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