Merge branch 'master' of github.com:RetroShare/RetroShare

This commit is contained in:
Gioacchino Mazzurco 2023-10-13 18:56:00 +02:00
commit ededce7bd6
No known key found for this signature in database
GPG Key ID: A1FBCA3872E87051
78 changed files with 1362 additions and 516 deletions

4
.gitmodules vendored
View File

@ -31,8 +31,8 @@
branch = master branch = master
[submodule "libretroshare"] [submodule "libretroshare"]
path = libretroshare path = libretroshare
url = ../libretroshare url = https://github.com/RetroShare/libretroshare.git
branch = master branch = master
[submodule "retroshare-webui"] [submodule "retroshare-webui"]
path = retroshare-webui path = retroshare-webui
url = ../RSNewWebUI url = https://github.com/RetroShare/RSNewWebUI.git

@ -1 +1 @@
Subproject commit 659423769541169457c41f71c8a038e2d64ba079 Subproject commit 2ddc86fb575a61170f4c06a00152e3e7dc74c8f4

@ -1 +1 @@
Subproject commit 8c02b54e4d16e38b28e77263a0b1570c50df4c99 Subproject commit 3bb5a2b282949bc170dcff6141424cb095e4bb7b

View File

@ -1151,10 +1151,10 @@ RsFeedReaderErrorState p3FeedReaderThread::processMsg(const RsFeedReaderFeed &fe
if (isRunning()) { if (isRunning()) {
/* process description */ /* process description */
bool processPostedFirstImage = (feed.flag & RS_FEED_FLAG_POSTED_FIRST_IMAGE) ? TRUE : FALSE; bool processPostedFirstImage = (feed.flag & RS_FEED_FLAG_POSTED_FIRST_IMAGE) ? true : false;
if (!msg->attachmentBinary.empty()) { if (!msg->attachmentBinary.empty()) {
/* use attachment as image */ /* use attachment as image */
processPostedFirstImage = FALSE; processPostedFirstImage = false;
} }
//long todo; // encoding //long todo; // encoding

View File

@ -86,6 +86,18 @@ const int SearchDialog::FILETYPE_IDX_DIRECTORY = 8;
QMap<int, QString> * SearchDialog::FileTypeExtensionMap = new QMap<int, QString>(); QMap<int, QString> * SearchDialog::FileTypeExtensionMap = new QMap<int, QString>();
bool SearchDialog::initialised = false; bool SearchDialog::initialised = false;
struct SearchDialog::FileDetail
{
public:
RsPeerId id;
std::string name;
RsFileHash hash;
std::string path;
uint64_t size;
uint32_t mtime;
uint32_t rank;
};
/** Constructor */ /** Constructor */
SearchDialog::SearchDialog(QWidget *parent) SearchDialog::SearchDialog(QWidget *parent)
: MainPage(parent), : MainPage(parent),
@ -265,6 +277,8 @@ void SearchDialog::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
f.hash = fe->mResults[i].fHash; f.hash = fe->mResults[i].fHash;
f.name = fe->mResults[i].fName; f.name = fe->mResults[i].fName;
f.size = fe->mResults[i].fSize; f.size = fe->mResults[i].fSize;
f.mtime = 0; // zero what's not available, otherwise we'll get some random values displayed.
f.rank = 0;
updateFiles(fe->mRequestId,f); updateFiles(fe->mRequestId,f);
} }
@ -966,7 +980,7 @@ void SearchDialog::searchKeywords(const QString& keywords)
} }
} }
void SearchDialog::updateFiles(qulonglong search_id,FileDetail file) void SearchDialog::updateFiles(qulonglong search_id,const FileDetail& file)
{ {
searchResultsQueue.push_back(std::pair<qulonglong,FileDetail>(search_id,file)) ; searchResultsQueue.push_back(std::pair<qulonglong,FileDetail>(search_id,file)) ;
@ -1320,8 +1334,8 @@ void SearchDialog::insertFile(qulonglong searchId, const FileDetail& file, int s
item->setText(SR_SIZE_COL, QString::number(file.size)); item->setText(SR_SIZE_COL, QString::number(file.size));
item->setData(SR_SIZE_COL, ROLE_SORT, (qulonglong) file.size); item->setData(SR_SIZE_COL, ROLE_SORT, (qulonglong) file.size);
item->setText(SR_AGE_COL, QString::number(file.age)); item->setText(SR_AGE_COL, QString::number(file.mtime));
item->setData(SR_AGE_COL, ROLE_SORT, file.age); item->setData(SR_AGE_COL, ROLE_SORT, file.mtime);
item->setTextAlignment( SR_SIZE_COL, Qt::AlignRight ); item->setTextAlignment( SR_SIZE_COL, Qt::AlignRight );
int friendSource = 0; int friendSource = 0;
int anonymousSource = 0; int anonymousSource = 0;
@ -1396,21 +1410,21 @@ void SearchDialog::resultsToTree(const QString& txt,qulonglong searchId, const s
std::list<DirDetails>::const_iterator it; std::list<DirDetails>::const_iterator it;
for(it = results.begin(); it != results.end(); ++it) for(it = results.begin(); it != results.end(); ++it)
if (it->type == DIR_TYPE_FILE) { if (it->type == DIR_TYPE_FILE)
{
FileDetail fd; FileDetail fd;
fd.id = it->id; fd.id = it->id;
fd.name = it->name; fd.name = it->name;
fd.hash = it->hash; fd.hash = it->hash;
fd.path = it->path; fd.path = it->path;
fd.size = it->size; fd.size = it->size;
fd.age = it->mtime; fd.mtime= it->mtime;
fd.rank = 0; fd.rank = 0;
insertFile(searchId,fd, FRIEND_SEARCH); insertFile(searchId,fd, FRIEND_SEARCH);
} else if (it->type == DIR_TYPE_DIR) { }
// insertDirectory(txt, searchId, *it, NULL); else if (it->type == DIR_TYPE_DIR)
insertDirectory(txt, searchId, *it); insertDirectory(txt, searchId, *it);
}
ui.searchResultWidget->setSortingEnabled(true); ui.searchResultWidget->setSortingEnabled(true);
} }

View File

@ -43,6 +43,7 @@ class SearchDialog : public MainPage
Q_PROPERTY(QColor textColorLowSources READ textColorLowSources WRITE setTextColorLowSources) Q_PROPERTY(QColor textColorLowSources READ textColorLowSources WRITE setTextColorLowSources)
Q_PROPERTY(QColor textColorHighSources READ textColorHighSources WRITE setTextColorHighSources) Q_PROPERTY(QColor textColorHighSources READ textColorHighSources WRITE setTextColorHighSources)
struct FileDetail; // useful structure to store search results.
public: public:
/** Default Constructor */ /** Default Constructor */
SearchDialog(QWidget *parent = 0); SearchDialog(QWidget *parent = 0);
@ -63,8 +64,7 @@ public:
void setTextColorLowSources(QColor color) { mTextColorLowSources = color; } void setTextColorLowSources(QColor color) { mTextColorLowSources = color; }
void setTextColorHighSources(QColor color) { mTextColorHighSources = color; } void setTextColorHighSources(QColor color) { mTextColorHighSources = color; }
public slots: void updateFiles(qulonglong request_id, const FileDetail& file) ;
void updateFiles(qulonglong request_id,FileDetail file) ;
private slots: private slots:

View File

@ -442,7 +442,7 @@ public:
{ {
QString strPath = QString::fromUtf8(fileInfo.path.c_str()); QString strPath = QString::fromUtf8(fileInfo.path.c_str());
QString strPathAfterDL = strPath; QString strPathAfterDL = strPath;
strPathAfterDL.replace(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()),""); strPathAfterDL.replace(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()),"[Download Dir]");
return QVariant(strPathAfterDL); return QVariant(strPathAfterDL);
} }
@ -2074,22 +2074,23 @@ void TransfersDialog::dlOpenFolder()
break; break;
} }
openFolder(info);
}
void TransfersDialog::openFolder(const FileInfo& info)
{
/* make path for downloaded or downloading files */ /* make path for downloaded or downloading files */
QFileInfo qinfo; QDir directory;
std::string path;
if (info.downloadStatus == FT_STATE_COMPLETE) { if (info.downloadStatus == FT_STATE_COMPLETE)
path = info.path; directory = QFileInfo(QString::fromStdString(info.path)).absoluteDir().path();
} else { else
path = rsFiles->getPartialsDirectory(); directory = QDir(QString::fromStdString(rsFiles->getPartialsDirectory()));
}
/* open folder with a suitable application */ /* open folder with a suitable application */
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists() && qinfo.isDir()) { if (directory.exists() && !RsUrlHandler::openUrl(QUrl::fromLocalFile(directory.path())))
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { std::cerr << "dlOpenFolder(): can't open folder " << directory.path().toStdString() << std::endl;
std::cerr << "dlOpenFolder(): can't open folder " << path << std::endl;
}
}
} }
void TransfersDialog::ulOpenFolder() void TransfersDialog::ulOpenFolder()
@ -2104,19 +2105,7 @@ void TransfersDialog::ulOpenFolder()
break; break;
} }
/* make path for uploading files */ openFolder(info);
QFileInfo qinfo;
std::string path;
path = info.path.substr(0,info.path.length()-info.fname.length());
/* open folder with a suitable application */
qinfo.setFile(QString::fromUtf8(path.c_str()));
if (qinfo.exists() && qinfo.isDir()) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) {
std::cerr << "ulOpenFolder(): can't open folder " << path << std::endl;
}
}
} }
void TransfersDialog::dlPreviewFile() void TransfersDialog::dlPreviewFile()
@ -2139,7 +2128,7 @@ void TransfersDialog::dlPreviewFile()
/* make path for downloaded or downloading files */ /* make path for downloaded or downloading files */
QFileInfo fileInfo; QFileInfo fileInfo;
if (info.downloadStatus == FT_STATE_COMPLETE) { if (info.downloadStatus == FT_STATE_COMPLETE) {
fileInfo = QFileInfo(QString::fromUtf8(info.path.c_str()), QString::fromUtf8(info.fname.c_str())); fileInfo = QFileInfo(QString::fromUtf8(info.path.c_str()));
} else { } else {
fileInfo = QFileInfo(QString::fromUtf8(rsFiles->getPartialsDirectory().c_str()), QString::fromUtf8(info.hash.toStdString().c_str())); fileInfo = QFileInfo(QString::fromUtf8(rsFiles->getPartialsDirectory().c_str()), QString::fromUtf8(info.hash.toStdString().c_str()));
@ -2204,7 +2193,7 @@ void TransfersDialog::dlOpenFile()
/* make path for downloaded or downloading files */ /* make path for downloaded or downloading files */
std::string path; std::string path;
if (info.downloadStatus == FT_STATE_COMPLETE) { if (info.downloadStatus == FT_STATE_COMPLETE) {
path = info.path + "/" + info.fname; path = info.path ;
/* open file with a suitable application */ /* open file with a suitable application */
QFileInfo qinfo; QFileInfo qinfo;
@ -2244,6 +2233,10 @@ void TransfersDialog::chunkStreaming()
} }
void TransfersDialog::chunkRandom() void TransfersDialog::chunkRandom()
{ {
#ifdef WINDOWS_SYS
if(QMessageBox::Yes != QMessageBox::warning(nullptr,tr("Warning"),tr("On Windows systems, writing in the middle of large empty files may hang the software for several seconds. Do you want to use this option anyway?"),QMessageBox::Yes,QMessageBox::No))
return;
#endif
setChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_RANDOM) ; setChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_RANDOM) ;
} }
void TransfersDialog::chunkProgressive() void TransfersDialog::chunkProgressive()

View File

@ -173,6 +173,7 @@ signals:
void playFiles(QStringList files); void playFiles(QStringList files);
private: private:
void openFolder(const FileInfo& info);
RsDownloadListModel *DLListModel; RsDownloadListModel *DLListModel;
QSortFilterProxyModel *DLLFilterModel; QSortFilterProxyModel *DLLFilterModel;

View File

@ -83,7 +83,7 @@ NetworkDialog::NetworkDialog(QWidget */*parent*/)
ui.connectTreeWidget->setUpdatesEnabled(true); ui.connectTreeWidget->setUpdatesEnabled(true);
ui.connectTreeWidget->setSortingEnabled(true); ui.connectTreeWidget->setSortingEnabled(true);
ui.connectTreeWidget->setSelectionBehavior(QAbstractItemView::SelectRows); ui.connectTreeWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui.connectTreeWidget->setSelectionMode(QAbstractItemView::SingleSelection); ui.connectTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(ui.connectTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( connectTreeWidgetCostumPopupMenu( QPoint ) ) ); connect(ui.connectTreeWidget, SIGNAL( customContextMenuRequested( QPoint ) ), this, SLOT( connectTreeWidgetCostumPopupMenu( QPoint ) ) );
connect(ui.connectTreeWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(peerdetails())); connect(ui.connectTreeWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(peerdetails()));
@ -117,24 +117,12 @@ void NetworkDialog::connectTreeWidgetCostumPopupMenu( QPoint /*point*/ )
{ {
return; return;
} }
QMenu *contextMnu = new QMenu; QMenu *contextMnu = new QMenu;
RsPgpId peer_id(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), pgpid_item_model::PGP_ITEM_MODEL_COLUMN_PEERID)).toString().toStdString()) ;
// That's what context menus are made for
RsPeerDetails detail;
if(!rsPeers->getGPGDetails(peer_id, detail)) // that is not suppose to fail.
return ;
if(peer_id == rsPeers->getGPGOwnId())
contextMnu->addAction(QIcon(), tr("Export/create a new node"), this, SLOT(on_actionExportKey_activated()));
contextMnu->addAction(QIcon(IMAGE_PEERDETAILS), tr("Profile details..."), this, SLOT(peerdetails())); contextMnu->addAction(QIcon(IMAGE_PEERDETAILS), tr("Profile details..."), this, SLOT(peerdetails()));
contextMnu->addSeparator() ; contextMnu->addSeparator() ;
contextMnu->addAction(QIcon(), tr("Remove unused keys..."), this, SLOT(removeUnusedKeys())); contextMnu->addAction(QIcon(), tr("Remove unused keys..."), this, SLOT(removeUnusedKeys()));
contextMnu->addAction(QIcon(), tr("Remove this key"), this, SLOT(removeSelectedKeys())); contextMnu->addAction(QIcon(), tr("Remove this key"), this, SLOT(removeSelectedKeys()));
contextMnu->exec(QCursor::pos()); contextMnu->exec(QCursor::pos());
} }
@ -177,11 +165,34 @@ void NetworkDialog::removeSelectedKeys()
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes(); QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty()) if(l.empty())
return; return;
std::set<RsPgpId> selected; std::set<RsPgpId> selected;
selected.insert(RsPgpId(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l.begin()->row(), pgpid_item_model::PGP_ITEM_MODEL_COLUMN_PEERID)).toString().toStdString()));
removeKeys(selected); std::set<RsPgpId> friends;
for (int i = 0; i < l.size(); i++)
{
RsPgpId peer_id = RsPgpId(ui.connectTreeWidget->model()->data(ui.connectTreeWidget->model()->index(l[i].row(), pgpid_item_model::PGP_ITEM_MODEL_COLUMN_PEERID)).toString().toStdString());
RsPeerDetails details ;
if(rsPeers->getGPGDetails(peer_id,details))
{
if(details.accept_connection)
friends.insert(peer_id);
else
selected.insert(peer_id);
}
}
if(!friends.empty())
{
if ((QMessageBox::question(this, "RetroShare", tr("You have selected %1 accepted peers among others,\n Are you sure you want to un-friend them?").arg(friends.size()), QMessageBox::Yes|QMessageBox::No, QMessageBox::Yes)) == QMessageBox::Yes)
{
for(std::set<RsPgpId>::const_iterator it(friends.begin());it!=friends.end();++it)
rsPeers->removeFriend(*it);
selected.insert(friends.begin(),friends.end());
}
}
if(!selected.empty())
removeKeys(selected);
updateDisplay();
} }
void NetworkDialog::removeKeys(std::set<RsPgpId> selected) void NetworkDialog::removeKeys(std::set<RsPgpId> selected)

View File

@ -74,7 +74,7 @@ BasePostedItem::BasePostedItem( FeedHolder *feedHolder, uint32_t feedId
BasePostedItem::~BasePostedItem() BasePostedItem::~BasePostedItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(200); auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(200);
while( (mIsLoadingGroup || mIsLoadingMessage || mIsLoadingComment) while( (mIsLoadingGroup || mIsLoadingMessage || mIsLoadingComment)
&& std::chrono::steady_clock::now() < timeout) && std::chrono::steady_clock::now() < timeout)
{ {

View File

@ -22,6 +22,7 @@
#include <QMenu> #include <QMenu>
#include <QSignalMapper> #include <QSignalMapper>
#include <QPainter> #include <QPainter>
#include <QClipboard>
#include <QMessageBox> #include <QMessageBox>
#include "retroshare/rsgxscircles.h" #include "retroshare/rsgxscircles.h"
@ -72,6 +73,7 @@ static const int POSTED_TABS_POSTS = 1;
// //
#define IMAGE_COPYLINK ":/images/copyrslink.png" #define IMAGE_COPYLINK ":/images/copyrslink.png"
#define IMAGE_AUTHOR ":/images/user/personal64.png" #define IMAGE_AUTHOR ":/images/user/personal64.png"
#define IMAGE_COPYHTTP ":/images/emblem-web.png"
Q_DECLARE_METATYPE(RsPostedPost); Q_DECLARE_METATYPE(RsPostedPost);
@ -340,7 +342,18 @@ void PostedListWidgetWithModel::postContextMenu(const QPoint& point)
// 2 - generate the menu for that post. // 2 - generate the menu for that post.
RsPostedPost post = index.data(Qt::UserRole).value<RsPostedPost>() ;
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()))->setData(index); menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()))->setData(index);
QByteArray urlarray(post.mLink.c_str());
QUrl url = QUrl::fromEncoded(urlarray.trimmed());
std::cerr << "Using link: \"" << post.mLink << "\"" << std::endl;
if(url.scheme()=="http" || url.scheme()=="https")
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYHTTP), tr("Copy http Link"), this, SLOT(copyHttpLink()))->setData(index);
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_AUTHOR), tr("Show author in People tab"), this, SLOT(showAuthorInPeople()))->setData(index); menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_AUTHOR), tr("Show author in People tab"), this, SLOT(showAuthorInPeople()))->setData(index);
#ifdef TODO #ifdef TODO
@ -456,6 +469,31 @@ void PostedListWidgetWithModel::showAuthorInPeople()
MainWindow::showWindow(MainWindow::People); MainWindow::showWindow(MainWindow::People);
idDialog->navigate(RsGxsId(post.mMeta.mAuthorId)); idDialog->navigate(RsGxsId(post.mMeta.mAuthorId));
} }
void PostedListWidgetWithModel::copyHttpLink()
{
try
{
if (groupId().isNull())
throw std::runtime_error("No channel currently selected!");
QModelIndex index = qobject_cast<QAction*>(QObject::sender())->data().toModelIndex();
if(!index.isValid())
throw std::runtime_error("No post under mouse!");
RsPostedPost post = index.data(Qt::UserRole).value<RsPostedPost>() ;
if(post.mMeta.mMsgId.isNull())
throw std::runtime_error("Post has empty MsgId!");
QApplication::clipboard()->setText(QString::fromStdString(post.mLink)) ;
QMessageBox::information(NULL,tr("information"),tr("The Retrohare link was copied to your clipboard.")) ;
}
catch(std::exception& e)
{
QMessageBox::critical(NULL,tr("Link creation error"),tr("Link could not be created: ")+e.what());
}
}
void PostedListWidgetWithModel::copyMessageLink() void PostedListWidgetWithModel::copyMessageLink()
{ {
try try
@ -823,6 +861,7 @@ void PostedListWidgetWithModel::insertBoardDetails(const RsPostedGroup& group)
ui->subscribeToolButton->setText(tr("Subscribe")); ui->subscribeToolButton->setText(tr("Subscribe"));
ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount)); ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount));
ui->poplabel->setText(QString::number(group.mMeta.mPop));
if(group.mMeta.mLastPost==0) if(group.mMeta.mLastPost==0)
ui->infoLastPost->setText(tr("Never")); ui->infoLastPost->setText(tr("Never"));

View File

@ -147,6 +147,7 @@ private slots:
void settingsChanged(); void settingsChanged();
void postPostLoad(); void postPostLoad();
void copyMessageLink(); void copyMessageLink();
void copyHttpLink();
void nextPosts(); void nextPosts();
void prevPosts(); void prevPosts();
void filterItems(QString s); void filterItems(QString s);

View File

@ -54,7 +54,7 @@
<string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt; <string notr="true">&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt; &lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; } p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt; &lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;Description&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> &lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'MS Shell Dlg 2'; font-size:8pt;&quot;&gt;Description&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<property name="textInteractionFlags"> <property name="textInteractionFlags">
@ -84,8 +84,11 @@ p, li { white-space: pre-wrap; }
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Maximum number of data items (including posts, comments, votes) across friend nodes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text"> <property name="text">
<string>Contributions:</string> <string>Items (at friends):</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -179,6 +182,9 @@ p, li { white-space: pre-wrap; }
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>
<property name="toolTip">
<string>Number of subscribed friend nodes</string>
</property>
<property name="text"> <property name="text">
<string>Popularity:</string> <string>Popularity:</string>
</property> </property>
@ -615,8 +621,8 @@ p, li { white-space: pre-wrap; }
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../icons.qrc"/>
<include location="Posted_images.qrc"/> <include location="Posted_images.qrc"/>
<include location="../icons.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -91,7 +91,8 @@ class RSHumanReadableAgeDelegate: public RSHumanReadableDelegate
QStyleOptionViewItem opt(option) ; QStyleOptionViewItem opt(option) ;
setPainterOptions(painter,opt,index) ; setPainterOptions(painter,opt,index) ;
painter->drawText(opt.rect, Qt::AlignCenter, misc::timeRelativeToNow(index.data().toLongLong())) ; if(index.data().toLongLong() > 0) // no date is present.
painter->drawText(opt.rect, Qt::AlignCenter, misc::timeRelativeToNow(index.data().toLongLong())) ;
} }
}; };

View File

@ -0,0 +1,41 @@
/*******************************************************************************
* gui/TheWire/CustomFrame.cpp *
* *
* Copyright (c) 2012-2020 Robert Fernie <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#include "CustomFrame.h"
#include <QPainter>
// Constructor
CustomFrame::CustomFrame(QWidget *parent) : QFrame(parent)
{
// Any initializations for this frame.
}
// Overriding the inbuilt paint function
void CustomFrame::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
QPainter painter(this);
painter.drawPixmap(rect(), backgroundImage);
}
// Function to set the member variable 'backgroundImage'
void CustomFrame::setPixmap(QPixmap pixmap){
backgroundImage = pixmap;
}

View File

@ -0,0 +1,44 @@
/*******************************************************************************
* gui/TheWire/CustomFrame.h *
* *
* Copyright (c) 2012-2020 Robert Fernie <retroshare.project@gmail.com> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU Affero General Public License as *
* published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. *
* *
* You should have received a copy of the GNU Affero General Public License *
* along with this program. If not, see <https://www.gnu.org/licenses/>. *
* *
*******************************************************************************/
#ifndef CUSTOMFRAMEH_H
#define CUSTOMFRAMEH_H
#include <QFrame>
#include <QPixmap>
// This class is made to implement the background image in a Qframe or any widget
class CustomFrame : public QFrame
{
Q_OBJECT
public:
explicit CustomFrame(QWidget *parent = nullptr);
void setPixmap(QPixmap pixmap);
protected:
void paintEvent(QPaintEvent *event) override;
private:
QPixmap backgroundImage;
};
#endif //CUSTOMFRAMEH_H

View File

@ -767,7 +767,6 @@
<property name="font"> <property name="font">
<font> <font>
<pointsize>12</pointsize> <pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold> <bold>true</bold>
</font> </font>
</property> </property>

View File

@ -24,86 +24,149 @@
#include <QBuffer> #include <QBuffer>
#include "PulseViewGroup.h" #include "PulseViewGroup.h"
#include "CustomFrame.h"
#include "WireGroupDialog.h"
#include "gui/gxs/GxsIdDetails.h" #include "gui/gxs/GxsIdDetails.h"
#include "gui/common/FilesDefs.h" #include "gui/common/FilesDefs.h"
#include "util/DateTime.h" #include "util/DateTime.h"
Q_DECLARE_METATYPE(RsWireGroup)
/** Constructor */ /** Constructor */
PulseViewGroup::PulseViewGroup(PulseViewHolder *holder, RsWireGroupSPtr group) PulseViewGroup::PulseViewGroup(PulseViewHolder *holder, RsWireGroupSPtr group)
:PulseViewItem(holder), mGroup(group) :PulseViewItem(holder), mGroup(group)
{ {
setupUi(this); setupUi(this);
setAttribute ( Qt::WA_DeleteOnClose, true ); setAttribute ( Qt::WA_DeleteOnClose, true );
setup(); setup();
connect(editButton, SIGNAL(clicked()), this, SLOT(editProfile()));
} }
void PulseViewGroup::setup() void PulseViewGroup::setup()
{ {
if (mGroup) { if (mGroup) {
connect(followButton, SIGNAL(clicked()), this, SLOT(actionFollow())); connect(followButton, SIGNAL(clicked()), this, SLOT(actionFollow()));
label_groupName->setText("@" + QString::fromStdString(mGroup->mMeta.mGroupName)); label_groupName->setText("@" + QString::fromStdString(mGroup->mMeta.mGroupName));
label_authorName->setText(BoldString(QString::fromStdString(mGroup->mMeta.mAuthorId.toStdString()))); label_authorName->setText(BoldString(QString::fromStdString(mGroup->mMeta.mAuthorId.toStdString())));
label_date->setText(DateTime::formatDateTime(mGroup->mMeta.mPublishTs)); label_date->setText(DateTime::formatDateTime(mGroup->mMeta.mPublishTs));
label_tagline->setText(QString::fromStdString(mGroup->mTagline)); label_tagline->setText(QString::fromStdString(mGroup->mTagline));
label_location->setText(QString::fromStdString(mGroup->mLocation)); label_location->setText(QString::fromStdString(mGroup->mLocation));
// need to draw mGroup->mMasthead, as background to headshot.
// TODO frame_headerBackground->setBackground()
if (mGroup->mHeadshot.mData) if (mGroup->mMasthead.mData)
{ {
QPixmap pixmap; QPixmap pixmap;
if (GxsIdDetails::loadPixmapFromData( if (GxsIdDetails::loadPixmapFromData(
mGroup->mHeadshot.mData, mGroup->mMasthead.mData,
mGroup->mHeadshot.mSize, mGroup->mMasthead.mSize,
pixmap,GxsIdDetails::ORIGINAL)) pixmap, GxsIdDetails::ORIGINAL))
{ {
pixmap = pixmap.scaled(50,50); QSize frameSize = frame_masthead->size();
label_headshot->setPixmap(pixmap);
} // Scale the pixmap based on the frame size
} pixmap = pixmap.scaledToWidth(frameSize.width(), Qt::SmoothTransformation);
else frame_masthead->setPixmap(pixmap);
{ }
}
// Uncomment the below code for default background
// else
// {
// // Default pixmap
// QPixmap pixmap = FilesDefs::getPixmapFromQtResourcePath(":/icons/png/posted.png");
// QSize frameSize = frame_masthead->size();
// // Scale the pixmap based on the frame size
// pixmap = pixmap.scaled(frameSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
// frame_masthead->setPixmap(pixmap);
// }
if (mGroup->mHeadshot.mData)
{
QPixmap pixmap;
if (GxsIdDetails::loadPixmapFromData(
mGroup->mHeadshot.mData,
mGroup->mHeadshot.mSize,
pixmap,GxsIdDetails::ORIGINAL))
{
pixmap = pixmap.scaled(100,100, Qt::KeepAspectRatio, Qt::SmoothTransformation);
label_headshot->setPixmap(pixmap);
}
}
else
{
// default. // default.
QPixmap pixmap = FilesDefs::getPixmapFromQtResourcePath(":/icons/png/posted.png").scaled(50,50); QPixmap pixmap = FilesDefs::getPixmapFromQtResourcePath(":/icons/wire.png").scaled(100,100, Qt::KeepAspectRatio, Qt::SmoothTransformation);
label_headshot->setPixmap(pixmap); label_headshot->setPixmap(pixmap);
} }
if (mGroup->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED) if (mGroup->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED)
{ {
uint32_t pulses = mGroup->mGroupPulses + mGroup->mGroupReplies; uint32_t pulses = mGroup->mGroupPulses + mGroup->mGroupReplies;
uint32_t replies = mGroup->mRefReplies; uint32_t replies = mGroup->mRefReplies;
uint32_t republishes = mGroup->mRefRepublishes; uint32_t republishes = mGroup->mRefRepublishes;
uint32_t likes = mGroup->mRefLikes; uint32_t likes = mGroup->mRefLikes;
label_extra_pulses->setText(BoldString(ToNumberUnits(pulses))); label_extra_pulses->setText(BoldString(ToNumberUnits(pulses)));
label_extra_replies->setText(BoldString(ToNumberUnits(replies))); label_extra_replies->setText(BoldString(ToNumberUnits(replies)));
label_extra_republishes->setText(BoldString(ToNumberUnits(republishes))); label_extra_republishes->setText(BoldString(ToNumberUnits(republishes)));
label_extra_likes->setText(BoldString(ToNumberUnits(likes))); label_extra_likes->setText(BoldString(ToNumberUnits(likes)));
// hide follow. // hide follow.
widget_actions->setVisible(false); widget_actions->setVisible(false);
} }
else else
{ {
// hide stats. // hide stats.
widget_replies->setVisible(false); widget_replies->setVisible(false);
} }
}
setGroupSet();
}
void PulseViewGroup::setGroupSet()
{
if (mGroup->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_ADMIN) {
editButton->show();
}
else if (mGroup->mMeta.mSubscribeFlags & GXS_SERV::GROUP_SUBSCRIBE_SUBSCRIBED)
{
editButton->hide();
}
else
{
editButton->hide();
} }
} }
void PulseViewGroup::actionFollow() void PulseViewGroup::actionFollow()
{ {
RsGxsGroupId groupId = mGroup->mMeta.mGroupId; RsGxsGroupId groupId = mGroup->mMeta.mGroupId;
std::cerr << "PulseViewGroup::actionFollow() following "; std::cerr << "PulseViewGroup::actionFollow() following ";
std::cerr << groupId; std::cerr << groupId;
std::cerr << std::endl; std::cerr << std::endl;
if (mHolder) { if (mHolder) {
mHolder->PVHfollow(groupId); mHolder->PVHfollow(groupId);
} }
}
void PulseViewGroup::editProfile()
{
RsGxsGroupId groupId = mGroup->mMeta.mGroupId;
if (groupId.isNull())
{
std::cerr << "PulseViewGroup::editProfile() No Group selected";
std::cerr << std::endl;
return;
}
WireGroupDialog wireEdit(GxsGroupDialog::MODE_EDIT, groupId, this);
wireEdit.exec ();
} }

View File

@ -35,10 +35,13 @@ public:
private slots: private slots:
void actionFollow(); void actionFollow();
void editProfile();
protected: protected:
void setup(); void setup();
private:
void setGroupSet();
protected: protected:
RsWireGroupSPtr mGroup; RsWireGroupSPtr mGroup;

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>745</width> <width>746</width>
<height>483</height> <height>483</height>
</rect> </rect>
</property> </property>
@ -48,19 +48,37 @@
<property name="frameShadow"> <property name="frameShadow">
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<layout class="QVBoxLayout" name="plainFrame_VL"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QFrame" name="frame_headerBackground"> <widget class="CustomFrame" name="frame_masthead">
<layout class="QHBoxLayout" name="frame_headerBackground_HL"> <property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>700</width>
<height>135</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<spacer name="frame_headerBackground_LHSpacer"> <spacer name="widget_actions_RHSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>283</width> <width>277</width>
<height>20</height> <height>17</height>
</size> </size>
</property> </property>
</spacer> </spacer>
@ -79,19 +97,22 @@
<height>100</height> <height>100</height>
</size> </size>
</property> </property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text"> <property name="text">
<string>headshot</string> <string>headshot</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<spacer name="frame_headerBackground_RHSpacer"> <spacer name="widget_actions_LHSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" stdset="0"> <property name="sizeHint" stdset="0">
<size> <size>
<width>23</width> <width>281</width>
<height>20</height> <height>20</height>
</size> </size>
</property> </property>
@ -115,38 +136,6 @@
</size> </size>
</property> </property>
<layout class="QGridLayout" name="widget_header_GL"> <layout class="QGridLayout" name="widget_header_GL">
<item row="0" column="1" rowspan="3">
<spacer name="widget_header_HSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>518</width>
<height>58</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_groupName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#555753;&quot;&gt;@sidler_here&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_authorName"> <widget class="QLabel" name="label_authorName">
<property name="sizePolicy"> <property name="sizePolicy">
@ -182,6 +171,45 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="label_groupName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#555753;&quot;&gt;@sidler_here&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="3">
<spacer name="widget_header_HSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>518</width>
<height>58</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="2" rowspan="3">
<widget class="QPushButton" name="editButton">
<property name="text">
<string>Edit profile</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -206,41 +234,6 @@
</size> </size>
</property> </property>
<layout class="QGridLayout" name="widget_publish_GL"> <layout class="QGridLayout" name="widget_publish_GL">
<item row="1" column="2">
<widget class="QLabel" name="label_date">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#2e3436;&quot;&gt;3:58 AM · Apr 13, 2020 ·&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="1">
<spacer name="widget_publish_LHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="label_location"> <widget class="QLabel" name="label_location">
<property name="sizePolicy"> <property name="sizePolicy">
@ -260,19 +253,6 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="3">
<spacer name="widget_publish_RHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>2000</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0" colspan="4"> <item row="0" column="0" colspan="4">
<widget class="QLabel" name="label_tagline"> <widget class="QLabel" name="label_tagline">
<property name="sizePolicy"> <property name="sizePolicy">
@ -292,6 +272,54 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2">
<widget class="QLabel" name="label_date">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; color:#2e3436;&quot;&gt;3:58 AM · Apr 13, 2020 ·&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>
<item row="1" column="3">
<spacer name="widget_publish_RHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>2000</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1">
<spacer name="widget_publish_LHSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -538,10 +566,25 @@
</widget> </widget>
</item> </item>
</layout> </layout>
<zorder>widget_header</zorder>
<zorder>widget_publish</zorder>
<zorder>line_1</zorder>
<zorder>widget_replies</zorder>
<zorder>line_2</zorder>
<zorder>widget_actions</zorder>
<zorder>frame_masthead</zorder>
</widget> </widget>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>CustomFrame</class>
<extends>QFrame</extends>
<header>gui/TheWire/CustomFrame.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View File

@ -434,8 +434,8 @@
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="TheWire_images.qrc"/>
<include location="../icons.qrc"/> <include location="../icons.qrc"/>
<include location="TheWire_images.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -152,7 +152,7 @@ bool WireGroupDialog::service_updateGroup(const RsGroupMetaData &editedMeta)
std::cerr << "WireGroupDialog::service_updateGroup() submitting changes"; std::cerr << "WireGroupDialog::service_updateGroup() submitting changes";
std::cerr << std::endl; std::cerr << std::endl;
bool success = rsWire->updateGroup(grp); bool success = rsWire->editWire(grp);
// TODO updateGroup should refresh groupId or Data // TODO updateGroup should refresh groupId or Data
return success; return success;
} }

View File

@ -34,13 +34,19 @@ WireGroupExtra::~WireGroupExtra()
void WireGroupExtra::setUp() void WireGroupExtra::setUp()
{ {
connect(ui.pushButton_masthead, SIGNAL(clicked() ), this , SLOT(addMasthead())); connect(ui.pushButton_masthead, SIGNAL(clicked() ), this , SLOT(addMasthead()));
}
int desired_height = ui.pushButton_masthead->height() + ui.removeButton->height() + ui.lineEdit_Tagline->height();
int desired_width = 3/1.0 * desired_height + ui.lineEdit_Tagline->width();
ui.label_masthead->setFixedSize(desired_width, desired_height);
setMasthead(QPixmap());
}
void WireGroupExtra::addMasthead() void WireGroupExtra::addMasthead()
{ {
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Masthead"), 400, 100); QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Masthead"), 800, 600);
if (img.isNull()) if (img.isNull())
return; return;
@ -48,7 +54,6 @@ void WireGroupExtra::addMasthead()
setMasthead(img); setMasthead(img);
} }
void WireGroupExtra::setTagline(const std::string &str) void WireGroupExtra::setTagline(const std::string &str)
{ {
ui.lineEdit_Tagline->setText(QString::fromStdString(str)); ui.lineEdit_Tagline->setText(QString::fromStdString(str));
@ -61,8 +66,21 @@ void WireGroupExtra::setLocation(const std::string &str)
void WireGroupExtra::setMasthead(const QPixmap &pixmap) void WireGroupExtra::setMasthead(const QPixmap &pixmap)
{ {
mMasthead = pixmap; mMasthead = pixmap;
ui.label_masthead->setPixmap(mMasthead);
if (!mMasthead.isNull()) {
ui.label_masthead->setPicture(mMasthead);
ui.label_masthead->setToolTip(tr("Use the mouse to zoom and adjust the image for your background."));
} else {
ui.label_masthead->setPicture(QPixmap());
ui.label_masthead->setText(tr("MastHead background Image"));
}
}
void WireGroupExtra::on_removeButton_clicked()
{
ui.label_masthead->setPicture(QPixmap());
ui.label_masthead->setText(tr("MastHead background Image"));
} }
std::string WireGroupExtra::getTagline() std::string WireGroupExtra::getTagline()
@ -77,7 +95,5 @@ std::string WireGroupExtra::getLocation()
QPixmap WireGroupExtra::getMasthead() QPixmap WireGroupExtra::getMasthead()
{ {
return mMasthead; return ui.label_masthead->extractCroppedScaledPicture();
} }

View File

@ -34,7 +34,6 @@ public:
void setMasthead(const QPixmap &pixmap); void setMasthead(const QPixmap &pixmap);
QPixmap getMasthead(); QPixmap getMasthead();
void setTagline(const std::string &str); void setTagline(const std::string &str);
void setLocation(const std::string &str); void setLocation(const std::string &str);
@ -43,7 +42,7 @@ public:
private slots: private slots:
void addMasthead(); void addMasthead();
void on_removeButton_clicked();
private: private:
void setUp(); void setUp();
private: private:

View File

@ -7,7 +7,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>516</width> <width>516</width>
<height>199</height> <height>133</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -19,50 +19,127 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout_2">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label_2"> <layout class="QGridLayout" name="gridLayout">
<property name="text"> <item row="5" column="1">
<string>Masthead</string> <widget class="QLineEdit" name="lineEdit_Location"/>
</property> </item>
</widget> <item row="4" column="0">
</item> <widget class="QLabel" name="captionLabel">
<item row="0" column="1" rowspan="2"> <property name="text">
<widget class="QLabel" name="label_masthead"> <string>Tagline:</string>
<property name="text"> </property>
<string>MastHead background Image</string> </widget>
</property> </item>
</widget> <item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_Tagline"/>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="removeButton">
<property name="text">
<string>Remove</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Location:</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pushButton_masthead">
<property name="text">
<string>Select Image</string>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1" rowspan="3">
<widget class="ZoomableLabel" name="label_masthead">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="text">
<string>MastHead background Image</string>
</property>
<property name="textFormat">
<enum>Qt::PlainText</enum>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QPushButton" name="pushButton_masthead"> <spacer name="verticalSpacer_2">
<property name="text"> <property name="orientation">
<string>Select Image</string> <enum>Qt::Vertical</enum>
</property> </property>
</widget> <property name="sizeHint" stdset="0">
</item> <size>
<item row="2" column="0"> <width>20</width>
<widget class="QLabel" name="captionLabel"> <height>10</height>
<property name="text"> </size>
<string>Tagline:</string>
</property> </property>
</widget> </spacer>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_Tagline"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Location:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_Location"/>
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>ZoomableLabel</class>
<extends>QLabel</extends>
<header>gui/gxschannels/GxsChannelPostThumbnail.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections/> <connections/>
</ui> </ui>

View File

@ -65,8 +65,7 @@ WireGroupItem::WireGroupItem(WireGroupHolder *holder, const RsWireGroup &grp)
setAttribute ( Qt::WA_DeleteOnClose, true ); setAttribute ( Qt::WA_DeleteOnClose, true );
setup(); setup();
// disabled, still not yet functional Edit/Update editButton->setEnabled(true);
editButton->setEnabled(false);
} }
RsGxsGroupId &WireGroupItem::groupId() RsGxsGroupId &WireGroupItem::groupId()
@ -93,14 +92,14 @@ void WireGroupItem::setup()
QImage circleImage = getCirclePhoto(orginalImage,orginalImage.size().width()); QImage circleImage = getCirclePhoto(orginalImage,orginalImage.size().width());
pixmap.convertFromImage(circleImage); pixmap.convertFromImage(circleImage);
pixmap = pixmap.scaled(40,40); pixmap = pixmap.scaled(40,40, Qt::KeepAspectRatio, Qt::SmoothTransformation);
label_headshot->setPixmap(pixmap); label_headshot->setPixmap(pixmap);
} }
} }
else else
{ {
// default. // default.
QPixmap pixmap = FilesDefs::getPixmapFromQtResourcePath(":/icons/wire.png").scaled(32,32); QPixmap pixmap = FilesDefs::getPixmapFromQtResourcePath(":/icons/wire.png").scaled(32,32, Qt::KeepAspectRatio, Qt::SmoothTransformation);
label_headshot->setPixmap(pixmap); label_headshot->setPixmap(pixmap);
} }

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>276</width> <width>292</width>
<height>114</height> <height>115</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">

View File

@ -258,7 +258,11 @@ void ElidedLabel::mousePressEvent(QMouseEvent *ev)
return; // eat event return; // eat event
} }
QLabel::mousePressEvent(ev); QLabel::mousePressEvent(ev);
emit clicked(ev->pos());
if(ev->buttons()==Qt::LeftButton)
emit clicked(ev->pos());
else if(ev->buttons()==Qt::RightButton)
emit rightClicked(ev->pos());
} }
void ElidedLabel::setTextColor(const QColor &color) void ElidedLabel::setTextColor(const QColor &color)

View File

@ -77,7 +77,8 @@ protected:
signals: signals:
void elisionChanged(bool elided); void elisionChanged(bool elided);
void clicked(QPoint pos); void rightClicked(QPoint pos);
void clicked(QPoint pos);
private: private:
bool mElided; bool mElided;

View File

@ -1145,8 +1145,6 @@ void RsFriendListModel::updateInternalData()
mLocations.clear(); mLocations.clear();
mTopLevel.clear(); mTopLevel.clear();
endResetModel();
auto TL = mTopLevel ; // This allows to fill TL without touching mTopLevel outside of [begin/end]InsertRows(). auto TL = mTopLevel ; // This allows to fill TL without touching mTopLevel outside of [begin/end]InsertRows().
// create a map of profiles and groups // create a map of profiles and groups
@ -1282,7 +1280,8 @@ void RsFriendListModel::updateInternalData()
endInsertRows(); endInsertRows();
} }
postMods(); endResetModel();
postMods();
mLastInternalDataUpdate = time(NULL); mLastInternalDataUpdate = time(NULL);
} }

View File

@ -49,6 +49,10 @@ GxsChannelPostItem::GxsChannelPostItem(FeedHolder *feedHolder, uint32_t feedId,
GxsFeedItem(feedHolder, feedId, group_meta.mGroupId, messageId, isHome, rsGxsChannels, autoUpdate), GxsFeedItem(feedHolder, feedId, group_meta.mGroupId, messageId, isHome, rsGxsChannels, autoUpdate),
mGroupMeta(group_meta) mGroupMeta(group_meta)
{ {
mLoadingGroup = false;
mLoadingMessage = false;
mLoadingComment = false;
mPost.mMeta.mMsgId = messageId; // useful for uniqueIdentifer() before the post is loaded mPost.mMeta.mMsgId = messageId; // useful for uniqueIdentifer() before the post is loaded
mPost.mMeta.mGroupId = mGroupMeta.mGroupId; mPost.mMeta.mGroupId = mGroupMeta.mGroupId;
@ -136,6 +140,19 @@ void GxsChannelPostItem::paintEvent(QPaintEvent *e)
GxsChannelPostItem::~GxsChannelPostItem() GxsChannelPostItem::~GxsChannelPostItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
while( (mLoadingGroup || mLoadingMessage || mLoadingComment)
&& std::chrono::steady_clock::now() < timeout)
{
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for "
<< (mLoadingGroup ? "Group " : "")
<< (mLoadingMessage ? "Message " : "")
<< (mLoadingComment ? "Comment " : "")
<< "loading." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
delete(ui); delete(ui);
} }
@ -277,6 +294,7 @@ void GxsChannelPostItem::loadGroup()
std::cerr << "GxsChannelGroupItem::loadGroup()"; std::cerr << "GxsChannelGroupItem::loadGroup()";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
{ {
@ -306,6 +324,7 @@ void GxsChannelPostItem::loadGroup()
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
mGroupMeta = group.mMeta; mGroupMeta = group.mMeta;
mLoadingGroup = false;
}, this ); }, this );
}); });
@ -316,6 +335,8 @@ void GxsChannelPostItem::loadMessage()
std::cerr << "GxsChannelPostItem::loadMessage()"; std::cerr << "GxsChannelPostItem::loadMessage()";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mLoadingMessage = true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group data // 1 - get group data
@ -337,7 +358,11 @@ void GxsChannelPostItem::loadMessage()
#endif #endif
const RsGxsChannelPost& post(posts[0]); const RsGxsChannelPost& post(posts[0]);
RsQThreadUtils::postToObject( [post,this]() { setPost(post); }, this ); RsQThreadUtils::postToObject( [post,this]()
{
setPost(post);
mLoadingMessage = false;
}, this );
} }
else if(comments.size() == 1) else if(comments.size() == 1)
{ {
@ -356,7 +381,8 @@ void GxsChannelPostItem::loadMessage()
setMessageId(cmt.mMeta.mThreadId); setMessageId(cmt.mMeta.mThreadId);
requestMessage(); requestMessage();
}, this ); mLoadingMessage = false;
}, this );
} }
else else
@ -366,7 +392,11 @@ void GxsChannelPostItem::loadMessage()
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
RsQThreadUtils::postToObject( [this]() { removeItem(); }, this ); RsQThreadUtils::postToObject( [this]()
{
removeItem();
mLoadingMessage = false;
}, this );
} }
}); });
} }
@ -377,6 +407,7 @@ void GxsChannelPostItem::loadComment()
std::cerr << "GxsChannelPostItem::loadComment()"; std::cerr << "GxsChannelPostItem::loadComment()";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mLoadingComment = true;
RsThread::async([this]() RsThread::async([this]()
{ {
@ -407,6 +438,7 @@ void GxsChannelPostItem::loadComment()
sComButText = tr("Comments ").append("(%1)").arg(comNb); sComButText = tr("Comments ").append("(%1)").arg(comNb);
ui->commentButton->setText(sComButText); ui->commentButton->setText(sComButText);
mLoadingComment = false;
}, this ); }, this );
}); });

View File

@ -119,7 +119,12 @@ private:
private: private:
bool mInFill; bool mInFill;
bool mCloseOnRead; bool mCloseOnRead;
bool mLoaded; bool mLoaded;
bool mLoadingMessage;
bool mLoadingGroup;
bool mLoadingComment;
RsGroupMetaData mGroupMeta; RsGroupMetaData mGroupMeta;
RsGxsChannelPost mPost; RsGxsChannelPost mPost;

View File

@ -47,7 +47,13 @@ GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const
{ {
mMessage.mMeta.mMsgId = messageId; // useful for uniqueIdentifier() before the post is actually loaded mMessage.mMeta.mMsgId = messageId; // useful for uniqueIdentifier() before the post is actually loaded
mMessage.mMeta.mGroupId = groupId; mMessage.mMeta.mGroupId = groupId;
setup();
mLoadingGroup = false;
mLoadingMessage = false;
mLoadingSetAsRead = false;
mLoadingParentMessage = false;
setup();
requestGroup(); requestGroup();
requestMessage(); requestMessage();
@ -83,6 +89,19 @@ GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const
GxsForumMsgItem::~GxsForumMsgItem() GxsForumMsgItem::~GxsForumMsgItem()
{ {
auto timeout = std::chrono::steady_clock::now() + std::chrono::milliseconds(300);
while( (mLoadingGroup || mLoadingMessage || mLoadingSetAsRead || mLoadingParentMessage)
&& std::chrono::steady_clock::now() < timeout)
{
RsDbg() << __PRETTY_FUNCTION__ << " is Waiting for "
<< (mLoadingGroup ? "Group " : "")
<< (mLoadingMessage ? "Message " : "")
<< (mLoadingParentMessage ? "Parent message " : "")
<< (mLoadingSetAsRead ? "Set as read" : "")
<< "loading." << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
delete(ui); delete(ui);
} }
@ -167,6 +186,8 @@ QString GxsForumMsgItem::groupName()
void GxsForumMsgItem::loadGroup() void GxsForumMsgItem::loadGroup()
{ {
mLoadingGroup = true;
RsThread::async([this]() RsThread::async([this]()
{ {
// 1 - get group data // 1 - get group data
@ -199,6 +220,7 @@ void GxsForumMsgItem::loadGroup()
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setGroup(group); setGroup(group);
mLoadingGroup = false;
}, this ); }, this );
}); });
@ -210,6 +232,7 @@ void GxsForumMsgItem::loadMessage()
std::cerr << "GxsForumMsgItem::loadMessage(): messageId=" << messageId() << " groupId=" << groupId() ; std::cerr << "GxsForumMsgItem::loadMessage(): messageId=" << messageId() << " groupId=" << groupId() ;
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mLoadingMessage = true;
RsThread::async([this]() RsThread::async([this]()
{ {
@ -244,6 +267,7 @@ void GxsForumMsgItem::loadMessage()
* after a blocking call to RetroShare API complete */ * after a blocking call to RetroShare API complete */
setMessage(msg); setMessage(msg);
mLoadingMessage = false;
}, this ); }, this );
}); });
@ -255,6 +279,7 @@ void GxsForumMsgItem::loadParentMessage(const RsGxsMessageId& parent_msg)
std::cerr << "GxsForumMsgItem::loadParentMessage()"; std::cerr << "GxsForumMsgItem::loadParentMessage()";
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
mLoadingParentMessage = true;
RsThread::async([parent_msg,this]() RsThread::async([parent_msg,this]()
{ {
@ -291,6 +316,8 @@ void GxsForumMsgItem::loadParentMessage(const RsGxsMessageId& parent_msg)
mParentMessage = msg; mParentMessage = msg;
fillParentMessage(); fillParentMessage();
mLoadingParentMessage = false;
}, this ); }, this );
}); });
} }
@ -480,6 +507,7 @@ void GxsForumMsgItem::setAsRead(bool doUpdate)
} }
mCloseOnRead = false; mCloseOnRead = false;
mLoadingSetAsRead = true;
RsThread::async( [this, doUpdate]() { RsThread::async( [this, doUpdate]() {
RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId()); RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId());
@ -489,6 +517,7 @@ void GxsForumMsgItem::setAsRead(bool doUpdate)
if (doUpdate) { if (doUpdate) {
RsQThreadUtils::postToObject( [this]() { RsQThreadUtils::postToObject( [this]() {
setReadStatus(false, true); setReadStatus(false, true);
mLoadingSetAsRead = false;
} ); } );
} }
}); });

View File

@ -87,6 +87,10 @@ private:
private: private:
bool mInFill; bool mInFill;
bool mCloseOnRead; bool mCloseOnRead;
bool mLoadingMessage;
bool mLoadingParentMessage;
bool mLoadingGroup;
bool mLoadingSetAsRead;
RsGxsForumGroup mGroup; RsGxsForumGroup mGroup;
RsGxsForumMsg mMessage; RsGxsForumMsg mMessage;

View File

@ -29,6 +29,8 @@
#include <QMessageBox> #include <QMessageBox>
#include <QDateTime> #include <QDateTime>
//#define DEBUG_COMMENT_DIALOG 1
/** Constructor */ /** Constructor */
GxsCommentDialog::GxsCommentDialog(QWidget *parent, const RsGxsId &default_author, RsGxsCommentService *comment_service) GxsCommentDialog::GxsCommentDialog(QWidget *parent, const RsGxsId &default_author, RsGxsCommentService *comment_service)
: QWidget(parent), ui(new Ui::GxsCommentDialog) : QWidget(parent), ui(new Ui::GxsCommentDialog)
@ -95,8 +97,11 @@ void GxsCommentDialog::commentClear()
} }
void GxsCommentDialog::commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId>& msg_versions,const RsGxsMessageId& most_recent_msgId,bool use_cache) void GxsCommentDialog::commentLoad(const RsGxsGroupId &grpId, const std::set<RsGxsMessageId>& msg_versions,const RsGxsMessageId& most_recent_msgId,bool use_cache)
{ {
std::cerr << "GxsCommentDialog::commentLoad(" << grpId << ", most recent msg version: " << most_recent_msgId << ")"; #ifdef DEBUG_COMMENT_DIALOG
std::cerr << std::endl; std::cerr << "GxsCommentDialog::commentLoad(" << grpId << ", most recent msg version: " << most_recent_msgId << ")" << std::endl;
for(const auto& mid:msg_versions)
std::cerr << " msg version: " << mid << std::endl;
#endif
mGrpId = grpId; mGrpId = grpId;
mMostRecentMsgId = most_recent_msgId; mMostRecentMsgId = most_recent_msgId;

View File

@ -42,6 +42,8 @@
#include <iostream> #include <iostream>
//#define DEBUG_COMMENT_TREE_WIDGET
#define PCITEM_COLUMN_COMMENT 0 #define PCITEM_COLUMN_COMMENT 0
#define PCITEM_COLUMN_AUTHOR 1 #define PCITEM_COLUMN_AUTHOR 1
#define PCITEM_COLUMN_DATE 2 #define PCITEM_COLUMN_DATE 2
@ -73,6 +75,7 @@ std::map<RsGxsMessageId, std::vector<RsGxsComment> > GxsCommentTreeWidget::mComm
QMutex GxsCommentTreeWidget::mCacheMutex; QMutex GxsCommentTreeWidget::mCacheMutex;
//#define USE_NEW_DELEGATE 1 //#define USE_NEW_DELEGATE 1
//#define DEBUG_GXSCOMMENT_TREEWIDGET 1
// This class allows to draw the item using an appropriate size // This class allows to draw the item using an appropriate size
@ -464,11 +467,7 @@ void GxsCommentTreeWidget::replyToComment()
void GxsCommentTreeWidget::copyComment() void GxsCommentTreeWidget::copyComment()
{ {
QString txt = dynamic_cast<QAction*>(sender())->data().toString(); QString txt = dynamic_cast<QAction*>(sender())->data().toString();
QApplication::clipboard()->setText(txt) ;
QMimeData *mimeData = new QMimeData();
mimeData->setHtml("<html>"+txt+"</html>");
QClipboard *clipboard = QApplication::clipboard();
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
} }
void GxsCommentTreeWidget::setup(RsGxsCommentService *comment_service) void GxsCommentTreeWidget::setup(RsGxsCommentService *comment_service)
@ -512,6 +511,8 @@ void GxsCommentTreeWidget::service_requestComments(const RsGxsGroupId& group_id,
/* request comments */ /* request comments */
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET #ifdef DEBUG_GXSCOMMENT_TREEWIDGET
std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl; std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl;
for(const auto& mid:msgIds)
std::cerr << " including message " << mid << std::endl;
#endif #endif
RsThread::async([this,group_id,msgIds]() RsThread::async([this,group_id,msgIds]()
@ -769,8 +770,10 @@ void GxsCommentTreeWidget::insertComments(const std::vector<RsGxsComment>& comme
new_comments.push_back(comment.mMeta.mMsgId); new_comments.push_back(comment.mMeta.mMsgId);
/* convert to a QTreeWidgetItem */ /* convert to a QTreeWidgetItem */
#ifdef DEBUG_COMMENT_TREE_WIDGET
std::cerr << "GxsCommentTreeWidget::service_loadThread() Got Comment: " << comment.mMeta.mMsgId; std::cerr << "GxsCommentTreeWidget::service_loadThread() Got Comment: " << comment.mMeta.mMsgId;
std::cerr << std::endl; std::cerr << std::endl;
#endif
GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(NULL,GxsIdDetails::ICON_TYPE_AVATAR) ; GxsIdRSTreeWidgetItem *item = new GxsIdRSTreeWidgetItem(NULL,GxsIdDetails::ICON_TYPE_AVATAR) ;
QString text; QString text;

View File

@ -1105,7 +1105,12 @@ void GxsGroupFrameDialog::updateGroupSummary()
* Qt::QueuedConnection is important! * Qt::QueuedConnection is important!
*/ */
insertGroupsData(*groupInfo); // Here we save the focus, and restore it afterwards: there's no need to grab the focus here and
// if we do, it may harm the navitation in forums, channels, boards, etc.
auto w = QApplication::focusWidget();
insertGroupsData(*groupInfo);
updateSearchResults(); updateSearchResults();
mStateHelper->setLoading(TOKEN_TYPE_GROUP_SUMMARY, false); mStateHelper->setLoading(TOKEN_TYPE_GROUP_SUMMARY, false);
@ -1132,7 +1137,12 @@ void GxsGroupFrameDialog::updateGroupSummary()
delete groupInfo; delete groupInfo;
}, this ); // Restore the focus.
if(w)
w->setFocus();
}, this );
}); });
} }
@ -1165,16 +1175,16 @@ void GxsGroupFrameDialog::updateGroupStatisticsReal(const RsGxsGroupId &groupId)
* Qt::QueuedConnection is important! * Qt::QueuedConnection is important!
*/ */
QTreeWidgetItem *item = ui->groupTreeWidget->getItemFromId(QString::fromStdString(stats.mGrpId.toStdString())); QTreeWidgetItem *item = ui->groupTreeWidget->getItemFromId(QString::fromStdString(stats.mGrpId.toStdString()));
if (!item)
return; if (item)
ui->groupTreeWidget->setUnreadCount(item, mCountChildMsgs ? (stats.mNumThreadMsgsUnread + stats.mNumChildMsgsUnread) : stats.mNumThreadMsgsUnread);
ui->groupTreeWidget->setUnreadCount(item, mCountChildMsgs ? (stats.mNumThreadMsgsUnread + stats.mNumChildMsgsUnread) : stats.mNumThreadMsgsUnread);
mCachedGroupStats[groupId] = stats; mCachedGroupStats[groupId] = stats;
getUserNotify()->updateIcon(); getUserNotify()->updateIcon();
}, this ); }, this );
}); });
} }

View File

@ -193,17 +193,25 @@ void GxsIdTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
QStyleOptionViewItem ownOption (option); QStyleOptionViewItem ownOption (option);
initStyleOption(&ownOption, index); initStyleOption(&ownOption, index);
RsGxsId id(index.data(Qt::UserRole).toString().toStdString()); QString dt = index.data(Qt::UserRole).toString();
QString cmt; RsGxsId id(index.data(Qt::UserRole).toString().toStdString());
if(id.isNull()) // This is a trick: UserRole in Mail generally is 0000...00000 when there is a notification, and is empty when there are multiple
// destinations at once. This is not so nice to do that this way, but it's a quick workaround to a more complex method involving an
// additional Qt role only to determine the number of destinations.
if(dt == "")
ownOption.icon = FilesDefs::getIconFromQtResourcePath(":/icons/svg/people2.svg");
else if(id.isNull())
{
if (ownOption.icon.isNull())
ownOption.icon = FilesDefs::getIconFromQtResourcePath(":/icons/notification.svg");
}
else
{ {
if (ownOption.icon.isNull()) QString cmt;
ownOption.icon = FilesDefs::getIconFromQtResourcePath(":/icons/notification.svg");
} if(! computeNameIconAndComment(id,ownOption.text,ownOption.icon,cmt))
else
{
if(! computeNameIconAndComment(id,ownOption.text,ownOption.icon,cmt))
{ {
if(mReloadPeriod > 3) if(mReloadPeriod > 3)
{ {

View File

@ -46,7 +46,6 @@ protected:
bool mCountChildMsgs; // Count new child messages? bool mCountChildMsgs; // Count new child messages?
private: private:
RsGxsUpdateBroadcastBase *mBase;
const GxsGroupFrameDialog *mGroupFrameDialog; const GxsGroupFrameDialog *mGroupFrameDialog;
unsigned int mNewThreadMessageCount; unsigned int mNewThreadMessageCount;

View File

@ -35,6 +35,7 @@
#include "util/rsdir.h" #include "util/rsdir.h"
#include "util/qtthreadsutils.h" #include "util/qtthreadsutils.h"
#include "util/RichTextEdit.h" #include "util/RichTextEdit.h"
#include "util/imageutil.h"
#include <retroshare/rsfiles.h> #include <retroshare/rsfiles.h>
@ -607,11 +608,13 @@ bool CreateGxsChannelMsg::setThumbNail(const std::string& path, int frame){
if(imageBuffer == NULL) if(imageBuffer == NULL)
return false; return false;
QImage tNail(imageBuffer, width, height, QImage::Format_RGB32); QImage tNail(imageBuffer, width, height, QImage::Format_RGBA32);
QByteArray ba; QByteArray ba;
QBuffer buffer(&ba); QBuffer buffer(&ba);
bool has_transparency = ImageUtil::hasAlphaContent(tNail.toImage());
buffer.open(QIODevice::WriteOnly); buffer.open(QIODevice::WriteOnly);
tNail.save(&buffer, "JPG"); tNail.save(&buffer, has_transparency?"PNG":"JPG");
QPixmap img; QPixmap img;
img.loadFromData(ba, "PNG"); img.loadFromData(ba, "PNG");
img = img.scaled(thumbnail_label->width(), thumbnail_label->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation); img = img.scaled(thumbnail_label->width(), thumbnail_label->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
@ -797,15 +800,19 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str
QByteArray ba; QByteArray ba;
QBuffer buffer(&ba); QBuffer buffer(&ba);
RsGxsImage image; RsGxsImage image;
QPixmap pixmap;
pixmap = preview_W->getCroppedScaledPicture();
QImage qimg = pixmap.toImage();
bool has_transparency = ImageUtil::hasAlphaContent(qimg);
if(!picture.isNull()) if(!picture.isNull())
{ {
// send chan image // send chan image
buffer.open(QIODevice::WriteOnly); buffer.open(QIODevice::WriteOnly);
preview_W->getCroppedScaledPicture().save(&buffer, "JPG"); // writes image into ba in PNG format preview_W->getCroppedScaledPicture().save(&buffer, has_transparency?"PNG":"JPG"); // writes image into ba in PNG format
image.copy((uint8_t *) ba.data(), ba.size()); image.copy((uint8_t *) ba.data(), ba.size());
} }
std::string error_string; std::string error_string;

View File

@ -50,14 +50,11 @@ GxsChannelFilesStatusWidget::GxsChannelFilesStatusWidget(const RsGxsFile &file,
connect(ui->openFilePushButton, SIGNAL(clicked()), this, SLOT(openFile())); connect(ui->openFilePushButton, SIGNAL(clicked()), this, SLOT(openFile()));
ui->downloadPushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/download.png")); ui->downloadPushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/download.png"));
ui->openFolderToolButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/arrow.png"));
QAction *openfolder = new QAction(tr("Open folder"), this); ui->openFolderPushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/folderopen.png"));
connect(openfolder, SIGNAL(triggered()), this, SLOT(openFolder())); ui->openFolderPushButton->setToolTip(tr("Open folder"));
QMenu *menu = new QMenu(); connect(ui->openFolderPushButton, SIGNAL(clicked()), this, SLOT(openFolder()));
menu->addAction(openfolder);
ui->openFolderToolButton->setMenu(menu);
check(); check();
} }
@ -90,7 +87,9 @@ void GxsChannelFilesStatusWidget::setSize(uint64_t size)
void GxsChannelFilesStatusWidget::check() void GxsChannelFilesStatusWidget::check()
{ {
FileInfo fileInfo; FileInfo fileInfo;
if (rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) {
if(haveFile(fileInfo))
{
mState = STATE_LOCAL; mState = STATE_LOCAL;
setSize(fileInfo.size); setSize(fileInfo.size);
@ -103,27 +102,25 @@ void GxsChannelFilesStatusWidget::check()
ui->openFilePushButton->setText(tr("Play")); ui->openFilePushButton->setText(tr("Play"));
ui->openFilePushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png")); ui->openFilePushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png"));
} }
}
} else { else
FileInfo fileInfo; {
bool detailsOk = rsFiles->FileDetails(mFile.mHash, RS_FILE_HINTS_DOWNLOAD | RS_FILE_HINTS_SPEC_ONLY, fileInfo); switch (fileInfo.downloadStatus)
{
if (detailsOk) {
switch (fileInfo.downloadStatus) {
case FT_STATE_WAITING: case FT_STATE_WAITING:
mState = STATE_WAITING; mState = STATE_WAITING;
break; break;
case FT_STATE_DOWNLOADING: case FT_STATE_DOWNLOADING:
if (fileInfo.avail == fileInfo.size) { if (fileInfo.avail == fileInfo.size)
mState = STATE_LOCAL; mState = STATE_LOCAL;
} else { else
mState = STATE_DOWNLOAD; mState = STATE_DOWNLOAD;
}
setSize(fileInfo.size); setSize(fileInfo.size);
ui->progressBar->setValue(fileInfo.avail / mDivisor); ui->progressBar->setValue(fileInfo.avail / mDivisor);
break; break;
case FT_STATE_COMPLETE: case FT_STATE_COMPLETE: // this should not happen, since the case is handled earlier
mState = STATE_DOWNLOAD; mState = STATE_ERROR;
break; break;
case FT_STATE_QUEUED: case FT_STATE_QUEUED:
mState = STATE_WAITING; mState = STATE_WAITING;
@ -134,14 +131,11 @@ void GxsChannelFilesStatusWidget::check()
case FT_STATE_CHECKING_HASH: case FT_STATE_CHECKING_HASH:
mState = STATE_CHECKING; mState = STATE_CHECKING;
break; break;
case FT_STATE_FAILED: default:
mState = STATE_ERROR; mState = STATE_REMOTE;
break; break;
} }
} else { }
mState = STATE_REMOTE;
}
}
int repeat = 0; int repeat = 0;
QString statusText; QString statusText;
@ -156,7 +150,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->hide(); ui->cancelToolButton->hide();
ui->progressBar->hide(); ui->progressBar->hide();
ui->openFilePushButton->hide(); ui->openFilePushButton->hide();
ui->openFolderToolButton->hide(); ui->openFolderPushButton->hide();
statusText = tr("Error"); statusText = tr("Error");
@ -171,7 +165,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->hide(); ui->cancelToolButton->hide();
ui->progressBar->hide(); ui->progressBar->hide();
ui->openFilePushButton->hide(); ui->openFilePushButton->hide();
ui->openFolderToolButton->hide(); ui->openFolderPushButton->hide();
break; break;
@ -184,7 +178,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show(); ui->cancelToolButton->show();
ui->progressBar->show(); ui->progressBar->show();
ui->openFilePushButton->hide(); ui->openFilePushButton->hide();
ui->openFolderToolButton->hide(); ui->openFolderPushButton->hide();
break; break;
@ -197,7 +191,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show(); ui->cancelToolButton->show();
ui->progressBar->hide(); ui->progressBar->hide();
ui->openFilePushButton->hide(); ui->openFilePushButton->hide();
ui->openFolderToolButton->hide(); ui->openFolderPushButton->hide();
statusText = tr("Paused"); statusText = tr("Paused");
@ -212,7 +206,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show(); ui->cancelToolButton->show();
ui->progressBar->hide(); ui->progressBar->hide();
ui->openFilePushButton->hide(); ui->openFilePushButton->hide();
ui->openFolderToolButton->hide(); ui->openFolderPushButton->hide();
statusText = tr("Waiting"); statusText = tr("Waiting");
@ -227,7 +221,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show(); ui->cancelToolButton->show();
ui->progressBar->hide(); ui->progressBar->hide();
ui->openFilePushButton->hide(); ui->openFilePushButton->hide();
ui->openFolderToolButton->hide(); ui->openFolderPushButton->hide();
statusText = tr("Checking"); statusText = tr("Checking");
@ -242,7 +236,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->hide(); ui->cancelToolButton->hide();
ui->progressBar->hide(); ui->progressBar->hide();
ui->openFilePushButton->show(); ui->openFilePushButton->show();
ui->openFolderToolButton->show(); ui->openFolderPushButton->show();
break; break;
} }
@ -324,35 +318,60 @@ void GxsChannelFilesStatusWidget::cancel()
void GxsChannelFilesStatusWidget::openFolder() void GxsChannelFilesStatusWidget::openFolder()
{ {
FileInfo fileInfo; FileInfo fileInfo;
if (!rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) { if (!haveFile(fileInfo))
return; return;
}
/* open folder with a suitable application */ QFileInfo finfo;
QDir dir = QFileInfo(QString::fromUtf8(fileInfo.path.c_str())).absoluteDir(); finfo.setFile(QString::fromUtf8(fileInfo.path.c_str()));
if (dir.exists()) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(dir.absolutePath()))) {
if(!mUsedAsEditor)
QMessageBox::warning(this, "", QString("%1 %2").arg(tr("Can't open folder"), dir.absolutePath()));
else
RsErr() << "Can't open folder " << dir.absolutePath().toStdString() ;
} /* open folder with a suitable application */
} if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(finfo.absolutePath()))) {
if(!mUsedAsEditor)
QMessageBox::warning(this, "", QString("%1 %2").arg(tr("Can't open folder"), finfo.absolutePath()));
else
RsErr() << "Can't open folder " << finfo.absolutePath().toStdString() ;
}
}
bool GxsChannelFilesStatusWidget::haveFile(FileInfo& info)
{
bool already_has_file = rsFiles->alreadyHaveFile(mFile.mHash, info);
if(!already_has_file)
if(!(rsFiles->FileDetails(mFile.mHash, RS_FILE_HINTS_DOWNLOAD | RS_FILE_HINTS_SPEC_ONLY, info) && info.downloadStatus==FT_STATE_COMPLETE))
return false;
// We need the code below because FileDetails() returns fileInfo.path as the directory when the file in COMPLETE and
// as a full path when the file is shared. The former is inconsistent with the documentation in rstypes.h, but I'm not
// sure what are the implications of changing the code in libretroshare so that the full path is always returned.
QFileInfo finfo;
if(QDir(QString::fromUtf8(info.path.c_str())).exists())
finfo.setFile(QString::fromUtf8(info.path.c_str()),QString::fromUtf8(info.fname.c_str()));
else if(QFile(QString::fromUtf8(info.path.c_str())).exists())
finfo.setFile(QString::fromUtf8(info.path.c_str()));
else
{
RsErr() << "Cannot find file!" << std::endl;
return false;
}
info.path = finfo.absoluteFilePath().toStdString();
return true;
} }
void GxsChannelFilesStatusWidget::openFile() void GxsChannelFilesStatusWidget::openFile()
{ {
FileInfo fileInfo; FileInfo fileInfo;
if (!rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) { if(!haveFile(fileInfo))
return; return;
}
/* open file with a suitable application */ QFileInfo finfo;
QFileInfo qinfo; finfo.setFile(QString::fromUtf8(fileInfo.path.c_str()));
qinfo.setFile(QString::fromUtf8(fileInfo.path.c_str()));
if (qinfo.exists()) { if (finfo.exists()) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) { if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(finfo.absoluteFilePath()))) {
std::cerr << "GxsChannelFilesStatusWidget(): can't open file " << fileInfo.path << std::endl; std::cerr << "GxsChannelFilesStatusWidget(): can't open file " << fileInfo.path << std::endl;
} }
}else{ }else{

View File

@ -53,6 +53,7 @@ private slots:
private: private:
void setSize(uint64_t size); void setSize(uint64_t size);
bool haveFile(FileInfo& info);
private: private:
enum State enum State

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>421</width> <width>473</width>
<height>29</height> <height>36</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -139,7 +139,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="openFolderToolButton"> <widget class="QToolButton" name="openFolderPushButton">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>

View File

@ -342,10 +342,20 @@ public:
case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE: case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE:
{ {
FileInfo fi1,fi2; FileInfo fi1,fi2;
rsFiles->FileDetails(f1.mHash,RS_FILE_HINTS_DOWNLOAD,fi1); bool r1 = rsFiles->FileDetails(f1.mHash,RS_FILE_HINTS_DOWNLOAD,fi1);
rsFiles->FileDetails(f2.mHash,RS_FILE_HINTS_DOWNLOAD,fi2); bool r2 = rsFiles->FileDetails(f2.mHash,RS_FILE_HINTS_DOWNLOAD,fi2);
return (ord==Qt::AscendingOrder)?(fi1.transfered<fi2.transfered):(fi1.transfered>fi2.transfered); if(r1 && r2)
return (ord==Qt::AscendingOrder)?(fi1.transfered<fi2.transfered):(fi1.transfered>fi2.transfered);
else
{
FileInfo fitmp;
if(!r1 && rsFiles->alreadyHaveFile(f1.mHash,fitmp)) fi1.downloadStatus = FT_STATE_COMPLETE;
if(!r2 && rsFiles->alreadyHaveFile(f2.mHash,fitmp)) fi2.downloadStatus = FT_STATE_COMPLETE;
return (ord==Qt::AscendingOrder)?(fi1.downloadStatus<fi2.downloadStatus):(fi1.downloadStatus>fi2.downloadStatus);
}
} }
} }

View File

@ -176,6 +176,25 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const
return 0; return 0;
} }
int RsGxsChannelPostsModel::columnCount(int row) const
{
if(mTreeMode == TREE_MODE_GRID)
{
if(row+1 == rowCount())
{
int r = ((int)mFilteredPosts.size() % (int)mColumns);
if(r > 0)
return r;
else
return columnCount();
}
else
return columnCount();
}
else
return 2;
}
int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const
{ {
if(mTreeMode == TREE_MODE_GRID) if(mTreeMode == TREE_MODE_GRID)
@ -245,7 +264,7 @@ bool RsGxsChannelPostsModel::convertRefPointerToTabEntry(quintptr ref, uint32_t&
QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex & parent) const QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex & parent) const
{ {
if(row < 0 || column < 0 || column >= (int)mColumns) if(row < 0 || column < 0 || row >= rowCount() || column >= columnCount(row))
return QModelIndex(); return QModelIndex();
quintptr ref = getChildRef(parent.internalId(),(mTreeMode == TREE_MODE_GRID)?(column + row*mColumns):row); quintptr ref = getChildRef(parent.internalId(),(mTreeMode == TREE_MODE_GRID)?(column + row*mColumns):row);

View File

@ -105,6 +105,7 @@ public:
QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;} QModelIndex root() const{ return createIndex(0,0,(void*)NULL) ;}
QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const; QModelIndex getIndexOfMessage(const RsGxsMessageId& mid) const;
int columnCount(int row) const; // columns in the row of this particular index.
std::vector<std::pair<time_t,RsGxsMessageId> > getPostVersions(const RsGxsMessageId& mid) const; std::vector<std::pair<time_t,RsGxsMessageId> > getPostVersions(const RsGxsMessageId& mid) const;

View File

@ -411,7 +411,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnPostFiles(int,Qt::SortOrder))); connect(ui->channelPostFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnPostFiles(int,Qt::SortOrder)));
connect(ui->channelFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnFiles(int,Qt::SortOrder))); connect(ui->channelFiles_TV->header(),SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(sortColumnFiles(int,Qt::SortOrder)));
connect(ui->channelPostFiles_TV,SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showChannelFilesContextMenu(QPoint))); connect(ui->channelPostFiles_TV,SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showChannelPostFilesContextMenu(QPoint)));
connect(ui->channelFiles_TV,SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showChannelFilesContextMenu(QPoint))); connect(ui->channelFiles_TV,SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showChannelFilesContextMenu(QPoint)));
connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails())); connect(ui->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails()));
@ -504,6 +504,30 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
}, mEventHandlerId, RsEventType::GXS_CHANNELS ); }, mEventHandlerId, RsEventType::GXS_CHANNELS );
} }
void GxsChannelPostsWidgetWithModel::keyPressEvent(QKeyEvent *e)
{
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
if(index.isValid() && mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
{
int n = mChannelPostsModel->columnCount(index.row())-1;
if(e->key() == Qt::Key_Left && index.column()==0)
{
ui->postsTree->setCurrentIndex(index.sibling(index.row(),n));
e->accept();
return;
}
if(e->key() == Qt::Key_Right && index.column()==n)
{
ui->postsTree->setCurrentIndex(index.sibling(index.row(),0));
e->accept();
return;
}
}
GxsMessageFrameWidget::keyPressEvent(e);
}
void GxsChannelPostsWidgetWithModel::resizeEvent(QResizeEvent *e) void GxsChannelPostsWidgetWithModel::resizeEvent(QResizeEvent *e)
{ {
GxsMessageFrameWidget::resizeEvent(e); GxsMessageFrameWidget::resizeEvent(e);
@ -1344,13 +1368,26 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
showPostDetails(); showPostDetails();
} }
void GxsChannelPostsWidgetWithModel::showChannelFilesContextMenu(QPoint p)
void GxsChannelPostsWidgetWithModel::showChannelFilesContextMenu(QPoint /*p*/)
{ {
QMenu contextMnu(this) ; QModelIndex index = ui->channelFiles_TV->indexAt(p);
QAction *action = contextMnu.addAction(QIcon(), tr("Copy Retroshare link"), this, SLOT(copyChannelFilesLink())); if(!index.isValid())
action->setData(QVariant::fromValue(sender())); return;
QMenu contextMnu(this) ;
contextMnu.addAction(QIcon(), tr("Copy Retroshare link"), this, SLOT(copyChannelFilesLink()))->setData(QVariant::fromValue(index));
contextMnu.exec(QCursor::pos());
}
void GxsChannelPostsWidgetWithModel::showChannelPostFilesContextMenu(QPoint p)
{
QModelIndex index = ui->channelPostFiles_TV->indexAt(p);
if(!index.isValid())
return;
QMenu contextMnu(this) ;
contextMnu.addAction(QIcon(), tr("Copy Retroshare link"), this, SLOT(copyChannelFilesLink()))->setData(QVariant::fromValue(index));
contextMnu.exec(QCursor::pos()); contextMnu.exec(QCursor::pos());
} }
@ -1358,16 +1395,11 @@ void GxsChannelPostsWidgetWithModel::copyChannelFilesLink()
{ {
// Block the popup if no results available // Block the popup if no results available
QAction *action = dynamic_cast<QAction*>(sender()); QAction *action = dynamic_cast<QAction*>(sender());
RSTreeView *tree = dynamic_cast<RSTreeView*>(action->data().value<QWidget*>());
QModelIndexList sel = tree->selectionModel()->selection().indexes();
if(sel.empty())
return;
QModelIndex s = action->data().toModelIndex();
ChannelPostFileInfo file; ChannelPostFileInfo file;
if(!static_cast<RsGxsChannelPostFilesModel*>(tree->model())->getFileData(sel.front(),file)) if(!static_cast<const RsGxsChannelPostFilesModel*>(s.model())->getFileData(s,file))
return; return;
RetroShareLink link = RetroShareLink::createFile(QString::fromUtf8(file.mName.c_str()), file.mSize, QString::fromStdString(file.mHash.toStdString())); RetroShareLink link = RetroShareLink::createFile(QString::fromUtf8(file.mName.c_str()), file.mSize, QString::fromStdString(file.mHash.toStdString()));

View File

@ -139,6 +139,7 @@ protected:
/* GxsMessageFrameWidget */ /* GxsMessageFrameWidget */
virtual void setAllMessagesReadDo(bool read) override; virtual void setAllMessagesReadDo(bool read) override;
virtual void resizeEvent(QResizeEvent *e) override; virtual void resizeEvent(QResizeEvent *e) override;
virtual void keyPressEvent(QKeyEvent *e) override;
private slots: private slots:
void showPostDetails(); void showPostDetails();
@ -166,6 +167,7 @@ public slots:
void sortColumnPostFiles(int col,Qt::SortOrder so); void sortColumnPostFiles(int col,Qt::SortOrder so);
void updateCommentsCount(int n); void updateCommentsCount(int n);
void showChannelFilesContextMenu(QPoint p); void showChannelFilesContextMenu(QPoint p);
void showChannelPostFilesContextMenu(QPoint p);
void copyChannelFilesLink(); void copyChannelFilesLink();
private: private:

View File

@ -15,6 +15,7 @@
<file>icons/svg/display_options.svg</file> <file>icons/svg/display_options.svg</file>
<file>icons/svg/listlayout.svg</file> <file>icons/svg/listlayout.svg</file>
<file>icons/svg/gridlayout.svg</file> <file>icons/svg/gridlayout.svg</file>
<file>icons/svg/people2.svg</file>
<file>icons/stars/star0.png</file> <file>icons/stars/star0.png</file>
<file>icons/stars/star1.png</file> <file>icons/stars/star1.png</file>
<file>icons/stars/star2.png</file> <file>icons/stars/star2.png</file>

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
id="svg4155"
version="1.1"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
xml:space="preserve"
width="80"
height="80"
viewBox="0 0 80 80"
sodipodi:docname="wire-notify.svg"
inkscape:export-xdpi="144"
inkscape:export-ydpi="144"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
id="metadata4161"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs4159" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="705"
id="namedview4157"
showgrid="false"
inkscape:zoom="5.11875"
inkscape:cx="35.457875"
inkscape:cy="40.927961"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g4163"
inkscape:pagecheckerboard="0" /><g
id="g4163"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,0,80)"><path
inkscape:connector-curvature="0"
id="path4167"
style="fill:#ff990d;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 64,32 C 64,14.327 49.673,0 32,0 14.327,0 0,14.327 0,32 0,49.673 14.327,64 32,64 49.673,64 64,49.673 64,32" /><path
style="fill:#ffffff;stroke:none;stroke-width:0.422421"
d="M 11.504608,50.061515 C 0.95186111,41.31166 9.91073,20.329766 22.487548,19.224797 v -0.42242 C 17.439916,16.700874 12.842245,14.816835 7.2804,14.578167 v -0.422421 c 13.723057,-5.705639 29.505712,-3.76208 38.535802,9.293259 3.987608,5.764904 3.334546,11.659532 5.649411,17.741673 1.140537,2.997245 4.589603,4.725495 6.08286,7.603575 -3.166889,0 -6.579204,-0.36248 -9.715677,0.08867 -3.52489,0.506989 -6.021355,2.241745 -9.715678,1.085368 -3.080123,-0.964134 -5.266278,-3.193206 -6.292,-6.243084 -0.395597,-1.176357 -0.200734,-3.00565 -1.144042,-3.90904 -1.225443,-1.173527 -4.184247,-0.416634 -5.659003,-0.09678 -5.829027,1.264221 -10.644877,5.188552 -13.517465,10.342128 z"
id="path1245" /></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
id="svg4155"
version="1.1"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
xml:space="preserve"
width="80"
height="80"
viewBox="0 0 80 80"
sodipodi:docname="wire.svg"
inkscape:export-xdpi="144"
inkscape:export-ydpi="144"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
id="metadata4161"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs4159" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="705"
id="namedview4157"
showgrid="false"
inkscape:zoom="5.11875"
inkscape:cx="35.457875"
inkscape:cy="40.927961"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="g4163"
inkscape:pagecheckerboard="0" /><g
id="g4163"
inkscape:groupmode="layer"
inkscape:label="ink_ext_XXXXXX"
transform="matrix(1.25,0,0,-1.25,0,80)"><path
inkscape:connector-curvature="0"
id="path4167"
style="fill:#039bd5;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 64,32 C 64,14.327 49.673,0 32,0 14.327,0 0,14.327 0,32 0,49.673 14.327,64 32,64 49.673,64 64,49.673 64,32" /><path
style="fill:#ffffff;stroke:none;stroke-width:0.422421"
d="M 11.504608,50.061515 C 0.95186111,41.31166 9.91073,20.329766 22.487548,19.224797 v -0.42242 C 17.439916,16.700874 12.842245,14.816835 7.2804,14.578167 v -0.422421 c 13.723057,-5.705639 29.505712,-3.76208 38.535802,9.293259 3.987608,5.764904 3.334546,11.659532 5.649411,17.741673 1.140537,2.997245 4.589603,4.725495 6.08286,7.603575 -3.166889,0 -6.579204,-0.36248 -9.715677,0.08867 -3.52489,0.506989 -6.021355,2.241745 -9.715678,1.085368 -3.080123,-0.964134 -5.266278,-3.193206 -6.292,-6.243084 -0.395597,-1.176357 -0.200734,-3.00565 -1.144042,-3.90904 -1.225443,-1.173527 -4.184247,-0.416634 -5.659003,-0.09678 -5.829027,1.264221 -10.644877,5.188552 -13.517465,10.342128 z"
id="path1245" /></g></svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -255,7 +255,7 @@ private:
QList<QLabel*> tagLabels; QList<QLabel*> tagLabels;
// needed to send system flags with reply // needed to send system flags with reply
unsigned msgFlags; unsigned int msgFlags;
RSTreeWidgetItemCompareRole *m_compareRole; RSTreeWidgetItemCompareRole *m_compareRole;
QCompleter *m_completer; QCompleter *m_completer;

View File

@ -459,14 +459,6 @@ QVariant RsMessageModel::sortRole(const Rs::Msgs::MsgInfoSummary& fmpe,int colum
case COLUMN_THREAD_SPAM: return QVariant((fmpe.msgflags & RS_MSG_SPAM)? 1:0); case COLUMN_THREAD_SPAM: return QVariant((fmpe.msgflags & RS_MSG_SPAM)? 1:0);
case COLUMN_THREAD_TO: {
QString name;
if(GxsIdTreeItemDelegate::computeName(RsGxsId(fmpe.to.toStdString()),name))
return name;
return ""; //Not Found
}
case COLUMN_THREAD_AUTHOR:{ case COLUMN_THREAD_AUTHOR:{
QString name; QString name;
@ -474,8 +466,10 @@ QVariant RsMessageModel::sortRole(const Rs::Msgs::MsgInfoSummary& fmpe,int colum
return name; return name;
return ""; //Not Found return ""; //Not Found
} }
default:
return displayRole(fmpe,column); case COLUMN_THREAD_TO: // fallthrough. In this case, the "to" field is not filled because the msg potentially has multiple destinations.
default:
return displayRole(fmpe,column);
} }
} }
@ -585,7 +579,18 @@ QVariant RsMessageModel::userRole(const Rs::Msgs::MsgInfoSummary& fmpe,int col)
{ {
case COLUMN_THREAD_AUTHOR: return QVariant(QString::fromStdString(fmpe.from.toStdString())); case COLUMN_THREAD_AUTHOR: return QVariant(QString::fromStdString(fmpe.from.toStdString()));
case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(fmpe.msgId)); case COLUMN_THREAD_MSGID: return QVariant(QString::fromStdString(fmpe.msgId));
case COLUMN_THREAD_TO: return QVariant(QString::fromStdString(fmpe.to.toStdString())); case COLUMN_THREAD_TO:
{
// First check if the .to field is filled.
if(!fmpe.to.toStdString().empty())
return QVariant(QString::fromStdString(fmpe.to.toStdString()));
// In the Send box, .to is never filled. In this case we look into destinations.
if(fmpe.destinations.size()==1)
return QVariant(QString::fromStdString((*fmpe.destinations.begin()).toStdString()));
}
default: default:
return QVariant(); return QVariant();
} }
@ -685,6 +690,10 @@ void RsMessageModel::setCurrentBox(Rs::Msgs::BoxName bn)
} }
} }
Rs::Msgs::BoxName RsMessageModel::currentBox() const
{
return mCurrentBox;
}
void RsMessageModel::setQuickViewFilter(QuickViewFilter fn) void RsMessageModel::setQuickViewFilter(QuickViewFilter fn)
{ {
if(fn != mQuickViewFilter) if(fn != mQuickViewFilter)

View File

@ -100,6 +100,7 @@ public:
// This method will asynchroneously update the data // This method will asynchroneously update the data
void setCurrentBox(Rs::Msgs::BoxName bn) ; void setCurrentBox(Rs::Msgs::BoxName bn) ;
Rs::Msgs::BoxName currentBox() const ;
void setQuickViewFilter(QuickViewFilter fn) ; void setQuickViewFilter(QuickViewFilter fn) ;
void setFilter(FilterType filter_type, const QStringList& strings) ; void setFilter(FilterType filter_type, const QStringList& strings) ;

View File

@ -738,7 +738,8 @@ void MessageWidget::remove()
return; return;
} }
bool deleteReal = false; #ifdef TO_REMOVE
bool deleteReal = false;
if (msgInfo.msgflags & RS_MSG_TRASH) { if (msgInfo.msgflags & RS_MSG_TRASH) {
deleteReal = true; deleteReal = true;
} else { } else {
@ -763,8 +764,8 @@ void MessageWidget::remove()
deleteLater(); deleteLater();
} }
} }
#endif
emit messageRemoved(); emit messageRemovalRequested(currMsgId);
} }
void MessageWidget::print() void MessageWidget::print()
@ -905,10 +906,8 @@ void MessageWidget::sendInvite()
if(mi.from.type()!=MsgAddress::MSG_ADDRESS_TYPE_RSGXSID) if(mi.from.type()!=MsgAddress::MSG_ADDRESS_TYPE_RSGXSID)
return; return;
if ((QMessageBox::question(this, tr("Send invite?"),tr("Do you really want send a invite with your Certificate?"),QMessageBox::Yes|QMessageBox::No, QMessageBox::Cancel))== QMessageBox::Yes) //if ((QMessageBox::question(this, tr("Send invite?"),tr("Do you really want to send an invite with your Certificate?"),QMessageBox::Yes, QMessageBox::No))== QMessageBox::Yes)
{ MessageComposer::sendInvite(mi.from.toGxsId(),false);
MessageComposer::sendInvite(mi.from.toGxsId(),false);
}
} }
void MessageWidget::setToolbarButtonStyle(Qt::ToolButtonStyle style) void MessageWidget::setToolbarButtonStyle(Qt::ToolButtonStyle style)

View File

@ -61,6 +61,7 @@ public:
signals: signals:
void messageRemoved(); void messageRemoved();
void messageRemovalRequested(std::string);
private slots: private slots:
void reply(); void reply();

View File

@ -95,6 +95,7 @@
#define ROW_SENTBOX 3 #define ROW_SENTBOX 3
#define ROW_TRASHBOX 4 #define ROW_TRASHBOX 4
// #define DEBUG_MESSAGES_DIALOG 1
class MessageSortFilterProxyModel: public QSortFilterProxyModel class MessageSortFilterProxyModel: public QSortFilterProxyModel
{ {
@ -144,7 +145,7 @@ MessagesDialog::MessagesDialog(QWidget *parent)
msgWidget = new MessageWidget(true, this); msgWidget = new MessageWidget(true, this);
ui.msgLayout->addWidget(msgWidget); ui.msgLayout->addWidget(msgWidget);
connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); connect(msgWidget, SIGNAL(messageRemovalRequested(std::string)), this, SLOT(removemessage()));
connectActions(); connectActions();
@ -365,15 +366,18 @@ void MessagesDialog::preModelUpdate()
if (m.isValid()) { if (m.isValid()) {
mTmpSavedCurrentId = m.sibling(m.row(), RsMessageModel::COLUMN_THREAD_MSGID).data(RsMessageModel::MsgIdRole).toString(); mTmpSavedCurrentId = m.sibling(m.row(), RsMessageModel::COLUMN_THREAD_MSGID).data(RsMessageModel::MsgIdRole).toString();
} }
#ifdef DEBUG_MESSAGES_DIALOG
std::cerr << "Pre-change: saving selection for " << mTmpSavedSelectedIds.size() << " indexes" << std::endl; std::cerr << "Pre-change: saving selection for " << mTmpSavedSelectedIds.size() << " indexes" << std::endl;
#endif
} }
void MessagesDialog::postModelUpdate() void MessagesDialog::postModelUpdate()
{ {
// restore selection // restore selection
#ifdef DEBUG_MESSAGES_DIALOG
std::cerr << "Post-change: restoring selection for " << mTmpSavedSelectedIds.size() << " indexes" << std::endl; std::cerr << "Post-change: restoring selection for " << mTmpSavedSelectedIds.size() << " indexes" << std::endl;
#endif
QItemSelection sel; QItemSelection sel;
foreach(const QString& s,mTmpSavedSelectedIds) foreach(const QString& s,mTmpSavedSelectedIds)
@ -838,7 +842,7 @@ void MessagesDialog::openAsWindow()
} }
msgWidget->activateWindow(); msgWidget->activateWindow();
connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); connect(msgWidget, SIGNAL(messageRemovalRequested(std::string)), this, SLOT(removemessage()));
/* window will destroy itself! */ /* window will destroy itself! */
} }
@ -858,7 +862,7 @@ void MessagesDialog::openAsTab()
ui.tabWidget->addTab(msgWidget,FilesDefs::getIconFromQtResourcePath(IMAGE_MAIL), msgWidget->subject(true)); ui.tabWidget->addTab(msgWidget,FilesDefs::getIconFromQtResourcePath(IMAGE_MAIL), msgWidget->subject(true));
ui.tabWidget->setCurrentWidget(msgWidget); ui.tabWidget->setCurrentWidget(msgWidget);
connect(msgWidget, SIGNAL(messageRemoved()), this, SLOT(messageRemoved())); connect(msgWidget, SIGNAL(messageRemovalRequested(std::string)), this, SLOT(removemessage()));
/* window will destroy itself! */ /* window will destroy itself! */
} }
@ -921,9 +925,9 @@ void MessagesDialog::changeBox(int box_row)
ui.messageTreeWidget->setPlaceholderText(placeholderText); ui.messageTreeWidget->setPlaceholderText(placeholderText);
ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_READ,box_row!=ROW_INBOX); ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_READ,box_row!=ROW_INBOX);
ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_STAR,box_row==ROW_OUTBOX); ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_STAR,box_row!=ROW_INBOX);
ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_SPAM,box_row==ROW_OUTBOX); ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_SPAM,box_row!=ROW_INBOX);
ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_TAGS,box_row==ROW_OUTBOX); ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_TAGS,box_row!=ROW_INBOX);
ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_MSGID,true); ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_MSGID,true);
ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_CONTENT,true); ui.messageTreeWidget->setColumnHidden(RsMessageModel::COLUMN_THREAD_CONTENT,true);
} }
@ -1292,7 +1296,7 @@ void MessagesDialog::updateMessageSummaryList()
/* calculating the new messages */ /* calculating the new messages */
std::list<MsgInfoSummary> msgList; std::list<MsgInfoSummary> msgList;
rsMail->getMessageSummaries(Rs::Msgs::BoxName::BOX_ALL,msgList); rsMail->getMessageSummaries(mMessageModel->currentBox(),msgList);
QMap<int, int> tagCount; QMap<int, int> tagCount;

View File

@ -117,7 +117,6 @@ class NotifyQt: public QObject, public NotifyClient
void chatStatusChanged(const ChatId&,const QString&) const ; void chatStatusChanged(const ChatId&,const QString&) const ;
void chatCleared(const ChatId&) const ; void chatCleared(const ChatId&) const ;
void peerHasNewCustomStateString(const QString& /* peer_id */, const QString& /* status_string */) const ; void peerHasNewCustomStateString(const QString& /* peer_id */, const QString& /* status_string */) const ;
void gotTurtleSearchResult(qulonglong search_id,FileDetail file) const ;
void peerHasNewAvatar(const QString& peer_id) const ; void peerHasNewAvatar(const QString& peer_id) const ;
void ownAvatarChanged() const ; void ownAvatarChanged() const ;
void ownStatusMessageChanged() const ; void ownStatusMessageChanged() const ;

View File

@ -2552,3 +2552,10 @@ OpModeStatus[opMode="Minimal"] {
[WrongValue="true"] { [WrongValue="true"] {
background-color: #702020; background-color: #702020;
} }
/**** The Wire ****/
QLabel#label_masthead{
border: 2px solid #CCCCCC;
border-radius: 4px;
}

View File

@ -2687,6 +2687,11 @@ PulseReply QLabel#label_groupName{
color: #5b7083; color: #5b7083;
} }
QLabel#label_masthead{
border: 2px solid #CCCCCC;
border-radius: 4px;
}
/**** PhotoShare ****/ /**** PhotoShare ****/
AlbumItem QFrame#albumFrame { AlbumItem QFrame#albumFrame {
border: 2px solid #CCCCCC; border: 2px solid #CCCCCC;

View File

@ -74,8 +74,13 @@ AppearancePage::AppearancePage(QWidget * parent, Qt::WindowFlags flags)
foreach (QString code, LanguageSupport::languageCodes()) { foreach (QString code, LanguageSupport::languageCodes()) {
ui.cmboLanguage->addItem(FilesDefs::getIconFromQtResourcePath(":/images/flags/" + code + ".png"), LanguageSupport::languageName(code), code); ui.cmboLanguage->addItem(FilesDefs::getIconFromQtResourcePath(":/images/flags/" + code + ".png"), LanguageSupport::languageName(code), code);
} }
foreach (QString style, QStyleFactory::keys()) {
ui.cmboStyle->addItem(style, style.toLower()); // Note: apparently, on some linux systems (e.g. Debian 11), the gtk2 style makes Qt libs crash when the environment variable is not set.
// So we first check that it's here before start.
foreach (QString style, QStyleFactory::keys()) {
if(style.toLower() != "gtk2" || (getenv("QT_QPA_PLATFORMTHEME")!=nullptr && !strcmp(getenv("QT_QPA_PLATFORMTHEME"),"gtk2")))
ui.cmboStyle->addItem(style, style.toLower());
} }
QMap<QString, QString> styleSheets; QMap<QString, QString> styleSheets;
@ -266,9 +271,9 @@ void AppearancePage::load()
index = ui.mainPageButtonType_CB->findData(Settings->getPageButtonLoc()); index = ui.mainPageButtonType_CB->findData(Settings->getPageButtonLoc());
if (index != 0) { if (index != 0) {
ui.cmboTollButtonsStyle->hide(); ui.cmboTollButtonsStyle->show();
}else { }else {
ui.cmboTollButtonsStyle->show(); ui.cmboTollButtonsStyle->hide();
} }
whileBlocking(ui.mainPageButtonType_CB)->setCurrentIndex(!Settings->getPageButtonLoc()); whileBlocking(ui.mainPageButtonType_CB)->setCurrentIndex(!Settings->getPageButtonLoc());

View File

@ -23,11 +23,14 @@
#include "rsharesettings.h" #include "rsharesettings.h"
#include "jsonapi/jsonapi.h" #include "jsonapi/jsonapi.h"
#include "util/misc.h" #include "util/misc.h"
#include "util/qtthreadsutils.h"
#include <QTimer> #include <QTimer>
#include <QStringListModel> #include <QStringListModel>
#include <QProgressDialog> #include <QProgressDialog>
#define IMAGE_LEDOFF ":/images/ledoff1.png"
#define IMAGE_LEDON ":/images/ledon1.png"
JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/) JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
{ {
@ -57,9 +60,31 @@ JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this); QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this);
ui.listenAddressLineEdit->setValidator(ipValidator); ui.listenAddressLineEdit->setValidator(ipValidator);
ui.providersListView->setSelectionMode(QAbstractItemView::NoSelection); // prevents edition.
mEventHandlerId = 0;
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> /* event */)
{
std::cerr << "Caught JSONAPI event!" << std::endl;
RsQThreadUtils::postToObject([=]() { load(); }, this );
},
mEventHandlerId, RsEventType::JSON_API );
} }
JsonApiPage::~JsonApiPage()
{
rsEvents->unregisterEventsHandler(mEventHandlerId);
}
QString JsonApiPage::helpText() const
{
return tr("<h1><img width=\"24\" src=\":/icons/help_64.png\">&nbsp;&nbsp;Webinterface</h1> \
<p>Retroshare provides a JSON API allowing other softwares to communicate with its core using token-controlled HTTP requests to http://localhost:[port]. \
Please refer to the Retroshare documentation for how to use this feature. </p>\
<p>Unless you know what you're doing, you shouldn't need to change anything in this page. \
The web interface for instance will automatically register its own token to the JSON API which will be visible \
in the list of authenticated tokens after you enable it.</p>");
}
void JsonApiPage::enableJsonApi(bool checked) void JsonApiPage::enableJsonApi(bool checked)
{ {
ui.addTokenPushButton->setEnabled(checked); ui.addTokenPushButton->setEnabled(checked);
@ -93,9 +118,9 @@ bool JsonApiPage::updateParams()
void JsonApiPage::load() void JsonApiPage::load()
{ {
whileBlocking(ui.portSpinBox)->setValue(Settings->getJsonApiPort()); whileBlocking(ui.portSpinBox)->setValue(rsJsonApi->listeningPort());
whileBlocking(ui.listenAddressLineEdit)->setText(Settings->getJsonApiListenAddress()); whileBlocking(ui.listenAddressLineEdit)->setText(QString::fromStdString(rsJsonApi->getBindingAddress()));
whileBlocking(ui.enableCheckBox)->setChecked(Settings->getJsonApiEnabled()); whileBlocking(ui.enableCheckBox)->setChecked(rsJsonApi->isRunning());
QStringList newTk; QStringList newTk;
@ -104,10 +129,20 @@ void JsonApiPage::load()
QString::fromStdString(it.first) + ":" + QString::fromStdString(it.first) + ":" +
QString::fromStdString(it.second) ); QString::fromStdString(it.second) );
whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk)); whileBlocking(ui.tokensListView)->setModel(new QStringListModel(newTk));
}
QString JsonApiPage::helpText() const { return ""; } QStringList newTk2;
for(const auto& it : rsJsonApi->getResourceProviders())
newTk2.push_back( QString::fromStdString(it.get().getName())) ;
whileBlocking(ui.providersListView)->setModel(new QStringListModel(newTk2));
if(rsJsonApi->isRunning())
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDON)) ;
else
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDOFF)) ;
}
bool JsonApiPage::checkStartJsonApi() bool JsonApiPage::checkStartJsonApi()
{ {

View File

@ -20,6 +20,8 @@
#pragma once #pragma once
#include "retroshare/rsevents.h"
#include "retroshare-gui/configpage.h" #include "retroshare-gui/configpage.h"
#include "gui/common/FilesDefs.h" #include "gui/common/FilesDefs.h"
#include "ui_JsonApiPage.h" #include "ui_JsonApiPage.h"
@ -31,7 +33,7 @@ class JsonApiPage : public ConfigPage
public: public:
JsonApiPage(QWidget * parent = nullptr, Qt::WindowFlags flags = 0); JsonApiPage(QWidget * parent = nullptr, Qt::WindowFlags flags = 0);
~JsonApiPage() override = default; ~JsonApiPage() override ;
virtual QPixmap iconPixmap() const override virtual QPixmap iconPixmap() const override
{ {
@ -63,4 +65,6 @@ public slots:
private: private:
Ui::JsonApiPage ui; /// Qt Designer generated object Ui::JsonApiPage ui; /// Qt Designer generated object
RsEventsHandlerId_t mEventHandlerId;
}; };

View File

@ -13,7 +13,7 @@
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="WebuiPageVLayout"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QGroupBox" name="jsonApiGroupBox"> <widget class="QGroupBox" name="jsonApiGroupBox">
<property name="minimumSize"> <property name="minimumSize">
@ -25,13 +25,65 @@
<property name="title"> <property name="title">
<string>JSON API Server</string> <string>JSON API Server</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_3"> <layout class="QVBoxLayout" name="verticalLayout">
<item> <item>
<widget class="QCheckBox" name="enableCheckBox"> <layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="text"> <item>
<string>Enable RetroShare JSON API Server</string> <widget class="QCheckBox" name="enableCheckBox">
</property> <property name="text">
</widget> <string>Enable RetroShare JSON API Server</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabelLED">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../images.qrc">:/images/ledoff1.png</pixmap>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Listen Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="listenAddressLineEdit">
<property name="text">
<string>127.0.0.1</string>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
@ -57,24 +109,6 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Listen Address:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="listenAddressLineEdit">
<property name="text">
<string>127.0.0.1</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="horizontalLayout_3"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<item> <item>
@ -110,13 +144,23 @@
<item> <item>
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Authenticated Tokens</string> <string>Authenticated Tokens:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QListView" name="tokensListView"/> <widget class="QListView" name="tokensListView"/>
</item> </item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Registered services:</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="providersListView"/>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>
@ -142,6 +186,8 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<resources/> <resources>
<include location="../images.qrc"/>
</resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -107,6 +107,8 @@ ServerPage::ServerPage(QWidget * parent, Qt::WindowFlags flags)
ui.hiddenpage_proxyPort_tor->setEnabled(false) ; ui.hiddenpage_proxyPort_tor->setEnabled(false) ;
ui.hiddenpage_localAddress->setEnabled(false) ; ui.hiddenpage_localAddress->setEnabled(false) ;
ui.hiddenpage_localPort->setEnabled(false) ; ui.hiddenpage_localPort->setEnabled(false) ;
ui.hiddenpage_serviceAddress->setEnabled(false) ;
ui.hiddenpage_servicePort->setEnabled(false) ;
ui.testIncoming_PB->hide() ; ui.testIncoming_PB->hide() ;
ui.l_incomingTestResult->hide() ; ui.l_incomingTestResult->hide() ;
ui.iconlabel_service_incoming->hide() ; ui.iconlabel_service_incoming->hide() ;

View File

@ -30,6 +30,7 @@
#include "retroshare/rspeers.h" #include "retroshare/rspeers.h"
#include <QCheckBox> #include <QCheckBox>
#include <QMessageBox>
#include <QToolTip> #include <QToolTip>
#include <iostream> #include <iostream>
@ -46,6 +47,8 @@ TransferPage::TransferPage(QWidget * parent, Qt::WindowFlags flags)
ui._max_tr_up_per_sec_SB->setMinimum(max_tr_low); ui._max_tr_up_per_sec_SB->setMinimum(max_tr_low);
ui._max_tr_up_per_sec_SB->setMaximum(max_tr_high); ui._max_tr_up_per_sec_SB->setMaximum(max_tr_high);
whileBlocking(ui._trustFriendNodesWithBannedFiles_CB)->setChecked(rsFiles->trustFriendNodesWithBannedFiles());
QObject::connect(ui._queueSize_SB,SIGNAL(valueChanged(int)),this,SLOT(updateQueueSize(int))) ; QObject::connect(ui._queueSize_SB,SIGNAL(valueChanged(int)),this,SLOT(updateQueueSize(int))) ;
QObject::connect(ui._max_up_SB,SIGNAL(valueChanged(int)),this,SLOT(updateMaxUploadSlots(int))) ; QObject::connect(ui._max_up_SB,SIGNAL(valueChanged(int)),this,SLOT(updateMaxUploadSlots(int))) ;
QObject::connect(ui._defaultStrategy_CB,SIGNAL(activated(int)),this,SLOT(updateDefaultStrategy(int))) ; QObject::connect(ui._defaultStrategy_CB,SIGNAL(activated(int)),this,SLOT(updateDefaultStrategy(int))) ;
@ -53,6 +56,7 @@ TransferPage::TransferPage(QWidget * parent, Qt::WindowFlags flags)
QObject::connect(ui._diskSpaceLimit_SB,SIGNAL(valueChanged(int)),this,SLOT(updateDiskSizeLimit(int))) ; QObject::connect(ui._diskSpaceLimit_SB,SIGNAL(valueChanged(int)),this,SLOT(updateDiskSizeLimit(int))) ;
QObject::connect(ui._max_tr_up_per_sec_SB, SIGNAL( valueChanged( int ) ), this, SLOT( updateMaxTRUpRate(int) ) ); QObject::connect(ui._max_tr_up_per_sec_SB, SIGNAL( valueChanged( int ) ), this, SLOT( updateMaxTRUpRate(int) ) );
QObject::connect(ui._filePermDirectDL_CB,SIGNAL(activated(int)),this,SLOT(updateFilePermDirectDL(int))); QObject::connect(ui._filePermDirectDL_CB,SIGNAL(activated(int)),this,SLOT(updateFilePermDirectDL(int)));
QObject::connect(ui._trustFriendNodesWithBannedFiles_CB,SIGNAL(toggled(bool)),this,SLOT(toggleTrustFriendNodesWithBannedFiles(bool))) ;
QObject::connect(ui.incomingButton, SIGNAL(clicked( bool ) ), this , SLOT( setIncomingDirectory() ) ); QObject::connect(ui.incomingButton, SIGNAL(clicked( bool ) ), this , SLOT( setIncomingDirectory() ) );
QObject::connect(ui.autoDLColl_CB, SIGNAL(toggled(bool)), this, SLOT(updateAutoDLColl())); QObject::connect(ui.autoDLColl_CB, SIGNAL(toggled(bool)), this, SLOT(updateAutoDLColl()));
@ -94,7 +98,10 @@ void TransferPage::updateIgnoreLists()
std::cerr << " suffixes: " ; for(auto it(ls.begin());it!=ls.end();++it) std::cerr << "\"" << *it << "\" " ; std::cerr << std::endl; std::cerr << " suffixes: " ; for(auto it(ls.begin());it!=ls.end();++it) std::cerr << "\"" << *it << "\" " ; std::cerr << std::endl;
#endif #endif
} }
void TransferPage::toggleTrustFriendNodesWithBannedFiles(bool b)
{
rsFiles->setTrustFriendNodesWithBannedFiles(b);
}
void TransferPage::updateMaxTRUpRate(int b) void TransferPage::updateMaxTRUpRate(int b)
{ {
rsTurtle->setMaxTRForwardRate(b) ; rsTurtle->setMaxTRForwardRate(b) ;
@ -208,11 +215,19 @@ void TransferPage::updateDefaultStrategy(int i)
case 0: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_STREAMING) ; case 0: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_STREAMING) ;
break ; break ;
case 2: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_RANDOM) ; case 2:
break ; #ifdef WINDOWS_SYS
if(QMessageBox::Yes != QMessageBox::warning(nullptr,tr("Warning"),tr("On Windows systems, randomly writing in the middle of large empty files may hang the software for several seconds. Do you want to use this option anyway (otherwise use \"progressive\")?"),QMessageBox::Yes,QMessageBox::No))
{
ui._defaultStrategy_CB->setCurrentIndex(1);
return;
}
#endif
rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_RANDOM) ;
break ;
case 1: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE) ; case 1: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_PROGRESSIVE) ;
break ; break ;
default: ; default: ;
} }
} }

View File

@ -58,7 +58,8 @@ class TransferPage: public ConfigPage
void updateAutoDLColl(); void updateAutoDLColl();
void setPartialsDirectory(); void setPartialsDirectory();
void toggleAutoCheckDirectories(bool); void toggleAutoCheckDirectories(bool);
void updateFontSize(); void toggleTrustFriendNodesWithBannedFiles(bool);
void updateFontSize();
void updateAutoCheckDirectories() ; void updateAutoCheckDirectories() ;
void updateAutoScanDirectoriesPeriod() ; void updateAutoScanDirectoriesPeriod() ;

View File

@ -14,7 +14,7 @@
<item row="0" column="0"> <item row="0" column="0">
<widget class="QTabWidget" name="tabWidget"> <widget class="QTabWidget" name="tabWidget">
<property name="currentIndex"> <property name="currentIndex">
<number>0</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="tab"> <widget class="QWidget" name="tab">
<attribute name="title"> <attribute name="title">
@ -30,7 +30,7 @@
<item> <item>
<widget class="QPushButton" name="editShareButton"> <widget class="QPushButton" name="editShareButton">
<property name="text"> <property name="text">
<string>Edit Share</string> <string>Configure shared directories</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -443,7 +443,7 @@ p, li { white-space: pre-wrap; }
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Streaming &lt;/span&gt;causes the transfer to request 1MB file chunks in increasing order, facilitating preview while downloading. &lt;span style=&quot; font-weight:600;&quot;&gt;Random&lt;/span&gt; is purely random and favors swarming behavior. &lt;span style=&quot; font-weight:600;&quot;&gt;Progressive&lt;/span&gt; is a compromise, selecting the next chunk at random within less than 50MB after the end of the partial file. That allows some randomness while preventing large empty file initialization times.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string> <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Streaming &lt;/span&gt;causes the transfer to request 1MB file chunks in increasing order, facilitating preview while downloading. &lt;span style=&quot; font-weight:600;&quot;&gt;Random&lt;/span&gt; is purely random and favors swarming behavior (although not recommended on Windows systems). &lt;span style=&quot; font-weight:600;&quot;&gt;Progressive&lt;/span&gt; is a good compromise, selecting the next chunk at random within less than 50MB after the end of the partial file. That allows some randomness while preventing large empty file initialization times.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property> </property>
<item> <item>
<property name="text"> <property name="text">
@ -547,7 +547,7 @@ p, li { white-space: pre-wrap; }
</layout> </layout>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="checkBox"> <widget class="QCheckBox" name="_trustFriendNodesWithBannedFiles_CB">
<property name="text"> <property name="text">
<string>Trust friend nodes with banned files</string> <string>Trust friend nodes with banned files</string>
</property> </property>

View File

@ -27,6 +27,7 @@
#include <QSpinBox> #include <QSpinBox>
#include "util/misc.h" #include "util/misc.h"
#include "util/qtthreadsutils.h"
#include "retroshare/rswebui.h" #include "retroshare/rswebui.h"
#include "retroshare/rsjsonapi.h" #include "retroshare/rsjsonapi.h"
@ -40,6 +41,8 @@ resource_api::ApiServerLocal* WebuiPage::apiServerLocal = 0;
#endif #endif
resource_api::RsControlModule* WebuiPage::controlModule = 0; resource_api::RsControlModule* WebuiPage::controlModule = 0;
#define IMAGE_LEDOFF ":/images/ledoff1.png"
#define IMAGE_LEDON ":/images/ledon1.png"
WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/) WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
{ {
@ -50,11 +53,20 @@ WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
connect(ui.password_LE, SIGNAL(textChanged(QString)), this, SLOT(onPasswordValueChanged(QString))); connect(ui.password_LE, SIGNAL(textChanged(QString)), this, SLOT(onPasswordValueChanged(QString)));
connect(ui.startWebBrowser_PB, SIGNAL(clicked()), this, SLOT(onStartWebBrowserClicked())); connect(ui.startWebBrowser_PB, SIGNAL(clicked()), this, SLOT(onStartWebBrowserClicked()));
connect(ui.webInterfaceFilesDirectory_PB, SIGNAL(clicked()), this, SLOT(selectWebInterfaceDirectory())); connect(ui.webInterfaceFilesDirectory_PB, SIGNAL(clicked()), this, SLOT(selectWebInterfaceDirectory()));
mEventsHandlerId = 0;
rsEvents->registerEventsHandler( [this](std::shared_ptr<const RsEvent> /* event */)
{
std::cerr << "Caught JSONAPI event in webui!" << std::endl;
RsQThreadUtils::postToObject([=]() { load(); }, this );
},
mEventsHandlerId, RsEventType::JSON_API );
} }
WebuiPage::~WebuiPage() WebuiPage::~WebuiPage()
{ {
rsEvents->unregisterEventsHandler(mEventsHandlerId);
} }
void WebuiPage::selectWebInterfaceDirectory() void WebuiPage::selectWebInterfaceDirectory()
@ -73,22 +85,12 @@ void WebuiPage::selectWebInterfaceDirectory()
bool WebuiPage::updateParams(QString &errmsg) bool WebuiPage::updateParams(QString &errmsg)
{ {
std::cerr << "WebuiPage::save()" << std::endl; std::cerr << "WebuiPage::save()" << std::endl;
bool ok = true;
bool changed = false;
if(ui.enableWebUI_CB->isChecked() != Settings->getWebinterfaceEnabled())
changed = true;
if(ui.webInterfaceFiles_LE->text() != Settings->getWebinterfaceFilesDirectory())
changed = true;
if(changed) // store config
{ Settings->setWebinterfaceEnabled(ui.enableWebUI_CB->isChecked());
// store config Settings->setWebinterfaceFilesDirectory(ui.webInterfaceFiles_LE->text());
Settings->setWebinterfaceEnabled(ui.enableWebUI_CB->isChecked());
Settings->setWebinterfaceFilesDirectory(ui.webInterfaceFiles_LE->text());
rsWebUi->setHtmlFilesDirectory(ui.webInterfaceFiles_LE->text().toStdString()); return true;
}
return ok;
} }
void WebuiPage::onPasswordValueChanged(QString password) void WebuiPage::onPasswordValueChanged(QString password)
@ -112,10 +114,23 @@ void WebuiPage::onPasswordValueChanged(QString password)
bool WebuiPage::restart() bool WebuiPage::restart()
{ {
return checkStartWebui(); if(ui.password_LE->text().isNull())
{
QMessageBox::critical(nullptr,tr("Missing passphrase"),tr("Please set a passphrase to proect the access to the WEB interface."));
return false;
}
rsWebUi->setUserPassword(ui.password_LE->text().toStdString());
rsWebUi->setHtmlFilesDirectory(ui.webInterfaceFiles_LE->text().toStdString());
setCursor(Qt::WaitCursor) ;
rsWebUi->restart();
setCursor(Qt::ArrowCursor) ;
return true;
} }
void WebuiPage::load() void WebuiPage::loadParams()
{ {
std::cerr << "WebuiPage::load()" << std::endl; std::cerr << "WebuiPage::load()" << std::endl;
whileBlocking(ui.enableWebUI_CB)->setChecked(Settings->getWebinterfaceEnabled()); whileBlocking(ui.enableWebUI_CB)->setChecked(Settings->getWebinterfaceEnabled());
@ -127,6 +142,13 @@ void WebuiPage::load()
if(it != smap.end()) if(it != smap.end())
whileBlocking(ui.password_LE)->setText(QString::fromStdString(it->second)); whileBlocking(ui.password_LE)->setText(QString::fromStdString(it->second));
if(rsWebUi->isRunning())
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDON)) ;
else
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDOFF)) ;
#else
ui.statusLabelLED->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_LEDOFF)) ;
#endif #endif
} }
@ -138,13 +160,11 @@ QString WebuiPage::helpText() const
<p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p>"); <p>Warning: don't expose the webinterface to the internet, because there is no access control and no encryption. If you want to use the webinterface over the internet, use a SSH tunnel or a proxy to secure the connection.</p>");
} }
/*static*/ bool WebuiPage::checkStartWebui() /*static*/ bool WebuiPage::checkStartWebui() // This is supposed to be called from main(). But normally the parameters below (including the paswd
// for the webUI should be saved in p3webui instead.
{ {
if(!Settings->getWebinterfaceEnabled()) rsWebUi->setHtmlFilesDirectory(Settings->getWebinterfaceFilesDirectory().toStdString());
return false; rsWebUi->restart();
rsWebUi->setHtmlFilesDirectory(Settings->getWebinterfaceFilesDirectory().toStdString());
rsWebUi->restart();
return true; return true;
} }
@ -173,15 +193,21 @@ QString WebuiPage::helpText() const
void WebuiPage::onEnableCBClicked(bool checked) void WebuiPage::onEnableCBClicked(bool checked)
{ {
ui.params_GB->setEnabled(checked); QString errmsg;
ui.apply_PB->setEnabled(checked); updateParams(errmsg);
ui.startWebBrowser_PB->setEnabled(checked);
QString S;
Settings->setWebinterfaceEnabled(checked); ui.params_GB->setEnabled(checked);
ui.startWebBrowser_PB->setEnabled(checked);
ui.apply_PB->setEnabled(checked);
if(checked) if(checked)
checkStartWebui(); {
if(!restart())
{
QMessageBox::warning(0, tr("failed to start Webinterface"), "Failed to start the webinterface.");
return;
}
}
else else
checkShutdownWebui(); checkShutdownWebui();
} }
@ -199,18 +225,12 @@ void WebuiPage::onAllIPCBClicked(bool /*checked*/)
} }
void WebuiPage::onApplyClicked() void WebuiPage::onApplyClicked()
{ {
rsWebUi->setUserPassword(ui.password_LE->text().toStdString());
QString errmsg; QString errmsg;
updateParams(errmsg); updateParams(errmsg);
if(!restart()) restart();
{
QMessageBox::warning(0, tr("failed to start Webinterface"), "Failed to start the webinterface.");
return;
}
emit passwordChanged(); load();
} }
void WebuiPage::onStartWebBrowserClicked() { showWebui(); } void WebuiPage::onStartWebBrowserClicked() { showWebui(); }

View File

@ -20,6 +20,8 @@
#pragma once #pragma once
#include "retroshare/rsevents.h"
#include "retroshare-gui/configpage.h" #include "retroshare-gui/configpage.h"
#include "gui/common/FilesDefs.h" #include "gui/common/FilesDefs.h"
#include "ui_WebuiPage.h" #include "ui_WebuiPage.h"
@ -42,11 +44,11 @@ public:
~WebuiPage(); ~WebuiPage();
/** Loads the settings for this page */ /** Loads the settings for this page */
virtual void load(); virtual void load() override { loadParams() ; }
virtual QPixmap iconPixmap() const { return FilesDefs::getPixmapFromQtResourcePath(":/icons/settings/webinterface.svg") ; } virtual QPixmap iconPixmap() const override { return FilesDefs::getPixmapFromQtResourcePath(":/icons/settings/webinterface.svg") ; }
virtual QString pageName() const { return tr("Webinterface") ; } virtual QString pageName() const override { return tr("Webinterface") ; }
virtual QString helpText() const; virtual QString helpText() const override ;
// call this after start of libretroshare/Retroshare // call this after start of libretroshare/Retroshare
// checks the settings and starts the webinterface if required // checks the settings and starts the webinterface if required
@ -67,10 +69,9 @@ public slots:
void onApplyClicked(); void onApplyClicked();
void onStartWebBrowserClicked(); void onStartWebBrowserClicked();
signals:
void passwordChanged();
private: private:
virtual void loadParams();
/** Qt Designer generated object */ /** Qt Designer generated object */
Ui::WebuiPage ui; Ui::WebuiPage ui;
@ -83,4 +84,6 @@ private:
static resource_api::ApiServerLocal* apiServerLocal; static resource_api::ApiServerLocal* apiServerLocal;
#endif #endif
static resource_api::RsControlModule* controlModule; static resource_api::RsControlModule* controlModule;
RsEventsHandlerId_t mEventsHandlerId;
}; };

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>960</width> <width>570</width>
<height>717</height> <height>646</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -15,11 +15,45 @@
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QCheckBox" name="enableWebUI_CB"> <layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="text"> <item>
<string>Enable Retroshare WEB Interface</string> <widget class="QCheckBox" name="enableWebUI_CB">
</property> <property name="text">
</widget> <string>Enable Retroshare WEB Interface</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Status:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="statusLabelLED">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../images.qrc">:/images/ledoff1.png</pixmap>
</property>
</widget>
</item>
</layout>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="params_GB"> <widget class="QGroupBox" name="params_GB">

View File

@ -178,10 +178,7 @@ SettingsPage::initStackedWidget()
JsonApiPage *jsonapi_p = new JsonApiPage() ; JsonApiPage *jsonapi_p = new JsonApiPage() ;
addPage(jsonapi_p); addPage(jsonapi_p);
#ifdef RS_WEBUI #ifdef RS_WEBUI
WebuiPage *webui_p = new WebuiPage() ; addPage(new WebuiPage());
addPage(new WebuiPage() );
QObject::connect(webui_p,SIGNAL(passwordChanged()),jsonapi_p,SLOT(load()));
#endif #endif
#endif #endif

View File

@ -39,9 +39,9 @@ void Histogram::draw(QPainter */*painter*/) const
void Histogram::insert(double val) void Histogram::insert(double val)
{ {
long int bin = (uint32_t)floor((val - mStart)/(mEnd - mStart) * mBins.size()); long int bin = (long int)floor((val - mStart)/(mEnd - mStart) * mBins.size());
if(bin >= 0 && bin < mBins.size()) if(bin >= 0 && bin < (long int)mBins.size())
++mBins[bin]; ++mBins[bin];
} }

View File

@ -20,7 +20,7 @@
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <stdint.h> #include <cstdint>
class QPainter; class QPainter;

View File

@ -536,11 +536,9 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO);
// avoid clashes between infos from threads. // avoid clashes between infos from threads.
// //
qRegisterMetaType<FileDetail>("FileDetail") ;
qRegisterMetaType<RsPeerId>("RsPeerId") ; qRegisterMetaType<RsPeerId>("RsPeerId") ;
std::cerr << "connecting signals and slots" << std::endl ; std::cerr << "connecting signals and slots" << std::endl ;
// QObject::connect(notify,SIGNAL(gotTurtleSearchResult(qulonglong,FileDetail)),w->transfersDialog->searchDialog ,SLOT(updateFiles(qulonglong,FileDetail))) ;
QObject::connect(notify,SIGNAL(deferredSignatureHandlingRequested()),notify,SLOT(handleSignatureEvent()),Qt::QueuedConnection) ; QObject::connect(notify,SIGNAL(deferredSignatureHandlingRequested()),notify,SLOT(handleSignatureEvent()),Qt::QueuedConnection) ;
QObject::connect(notify,SIGNAL(chatLobbyTimeShift(int)),notify,SLOT(handleChatLobbyTimeShift(int)),Qt::QueuedConnection) ; QObject::connect(notify,SIGNAL(chatLobbyTimeShift(int)),notify,SLOT(handleChatLobbyTimeShift(int)),Qt::QueuedConnection) ;
QObject::connect(notify,SIGNAL(diskFull(int,int)) ,w ,SLOT(displayDiskSpaceWarning(int,int))) ; QObject::connect(notify,SIGNAL(diskFull(int,int)) ,w ,SLOT(displayDiskSpaceWarning(int,int))) ;

View File

@ -178,3 +178,9 @@ IdDialog QWidget#idTreeWidget {
selection-background-color: #9FCBFF; selection-background-color: #9FCBFF;
show-decoration-selected: 1; show-decoration-selected: 1;
} }
/* Wire */
QLabel#label_masthead{
border: 2px solid #CCCCCC;
border-radius: 4px;
}

View File

@ -1220,6 +1220,7 @@ gxsthewire {
gui/TheWire/PulseReply.h \ gui/TheWire/PulseReply.h \
gui/TheWire/PulseReplySeperator.h \ gui/TheWire/PulseReplySeperator.h \
gui/TheWire/PulseMessage.h \ gui/TheWire/PulseMessage.h \
gui/TheWire/CustomFrame.h \
FORMS += gui/TheWire/WireDialog.ui \ FORMS += gui/TheWire/WireDialog.ui \
gui/TheWire/WireGroupItem.ui \ gui/TheWire/WireGroupItem.ui \
@ -1242,6 +1243,7 @@ gxsthewire {
gui/TheWire/PulseReply.cpp \ gui/TheWire/PulseReply.cpp \
gui/TheWire/PulseReplySeperator.cpp \ gui/TheWire/PulseReplySeperator.cpp \
gui/TheWire/PulseMessage.cpp \ gui/TheWire/PulseMessage.cpp \
gui/TheWire/CustomFrame.cpp \
RESOURCES += gui/TheWire/TheWire_images.qrc RESOURCES += gui/TheWire/TheWire_images.qrc
} }

@ -1 +1 @@
Subproject commit b0ddb09184e8fff86bd3325e00c6d4b329ae1790 Subproject commit 542a8c07bd02f9bb9082f7aba5aaaed54e643fc1