mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-02-18 13:54:07 -05:00
![thunder2](/assets/img/avatar_default.png)
Sort strings case insensitive in NetworkDialog, PeersDialog (changed to RSTreeWidgetItem), MessengerWindow (changed to RSTreeWidgetItem) and SharedFilesDialog (with folders first). Sort the columns size and age in SharedFilesDialog by internal data and not by the shown string. Save and load layout of the SharedFilesDialog in profile. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3515 b45a01b8-16f6-495d-af2f-9b41ad6348cc
1295 lines
31 KiB
C++
1295 lines
31 KiB
C++
/*************************************:***************************
|
|
* RetroShare is distributed under the following license:
|
|
*
|
|
* Copyright (C) 2006 - 2009 RetroShare Team
|
|
*
|
|
* 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.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
****************************************************************/
|
|
|
|
#include <QFileInfo>
|
|
#include <QDir>
|
|
#include <QDesktopServices>
|
|
#include <QUrl>
|
|
#include <QMimeData>
|
|
|
|
#include "RemoteDirModel.h"
|
|
#include <retroshare/rsfiles.h>
|
|
#include <retroshare/rstypes.h>
|
|
#include "util/misc.h"
|
|
|
|
#include <set>
|
|
#include <sstream>
|
|
#include <algorithm>
|
|
|
|
/*****
|
|
* #define RDM_DEBUG
|
|
****/
|
|
|
|
RemoteDirModel::RemoteDirModel(bool mode, QObject *parent)
|
|
: QAbstractItemModel(parent),
|
|
ageIndicator(IND_ALWAYS),
|
|
RemoteMode(mode), nIndex(1), indexSet(1) /* ass zero index cant be used */
|
|
{
|
|
setSupportedDragActions(Qt::CopyAction);
|
|
treeStyle();
|
|
}
|
|
|
|
void RemoteDirModel::treeStyle()
|
|
{
|
|
categoryIcon.addPixmap(QPixmap(":/images/folder16.png"),
|
|
QIcon::Normal, QIcon::Off);
|
|
categoryIcon.addPixmap(QPixmap(":/images/folder_video.png"),
|
|
QIcon::Normal, QIcon::On);
|
|
peerIcon = QIcon(":/images/user/identity16.png");
|
|
}
|
|
|
|
bool RemoteDirModel::hasChildren(const QModelIndex &parent) const
|
|
{
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::hasChildren() :" << parent.internalPointer();
|
|
std::cerr << ": ";
|
|
#endif
|
|
|
|
if (!parent.isValid())
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "root -> true ";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
void *ref = parent.internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_CHILDREN;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
/* error */
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup failed -> false";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
if (details.type == DIR_TYPE_FILE)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup FILE -> false";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return false;
|
|
}
|
|
/* PERSON/DIR*/
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup PER/DIR #" << details.count;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return (details.count > 0); /* do we have children? */
|
|
}
|
|
|
|
|
|
int RemoteDirModel::rowCount(const QModelIndex &parent) const
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::rowCount(): " << parent.internalPointer();
|
|
std::cerr << ": ";
|
|
#endif
|
|
|
|
void *ref = (parent.isValid())? parent.internalPointer() : NULL ;
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_CHILDREN;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup failed -> 0";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return 0;
|
|
}
|
|
if (details.type == DIR_TYPE_FILE)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup FILE: 0";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/* else PERSON/DIR*/
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup PER/DIR #" << details.count;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return details.count;
|
|
}
|
|
|
|
int RemoteDirModel::columnCount(const QModelIndex &parent) const
|
|
{
|
|
return 5;
|
|
}
|
|
QString RemoteDirModel::getFlagsString(uint32_t flags)
|
|
{
|
|
switch(flags & (DIR_FLAGS_NETWORK_WIDE|DIR_FLAGS_BROWSABLE))
|
|
{
|
|
case DIR_FLAGS_NETWORK_WIDE: return tr("Anonymous") ;
|
|
case DIR_FLAGS_NETWORK_WIDE | DIR_FLAGS_BROWSABLE: return tr("Anonymous and browsable by friends") ;
|
|
case DIR_FLAGS_BROWSABLE: return tr("Only browsable by friends") ;
|
|
default:
|
|
return QString() ;
|
|
}
|
|
}
|
|
|
|
QString RemoteDirModel::getAgeIndicatorString(const DirDetails &details) const
|
|
{
|
|
QString ret("");
|
|
QString nind("NEW");
|
|
QString oind("OLD");
|
|
uint32_t age = details.age;
|
|
|
|
switch (ageIndicator) {
|
|
case IND_LAST_DAY:
|
|
if (age < 24 * 60 * 60) return nind;
|
|
break;
|
|
case IND_LAST_WEEK:
|
|
if (age < 7 * 24 * 60 * 60) return nind;
|
|
break;
|
|
case IND_LAST_MONTH:
|
|
if (age < 30 * 24 * 60 * 60) return nind;
|
|
break;
|
|
// case IND_OLDER:
|
|
// if (age >= 30 * 24 * 60 * 60) return oind;
|
|
// break;
|
|
case IND_ALWAYS:
|
|
return ret;
|
|
default:
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
QVariant RemoteDirModel::data(const QModelIndex &index, int role) const
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::data(): " << index.internalPointer();
|
|
std::cerr << ": ";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
if (!index.isValid())
|
|
return QVariant();
|
|
|
|
/* get the data from the index */
|
|
void *ref = index.internalPointer();
|
|
int coln = index.column();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
return QVariant();
|
|
}
|
|
|
|
if (role == RemoteDirModel::FileNameRole)
|
|
{
|
|
FileInfo finfo;
|
|
rsFiles->FileDetails(details.hash, 0, finfo);
|
|
|
|
return QString::fromUtf8(finfo.path.c_str()) ;
|
|
} /* end of FileNameRole */
|
|
|
|
if (role == Qt::TextColorRole)
|
|
{
|
|
FileInfo finfo;
|
|
rsFiles->FileDetails(details.hash, 0, finfo);
|
|
|
|
if(details.min_age > ageIndicator)
|
|
return Qt::gray ;
|
|
else
|
|
return Qt::black ;
|
|
} /* end of TextColorRole */
|
|
|
|
|
|
if (role == Qt::DecorationRole)
|
|
{
|
|
FileInfo finfo;
|
|
rsFiles->FileDetails(details.hash, 0, finfo);
|
|
|
|
if (details.type == DIR_TYPE_PERSON)
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
if(details.min_age > ageIndicator)
|
|
{
|
|
return QIcon(":/images/folder_grey.png");
|
|
}
|
|
else if (ageIndicator == IND_LAST_DAY )
|
|
{
|
|
return QIcon(":/images/folder_green.png");
|
|
}
|
|
else if (ageIndicator == IND_LAST_WEEK )
|
|
{
|
|
return QIcon(":/images/folder_yellow.png");
|
|
}
|
|
else if (ageIndicator == IND_LAST_MONTH )
|
|
{
|
|
return QIcon(":/images/folder_red.png");
|
|
}
|
|
else
|
|
{
|
|
return (QIcon(peerIcon));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_DIR)
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
if(details.min_age > ageIndicator)
|
|
{
|
|
return QIcon(":/images/folder_grey.png");
|
|
}
|
|
else if (ageIndicator == IND_LAST_DAY )
|
|
{
|
|
return QIcon(":/images/folder_green.png");
|
|
}
|
|
else if (ageIndicator == IND_LAST_WEEK )
|
|
{
|
|
return QIcon(":/images/folder_yellow.png");
|
|
}
|
|
else if (ageIndicator == IND_LAST_MONTH )
|
|
{
|
|
return QIcon(":/images/folder_red.png");
|
|
}
|
|
else
|
|
{
|
|
return(QIcon(categoryIcon));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_FILE) /* File */
|
|
{
|
|
// extensions predefined
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
QString ext = QFileInfo(QString::fromUtf8(details.name.c_str())).suffix();
|
|
if (ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "gif"
|
|
|| ext == "bmp" || ext == "ico" || ext == "svg")
|
|
{
|
|
QIcon icon(":/images/FileTypePicture.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "avi" || ext == "AVI" || ext == "mpg" || ext == "mpeg" || ext == "wmv" || ext == "ogm"
|
|
|| ext == "mkv" || ext == "mp4" || ext == "flv" || ext == "mov"
|
|
|| ext == "vob" || ext == "qt" || ext == "rm" || ext == "3gp")
|
|
{
|
|
QIcon icon(":/images/FileTypeVideo.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "ogg" || ext == "mp3" || ext == "wav" || ext == "wma" || ext == "xpm")
|
|
{
|
|
QIcon icon(":/images/FileTypeAudio.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "tar" || ext == "bz2" || ext == "zip" || ext == "gz" || ext == "7z"
|
|
|| ext == "rar" || ext == "rpm" || ext == "deb")
|
|
{
|
|
QIcon icon(":/images/FileTypeArchive.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "app" || ext == "bat" || ext == "cgi" || ext == "com"
|
|
|| ext == "bin" || ext == "exe" || ext == "js" || ext == "pif"
|
|
|| ext == "py" || ext == "pl" || ext == "sh" || ext == "vb" || ext == "ws")
|
|
{
|
|
return(QIcon(":/images/FileTypeProgram.png"));
|
|
}
|
|
else if (ext == "iso" || ext == "nrg" || ext == "mdf" )
|
|
{
|
|
QIcon icon(":/images/FileTypeCDImage.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "txt" || ext == "cpp" || ext == "c" || ext == "h")
|
|
{
|
|
QIcon icon(":/images/FileTypeDocument.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "doc" || ext == "rtf" || ext == "sxw" || ext == "xls"
|
|
|| ext == "sxc" || ext == "odt" || ext == "ods")
|
|
{
|
|
QIcon icon(":/images/FileTypeDocument.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "html" || ext == "htm" || ext == "php")
|
|
{
|
|
QIcon icon(":/images/FileTypeDocument.png");
|
|
return icon;
|
|
}
|
|
else
|
|
{
|
|
QIcon icon(":/images/FileTypeAny.png");
|
|
return icon;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return QVariant();
|
|
}
|
|
} /* end of DecorationRole */
|
|
|
|
/*****************
|
|
Qt::EditRole
|
|
Qt::ToolTipRole
|
|
Qt::StatusTipRole
|
|
Qt::WhatsThisRole
|
|
Qt::SizeHintRole
|
|
****************/
|
|
|
|
if (role == Qt::SizeHintRole)
|
|
{
|
|
return QSize(18, 18);
|
|
} /* end of SizeHintRole */
|
|
|
|
if (role == Qt::TextAlignmentRole)
|
|
{
|
|
if(coln == 1)
|
|
{
|
|
return int( Qt::AlignRight | Qt::AlignVCenter);
|
|
}
|
|
} /* end of TextAlignmentRole */
|
|
|
|
if (role == Qt::DisplayRole)
|
|
{
|
|
|
|
/*
|
|
* Person: name, id, 0, 0;
|
|
* File : name, size, rank, (0) ts
|
|
* Dir : name, (0) count, (0) path, (0) ts
|
|
*/
|
|
|
|
|
|
if (details.type == DIR_TYPE_PERSON) /* Person */
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(details.name.c_str());
|
|
break;
|
|
case 1:
|
|
return QString() ;
|
|
break;
|
|
default:
|
|
return QString() ;
|
|
break;
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_FILE) /* File */
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(details.name.c_str());
|
|
break;
|
|
case 1:
|
|
{
|
|
std::ostringstream out;
|
|
return misc::friendlyUnit(details.count);
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
std::ostringstream out;
|
|
return misc::userFriendlyDuration(details.age);
|
|
}
|
|
break;
|
|
case 3:
|
|
{
|
|
return getFlagsString(details.flags);
|
|
}
|
|
break;
|
|
case 4:
|
|
{
|
|
QString ind("");
|
|
if (ageIndicator != IND_ALWAYS)
|
|
ind = getAgeIndicatorString(details);
|
|
return ind;
|
|
}
|
|
break;
|
|
default:
|
|
return QString(tr("FILE"));
|
|
break;
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_DIR) /* Dir */
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(details.name.c_str());
|
|
break;
|
|
case 1:
|
|
{
|
|
std::ostringstream out;
|
|
out << details.count;
|
|
if (details.count > 1)
|
|
{
|
|
return QString::fromStdString(out.str()) + " " + tr("Files");
|
|
}
|
|
else
|
|
return QString::fromStdString(out.str()) + " " + tr("File");
|
|
}
|
|
break;
|
|
case 2:
|
|
return misc::userFriendlyDuration(details.min_age);
|
|
break;
|
|
case 3:
|
|
return getFlagsString(details.flags);
|
|
break;
|
|
default:
|
|
return QString(tr("DIR"));
|
|
break;
|
|
}
|
|
}
|
|
} /* end of DisplayRole */
|
|
|
|
if (role == SortRole)
|
|
{
|
|
|
|
/*
|
|
* Person: name, id, 0, 0;
|
|
* File : name, size, rank, (0) ts
|
|
* Dir : name, (0) count, (0) path, (0) ts
|
|
*/
|
|
|
|
|
|
if (details.type == DIR_TYPE_PERSON) /* Person */
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(details.name.c_str());
|
|
case 1:
|
|
return QString();
|
|
default:
|
|
return QString();
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_FILE) /* File */
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(details.name.c_str());
|
|
case 1:
|
|
return details.count;
|
|
case 2:
|
|
return details.age;
|
|
case 3:
|
|
return getFlagsString(details.flags);
|
|
case 4:
|
|
{
|
|
QString ind("");
|
|
if (ageIndicator != IND_ALWAYS)
|
|
ind = getAgeIndicatorString(details);
|
|
return ind;
|
|
}
|
|
default:
|
|
return QString(tr("FILE"));
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_DIR) /* Dir */
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return QString::fromUtf8(details.name.c_str());
|
|
case 1:
|
|
return details.count;
|
|
case 2:
|
|
return details.min_age;
|
|
case 3:
|
|
return getFlagsString(details.flags);
|
|
default:
|
|
return QString(tr("DIR"));
|
|
}
|
|
}
|
|
} /* end of SortRole */
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
void RemoteDirModel::getAgeIndicatorRec(DirDetails &details, QString &ret) const {
|
|
if (details.type == DIR_TYPE_FILE) {
|
|
ret = getAgeIndicatorString(details);
|
|
return;
|
|
} else if (details.type == DIR_TYPE_DIR && ret == tr("")) {
|
|
std::list<DirStub>::iterator it;
|
|
for (it = details.children.begin(); it != details.children.end(); it++) {
|
|
void *ref = it->ref;
|
|
DirDetails childDetails;
|
|
uint32_t flags;
|
|
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (rsFiles->RequestDirDetails(ref, childDetails, flags) && ret == tr(""))
|
|
getAgeIndicatorRec(childDetails, ret);
|
|
}
|
|
}
|
|
}
|
|
|
|
QVariant RemoteDirModel::headerData(int section, Qt::Orientation orientation,
|
|
int role) const
|
|
{
|
|
if (role == Qt::SizeHintRole)
|
|
{
|
|
int defw = 50;
|
|
int defh = 21;
|
|
if (section < 2)
|
|
{
|
|
defw = 200;
|
|
}
|
|
return QSize(defw, defh);
|
|
}
|
|
|
|
if (role != Qt::DisplayRole)
|
|
return QVariant();
|
|
|
|
if (orientation == Qt::Horizontal)
|
|
{
|
|
switch(section)
|
|
{
|
|
case 0:
|
|
if (RemoteMode)
|
|
{
|
|
return QString(tr("Friends Directories"));
|
|
}
|
|
else
|
|
{
|
|
return QString(tr("My Directories"));
|
|
}
|
|
break;
|
|
case 1:
|
|
return QString(tr("Size"));
|
|
break;
|
|
case 2:
|
|
return QString(tr("Age"));
|
|
break;
|
|
case 3:
|
|
return QString(tr("Share Type"));
|
|
break;
|
|
case 4:
|
|
return QString(tr("What's new"));
|
|
break;
|
|
}
|
|
return QString("Column %1").arg(section);
|
|
}
|
|
else
|
|
return QString("Row %1").arg(section);
|
|
}
|
|
|
|
QModelIndex RemoteDirModel::index(int row, int column, const QModelIndex & parent) const
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::index(): " << parent.internalPointer();
|
|
std::cerr << ": row:" << row << " col:" << column << " ";
|
|
#endif
|
|
|
|
if(row < 0)
|
|
return QModelIndex() ;
|
|
|
|
void *ref = (parent.isValid()) ? parent.internalPointer() : NULL;
|
|
|
|
/********
|
|
if (!RemoteMode)
|
|
{
|
|
remote = &(rsiface->getLocalDirectoryList());
|
|
}
|
|
********/
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_CHILDREN;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "lookup failed -> invalid";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return QModelIndex();
|
|
}
|
|
|
|
|
|
/* now iterate through the details to
|
|
* get the reference number
|
|
*/
|
|
|
|
std::list<DirStub>::iterator it;
|
|
int i = 0;
|
|
for(it = details.children.begin(); ((i < row) && (it != details.children.end())); ++it,++i) ;
|
|
|
|
if (it == details.children.end())
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "wrong number of children -> invalid";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return QModelIndex();
|
|
}
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "success index(" << row << "," << column << "," << it->ref << ")";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
/* we can just grab the reference now */
|
|
|
|
return createIndex(row, column, it->ref);
|
|
}
|
|
|
|
|
|
QModelIndex RemoteDirModel::parent( const QModelIndex & index ) const
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::parent(): " << index.internalPointer();
|
|
std::cerr << ": ";
|
|
#endif
|
|
|
|
/* create the index */
|
|
if (!index.isValid())
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Invalid Index -> invalid";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
/* Parent is invalid too */
|
|
return QModelIndex();
|
|
}
|
|
void *ref = index.internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = (RemoteMode)?DIR_FLAGS_REMOTE:DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Failed Lookup -> invalid";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return QModelIndex();
|
|
}
|
|
|
|
if (!(details.parent))
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "success. parent is Root/NULL --> invalid";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
return QModelIndex();
|
|
}
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "success index(" << details.prow << ",0," << details.parent << ")";
|
|
std::cerr << std::endl;
|
|
|
|
#endif
|
|
return createIndex(details.prow, 0, details.parent);
|
|
}
|
|
|
|
Qt::ItemFlags RemoteDirModel::flags( const QModelIndex & index ) const
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::flags()";
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
if (!index.isValid())
|
|
return (Qt::ItemIsSelectable); // Error.
|
|
|
|
void *ref = index.internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
return Qt::ItemIsSelectable; // Error.
|
|
|
|
switch(details.type)
|
|
{
|
|
case DIR_TYPE_PERSON: return Qt::ItemIsEnabled;
|
|
case DIR_TYPE_DIR: return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
|
default: ;
|
|
case DIR_TYPE_FILE: return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled;
|
|
}
|
|
}
|
|
|
|
// The other flags...
|
|
//Qt::ItemIsUserCheckable
|
|
//Qt::ItemIsEditable
|
|
//Qt::ItemIsDropEnabled
|
|
//Qt::ItemIsTristate
|
|
|
|
|
|
|
|
/* Callback from */
|
|
void RemoteDirModel::preMods()
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::preMods()" << std::endl;
|
|
#endif
|
|
//modelAboutToBeReset();
|
|
// reset();
|
|
layoutAboutToBeChanged();
|
|
}
|
|
|
|
/* Callback from */
|
|
void RemoteDirModel::postMods()
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::postMods()" << std::endl;
|
|
#endif
|
|
//modelReset();
|
|
layoutChanged();
|
|
//reset();
|
|
}
|
|
|
|
|
|
//void RemoteDirModel::update (const QModelIndex &index )
|
|
//{
|
|
//#ifdef RDM_DEBUG
|
|
// //std::cerr << "Directory Request(" << id << ") : ";
|
|
// //std::cerr << path << std::endl;
|
|
//#endif
|
|
// //rsFiles -> RequestDirectories(id, path, 1);
|
|
//}
|
|
|
|
void RemoteDirModel::downloadSelected(QModelIndexList list)
|
|
{
|
|
if (!RemoteMode)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Cannot download from local" << std::endl;
|
|
#endif
|
|
}
|
|
|
|
/* so for all the selected .... get the name out,
|
|
* make it into something the RsControl can understand
|
|
*/
|
|
|
|
std::vector <DirDetails> dirVec;
|
|
|
|
getDirDetailsFromSelect(list, dirVec);
|
|
|
|
/* Fire off requests */
|
|
for (int i = 0, n = dirVec.size(); i < n; ++i)
|
|
{
|
|
if (!RemoteMode)
|
|
{
|
|
continue; /* don't try to download local stuff */
|
|
}
|
|
|
|
const DirDetails& details = dirVec[i];
|
|
|
|
/* if it is a file */
|
|
if (details.type == DIR_TYPE_FILE)
|
|
{
|
|
std::cerr << "RemoteDirModel::downloadSelected() Calling File Request";
|
|
std::cerr << std::endl;
|
|
std::list<std::string> srcIds;
|
|
srcIds.push_back(details.id);
|
|
rsFiles -> FileRequest(details.name, details.hash,
|
|
details.count, "", RS_FILE_HINTS_NETWORK_WIDE, srcIds);
|
|
}
|
|
/* if it is a dir, copy all files included*/
|
|
else if (details.type == DIR_TYPE_DIR)
|
|
{
|
|
int prefixLen = details.path.rfind(details.name);
|
|
if (prefixLen < 0) continue;
|
|
downloadDirectory(details, prefixLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* recursively download a directory */
|
|
void RemoteDirModel::downloadDirectory(const DirDetails & dirDetails, int prefixLen)
|
|
{
|
|
if (dirDetails.type & DIR_TYPE_FILE)
|
|
{
|
|
std::list<std::string> srcIds;
|
|
QString cleanPath = QDir::cleanPath(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()) + "/" + QString::fromUtf8(dirDetails.path.substr(prefixLen).c_str()));
|
|
|
|
srcIds.push_back(dirDetails.id);
|
|
rsFiles->FileRequest(dirDetails.name, dirDetails.hash, dirDetails.count, cleanPath.toUtf8().constData(), RS_FILE_HINTS_NETWORK_WIDE, srcIds);
|
|
}
|
|
else if (dirDetails.type & DIR_TYPE_DIR)
|
|
{
|
|
std::list<DirStub>::const_iterator it;
|
|
QDir dwlDir(rsFiles->getDownloadDirectory().c_str());
|
|
QString cleanPath = QDir::cleanPath(QString::fromUtf8(dirDetails.path.substr(prefixLen).c_str()));
|
|
|
|
if (!dwlDir.mkpath(cleanPath)) return;
|
|
|
|
for (it = dirDetails.children.begin(); it != dirDetails.children.end(); it++)
|
|
{
|
|
if (!it->ref) continue;
|
|
|
|
DirDetails subDirDetails;
|
|
uint32_t flags = DIR_FLAGS_CHILDREN | DIR_FLAGS_REMOTE;
|
|
|
|
if (!rsFiles->RequestDirDetails(it->ref, subDirDetails, flags)) continue;
|
|
|
|
downloadDirectory(subDirDetails, prefixLen);
|
|
}
|
|
}
|
|
}
|
|
|
|
void RemoteDirModel::getDirDetailsFromSelect (QModelIndexList list, std::vector <DirDetails>& dirVec)
|
|
{
|
|
dirVec.clear();
|
|
|
|
/* Fire off requests */
|
|
QModelIndexList::iterator it;
|
|
for(it = list.begin(); it != list.end(); it++)
|
|
{
|
|
if(it->column()==1)
|
|
{
|
|
void *ref = it -> internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
if (RemoteMode)
|
|
{
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
}
|
|
else
|
|
{
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
}
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dirVec.push_back(details);
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
* OLD RECOMMEND SYSTEM - DISABLED
|
|
*
|
|
*/
|
|
|
|
void RemoteDirModel::getFileInfoFromIndexList(const QModelIndexList& list, std::list<DirDetails>& file_details)
|
|
{
|
|
file_details.clear() ;
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "recommendSelected()" << std::endl;
|
|
#endif
|
|
if (RemoteMode)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Cannot recommend remote! (should download)" << std::endl;
|
|
#endif
|
|
}
|
|
/* Fire off requests */
|
|
|
|
std::set<std::string> already_in ;
|
|
|
|
for(QModelIndexList::const_iterator it(list.begin()); it != list.end(); ++it)
|
|
if(it->column()==0)
|
|
{
|
|
void *ref = it -> internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
continue;
|
|
|
|
if(details.type == DIR_TYPE_PERSON)
|
|
continue ;
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::FileRecommend:::: " << std::endl;
|
|
std::cerr << "Name: " << details.name << std::endl;
|
|
std::cerr << "Hash: " << details.hash << std::endl;
|
|
std::cerr << "Size: " << details.count << std::endl;
|
|
std::cerr << "Path: " << details.path << std::endl;
|
|
#endif
|
|
// Note: for directories, the returned hash, is the peer id, so if we collect
|
|
// dirs, we need to be a bit more conservative for the
|
|
|
|
if(already_in.find(details.hash+details.name) == already_in.end())
|
|
{
|
|
file_details.push_back(details) ;
|
|
already_in.insert(details.hash+details.name) ;
|
|
}
|
|
}
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::Done FileRecommend" << std::endl;
|
|
#endif
|
|
}
|
|
|
|
#if 0
|
|
void RemoteDirModel::recommendSelectedOnly(QModelIndexList list)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "recommendSelectedOnly()" << std::endl;
|
|
#endif
|
|
if (RemoteMode)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Cannot recommend remote! (should download)" << std::endl;
|
|
#endif
|
|
}
|
|
rsFiles->ClearInRecommend();
|
|
|
|
/* Fire off requests */
|
|
QModelIndexList::iterator it;
|
|
for(it = list.begin(); it != list.end(); it++)
|
|
{
|
|
void *ref = it -> internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
if (RemoteMode)
|
|
{
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
continue; /* don't recommend remote stuff */
|
|
}
|
|
else
|
|
{
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
}
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::FileRecommend:::: " << std::endl;
|
|
std::cerr << "Name: " << details.name << std::endl;
|
|
std::cerr << "Hash: " << details.hash << std::endl;
|
|
std::cerr << "Size: " << details.count << std::endl;
|
|
std::cerr << "Path: " << details.path << std::endl;
|
|
#endif
|
|
|
|
rsFiles -> FileRecommend(details.name, details.hash, details.count);
|
|
rsFiles -> SetInRecommend(details.name, true);
|
|
}
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::Done FileRecommend" << std::endl;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* OLD RECOMMEND SYSTEM - DISABLED
|
|
******/
|
|
|
|
void RemoteDirModel::openSelected(QModelIndexList qmil, bool openFolder)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::openSelected()" << std::endl;
|
|
#endif
|
|
|
|
if (RemoteMode) {
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Cannot open remote. Download first." << std::endl;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
std::list<std::string> dirs_to_open;
|
|
|
|
std::list<DirDetails> files_info;
|
|
std::list<DirDetails>::iterator it;
|
|
getFileInfoFromIndexList(qmil, files_info);
|
|
|
|
for (it = files_info.begin(); it != files_info.end(); it++)
|
|
{
|
|
if ((*it).type & DIR_TYPE_PERSON) continue;
|
|
|
|
std::string fullpath, name;
|
|
rsFiles->ConvertSharedFilePath((*it).path, fullpath);
|
|
int len = fullpath.length();
|
|
if (len && (fullpath[len - 1] != '/')) fullpath += '/';
|
|
|
|
if ((*it).type & DIR_TYPE_FILE) {
|
|
name = fullpath + (*it).name;
|
|
} else if ((*it).type & DIR_TYPE_DIR) {
|
|
name = fullpath;
|
|
}
|
|
|
|
std::cerr << "Opennign this file: " << name << std::endl ;
|
|
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromUtf8(name.c_str(),name.length())));
|
|
}
|
|
|
|
// if (openFolder) {
|
|
// std::list<std::string>::iterator dit;
|
|
// for (dit = dirs_to_open.begin(); dit != dirs_to_open.end(); dit++)
|
|
// {
|
|
// std::cerr << "Opennign this folder: " << (*dit).c_str() << std::endl ;
|
|
// QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromUtf8((*dit).c_str())));
|
|
// }
|
|
// }
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::Done RemoteDirModel::openSelected()" << std::endl;
|
|
#endif
|
|
}
|
|
|
|
void RemoteDirModel::getFilePaths(QModelIndexList list, std::list<std::string> &fullpaths)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::getFilePaths()" << std::endl;
|
|
#endif
|
|
if (RemoteMode)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "No File Paths for remote files" << std::endl;
|
|
#endif
|
|
return;
|
|
}
|
|
/* translate */
|
|
QModelIndexList::iterator it;
|
|
for(it = list.begin(); it != list.end(); it++)
|
|
{
|
|
void *ref = it -> internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "getFilePaths() Bad Request" << std::endl;
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (details.type != DIR_TYPE_FILE)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "getFilePaths() Not File" << std::endl;
|
|
#endif
|
|
continue; /* not file! */
|
|
}
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::File Details:::: " << std::endl;
|
|
std::cerr << "Name: " << details.name << std::endl;
|
|
std::cerr << "Hash: " << details.hash << std::endl;
|
|
std::cerr << "Size: " << details.count << std::endl;
|
|
std::cerr << "Path: " << details.path << std::endl;
|
|
#endif
|
|
|
|
std::string filepath = details.path + "/";
|
|
filepath += details.name;
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Constructed FilePath: " << filepath << std::endl;
|
|
#endif
|
|
if (fullpaths.end() == std::find(fullpaths.begin(), fullpaths.end(), filepath))
|
|
{
|
|
fullpaths.push_back(filepath);
|
|
}
|
|
}
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::Done getFilePaths" << std::endl;
|
|
#endif
|
|
}
|
|
|
|
/* Drag and Drop Functionality */
|
|
QMimeData * RemoteDirModel::mimeData ( const QModelIndexList & indexes ) const
|
|
{
|
|
/* extract from each the member text */
|
|
std::string text;
|
|
QModelIndexList::const_iterator it;
|
|
std::map<std::string, uint64_t> drags;
|
|
std::map<std::string, uint64_t>::iterator dit;
|
|
|
|
for(it = indexes.begin(); it != indexes.end(); it++)
|
|
{
|
|
void *ref = it -> internalPointer();
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
if (RemoteMode)
|
|
{
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
}
|
|
else
|
|
{
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
}
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "::::::::::::FileDrag:::: " << std::endl;
|
|
std::cerr << "Name: " << details.name << std::endl;
|
|
std::cerr << "Hash: " << details.hash << std::endl;
|
|
std::cerr << "Size: " << details.count << std::endl;
|
|
std::cerr << "Path: " << details.path << std::endl;
|
|
#endif
|
|
|
|
if (details.type != DIR_TYPE_FILE)
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::mimeData() Not File" << std::endl;
|
|
#endif
|
|
continue; /* not file! */
|
|
}
|
|
|
|
if (drags.end() != (dit = drags.find(details.hash)))
|
|
{
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "RemoteDirModel::mimeData() Duplicate" << std::endl;
|
|
#endif
|
|
continue; /* duplicate */
|
|
}
|
|
|
|
drags[details.hash] = details.count;
|
|
|
|
std::string line = details.name;
|
|
line += "/";
|
|
line += details.hash;
|
|
line += "/";
|
|
|
|
{
|
|
std::ostringstream out;
|
|
out << details.count;
|
|
line += out.str();
|
|
line += "/";
|
|
}
|
|
|
|
if (RemoteMode)
|
|
{
|
|
line += "Remote";
|
|
}
|
|
else
|
|
{
|
|
line += "Local";
|
|
}
|
|
line += "/\n";
|
|
|
|
text += line;
|
|
}
|
|
|
|
#ifdef RDM_DEBUG
|
|
std::cerr << "Created MimeData:";
|
|
std::cerr << std::endl;
|
|
|
|
std::cerr << text;
|
|
std::cerr << std::endl;
|
|
#endif
|
|
|
|
QMimeData *data = new QMimeData();
|
|
data->setData("application/x-rsfilelist", QByteArray(text.c_str()));
|
|
|
|
return data;
|
|
|
|
|
|
}
|
|
|
|
QStringList RemoteDirModel::mimeTypes () const
|
|
{
|
|
QStringList list;
|
|
list.push_back("application/x-rsfilelist");
|
|
|
|
return list;
|
|
}
|
|
|
|
//============================================================================
|
|
|
|
bool
|
|
RemoteDirModel::isDir ( const QModelIndex & index ) const
|
|
{
|
|
//if (RemoteMode) // only local files can be opened
|
|
// return ;
|
|
void *ref = index.internalPointer();
|
|
if (!ref)
|
|
return false;
|
|
|
|
DirDetails details;
|
|
uint32_t flags = DIR_FLAGS_DETAILS;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= DIR_FLAGS_LOCAL;
|
|
|
|
if (!rsFiles->RequestDirDetails(ref, details, flags))
|
|
{
|
|
return false;//not good, but....
|
|
}
|
|
|
|
return (details.type == DIR_TYPE_DIR) ;
|
|
}
|
|
|
|
|
|
|