Add buffer-specific actions to ChatView's context menu
[quassel.git] / src / qtui / chatitem.h
index 98056ef..d68f315 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef CHATITEM_H_
 #define CHATITEM_H_
 
+#include <QAction>
 #include <QGraphicsItem>
 #include <QObject>
 
@@ -67,6 +68,7 @@ public:
 
   QList<QRectF> findWords(const QString &searchWord, Qt::CaseSensitivity caseSensitive);
 
+  virtual void addActionsToMenu(QMenu *menu, const QPointF &itemPos);
   virtual void handleClick(const QPointF &pos, ChatScene::ClickMode);
 
 protected:
@@ -80,8 +82,6 @@ protected:
   virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
   virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
 
-  //virtual bool handleClick(ClickMode mode);
-
   inline QTextLayout *layout() const;
 
   virtual QTextLayout::FormatRange selectionFormat() const;
@@ -131,7 +131,7 @@ private:
 struct ChatItemPrivate {
   QTextLayout *layout;
   ChatItemPrivate(QTextLayout *l) : layout(l) {}
-  ~ChatItemPrivate() {
+  virtual ~ChatItemPrivate() {
     delete layout;
   }
 };
@@ -176,6 +176,8 @@ struct ContentsChatItemPrivate;
 
 //! A ChatItem for the contents column
 class ContentsChatItem : public ChatItem {
+  Q_DECLARE_TR_FUNCTIONS(ContentsChatItem);
+
 public:
   ContentsChatItem(const qreal &width, const QPointF &pos, QGraphicsItem *parent);
 
@@ -189,10 +191,11 @@ protected:
   virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
   virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
   virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
-  virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
-
   virtual void handleClick(const QPointF &pos, ChatScene::ClickMode clickMode);
 
+  virtual void addActionsToMenu(QMenu *menu, const QPointF &itemPos);
+  virtual void copyLinkToClipboard();
+
   virtual QVector<QTextLayout::FormatRange> additionalFormats() const;
 
   virtual void doLayout();
@@ -200,11 +203,14 @@ protected:
 
 private:
   struct Clickable;
+  class ActionProxy;
   class WrapColumnFinder;
 
   inline ContentsChatItemPrivate *privateData() const;
 
   QList<Clickable> findClickables() const;
+  Clickable clickableAt(const QPointF &pos) const;
+
   void endHoverMode();
   void showWebPreview(const Clickable &click);
   void clearWebPreview();
@@ -214,6 +220,9 @@ private:
   friend struct ContentsChatItemPrivate;
 
   QFontMetricsF *_fontMetrics;
+
+  // we need a receiver for Action signals
+  static ActionProxy _actionProxy;
 };
 
 struct ContentsChatItem::Clickable {
@@ -238,6 +247,7 @@ struct ContentsChatItemPrivate : ChatItemPrivate {
   ContentsChatItem *contentsItem;
   QList<ContentsChatItem::Clickable> clickables;
   ContentsChatItem::Clickable currentClickable;
+  ContentsChatItem::Clickable activeClickable;
 
   ContentsChatItemPrivate(QTextLayout *l, const QList<ContentsChatItem::Clickable> &c, ContentsChatItem *parent)
   : ChatItemPrivate(l), contentsItem(parent), clickables(c) {}
@@ -266,6 +276,28 @@ private:
   qreal choppedTrailing;
 };
 
+//! Acts as a proxy for Action signals targetted at a ContentsChatItem
+/** Since a ChatItem is not a QObject, hence cannot receive signals, we use a static ActionProxy
+ *  as a receiver instead. This avoids having to handle ChatItem actions (e.g. context menu entries)
+ *  outside the ChatItem.
+ */
+class ContentsChatItem::ActionProxy : public QObject {
+  Q_OBJECT
+
+public slots:
+  inline void copyLinkToClipboard() { item()->copyLinkToClipboard(); }
+
+private:
+  /// Returns the ContentsChatItem that should receive the action event.
+  /** For efficiency reasons, values are not checked for validity. You gotta make sure that you set the data() member
+   *  in the Action correctly.
+   *  @return The ChatItem from which the sending Action originated
+   */
+  inline ContentsChatItem *item() const {
+    return static_cast<ContentsChatItem *>(qobject_cast<QAction *>(sender())->data().value<void *>());
+  }
+};
+
 /*************************************************************************************************/
 
 // Avoid circular include deps