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 <KDirWatch>
19#include <KSharedConfig>
20#include <KWindowEffects>
21#include <Plasma/Applet>
22
23ToolTipDialog *ToolTipArea::s_dialog = nullptr;
24int ToolTipArea::s_dialogUsers = 0;
25
26ToolTipArea::ToolTipArea(QQuickItem *parent)
27 : QQuickItem(parent)
28 , m_tooltipsEnabledGlobally(false)
29 , m_containsMouse(false)
30 , m_location(Plasma::Types::Floating)
31 , m_textFormat(Qt::AutoText)
32 , m_active(true)
33 , m_interactive(false)
34 , m_timeout(-1)
35 , m_usingDialog(false)
36{
37 setAcceptHoverEvents(true);
38 setFiltersChildMouseEvents(true);
39
40 m_showTimer.setSingleShot(true);
41 connect(&m_showTimer, &QTimer::timeout, this, &ToolTipArea::showToolTip);
42
43 loadSettings();
44
45 const QString configFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/plasmarc");
46 KDirWatch::self()->addFile(configFile);
47 QObject::connect(KDirWatch::self(), &KDirWatch::created, this, &ToolTipArea::settingsChanged);
48 QObject::connect(KDirWatch::self(), &KDirWatch::dirty, this, &ToolTipArea::settingsChanged);
49}
50
51ToolTipArea::~ToolTipArea()
52{
53 if (s_dialog && s_dialog->owner() == this) {
54 s_dialog->setVisible(false);
55 }
56
57 if (m_usingDialog) {
58 --s_dialogUsers;
59 }
60
61 if (s_dialogUsers == 0) {
62 delete s_dialog;
63 s_dialog = nullptr;
64 }
65}
66
67void ToolTipArea::settingsChanged(const QString &file)
68{
69 if (!file.endsWith(QLatin1String("plasmarc"))) {
70 return;
71 }
72
73 KSharedConfig::openConfig(QStringLiteral("plasmarc"))->reparseConfiguration();
74 loadSettings();
75}
76
77void ToolTipArea::loadSettings()
78{
79 KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig(QStringLiteral("plasmarc")), QStringLiteral("PlasmaToolTips"));
80 m_interval = cfg.readEntry("Delay", 700);
81 m_tooltipsEnabledGlobally = (m_interval > 0);
82}
83
85{
86 return m_mainItem.data();
87}
88
89ToolTipDialog *ToolTipArea::tooltipDialogInstance()
90{
91 if (!s_dialog) {
92 s_dialog = new ToolTipDialog;
93 }
94
95 if (!m_usingDialog) {
96 s_dialogUsers++;
97 m_usingDialog = true;
98 }
99
100 return s_dialog;
101}
102
103void ToolTipArea::setMainItem(QQuickItem *mainItem)
104{
105 if (m_mainItem.data() != mainItem) {
106 m_mainItem = mainItem;
107
108 Q_EMIT mainItemChanged();
109
110 if (!isValid() && s_dialog && s_dialog->owner() == this) {
111 s_dialog->setVisible(false);
112 }
113 }
114}
115
117{
118 if (!m_active) {
119 return;
120 }
121
123
124 ToolTipDialog *dlg = tooltipDialogInstance();
125
126 if (!mainItem()) {
127 setMainItem(dlg->loadDefaultItem());
128 }
129
130 // Unset the dialog's old contents before reparenting the dialog.
131 dlg->setMainItem(nullptr);
132
134 if (m_location == Plasma::Types::Floating) {
135 QQuickItem *p = parentItem();
136 while (p) {
137 PlasmaQuick::AppletQuickItem *appletItem = qobject_cast<PlasmaQuick::AppletQuickItem *>(p);
138 if (appletItem) {
139 location = appletItem->applet()->location();
140 break;
141 }
142 p = p->parentItem();
143 }
144 }
145
146 if (mainItem()) {
147 mainItem()->setProperty("toolTip", QVariant::fromValue(this));
148 mainItem()->setVisible(true);
149 }
150
152
153 dlg->setHideTimeout(m_timeout);
154 dlg->setOwner(this);
155 dlg->setVisualParent(this);
156 dlg->setMainItem(mainItem());
157 dlg->setInteractive(m_interactive);
158
159 switch (location) {
163 dlg->setFloating(true);
164 dlg->setPopupDirection(Qt::BottomEdge);
165 break;
167 dlg->setFloating(false);
168 dlg->setPopupDirection(Qt::BottomEdge);
169 break;
171 dlg->setFloating(false);
172 dlg->setPopupDirection(Qt::TopEdge);
173 break;
175 dlg->setFloating(false);
176 dlg->setPopupDirection(Qt::RightEdge);
177 break;
179 dlg->setFloating(false);
180 dlg->setPopupDirection(Qt::LeftEdge);
181 break;
182 }
183
184 dlg->setVisible(true);
185 // In case the last owner triggered a dismiss but the dialog is still shown,
186 // showEvent won't be reached and the old timeout will still be effective.
187 // Call keepalive() to make it use the new timeout.
188 dlg->keepalive();
189}
190
192{
193 return m_mainText;
194}
195
196void ToolTipArea::setMainText(const QString &mainText)
197{
198 if (mainText == m_mainText) {
199 return;
200 }
201
202 m_mainText = mainText;
203 Q_EMIT mainTextChanged();
204
205 if (!isValid() && s_dialog && s_dialog->owner() == this) {
206 s_dialog->setVisible(false);
207 }
208}
209
211{
212 return m_subText;
213}
214
215void ToolTipArea::setSubText(const QString &subText)
216{
217 if (subText == m_subText) {
218 return;
219 }
220
221 m_subText = subText;
222 Q_EMIT subTextChanged();
223
224 if (!isValid() && s_dialog && s_dialog->owner() == this) {
225 s_dialog->setVisible(false);
226 }
227}
228
229int ToolTipArea::textFormat() const
230{
231 return m_textFormat;
232}
233
234void ToolTipArea::setTextFormat(int format)
235{
236 if (m_textFormat == format) {
237 return;
238 }
239
240 m_textFormat = format;
241 Q_EMIT textFormatChanged();
242}
243
245{
246 return m_location;
247}
248
249void ToolTipArea::setLocation(Plasma::Types::Location location)
250{
251 if (m_location == location) {
252 return;
253 }
254 m_location = location;
255 Q_EMIT locationChanged();
256}
257
258void ToolTipArea::setActive(bool active)
259{
260 if (m_active == active) {
261 return;
262 }
263
264 m_active = active;
265 if (!active) {
266 tooltipDialogInstance()->dismiss();
267 }
268 Q_EMIT activeChanged();
269}
270
271void ToolTipArea::setInteractive(bool interactive)
272{
273 if (m_interactive == interactive) {
274 return;
275 }
276
277 m_interactive = interactive;
278
279 Q_EMIT interactiveChanged();
280}
281
282void ToolTipArea::setTimeout(int timeout)
283{
284 m_timeout = timeout;
285}
286
288{
289 m_showTimer.stop();
290 tooltipDialogInstance()->dismiss();
291}
292
294{
295 m_showTimer.stop();
296 tooltipDialogInstance()->setVisible(false);
297}
298
300{
301 if (m_icon.isValid()) {
302 return m_icon;
303 } else {
304 return QString();
305 }
306}
307
308void ToolTipArea::setIcon(const QVariant &icon)
309{
310 if (icon == m_icon) {
311 return;
312 }
313
314 m_icon = icon;
315 Q_EMIT iconChanged();
316}
317
319{
320 if (m_image.isValid()) {
321 return m_image;
322 } else {
323 return QString();
324 }
325}
326
327void ToolTipArea::setImage(const QVariant &image)
328{
329 if (image == m_image) {
330 return;
331 }
332
333 m_image = image;
334 Q_EMIT imageChanged();
335}
336
338{
339 return m_containsMouse;
340}
341
342void ToolTipArea::setContainsMouse(bool contains)
343{
344 if (m_containsMouse != contains) {
345 m_containsMouse = contains;
346 Q_EMIT containsMouseChanged();
347 }
348 if (!contains && tooltipDialogInstance()->owner() == this) {
349 tooltipDialogInstance()->dismiss();
350 }
351}
352
354{
355 Q_UNUSED(event)
356 setContainsMouse(true);
357
358 if (!m_tooltipsEnabledGlobally) {
359 return;
360 }
361
362 if (!isValid()) {
363 return;
364 }
365
366 if (tooltipDialogInstance()->isVisible()) {
367 // We signal the tooltipmanager that we're "potentially interested,
368 // and ask to keep it open for a bit, so other items get the chance
369 // to update the content before the tooltip hides -- this avoids
370 // flickering
371 // It need to be considered only when other items can deal with tooltip area
372 if (m_active) {
373 tooltipDialogInstance()->keepalive();
374 // FIXME: showToolTip needs to be renamed in sync or something like that
375 showToolTip();
376 }
377 } else {
378 m_showTimer.start(m_interval);
379 }
380}
381
383{
384 Q_UNUSED(event)
385 setContainsMouse(false);
386 m_showTimer.stop();
387}
388
390{
391 if (event->type() == QEvent::MouseButtonPress) {
392 hideToolTip();
393 }
395}
396
397bool ToolTipArea::isValid() const
398{
399 return m_mainItem || !mainText().isEmpty() || !subText().isEmpty();
400}
401
402#include "moc_tooltiparea.cpp"
QString readEntry(const char *key, const char *aDefault=nullptr) const
void addFile(const QString &file)
static KDirWatch * self()
void dirty(const QString &path)
void created(const QString &path)
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:79
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:89
QString subText
The description of this tooltip.
Definition tooltiparea.h:69
void toolTipVisibleChanged(bool toolTipVisible)
Emitted when the tooltip's visibility changes.
QML_ELEMENTQQuickItem * mainItem
The item shown inside the tooltip.
Definition tooltiparea.h:59
QVariant image
TODO: single property for images? An image for this tooltip, accepted values are an icon name,...
QString mainText
The main text of this tooltip.
Definition tooltiparea.h:64
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:84
Plasma::Types::Location location
Plasma Location of the dialog window.
Definition tooltiparea.h:94
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)
T * data() const const
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
QString writableLocation(StandardLocation type)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
UniqueConnection
BottomEdge
AutoText
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void start()
void stop()
void timeout()
QVariant fromValue(T &&value)
bool isValid() const const
void setVisible(bool visible)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:09:36 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.