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
[submodule "libretroshare"]
path = libretroshare
url = ../libretroshare
url = https://github.com/RetroShare/libretroshare.git
branch = master
[submodule "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()) {
/* 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()) {
/* use attachment as image */
processPostedFirstImage = FALSE;
processPostedFirstImage = false;
}
//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>();
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 */
SearchDialog::SearchDialog(QWidget *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.name = fe->mResults[i].fName;
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);
}
@ -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)) ;
@ -1320,8 +1334,8 @@ void SearchDialog::insertFile(qulonglong searchId, const FileDetail& file, int s
item->setText(SR_SIZE_COL, QString::number(file.size));
item->setData(SR_SIZE_COL, ROLE_SORT, (qulonglong) file.size);
item->setText(SR_AGE_COL, QString::number(file.age));
item->setData(SR_AGE_COL, ROLE_SORT, file.age);
item->setText(SR_AGE_COL, QString::number(file.mtime));
item->setData(SR_AGE_COL, ROLE_SORT, file.mtime);
item->setTextAlignment( SR_SIZE_COL, Qt::AlignRight );
int friendSource = 0;
int anonymousSource = 0;
@ -1396,21 +1410,21 @@ void SearchDialog::resultsToTree(const QString& txt,qulonglong searchId, const s
std::list<DirDetails>::const_iterator it;
for(it = results.begin(); it != results.end(); ++it)
if (it->type == DIR_TYPE_FILE) {
if (it->type == DIR_TYPE_FILE)
{
FileDetail fd;
fd.id = it->id;
fd.name = it->name;
fd.hash = it->hash;
fd.path = it->path;
fd.size = it->size;
fd.age = it->mtime;
fd.mtime= it->mtime;
fd.rank = 0;
insertFile(searchId,fd, FRIEND_SEARCH);
} else if (it->type == DIR_TYPE_DIR) {
// insertDirectory(txt, searchId, *it, NULL);
insertDirectory(txt, searchId, *it);
}
else if (it->type == DIR_TYPE_DIR)
insertDirectory(txt, searchId, *it);
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 textColorHighSources READ textColorHighSources WRITE setTextColorHighSources)
struct FileDetail; // useful structure to store search results.
public:
/** Default Constructor */
SearchDialog(QWidget *parent = 0);
@ -63,8 +64,7 @@ public:
void setTextColorLowSources(QColor color) { mTextColorLowSources = color; }
void setTextColorHighSources(QColor color) { mTextColorHighSources = color; }
public slots:
void updateFiles(qulonglong request_id,FileDetail file) ;
void updateFiles(qulonglong request_id, const FileDetail& file) ;
private slots:

View File

@ -442,7 +442,7 @@ public:
{
QString strPath = QString::fromUtf8(fileInfo.path.c_str());
QString strPathAfterDL = strPath;
strPathAfterDL.replace(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()),"");
strPathAfterDL.replace(QString::fromUtf8(rsFiles->getDownloadDirectory().c_str()),"[Download Dir]");
return QVariant(strPathAfterDL);
}
@ -2074,22 +2074,23 @@ void TransfersDialog::dlOpenFolder()
break;
}
/* make path for downloaded or downloading files */
QFileInfo qinfo;
std::string path;
if (info.downloadStatus == FT_STATE_COMPLETE) {
path = info.path;
} else {
path = rsFiles->getPartialsDirectory();
openFolder(info);
}
void TransfersDialog::openFolder(const FileInfo& info)
{
/* make path for downloaded or downloading files */
QDir directory;
if (info.downloadStatus == FT_STATE_COMPLETE)
directory = QFileInfo(QString::fromStdString(info.path)).absoluteDir().path();
else
directory = QDir(QString::fromStdString(rsFiles->getPartialsDirectory()));
/* 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 << "dlOpenFolder(): can't open folder " << path << std::endl;
}
}
if (directory.exists() && !RsUrlHandler::openUrl(QUrl::fromLocalFile(directory.path())))
std::cerr << "dlOpenFolder(): can't open folder " << directory.path().toStdString() << std::endl;
}
void TransfersDialog::ulOpenFolder()
@ -2104,19 +2105,7 @@ void TransfersDialog::ulOpenFolder()
break;
}
/* make path for uploading files */
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;
}
}
openFolder(info);
}
void TransfersDialog::dlPreviewFile()
@ -2139,7 +2128,7 @@ void TransfersDialog::dlPreviewFile()
/* make path for downloaded or downloading files */
QFileInfo fileInfo;
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 {
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 */
std::string path;
if (info.downloadStatus == FT_STATE_COMPLETE) {
path = info.path + "/" + info.fname;
path = info.path ;
/* open file with a suitable application */
QFileInfo qinfo;
@ -2244,6 +2233,10 @@ void TransfersDialog::chunkStreaming()
}
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) ;
}
void TransfersDialog::chunkProgressive()

View File

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

View File

@ -83,7 +83,7 @@ NetworkDialog::NetworkDialog(QWidget */*parent*/)
ui.connectTreeWidget->setUpdatesEnabled(true);
ui.connectTreeWidget->setSortingEnabled(true);
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(doubleClicked(QModelIndex)), this, SLOT(peerdetails()));
@ -117,24 +117,12 @@ void NetworkDialog::connectTreeWidgetCostumPopupMenu( QPoint /*point*/ )
{
return;
}
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->addSeparator() ;
contextMnu->addAction(QIcon(), tr("Remove unused keys..."), this, SLOT(removeUnusedKeys()));
contextMnu->addAction(QIcon(), tr("Remove this key"), this, SLOT(removeSelectedKeys()));
contextMnu->exec(QCursor::pos());
}
@ -177,11 +165,34 @@ void NetworkDialog::removeSelectedKeys()
QModelIndexList l = ui.connectTreeWidget->selectionModel()->selection().indexes();
if(l.empty())
return;
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()));
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)

View File

@ -22,6 +22,7 @@
#include <QMenu>
#include <QSignalMapper>
#include <QPainter>
#include <QClipboard>
#include <QMessageBox>
#include "retroshare/rsgxscircles.h"
@ -72,6 +73,7 @@ static const int POSTED_TABS_POSTS = 1;
//
#define IMAGE_COPYLINK ":/images/copyrslink.png"
#define IMAGE_AUTHOR ":/images/user/personal64.png"
#define IMAGE_COPYHTTP ":/images/emblem-web.png"
Q_DECLARE_METATYPE(RsPostedPost);
@ -340,7 +342,18 @@ void PostedListWidgetWithModel::postContextMenu(const QPoint& point)
// 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);
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);
#ifdef TODO
@ -456,6 +469,31 @@ void PostedListWidgetWithModel::showAuthorInPeople()
MainWindow::showWindow(MainWindow::People);
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()
{
try
@ -823,6 +861,7 @@ void PostedListWidgetWithModel::insertBoardDetails(const RsPostedGroup& group)
ui->subscribeToolButton->setText(tr("Subscribe"));
ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount));
ui->poplabel->setText(QString::number(group.mMeta.mPop));
if(group.mMeta.mLastPost==0)
ui->infoLastPost->setText(tr("Never"));

View File

@ -147,6 +147,7 @@ private slots:
void settingsChanged();
void postPostLoad();
void copyMessageLink();
void copyHttpLink();
void nextPosts();
void prevPosts();
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;
&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; }
&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>
</property>
<property name="textInteractionFlags">
@ -84,8 +84,11 @@ p, li { white-space: pre-wrap; }
<bold>true</bold>
</font>
</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">
<string>Contributions:</string>
<string>Items (at friends):</string>
</property>
</widget>
</item>
@ -179,6 +182,9 @@ p, li { white-space: pre-wrap; }
<bold>true</bold>
</font>
</property>
<property name="toolTip">
<string>Number of subscribed friend nodes</string>
</property>
<property name="text">
<string>Popularity:</string>
</property>
@ -615,8 +621,8 @@ p, li { white-space: pre-wrap; }
</customwidget>
</customwidgets>
<resources>
<include location="../icons.qrc"/>
<include location="Posted_images.qrc"/>
<include location="../icons.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -91,6 +91,7 @@ class RSHumanReadableAgeDelegate: public RSHumanReadableDelegate
QStyleOptionViewItem opt(option) ;
setPainterOptions(painter,opt,index) ;
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">
<font>
<pointsize>12</pointsize>
<weight>75</weight>
<bold>true</bold>
</font>
</property>

View File

@ -24,11 +24,15 @@
#include <QBuffer>
#include "PulseViewGroup.h"
#include "CustomFrame.h"
#include "WireGroupDialog.h"
#include "gui/gxs/GxsIdDetails.h"
#include "gui/common/FilesDefs.h"
#include "util/DateTime.h"
Q_DECLARE_METATYPE(RsWireGroup)
/** Constructor */
PulseViewGroup::PulseViewGroup(PulseViewHolder *holder, RsWireGroupSPtr group)
@ -37,6 +41,9 @@ PulseViewGroup::PulseViewGroup(PulseViewHolder *holder, RsWireGroupSPtr group)
setupUi(this);
setAttribute ( Qt::WA_DeleteOnClose, true );
setup();
connect(editButton, SIGNAL(clicked()), this, SLOT(editProfile()));
}
void PulseViewGroup::setup()
@ -50,8 +57,33 @@ void PulseViewGroup::setup()
label_tagline->setText(QString::fromStdString(mGroup->mTagline));
label_location->setText(QString::fromStdString(mGroup->mLocation));
// need to draw mGroup->mMasthead, as background to headshot.
// TODO frame_headerBackground->setBackground()
if (mGroup->mMasthead.mData)
{
QPixmap pixmap;
if (GxsIdDetails::loadPixmapFromData(
mGroup->mMasthead.mData,
mGroup->mMasthead.mSize,
pixmap, GxsIdDetails::ORIGINAL))
{
QSize frameSize = frame_masthead->size();
// Scale the pixmap based on the frame size
pixmap = pixmap.scaledToWidth(frameSize.width(), Qt::SmoothTransformation);
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)
{
@ -61,14 +93,14 @@ void PulseViewGroup::setup()
mGroup->mHeadshot.mSize,
pixmap,GxsIdDetails::ORIGINAL))
{
pixmap = pixmap.scaled(50,50);
pixmap = pixmap.scaled(100,100, Qt::KeepAspectRatio, Qt::SmoothTransformation);
label_headshot->setPixmap(pixmap);
}
}
else
{
// 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);
}
@ -93,6 +125,23 @@ void PulseViewGroup::setup()
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()
@ -107,3 +156,17 @@ void PulseViewGroup::actionFollow()
}
}
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:
void actionFollow();
void editProfile();
protected:
void setup();
private:
void setGroupSet();
protected:
RsWireGroupSPtr mGroup;

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>745</width>
<width>746</width>
<height>483</height>
</rect>
</property>
@ -48,19 +48,37 @@
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="plainFrame_VL">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QFrame" name="frame_headerBackground">
<layout class="QHBoxLayout" name="frame_headerBackground_HL">
<widget class="CustomFrame" name="frame_masthead">
<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>
<spacer name="frame_headerBackground_LHSpacer">
<spacer name="widget_actions_RHSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>283</width>
<height>20</height>
<width>277</width>
<height>17</height>
</size>
</property>
</spacer>
@ -79,19 +97,22 @@
<height>100</height>
</size>
</property>
<property name="styleSheet">
<string notr="true"/>
</property>
<property name="text">
<string>headshot</string>
</property>
</widget>
</item>
<item>
<spacer name="frame_headerBackground_RHSpacer">
<spacer name="widget_actions_LHSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>23</width>
<width>281</width>
<height>20</height>
</size>
</property>
@ -115,38 +136,6 @@
</size>
</property>
<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">
<widget class="QLabel" name="label_authorName">
<property name="sizePolicy">
@ -182,6 +171,45 @@
</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="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>
</widget>
</item>
@ -206,41 +234,6 @@
</size>
</property>
<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">
<widget class="QLabel" name="label_location">
<property name="sizePolicy">
@ -260,19 +253,6 @@
</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="0" column="0" colspan="4">
<widget class="QLabel" name="label_tagline">
<property name="sizePolicy">
@ -292,6 +272,54 @@
</property>
</widget>
</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>
</widget>
</item>
@ -538,10 +566,25 @@
</widget>
</item>
</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>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>CustomFrame</class>
<extends>QFrame</extends>
<header>gui/TheWire/CustomFrame.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

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

View File

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

View File

@ -35,12 +35,18 @@ WireGroupExtra::~WireGroupExtra()
void WireGroupExtra::setUp()
{
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()
{
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Masthead"), 400, 100);
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load Masthead"), 800, 600);
if (img.isNull())
return;
@ -48,7 +54,6 @@ void WireGroupExtra::addMasthead()
setMasthead(img);
}
void WireGroupExtra::setTagline(const std::string &str)
{
ui.lineEdit_Tagline->setText(QString::fromStdString(str));
@ -62,7 +67,20 @@ void WireGroupExtra::setLocation(const std::string &str)
void WireGroupExtra::setMasthead(const QPixmap &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()
@ -77,7 +95,5 @@ std::string WireGroupExtra::getLocation()
QPixmap WireGroupExtra::getMasthead()
{
return mMasthead;
return ui.label_masthead->extractCroppedScaledPicture();
}

View File

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

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>516</width>
<height>199</height>
<height>133</height>
</rect>
</property>
<property name="sizePolicy">
@ -19,21 +19,55 @@
<property name="windowTitle">
<string>Form</string>
</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">
<widget class="QLabel" name="label_2">
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="1">
<widget class="QLineEdit" name="lineEdit_Location"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="captionLabel">
<property name="text">
<string>Masthead</string>
<string>Tagline:</string>
</property>
</widget>
</item>
<item row="0" column="1" rowspan="2">
<widget class="QLabel" name="label_masthead">
<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>MastHead background Image</string>
<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">
@ -41,28 +75,71 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="captionLabel">
<property name="text">
<string>Tagline:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineEdit_Tagline"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<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>Location:</string>
<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>
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_Location"/>
</layout>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ZoomableLabel</class>
<extends>QLabel</extends>
<header>gui/gxschannels/GxsChannelPostThumbnail.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

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

View File

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

View File

@ -258,7 +258,11 @@ void ElidedLabel::mousePressEvent(QMouseEvent *ev)
return; // eat event
}
QLabel::mousePressEvent(ev);
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)

View File

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

View File

@ -1145,8 +1145,6 @@ void RsFriendListModel::updateInternalData()
mLocations.clear();
mTopLevel.clear();
endResetModel();
auto TL = mTopLevel ; // This allows to fill TL without touching mTopLevel outside of [begin/end]InsertRows().
// create a map of profiles and groups
@ -1282,6 +1280,7 @@ void RsFriendListModel::updateInternalData()
endInsertRows();
}
endResetModel();
postMods();
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),
mGroupMeta(group_meta)
{
mLoadingGroup = false;
mLoadingMessage = false;
mLoadingComment = false;
mPost.mMeta.mMsgId = messageId; // useful for uniqueIdentifer() before the post is loaded
mPost.mMeta.mGroupId = mGroupMeta.mGroupId;
@ -136,6 +140,19 @@ void GxsChannelPostItem::paintEvent(QPaintEvent *e)
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);
}
@ -277,6 +294,7 @@ void GxsChannelPostItem::loadGroup()
std::cerr << "GxsChannelGroupItem::loadGroup()";
std::cerr << std::endl;
#endif
mLoadingGroup = true;
RsThread::async([this]()
{
@ -306,6 +324,7 @@ void GxsChannelPostItem::loadGroup()
* after a blocking call to RetroShare API complete */
mGroupMeta = group.mMeta;
mLoadingGroup = false;
}, this );
});
@ -316,6 +335,8 @@ void GxsChannelPostItem::loadMessage()
std::cerr << "GxsChannelPostItem::loadMessage()";
std::cerr << std::endl;
#endif
mLoadingMessage = true;
RsThread::async([this]()
{
// 1 - get group data
@ -337,7 +358,11 @@ void GxsChannelPostItem::loadMessage()
#endif
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)
{
@ -356,6 +381,7 @@ void GxsChannelPostItem::loadMessage()
setMessageId(cmt.mMeta.mThreadId);
requestMessage();
mLoadingMessage = false;
}, this );
}
@ -366,7 +392,11 @@ void GxsChannelPostItem::loadMessage()
std::cerr << std::endl;
#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 << std::endl;
#endif
mLoadingComment = true;
RsThread::async([this]()
{
@ -407,6 +438,7 @@ void GxsChannelPostItem::loadComment()
sComButText = tr("Comments ").append("(%1)").arg(comNb);
ui->commentButton->setText(sComButText);
mLoadingComment = false;
}, this );
});

View File

@ -121,6 +121,11 @@ private:
bool mCloseOnRead;
bool mLoaded;
bool mLoadingMessage;
bool mLoadingGroup;
bool mLoadingComment;
RsGroupMetaData mGroupMeta;
RsGxsChannelPost mPost;

View File

@ -47,6 +47,12 @@ GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const
{
mMessage.mMeta.mMsgId = messageId; // useful for uniqueIdentifier() before the post is actually loaded
mMessage.mMeta.mGroupId = groupId;
mLoadingGroup = false;
mLoadingMessage = false;
mLoadingSetAsRead = false;
mLoadingParentMessage = false;
setup();
requestGroup();
@ -83,6 +89,19 @@ GxsForumMsgItem::GxsForumMsgItem(FeedHolder *feedHolder, uint32_t feedId, const
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);
}
@ -167,6 +186,8 @@ QString GxsForumMsgItem::groupName()
void GxsForumMsgItem::loadGroup()
{
mLoadingGroup = true;
RsThread::async([this]()
{
// 1 - get group data
@ -199,6 +220,7 @@ void GxsForumMsgItem::loadGroup()
* after a blocking call to RetroShare API complete */
setGroup(group);
mLoadingGroup = false;
}, this );
});
@ -210,6 +232,7 @@ void GxsForumMsgItem::loadMessage()
std::cerr << "GxsForumMsgItem::loadMessage(): messageId=" << messageId() << " groupId=" << groupId() ;
std::cerr << std::endl;
#endif
mLoadingMessage = true;
RsThread::async([this]()
{
@ -244,6 +267,7 @@ void GxsForumMsgItem::loadMessage()
* after a blocking call to RetroShare API complete */
setMessage(msg);
mLoadingMessage = false;
}, this );
});
@ -255,6 +279,7 @@ void GxsForumMsgItem::loadParentMessage(const RsGxsMessageId& parent_msg)
std::cerr << "GxsForumMsgItem::loadParentMessage()";
std::cerr << std::endl;
#endif
mLoadingParentMessage = true;
RsThread::async([parent_msg,this]()
{
@ -291,6 +316,8 @@ void GxsForumMsgItem::loadParentMessage(const RsGxsMessageId& parent_msg)
mParentMessage = msg;
fillParentMessage();
mLoadingParentMessage = false;
}, this );
});
}
@ -480,6 +507,7 @@ void GxsForumMsgItem::setAsRead(bool doUpdate)
}
mCloseOnRead = false;
mLoadingSetAsRead = true;
RsThread::async( [this, doUpdate]() {
RsGxsGrpMsgIdPair msgPair = std::make_pair(groupId(), messageId());
@ -489,6 +517,7 @@ void GxsForumMsgItem::setAsRead(bool doUpdate)
if (doUpdate) {
RsQThreadUtils::postToObject( [this]() {
setReadStatus(false, true);
mLoadingSetAsRead = false;
} );
}
});

View File

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

View File

@ -29,6 +29,8 @@
#include <QMessageBox>
#include <QDateTime>
//#define DEBUG_COMMENT_DIALOG 1
/** Constructor */
GxsCommentDialog::GxsCommentDialog(QWidget *parent, const RsGxsId &default_author, RsGxsCommentService *comment_service)
: 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)
{
std::cerr << "GxsCommentDialog::commentLoad(" << grpId << ", most recent msg version: " << most_recent_msgId << ")";
std::cerr << std::endl;
#ifdef DEBUG_COMMENT_DIALOG
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;
mMostRecentMsgId = most_recent_msgId;

View File

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

View File

@ -1105,6 +1105,11 @@ void GxsGroupFrameDialog::updateGroupSummary()
* Qt::QueuedConnection is important!
*/
// 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();
@ -1132,6 +1137,11 @@ void GxsGroupFrameDialog::updateGroupSummary()
delete groupInfo;
// Restore the focus.
if(w)
w->setFocus();
}, this );
});
}
@ -1166,10 +1176,10 @@ void GxsGroupFrameDialog::updateGroupStatisticsReal(const RsGxsGroupId &groupId)
*/
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);
mCachedGroupStats[groupId] = stats;
getUserNotify()->updateIcon();

View File

@ -193,16 +193,24 @@ void GxsIdTreeItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem
QStyleOptionViewItem ownOption (option);
initStyleOption(&ownOption, index);
QString dt = index.data(Qt::UserRole).toString();
RsGxsId id(index.data(Qt::UserRole).toString().toStdString());
QString cmt;
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
{
QString cmt;
if(! computeNameIconAndComment(id,ownOption.text,ownOption.icon,cmt))
{
if(mReloadPeriod > 3)

View File

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

View File

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

View File

@ -50,14 +50,11 @@ GxsChannelFilesStatusWidget::GxsChannelFilesStatusWidget(const RsGxsFile &file,
connect(ui->openFilePushButton, SIGNAL(clicked()), this, SLOT(openFile()));
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);
connect(openfolder, SIGNAL(triggered()), this, SLOT(openFolder()));
ui->openFolderPushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/folderopen.png"));
ui->openFolderPushButton->setToolTip(tr("Open folder"));
QMenu *menu = new QMenu();
menu->addAction(openfolder);
ui->openFolderToolButton->setMenu(menu);
connect(ui->openFolderPushButton, SIGNAL(clicked()), this, SLOT(openFolder()));
check();
}
@ -90,7 +87,9 @@ void GxsChannelFilesStatusWidget::setSize(uint64_t size)
void GxsChannelFilesStatusWidget::check()
{
FileInfo fileInfo;
if (rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) {
if(haveFile(fileInfo))
{
mState = STATE_LOCAL;
setSize(fileInfo.size);
@ -103,27 +102,25 @@ void GxsChannelFilesStatusWidget::check()
ui->openFilePushButton->setText(tr("Play"));
ui->openFilePushButton->setIcon(FilesDefs::getIconFromQtResourcePath(":/icons/png/play.png"));
}
} else {
FileInfo fileInfo;
bool detailsOk = rsFiles->FileDetails(mFile.mHash, RS_FILE_HINTS_DOWNLOAD | RS_FILE_HINTS_SPEC_ONLY, fileInfo);
if (detailsOk) {
switch (fileInfo.downloadStatus) {
}
else
{
switch (fileInfo.downloadStatus)
{
case FT_STATE_WAITING:
mState = STATE_WAITING;
break;
case FT_STATE_DOWNLOADING:
if (fileInfo.avail == fileInfo.size) {
if (fileInfo.avail == fileInfo.size)
mState = STATE_LOCAL;
} else {
else
mState = STATE_DOWNLOAD;
}
setSize(fileInfo.size);
ui->progressBar->setValue(fileInfo.avail / mDivisor);
break;
case FT_STATE_COMPLETE:
mState = STATE_DOWNLOAD;
case FT_STATE_COMPLETE: // this should not happen, since the case is handled earlier
mState = STATE_ERROR;
break;
case FT_STATE_QUEUED:
mState = STATE_WAITING;
@ -134,12 +131,9 @@ void GxsChannelFilesStatusWidget::check()
case FT_STATE_CHECKING_HASH:
mState = STATE_CHECKING;
break;
case FT_STATE_FAILED:
mState = STATE_ERROR;
break;
}
} else {
default:
mState = STATE_REMOTE;
break;
}
}
@ -156,7 +150,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->hide();
ui->progressBar->hide();
ui->openFilePushButton->hide();
ui->openFolderToolButton->hide();
ui->openFolderPushButton->hide();
statusText = tr("Error");
@ -171,7 +165,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->hide();
ui->progressBar->hide();
ui->openFilePushButton->hide();
ui->openFolderToolButton->hide();
ui->openFolderPushButton->hide();
break;
@ -184,7 +178,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show();
ui->progressBar->show();
ui->openFilePushButton->hide();
ui->openFolderToolButton->hide();
ui->openFolderPushButton->hide();
break;
@ -197,7 +191,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show();
ui->progressBar->hide();
ui->openFilePushButton->hide();
ui->openFolderToolButton->hide();
ui->openFolderPushButton->hide();
statusText = tr("Paused");
@ -212,7 +206,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show();
ui->progressBar->hide();
ui->openFilePushButton->hide();
ui->openFolderToolButton->hide();
ui->openFolderPushButton->hide();
statusText = tr("Waiting");
@ -227,7 +221,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->show();
ui->progressBar->hide();
ui->openFilePushButton->hide();
ui->openFolderToolButton->hide();
ui->openFolderPushButton->hide();
statusText = tr("Checking");
@ -242,7 +236,7 @@ void GxsChannelFilesStatusWidget::check()
ui->cancelToolButton->hide();
ui->progressBar->hide();
ui->openFilePushButton->show();
ui->openFolderToolButton->show();
ui->openFolderPushButton->show();
break;
}
@ -324,35 +318,60 @@ void GxsChannelFilesStatusWidget::cancel()
void GxsChannelFilesStatusWidget::openFolder()
{
FileInfo fileInfo;
if (!rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) {
if (!haveFile(fileInfo))
return;
}
QFileInfo finfo;
finfo.setFile(QString::fromUtf8(fileInfo.path.c_str()));
/* open folder with a suitable application */
QDir dir = QFileInfo(QString::fromUtf8(fileInfo.path.c_str())).absoluteDir();
if (dir.exists()) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(dir.absolutePath()))) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(finfo.absolutePath()))) {
if(!mUsedAsEditor)
QMessageBox::warning(this, "", QString("%1 %2").arg(tr("Can't open folder"), dir.absolutePath()));
QMessageBox::warning(this, "", QString("%1 %2").arg(tr("Can't open folder"), finfo.absolutePath()));
else
RsErr() << "Can't open folder " << dir.absolutePath().toStdString() ;
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()
{
FileInfo fileInfo;
if (!rsFiles->alreadyHaveFile(mFile.mHash, fileInfo)) {
if(!haveFile(fileInfo))
return;
}
/* open file with a suitable application */
QFileInfo qinfo;
qinfo.setFile(QString::fromUtf8(fileInfo.path.c_str()));
if (qinfo.exists()) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(qinfo.absoluteFilePath()))) {
QFileInfo finfo;
finfo.setFile(QString::fromUtf8(fileInfo.path.c_str()));
if (finfo.exists()) {
if (!RsUrlHandler::openUrl(QUrl::fromLocalFile(finfo.absoluteFilePath()))) {
std::cerr << "GxsChannelFilesStatusWidget(): can't open file " << fileInfo.path << std::endl;
}
}else{

View File

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

View File

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

View File

@ -342,10 +342,20 @@ public:
case RsGxsChannelPostFilesModel::COLUMN_FILES_FILE:
{
FileInfo fi1,fi2;
rsFiles->FileDetails(f1.mHash,RS_FILE_HINTS_DOWNLOAD,fi1);
rsFiles->FileDetails(f2.mHash,RS_FILE_HINTS_DOWNLOAD,fi2);
bool r1 = rsFiles->FileDetails(f1.mHash,RS_FILE_HINTS_DOWNLOAD,fi1);
bool r2 = rsFiles->FileDetails(f2.mHash,RS_FILE_HINTS_DOWNLOAD,fi2);
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;
}
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
{
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
{
if(row < 0 || column < 0 || column >= (int)mColumns)
if(row < 0 || column < 0 || row >= rowCount() || column >= columnCount(row))
return QModelIndex();
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 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;

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->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->postsTree->selectionModel(),SIGNAL(selectionChanged(const QItemSelection&,const QItemSelection&)),this,SLOT(showPostDetails()));
@ -504,6 +504,30 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
}, 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)
{
GxsMessageFrameWidget::resizeEvent(e);
@ -1344,13 +1368,26 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
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()));
action->setData(QVariant::fromValue(sender()));
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());
}
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());
}
@ -1358,16 +1395,11 @@ void GxsChannelPostsWidgetWithModel::copyChannelFilesLink()
{
// Block the popup if no results available
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;
if(!static_cast<RsGxsChannelPostFilesModel*>(tree->model())->getFileData(sel.front(),file))
if(!static_cast<const RsGxsChannelPostFilesModel*>(s.model())->getFileData(s,file))
return;
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 */
virtual void setAllMessagesReadDo(bool read) override;
virtual void resizeEvent(QResizeEvent *e) override;
virtual void keyPressEvent(QKeyEvent *e) override;
private slots:
void showPostDetails();
@ -166,6 +167,7 @@ public slots:
void sortColumnPostFiles(int col,Qt::SortOrder so);
void updateCommentsCount(int n);
void showChannelFilesContextMenu(QPoint p);
void showChannelPostFilesContextMenu(QPoint p);
void copyChannelFilesLink();
private:

View File

@ -15,6 +15,7 @@
<file>icons/svg/display_options.svg</file>
<file>icons/svg/listlayout.svg</file>
<file>icons/svg/gridlayout.svg</file>
<file>icons/svg/people2.svg</file>
<file>icons/stars/star0.png</file>
<file>icons/stars/star1.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;
// needed to send system flags with reply
unsigned msgFlags;
unsigned int msgFlags;
RSTreeWidgetItemCompareRole *m_compareRole;
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_TO: {
QString name;
if(GxsIdTreeItemDelegate::computeName(RsGxsId(fmpe.to.toStdString()),name))
return name;
return ""; //Not Found
}
case COLUMN_THREAD_AUTHOR:{
QString name;
@ -474,6 +466,8 @@ QVariant RsMessageModel::sortRole(const Rs::Msgs::MsgInfoSummary& fmpe,int colum
return name;
return ""; //Not Found
}
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_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:
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)
{
if(fn != mQuickViewFilter)

View File

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

View File

@ -738,6 +738,7 @@ void MessageWidget::remove()
return;
}
#ifdef TO_REMOVE
bool deleteReal = false;
if (msgInfo.msgflags & RS_MSG_TRASH) {
deleteReal = true;
@ -763,8 +764,8 @@ void MessageWidget::remove()
deleteLater();
}
}
emit messageRemoved();
#endif
emit messageRemovalRequested(currMsgId);
}
void MessageWidget::print()
@ -905,11 +906,9 @@ void MessageWidget::sendInvite()
if(mi.from.type()!=MsgAddress::MSG_ADDRESS_TYPE_RSGXSID)
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);
}
}
void MessageWidget::setToolbarButtonStyle(Qt::ToolButtonStyle style)
{

View File

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

View File

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

View File

@ -117,7 +117,6 @@ class NotifyQt: public QObject, public NotifyClient
void chatStatusChanged(const ChatId&,const QString&) const ;
void chatCleared(const ChatId&) 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 ownAvatarChanged() const ;
void ownStatusMessageChanged() const ;

View File

@ -2552,3 +2552,10 @@ OpModeStatus[opMode="Minimal"] {
[WrongValue="true"] {
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;
}
QLabel#label_masthead{
border: 2px solid #CCCCCC;
border-radius: 4px;
}
/**** PhotoShare ****/
AlbumItem QFrame#albumFrame {
border: 2px solid #CCCCCC;

View File

@ -74,7 +74,12 @@ AppearancePage::AppearancePage(QWidget * parent, Qt::WindowFlags flags)
foreach (QString code, LanguageSupport::languageCodes()) {
ui.cmboLanguage->addItem(FilesDefs::getIconFromQtResourcePath(":/images/flags/" + code + ".png"), LanguageSupport::languageName(code), code);
}
// 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());
}
@ -266,9 +271,9 @@ void AppearancePage::load()
index = ui.mainPageButtonType_CB->findData(Settings->getPageButtonLoc());
if (index != 0) {
ui.cmboTollButtonsStyle->hide();
}else {
ui.cmboTollButtonsStyle->show();
}else {
ui.cmboTollButtonsStyle->hide();
}
whileBlocking(ui.mainPageButtonType_CB)->setCurrentIndex(!Settings->getPageButtonLoc());

View File

@ -23,11 +23,14 @@
#include "rsharesettings.h"
#include "jsonapi/jsonapi.h"
#include "util/misc.h"
#include "util/qtthreadsutils.h"
#include <QTimer>
#include <QStringListModel>
#include <QProgressDialog>
#define IMAGE_LEDOFF ":/images/ledoff1.png"
#define IMAGE_LEDON ":/images/ledon1.png"
JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
{
@ -57,9 +60,31 @@ JsonApiPage::JsonApiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
QRegExpValidator *ipValidator = new QRegExpValidator(ipRegex, this);
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)
{
ui.addTokenPushButton->setEnabled(checked);
@ -93,9 +118,9 @@ bool JsonApiPage::updateParams()
void JsonApiPage::load()
{
whileBlocking(ui.portSpinBox)->setValue(Settings->getJsonApiPort());
whileBlocking(ui.listenAddressLineEdit)->setText(Settings->getJsonApiListenAddress());
whileBlocking(ui.enableCheckBox)->setChecked(Settings->getJsonApiEnabled());
whileBlocking(ui.portSpinBox)->setValue(rsJsonApi->listeningPort());
whileBlocking(ui.listenAddressLineEdit)->setText(QString::fromStdString(rsJsonApi->getBindingAddress()));
whileBlocking(ui.enableCheckBox)->setChecked(rsJsonApi->isRunning());
QStringList newTk;
@ -105,9 +130,19 @@ void JsonApiPage::load()
QString::fromStdString(it.second) );
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()
{

View File

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

View File

@ -13,7 +13,7 @@
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="WebuiPageVLayout">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="jsonApiGroupBox">
<property name="minimumSize">
@ -25,7 +25,9 @@
<property name="title">
<string>JSON API Server</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="enableCheckBox">
<property name="text">
@ -33,6 +35,56 @@
</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>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
@ -57,24 +109,6 @@
</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>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
@ -110,13 +144,23 @@
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Authenticated Tokens</string>
<string>Authenticated Tokens:</string>
</property>
</widget>
</item>
<item>
<widget class="QListView" name="tokensListView"/>
</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>
</widget>
</item>
@ -142,6 +186,8 @@
</item>
</layout>
</widget>
<resources/>
<resources>
<include location="../images.qrc"/>
</resources>
<connections/>
</ui>

View File

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

View File

@ -30,6 +30,7 @@
#include "retroshare/rspeers.h"
#include <QCheckBox>
#include <QMessageBox>
#include <QToolTip>
#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->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._max_up_SB,SIGNAL(valueChanged(int)),this,SLOT(updateMaxUploadSlots(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._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._trustFriendNodesWithBannedFiles_CB,SIGNAL(toggled(bool)),this,SLOT(toggleTrustFriendNodesWithBannedFiles(bool))) ;
QObject::connect(ui.incomingButton, SIGNAL(clicked( bool ) ), this , SLOT( setIncomingDirectory() ) );
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;
#endif
}
void TransferPage::toggleTrustFriendNodesWithBannedFiles(bool b)
{
rsFiles->setTrustFriendNodesWithBannedFiles(b);
}
void TransferPage::updateMaxTRUpRate(int b)
{
rsTurtle->setMaxTRForwardRate(b) ;
@ -208,7 +215,15 @@ void TransferPage::updateDefaultStrategy(int i)
case 0: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_STREAMING) ;
break ;
case 2: rsFiles->setDefaultChunkStrategy(FileChunksInfo::CHUNK_STRATEGY_RANDOM) ;
case 2:
#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) ;

View File

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

View File

@ -14,7 +14,7 @@
<item row="0" column="0">
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
@ -30,7 +30,7 @@
<item>
<widget class="QPushButton" name="editShareButton">
<property name="text">
<string>Edit Share</string>
<string>Configure shared directories</string>
</property>
</widget>
</item>
@ -443,7 +443,7 @@ p, li { white-space: pre-wrap; }
<bool>true</bool>
</property>
<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>
<item>
<property name="text">
@ -547,7 +547,7 @@ p, li { white-space: pre-wrap; }
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox">
<widget class="QCheckBox" name="_trustFriendNodesWithBannedFiles_CB">
<property name="text">
<string>Trust friend nodes with banned files</string>
</property>

View File

@ -27,6 +27,7 @@
#include <QSpinBox>
#include "util/misc.h"
#include "util/qtthreadsutils.h"
#include "retroshare/rswebui.h"
#include "retroshare/rsjsonapi.h"
@ -40,6 +41,8 @@ resource_api::ApiServerLocal* WebuiPage::apiServerLocal = 0;
#endif
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*/)
{
@ -50,11 +53,20 @@ WebuiPage::WebuiPage(QWidget */*parent*/, Qt::WindowFlags /*flags*/)
connect(ui.password_LE, SIGNAL(textChanged(QString)), this, SLOT(onPasswordValueChanged(QString)));
connect(ui.startWebBrowser_PB, SIGNAL(clicked()), this, SLOT(onStartWebBrowserClicked()));
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()
{
rsEvents->unregisterEventsHandler(mEventsHandlerId);
}
void WebuiPage::selectWebInterfaceDirectory()
@ -73,22 +85,12 @@ void WebuiPage::selectWebInterfaceDirectory()
bool WebuiPage::updateParams(QString &errmsg)
{
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());
Settings->setWebinterfaceFilesDirectory(ui.webInterfaceFiles_LE->text());
rsWebUi->setHtmlFilesDirectory(ui.webInterfaceFiles_LE->text().toStdString());
}
return ok;
return true;
}
void WebuiPage::onPasswordValueChanged(QString password)
@ -112,10 +114,23 @@ void WebuiPage::onPasswordValueChanged(QString password)
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;
}
void WebuiPage::load()
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::loadParams()
{
std::cerr << "WebuiPage::load()" << std::endl;
whileBlocking(ui.enableWebUI_CB)->setChecked(Settings->getWebinterfaceEnabled());
@ -127,6 +142,13 @@ void WebuiPage::load()
if(it != smap.end())
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
}
@ -138,11 +160,9 @@ 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>");
}
/*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())
return false;
rsWebUi->setHtmlFilesDirectory(Settings->getWebinterfaceFilesDirectory().toStdString());
rsWebUi->restart();
@ -173,15 +193,21 @@ QString WebuiPage::helpText() const
void WebuiPage::onEnableCBClicked(bool checked)
{
ui.params_GB->setEnabled(checked);
ui.apply_PB->setEnabled(checked);
ui.startWebBrowser_PB->setEnabled(checked);
QString S;
QString errmsg;
updateParams(errmsg);
Settings->setWebinterfaceEnabled(checked);
ui.params_GB->setEnabled(checked);
ui.startWebBrowser_PB->setEnabled(checked);
ui.apply_PB->setEnabled(checked);
if(checked)
checkStartWebui();
{
if(!restart())
{
QMessageBox::warning(0, tr("failed to start Webinterface"), "Failed to start the webinterface.");
return;
}
}
else
checkShutdownWebui();
}
@ -199,18 +225,12 @@ void WebuiPage::onAllIPCBClicked(bool /*checked*/)
}
void WebuiPage::onApplyClicked()
{
rsWebUi->setUserPassword(ui.password_LE->text().toStdString());
QString errmsg;
updateParams(errmsg);
if(!restart())
{
QMessageBox::warning(0, tr("failed to start Webinterface"), "Failed to start the webinterface.");
return;
}
restart();
emit passwordChanged();
load();
}
void WebuiPage::onStartWebBrowserClicked() { showWebui(); }

View File

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

View File

@ -6,14 +6,16 @@
<rect>
<x>0</x>
<y>0</y>
<width>960</width>
<height>717</height>
<width>570</width>
<height>646</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="enableWebUI_CB">
<property name="text">
@ -21,6 +23,38 @@
</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>
<widget class="QGroupBox" name="params_GB">
<property name="enabled">

View File

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

View File

@ -39,9 +39,9 @@ void Histogram::draw(QPainter */*painter*/) const
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];
}

View File

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

View File

@ -536,11 +536,9 @@ feenableexcept(FE_INVALID | FE_DIVBYZERO);
// avoid clashes between infos from threads.
//
qRegisterMetaType<FileDetail>("FileDetail") ;
qRegisterMetaType<RsPeerId>("RsPeerId") ;
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(chatLobbyTimeShift(int)),notify,SLOT(handleChatLobbyTimeShift(int)),Qt::QueuedConnection) ;
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;
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/PulseReplySeperator.h \
gui/TheWire/PulseMessage.h \
gui/TheWire/CustomFrame.h \
FORMS += gui/TheWire/WireDialog.ui \
gui/TheWire/WireGroupItem.ui \
@ -1242,6 +1243,7 @@ gxsthewire {
gui/TheWire/PulseReply.cpp \
gui/TheWire/PulseReplySeperator.cpp \
gui/TheWire/PulseMessage.cpp \
gui/TheWire/CustomFrame.cpp \
RESOURCES += gui/TheWire/TheWire_images.qrc
}

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