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