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