2 * SPDX-FileCopyrightText: 2008 Konstantin Heil <konst.heil@stud.uni-heidelberg.de>
4 * SPDX-License-Identifier: GPL-2.0-or-later
7 #include "tooltipmanager.h"
9 #include "dolphinfilemetadatawidget.h"
11 #include <KIO/JobUiDelegate>
12 #include <KIO/PreviewJob>
13 #include <KConfigGroup>
14 #include <KJobWidgets>
15 #include <KSharedConfig>
16 #include <KToolTipWidget>
17 #include <KIconLoader>
19 #include <QApplication>
26 class IconLoaderSingleton
{
28 IconLoaderSingleton() = default;
33 Q_GLOBAL_STATIC(IconLoaderSingleton
, iconLoader
)
35 ToolTipManager::ToolTipManager(QWidget
* 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),
48 m_margin
= qMax(m_margin
, parent
->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth
));
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
));
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
);
61 Q_ASSERT(m_contentRetrievalTimer
->interval() < m_showToolTipTimer
->interval());
64 ToolTipManager::~ToolTipManager()
66 if (!m_fileMetaDatWidgetOwnershipTransferred
) {
67 delete m_fileMetaDataWidget
;
71 void ToolTipManager::showToolTip(const KFileItem
& item
, const QRectF
& itemRect
, QWindow
*transientParent
)
73 hideToolTip(HideBehavior::Instantly
);
75 m_itemRect
= itemRect
.toRect();
77 m_itemRect
.adjust(-m_margin
, -m_margin
, m_margin
, m_margin
);
80 m_transientParent
= transientParent
;
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
);
91 m_contentRetrievalTimer
->start();
92 m_showToolTipTimer
->start();
93 m_toolTipRequested
= true;
94 Q_ASSERT(!m_metaDataRequested
);
97 void ToolTipManager::hideToolTip(const HideBehavior behavior
)
99 if (m_appliedWaitCursor
) {
100 QApplication::restoreOverrideCursor();
101 m_appliedWaitCursor
= false;
104 m_toolTipRequested
= false;
105 m_metaDataRequested
= false;
106 m_showToolTipTimer
->stop();
107 m_contentRetrievalTimer
->stop();
108 if (m_tooltipWidget
) {
110 case HideBehavior::Instantly
:
111 m_tooltipWidget
->hide();
113 case HideBehavior::Later
:
114 m_tooltipWidget
->hideLater();
120 void ToolTipManager::startContentRetrieval()
122 if (!m_toolTipRequested
) {
126 m_fileMetaDataWidget
->setName(m_item
.text());
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();
135 // Request a preview of the item
136 m_fileMetaDataWidget
->setPreview(QPixmap());
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
,
143 job
->setIgnoreMaximumSize(m_item
.isLocalFile() && !m_item
.isSlow());
144 if (job
->uiDelegate()) {
145 KJobWidgets::setWindow(job
, qApp
->activeWindow());
148 connect(job
, &KIO::PreviewJob::gotPreview
,
149 this, &ToolTipManager::setPreviewPix
);
150 connect(job
, &KIO::PreviewJob::failed
,
151 this, &ToolTipManager::previewFailed
);
155 void ToolTipManager::setPreviewPix(const KFileItem
& item
,
156 const QPixmap
& pixmap
)
158 if (!m_toolTipRequested
|| (m_item
.url() != item
.url())) {
159 // No tooltip is requested anymore or an old preview has been received
163 if (pixmap
.isNull()) {
166 m_fileMetaDataWidget
->setPreview(pixmap
);
167 if (!m_showToolTipTimer
->isActive()) {
173 void ToolTipManager::previewFailed()
175 if (!m_toolTipRequested
) {
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());
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()) {
191 void ToolTipManager::slotMetaDataRequestFinished()
193 if (!m_toolTipRequested
) {
197 m_metaDataRequested
= false;
199 if (!m_showToolTipTimer
->isActive()) {
204 void ToolTipManager::showToolTip()
206 Q_ASSERT(m_toolTipRequested
);
207 if (m_appliedWaitCursor
) {
208 QApplication::restoreOverrideCursor();
209 m_appliedWaitCursor
= false;
212 if (m_fileMetaDataWidget
->preview().isNull() || m_metaDataRequested
) {
213 Q_ASSERT(!m_appliedWaitCursor
);
214 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor
));
215 m_appliedWaitCursor
= true;
219 // Adjust the size to get a proper sizeHint()
220 m_fileMetaDataWidget
->adjustSize();
221 if (!m_tooltipWidget
) {
222 m_tooltipWidget
.reset(new KToolTipWidget());
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;
228 m_toolTipRequested
= false;