On Saturday 06 June 2009, 潘卫平 wrote:
> Hi, <br><br>&nbsp; I found that when kwin enables taskbarthumbnail effect,
> the tooltip can show the preview of windows, but we can't click these
> preview to activate or iconify the corresponding window.
> <br>&nbsp;<br>&nbsp; I made two patches.<br>1

thanks for the patches; i've modified them a bit to fix a few issues, but 
nothing significant.

i appreciate the contribution from you and Red Flag Linux and am glad to 
accept this improvement from you.

my updated patch to kdelibs is attached: can others on plasma-devel give it a 
quick API review please? thank you.

-- 
Aaron J. Seigo
humru othro a kohnu se
GPG Fingerprint: 8B8B 2209 0C6F 7C47 B1EA  EE75 D6B7 2EB1 A7F1 DB43

KDE core developer sponsored by Qt Software

Index: tooltipmanager.cpp
===================================================================
--- tooltipmanager.cpp	(revision 978920)
+++ tooltipmanager.cpp	(working copy)
@@ -62,9 +62,11 @@
           tipWidget(new ToolTip(0)),
           state(ToolTipManager::Activated),
           isShown(false),
-          delayedHide(false)
+          delayedHide(false),
+          clickable(false)
     {
-
+        QObject::connect(tipWidget, SIGNAL(activateWindowByWId(WId)),
+                         q, SLOT(activateWindowByWId(WId)));
     }
 
     ~ToolTipManagerPrivate()
@@ -81,9 +83,10 @@
       * called when a widget inside the tooltip manager is deleted
       */
     void onWidgetDestroyed(QObject * object);
-    void removeWidget(QGraphicsWidget *w);
+    void removeWidget(QGraphicsWidget *w, bool canSafelyAccess = true);
     void clearTips();
     void doDelayedHide();
+    void activateWindowByWId(WId wid);
 
     ToolTipManager *q;
     QGraphicsWidget *currentWidget;
@@ -94,6 +97,7 @@
     ToolTipManager::State state;
     bool isShown : 1;
     bool delayedHide : 1;
+    bool clickable : 1;
 };
 
 //TOOLTIP IMPLEMENTATION
@@ -137,6 +141,10 @@
         return;
     }
 
+    if (d->currentWidget) {
+        disconnect(this, 0, d->currentWidget, 0);
+    }
+
     d->hideTimer->stop();
     d->delayedHide = false;
     d->showTimer->stop();
@@ -160,7 +168,13 @@
 {
     showTimer->stop();  // stop the timer to show the tooltip
     delayedHide = true;
-    hideTimer->start(250);
+
+    if (isShown && clickable) {
+        // leave enough time for user to choose
+        hideTimer->start(1000);
+    } else {
+        hideTimer->start(250);
+    }
 }
 
 void ToolTipManager::hide(QGraphicsWidget *widget)
@@ -169,6 +183,10 @@
         return;
     }
 
+    if (d->currentWidget) {
+        disconnect(this, 0, d->currentWidget, 0);
+    }
+
     d->currentWidget = 0;
     d->showTimer->stop();  // stop the timer to show the tooltip
     d->delayedHide = false;
@@ -211,6 +229,7 @@
             hide(widget);
         } else {
             d->delayedHide = data.autohide();
+            d->clickable = data.isClickable();
             if (d->delayedHide) {
                 //kDebug() << "starting authoide";
                 d->hideTimer->start(3000);
@@ -267,13 +286,16 @@
     // NOTE: DO NOT USE THE w VARIABLE FOR ANYTHING OTHER THAN COMPARING
     //       THE ADDRESS! ACTUALLY USING THE OBJECT WILL RESULT IN A CRASH!!!
     QGraphicsWidget *w = static_cast<QGraphicsWidget*>(object);
-    removeWidget(w);
+    removeWidget(w, false);
 }
 
-void ToolTipManagerPrivate::removeWidget(QGraphicsWidget *w)
+void ToolTipManagerPrivate::removeWidget(QGraphicsWidget *w, bool canSafelyAccess)
 {
-    // DO NOT ACCESS w HERE!! IT MAY BE IN THE PROCESS OF DELETION!
-    if (currentWidget == w) {
+    if (currentWidget == w && currentWidget) {
+        if (canSafelyAccess) {
+            QObject::disconnect(q, 0, currentWidget, 0);
+        }
+
         currentWidget = 0;
         showTimer->stop();  // stop the timer to show the tooltip
         tipWidget->setContent(0, ToolTipContent());
@@ -296,6 +318,7 @@
             //One might have moused out and back in again
             delayedHide = false;
             isShown = false;
+            QObject::disconnect(q, 0, currentWidget, 0);
             currentWidget = 0;
             tipWidget->hide();
         }
@@ -353,6 +376,11 @@
     }
 }
 
+void ToolTipManagerPrivate::activateWindowByWId(WId wid)
+{
+    emit q->clicked(ToolTipManager::WindowPreviewClicked, QVariant::fromValue(wid));
+}
+
 bool ToolTipManager::eventFilter(QObject *watched, QEvent *event)
 {
     QGraphicsWidget * widget = dynamic_cast<QGraphicsWidget *>(watched);
@@ -399,6 +427,7 @@
 
         case QEvent::GraphicsSceneMousePress:
             hide(widget);
+            break;
 
         case QEvent::GraphicsSceneWheel:
         default:
Index: tooltipcontent.h
===================================================================
--- tooltipcontent.h	(revision 978920)
+++ tooltipcontent.h	(working copy)
@@ -48,79 +48,135 @@
 public:
     enum ResourceType { ImageResource = 0, HtmlResource, CssResource };
 
-    /** Creates an empty Content */
+    /**
+     * Creates an empty Content
+     */
     ToolTipContent();
 
     ~ToolTipContent();
 
-    /** Copy constructor */
+    /**
+     * Copy constructor
+     */
     ToolTipContent(const ToolTipContent &other);
 
-    /** Constructor that sets the common fields */
+    /**
+     * Constructor that sets the common fields
+     */
     ToolTipContent(const QString &mainText,
                    const QString &subText,
                    const QPixmap &image = QPixmap());
 
-    /** Constructor that sets the common fields */
+    /**
+     * Constructor that sets the common fields
+     */
     ToolTipContent(const QString &mainText,
                    const QString &subText,
                    const QIcon &icon);
 
     ToolTipContent &operator=(const ToolTipContent &other);
 
-    /** @return true if all the fields are empty */
+    /**
+     * @return true if all the fields are empty
+     */
     bool isEmpty() const;
 
-    /** Sets the main text which containts important information, e.g. the title */
+    /**
+     * Sets the main text which containts important information, e.g. the title
+     */
     void setMainText(const QString &text);
 
-    /** Important information, e.g. the title */
+    /**
+     * Important information, e.g. the title
+     */
     QString mainText() const;
 
-    /** Sets text which elaborates on the @p mainText */
+    /**
+     * Sets text which elaborates on the @p mainText
+     */
     void setSubText(const QString &text) ;
 
-    /** Elaborates on the @p mainText */
+    /**
+     * Elaborates on the @p mainText
+     */
     QString subText() const;
 
-    /** Sets the icon to show **/
+    /**
+     * Sets the icon to show
+     */
     void setImage(const QPixmap &image);
 
-    /** Sets the icon to show **/
+    /**
+     * Sets the icon to show
+     */
     void setImage(const QIcon &icon);
 
-    /** An icon to display */
+    /**
+     * An icon to display
+     */
     QPixmap image() const;
 
-    //BIC FIXME: remove when we can break BC
-    /** Sets the ID of the window to show a preview for */
+    /**
+     * Sets the ID of the window to show a preview for.
+     * @deprecated
+     * @see setWindowsToPreview
+     */
     void setWindowToPreview(WId id);
 
-    //BIC FIXME: remove when we can break BC
-    /** Id of a window if you want to show a preview */
+    /**
+     * Id of a window if you want to show a preview
+     * @deprecated
+     * @see windowsToPreview
+     */
     WId windowToPreview() const;
 
-    /** Sets the IDS of the windows to show a preview for
-        @since 4.3*/
+    /**
+     * Sets the IDS of the windows to show a preview for
+     * @since 4.3
+     */
     void setWindowsToPreview(const QList<WId> &ids);
 
-    /** Ids of a windows if you want to show a preview
-        @since 4.3*/
+    /**
+     * Ids of a windows if you want to show a preview
+     * @since 4.3
+     */
     QList<WId> windowsToPreview() const;
 
-    /** Sets whether or not to autohide the tooltip, defaults to true */
+    /** Sets whether or not to autohide the tooltip, defaults to true
+     */
     void setAutohide(bool autohide);
 
-    /** Whether or not to autohide the tooltip, defaults to true */
+    /**
+     * Whether or not to autohide the tooltip, defaults to true
+     */
     bool autohide() const;
 
-    /** Adds a resource that can then be referenced from the text elements
-        using rich text **/
+    /**
+     * Adds a resource that can then be referenced from the text elements
+     * using rich text
+     */
     void addResource(ResourceType type, const QUrl &path, const QVariant &resource);
 
-    /** Registers all resources with a given document */
+    /**
+     * Registers all resources with a given document
+     */
     void registerResources(QTextDocument *document) const;
 
+    /**
+     * Sets whether or not the tooltip contains clickable content, such as
+     * window previews. Defaults to false, or not clickable.
+     *
+     * @since 4.3
+     */
+    void setIsClickable(bool clickable);
+
+    /**
+     * @return true if the tooltip is clickabel
+     *
+     * @since 4.3
+     */
+    bool isClickable() const;
+
 private:
     ToolTipContentPrivate * const d;
 };
Index: tooltipcontent.cpp
===================================================================
--- tooltipcontent.cpp	(revision 978920)
+++ tooltipcontent.cpp	(working copy)
@@ -47,7 +47,8 @@
 {
 public:
     ToolTipContentPrivate()
-      : autohide(true)
+      : autohide(true),
+        clickable(false)
     {
     }
 
@@ -56,7 +57,8 @@
     QPixmap image;
     QList<WId> windowsToPreview;
     QHash<QString, ToolTipResource> resources;
-    bool autohide;
+    bool autohide : 1;
+    bool clickable : 1;
 };
 
 ToolTipContent::ToolTipContent()
@@ -211,6 +213,16 @@
     }
 }
 
+void ToolTipContent::setIsClickable(bool clickable)
+{
+    d->clickable = clickable;
+}
+
+bool ToolTipContent::isClickable() const
+{
+    return d->clickable;
+}
+
 } // namespace Plasma
 
 
Index: private/tooltip_p.h
===================================================================
--- private/tooltip_p.h	(revision 978920)
+++ private/tooltip_p.h	(working copy)
@@ -43,6 +43,9 @@
     bool autohide() const;
     void setDirection(Plasma::Direction);
 
+signals:
+    void activateWindowByWId(WId wid);
+
 protected:
     void checkSize();
     void adjustPosition(const QSize &previous, const QSize &current);
Index: private/windowpreview.cpp
===================================================================
--- private/windowpreview.cpp	(revision 978920)
+++ private/windowpreview.cpp	(working copy)
@@ -22,6 +22,7 @@
 
 #include <QPainter>
 #include <QVarLengthArray>
+#include <QMouseEvent>
 
 #include <kwindowsystem.h>
 #include <kdebug.h>
@@ -224,6 +225,23 @@
 #endif
 }
 
+void WindowPreview::mousePressEvent(QMouseEvent *event)
+{
+    QPoint p = event->pos();
+    WId wid = 0;
+
+    for (int i = 0; i < m_thumbnailRects.size(); ++i) {
+        if (m_thumbnailRects[i].contains(p)) {
+            wid = ids[i];
+            break;
+        }
+    }
+
+    if (wid) {
+        emit windowPreviewClicked(wid);
+    }
+}
+
 } // namespace Plasma
 
 #include "windowpreview_p.moc"
Index: private/tooltip.cpp
===================================================================
--- private/tooltip.cpp	(revision 978920)
+++ private/tooltip.cpp	(working copy)
@@ -165,7 +165,7 @@
     d->background->setEnabledBorders(FrameSvg::AllBorders);
     updateTheme();
     connect(d->background, SIGNAL(repaintNeeded()), this, SLOT(updateTheme()));
-
+    connect(d->preview, SIGNAL(windowPreviewClicked(WId)), this, SIGNAL(activateWindowByWId(WId)));
     l->addWidget(d->preview, 0, 0, 1, 2);
     l->addWidget(d->imageLabel, 1, 0);
     l->addWidget(d->text, 1, 1);
Index: private/windowpreview_p.h
===================================================================
--- private/windowpreview_p.h	(revision 978920)
+++ private/windowpreview_p.h	(working copy)
@@ -50,8 +50,12 @@
     bool isEmpty() const;
     virtual QSize sizeHint() const;
 
+signals:
+    void windowPreviewClicked(WId wid);
+
 protected:
     void paintEvent(QPaintEvent *e);
+    void mousePressEvent(QMouseEvent *event);
 
 private:
     void readWindowSizes() const;
Index: containment.cpp
===================================================================
--- containment.cpp	(revision 978920)
+++ containment.cpp	(working copy)
@@ -144,20 +144,32 @@
 
     //fix the text of the actions that need name()
     //btw, do we really want to use name() when it's a desktopcontainment?
-    QAction *closeApplet = d->actions()->action("remove");
-    closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", name()));
-    QAction *configAction = d->actions()->action("configure");
-    configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", name()));
+    QAction *closeApplet = action("remove");
+    if (closeApplet) {
+        closeApplet->setText(i18nc("%1 is the name of the applet", "Remove this %1", name()));
+    }
 
+    QAction *configAction = action("configure");
+    if (configAction) {
+        configAction->setText(i18nc("%1 is the name of the applet", "%1 Settings", name()));
+    }
+
     QAction *appletBrowserAction = action("add widgets");
-    appletBrowserAction->setVisible(unlocked);
-    appletBrowserAction->setEnabled(unlocked);
-    connect(appletBrowserAction, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
+    if (appletBrowserAction) {
+        appletBrowserAction->setVisible(unlocked);
+        appletBrowserAction->setEnabled(unlocked);
+        connect(appletBrowserAction, SIGNAL(triggered()), this, SLOT(triggerShowAddWidgets()));
+    }
 
     QAction *act = action("next applet");
-    connect(act, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
+    if (act) {
+        connect(act, SIGNAL(triggered()), this, SLOT(focusNextApplet()));
+    }
+
     act = action("previous applet");
-    connect(act, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
+    if (act) {
+        connect(act, SIGNAL(triggered()), this, SLOT(focusPreviousApplet()));
+    }
 
     if (immutability() != SystemImmutable && corona()) {
         QAction *lockDesktopAction = corona()->action("lock widgets");
@@ -169,7 +181,7 @@
 
     if (d->type == PanelContainment ||
         d->type == CustomPanelContainment) {
-        d->actions()->removeAction(d->actions()->action("zoom in"));
+        d->actions()->removeAction(action("zoom in"));
     } else {
         QAction *zoomAction = action("zoom in");
         connect(zoomAction, SIGNAL(triggered()), this, SLOT(zoomIn()));
Index: tooltipmanager.h
===================================================================
--- tooltipmanager.h	(revision 978920)
+++ tooltipmanager.h	(working copy)
@@ -76,6 +76,13 @@
         Deactivated /**<< Will discard tooltip data, and not attempt to show them */
     };
 
+    enum ClickTarget {
+        NothingClicked = 0,
+        WindowPreviewClicked = 1,
+        LinkClicked = 2,
+        IconClicked = 3
+    };
+
     /**
      * @return The singleton instance of the manager.
      */
@@ -164,6 +171,17 @@
      */
     ToolTipManager::State state() const;
 
+signals:
+    /**
+     * This signal is emitted when something in the tooltip is clicked.
+     * @arg clicked what kind of item was clicked @see ClickTarget
+     * @arg data what was clicked, such as a url in the case of a hyperlink,
+     *           or a window id in the case of a window preview.
+     * @since 4.3
+     */
+    void clicked(ToolTipManager::ClickTarget clicked, QVariant data);
+
+
 private:
     /**
      * Default constructor.
@@ -188,6 +206,7 @@
     Q_PRIVATE_SLOT(d, void showToolTip())
     Q_PRIVATE_SLOT(d, void resetShownState())
     Q_PRIVATE_SLOT(d, void onWidgetDestroyed(QObject*))
+    Q_PRIVATE_SLOT(d, void activateWindowByWId(WId wid))
 };
 
 } // namespace Plasma

Attachment: signature.asc
Description: This is a digitally signed message part.

_______________________________________________
Plasma-devel mailing list
Plasma-devel@kde.org
https://mail.kde.org/mailman/listinfo/plasma-devel

Reply via email to