mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
506f14eb2f
en visible, and each time it gets showed. I already made some RS pages derive from this page. - Modified and renamed the taskGraphPainterWidget to display info about currently selected file transfers. For know, it only shows file chunks info, but we should use it to display additional info about the transfer. Warning: in its current state, only fake chunk info is displayed. - Suppressed p3files.h, because it is not used. Remains to do (in order): - Implement a chunk map class in ft/ to properly manage which chunks should be downloaded - Display correct chunk info by requesting the transfer's chunk map - Add check-sum verification of chunks - allow RS to import a partially downloaded file by force re-checking chunks - Add chunk map exchange from file source peer id to file destination peer id. - Manage chunks from different peers. - Allow search (turtle search) for partially downloaded files git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1832 b45a01b8-16f6-495d-af2f-9b41ad6348cc
1318 lines
30 KiB
C++
1318 lines
30 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 <set>
|
|
|
|
#include "RemoteDirModel.h"
|
|
#include "rsiface/rsfiles.h"
|
|
|
|
#include <QtGui>
|
|
#include <QIcon>
|
|
#include <QPixmap>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <math.h>
|
|
#include <algorithm>
|
|
#include "util/misc.h"
|
|
|
|
/*****
|
|
* #define RDM_DEBUG
|
|
****/
|
|
|
|
RemoteDirModel::RemoteDirModel(bool mode, QObject *parent)
|
|
: QAbstractItemModel(parent),
|
|
RemoteMode(mode), nIndex(1), indexSet(1) /* ass zero index cant be used */,
|
|
ageIndicator(0)
|
|
{
|
|
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 = NULL;
|
|
if (parent.isValid())
|
|
{
|
|
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))
|
|
{
|
|
#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 QString("Anonymous") ;
|
|
case DIR_FLAGS_NETWORK_WIDE | DIR_FLAGS_BROWSABLE: return QString("Anonymous and browsable by friends") ;
|
|
case DIR_FLAGS_BROWSABLE: return QString("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_DEFAULT:
|
|
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 0
|
|
/*if (role == Qt::BackgroundRole)
|
|
{*/
|
|
/*** colour entries based on rank/age/count **/
|
|
/*** rank (0-10) ***/
|
|
/ *uint32_t r = details.rank;
|
|
if (r > 10) r = 10;
|
|
r = 200 + r * 5; /* 0->250 */
|
|
|
|
/*** age: log2(age) ***
|
|
* 1 hour = 3,600 - 250
|
|
* 1 day = 86,400 - 200
|
|
* 1 week = 604,800 - 100
|
|
* 1 month = 2,419,200 - 50
|
|
*
|
|
*
|
|
* 250 - log2( 1 + (age / 100) ) * 10
|
|
* 0 => 1 => 0 => 0 => 250
|
|
* 900 => 10 => 3.2 => 32 => 220
|
|
* 3600 => 37 => 5.2 => 52 => 200
|
|
* 86400 => 865 => 9.2 => 92 => 160
|
|
* 604800 => 6049 => 12.3 => 120 => 130
|
|
* 2419200 => 24193 => 14.4 => 140 => 110
|
|
*
|
|
* value log2
|
|
*
|
|
* 1 0
|
|
* 2 1
|
|
* 4 2
|
|
* 8 3
|
|
* 16 4
|
|
* 32 5
|
|
* 64 6
|
|
* 128 7
|
|
* 256 8
|
|
* 512 9
|
|
* 1024 10
|
|
* 2048 11
|
|
* 4096 12
|
|
* 8192 13
|
|
* 16384 14
|
|
* 32K 15
|
|
*
|
|
*/
|
|
|
|
/*uint32_t g = (uint32_t) log2 ( 1.0 + ( details.age / 100 ) ) * 4;
|
|
if (g > 250) g = 250;
|
|
g = 250 - g;
|
|
|
|
if (details.type == DIR_TYPE_PERSON)
|
|
{
|
|
return QVariant();
|
|
}
|
|
else if (details.type == DIR_TYPE_DIR)
|
|
{
|
|
uint32_t b = 200 + details.count;
|
|
if (b > 250) b = 250;
|
|
|
|
QBrush brush(QColor(r,g,b));
|
|
return brush;
|
|
}
|
|
else if (details.type == DIR_TYPE_FILE)
|
|
{
|
|
uint32_t b = (uint32_t) (200 + 2 * log2(details.count));
|
|
if (b > 250) b = 250;
|
|
|
|
QBrush brush(QColor(r,g,b));
|
|
return brush;
|
|
}
|
|
else
|
|
{
|
|
return QVariant();
|
|
}
|
|
}*/
|
|
#endif
|
|
|
|
if (role == RemoteDirModel::FileNameRole)
|
|
{
|
|
FileInfo finfo;
|
|
rsFiles->FileDetails(details.hash, 0, finfo);
|
|
|
|
return QString::fromStdString(finfo.path) ;
|
|
}
|
|
|
|
if (role == Qt::DecorationRole)
|
|
{
|
|
|
|
if (details.type == DIR_TYPE_PERSON)
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
return (QIcon(peerIcon));
|
|
break;
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_DIR)
|
|
{
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
QString ext = QFileInfo(QString::fromStdString(details.name)).suffix();
|
|
if (ext == "avi" || ext == "mpg" || ext == "movie")
|
|
{
|
|
QIcon icon(":/images/folder_video.png");
|
|
return icon;
|
|
}
|
|
else
|
|
{
|
|
return(QIcon(categoryIcon));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else if (details.type == DIR_TYPE_FILE) /* File */
|
|
{
|
|
// extensions predefined
|
|
//QString name;
|
|
switch(coln)
|
|
{
|
|
case 0:
|
|
QString ext = QFileInfo(QString::fromStdString(details.name)).suffix();
|
|
if (ext == "jpg" || ext == "jpeg" || ext == "png" || ext == "gif"
|
|
|| ext == "bmp" || ext == "ico" || ext == "svg")
|
|
{
|
|
//setIcon(0, QIcon(":/images/FileTypePicture.png"));
|
|
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")
|
|
{
|
|
//setIcon(0, QIcon(":/images/videofile.png"));
|
|
QIcon icon(":/images/FileTypeVideo.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "ogg" || ext == "mp3" || ext == "wav" || ext == "wma" || ext == "xpm")
|
|
{
|
|
//setIcon(0, QIcon(":/images/soundfile.png"));
|
|
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")
|
|
{
|
|
//setIcon(0, QIcon(":/images/compressedfile.png"));
|
|
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" )
|
|
{
|
|
//setIcon(0, QIcon(":/images/txtfile.png"));
|
|
QIcon icon(":/images/FileTypeCDImage.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "txt" || ext == "cpp" || ext == "c" || ext == "h")
|
|
{
|
|
//setIcon(0, QIcon(":/images/txtfile.png"));
|
|
QIcon icon(":/images/FileTypeDocument.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "doc" || ext == "rtf" || ext == "sxw" || ext == "xls"
|
|
|| ext == "sxc" || ext == "odt" || ext == "ods")
|
|
{
|
|
//setIcon(0, QIcon(":/images/docfile.png"));
|
|
QIcon icon(":/images/FileTypeDocument.png");
|
|
return icon;
|
|
}
|
|
else if (ext == "html" || ext == "htm" || ext == "php")
|
|
{
|
|
//setIcon(0, QIcon(":/images/netfile.png"));
|
|
QIcon icon(":/images/FileTypeDocument.png");
|
|
return icon;
|
|
}
|
|
else
|
|
{
|
|
//setIcon(0, QIcon(":/images/file.png"));
|
|
QIcon icon(":/images/FileTypeAny.png");
|
|
return icon;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return QVariant();
|
|
}
|
|
}
|
|
|
|
/*************
|
|
Qt::EditRole
|
|
Qt::ToolTipRole
|
|
Qt::StatusTipRole
|
|
Qt::WhatsThisRole
|
|
Qt::SizeHintRole
|
|
****************/
|
|
|
|
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::fromStdString(details.name);
|
|
break;
|
|
case 1:
|
|
//return QString("");
|
|
return QString::fromStdString(details.id);
|
|
break;
|
|
default:
|
|
//return QString("");
|
|
return QString::fromStdString("P");
|
|
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;
|
|
//out << details.count;
|
|
//return QString::fromStdString(out.str());
|
|
return misc::friendlyUnit(details.count);
|
|
}
|
|
break;
|
|
case 2:
|
|
{
|
|
return getFlagsString(details.flags);
|
|
}
|
|
break;
|
|
case 3:
|
|
{
|
|
std::ostringstream out;
|
|
//out << details.age;
|
|
return misc::userFriendlyDuration(details.age);
|
|
}
|
|
break;
|
|
case 4:
|
|
{
|
|
QString ind("");
|
|
if (ageIndicator != IND_DEFAULT)
|
|
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:
|
|
//return QString("");
|
|
{
|
|
std::ostringstream out;
|
|
out << details.count;
|
|
return QString::fromStdString(out.str());
|
|
}
|
|
break;
|
|
case 2:
|
|
return getFlagsString(details.flags);
|
|
break;
|
|
case 3:
|
|
return misc::userFriendlyDuration(details.age);
|
|
break;
|
|
case 4:
|
|
{
|
|
if (ageIndicator == IND_DEFAULT)
|
|
return QString("");
|
|
QModelIndex pidx = parent(index);
|
|
QModelIndex pidxs = pidx.sibling(pidx.row(), 4);
|
|
if (pidxs.isValid() && pidxs.data() != tr(""))
|
|
return pidxs.data();
|
|
else {
|
|
QString ind("");
|
|
getAgeIndicatorRec(details, ind);
|
|
return ind;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return QString(tr("DIR"));
|
|
break;
|
|
}
|
|
}
|
|
} /* end of DisplayRole */
|
|
return QVariant();
|
|
|
|
if (role == Qt::TextAlignmentRole)
|
|
{
|
|
if(coln == 1)
|
|
{
|
|
return int( Qt::AlignLeft | Qt::AlignVCenter);
|
|
}
|
|
|
|
|
|
}
|
|
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("Share type"));
|
|
break;
|
|
case 3:
|
|
return QString(tr("Age"));
|
|
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
|
|
|
|
void *ref = NULL;
|
|
|
|
if (parent.isValid())
|
|
{
|
|
ref = parent.internalPointer();
|
|
}
|
|
|
|
/********
|
|
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 */
|
|
QModelIndex qmi = createIndex(row, column, it->ref);
|
|
return qmi;
|
|
}
|
|
|
|
|
|
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 = DIR_FLAGS_PARENT;
|
|
if (RemoteMode)
|
|
flags |= DIR_FLAGS_REMOTE;
|
|
else
|
|
flags |= 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.
|
|
}
|
|
|
|
if (details.type == DIR_TYPE_PERSON)
|
|
{
|
|
return (Qt::ItemIsEnabled);
|
|
}
|
|
else if (details.type == DIR_TYPE_DIR)
|
|
{
|
|
return ( Qt::ItemIsSelectable |
|
|
Qt::ItemIsEnabled);
|
|
|
|
// Qt::ItemIsDragEnabled |
|
|
// Qt::ItemIsDropEnabled |
|
|
|
|
}
|
|
else // (details.type == 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, "", 0, 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((rsFiles->getDownloadDirectory() + "/" + dirDetails.path.substr(prefixLen)).c_str());
|
|
|
|
srcIds.push_back(dirDetails.id);
|
|
rsFiles->FileRequest(dirDetails.name, dirDetails.hash, dirDetails.count, cleanPath.toStdString(), 0, 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(dirDetails.path.c_str()).right(dirDetails.path.length() - prefixLen));
|
|
|
|
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)
|
|
{
|
|
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
|
|
|
|
if(already_in.find(details.hash) == already_in.end())
|
|
{
|
|
file_details.push_back(details) ;
|
|
already_in.insert(details.hash) ;
|
|
}
|
|
}
|
|
#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;
|
|
}
|
|
|
|
if (!openFolder) {
|
|
if ((*it).type & DIR_TYPE_FILE) {
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile(name.c_str()));
|
|
}
|
|
} else {
|
|
if (dirs_to_open.end() == std::find(dirs_to_open.begin(), dirs_to_open.end(), fullpath)) {
|
|
dirs_to_open.push_back(fullpath);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (openFolder) {
|
|
std::list<std::string>::iterator dit;
|
|
for (dit = dirs_to_open.begin(); dit != dirs_to_open.end(); dit++) {
|
|
QDesktopServices::openUrl(QUrl::fromLocalFile((*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) ;
|
|
}
|
|
|
|
|
|
|