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