From 50d5c1159d1118fda6756c9a6711231ac355f11a Mon Sep 17 00:00:00 2001 From: csoler Date: Mon, 7 Nov 2011 23:07:25 +0000 Subject: [PATCH] Added the hability to create and handle collection files. A collection file contains a directory structure and files that RS can DL seamlessly in the DL directory. Collection files are created from shared files and can be handled by righ-clicking on them in Transfers and Shared files. Handling is based on the extension, that must be "rscollection". git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@4664 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- retroshare-gui/src/RetroShare.pro | 4 + retroshare-gui/src/gui/RemoteDirModel.cpp | 27 ++- retroshare-gui/src/gui/RemoteDirModel.h | 1 + retroshare-gui/src/gui/SharedFilesDialog.cpp | 14 ++ retroshare-gui/src/gui/SharedFilesDialog.h | 2 + retroshare-gui/src/gui/TransfersDialog.cpp | 12 +- .../src/gui/common/RsCollectionFile.cpp | 184 ++++++++++++++++++ .../src/gui/common/RsCollectionFile.h | 69 +++++++ .../src/gui/common/RsUrlHandler.cpp | 48 +++++ retroshare-gui/src/gui/common/RsUrlHandler.h | 32 +++ 10 files changed, 385 insertions(+), 8 deletions(-) create mode 100644 retroshare-gui/src/gui/common/RsCollectionFile.cpp create mode 100644 retroshare-gui/src/gui/common/RsCollectionFile.h create mode 100644 retroshare-gui/src/gui/common/RsUrlHandler.cpp create mode 100644 retroshare-gui/src/gui/common/RsUrlHandler.h diff --git a/retroshare-gui/src/RetroShare.pro b/retroshare-gui/src/RetroShare.pro index 35ce75395..2c21a9f29 100644 --- a/retroshare-gui/src/RetroShare.pro +++ b/retroshare-gui/src/RetroShare.pro @@ -310,6 +310,8 @@ HEADERS += rshare.h \ gui/toaster/OnlineToaster.h \ gui/toaster/DownloadToaster.h \ gui/common/vmessagebox.h \ + gui/common/RsUrlHandler.h \ + gui/common/RsCollectionFile.h \ gui/common/rwindow.h \ gui/common/html.h \ gui/common/AvatarDefs.h \ @@ -531,6 +533,8 @@ SOURCES += main.cpp \ gui/msgs/MessageWindow.cpp \ gui/msgs/TagsMenu.cpp \ gui/common/vmessagebox.cpp \ + gui/common/RsCollectionFile.cpp \ + gui/common/RsUrlHandler.cpp \ gui/common/rwindow.cpp \ gui/common/html.cpp \ gui/common/AvatarDefs.cpp \ diff --git a/retroshare-gui/src/gui/RemoteDirModel.cpp b/retroshare-gui/src/gui/RemoteDirModel.cpp index 2e382563b..2f4c14e1c 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.cpp +++ b/retroshare-gui/src/gui/RemoteDirModel.cpp @@ -21,12 +21,14 @@ #include #include -#include #include #include #include +#include #include +#include +#include #include "RemoteDirModel.h" #include #include @@ -904,6 +906,26 @@ bool RetroshareDirModel::requestDirDetails(void *ref,DirDetails& details,uint32_ return rsFiles->RequestDirDetails(ref, details, flags) ; } +void RetroshareDirModel::createCollectionFile(const QModelIndexList &list) +{ + if(RemoteMode) + { + std::cerr << "Cannot create a collection file from remote" << std::endl; + return ; + } + + QString filename = QFileDialog::getSaveFileName(NULL,tr("Create selection file"),".",tr("Collection files")+" (*.rsCollection)") ; + + if(filename.isNull()) + return ; + + std::cerr << "Got file name: "<< filename.toStdString() << std::endl; + std::vector dirVec; + getDirDetailsFromSelect(list, dirVec); + + RsCollectionFile(dirVec).save(filename) ; +} + void RetroshareDirModel::downloadSelected(const QModelIndexList &list) { if (!RemoteMode) @@ -911,6 +933,7 @@ void RetroshareDirModel::downloadSelected(const QModelIndexList &list) #ifdef RDM_DEBUG std::cerr << "Cannot download from local" << std::endl; #endif + return ; } /* so for all the selected .... get the name out, @@ -1119,7 +1142,7 @@ void RetroshareDirModel::openSelected(const QModelIndexList &qmil) std::cerr << "Opening this file: " << dest.toStdString() << std::endl ; - QDesktopServices::openUrl(QUrl::fromLocalFile(dest)); + RsUrlHandler::openUrl(QUrl::fromLocalFile(dest)); } #ifdef RDM_DEBUG diff --git a/retroshare-gui/src/gui/RemoteDirModel.h b/retroshare-gui/src/gui/RemoteDirModel.h index 291040cf1..046a72232 100644 --- a/retroshare-gui/src/gui/RemoteDirModel.h +++ b/retroshare-gui/src/gui/RemoteDirModel.h @@ -55,6 +55,7 @@ class RetroshareDirModel : public QAbstractItemModel /* Callback from GUI */ void downloadSelected(const QModelIndexList &list); + void createCollectionFile(const QModelIndexList &list); void getDirDetailsFromSelect (const QModelIndexList &list, std::vector & dirVec); diff --git a/retroshare-gui/src/gui/SharedFilesDialog.cpp b/retroshare-gui/src/gui/SharedFilesDialog.cpp index 694959961..798009b79 100644 --- a/retroshare-gui/src/gui/SharedFilesDialog.cpp +++ b/retroshare-gui/src/gui/SharedFilesDialog.cpp @@ -229,6 +229,8 @@ SharedFilesDialog::SharedFilesDialog(QWidget *parent) addlinkCloudAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Add Links to Cloud" ), this ); connect( addlinkCloudAct , SIGNAL( triggered() ), this, SLOT( addLinkToCloud( ) ) ); #endif + createcollectionfileAct = new QAction(QIcon(IMAGE_OPENFILE), tr("Create collection file"), this); + connect(createcollectionfileAct, SIGNAL(triggered()), this, SLOT(createCollectionFile())); openfileAct = new QAction(QIcon(IMAGE_OPENFILE), tr("Open File"), this); connect(openfileAct, SIGNAL(triggered()), this, SLOT(openfile())); openfolderAct = new QAction(QIcon(IMAGE_OPENFOLDER), tr("Open Folder"), this); @@ -426,6 +428,14 @@ QModelIndexList SharedFilesDialog::getRemoteSelected() return proxyList; } +void SharedFilesDialog::createCollectionFile() +{ + /* call back to the model (which does all the interfacing? */ + + std::cerr << "Creating a collection file!" << std::endl; + QModelIndexList lst = getLocalSelected(); + localModel->createCollectionFile(lst); +} void SharedFilesDialog::downloadRemoteSelected() { /* call back to the model (which does all the interfacing? */ @@ -762,6 +772,8 @@ void SharedFilesDialog::sharedDirTreeWidgetContextMenu( QPoint point ) switch (type) { case DIR_TYPE_DIR: contextMnu.addAction(openfolderAct); + contextMnu.addSeparator(); + contextMnu.addAction(createcollectionfileAct) ; break; case DIR_TYPE_FILE: contextMnu.addAction(openfileAct); @@ -770,6 +782,8 @@ void SharedFilesDialog::sharedDirTreeWidgetContextMenu( QPoint point ) // contextMnu.addAction(copylinklocalhtmlAct); contextMnu.addAction(sendlinkAct); // contextMnu.addAction(sendhtmllinkAct); + contextMnu.addSeparator(); + contextMnu.addAction(createcollectionfileAct) ; contextMnu.addSeparator(); #ifdef RS_USE_LINKS contextMnu.addAction(sendlinkCloudAct); diff --git a/retroshare-gui/src/gui/SharedFilesDialog.h b/retroshare-gui/src/gui/SharedFilesDialog.h index 05a3f48e2..8894a46a9 100644 --- a/retroshare-gui/src/gui/SharedFilesDialog.h +++ b/retroshare-gui/src/gui/SharedFilesDialog.h @@ -58,6 +58,7 @@ private slots: void sharedDirTreeWidgetContextMenu( QPoint point ); void downloadRemoteSelected(); + void createCollectionFile(); void addMsgRemoteSelected(); void copyLinkRemote(); @@ -115,6 +116,7 @@ private: /** Defines the actions for the context menu for QTreeWidget */ QAction* openfileAct; + QAction* createcollectionfileAct; QAction* openfolderAct; QAction* copyremotelinkAct; QAction* copylinklocalAct; diff --git a/retroshare-gui/src/gui/TransfersDialog.cpp b/retroshare-gui/src/gui/TransfersDialog.cpp index 55fde595c..962ca5a44 100644 --- a/retroshare-gui/src/gui/TransfersDialog.cpp +++ b/retroshare-gui/src/gui/TransfersDialog.cpp @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include @@ -1402,7 +1402,7 @@ void TransfersDialog::openFolderTransfer() /* open folder with a suitable application */ qinfo.setFile(QString::fromUtf8(path.c_str())); if (qinfo.exists() && qinfo.isDir()) { - if (!QDesktopServices::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { std::cerr << "openFolderTransfer(): can't open folder " << path << std::endl; } } @@ -1438,7 +1438,7 @@ void TransfersDialog::previewTransfer() } #ifndef WIN32 - if (!QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromUtf8(path.c_str())))) + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(QString::fromUtf8(path.c_str())))) QMessageBox::warning(this, tr("File preview"), tr("File %1 preview failed.").arg(QString::fromUtf8(path.c_str()))); #else /* open or preview them with a suitable application */ @@ -1446,7 +1446,7 @@ void TransfersDialog::previewTransfer() if (complete) { qinfo.setFile(QString::fromUtf8(path.c_str())); if (qinfo.exists()) { - if (!QDesktopServices::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { std::cerr << "previewTransfer(): can't preview file " << path << std::endl; } } @@ -1456,7 +1456,7 @@ void TransfersDialog::previewTransfer() if (QFile::link(QString::fromUtf8(path.c_str()), linkName)) { qinfo.setFile(linkName); if (qinfo.exists()) { - if (!QDesktopServices::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { std::cerr << "previewTransfer(): can't preview file " << path << std::endl; } } @@ -1495,7 +1495,7 @@ void TransfersDialog::openTransfer() QFileInfo qinfo; qinfo.setFile(QString::fromUtf8(path.c_str())); if (qinfo.exists()) { - if (!QDesktopServices::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { + if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { std::cerr << "openTransfer(): can't open file " << path << std::endl; } } diff --git a/retroshare-gui/src/gui/common/RsCollectionFile.cpp b/retroshare-gui/src/gui/common/RsCollectionFile.cpp new file mode 100644 index 000000000..6603d1d68 --- /dev/null +++ b/retroshare-gui/src/gui/common/RsCollectionFile.cpp @@ -0,0 +1,184 @@ +/*************************************:*************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2011 - 2011 RetroShare Team + * + * Cyril Soler (csoler@users.sourceforge.net) + * + * 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 +#include + +#include "RsCollectionFile.h" + +#include +#include +#include +#include +#include +#include +#include + +const QString RsCollectionFile::ExtensionString = QString(".rscollection") ; + +RsCollectionFile::RsCollectionFile(const QString& filename) + : _xml_doc("RsCollection") +{ + QFile file(filename); + + if (!file.open(QIODevice::ReadOnly)) + { + std::cerr << "Cannot open file " << filename.toStdString() << " !!" << std::endl; + return; + } + + bool ok = _xml_doc.setContent(&file) ; + file.close(); + + if(!ok) + throw std::runtime_error("Error parsing xml file") ; +} + + +void RsCollectionFile::downloadFiles() const +{ + // print out the element names of all elements that are direct children + // of the outermost element. + QDomElement docElem = _xml_doc.documentElement(); + + std::vector dlinfos ; + recursCollectDLinfos(docElem,dlinfos,QString()) ; + + QString msg(QObject::tr("About to download the following files:")+"

") ; + + for(uint32_t i=0;i" ; + + QString dldir = QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()) ; + + if(QMessageBox::Ok == QMessageBox::critical(NULL,QObject::tr("About to download these files"),msg) ) + { + std::cerr << "downloading all these files:" << std::endl; + + for(uint32_t i=0;i "+cleanPath) ; + + rsFiles->FileRequest(dlinfos[i].name.toUtf8().constData(), dlinfos[i].hash.toUtf8().constData(), dlinfos[i].size, cleanPath.toUtf8().constData(), RS_FILE_HINTS_NETWORK_WIDE, std::list()); + } + } +} + +void RsCollectionFile::recursCollectDLinfos(const QDomElement& e,std::vector& dlinfos,const QString& current_path) const +{ + QDomNode n = e.firstChild() ; + + std::cerr << "Parsing element " << e.tagName().toStdString() << std::endl; + + while(!n.isNull()) + { + QDomElement ee = n.toElement(); // try to convert the node to an element. + + std::cerr << " Seeing child " << ee.tagName().toStdString() << std::endl; + + if(ee.tagName() == QString("File")) + { + DLinfo i ; + i.hash = ee.attribute(QString("sha1")) ; + i.name = ee.attribute(QString("name")) ; + i.size = ee.attribute(QString("size")).toULongLong() ; + i.path = current_path ; + + dlinfos.push_back(i) ; + } + else if(ee.tagName() == QString("Directory")) + recursCollectDLinfos(ee,dlinfos,current_path + "/" + ee.attribute(QString("name"))) ; + + n = n.nextSibling() ; + } +} + + +void RsCollectionFile::recursAddElements(QDomDocument& doc,const DirDetails& details,QDomElement& e) const +{ + if (details.type == DIR_TYPE_FILE) + { + QDomElement f = doc.createElement("File") ; + + f.setAttribute(QString("name"),QString::fromUtf8(details.name.c_str())) ; + f.setAttribute(QString("sha1"),QString::fromStdString(details.hash)) ; + f.setAttribute(QString("size"),QString::number(details.count)) ; + + e.appendChild(f) ; + } + else if (details.type == DIR_TYPE_DIR) + { + QDomElement d = doc.createElement("Directory") ; + + d.setAttribute(QString("name"),QString::fromUtf8(details.name.c_str())) ; + + for (std::list::const_iterator it = details.children.begin(); it != details.children.end(); it++) + { + if (!it->ref) + continue; + + DirDetails subDirDetails; + uint32_t flags = DIR_FLAGS_CHILDREN | DIR_FLAGS_LOCAL; + + if (!rsFiles->RequestDirDetails(it->ref, subDirDetails, flags)) + continue; + + recursAddElements(doc,subDirDetails,d) ; + } + + e.appendChild(d) ; + } +} + +RsCollectionFile::RsCollectionFile(const std::vector& file_infos) + : _xml_doc("RsCollection") +{ + QDomElement root = _xml_doc.createElement("RsCollection"); + _xml_doc.appendChild(root); + + for(uint32_t i = 0;i +#include +#include + +class QDomElement ; + +class RsCollectionFile +{ + public: + static const QString ExtensionString ; + + // Loads file from disk. + RsCollectionFile(const QString& filename) ; + + // create from list of files and directories + RsCollectionFile(const std::vector& file_entries) ; + + // Save to disk + void save(const QString& filename) const ; + + // Download the content. + void downloadFiles() const ; + + private: + struct DLinfo + { + QString name ; + qulonglong size ; + QString path ; + QString hash ; + }; + + void recursAddElements(QDomDocument&,const DirDetails&,QDomElement&) const ; + void recursCollectDLinfos(const QDomElement&,std::vector& dlinfos,const QString& current_dir) const ; + + QDomDocument _xml_doc ; +}; + diff --git a/retroshare-gui/src/gui/common/RsUrlHandler.cpp b/retroshare-gui/src/gui/common/RsUrlHandler.cpp new file mode 100644 index 000000000..e0019f952 --- /dev/null +++ b/retroshare-gui/src/gui/common/RsUrlHandler.cpp @@ -0,0 +1,48 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2011, Cyril Soler (csoler@users.sourceforge.net) + * + * 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 +#include +#include +#include +#include "RsCollectionFile.h" +#include "RsUrlHandler.h" + +bool RsUrlHandler::openUrl(const QUrl& url) +{ + if(url.scheme() == QString("file") && url.toLocalFile().endsWith(RsCollectionFile::ExtensionString)) + { + try + { + RsCollectionFile(url.toLocalFile().toUtf8().constData()).downloadFiles() ; + } + catch(std::runtime_error& e) + { + QMessageBox::warning(NULL,QObject::tr("Treatment of collection file has failed."),QObject::tr("The collection file ") + url.toLocalFile() + QObject::tr(" could not be openned. Reported error is: ") + QString::fromStdString(e.what())) ; + return false ; + } + } + else + return QDesktopServices::openUrl(url) ; +} + + + diff --git a/retroshare-gui/src/gui/common/RsUrlHandler.h b/retroshare-gui/src/gui/common/RsUrlHandler.h new file mode 100644 index 000000000..ff7463925 --- /dev/null +++ b/retroshare-gui/src/gui/common/RsUrlHandler.h @@ -0,0 +1,32 @@ +/**************************************************************** + * RetroShare is distributed under the following license: + * + * Copyright (C) 2011 Cyril Soler (csoler@users.sourceforge.net) + * + * 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. + ****************************************************************/ + +// This class overrides the desktop url handling. It's used to have e.g. rsCollection files +// openned by retroshare. Other urls are passed on to the system. +// +class QUrl ; + +class RsUrlHandler +{ + public: + static bool openUrl(const QUrl& url) ; +}; +