mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-29 01:16:20 -05:00
Merge pull request #2054 from csoler/v0.6-ChannelsGUI
V0.6 channels gui
This commit is contained in:
commit
37c7a0aa44
@ -52,6 +52,7 @@ void GxsCommentDialog::init()
|
||||
connect(ui->refreshButton, SIGNAL(clicked()), this, SLOT(refresh()));
|
||||
connect(ui->idChooser, SIGNAL(currentIndexChanged( int )), this, SLOT(voterSelectionChanged( int )));
|
||||
connect(ui->idChooser, SIGNAL(idsLoaded()), this, SLOT(idChooserReady()));
|
||||
connect(ui->treeWidget,SIGNAL(commentsLoaded(int)),this,SLOT(notifyCommentsLoaded(int)));
|
||||
|
||||
connect(ui->commentButton, SIGNAL(clicked()), ui->treeWidget, SLOT(makeComment()));
|
||||
connect(ui->sortBox, SIGNAL(currentIndexChanged(int)), this, SLOT(sortComments(int)));
|
||||
@ -95,6 +96,11 @@ void GxsCommentDialog::commentLoad(const RsGxsGroupId &grpId, const std::set<RsG
|
||||
ui->treeWidget->requestComments(mGrpId,msg_versions,most_recent_msgId);
|
||||
}
|
||||
|
||||
void GxsCommentDialog::notifyCommentsLoaded(int n)
|
||||
{
|
||||
emit commentsLoaded(n);
|
||||
}
|
||||
|
||||
void GxsCommentDialog::refresh()
|
||||
{
|
||||
std::cerr << "GxsCommentDialog::refresh()";
|
||||
|
@ -48,6 +48,10 @@ private slots:
|
||||
void idChooserReady();
|
||||
void voterSelectionChanged( int index );
|
||||
void sortComments(int);
|
||||
void notifyCommentsLoaded(int n);
|
||||
|
||||
signals:
|
||||
void commentsLoaded(int);
|
||||
|
||||
private:
|
||||
void init();
|
||||
|
@ -228,8 +228,10 @@ void GxsCommentTreeWidget::customPopUpMenu(const QPoint& /*point*/)
|
||||
|
||||
void GxsCommentTreeWidget::voteUp()
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::voteUp()";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::voteUp()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
vote(mGroupId, mLatestMsgId, mCurrentCommentMsgId, mVoterId, true);
|
||||
}
|
||||
@ -237,8 +239,10 @@ void GxsCommentTreeWidget::voteUp()
|
||||
|
||||
void GxsCommentTreeWidget::voteDown()
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::voteDown()";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::voteDown()";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
vote(mGroupId, mLatestMsgId, mCurrentCommentMsgId, mVoterId, false);
|
||||
}
|
||||
@ -246,8 +250,10 @@ void GxsCommentTreeWidget::voteDown()
|
||||
void GxsCommentTreeWidget::setVoteId(const RsGxsId &voterId)
|
||||
{
|
||||
mVoterId = voterId;
|
||||
std::cerr << "GxsCommentTreeWidget::setVoterId(" << mVoterId << ")";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::setVoterId(" << mVoterId << ")";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -270,6 +276,7 @@ void GxsCommentTreeWidget::vote(const RsGxsGroupId &groupId, const RsGxsMessageI
|
||||
vote.mVoteType = GXS_VOTE_DOWN;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::vote()";
|
||||
std::cerr << std::endl;
|
||||
|
||||
@ -277,6 +284,7 @@ void GxsCommentTreeWidget::vote(const RsGxsGroupId &groupId, const RsGxsMessageI
|
||||
std::cerr << "ThreadId : " << vote.mMeta.mThreadId << std::endl;
|
||||
std::cerr << "ParentId : " << vote.mMeta.mParentId << std::endl;
|
||||
std::cerr << "AuthorId : " << vote.mMeta.mAuthorId << std::endl;
|
||||
#endif
|
||||
|
||||
uint32_t token;
|
||||
mCommentService->createNewVote(token, vote);
|
||||
@ -361,13 +369,17 @@ void GxsCommentTreeWidget::requestComments(const RsGxsGroupId& group, const std:
|
||||
void GxsCommentTreeWidget::service_requestComments(const RsGxsGroupId& group_id,const std::set<RsGxsMessageId> & msgIds)
|
||||
{
|
||||
/* request comments */
|
||||
std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::service_requestComments for group " << group_id << std::endl;
|
||||
#endif
|
||||
|
||||
std::vector<RsGxsGrpMsgIdPair> ids_to_ask;
|
||||
|
||||
for(std::set<RsGxsMessageId>::const_iterator it(msgIds.begin());it!=msgIds.end();++it)
|
||||
{
|
||||
std::cerr << " asking for msg " << *it << std::endl;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << " asking for msg " << *it << std::endl;
|
||||
#endif
|
||||
|
||||
ids_to_ask.push_back(std::make_pair(group_id,*it));
|
||||
}
|
||||
@ -399,14 +411,18 @@ void GxsCommentTreeWidget::completeItems()
|
||||
std::map<RsGxsMessageId, QTreeWidgetItem *>::iterator lit;
|
||||
std::multimap<RsGxsMessageId, QTreeWidgetItem *>::iterator pit;
|
||||
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() " << mPendingInsertMap.size();
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() " << mPendingInsertMap.size();
|
||||
std::cerr << " PendingItems";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
for(pit = mPendingInsertMap.begin(); pit != mPendingInsertMap.end(); ++pit)
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() item->parent: " << pit->first;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() item->parent: " << pit->first;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if (pit->first != parentId)
|
||||
{
|
||||
@ -425,15 +441,19 @@ void GxsCommentTreeWidget::completeItems()
|
||||
|
||||
if (parent)
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to Parent";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to Parent";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
parent->addChild(pit->second);
|
||||
}
|
||||
else if (mMsgVersions.find(parentId) != mMsgVersions.end())
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to topLevelItems";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added to topLevelItems";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
topLevelItems.append(pit->second);
|
||||
}
|
||||
@ -443,8 +463,10 @@ void GxsCommentTreeWidget::completeItems()
|
||||
/* missing parent -> insert At Top Level */
|
||||
QTreeWidgetItem *missingItem = service_createMissingItem(pit->first);
|
||||
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added MissingItem";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::completeItems() Added MissingItem";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
parent = missingItem;
|
||||
parent->addChild(pit->second);
|
||||
@ -464,9 +486,11 @@ void GxsCommentTreeWidget::completeItems()
|
||||
|
||||
void GxsCommentTreeWidget::addItem(RsGxsMessageId itemId, RsGxsMessageId parentId, QTreeWidgetItem *item)
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Id: " << itemId;
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Id: " << itemId;
|
||||
std::cerr << " ParentId: " << parentId;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
/* store in map -> for children */
|
||||
mLoadingMap[itemId] = item;
|
||||
@ -475,20 +499,48 @@ void GxsCommentTreeWidget::addItem(RsGxsMessageId itemId, RsGxsMessageId parentI
|
||||
it = mLoadingMap.find(parentId);
|
||||
if (it != mLoadingMap.end())
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Parent";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Parent";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
it->second->addChild(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Pending List";
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::addItem() Added to Pending List";
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
mPendingInsertMap.insert(std::make_pair(parentId, item));
|
||||
}
|
||||
}
|
||||
|
||||
int treeCount(QTreeWidget *tree, QTreeWidgetItem *parent = 0)
|
||||
{
|
||||
int count = 0;
|
||||
if (parent == 0) {
|
||||
int topCount = tree->topLevelItemCount();
|
||||
for (int i = 0; i < topCount; i++) {
|
||||
QTreeWidgetItem *item = tree->topLevelItem(i);
|
||||
if (item->isExpanded()) {
|
||||
count += treeCount(tree, item);
|
||||
}
|
||||
}
|
||||
count += topCount;
|
||||
} else {
|
||||
int childCount = parent->childCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
QTreeWidgetItem *item = parent->child(i);
|
||||
if (item->isExpanded()) {
|
||||
count += treeCount(tree, item);
|
||||
}
|
||||
}
|
||||
count += childCount;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
void GxsCommentTreeWidget::loadThread(const uint32_t &token)
|
||||
{
|
||||
clearItems();
|
||||
@ -496,6 +548,8 @@ void GxsCommentTreeWidget::loadThread(const uint32_t &token)
|
||||
service_loadThread(token);
|
||||
|
||||
completeItems();
|
||||
|
||||
emit commentsLoaded(treeCount(this));
|
||||
}
|
||||
|
||||
void GxsCommentTreeWidget::acknowledgeComment(const uint32_t &token)
|
||||
@ -615,8 +669,10 @@ QTreeWidgetItem *GxsCommentTreeWidget::service_createMissingItem(const RsGxsMess
|
||||
|
||||
void GxsCommentTreeWidget::loadRequest(const TokenQueue *queue, const TokenRequest &req)
|
||||
{
|
||||
#ifdef DEBUG_GXSCOMMENT_TREEWIDGET
|
||||
std::cerr << "GxsCommentTreeWidget::loadRequest() UserType: " << req.mUserType;
|
||||
std::cerr << std::endl;
|
||||
#endif
|
||||
|
||||
if (queue != mTokenQueue)
|
||||
{
|
||||
|
@ -80,6 +80,9 @@ public slots:
|
||||
void markSpammer();
|
||||
void banUser();
|
||||
|
||||
signals:
|
||||
void commentsLoaded(int);
|
||||
|
||||
protected:
|
||||
|
||||
void vote(const RsGxsGroupId &groupId, const RsGxsMessageId &threadId,
|
||||
|
@ -78,10 +78,19 @@ CreateGxsChannelMsg::CreateGxsChannelMsg(const RsGxsGroupId &cId, RsGxsMessageId
|
||||
connect(thumbNailCb, SIGNAL(toggled(bool)), this, SLOT(allowAutoMediaThumbNail(bool)));
|
||||
connect(stackedWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenu(QPoint)));
|
||||
connect(generateCheckBox, SIGNAL(toggled(bool)), generateSpinBox, SLOT(setEnabled(bool)));
|
||||
connect(aspectRatio_CB,SIGNAL(currentIndexChanged(int)),this,SLOT(changeAspectRatio(int)));
|
||||
|
||||
aspectRatio_CB->setItemIcon(0,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-auto.svg"));
|
||||
aspectRatio_CB->setItemIcon(1,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-1-1.svg"));
|
||||
aspectRatio_CB->setItemIcon(2,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-3-4.svg"));
|
||||
aspectRatio_CB->setItemIcon(3,FilesDefs::getIconFromQtResourcePath(":/icons/svg/ratio-16-9.svg"));
|
||||
|
||||
generateSpinBox->setEnabled(false);
|
||||
|
||||
thumbNailCb->setVisible(false);
|
||||
preview_W->setPixmap(FilesDefs::getPixmapFromQtResourcePath(ChannelPostThumbnailView::CHAN_DEFAULT_IMAGE),true);
|
||||
preview_W->setText("[Text preview]");
|
||||
|
||||
thumbNailCb->setVisible(false);
|
||||
thumbNailCb->setEnabled(false);
|
||||
#ifdef CHANNELS_FRAME_CATCHER
|
||||
fCatcher = new framecatcher();
|
||||
@ -107,6 +116,19 @@ CreateGxsChannelMsg::~CreateGxsChannelMsg()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CreateGxsChannelMsg::changeAspectRatio(int s)
|
||||
{
|
||||
switch(s)
|
||||
{
|
||||
case 0: break;
|
||||
case 1: preview_W->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_1_1);
|
||||
break;
|
||||
case 2: preview_W->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_2_3);
|
||||
break;
|
||||
case 3: preview_W->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_16_9);
|
||||
break;
|
||||
}
|
||||
}
|
||||
void CreateGxsChannelMsg::contextMenu(QPoint /*point*/)
|
||||
{
|
||||
QList<RetroShareLink> links ;
|
||||
@ -688,7 +710,7 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str
|
||||
// send chan image
|
||||
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
picture.save(&buffer, "PNG"); // writes image into ba in PNG format
|
||||
preview_W->getCroppedScaledPicture().save(&buffer, "PNG"); // writes image into ba in PNG format
|
||||
post.mThumbnail.copy((uint8_t *) ba.data(), ba.size());
|
||||
}
|
||||
|
||||
@ -723,7 +745,7 @@ void CreateGxsChannelMsg::sendMessage(const std::string &subject, const std::str
|
||||
|
||||
void CreateGxsChannelMsg::addThumbnail()
|
||||
{
|
||||
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 107,156); // these absolute sizes are terrible
|
||||
QPixmap img = misc::getOpenThumbnailedPicture(this, tr("Load thumbnail picture"), 0,0); // 0,0 means: no scale.
|
||||
|
||||
if (img.isNull())
|
||||
return;
|
||||
@ -731,7 +753,8 @@ void CreateGxsChannelMsg::addThumbnail()
|
||||
picture = img;
|
||||
|
||||
// to show the selected
|
||||
preview_W->setPixmap(picture);
|
||||
preview_W->setPixmap(picture, aspectRatio_CB->currentIndex()==0);
|
||||
|
||||
}
|
||||
|
||||
void CreateGxsChannelMsg::loadOriginalChannelPostInfo()
|
||||
@ -775,7 +798,7 @@ void CreateGxsChannelMsg::loadOriginalChannelPostInfo()
|
||||
if(post.mThumbnail.mData != NULL)
|
||||
{
|
||||
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData,post.mThumbnail.mSize,picture,GxsIdDetails::ORIGINAL);
|
||||
preview_W->setPixmap(picture);
|
||||
preview_W->setPixmap(picture,true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -64,6 +64,7 @@ private slots:
|
||||
void sendMsg();
|
||||
void pasteLink() ;
|
||||
void contextMenu(QPoint) ;
|
||||
void changeAspectRatio(int s);
|
||||
|
||||
void addThumbnail();
|
||||
void allowAutoMediaThumbNail(bool);
|
||||
|
@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>736</width>
|
||||
<height>271</height>
|
||||
<width>881</width>
|
||||
<height>383</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="acceptDrops">
|
||||
@ -79,32 +79,35 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="stackedWidgetPage1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="ChannelPostThumbnailView" name="preview_W" native="true"/>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="ChannelPostThumbnailView" name="preview_W" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@ -168,7 +171,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Add Channel Thumbnail</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/add-image.png</normaloff>:/icons/png/add-image.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -179,13 +182,43 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="aspectRatio_CB">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1:1</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>3:4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16:9</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="addfilepushButton">
|
||||
<property name="text">
|
||||
<string>Add File to Attach</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/add-file.png</normaloff>:/icons/png/add-file.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -285,7 +318,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/add-file.png</normaloff>:/icons/png/add-file.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -309,7 +342,7 @@ p, li { white-space: pre-wrap; }
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>81</width>
|
||||
<width>84</width>
|
||||
<height>24</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -389,7 +422,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Channel Post</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/comment.png</normaloff>:/icons/png/comment.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -419,7 +452,7 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Attachments</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/png/attachements.png</normaloff>:/icons/png/attachements.png</iconset>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
@ -491,7 +524,6 @@ p, li { white-space: pre-wrap; }
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../images.qrc"/>
|
||||
<include location="../icons.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@ -35,9 +35,9 @@ public:
|
||||
/** Default Destructor */
|
||||
~GxsChannelDialog();
|
||||
|
||||
virtual QIcon iconPixmap() const { return QIcon(IMAGE_GXSCHANNELS) ; } //MainPage
|
||||
virtual QString pageName() const { return tr("Channels") ; } //MainPage
|
||||
virtual QString helpText() const { return ""; } //MainPage
|
||||
virtual QIcon iconPixmap() const override { return QIcon(IMAGE_GXSCHANNELS) ; } //MainPage
|
||||
virtual QString pageName() const override { return tr("Channels") ; } //MainPage
|
||||
virtual QString helpText() const override { return ""; } //MainPage
|
||||
|
||||
void shareOnChannel(const RsGxsGroupId& channel_id, const QList<RetroShareLink>& file_link) ;
|
||||
|
||||
@ -69,17 +69,17 @@ private slots:
|
||||
|
||||
private:
|
||||
/* GxsGroupFrameDialog */
|
||||
virtual QString text(TextType type);
|
||||
virtual QString icon(IconType type);
|
||||
virtual QString settingsGroupName() { return "ChannelDialog"; }
|
||||
virtual GxsGroupDialog *createNewGroupDialog();
|
||||
virtual GxsGroupDialog *createGroupDialog(GxsGroupDialog::Mode mode, RsGxsGroupId groupId);
|
||||
virtual int shareKeyType();
|
||||
virtual GxsMessageFrameWidget *createMessageFrameWidget(const RsGxsGroupId &groupId);
|
||||
virtual void groupTreeCustomActions(RsGxsGroupId grpId, int subscribeFlags, QList<QAction*> &actions);
|
||||
virtual RsGxsCommentService *getCommentService();
|
||||
virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId);
|
||||
virtual uint32_t requestGroupSummaryType() { return GXS_REQUEST_TYPE_GROUP_DATA; } // request complete group data
|
||||
virtual QString text(TextType type) override;
|
||||
virtual QString icon(IconType type) override;
|
||||
virtual QString settingsGroupName() override { return "ChannelDialog"; }
|
||||
virtual GxsGroupDialog *createNewGroupDialog() override;
|
||||
virtual GxsGroupDialog *createGroupDialog(GxsGroupDialog::Mode mode, RsGxsGroupId groupId) override;
|
||||
virtual int shareKeyType() override;
|
||||
virtual GxsMessageFrameWidget *createMessageFrameWidget(const RsGxsGroupId &groupId) override;
|
||||
virtual void groupTreeCustomActions(RsGxsGroupId grpId, int subscribeFlags, QList<QAction*> &actions) override;
|
||||
virtual RsGxsCommentService *getCommentService() override;
|
||||
virtual QWidget *createCommentHeaderWidget(const RsGxsGroupId &grpId, const RsGxsMessageId &msgId) override;
|
||||
virtual uint32_t requestGroupSummaryType() override { return GXS_REQUEST_TYPE_GROUP_DATA; } // request complete group data
|
||||
|
||||
void handleEvent_main_thread(std::shared_ptr<const RsEvent> event);
|
||||
|
||||
|
@ -306,7 +306,7 @@ void RsGxsChannelPostFilesModel::setFilter(const QStringList& strings, uint32_t&
|
||||
if(strings.empty())
|
||||
{
|
||||
mFilteredFiles.clear();
|
||||
for(int i=0;i<mFiles.size();++i)
|
||||
for(uint32_t i=0;i<mFiles.size();++i)
|
||||
mFilteredFiles.push_back(i);
|
||||
}
|
||||
else
|
||||
@ -314,7 +314,7 @@ void RsGxsChannelPostFilesModel::setFilter(const QStringList& strings, uint32_t&
|
||||
mFilteredFiles.clear();
|
||||
//mFilteredPosts.push_back(0);
|
||||
|
||||
for(int i=0;i<mFiles.size();++i)
|
||||
for(uint32_t i=0;i<mFiles.size();++i)
|
||||
{
|
||||
bool passes_strings = true;
|
||||
|
||||
|
324
retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.cpp
Normal file
324
retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
/*******************************************************************************
|
||||
* retroshare-gui/src/gui/gxschannels/GxsChannelPostThumbnail.cpp *
|
||||
* *
|
||||
* Copyright 2020 by Retroshare Team <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 <QWheelEvent>
|
||||
#include <QDateTime>
|
||||
|
||||
#include "gui/common/FilesDefs.h"
|
||||
#include "gui/gxschannels/GxsChannelPostThumbnail.h"
|
||||
|
||||
const float ChannelPostThumbnailView::DEFAULT_SIZE_IN_FONT_HEIGHT = 5.0;
|
||||
const float ChannelPostThumbnailView::FONT_SCALE_FACTOR = 1.5;
|
||||
|
||||
ChannelPostThumbnailView::ChannelPostThumbnailView(const RsGxsChannelPost& post,uint32_t flags,QWidget *parent)
|
||||
: QWidget(parent),mPostTitle(nullptr),mFlags(flags), mAspectRatio(ASPECT_RATIO_2_3)
|
||||
{
|
||||
// now fill the data
|
||||
|
||||
init(post);
|
||||
}
|
||||
|
||||
ChannelPostThumbnailView::ChannelPostThumbnailView(QWidget *parent,uint32_t flags)
|
||||
: QWidget(parent),mFlags(flags), mAspectRatio(ASPECT_RATIO_2_3)
|
||||
{
|
||||
init(RsGxsChannelPost());
|
||||
}
|
||||
|
||||
ChannelPostThumbnailView::~ChannelPostThumbnailView()
|
||||
{
|
||||
delete mPostImage;
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::setText(const QString& s)
|
||||
{
|
||||
if(mPostTitle == NULL)
|
||||
{
|
||||
std::cerr << "(EE) calling setText on a ChannelPostThumbnailView without SHOW_TEXT flag!"<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
QString ss;
|
||||
if(s.length() > 30)
|
||||
ss = s.left(30)+"...";
|
||||
else
|
||||
ss =s;
|
||||
|
||||
mPostTitle->setText(ss);
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::setPixmap(const QPixmap& p, bool guess_aspect_ratio)
|
||||
{
|
||||
mPostImage->setPicture(p);
|
||||
|
||||
if(guess_aspect_ratio)// aspect ratio is automatically guessed.
|
||||
{
|
||||
// compute closest aspect ratio
|
||||
float r = p.width()/(float)p.height();
|
||||
|
||||
if(r < 0.8)
|
||||
setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_2_3);
|
||||
else if(r < 1.15)
|
||||
setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_1_1);
|
||||
else
|
||||
setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_16_9);
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::setAspectRatio(AspectRatio r)
|
||||
{
|
||||
mAspectRatio = r;
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
int W = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_w() * fm.height() ;
|
||||
int H = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_h() * fm.height() ;
|
||||
|
||||
mPostImage->setFixedSize(W,H);
|
||||
mPostImage->reset();
|
||||
mPostImage->updateView();
|
||||
}
|
||||
|
||||
void ChannelPostThumbnailView::init(const RsGxsChannelPost& post)
|
||||
{
|
||||
QString msg = QString::fromUtf8(post.mMeta.mMsgName.c_str());
|
||||
bool is_msg_new = IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus);
|
||||
|
||||
QPixmap thumbnail;
|
||||
|
||||
if(post.mThumbnail.mSize > 0)
|
||||
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL);
|
||||
else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row)
|
||||
thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE);
|
||||
|
||||
mPostImage = new ZoomableLabel(this);
|
||||
mPostImage->setEnableZoom(mFlags & FLAG_ALLOW_PAN);
|
||||
mPostImage->setScaledContents(true);
|
||||
mPostImage->setPicture(thumbnail);
|
||||
|
||||
if(mFlags & FLAG_ALLOW_PAN)
|
||||
mPostImage->setToolTip(tr("Use mouse to center and zoom into the image"));
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
layout->addWidget(mPostImage);
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
int W = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_w() * fm.height() ;
|
||||
int H = THUMBNAIL_OVERSAMPLE_FACTOR * thumbnail_h() * fm.height() ;
|
||||
|
||||
mPostImage->setFixedSize(W,H);
|
||||
|
||||
if(mFlags & FLAG_SHOW_TEXT)
|
||||
{
|
||||
mPostTitle = new QLabel(this);
|
||||
layout->addWidget(mPostTitle);
|
||||
|
||||
QString ss = (msg.length() > 30)? (msg.left(30)+"..."):msg;
|
||||
|
||||
mPostTitle->setText(ss);
|
||||
|
||||
QFont font = mPostTitle->font();
|
||||
|
||||
if(mFlags & ChannelPostThumbnailView::FLAG_SCALE_FONT)
|
||||
font.setPointSizeF(FONT_SCALE_FACTOR * DEFAULT_SIZE_IN_FONT_HEIGHT / 5.0 * font.pointSizeF());
|
||||
else
|
||||
font.setPointSizeF(DEFAULT_SIZE_IN_FONT_HEIGHT / 5.0 * font.pointSizeF());
|
||||
|
||||
if(is_msg_new)
|
||||
font.setBold(true);
|
||||
|
||||
mPostTitle->setFont(font);
|
||||
mPostTitle->setMaximumWidth(W);
|
||||
mPostTitle->setWordWrap(true);
|
||||
}
|
||||
setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding);
|
||||
|
||||
layout->addStretch();
|
||||
|
||||
setLayout(layout);
|
||||
adjustSize();
|
||||
update();
|
||||
}
|
||||
|
||||
ChannelPostThumbnailView::AspectRatio ChannelPostThumbnailView::bestAspectRatio()
|
||||
{
|
||||
if(mPostImage->originalImage().isNull())
|
||||
return ASPECT_RATIO_1_1;
|
||||
|
||||
float as = mPostImage->originalImage().height() / (float)mPostImage->originalImage().width() ;
|
||||
|
||||
if(as <= 0.8)
|
||||
return ASPECT_RATIO_16_9;
|
||||
else if(as < 1.15)
|
||||
return ASPECT_RATIO_1_1;
|
||||
else
|
||||
return ASPECT_RATIO_2_3;
|
||||
}
|
||||
QSize ChannelPostThumbnailView::actualSize() const
|
||||
{
|
||||
QFontMetricsF fm(font());
|
||||
|
||||
if(mPostTitle != nullptr)
|
||||
{
|
||||
QMargins cm = layout()->contentsMargins();
|
||||
|
||||
return QSize(width(),
|
||||
mPostTitle->height() + mPostImage->height() + 0.5*fm.height()
|
||||
+ cm.top() + cm.bottom() + layout()->spacing());
|
||||
}
|
||||
else
|
||||
return size();
|
||||
}
|
||||
|
||||
float ChannelPostThumbnailView::thumbnail_w() const
|
||||
{
|
||||
switch(mAspectRatio)
|
||||
{
|
||||
default:
|
||||
case ASPECT_RATIO_1_1:
|
||||
case ASPECT_RATIO_UNKNOWN: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
|
||||
case ASPECT_RATIO_2_3: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
case ASPECT_RATIO_16_9: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
}
|
||||
}
|
||||
float ChannelPostThumbnailView::thumbnail_h() const
|
||||
{
|
||||
switch(mAspectRatio)
|
||||
{
|
||||
default:
|
||||
case ASPECT_RATIO_1_1:
|
||||
case ASPECT_RATIO_UNKNOWN: return DEFAULT_SIZE_IN_FONT_HEIGHT;
|
||||
|
||||
case ASPECT_RATIO_2_3: return DEFAULT_SIZE_IN_FONT_HEIGHT * 3.0/2.0;
|
||||
case ASPECT_RATIO_16_9: return DEFAULT_SIZE_IN_FONT_HEIGHT * 9.0/16.0;
|
||||
}
|
||||
}
|
||||
|
||||
void ZoomableLabel::reset()
|
||||
{
|
||||
mCenterX = mFullImage.width()/2.0;
|
||||
mCenterY = mFullImage.height()/2.0;
|
||||
mZoomFactor = 1.0/std::max(width() / (float)mFullImage.width(), height()/(float)mFullImage.height());
|
||||
|
||||
updateView();
|
||||
}
|
||||
void ZoomableLabel::mouseMoveEvent(QMouseEvent *me)
|
||||
{
|
||||
if(!mZoomEnabled)
|
||||
return;
|
||||
|
||||
float new_center_x = mCenterX - (me->x() - mLastX);
|
||||
float new_center_y = mCenterY - (me->y() - mLastY);
|
||||
|
||||
mLastX = me->x();
|
||||
mLastY = me->y();
|
||||
|
||||
if(new_center_x - 0.5 * width()*mZoomFactor < 0) return;
|
||||
if(new_center_y - 0.5 *height()*mZoomFactor < 0) return;
|
||||
|
||||
if(new_center_x + 0.5 * width()*mZoomFactor >= mFullImage.width()) return;
|
||||
if(new_center_y + 0.5 *height()*mZoomFactor >=mFullImage.height()) return;
|
||||
|
||||
mCenterX = new_center_x;
|
||||
mCenterY = new_center_y;
|
||||
|
||||
updateView();
|
||||
}
|
||||
void ZoomableLabel::mousePressEvent(QMouseEvent *me)
|
||||
{
|
||||
mMoving = true;
|
||||
mLastX = me->x();
|
||||
mLastY = me->y();
|
||||
}
|
||||
void ZoomableLabel::mouseReleaseEvent(QMouseEvent *)
|
||||
{
|
||||
mMoving = false;
|
||||
}
|
||||
void ZoomableLabel::wheelEvent(QWheelEvent *me)
|
||||
{
|
||||
if(!mZoomEnabled)
|
||||
return;
|
||||
|
||||
float new_zoom_factor = (me->delta() > 0)?(mZoomFactor*1.05):(mZoomFactor/1.05);
|
||||
float new_center_x = mCenterX;
|
||||
float new_center_y = mCenterY;
|
||||
|
||||
// Try to find centerX and centerY so that the crop does not overlap the original image
|
||||
|
||||
float min_x = 0.5 * width()*new_zoom_factor;
|
||||
float max_x = mFullImage.width() - 0.5 * width()*new_zoom_factor;
|
||||
float min_y = 0.5 * height()*new_zoom_factor;
|
||||
float max_y = mFullImage.height() - 0.5 * height()*new_zoom_factor;
|
||||
|
||||
if(min_x >= max_x) return;
|
||||
if(min_y >= max_y) return;
|
||||
|
||||
if(new_center_x < min_x) new_center_x = min_x;
|
||||
if(new_center_y < min_y) new_center_y = min_y;
|
||||
if(new_center_x > max_x) new_center_x = max_x;
|
||||
if(new_center_y > max_y) new_center_y = max_y;
|
||||
|
||||
mZoomFactor = new_zoom_factor;
|
||||
mCenterX = new_center_x;
|
||||
mCenterY = new_center_y;
|
||||
|
||||
updateView();
|
||||
}
|
||||
|
||||
QPixmap ZoomableLabel::extractCroppedScaledPicture() const
|
||||
{
|
||||
QRect rect(mCenterX - 0.5 * width()*mZoomFactor, mCenterY - 0.5 * height()*mZoomFactor, width()*mZoomFactor, height()*mZoomFactor);
|
||||
QPixmap pix = mFullImage.copy(rect).scaledToHeight(height(),Qt::SmoothTransformation);
|
||||
|
||||
return pix;
|
||||
}
|
||||
|
||||
void ZoomableLabel::setPicture(const QPixmap& pix)
|
||||
{
|
||||
mFullImage = pix;
|
||||
|
||||
reset();
|
||||
updateView();
|
||||
}
|
||||
void ZoomableLabel::resizeEvent(QResizeEvent *e)
|
||||
{
|
||||
QLabel::resizeEvent(e);
|
||||
|
||||
updateView();
|
||||
}
|
||||
|
||||
void ZoomableLabel::updateView()
|
||||
{
|
||||
// The new image will be cropped from the original image, using the following rules:
|
||||
// - first the cropped image size is computed
|
||||
// - then center is calculated so that
|
||||
// - the original center is preferred
|
||||
// - if the crop overlaps the image border, the center is moved.
|
||||
|
||||
QRect rect(mCenterX - 0.5 * width()*mZoomFactor, mCenterY - 0.5 * height()*mZoomFactor, width()*mZoomFactor, height()*mZoomFactor);
|
||||
QLabel::setPixmap(mFullImage.copy(rect));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -32,6 +32,39 @@
|
||||
#include "gui/gxs/GxsIdDetails.h"
|
||||
#include "gui/common/FilesDefs.h"
|
||||
|
||||
// Class to provide a label in which the image can be zoomed/moved. The widget size is fixed by the GUI and the user can move/zoom the image
|
||||
// inside the window formed by the widget. When happy, the view-able part of the image can be extracted.
|
||||
|
||||
class ZoomableLabel: public QLabel
|
||||
{
|
||||
public:
|
||||
ZoomableLabel(QWidget *parent): QLabel(parent),mZoomFactor(1.0),mCenterX(0.0),mCenterY(0.0),mZoomEnabled(true) {}
|
||||
|
||||
void setPicture(const QPixmap& pix);
|
||||
void setEnableZoom(bool b) { mZoomEnabled = b; }
|
||||
void reset();
|
||||
QPixmap extractCroppedScaledPicture() const;
|
||||
void updateView();
|
||||
|
||||
const QPixmap& originalImage() const { return mFullImage ; }
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *ev) override;
|
||||
void mouseReleaseEvent(QMouseEvent *ev) override;
|
||||
void mouseMoveEvent(QMouseEvent *ev) override;
|
||||
void resizeEvent(QResizeEvent *ev) override;
|
||||
void wheelEvent(QWheelEvent *me) override;
|
||||
|
||||
QPixmap mFullImage;
|
||||
|
||||
float mCenterX;
|
||||
float mCenterY;
|
||||
float mZoomFactor;
|
||||
int mLastX,mLastY;
|
||||
bool mMoving;
|
||||
bool mZoomEnabled;
|
||||
};
|
||||
|
||||
// Class to paint the thumbnails with title
|
||||
|
||||
class ChannelPostThumbnailView: public QWidget
|
||||
@ -39,8 +72,20 @@ class ChannelPostThumbnailView: public QWidget
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
typedef enum {
|
||||
ASPECT_RATIO_UNKNOWN = 0x00,
|
||||
ASPECT_RATIO_2_3 = 0x01,
|
||||
ASPECT_RATIO_1_1 = 0x02,
|
||||
ASPECT_RATIO_16_9 = 0x03,
|
||||
} AspectRatio;
|
||||
|
||||
// This variable determines the zoom factor on the text below thumbnails. 2.0 is mostly correct for all screen.
|
||||
static constexpr float THUMBNAIL_OVERSAMPLE_FACTOR = 2.0;
|
||||
static constexpr float THUMBNAIL_OVERSAMPLE_FACTOR = 2.0;
|
||||
|
||||
static constexpr uint32_t FLAG_NONE = 0x00;
|
||||
static constexpr uint32_t FLAG_SHOW_TEXT = 0x01;
|
||||
static constexpr uint32_t FLAG_ALLOW_PAN = 0x02;
|
||||
static constexpr uint32_t FLAG_SCALE_FONT= 0x04;
|
||||
|
||||
// Size of thumbnails as a function of the height of the font. An aspect ratio of 3/4 is good.
|
||||
|
||||
@ -49,77 +94,40 @@ public:
|
||||
|
||||
static constexpr char *CHAN_DEFAULT_IMAGE = ":images/thumb-default-video.png";
|
||||
|
||||
virtual ~ChannelPostThumbnailView()
|
||||
{
|
||||
delete lb;
|
||||
delete lt;
|
||||
}
|
||||
virtual ~ChannelPostThumbnailView();
|
||||
ChannelPostThumbnailView(QWidget *parent=NULL,uint32_t flags=FLAG_ALLOW_PAN | FLAG_SHOW_TEXT | FLAG_SCALE_FONT);
|
||||
ChannelPostThumbnailView(const RsGxsChannelPost& post,uint32_t flags,QWidget *parent=NULL);
|
||||
|
||||
ChannelPostThumbnailView(QWidget *parent=NULL): QWidget(parent)
|
||||
{
|
||||
init(FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE), QString("New post"),false);
|
||||
}
|
||||
void init(const RsGxsChannelPost& post);
|
||||
|
||||
ChannelPostThumbnailView(const RsGxsChannelPost& post,QWidget *parent=NULL)
|
||||
: QWidget(parent)
|
||||
{
|
||||
// now fill the data
|
||||
void setAspectRatio(AspectRatio r);
|
||||
void setPixmap(const QPixmap& p,bool guess_aspect_ratio) ;
|
||||
QPixmap getCroppedScaledPicture() const { return mPostImage->extractCroppedScaledPicture() ; }
|
||||
|
||||
QPixmap thumbnail;
|
||||
void setText(const QString& s);
|
||||
|
||||
if(post.mThumbnail.mSize > 0)
|
||||
GxsIdDetails::loadPixmapFromData(post.mThumbnail.mData, post.mThumbnail.mSize, thumbnail,GxsIdDetails::ORIGINAL);
|
||||
else if(post.mMeta.mPublishTs > 0) // this is for testing that the post is not an empty post (happens at the end of the last row)
|
||||
thumbnail = FilesDefs::getPixmapFromQtResourcePath(CHAN_DEFAULT_IMAGE);
|
||||
// This is used to allow to render the widget into a pixmap without the white space that Qt adds vertically. There is *no way* apparently
|
||||
// to get rid of that bloody space. It depends on the aspect ratio of the image and it only shows up when the text label is shown.
|
||||
// The label however has a correct size. It seems that Qt doesn't like widgets with horizontal aspect ratio and forces the size accordingly.
|
||||
|
||||
init(thumbnail, QString::fromUtf8(post.mMeta.mMsgName.c_str()), IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus) );
|
||||
|
||||
}
|
||||
|
||||
void init(const QPixmap& thumbnail,const QString& msg,bool is_msg_new)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
|
||||
lb = new QLabel(this);
|
||||
lb->setScaledContents(true);
|
||||
layout->addWidget(lb);
|
||||
|
||||
lt = new QLabel(this);
|
||||
layout->addWidget(lt);
|
||||
|
||||
setLayout(layout);
|
||||
|
||||
setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Maximum);
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
int W = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_W * fm.height() ;
|
||||
int H = THUMBNAIL_OVERSAMPLE_FACTOR * THUMBNAIL_H * fm.height() ;
|
||||
|
||||
lb->setFixedSize(W,H);
|
||||
lb->setPixmap(thumbnail);
|
||||
|
||||
lt->setText(msg);
|
||||
|
||||
QFont font = lt->font();
|
||||
|
||||
if(is_msg_new)
|
||||
{
|
||||
font.setBold(true);
|
||||
lt->setFont(font);
|
||||
}
|
||||
|
||||
lt->setMaximumWidth(W);
|
||||
lt->setWordWrap(true);
|
||||
|
||||
adjustSize();
|
||||
update();
|
||||
}
|
||||
|
||||
void setPixmap(const QPixmap& p) { lb->setPixmap(p); }
|
||||
void setText(const QString& s) { lt->setText(s); }
|
||||
QSize actualSize() const ;
|
||||
|
||||
/*!
|
||||
* \brief bestAspectRatio
|
||||
* Computes the preferred aspect ratio for the image in the post. The default is 1:1.
|
||||
* \return the prefered aspect ratio
|
||||
*/
|
||||
AspectRatio bestAspectRatio() ;
|
||||
private:
|
||||
QLabel *lb;
|
||||
QLabel *lt;
|
||||
static const float DEFAULT_SIZE_IN_FONT_HEIGHT ;
|
||||
static const float FONT_SCALE_FACTOR ;
|
||||
|
||||
float thumbnail_w() const;
|
||||
float thumbnail_h() const;
|
||||
|
||||
ZoomableLabel *mPostImage;
|
||||
QLabel *mPostTitle;
|
||||
uint32_t mFlags;
|
||||
AspectRatio mAspectRatio;
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,7 @@ Q_DECLARE_METATYPE(RsGxsChannelPost)
|
||||
std::ostream& operator<<(std::ostream& o, const QModelIndex& i);// defined elsewhere
|
||||
|
||||
RsGxsChannelPostsModel::RsGxsChannelPostsModel(QObject *parent)
|
||||
: QAbstractItemModel(parent), mTreeMode(TREE_MODE_PLAIN), mColumns(6)
|
||||
: QAbstractItemModel(parent), mTreeMode(RsGxsChannelPostsModel::TREE_MODE_GRID), mColumns(6)
|
||||
{
|
||||
initEmptyHierarchy();
|
||||
|
||||
@ -62,6 +62,16 @@ RsGxsChannelPostsModel::~RsGxsChannelPostsModel()
|
||||
rsEvents->unregisterEventsHandler(mEventHandlerId);
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::setMode(TreeMode mode)
|
||||
{
|
||||
mTreeMode = mode;
|
||||
|
||||
if(mode == TREE_MODE_LIST)
|
||||
setNumColumns(2);
|
||||
|
||||
triggerViewUpdate();
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr<const RsEvent> event)
|
||||
{
|
||||
const RsGxsChannelEvent *e = dynamic_cast<const RsGxsChannelEvent*>(event.get());
|
||||
@ -106,7 +116,7 @@ void RsGxsChannelPostsModel::handleEvent_main_thread(std::shared_ptr<const RsEve
|
||||
{
|
||||
mPosts[j] = posts[i];
|
||||
|
||||
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredPosts.size(),mColumns-1,(void*)NULL));
|
||||
triggerViewUpdate();
|
||||
}
|
||||
}
|
||||
},this);
|
||||
@ -124,25 +134,23 @@ void RsGxsChannelPostsModel::initEmptyHierarchy()
|
||||
|
||||
mPosts.clear();
|
||||
mFilteredPosts.clear();
|
||||
// mPosts.resize(1); // adds a sentinel item
|
||||
// mPosts[0].mMeta.mMsgName = "Root sentinel post" ;
|
||||
// mFilteredPosts.resize(1);
|
||||
// mFilteredPosts[0] = 1;
|
||||
|
||||
postMods();
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::preMods()
|
||||
{
|
||||
//emit layoutAboutToBeChanged(); //Generate SIGSEGV when click on button move next/prev.
|
||||
|
||||
beginResetModel();
|
||||
}
|
||||
void RsGxsChannelPostsModel::postMods()
|
||||
{
|
||||
endResetModel();
|
||||
|
||||
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(mFilteredPosts.size(),mColumns-1,(void*)NULL));
|
||||
triggerViewUpdate();
|
||||
}
|
||||
void RsGxsChannelPostsModel::triggerViewUpdate()
|
||||
{
|
||||
emit dataChanged(createIndex(0,0,(void*)NULL), createIndex(rowCount()-1,mColumns-1,(void*)NULL));
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::getFilesList(std::list<ChannelPostFileInfo>& files)
|
||||
@ -161,35 +169,30 @@ void RsGxsChannelPostsModel::getFilesList(std::list<ChannelPostFileInfo>& files)
|
||||
files.push_back(it.second);
|
||||
}
|
||||
|
||||
void RsGxsChannelPostsModel::setFilter(const QStringList& strings, uint32_t& count)
|
||||
void RsGxsChannelPostsModel::setFilter(const QStringList& strings,bool only_unread, uint32_t& count)
|
||||
{
|
||||
preMods();
|
||||
|
||||
beginRemoveRows(QModelIndex(),0,rowCount()-1);
|
||||
endRemoveRows();
|
||||
|
||||
if(strings.empty())
|
||||
mFilteredPosts.clear();
|
||||
//mFilteredPosts.push_back(0);
|
||||
|
||||
for(size_t i=0;i<mPosts.size();++i)
|
||||
{
|
||||
mFilteredPosts.clear();
|
||||
for(size_t i=0;i<mPosts.size();++i)
|
||||
bool passes_strings = true;
|
||||
|
||||
for(auto& s:strings)
|
||||
passes_strings = passes_strings && QString::fromStdString(mPosts[i].mMeta.mMsgName).contains(s,Qt::CaseInsensitive);
|
||||
|
||||
if(strings.empty())
|
||||
passes_strings = true;
|
||||
|
||||
if(passes_strings && (!only_unread || (IS_MSG_UNREAD(mPosts[i].mMeta.mMsgStatus) || IS_MSG_NEW(mPosts[i].mMeta.mMsgStatus))))
|
||||
mFilteredPosts.push_back(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
mFilteredPosts.clear();
|
||||
//mFilteredPosts.push_back(0);
|
||||
|
||||
for(size_t i=0;i<mPosts.size();++i)
|
||||
{
|
||||
bool passes_strings = true;
|
||||
|
||||
for(auto& s:strings)
|
||||
passes_strings = passes_strings && QString::fromStdString(mPosts[i].mMeta.mMsgName).contains(s,Qt::CaseInsensitive);
|
||||
|
||||
if(passes_strings)
|
||||
mFilteredPosts.push_back(i);
|
||||
}
|
||||
}
|
||||
count = mFilteredPosts.size();
|
||||
|
||||
std::cerr << "After filtering: " << count << " posts remain." << std::endl;
|
||||
@ -209,7 +212,12 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const
|
||||
return 0;
|
||||
|
||||
if(!parent.isValid())
|
||||
return (mFilteredPosts.size() + mColumns-1)/mColumns; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1
|
||||
{
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return (mFilteredPosts.size() + mColumns-1)/mColumns; // mFilteredPosts always has an item at 0, so size()>=1, and mColumn>=1
|
||||
else
|
||||
return mFilteredPosts.size();
|
||||
}
|
||||
|
||||
RsErr() << __PRETTY_FUNCTION__ << " rowCount cannot figure out the porper number of rows." << std::endl;
|
||||
return 0;
|
||||
@ -217,7 +225,10 @@ int RsGxsChannelPostsModel::rowCount(const QModelIndex& parent) const
|
||||
|
||||
int RsGxsChannelPostsModel::columnCount(const QModelIndex &/*parent*/) const
|
||||
{
|
||||
return std::min((int)mFilteredPosts.size(),(int)mColumns) ;
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return std::min((int)mFilteredPosts.size(),(int)mColumns) ;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
bool RsGxsChannelPostsModel::getPostData(const QModelIndex& i,RsGxsChannelPost& fmpe) const
|
||||
@ -284,7 +295,7 @@ QModelIndex RsGxsChannelPostsModel::index(int row, int column, const QModelIndex
|
||||
if(row < 0 || column < 0 || column >= (int)mColumns)
|
||||
return QModelIndex();
|
||||
|
||||
quintptr ref = getChildRef(parent.internalId(),column + row*mColumns);
|
||||
quintptr ref = getChildRef(parent.internalId(),(mTreeMode == TREE_MODE_GRID)?(column + row*mColumns):row);
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
std::cerr << "index-3(" << row << "," << column << " parent=" << parent << ") : " << createIndex(row,column,ref) << std::endl;
|
||||
@ -363,8 +374,6 @@ quintptr RsGxsChannelPostsModel::getParentRow(quintptr ref,int& row) const
|
||||
|
||||
int RsGxsChannelPostsModel::getChildrenCount(quintptr ref) const
|
||||
{
|
||||
uint32_t entry = 0 ;
|
||||
|
||||
if(ref == quintptr(0))
|
||||
return rowCount()-1;
|
||||
|
||||
@ -421,7 +430,7 @@ QVariant RsGxsChannelPostsModel::data(const QModelIndex &index, int role) const
|
||||
}
|
||||
}
|
||||
|
||||
QVariant RsGxsChannelPostsModel::sizeHintRole(int col) const
|
||||
QVariant RsGxsChannelPostsModel::sizeHintRole(int /* col */) const
|
||||
{
|
||||
float factor = QFontMetricsF(QApplication::font()).height()/14.0f ;
|
||||
|
||||
@ -493,7 +502,7 @@ void RsGxsChannelPostsModel::setPosts(const RsGxsChannelGroup& group, std::vecto
|
||||
std::sort(mPosts.begin(),mPosts.end());
|
||||
|
||||
mFilteredPosts.clear();
|
||||
for(int i=0;i<mPosts.size();++i)
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
mFilteredPosts.push_back(i);
|
||||
|
||||
#ifdef DEBUG_CHANNEL_MODEL
|
||||
@ -564,8 +573,6 @@ void RsGxsChannelPostsModel::update_posts(const RsGxsGroupId& group_id)
|
||||
});
|
||||
}
|
||||
|
||||
static bool decreasing_time_comp(const std::pair<time_t,RsGxsMessageId>& e1,const std::pair<time_t,RsGxsMessageId>& e2) { return e2.first < e1.first ; }
|
||||
|
||||
void RsGxsChannelPostsModel::createPostsArray(std::vector<RsGxsChannelPost>& posts)
|
||||
{
|
||||
// collect new versions of posts if any
|
||||
@ -689,10 +696,25 @@ void RsGxsChannelPostsModel::setAllMsgReadStatus(bool read_status)
|
||||
// No need to call preMods()/postMods() here because we're not changing the model
|
||||
// All operations below are done async
|
||||
|
||||
RsThread::async([this, read_status]()
|
||||
// 1 - copy all msg/grp id groups, so that changing the mPosts list while calling the async method will not break the work
|
||||
|
||||
std::vector<RsGxsGrpMsgIdPair> pairs;
|
||||
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
{
|
||||
for(uint32_t i=0;i<mPosts.size();++i)
|
||||
rsGxsChannels->markRead(RsGxsGrpMsgIdPair(mPosts[i].mMeta.mGroupId,mPosts[i].mMeta.mMsgId),read_status);
|
||||
bool post_status = !((IS_MSG_UNREAD(mPosts[i].mMeta.mMsgStatus) || IS_MSG_NEW(mPosts[i].mMeta.mMsgStatus)));
|
||||
|
||||
if(post_status != read_status)
|
||||
pairs.push_back(RsGxsGrpMsgIdPair(mPosts[i].mMeta.mGroupId,mPosts[i].mMeta.mMsgId));
|
||||
}
|
||||
|
||||
// 2 - then call the async methods
|
||||
|
||||
RsThread::async([pairs, read_status]()
|
||||
{
|
||||
for(uint32_t i=0;i<pairs.size();++i)
|
||||
if(!rsGxsChannels->markRead(pairs[i],read_status))
|
||||
RsErr() << "setAllMsgReadStatus: failed to change status of msg " << pairs[i].first << " in group " << pairs[i].second << " to status " << read_status << std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
@ -720,15 +742,18 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid)
|
||||
|
||||
for(uint32_t i=0;i<mFilteredPosts.size();++i)
|
||||
{
|
||||
// First look into msg versions, in case the msg is a version of an existing message
|
||||
// First look into msg versions, in case the msg is a version of an existing message
|
||||
|
||||
for(auto& msg_id:mPosts[mFilteredPosts[i]].mOlderVersions)
|
||||
if(msg_id == postId)
|
||||
{
|
||||
quintptr ref ;
|
||||
convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab
|
||||
quintptr ref ;
|
||||
convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab
|
||||
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
else
|
||||
return createIndex(i,0, ref);
|
||||
}
|
||||
|
||||
if(mPosts[mFilteredPosts[i]].mMeta.mMsgId == postId)
|
||||
@ -736,7 +761,10 @@ QModelIndex RsGxsChannelPostsModel::getIndexOfMessage(const RsGxsMessageId& mid)
|
||||
quintptr ref ;
|
||||
convertTabEntryToRefPointer(i,ref); // we dont use i+1 here because i is not a row, but an index in the mPosts tab
|
||||
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
if(mTreeMode == TREE_MODE_GRID)
|
||||
return createIndex(i/mColumns,i%mColumns, ref);
|
||||
else
|
||||
return createIndex(i,0, ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,8 +92,8 @@ public:
|
||||
#endif
|
||||
|
||||
enum TreeMode{ TREE_MODE_UNKWN = 0x00,
|
||||
TREE_MODE_PLAIN = 0x01,
|
||||
TREE_MODE_FILES = 0x02,
|
||||
TREE_MODE_GRID = 0x01,
|
||||
TREE_MODE_LIST = 0x02,
|
||||
};
|
||||
|
||||
#ifdef TODO
|
||||
@ -107,11 +107,18 @@ public:
|
||||
|
||||
std::vector<std::pair<time_t,RsGxsMessageId> > getPostVersions(const RsGxsMessageId& mid) const;
|
||||
|
||||
uint32_t getNumberOfPosts() { return mPosts.size() ; }
|
||||
const RsGxsChannelPost& post(uint32_t i) const { return mPosts[i]; }
|
||||
|
||||
// This method will asynchroneously update the data
|
||||
void updateChannel(const RsGxsGroupId& channel_group_id);
|
||||
const RsGxsGroupId& currentGroupId() const;
|
||||
|
||||
void triggerViewUpdate();
|
||||
|
||||
void setNumColumns(int n);
|
||||
void setMode(TreeMode mode);
|
||||
TreeMode getMode() const { return mTreeMode; }
|
||||
|
||||
// Retrieve the full list of files for all posts.
|
||||
|
||||
@ -130,7 +137,7 @@ public:
|
||||
void setMsgReadStatus(const QModelIndex &i, bool read_status);
|
||||
void setAllMsgReadStatus(bool read_status);
|
||||
|
||||
void setFilter(const QStringList &strings, uint32_t &count) ;
|
||||
void setFilter(const QStringList &strings, bool only_unread,uint32_t &count) ;
|
||||
|
||||
#ifdef TODO
|
||||
void setAuthorOpinion(const QModelIndex& indx,RsOpinion op);
|
||||
@ -228,8 +235,6 @@ private:
|
||||
std::vector<int> mFilteredPosts; // stores the list of displayes indices due to filtering.
|
||||
std::vector<RsGxsChannelPost> mPosts ; // store the list of posts updated from rsForums.
|
||||
|
||||
//std::map<RsGxsMessageId,std::vector<std::pair<time_t,RsGxsMessageId> > > mPostVersions; // stores versions of posts
|
||||
|
||||
QColor mTextColorRead ;
|
||||
QColor mTextColorUnread ;
|
||||
QColor mTextColorUnreadChildren;
|
||||
|
@ -61,6 +61,8 @@ static const int CHANNEL_TABS_DETAILS= 0;
|
||||
static const int CHANNEL_TABS_POSTS = 1;
|
||||
static const int CHANNEL_TABS_FILES = 2;
|
||||
|
||||
QColor SelectedColor = QRgb(0xff308dc7);
|
||||
|
||||
/* View mode */
|
||||
#define VIEW_MODE_FEEDS 1
|
||||
#define VIEW_MODE_FILES 2
|
||||
@ -74,14 +76,23 @@ static const int CHANNEL_TABS_FILES = 2;
|
||||
|
||||
#define STAR_OVERLAY_IMAGE ":icons/star_overlay_128.png"
|
||||
#define IMAGE_COPYLINK ":/images/copyrslink.png"
|
||||
#define IMAGE_GRID_VIEW ":icons/png/menu.png"
|
||||
#define IMAGE_DOWNLOAD ":icons/png/download.png"
|
||||
|
||||
Q_DECLARE_METATYPE(ChannelPostFileInfo)
|
||||
|
||||
// Delegate used to paint into the table of thumbnails
|
||||
|
||||
int ChannelPostDelegate::cellSize(const QFont& font) const
|
||||
//===============================================================================================================================================//
|
||||
//=== ChannelPostDelegate ===//
|
||||
//===============================================================================================================================================//
|
||||
|
||||
int ChannelPostDelegate::cellSize(int col,const QFont& font,uint32_t parent_width) const
|
||||
{
|
||||
return mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height();
|
||||
if(mUseGrid || col==0)
|
||||
return mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height();
|
||||
else
|
||||
return 0.8*parent_width - mZoom*COLUMN_SIZE_FONT_FACTOR_W*QFontMetricsF(font).height();
|
||||
}
|
||||
|
||||
void ChannelPostDelegate::zoom(bool zoom_or_unzoom)
|
||||
@ -91,53 +102,106 @@ void ChannelPostDelegate::zoom(bool zoom_or_unzoom)
|
||||
else
|
||||
mZoom /= 1.02;
|
||||
|
||||
std::cerr << "zoom factor: " << mZoom << std::endl;
|
||||
if(mZoom < 0.5)
|
||||
mZoom = 0.5;
|
||||
if(mZoom > 2.0)
|
||||
mZoom = 2.0;
|
||||
}
|
||||
|
||||
void ChannelPostDelegate::setAspectRatio(ChannelPostThumbnailView::AspectRatio r)
|
||||
{
|
||||
mAspectRatio = r;
|
||||
}
|
||||
void ChannelPostDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
|
||||
{
|
||||
// prepare
|
||||
painter->save();
|
||||
painter->setClipRect(option.rect);
|
||||
// prepare
|
||||
painter->save();
|
||||
painter->setClipRect(option.rect);
|
||||
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
|
||||
painter->fillRect( option.rect, option.backgroundBrush);
|
||||
painter->restore();
|
||||
|
||||
ChannelPostThumbnailView w(post);
|
||||
if(mUseGrid || index.column()==0)
|
||||
{
|
||||
// Draw a thumbnail
|
||||
|
||||
QPixmap pixmap(w.size());
|
||||
uint32_t flags = (mUseGrid)?(ChannelPostThumbnailView::FLAG_SHOW_TEXT | ChannelPostThumbnailView::FLAG_SCALE_FONT):0;
|
||||
ChannelPostThumbnailView w(post,flags);
|
||||
w.setAspectRatio(mAspectRatio);
|
||||
w.updateGeometry();
|
||||
w.adjustSize();
|
||||
|
||||
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
|
||||
pixmap.fill(QRgb(0xff308dc7)); // I dont know how to grab the backgroud color for selected objects automatically.
|
||||
else
|
||||
pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background
|
||||
QPixmap pixmap(w.size());
|
||||
|
||||
w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
|
||||
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
|
||||
pixmap.fill(SelectedColor); // I dont know how to grab the backgroud color for selected objects automatically.
|
||||
else
|
||||
pixmap.fill(QRgb(0x00ffffff)); // choose a fully transparent background
|
||||
|
||||
if(mZoom != 1.0)
|
||||
pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
|
||||
w.render(&pixmap,QPoint(),QRegion(),QWidget::DrawChildren );// draw the widgets, not the background
|
||||
|
||||
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
{
|
||||
QPainter p(&pixmap);
|
||||
QFontMetricsF fm(option.font);
|
||||
p.drawPixmap(mZoom*QPoint(6.2*fm.height(),6.9*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*7*fm.height(),mZoom*7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
|
||||
}
|
||||
// We extract from the pixmap the part of the widget that we want. Saddly enough, Qt adds some white space
|
||||
// below the widget and there is no way to control that.
|
||||
|
||||
// debug
|
||||
// if(index.row()==0 && index.column()==0)
|
||||
// {
|
||||
// QFile file("yourFile.png");
|
||||
// file.open(QIODevice::WriteOnly);
|
||||
// pixmap.save(&file, "PNG");
|
||||
// std::cerr << "Saved pxmap to png" << std::endl;
|
||||
// }
|
||||
//std::cerr << "option.rect = " << option.rect.width() << "x" << option.rect.height() << ". fm.height()=" << QFontMetricsF(option.font).height() << std::endl;
|
||||
pixmap = pixmap.copy(QRect(0,0,w.actualSize().width(),w.actualSize().height()));
|
||||
|
||||
painter->drawPixmap(option.rect.topLeft(),
|
||||
pixmap.scaled(option.rect.width(),option.rect.width()*w.height()/(float)w.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
|
||||
// if(index.row()==0 && index.column()==0)
|
||||
// {
|
||||
// QFile file("yourFile.png");
|
||||
// file.open(QIODevice::WriteOnly);
|
||||
// pixmap.save(&file, "PNG");
|
||||
// file.close();
|
||||
// }
|
||||
|
||||
if(mUseGrid || index.column()==0)
|
||||
{
|
||||
if(mZoom != 1.0)
|
||||
pixmap = pixmap.scaled(mZoom*pixmap.size(),Qt::KeepAspectRatio,Qt::SmoothTransformation);
|
||||
|
||||
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
{
|
||||
QPainter p(&pixmap);
|
||||
QFontMetricsF fm(option.font);
|
||||
|
||||
p.drawPixmap(mZoom*QPoint(0.1*fm.height(),-3.6*fm.height()),FilesDefs::getPixmapFromQtResourcePath(STAR_OVERLAY_IMAGE).scaled(mZoom*7*fm.height(),mZoom*7*fm.height(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
|
||||
}
|
||||
}
|
||||
|
||||
painter->drawPixmap(option.rect.topLeft(),
|
||||
pixmap.scaled(option.rect.width(),option.rect.width()*pixmap.height()/(float)pixmap.width(),Qt::IgnoreAspectRatio,Qt::SmoothTransformation));
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're drawing the text on the second column
|
||||
|
||||
uint32_t font_height = QFontMetricsF(option.font).height();
|
||||
QPoint p = option.rect.topLeft();
|
||||
float y = p.y() + font_height;
|
||||
|
||||
painter->save();
|
||||
|
||||
if((option.state & QStyle::State_Selected) && post.mMeta.mPublishTs > 0) // check if post is selected and is not empty (end of last row)
|
||||
painter->setPen(SelectedColor);
|
||||
|
||||
if(IS_MSG_UNREAD(post.mMeta.mMsgStatus) || IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
{
|
||||
QFont font(option.font);
|
||||
font.setBold(true);
|
||||
painter->setFont(font);
|
||||
}
|
||||
painter->drawText(QPoint(p.x()+0.5*font_height,y),QString::fromUtf8(post.mMeta.mMsgName.c_str()));
|
||||
y += font_height;
|
||||
|
||||
painter->drawText(QPoint(p.x()+0.5*font_height,y),QDateTime::fromSecsSinceEpoch(post.mMeta.mPublishTs).toString(Qt::DefaultLocaleShortDate));
|
||||
y += font_height;
|
||||
|
||||
painter->drawText(QPoint(p.x()+0.5*font_height,y),QString::number(post.mCount)+ " " +((post.mCount>1)?tr("files"):tr("file")) + " (" + QString::number(post.mSize) + " " + tr("bytes") + ")" );
|
||||
y += font_height;
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
}
|
||||
|
||||
QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const
|
||||
@ -146,9 +210,36 @@ QSize ChannelPostDelegate::sizeHint(const QStyleOptionViewItem& option, const QM
|
||||
|
||||
QFontMetricsF fm(option.font);
|
||||
|
||||
return QSize(mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height(),mZoom*COLUMN_SIZE_FONT_FACTOR_H*fm.height());
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
uint32_t flags = (mUseGrid)?(ChannelPostThumbnailView::FLAG_SHOW_TEXT | ChannelPostThumbnailView::FLAG_SCALE_FONT):0;
|
||||
|
||||
ChannelPostThumbnailView w(post,flags);
|
||||
w.setAspectRatio(mAspectRatio);
|
||||
w.updateGeometry();
|
||||
w.adjustSize();
|
||||
|
||||
//std::cerr << "w.size(): " << w.width() << " x " << w.height() << ". Actual size: " << w.actualSize().width() << " x " << w.actualSize().height() << std::endl;
|
||||
|
||||
float aspect_ratio = w.actualSize().height()/(float)w.actualSize().width();
|
||||
|
||||
float cell_width = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height();
|
||||
float cell_height = mZoom*COLUMN_SIZE_FONT_FACTOR_W*fm.height()*aspect_ratio;
|
||||
|
||||
if(mUseGrid || index.column()==0)
|
||||
return QSize(cell_width,cell_height);
|
||||
else
|
||||
return QSize(option.rect.width()-cell_width,cell_height);
|
||||
}
|
||||
|
||||
void ChannelPostDelegate::setWidgetGrid(bool use_grid)
|
||||
{
|
||||
mUseGrid = use_grid;
|
||||
}
|
||||
|
||||
//===============================================================================================================================================//
|
||||
//=== ChannelPostFilesDelegate ===//
|
||||
//===============================================================================================================================================//
|
||||
|
||||
QWidget *ChannelPostFilesDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex& index) const
|
||||
{
|
||||
ChannelPostFileInfo file = index.data(Qt::UserRole).value<ChannelPostFileInfo>() ;
|
||||
@ -222,6 +313,10 @@ QSize ChannelPostFilesDelegate::sizeHint(const QStyleOptionViewItem& option, con
|
||||
}
|
||||
}
|
||||
|
||||
//===============================================================================================================================================//
|
||||
//=== GxsChannelPostWidgetWithModel ===//
|
||||
//===============================================================================================================================================//
|
||||
|
||||
/** Constructor */
|
||||
GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupId &channelId, QWidget *parent) :
|
||||
GxsMessageFrameWidget(rsGxsChannels, parent),
|
||||
@ -230,13 +325,25 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
|
||||
/* Invoke the Qt Designer generated object setup routine */
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel());
|
||||
ui->viewType_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":icons/svg/gridlayout.svg"));
|
||||
ui->viewType_TB->setToolTip(tr("Click to switch to list view"));
|
||||
connect(ui->viewType_TB,SIGNAL(clicked()),this,SLOT(switchView()));
|
||||
|
||||
ui->showUnread_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":/images/message-state-unread.png"));
|
||||
ui->showUnread_TB->setChecked(false);
|
||||
ui->showUnread_TB->setToolTip(tr("Show unread posts only"));
|
||||
connect(ui->showUnread_TB,SIGNAL(toggled(bool)),this,SLOT(switchOnlyUnread(bool)));
|
||||
|
||||
ui->postsTree->setModel(mChannelPostsModel = new RsGxsChannelPostsModel());
|
||||
ui->postsTree->setItemDelegate(mChannelPostsDelegate = new ChannelPostDelegate());
|
||||
ui->postsTree->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // prevents bug on w10, since row size depends on widget width
|
||||
ui->postsTree->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);// more beautiful if we scroll at pixel level
|
||||
ui->postsTree->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
|
||||
mChannelPostsDelegate->setAspectRatio(ChannelPostThumbnailView::ASPECT_RATIO_16_9);
|
||||
|
||||
connect(ui->postsTree,SIGNAL(zoomRequested(bool)),this,SLOT(updateZoomFactor(bool)));
|
||||
connect(ui->commentsDialog,SIGNAL(commentsLoaded(int)),this,SLOT(updateCommentsCount(int)));
|
||||
|
||||
ui->channelPostFiles_TV->setModel(mChannelPostFilesModel = new RsGxsChannelPostFilesModel(this));
|
||||
ui->channelPostFiles_TV->setItemDelegate(new ChannelPostFilesDelegate());
|
||||
@ -262,7 +369,7 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
|
||||
ui->postTime_LB->hide();
|
||||
ui->postLogo_LB->hide();
|
||||
|
||||
ui->postDetails_TE->setPlaceholderText(tr("No post selected"));
|
||||
ui->postDetails_TE->setPlaceholderText(tr("No text to display"));
|
||||
|
||||
// Set initial size of the splitter
|
||||
ui->splitter->setStretchFactor(0, 1);
|
||||
@ -270,8 +377,9 @@ GxsChannelPostsWidgetWithModel::GxsChannelPostsWidgetWithModel(const RsGxsGroupI
|
||||
|
||||
QFontMetricsF fm(font());
|
||||
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(font()));
|
||||
if(mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(i,font(),ui->postsTree->width()));
|
||||
|
||||
/* Setup UI helper */
|
||||
|
||||
@ -339,12 +447,11 @@ void GxsChannelPostsWidgetWithModel::updateZoomFactor(bool zoom_or_unzoom)
|
||||
mChannelPostsDelegate->zoom(zoom_or_unzoom);
|
||||
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(font()));
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(i,font(),ui->postsTree->width()));
|
||||
|
||||
QSize s = ui->postsTree->size();
|
||||
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(font()))));
|
||||
std::cerr << "nb columns: " << n_columns << std::endl;
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(0,font(),s.width()))));
|
||||
|
||||
mChannelPostsModel->setNumColumns(n_columns); // forces the update
|
||||
|
||||
@ -366,7 +473,28 @@ void GxsChannelPostsWidgetWithModel::postContextMenu(const QPoint&)
|
||||
{
|
||||
QMenu menu(this);
|
||||
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()));
|
||||
#ifdef TO_REMOVE
|
||||
if(mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_GRID_VIEW), tr("Switch to list view"), this, SLOT(switchView()));
|
||||
else
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_GRID_VIEW), tr("Switch to grid view"), this, SLOT(switchView()));
|
||||
|
||||
menu.addSeparator();
|
||||
#endif
|
||||
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
|
||||
if(index.isValid())
|
||||
{
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
|
||||
if(!post.mFiles.empty())
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_DOWNLOAD), tr("Download files"), this, SLOT(download()));
|
||||
|
||||
if(!IS_MSG_UNREAD(post.mMeta.mMsgStatus) && !IS_MSG_NEW(post.mMeta.mMsgStatus))
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Mark as unread"), this, SLOT(markMessageUnread()));
|
||||
}
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(IMAGE_COPYLINK), tr("Copy RetroShare Link"), this, SLOT(copyMessageLink()));
|
||||
|
||||
if(IS_GROUP_PUBLISHER(mGroup.mMeta.mSubscribeFlags))
|
||||
menu.addAction(FilesDefs::getIconFromQtResourcePath(":/images/edit_16.png"), tr("Edit"), this, SLOT(editPost()));
|
||||
@ -374,6 +502,70 @@ void GxsChannelPostsWidgetWithModel::postContextMenu(const QPoint&)
|
||||
menu.exec(QCursor::pos());
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::markMessageUnread()
|
||||
{
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
|
||||
mChannelPostsModel->setMsgReadStatus(index,false);
|
||||
}
|
||||
|
||||
RsGxsMessageId GxsChannelPostsWidgetWithModel::getCurrentItemId() const
|
||||
{
|
||||
RsGxsMessageId selected_msg_id ;
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
|
||||
if(index.isValid())
|
||||
selected_msg_id = index.data(Qt::UserRole).value<RsGxsChannelPost>().mMeta.mMsgId ;
|
||||
|
||||
return selected_msg_id;
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::selectItem(const RsGxsMessageId& msg_id)
|
||||
{
|
||||
auto index = mChannelPostsModel->getIndexOfMessage(msg_id);
|
||||
|
||||
ui->postsTree->selectionModel()->setCurrentIndex(index,QItemSelectionModel::ClearAndSelect);
|
||||
ui->postsTree->scrollTo(index);//May change if model reloaded
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::switchView()
|
||||
{
|
||||
auto msg_id = getCurrentItemId();
|
||||
|
||||
if(mChannelPostsModel->getMode() == RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
{
|
||||
ui->viewType_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":icons/svg/listlayout.svg"));
|
||||
ui->viewType_TB->setToolTip(tr("Click to switch to grid view"));
|
||||
|
||||
ui->postsTree->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
||||
mChannelPostsDelegate->setWidgetGrid(false);
|
||||
mChannelPostsModel->setMode(RsGxsChannelPostsModel::TREE_MODE_LIST);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->viewType_TB->setIcon(FilesDefs::getIconFromQtResourcePath(":icons/svg/gridlayout.svg"));
|
||||
ui->viewType_TB->setToolTip(tr("Click to switch to list view"));
|
||||
|
||||
ui->postsTree->setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
|
||||
mChannelPostsDelegate->setWidgetGrid(true);
|
||||
mChannelPostsModel->setMode(RsGxsChannelPostsModel::TREE_MODE_GRID);
|
||||
|
||||
handlePostsTreeSizeChange(ui->postsTree->size(),true);
|
||||
}
|
||||
|
||||
for(int i=0;i<mChannelPostsModel->columnCount();++i)
|
||||
ui->postsTree->setColumnWidth(i,mChannelPostsDelegate->cellSize(i,font(),ui->postsTree->width()));
|
||||
|
||||
selectItem(msg_id);
|
||||
ui->postsTree->setFocus();
|
||||
|
||||
mChannelPostsModel->triggerViewUpdate(); // This is already called by setMode(), but the model cannot know how many
|
||||
// columns is actually has until we call handlePostsTreeSizeChange(), so
|
||||
// we have to call it again here.
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::copyMessageLink()
|
||||
{
|
||||
try
|
||||
@ -405,6 +597,30 @@ void GxsChannelPostsWidgetWithModel::copyMessageLink()
|
||||
QMessageBox::critical(NULL,tr("Link creation error"),tr("Link could not be created: ")+e.what());
|
||||
}
|
||||
}
|
||||
void GxsChannelPostsWidgetWithModel::download()
|
||||
{
|
||||
QModelIndex index = ui->postsTree->selectionModel()->currentIndex();
|
||||
RsGxsChannelPost post = index.data(Qt::UserRole).value<RsGxsChannelPost>() ;
|
||||
|
||||
std::string destination;
|
||||
rsGxsChannels->getChannelDownloadDirectory(mGroup.mMeta.mGroupId,destination);
|
||||
|
||||
for(auto file:post.mFiles)
|
||||
{
|
||||
std::list<RsPeerId> sources;
|
||||
std::string destination;
|
||||
|
||||
// Add possible direct sources.
|
||||
FileInfo fileInfo;
|
||||
rsFiles->FileDetails(file.mHash, RS_FILE_HINTS_REMOTE, fileInfo);
|
||||
|
||||
for(std::vector<TransferInfo>::const_iterator it = fileInfo.peers.begin(); it != fileInfo.peers.end(); ++it) {
|
||||
sources.push_back((*it).peerId);
|
||||
}
|
||||
|
||||
rsFiles->FileRequest(file.mName, file.mHash, file.mSize, destination, RS_FILE_REQ_ANONYMOUS_ROUTING, sources);
|
||||
}
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::editPost()
|
||||
{
|
||||
@ -415,12 +631,15 @@ void GxsChannelPostsWidgetWithModel::editPost()
|
||||
msgDialog->show();
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s)
|
||||
void GxsChannelPostsWidgetWithModel::handlePostsTreeSizeChange(QSize s,bool force)
|
||||
{
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(font()))));
|
||||
std::cerr << "nb columns: " << n_columns << std::endl;
|
||||
if(mChannelPostsModel->getMode() != RsGxsChannelPostsModel::TREE_MODE_GRID)
|
||||
return;
|
||||
|
||||
if(n_columns != mChannelPostsModel->columnCount())
|
||||
int n_columns = std::max(1,(int)floor(s.width() / (mChannelPostsDelegate->cellSize(0,font(),ui->postsTree->width()))));
|
||||
std::cerr << "nb columns: " << n_columns << " current count=" << mChannelPostsModel->columnCount() << std::endl;
|
||||
|
||||
if(force || (n_columns != mChannelPostsModel->columnCount()))
|
||||
mChannelPostsModel->setNumColumns(n_columns);
|
||||
}
|
||||
|
||||
@ -461,10 +680,12 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
|
||||
ui->postLogo_LB->hide();
|
||||
ui->postName_LB->hide();
|
||||
ui->postTime_LB->hide();
|
||||
mChannelPostFilesModel->clear();
|
||||
mChannelPostFilesModel->clear();
|
||||
ui->details_TW->setEnabled(false);
|
||||
|
||||
return;
|
||||
}
|
||||
ui->details_TW->setEnabled(true);
|
||||
|
||||
ui->postLogo_LB->show();
|
||||
ui->postName_LB->show();
|
||||
@ -506,7 +727,7 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
|
||||
ui->postLogo_LB->setFixedSize(W,postImage.height()/(float)postImage.width()*W);
|
||||
|
||||
ui->postName_LB->setText(QString::fromUtf8(post.mMeta.mMsgName.c_str()));
|
||||
ui->postName_LB->setFixedWidth(W);
|
||||
|
||||
ui->postTime_LB->setText(QDateTime::fromMSecsSinceEpoch(post.mMeta.mPublishTs*1000).toString("MM/dd/yyyy, hh:mm"));
|
||||
ui->postTime_LB->setFixedWidth(W);
|
||||
|
||||
@ -526,6 +747,13 @@ void GxsChannelPostsWidgetWithModel::showPostDetails()
|
||||
}
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::updateCommentsCount(int n)
|
||||
{
|
||||
if(n > 0)
|
||||
ui->details_TW->setTabText(2,tr("Comments (%1)").arg(n));
|
||||
else
|
||||
ui->details_TW->setTabText(2,tr("Comments"));
|
||||
}
|
||||
void GxsChannelPostsWidgetWithModel::updateGroupData()
|
||||
{
|
||||
if(groupId().isNull())
|
||||
@ -553,6 +781,8 @@ void GxsChannelPostsWidgetWithModel::updateGroupData()
|
||||
{
|
||||
mGroup = group;
|
||||
mChannelPostsModel->updateChannel(groupId());
|
||||
whileBlocking(ui->filterLineEdit)->clear();
|
||||
whileBlocking(ui->showUnread_TB)->setChecked(false);
|
||||
|
||||
insertChannelDetails(mGroup);
|
||||
|
||||
@ -585,10 +815,30 @@ void GxsChannelPostsWidgetWithModel::postChannelPostLoad()
|
||||
mChannelPostsModel->getFilesList(files);
|
||||
mChannelFilesModel->setFiles(files);
|
||||
|
||||
//ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_FILE);
|
||||
//ui->channelFiles_TV->resizeColumnToContents(RsGxsChannelPostFilesModel::COLUMN_FILES_SIZE);
|
||||
ui->channelFiles_TV->setAutoSelect(true);
|
||||
ui->channelFiles_TV->sortByColumn(0, Qt::AscendingOrder);
|
||||
|
||||
ui->infoPosts->setText(QString::number(mChannelPostsModel->getNumberOfPosts()) + " / " + QString::number(mGroup.mMeta.mVisibleMsgCount));
|
||||
|
||||
// now compute aspect ratio for posts. We do that by looking at the 5 latest posts and compute the best aspect ratio for them.
|
||||
|
||||
std::vector<uint32_t> ar_votes(4,0);
|
||||
|
||||
for(uint32_t i=0;i<std::min(mChannelPostsModel->getNumberOfPosts(),5u);++i)
|
||||
{
|
||||
const RsGxsChannelPost& post = mChannelPostsModel->post(i);
|
||||
ChannelPostThumbnailView v(post,ChannelPostThumbnailView::FLAG_SHOW_TEXT | ChannelPostThumbnailView::FLAG_SCALE_FONT);
|
||||
|
||||
++ar_votes[ static_cast<uint32_t>( v.bestAspectRatio() )];
|
||||
}
|
||||
int best=0;
|
||||
for(uint32_t i=0;i<4;++i)
|
||||
if(ar_votes[i] > ar_votes[best])
|
||||
best = i;
|
||||
|
||||
mChannelPostsDelegate->setAspectRatio(static_cast<ChannelPostThumbnailView::AspectRatio>(best));
|
||||
mChannelPostsModel->triggerViewUpdate();
|
||||
handlePostsTreeSizeChange(ui->postsTree->size(),true); // force the update
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::updateDisplay(bool complete)
|
||||
@ -769,8 +1019,6 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
rsGxsChannels->getChannelAutoDownload(group.mMeta.mGroupId,autoDownload);
|
||||
setAutoDownload(autoDownload);
|
||||
|
||||
RetroShareLink link;
|
||||
|
||||
if (IS_GROUP_SUBSCRIBED(group.mMeta.mSubscribeFlags))
|
||||
{
|
||||
ui->subscribeToolButton->setText(tr("Subscribed") + " " + QString::number(group.mMeta.mPop) );
|
||||
@ -789,6 +1037,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
|
||||
|
||||
ui->infoPosts->setText(QString::number(group.mMeta.mVisibleMsgCount));
|
||||
|
||||
if(group.mMeta.mLastPost==0)
|
||||
ui->infoLastPost->setText(tr("Never"));
|
||||
else
|
||||
@ -808,8 +1057,11 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
|
||||
ui->infoAdministrator->setId(group.mMeta.mAuthorId) ;
|
||||
|
||||
link = RetroShareLink::createMessage(group.mMeta.mAuthorId, "");
|
||||
ui->infoAdministrator->setText(link.toHtml());
|
||||
if(!group.mMeta.mAuthorId.isNull())
|
||||
{
|
||||
RetroShareLink link = RetroShareLink::createMessage(group.mMeta.mAuthorId, "");
|
||||
ui->infoAdministrator->setText(link.toHtml());
|
||||
}
|
||||
|
||||
ui->infoCreated->setText(DateTime::formatLongDateTime(group.mMeta.mPublishTs));
|
||||
|
||||
@ -850,6 +1102,7 @@ void GxsChannelPostsWidgetWithModel::insertChannelDetails(const RsGxsChannelGrou
|
||||
#endif
|
||||
ui->subscribeToolButton->setText(tr("Subscribe ") + " " + QString::number(group.mMeta.mPop) );
|
||||
|
||||
showPostDetails();
|
||||
}
|
||||
|
||||
#ifdef TODO
|
||||
@ -893,15 +1146,17 @@ void GxsChannelPostsWidgetWithModel::setViewMode(int viewMode)
|
||||
#endif
|
||||
}
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::switchOnlyUnread(bool)
|
||||
{
|
||||
filterChanged(ui->filterLineEdit->text());
|
||||
std::cerr << "Switched to unread/read"<< std::endl;
|
||||
}
|
||||
void GxsChannelPostsWidgetWithModel::filterChanged(QString s)
|
||||
{
|
||||
QStringList ql = s.split(' ',QString::SkipEmptyParts);
|
||||
uint32_t count;
|
||||
mChannelPostsModel->setFilter(ql,count);
|
||||
mChannelPostsModel->setFilter(ql,ui->showUnread_TB->isChecked(),count);
|
||||
mChannelFilesModel->setFilter(ql,count);
|
||||
|
||||
//mChannelPostFilesProxyModel->setFilterKeyColumn(RsGxsChannelPostFilesModel::COLUMN_FILES_NAME);
|
||||
//mChannelPostFilesProxyModel->setFilterRegExp(s) ;// triggers a re-display. s is actually not used.
|
||||
}
|
||||
|
||||
#ifdef TODO
|
||||
@ -1148,25 +1403,6 @@ public:
|
||||
uint32_t mLastToken;
|
||||
};
|
||||
|
||||
#ifdef TO_REMOVE
|
||||
static void setAllMessagesReadCallback(FeedItem *feedItem, void *data)
|
||||
{
|
||||
GxsChannelPostItem *channelPostItem = dynamic_cast<GxsChannelPostItem*>(feedItem);
|
||||
if (!channelPostItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
GxsChannelPostsReadData *readData = (GxsChannelPostsReadData*) data;
|
||||
bool isRead = !channelPostItem->isUnread() ;
|
||||
|
||||
if(channelPostItem->isLoaded() && (isRead == readData->mRead))
|
||||
return ;
|
||||
|
||||
RsGxsGrpMsgIdPair msgPair = std::make_pair(channelPostItem->groupId(), channelPostItem->messageId());
|
||||
rsGxsChannels->setMessageReadStatus(readData->mLastToken, msgPair, readData->mRead);
|
||||
}
|
||||
#endif
|
||||
|
||||
void GxsChannelPostsWidgetWithModel::setAllMessagesReadDo(bool read, uint32_t& /*token*/)
|
||||
{
|
||||
if (groupId().isNull() || !IS_GROUP_SUBSCRIBED(mGroup.mMeta.mSubscribeFlags))
|
||||
|
@ -28,6 +28,8 @@
|
||||
#include "gui/gxs/GxsMessageFramePostWidget.h"
|
||||
#include "gui/feeds/FeedHolder.h"
|
||||
|
||||
#include "GxsChannelPostThumbnail.h"
|
||||
|
||||
namespace Ui {
|
||||
class GxsChannelPostsWidgetWithModel;
|
||||
}
|
||||
@ -60,21 +62,26 @@ class ChannelPostDelegate: public QAbstractItemDelegate
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent), mZoom(1.0){}
|
||||
ChannelPostDelegate(QObject *parent=0) : QAbstractItemDelegate(parent), mZoom(1.0), mUseGrid(true){}
|
||||
virtual ~ChannelPostDelegate(){}
|
||||
|
||||
void paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override;
|
||||
|
||||
int cellSize(const QFont& font) const;
|
||||
int cellSize(int col, const QFont& font, uint32_t parent_width) const;
|
||||
void zoom(bool zoom_or_unzoom) ;
|
||||
private:
|
||||
void setWidgetGrid(bool use_grid) ;
|
||||
void setAspectRatio(ChannelPostThumbnailView::AspectRatio r) ;
|
||||
|
||||
private:
|
||||
static constexpr float IMAGE_MARGIN_FACTOR = 1.0;
|
||||
static constexpr float IMAGE_SIZE_FACTOR_W = 4.0 ;
|
||||
static constexpr float IMAGE_SIZE_FACTOR_H = 6.0 ;
|
||||
static constexpr float IMAGE_ZOOM_FACTOR = 1.0;
|
||||
|
||||
float mZoom; // zoom factor for the whole thumbnail
|
||||
bool mUseGrid; // wether we use the grid widget or the list widget
|
||||
ChannelPostThumbnailView::AspectRatio mAspectRatio;
|
||||
};
|
||||
|
||||
class GxsChannelPostsWidgetWithModel: public GxsMessageFrameWidget
|
||||
@ -135,25 +142,32 @@ protected:
|
||||
private slots:
|
||||
void showPostDetails();
|
||||
void updateGroupData();
|
||||
void createMsg();
|
||||
void download();
|
||||
void createMsg();
|
||||
void toggleAutoDownload();
|
||||
void subscribeGroup(bool subscribe);
|
||||
void filterChanged(QString);
|
||||
void setViewMode(int viewMode);
|
||||
void settingsChanged();
|
||||
void handlePostsTreeSizeChange(QSize s);
|
||||
void handlePostsTreeSizeChange(QSize s, bool force=false);
|
||||
void postChannelPostLoad();
|
||||
void editPost();
|
||||
void postContextMenu(const QPoint&);
|
||||
void copyMessageLink();
|
||||
void updateZoomFactor(bool zoom_or_unzoom);
|
||||
void switchView();
|
||||
void switchOnlyUnread(bool b);
|
||||
void markMessageUnread();
|
||||
|
||||
public slots:
|
||||
void sortColumnFiles(int col,Qt::SortOrder so);
|
||||
void sortColumnPostFiles(int col,Qt::SortOrder so);
|
||||
void updateCommentsCount(int n);
|
||||
|
||||
private:
|
||||
void processSettings(bool load);
|
||||
RsGxsMessageId getCurrentItemId() const;
|
||||
void selectItem(const RsGxsMessageId& msg_id);
|
||||
|
||||
void setAutoDownload(bool autoDl);
|
||||
static bool filterItem(FeedItem *feedItem, const QString &text, int filter);
|
||||
|
@ -120,6 +120,26 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="showUnread_TB">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="viewType_TB">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="viewModeLayout">
|
||||
<property name="spacing">
|
||||
@ -161,7 +181,7 @@
|
||||
<item>
|
||||
<widget class="QTabWidget" name="channel_TW">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
@ -199,26 +219,6 @@
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="infoLastPost">
|
||||
<property name="text">
|
||||
<string notr="true">unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Created:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="GxsIdLabel" name="infoAdministrator">
|
||||
<property name="text">
|
||||
@ -229,26 +229,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Distribution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="infoPosts">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QLabel" name="infoLastPostLabel">
|
||||
<property name="sizePolicy">
|
||||
@ -268,8 +248,8 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="infoDistribution">
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="infoCreated">
|
||||
<property name="text">
|
||||
<string>unknown</string>
|
||||
</property>
|
||||
@ -288,8 +268,48 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="3">
|
||||
<widget class="QLabel" name="infoCreated">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="infoLastPost">
|
||||
<property name="text">
|
||||
<string notr="true">unknown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Distribution:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" colspan="2">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Created:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QLabel" name="infoPosts">
|
||||
<property name="text">
|
||||
<string notr="true">0</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="3">
|
||||
<widget class="QLabel" name="infoDistribution">
|
||||
<property name="text">
|
||||
<string>unknown</string>
|
||||
</property>
|
||||
@ -309,8 +329,11 @@
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p align="justify">The number of posts at friends is progressively updated.</p><p align="justify">The new numbers will show next time you load this channel.</p><p align="justify">The two numbers differ depending on your friends synchronization</p><p>time limits as well as yours.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Posts:</string>
|
||||
<string>Posts (locally / at friends):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -412,9 +435,6 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Details</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<property name="bottomMargin">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
@ -433,16 +453,6 @@ p, li { white-space: pre-wrap; }
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="postName_LB">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="postTime_LB">
|
||||
<property name="text">
|
||||
@ -466,11 +476,22 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="postDetails_TE">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="postName_LB">
|
||||
<property name="text">
|
||||
<string>TextLabel</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="postDetails_TE">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@ -526,7 +547,7 @@ p, li { white-space: pre-wrap; }
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_5">
|
||||
<attribute name="title">
|
||||
<string>Files</string>
|
||||
<string>All files</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
|
@ -2,8 +2,14 @@
|
||||
<qresource prefix="/">
|
||||
<file>icons/onion.png</file>
|
||||
<file>icons/svg/hidden.svg</file>
|
||||
<file>icons/svg/ratio-auto.svg</file>
|
||||
<file>icons/svg/ratio-1-1.svg</file>
|
||||
<file>icons/svg/ratio-3-4.svg</file>
|
||||
<file>icons/svg/ratio-16-9.svg</file>
|
||||
<file>icons/svg/randomness.svg</file>
|
||||
<file>icons/svg/password.svg</file>
|
||||
<file>icons/svg/listlayout.svg</file>
|
||||
<file>icons/svg/gridlayout.svg</file>
|
||||
<file>icons/stars/star0.png</file>
|
||||
<file>icons/stars/star1.png</file>
|
||||
<file>icons/stars/star2.png</file>
|
||||
|
11
retroshare-gui/src/gui/icons/svg/gridlayout.svg
Normal file
11
retroshare-gui/src/gui/icons/svg/gridlayout.svg
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 35 35" style="enable-background:new 0 0 35 35;" xml:space="preserve" class=""><g transform="matrix(0.922745 0 0 0.922745 1.35197 1.35197)"><g>
|
||||
<g>
|
||||
<rect width="9.182" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect y="19.5" width="9.182" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="12.9" y="19.5" width="9.202" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="12.9" width="9.202" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="25.82" width="9.18" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
<rect x="25.82" y="19.5" width="9.18" height="15.5" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/>
|
||||
</g>
|
||||
</g></g> </svg>
|
After Width: | Height: | Size: 1.1 KiB |
2
retroshare-gui/src/gui/icons/svg/listlayout.svg
Normal file
2
retroshare-gui/src/gui/icons/svg/listlayout.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" enable-background="new 0 0 512 512" height="512px" viewBox="0 0 512 512" width="512px" class=""><g transform="matrix(0.94148 0 0 0.94148 14.9811 14.9811)"><path d="m464.883 64.267h-417.766c-25.98 0-47.117 21.136-47.117 47.149 0 25.98 21.137 47.117 47.117 47.117h417.766c25.98 0 47.117-21.137 47.117-47.117 0-26.013-21.137-47.149-47.117-47.149z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/><path d="m464.883 208.867h-417.766c-25.98 0-47.117 21.136-47.117 47.149 0 25.98 21.137 47.117 47.117 47.117h417.766c25.98 0 47.117-21.137 47.117-47.117 0-26.013-21.137-47.149-47.117-47.149z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/><path d="m464.883 353.467h-417.766c-25.98 0-47.117 21.137-47.117 47.149 0 25.98 21.137 47.117 47.117 47.117h417.766c25.98 0 47.117-21.137 47.117-47.117 0-26.012-21.137-47.149-47.117-47.149z" data-original="#000000" class="active-path" data-old_color="#000000" fill="#039BD5"/></g> </svg>
|
After Width: | Height: | Size: 1.0 KiB |
97
retroshare-gui/src/gui/icons/svg/ratio-1-1.svg
Normal file
97
retroshare-gui/src/gui/icons/svg/ratio-1-1.svg
Normal file
@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
height="512"
|
||||
viewBox="0 -64 512 512"
|
||||
width="512"
|
||||
version="1.1"
|
||||
id="svg18"
|
||||
sodipodi:docname="ratio-1-1.svg"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
|
||||
<metadata
|
||||
id="metadata24">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs22" />
|
||||
<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="namedview20"
|
||||
showgrid="true"
|
||||
inkscape:zoom="0.65186406"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="342.77966"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g16">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid834" />
|
||||
</sodipodi:namedview>
|
||||
<g
|
||||
transform="matrix(0.922745 0 0 0.922745 19.7773 14.833)"
|
||||
id="g16">
|
||||
<path
|
||||
d="m 366.53972,252.68845 c -8.53125,0 -17.0664,-6.39844 -17.0664,-17.06641 v -93.86719 c 0,-8.53125 6.40234,-17.0664 17.0664,-17.0664 10.66797,0 14.9336,6.39843 14.9336,17.0664 v 96 c 0,8.53516 -6.39844,14.9336 -14.9336,14.9336 z m 0,0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039bd5"
|
||||
id="path4"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
d="m277.332031 149.332031c0 11.785157-9.550781 21.335938-21.332031 21.335938s-21.332031-9.550781-21.332031-21.335938c0-11.78125 9.550781-21.332031 21.332031-21.332031s21.332031 9.550781 21.332031 21.332031zm0 0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039BD5"
|
||||
id="path10" />
|
||||
<path
|
||||
d="m277.332031 234.667969c0 11.78125-9.550781 21.332031-21.332031 21.332031s-21.332031-9.550781-21.332031-21.332031c0-11.785157 9.550781-21.335938 21.332031-21.335938s21.332031 9.550781 21.332031 21.335938zm0 0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039BD5"
|
||||
id="path12" />
|
||||
<path
|
||||
d="m454.398438 384h-394.664063c-34.132813 0-59.734375-25.601562-59.734375-57.601562v-266.664063c0-34.132813 25.601562-59.734375 59.734375-59.734375h394.664063c32 0 57.601562 25.601562 57.601562 59.734375v266.664063c0 32-25.601562 57.601562-57.601562 57.601562zm-394.664063-352c-14.933594 0-27.734375 12.800781-27.734375 27.734375v266.664063c0 14.933593 12.800781 27.734374 27.734375 27.734374h394.664063c14.933593 0 27.734374-12.800781 27.734374-27.734374v-266.664063c0-14.933594-12.800781-27.734375-27.734374-27.734375zm0 0"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039BD5"
|
||||
id="path14" />
|
||||
<path
|
||||
d="m 156.29747,252.68845 c -8.53125,0 -17.0664,-6.39844 -17.0664,-17.0664 v -93.8672 c 0,-8.53125 6.40234,-17.0664 17.0664,-17.0664 10.66797,0 14.9336,6.39843 14.9336,17.0664 v 96.00001 c 0,8.53515 -6.39844,14.93359 -14.9336,14.93359 z"
|
||||
data-original="#000000"
|
||||
class="active-path"
|
||||
data-old_color="#000000"
|
||||
style="fill:#039bd5;stroke-width:1"
|
||||
id="path4-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssss" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
2
retroshare-gui/src/gui/icons/svg/ratio-16-9.svg
Normal file
2
retroshare-gui/src/gui/icons/svg/ratio-16-9.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="512" viewBox="0 -64 512 512" width="512" class=""><g transform="matrix(0.932065 0 0 0.932065 17.3913 13.0434)"><path d="m454.398438 384h-394.664063c-34.132813 0-59.734375-25.601562-59.734375-57.601562v-266.664063c0-34.132813 25.601562-59.734375 59.734375-59.734375h394.664063c32 0 57.601562 25.601562 57.601562 59.734375v266.664063c0 32-25.601562 57.601562-57.601562 57.601562zm-394.664063-352c-14.933594 0-27.734375 12.800781-27.734375 27.734375v266.664063c0 14.933593 12.800781 27.734374 27.734375 27.734374h394.664063c14.933593 0 27.734374-12.800781 27.734374-27.734374v-266.664063c0-14.933594-12.800781-27.734375-27.734374-27.734375zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m177.066406 256h-10.667968c-21.332032 0-38.398438-17.066406-38.398438-38.398438v-53.335937c0-19.199219 17.066406-36.265625 38.398438-36.265625h32c8.535156 0 14.933593 6.398438 14.933593 17.066406 0 10.667969-6.398437 17.066406-17.066406 17.066406h-29.867187c-2.132813 0-6.398438 2.132813-6.398438 6.402344v10.664063h17.066406c21.332032 0 38.398438 17.066406 38.398438 38.402343v6.398438c-2.132813 14.933594-19.199219 32-38.398438 32zm-17.066406-46.933594v10.667969c0 2.132813 2.132812 6.398437 6.398438 6.398437h10.667968c2.132813 0 6.398438-2.132812 6.398438-6.398437v-6.402344c0-2.132812-2.132813-6.398437-6.398438-6.398437h-17.066406zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m390.398438 256h-32c-8.53125 0-17.066407-6.398438-17.066407-17.066406 0-10.667969 6.402344-17.066406 17.066407-17.066406h32c2.136718 0 6.402343-2.132813 6.402343-6.402344v-10.664063h-17.066406c-21.335937 0-38.402344-17.066406-38.402344-38.402343v-6.398438c0-21.332031 17.066407-38.398438 38.402344-38.398438h10.664063c21.335937 0 38.402343 17.066407 38.402343 38.398438v53.332031c-2.132812 25.601563-19.199219 42.667969-38.402343 42.667969zm-10.664063-96c-2.132813 0-6.402344 2.132812-6.402344 6.398438v4.269531c0 2.132812 2.132813 6.398437 6.402344 6.398437h17.066406v-10.667968c0-2.132813-2.132812-6.398438-6.402343-6.398438zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m91.734375 256c-8.535156 0-17.066406-6.398438-17.066406-17.066406v-93.867188c0-10.667968 6.398437-17.066406 17.066406-17.066406 10.664063 0 14.933594 6.398438 14.933594 17.066406v96c0 8.535156-6.402344 14.933594-14.933594 14.933594zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m298.667969 149.332031c0 11.785157-9.550781 21.335938-21.335938 21.335938-11.78125 0-21.332031-9.550781-21.332031-21.335938 0-11.78125 9.550781-21.332031 21.332031-21.332031 11.785157 0 21.335938 9.550781 21.335938 21.332031zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/><path d="m298.667969 234.667969c0 11.78125-9.550781 21.332031-21.335938 21.332031-11.78125 0-21.332031-9.550781-21.332031-21.332031 0-11.785157 9.550781-21.335938 21.332031-21.335938 11.785157 0 21.335938 9.550781 21.335938 21.335938zm0 0" data-original="#000000" class="active-path" style="fill:#039BD5" data-old_color="#000000"/></g> </svg>
|
After Width: | Height: | Size: 3.2 KiB |
2
retroshare-gui/src/gui/icons/svg/ratio-3-4.svg
Normal file
2
retroshare-gui/src/gui/icons/svg/ratio-3-4.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="512" viewBox="0 -64 512 512" width="512"><g transform="matrix(0.922745 0 0 0.922745 19.7773 14.833)"><path d="m390.398438 209.066406h-32c-21.332032 0-38.398438-17.066406-38.398438-38.398437v-25.601563c0-10.667968 6.398438-17.066406 17.066406-17.066406 10.667969 0 17.066406 6.398438 17.066406 17.066406v25.601563c0 2.132812 2.132813 6.398437 6.402344 6.398437h32c8.53125 0 17.066406 6.398438 17.066406 17.066406 0 10.667969-10.667968 14.933594-19.203124 14.933594zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m390.398438 256c-8.53125 0-17.066407-6.398438-17.066407-17.066406v-93.867188c0-8.53125 6.402344-17.066406 17.066407-17.066406 10.667968 0 14.933593 6.398438 14.933593 17.066406v96c0 8.535156-6.398437 14.933594-14.933593 14.933594zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m177.066406 209.066406h-53.332031c-10.667969 0-17.066406-8.53125-17.066406-17.066406s6.398437-17.066406 17.066406-17.066406h53.332031c8.535156 2.132812 14.933594 8.53125 14.933594 17.066406s-6.398438 17.066406-14.933594 17.066406zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m155.734375 256h-32c-10.667969 0-17.066406-6.398438-17.066406-14.933594 0-8.53125 6.398437-17.066406 17.066406-17.066406h32c2.132813 0 6.398437-2.132812 6.398437-6.398438v-53.335937c0-2.132813-2.132812-6.398437-6.398437-6.398437h-32c-10.667969 2.132812-17.066406-4.265626-17.066406-12.800782 0-8.53125 6.398437-17.066406 17.066406-17.066406h32c19.199219 0 36.265625 17.066406 36.265625 38.398438v53.335937c0 19.199219-17.066406 36.265625-36.265625 36.265625zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m277.332031 149.332031c0 11.785157-9.550781 21.335938-21.332031 21.335938s-21.332031-9.550781-21.332031-21.335938c0-11.78125 9.550781-21.332031 21.332031-21.332031s21.332031 9.550781 21.332031 21.332031zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m277.332031 234.667969c0 11.78125-9.550781 21.332031-21.332031 21.332031s-21.332031-9.550781-21.332031-21.332031c0-11.785157 9.550781-21.335938 21.332031-21.335938s21.332031 9.550781 21.332031 21.335938zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/><path d="m454.398438 384h-394.664063c-34.132813 0-59.734375-25.601562-59.734375-57.601562v-266.664063c0-34.132813 25.601562-59.734375 59.734375-59.734375h394.664063c32 0 57.601562 25.601562 57.601562 59.734375v266.664063c0 32-25.601562 57.601562-57.601562 57.601562zm-394.664063-352c-14.933594 0-27.734375 12.800781-27.734375 27.734375v266.664063c0 14.933593 12.800781 27.734374 27.734375 27.734374h394.664063c14.933593 0 27.734374-12.800781 27.734374-27.734374v-266.664063c0-14.933594-12.800781-27.734375-27.734374-27.734375zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" style="fill:#039BD5"/></g> </svg>
|
After Width: | Height: | Size: 3.0 KiB |
14
retroshare-gui/src/gui/icons/svg/ratio-auto.svg
Normal file
14
retroshare-gui/src/gui/icons/svg/ratio-auto.svg
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512 512" style="enable-background:new 0 0 512 512;" xml:space="preserve" width="512" height="512" class="hovered-paths"><g transform="matrix(0.922745 0 0 0.922745 19.7773 19.7773)"><g>
|
||||
<g>
|
||||
<g>
|
||||
<path d="M0,64v384h512V64H0z M480,416H32V96h448V416z" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<polygon points="96,160 160,160 160,128 64,128 64,224 96,224 " data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<polygon points="448,288 416,288 416,352 352,352 352,384 448,384 " data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="192" y="128" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="64" y="256" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="416" y="224" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
<rect x="288" y="352" width="32" height="32" data-original="#000000" class="hovered-path active-path" style="fill:#039BD5" data-old_color="#000000"/>
|
||||
</g>
|
||||
</g>
|
||||
</g></g> </svg>
|
After Width: | Height: | Size: 1.5 KiB |
@ -33,17 +33,10 @@ ChannelPage::ChannelPage(QWidget * parent, Qt::WindowFlags flags)
|
||||
ui.groupFrameSettingsWidget->setOpenAllInNewTabText(tr("Open each channel in a new tab"));
|
||||
ui.groupFrameSettingsWidget->setType(GroupFrameSettings::Channel) ;
|
||||
|
||||
connect(ui.loadThreadCheckBox,SIGNAL(toggled(bool)),this,SLOT(updateLoadThread())) ;
|
||||
connect(ui.emoteicon_checkBox,SIGNAL(toggled(bool)),this,SLOT(updateEmotes())) ;
|
||||
|
||||
}
|
||||
|
||||
void ChannelPage::updateLoadThread()
|
||||
{
|
||||
Settings->setChannelLoadThread(ui.loadThreadCheckBox->isChecked());
|
||||
NotifyQt::getInstance()->notifySettingsChanged();
|
||||
}
|
||||
|
||||
ChannelPage::~ChannelPage()
|
||||
{
|
||||
}
|
||||
@ -51,7 +44,6 @@ ChannelPage::~ChannelPage()
|
||||
/** Loads the settings for this page */
|
||||
void ChannelPage::load()
|
||||
{
|
||||
whileBlocking(ui.loadThreadCheckBox)->setChecked(Settings->getChannelLoadThread());
|
||||
ui.groupFrameSettingsWidget->loadSettings(GroupFrameSettings::Channel);
|
||||
|
||||
Settings->beginGroup(QString("ChannelPostsWidget"));
|
||||
|
@ -42,9 +42,6 @@ public:
|
||||
private slots:
|
||||
void updateEmotes();
|
||||
|
||||
protected slots:
|
||||
void updateLoadThread() ;
|
||||
|
||||
private:
|
||||
Ui::ChannelPage ui;
|
||||
};
|
||||
|
@ -29,13 +29,6 @@
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="loadThreadCheckBox">
|
||||
<property name="text">
|
||||
<string>Load posts in background (Thread)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="emoteicon_checkBox">
|
||||
<property name="text">
|
||||
|
@ -1382,7 +1382,8 @@ gxschannels {
|
||||
gui/gxschannels/GxsChannelPostsModel.cpp \
|
||||
gui/gxschannels/GxsChannelPostFilesModel.cpp \
|
||||
gui/gxschannels/GxsChannelFilesWidget.cpp \
|
||||
gui/gxschannels/GxsChannelFilesStatusWidget.cpp \
|
||||
gui/gxschannels/GxsChannelPostThumbnail.cpp \
|
||||
gui/gxschannels/GxsChannelFilesStatusWidget.cpp \
|
||||
gui/gxschannels/GxsChannelGroupDialog.cpp \
|
||||
gui/gxschannels/CreateGxsChannelMsg.cpp \
|
||||
gui/feeds/GxsChannelGroupItem.cpp \
|
||||
|
@ -307,7 +307,11 @@ QPixmap misc::getOpenThumbnailedPicture(QWidget *parent, const QString &caption,
|
||||
if (!getOpenFileName(parent, RshareSettings::LASTDIR_IMAGES, caption, tr("Pictures (*.png *.jpeg *.xpm *.jpg *.tiff *.gif)"), fileName))
|
||||
return QPixmap();
|
||||
|
||||
return QPixmap(fileName).scaledToHeight(height, Qt::SmoothTransformation).copy( 0, 0, width, height);
|
||||
if(width > 0 && height > 0)
|
||||
return QPixmap(fileName).scaledToHeight(height, Qt::SmoothTransformation).copy( 0, 0, width, height);
|
||||
else
|
||||
return QPixmap(fileName);
|
||||
|
||||
//return QPixmap(fileName).scaledToHeight(width, height, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user