]> cloud.milkyroute.net Git - dolphin.git/blob - src/views/tooltips/tooltipmanager.cpp
5a40d1023cebbf184539b7dd0ef8ca0a643738c5
[dolphin.git] / src / views / tooltips / tooltipmanager.cpp
1 /*
2 * SPDX-FileCopyrightText: 2008 Konstantin Heil <konst.heil@stud.uni-heidelberg.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "tooltipmanager.h"
8
9 #include "dolphinfilemetadatawidget.h"
10
11 #include <KIO/PreviewJob>
12 #include <KConfigGroup>
13 #include <KJobWidgets>
14 #include <KSharedConfig>
15 #include <KToolTipWidget>
16 #include <KIconLoader>
17
18 #include <QApplication>
19 #include <QStyle>
20 #include <QTimer>
21 #include <QWindow>
22
23 class IconLoaderSingleton {
24 public:
25 IconLoaderSingleton() = default;
26
27 KIconLoader self;
28 };
29
30 Q_GLOBAL_STATIC(IconLoaderSingleton, iconLoader)
31
32 ToolTipManager::ToolTipManager(QWidget* parent) :
33 QObject(parent),
34 m_showToolTipTimer(nullptr),
35 m_contentRetrievalTimer(nullptr),
36 m_transientParent(nullptr),
37 m_toolTipRequested(false),
38 m_metaDataRequested(false),
39 m_appliedWaitCursor(false),
40 m_margin(4),
41 m_item(),
42 m_itemRect()
43 {
44 if (parent) {
45 m_margin = qMax(m_margin, parent->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth));
46 }
47
48 m_showToolTipTimer = new QTimer(this);
49 m_showToolTipTimer->setSingleShot(true);
50 m_showToolTipTimer->setInterval(500);
51 connect(m_showToolTipTimer, &QTimer::timeout, this, QOverload<>::of(&ToolTipManager::showToolTip));
52
53 m_contentRetrievalTimer = new QTimer(this);
54 m_contentRetrievalTimer->setSingleShot(true);
55 m_contentRetrievalTimer->setInterval(200);
56 connect(m_contentRetrievalTimer, &QTimer::timeout, this, &ToolTipManager::startContentRetrieval);
57
58 Q_ASSERT(m_contentRetrievalTimer->interval() < m_showToolTipTimer->interval());
59 }
60
61 ToolTipManager::~ToolTipManager()
62 {
63 if (!m_fileMetaDatWidgetOwnershipTransferred) {
64 delete m_fileMetaDataWidget;
65 }
66 }
67
68 void ToolTipManager::showToolTip(const KFileItem& item, const QRectF& itemRect, QWindow *transientParent)
69 {
70 hideToolTip(HideBehavior::Instantly);
71
72 m_itemRect = itemRect.toRect();
73
74 m_itemRect.adjust(-m_margin, -m_margin, m_margin, m_margin);
75 m_item = item;
76
77 m_transientParent = transientParent;
78
79 // Only start the retrieving of the content, when the mouse has been over this
80 // item for 200 milliseconds. This prevents a lot of useless preview jobs and
81 // meta data retrieval, when passing rapidly over a lot of items.
82 if (!m_fileMetaDataWidget) {
83 m_fileMetaDataWidget = new DolphinFileMetaDataWidget();
84 connect(m_fileMetaDataWidget, &DolphinFileMetaDataWidget::metaDataRequestFinished, this, &ToolTipManager::slotMetaDataRequestFinished);
85 connect(m_fileMetaDataWidget, &DolphinFileMetaDataWidget::urlActivated, this, &ToolTipManager::urlActivated);
86 }
87
88 m_contentRetrievalTimer->start();
89 m_showToolTipTimer->start();
90 m_toolTipRequested = true;
91 Q_ASSERT(!m_metaDataRequested);
92 }
93
94 void ToolTipManager::hideToolTip(const HideBehavior behavior)
95 {
96 if (m_appliedWaitCursor) {
97 QApplication::restoreOverrideCursor();
98 m_appliedWaitCursor = false;
99 }
100
101 m_toolTipRequested = false;
102 m_metaDataRequested = false;
103 m_showToolTipTimer->stop();
104 m_contentRetrievalTimer->stop();
105 if (m_tooltipWidget) {
106 switch (behavior) {
107 case HideBehavior::Instantly:
108 m_tooltipWidget->hide();
109 break;
110 case HideBehavior::Later:
111 m_tooltipWidget->hideLater();
112 break;
113 }
114 }
115 }
116
117 void ToolTipManager::startContentRetrieval()
118 {
119 if (!m_toolTipRequested) {
120 return;
121 }
122
123 m_fileMetaDataWidget->setName(m_item.text());
124
125 // Request the retrieval of meta-data. The slot
126 // slotMetaDataRequestFinished() is invoked after the
127 // meta-data have been received.
128 m_metaDataRequested = true;
129 m_fileMetaDataWidget->setItems(KFileItemList() << m_item);
130 m_fileMetaDataWidget->adjustSize();
131
132 // Request a preview of the item
133 m_fileMetaDataWidget->setPreview(QPixmap());
134
135 const KConfigGroup globalConfig(KSharedConfig::openConfig(), "PreviewSettings");
136 const QStringList plugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins());
137 KIO::PreviewJob* job = new KIO::PreviewJob(KFileItemList() << m_item,
138 QSize(256, 256),
139 &plugins);
140 job->setIgnoreMaximumSize(m_item.isLocalFile() && !m_item.isSlow());
141 if (job->uiDelegate()) {
142 KJobWidgets::setWindow(job, qApp->activeWindow());
143 }
144
145 connect(job, &KIO::PreviewJob::gotPreview,
146 this, &ToolTipManager::setPreviewPix);
147 connect(job, &KIO::PreviewJob::failed,
148 this, &ToolTipManager::previewFailed);
149 }
150
151
152 void ToolTipManager::setPreviewPix(const KFileItem& item,
153 const QPixmap& pixmap)
154 {
155 if (!m_toolTipRequested || (m_item.url() != item.url())) {
156 // No tooltip is requested anymore or an old preview has been received
157 return;
158 }
159
160 if (pixmap.isNull()) {
161 previewFailed();
162 } else {
163 m_fileMetaDataWidget->setPreview(pixmap);
164 if (!m_showToolTipTimer->isActive()) {
165 showToolTip();
166 }
167 }
168 }
169
170 void ToolTipManager::previewFailed()
171 {
172 if (!m_toolTipRequested) {
173 return;
174 }
175 QPalette pal;
176 for (auto state : { QPalette::Active, QPalette::Inactive, QPalette::Disabled }) {
177 pal.setBrush(state, QPalette::WindowText, pal.toolTipText());
178 pal.setBrush(state, QPalette::Window, pal.toolTipBase());
179 }
180 iconLoader->self.setCustomPalette(pal);
181 const QPixmap pixmap = KDE::icon(m_item.iconName(), &iconLoader->self).pixmap(128, 128);
182 m_fileMetaDataWidget->setPreview(pixmap);
183 if (!m_showToolTipTimer->isActive()) {
184 showToolTip();
185 }
186 }
187
188 void ToolTipManager::slotMetaDataRequestFinished()
189 {
190 if (!m_toolTipRequested) {
191 return;
192 }
193
194 m_metaDataRequested = false;
195
196 if (!m_showToolTipTimer->isActive()) {
197 showToolTip();
198 }
199 }
200
201 void ToolTipManager::showToolTip()
202 {
203 Q_ASSERT(m_toolTipRequested);
204 if (m_appliedWaitCursor) {
205 QApplication::restoreOverrideCursor();
206 m_appliedWaitCursor = false;
207 }
208
209 if (m_fileMetaDataWidget->preview().isNull() || m_metaDataRequested) {
210 Q_ASSERT(!m_appliedWaitCursor);
211 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
212 m_appliedWaitCursor = true;
213 return;
214 }
215
216 // Adjust the size to get a proper sizeHint()
217 m_fileMetaDataWidget->adjustSize();
218 if (!m_tooltipWidget) {
219 m_tooltipWidget.reset(new KToolTipWidget());
220 }
221 m_tooltipWidget->showBelow(m_itemRect, m_fileMetaDataWidget, m_transientParent);
222 // At this point KToolTipWidget adopted our parent-less metadata widget.
223 m_fileMetaDatWidgetOwnershipTransferred = true;
224
225 m_toolTipRequested = false;
226 }
227