Libplasma

tooltiparea.cpp
1/*
2 SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
3 SPDX-FileCopyrightText: 2011 Artur Duque de Souza <asouza@kde.org>
4 SPDX-FileCopyrightText: 2013 Sebastian Kügler <sebas@kde.org>
5 SPDX-FileCopyrightText: 2023 David Edmundson <davidedmundson@kde.org>
6
7 SPDX-License-Identifier: GPL-2.0-or-later
8*/
9
10#include "tooltiparea.h"
11#include "appletquickitem.h"
12#include "tooltipdialog.h"
13
14#include <QDebug>
15#include <QQmlEngine>
16#include <QStandardPaths>
17
18#include <KSharedConfig>
19#include <KWindowEffects>
20#include <Plasma/Applet>
21
22using namespace Qt::Literals;
23
24ToolTipDialog *ToolTipArea::s_dialog = nullptr;
25int ToolTipArea::s_dialogUsers = 0;
26
27ToolTipArea::ToolTipArea(QQuickItem *parent)
28 : QQuickItem(parent)
29 , m_tooltipsEnabledGlobally(false)
30 , m_containsMouse(false)
31 , m_location(Plasma::Types::Floating)
32 , m_textFormat(Qt::AutoText)
33 , m_active(true)
34 , m_interactive(false)
35 , m_timeout(-1)
36 , m_usingDialog(false)
37{
38 setAcceptHoverEvents(true);
39 setFiltersChildMouseEvents(true);
40
41 m_showTimer.setSingleShot(true);
42 connect(&m_showTimer, &QTimer::timeout, this, &ToolTipArea::showToolTip);
43
44 m_plasmarcWatcher = KConfigWatcher::create(KSharedConfig::openConfig(u"plasmarc"_s));
45 connect(m_plasmarcWatcher.get(), &KConfigWatcher::configChanged, this, &ToolTipArea::settingsChanged);
46 loadSettings(m_plasmarcWatcher->config()->group(u"PlasmaToolTips"_s));
47}
48
49ToolTipArea::~ToolTipArea()
50{
51 if (s_dialog && s_dialog->owner() == this) {
52 s_dialog->setVisible(false);
53 }
54
55 if (m_usingDialog) {
56 --s_dialogUsers;
57 }
58
59 if (s_dialogUsers == 0) {
60 delete s_dialog;
61 s_dialog = nullptr;
62 }
63}
64
65void ToolTipArea::settingsChanged(const KConfigGroup &group, const QByteArrayList & /*names*/)
66{
67 if (group.name() == u"PlasmaToolTips") {
68 loadSettings(group);
69 }
70}
71
72void ToolTipArea::loadSettings(const KConfigGroup &cfg)
73{
74 m_interval = cfg.readEntry("Delay", 700);
75 m_tooltipsEnabledGlobally = (m_interval > 0);
76}
77
79{
80 return m_mainItem.data();
81}
82
83ToolTipDialog *ToolTipArea::tooltipDialogInstance()
84{
85 if (!s_dialog) {
86 s_dialog = new ToolTipDialog;
87 }
88
89 if (!m_usingDialog) {
90 s_dialogUsers++;
91 m_usingDialog = true;
92 }
93
94 return s_dialog;
95}
96
97void ToolTipArea::setMainItem(QQuickItem *mainItem)
98{
99 if (m_mainItem.data() != mainItem) {
100 m_mainItem = mainItem;
101
102 Q_EMIT mainItemChanged();
103
104 if (!isValid() && s_dialog && s_dialog->owner() == this) {
105 s_dialog->setVisible(false);
106 }
107 }
108}
109
111{
112 if (!m_active) {
113 return;
114 }
115
117
118 ToolTipDialog *dlg = tooltipDialogInstance();
119
120 if (!mainItem()) {
121 setMainItem(dlg->loadDefaultItem());
122 }
123
124 // Unset the dialog's old contents before reparenting the dialog.
125 dlg->setMainItem(nullptr);
126
128 if (m_location == Plasma::Types::Floating) {
129 QQuickItem *p = parentItem();
130 while (p) {
131 PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(p);
132 if (appletItem) {
133 location = appletItem->applet()->location();
134 break;
135 }
136 p = p->parentItem();
137 }
138 }
139
140 if (mainItem()) {
141 mainItem()->setProperty("toolTip", QVariant::fromValue(this));
142 mainItem()->setVisible(true);
143 }
144
146
147 dlg->setHideTimeout(m_timeout);
148 dlg->setOwner(this);
149 dlg->setVisualParent(this);
150 dlg->setMainItem(mainItem());
151 dlg->setInteractive(m_interactive);
152
153 switch (location) {
157 dlg->setFloating(true);
158 dlg->setPopupDirection(Qt::BottomEdge);
159 break;
161 dlg->setFloating(false);
162 dlg->setPopupDirection(Qt::BottomEdge);
163 break;
165 dlg->setFloating(false);
166 dlg->setPopupDirection(Qt::TopEdge);
167 break;
169 dlg->setFloating(false);
170 dlg->setPopupDirection(Qt::RightEdge);
171 break;
173 dlg->setFloating(false);
174 dlg->setPopupDirection(Qt::LeftEdge);
175 break;
176 }
177
178 dlg->setVisible(true);
179 // In case the last owner triggered a dismiss but the dialog is still shown,
180 // showEvent won't be reached and the old timeout will still be effective.
181 // Call keepalive() to make it use the new timeout.
182 dlg->keepalive();
183}
184
186{
187 return m_mainText;
188}
189
190void ToolTipArea::setMainText(const QString &mainText)
191{
192 if (mainText == m_mainText) {
193 return;
194 }
195
196 m_mainText = mainText;
197 Q_EMIT mainTextChanged();
198
199 if (!isValid() && s_dialog && s_dialog->owner() == this) {
200 s_dialog->setVisible(false);
201 }
202}
203
205{
206 return m_subText;
207}
208
209void ToolTipArea::setSubText(const QString &subText)
210{
211 if (subText == m_subText) {
212 return;
213 }
214
215 m_subText = subText;
216 Q_EMIT subTextChanged();
217
218 if (!isValid() && s_dialog && s_dialog->owner() == this) {
219 s_dialog->setVisible(false);
220 }
221}
222
223int ToolTipArea::textFormat() const
224{
225 return m_textFormat;
226}
227
228void ToolTipArea::setTextFormat(int format)
229{
230 if (m_textFormat == format) {
231 return;
232 }
233
234 m_textFormat = format;
235 Q_EMIT textFormatChanged();
236}
237
239{
240 return m_location;
241}
242
243void ToolTipArea::setLocation(Plasma::Types::Location location)
244{
245 if (m_location == location) {
246 return;
247 }
248 m_location = location;
249 Q_EMIT locationChanged();
250}
251
252void ToolTipArea::setActive(bool active)
253{
254 if (m_active == active) {
255 return;
256 }
257
258 m_active = active;
259 if (!active) {
260 tooltipDialogInstance()->dismiss();
261 }
262 Q_EMIT activeChanged();
263}
264
265void ToolTipArea::setInteractive(bool interactive)
266{
267 if (m_interactive == interactive) {
268 return;
269 }
270
271 m_interactive = interactive;
272
273 Q_EMIT interactiveChanged();
274}
275
276void ToolTipArea::setTimeout(int timeout)
277{
278 m_timeout = timeout;
279}
280
282{
283 m_showTimer.stop();
284 tooltipDialogInstance()->dismiss();
285}
286
288{
289 m_showTimer.stop();
290 tooltipDialogInstance()->setVisible(false);
291}
292
294{
295 if (m_icon.isValid()) {
296 return m_icon;
297 } else {
298 return QString();
299 }
300}
301
302void ToolTipArea::setIcon(const QVariant &icon)
303{
304 if (icon == m_icon) {
305 return;
306 }
307
308 m_icon = icon;
309 Q_EMIT iconChanged();
310}
311
313{
314 if (m_image.isValid()) {
315 return m_image;
316 } else {
317 return QString();
318 }
319}
320
321void ToolTipArea::setImage(const QVariant &image)
322{
323 if (image == m_image) {
324 return;
325 }
326
327 m_image = image;
328 Q_EMIT imageChanged();
329}
330
332{
333 return m_containsMouse;
334}
335
336void ToolTipArea::setContainsMouse(bool contains)
337{
338 if (m_containsMouse != contains) {
339 m_containsMouse = contains;
340 Q_EMIT containsMouseChanged();
341 }
342 if (!contains && tooltipDialogInstance()->owner() == this) {
343 tooltipDialogInstance()->dismiss();
344 }
345}
346
348{
349 Q_UNUSED(event)
350 setContainsMouse(true);
351
352 if (!m_tooltipsEnabledGlobally) {
353 return;
354 }
355
356 if (!isValid()) {
357 return;
358 }
359
360 if (tooltipDialogInstance()->isVisible()) {
361 // We signal the tooltipmanager that we're "potentially interested,
362 // and ask to keep it open for a bit, so other items get the chance
363 // to update the content before the tooltip hides -- this avoids
364 // flickering
365 // It need to be considered only when other items can deal with tooltip area
366 if (m_active) {
367 tooltipDialogInstance()->keepalive();
368 // FIXME: showToolTip needs to be renamed in sync or something like that
369 showToolTip();
370 }
371 } else {
372 m_showTimer.start(m_interval);
373 }
374}
375
377{
378 Q_UNUSED(event)
379 setContainsMouse(false);
380 m_showTimer.stop();
381}
382
384{
385 if (event->type() == QEvent::MouseButtonPress) {
386 hideToolTip();
387 }
389}
390
391bool ToolTipArea::isValid() const
392{
393 return m_mainItem || !mainText().isEmpty() || !subText().isEmpty();
394}
395
396#include "moc_tooltiparea.cpp"
QString name() const
QString readEntry(const char *key, const char *aDefault=nullptr) const
static Ptr create(const KSharedConfig::Ptr &config)
void configChanged(const KConfigGroup &group, const QByteArrayList &names)
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
Plasma::Types::Location location
The location of the scene which is displaying applet.
Definition applet.h:95
Location
The Location enumeration describes where on screen an element, such as an Applet or its managing cont...
Definition plasma.h:81
@ RightEdge
Along the right side of the screen.
Definition plasma.h:90
@ Floating
Free floating.
Definition plasma.h:82
@ FullScreen
Full screen.
Definition plasma.h:86
@ TopEdge
Along the top of the screen.
Definition plasma.h:87
@ Desktop
On the planar desktop layer, extending across the full screen from edge to edge.
Definition plasma.h:84
@ LeftEdge
Along the left side of the screen.
Definition plasma.h:89
@ BottomEdge
Along the bottom of the screen.
Definition plasma.h:88
void hideToolTip()
Hides the tooltip after a grace period if shown.
int textFormat
how to handle the text format of the tooltip subtext:
Definition tooltiparea.h:82
bool interactive
If interactive is false (default), the tooltip will automatically hide itself as soon as the mouse le...
bool containsMouse
Returns whether the mouse is inside the item.
Definition tooltiparea.h:92
QString subText
The description of this tooltip.
Definition tooltiparea.h:72
void toolTipVisibleChanged(bool toolTipVisible)
Emitted when the tooltip's visibility changes.
QML_ELEMENTQQuickItem * mainItem
The item shown inside the tooltip.
Definition tooltiparea.h:62
QVariant image
TODO: single property for images?
QString mainText
The main text of this tooltip.
Definition tooltiparea.h:67
void showToolTip()
Shows the tooltip.
int timeout
Timeout in milliseconds after which the tooltip will hide itself.
void hideImmediately()
Hides the tooltip immediately, in comparison to hideToolTip.
QVariant icon
An icon for this tooltip, accepted values are an icon name, a QIcon, QImage or QPixmap.
Definition tooltiparea.h:87
Plasma::Types::Location location
Plasma Location of the dialog window.
Definition tooltiparea.h:97
bool active
Property that controls if a tooltips will show on mouse over.
void aboutToShow()
Emitted just before the tooltip dialog is shown.
Namespace for everything in libplasma.
MouseButtonPress
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
T qobject_cast(QObject *object)
QQuickItem(QQuickItem *parent)
virtual bool childMouseEventFilter(QQuickItem *item, QEvent *event)
virtual bool contains(const QPointF &point) const const
virtual bool event(QEvent *ev) override
virtual void hoverEnterEvent(QHoverEvent *event)
virtual void hoverLeaveEvent(QHoverEvent *event)
QQuickItem * parentItem() const const
bool isVisible() const const
bool isEmpty() const const
UniqueConnection
BottomEdge
AutoText
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void timeout()
QVariant fromValue(T &&value)
bool isValid() const const
void visibleChanged(bool arg)
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri Feb 28 2025 11:50:52 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.