]> cloud.milkyroute.net Git - dolphin.git/blob - src/views/tooltips/tooltipmanager.cpp
ToolTipManager: double the size of the preview and use dpr
[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(512, 512), &plugins);
139 job->setDevicePixelRatio(m_fileMetaDataWidget->devicePixelRatioF());
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, this, &ToolTipManager::setPreviewPix);
146 connect(job, &KIO::PreviewJob::failed, this, &ToolTipManager::previewFailed);
147 }
148
149 void ToolTipManager::setPreviewPix(const KFileItem &item, const QPixmap &pixmap)
150 {
151 if (!m_toolTipRequested || (m_item.url() != item.url())) {
152 // No tooltip is requested anymore or an old preview has been received
153 return;
154 }
155
156 if (pixmap.isNull()) {
157 previewFailed();
158 } else {
159 m_fileMetaDataWidget->setPreview(pixmap);
160 if (!m_showToolTipTimer->isActive()) {
161 showToolTip();
162 }
163 }
164 }
165
166 void ToolTipManager::previewFailed()
167 {
168 if (!m_toolTipRequested) {
169 return;
170 }
171 QPalette pal;
172 for (auto state : {QPalette::Active, QPalette::Inactive, QPalette::Disabled}) {
173 pal.setBrush(state, QPalette::WindowText, pal.toolTipText());
174 pal.setBrush(state, QPalette::Window, pal.toolTipBase());
175 }
176 iconLoader->self.setCustomPalette(pal);
177 const QPixmap pixmap = KDE::icon(m_item.iconName(), &iconLoader->self).pixmap(128, 128);
178 m_fileMetaDataWidget->setPreview(pixmap);
179 if (!m_showToolTipTimer->isActive()) {
180 showToolTip();
181 }
182 }
183
184 void ToolTipManager::slotMetaDataRequestFinished()
185 {
186 if (!m_toolTipRequested) {
187 return;
188 }
189
190 m_metaDataRequested = false;
191
192 if (!m_showToolTipTimer->isActive()) {
193 showToolTip();
194 }
195 }
196
197 void ToolTipManager::showToolTip()
198 {
199 Q_ASSERT(m_toolTipRequested);
200 if (m_appliedWaitCursor) {
201 QApplication::restoreOverrideCursor();
202 m_appliedWaitCursor = false;
203 }
204
205 if (m_fileMetaDataWidget->preview().isNull() || m_metaDataRequested) {
206 Q_ASSERT(!m_appliedWaitCursor);
207 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
208 m_appliedWaitCursor = true;
209 return;
210 }
211
212 // Adjust the size to get a proper sizeHint()
213 m_fileMetaDataWidget->adjustSize();
214 if (!m_tooltipWidget) {
215 m_tooltipWidget.reset(new KToolTipWidget());
216 }
217 m_tooltipWidget->showBelow(m_itemRect, m_fileMetaDataWidget, m_transientParent);
218 // At this point KToolTipWidget adopted our parent-less metadata widget.
219 m_fileMetaDatWidgetOwnershipTransferred = true;
220
221 m_toolTipRequested = false;
222 }
223
224 #include "moc_tooltipmanager.cpp"