diff --git a/shared/utils.cpp b/shared/utils.cpp
index 924be85..f5f7fa5 100644
--- a/shared/utils.cpp
+++ b/shared/utils.cpp
@@ -46,3 +46,40 @@ QString Shared::processMessageBody(const QString& msg)
processed.replace(urlReg, "\\1");
return "
" + processed + "
";
}
+
+static const QStringList query = {"query", "default", "inode/directory"};
+static const QRegularExpression dolphinReg("[Dd]olphin");
+static const QRegularExpression nautilusReg("[Nn]autilus");
+static const QRegularExpression cajaReg("[Cc]aja");
+static const QRegularExpression nemoReg("[Nn]emo");
+static const QRegularExpression konquerorReg("kfmclient");
+
+void Shared::showInDirectory(const QString& path)
+{
+ QFileInfo info = path;
+ if (info.exists()) {
+ QProcess proc;
+ proc.start("xdg-mime", query);
+ proc.waitForFinished();
+ QString output = proc.readLine().simplified();
+ if (output.contains(dolphinReg)) {
+ proc.startDetached("dolphin", QStringList() << "--select" << info.canonicalFilePath());
+ } else if (output.contains(nautilusReg)) {
+ proc.startDetached("nautilus", QStringList() << "--no-desktop" << info.canonicalFilePath());
+ } else if (output.contains(cajaReg)) {
+ proc.startDetached("caja", QStringList() << "--no-desktop" << info.canonicalFilePath());
+ } else if (output.contains(nemoReg)) {
+ proc.startDetached("nemo", QStringList() << "--no-desktop" << info.canonicalFilePath());
+ } else if (output.contains(konquerorReg)) {
+ proc.startDetached("konqueror", QStringList() << "--select" << info.canonicalFilePath());
+ } else {
+ QString folder;
+ if (info.isDir()) {
+ folder = info.canonicalFilePath();
+ } else {
+ folder = info.canonicalPath();
+ }
+ QDesktopServices::openUrl(QUrl::fromLocalFile(folder));
+ }
+ }
+}
diff --git a/shared/utils.h b/shared/utils.h
index e9e3d29..6bbe978 100644
--- a/shared/utils.h
+++ b/shared/utils.h
@@ -20,8 +20,13 @@
#define SHARED_UTILS_H
#include
+#include
#include
#include
+#include
+#include
+#include
+#include
#include
#include
@@ -30,6 +35,7 @@ namespace Shared {
QString generateUUID();
QString processMessageBody(const QString& msg);
+void showInDirectory(const QString& path);
static const std::vector colorPalette = {
QColor(244, 27, 63),
diff --git a/ui/models/messagefeed.cpp b/ui/models/messagefeed.cpp
index 09b11cd..743e64a 100644
--- a/ui/models/messagefeed.cpp
+++ b/ui/models/messagefeed.cpp
@@ -379,6 +379,22 @@ void Models::MessageFeed::responseArchive(const std::list list,
}
}
+QModelIndex Models::MessageFeed::index(int row, int column, const QModelIndex& parent) const
+{
+ if (!hasIndex(row, column, parent)) {
+ return QModelIndex();
+ }
+
+ StorageByTime::iterator itr = indexByTime.nth(row);
+ if (itr != indexByTime.end()) {
+ Shared::Message* msg = *itr;
+
+ return createIndex(row, column, msg);
+ } else {
+ return QModelIndex();
+ }
+}
+
QHash Models::MessageFeed::roleNames() const
{
return roles;
diff --git a/ui/models/messagefeed.h b/ui/models/messagefeed.h
index cc833fa..abf67ee 100644
--- a/ui/models/messagefeed.h
+++ b/ui/models/messagefeed.h
@@ -61,6 +61,7 @@ public:
bool canFetchMore(const QModelIndex & parent) const override;
void fetchMore(const QModelIndex & parent) override;
QHash roleNames() const override;
+ QModelIndex index(int row, int column, const QModelIndex & parent) const override;
void responseArchive(const std::list list, bool last);
void downloadAttachment(const QString& messageId);
diff --git a/ui/utils/feedview.cpp b/ui/utils/feedview.cpp
index 226b9a7..fd9669e 100644
--- a/ui/utils/feedview.cpp
+++ b/ui/utils/feedview.cpp
@@ -68,8 +68,13 @@ QModelIndex FeedView::indexAt(const QPoint& point) const
uint32_t y = vh - point.y() + vo;
for (std::deque::size_type i = 0; i < hints.size(); ++i) {
- if (hints[i].offset + hints[i].height >= y) {
- return model()->index(i, 0, rootIndex());
+ const Hint& hint = hints[i];
+ if (y <= hint.offset + hint.height) {
+ if (y > hint.offset) {
+ return model()->index(i, 0, rootIndex());
+ } else {
+ break;
+ }
}
}
@@ -279,7 +284,8 @@ void FeedView::paintEvent(QPaintEvent* event)
for (const QModelIndex& index : toRener) {
option.rect = visualRect(index);
- option.state.setFlag(QStyle::State_MouseOver, option.rect.contains(cursor));
+ bool mouseOver = option.rect.contains(cursor) && vp->rect().contains(cursor);
+ option.state.setFlag(QStyle::State_MouseOver, mouseOver);
itemDelegate(index)->paint(&painter, option, index);
}
diff --git a/ui/widgets/conversation.cpp b/ui/widgets/conversation.cpp
index e678caf..db6a92e 100644
--- a/ui/widgets/conversation.cpp
+++ b/ui/widgets/conversation.cpp
@@ -47,7 +47,8 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
delegate(new MessageDelegate(this)),
manualSliderChange(false),
tsb(QApplication::style()->styleHint(QStyle::SH_ScrollBar_Transient) == 1),
- shadow(10, 1, Qt::black, this)
+ shadow(10, 1, Qt::black, this),
+ contextMenu(new QMenu())
{
m_ui->setupUi(this);
@@ -55,6 +56,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
feed->setItemDelegate(delegate);
feed->setFrameShape(QFrame::NoFrame);
+ feed->setContextMenuPolicy(Qt::CustomContextMenu);
delegate->initializeFonts(feed->getFont());
feed->setModel(el->feed);
el->feed->incrementObservers();
@@ -62,6 +64,7 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
connect(el->feed, &Models::MessageFeed::newMessage, this, &Conversation::onFeedMessage);
connect(feed, &FeedView::resized, this, &Conversation::positionShadow);
+ connect(feed, &FeedView::customContextMenuRequested, this, &Conversation::onFeedContext);
connect(acc, &Models::Account::childChanged, this, &Conversation::onAccountChanged);
@@ -88,8 +91,6 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
//m_ui->scrollArea->setBackgroundRole(QPalette::Base);
//}
- //m_ui->scrollArea->installEventFilter(&scrollResizeCatcher);
-
//line->setMyAvatarPath(acc->getAvatarPath());
//line->setMyName(acc->getName());
@@ -98,6 +99,8 @@ Conversation::Conversation(bool muc, Models::Account* acc, Models::Element* el,
Conversation::~Conversation()
{
+ delete contextMenu;
+
element->feed->decrementObservers();
}
@@ -402,3 +405,31 @@ void Conversation::positionShadow()
shadow.move(feed->pos());
shadow.raise();
}
+
+void Conversation::onFeedContext(const QPoint& pos)
+{
+ QModelIndex index = feed->indexAt(pos);
+ if (index.isValid()) {
+ Shared::Message* item = static_cast(index.internalPointer());
+
+ contextMenu->clear();
+ bool showMenu = false;
+ QString path = item->getAttachPath();
+ if (path.size() > 0) {
+ showMenu = true;
+ QAction* open = contextMenu->addAction(Shared::icon("document-new-from-template"), tr("Open"));
+ connect(open, &QAction::triggered, [path]() {
+ QDesktopServices::openUrl(QUrl::fromLocalFile(path));
+ });
+
+ QAction* show = contextMenu->addAction(Shared::icon("document-new-from-template"), tr("Show in folder"));
+ connect(show, &QAction::triggered, [path]() {
+ Shared::showInDirectory(path);
+ });
+ }
+
+ if (showMenu) {
+ contextMenu->popup(feed->viewport()->mapToGlobal(pos));
+ }
+ }
+}
diff --git a/ui/widgets/conversation.h b/ui/widgets/conversation.h
index eaec954..690a51c 100644
--- a/ui/widgets/conversation.h
+++ b/ui/widgets/conversation.h
@@ -25,6 +25,9 @@
#include
#include
#include
+#include
+#include
+#include
#include "shared/message.h"
#include "order.h"
@@ -103,6 +106,7 @@ protected slots:
void onAccountChanged(Models::Item* item, int row, int col);
void onFeedMessage(const Shared::Message& msg);
void positionShadow();
+ void onFeedContext(const QPoint &pos);
public:
const bool isMuc;
@@ -126,6 +130,7 @@ protected:
bool tsb; //transient scroll bars
ShadowOverlay shadow;
+ QMenu* contextMenu;
};
#endif // CONVERSATION_H