File indexing completed on 2024-05-12 05:47:52
0001 /* 0002 * SPDX-FileCopyrightText: 2008 Konstantin Heil <konst.heil@stud.uni-heidelberg.de> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "tooltipmanager.h" 0008 0009 #include "dolphinfilemetadatawidget.h" 0010 0011 #include <KConfigGroup> 0012 #include <KIO/PreviewJob> 0013 #include <KIconLoader> 0014 #include <KJobWidgets> 0015 #include <KSharedConfig> 0016 #include <KToolTipWidget> 0017 0018 #include <QApplication> 0019 #include <QStyle> 0020 #include <QTimer> 0021 #include <QWindow> 0022 0023 class IconLoaderSingleton 0024 { 0025 public: 0026 IconLoaderSingleton() = default; 0027 0028 KIconLoader self; 0029 }; 0030 0031 Q_GLOBAL_STATIC(IconLoaderSingleton, iconLoader) 0032 0033 ToolTipManager::ToolTipManager(QWidget *parent) 0034 : QObject(parent) 0035 , m_showToolTipTimer(nullptr) 0036 , m_contentRetrievalTimer(nullptr) 0037 , m_transientParent(nullptr) 0038 , m_toolTipRequested(false) 0039 , m_metaDataRequested(false) 0040 , m_appliedWaitCursor(false) 0041 , m_margin(4) 0042 , m_item() 0043 , m_itemRect() 0044 { 0045 if (parent) { 0046 m_margin = qMax(m_margin, parent->style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth)); 0047 } 0048 0049 m_showToolTipTimer = new QTimer(this); 0050 m_showToolTipTimer->setSingleShot(true); 0051 m_showToolTipTimer->setInterval(500); 0052 connect(m_showToolTipTimer, &QTimer::timeout, this, QOverload<>::of(&ToolTipManager::showToolTip)); 0053 0054 m_contentRetrievalTimer = new QTimer(this); 0055 m_contentRetrievalTimer->setSingleShot(true); 0056 m_contentRetrievalTimer->setInterval(200); 0057 connect(m_contentRetrievalTimer, &QTimer::timeout, this, &ToolTipManager::startContentRetrieval); 0058 0059 Q_ASSERT(m_contentRetrievalTimer->interval() < m_showToolTipTimer->interval()); 0060 } 0061 0062 ToolTipManager::~ToolTipManager() 0063 { 0064 if (!m_fileMetaDatWidgetOwnershipTransferred) { 0065 delete m_fileMetaDataWidget; 0066 } 0067 } 0068 0069 void ToolTipManager::showToolTip(const KFileItem &item, const QRectF &itemRect, QWindow *transientParent) 0070 { 0071 hideToolTip(HideBehavior::Instantly); 0072 0073 m_itemRect = itemRect.toRect(); 0074 0075 m_itemRect.adjust(-m_margin, -m_margin, m_margin, m_margin); 0076 m_item = item; 0077 0078 m_transientParent = transientParent; 0079 0080 // Only start the retrieving of the content, when the mouse has been over this 0081 // item for 200 milliseconds. This prevents a lot of useless preview jobs and 0082 // meta data retrieval, when passing rapidly over a lot of items. 0083 if (!m_fileMetaDataWidget) { 0084 m_fileMetaDataWidget = new DolphinFileMetaDataWidget(); 0085 connect(m_fileMetaDataWidget, &DolphinFileMetaDataWidget::metaDataRequestFinished, this, &ToolTipManager::slotMetaDataRequestFinished); 0086 connect(m_fileMetaDataWidget, &DolphinFileMetaDataWidget::urlActivated, this, &ToolTipManager::urlActivated); 0087 } 0088 0089 m_contentRetrievalTimer->start(); 0090 m_showToolTipTimer->start(); 0091 m_toolTipRequested = true; 0092 Q_ASSERT(!m_metaDataRequested); 0093 } 0094 0095 void ToolTipManager::hideToolTip(const HideBehavior behavior) 0096 { 0097 if (m_appliedWaitCursor) { 0098 QApplication::restoreOverrideCursor(); 0099 m_appliedWaitCursor = false; 0100 } 0101 0102 m_toolTipRequested = false; 0103 m_metaDataRequested = false; 0104 m_showToolTipTimer->stop(); 0105 m_contentRetrievalTimer->stop(); 0106 if (m_tooltipWidget) { 0107 switch (behavior) { 0108 case HideBehavior::Instantly: 0109 m_tooltipWidget->hide(); 0110 break; 0111 case HideBehavior::Later: 0112 m_tooltipWidget->hideLater(); 0113 break; 0114 } 0115 } 0116 } 0117 0118 void ToolTipManager::startContentRetrieval() 0119 { 0120 if (!m_toolTipRequested) { 0121 return; 0122 } 0123 0124 m_fileMetaDataWidget->setName(m_item.text()); 0125 0126 // Request the retrieval of meta-data. The slot 0127 // slotMetaDataRequestFinished() is invoked after the 0128 // meta-data have been received. 0129 m_metaDataRequested = true; 0130 m_fileMetaDataWidget->setItems(KFileItemList() << m_item); 0131 m_fileMetaDataWidget->adjustSize(); 0132 0133 // Request a preview of the item 0134 m_fileMetaDataWidget->setPreview(QPixmap()); 0135 0136 const KConfigGroup globalConfig(KSharedConfig::openConfig(), QLatin1String("PreviewSettings")); 0137 const QStringList plugins = globalConfig.readEntry("Plugins", KIO::PreviewJob::defaultPlugins()); 0138 KIO::PreviewJob *job = new KIO::PreviewJob(KFileItemList() << m_item, QSize(256, 256), &plugins); 0139 job->setIgnoreMaximumSize(m_item.isLocalFile() && !m_item.isSlow()); 0140 if (job->uiDelegate()) { 0141 KJobWidgets::setWindow(job, qApp->activeWindow()); 0142 } 0143 0144 connect(job, &KIO::PreviewJob::gotPreview, this, &ToolTipManager::setPreviewPix); 0145 connect(job, &KIO::PreviewJob::failed, this, &ToolTipManager::previewFailed); 0146 } 0147 0148 void ToolTipManager::setPreviewPix(const KFileItem &item, const QPixmap &pixmap) 0149 { 0150 if (!m_toolTipRequested || (m_item.url() != item.url())) { 0151 // No tooltip is requested anymore or an old preview has been received 0152 return; 0153 } 0154 0155 if (pixmap.isNull()) { 0156 previewFailed(); 0157 } else { 0158 m_fileMetaDataWidget->setPreview(pixmap); 0159 if (!m_showToolTipTimer->isActive()) { 0160 showToolTip(); 0161 } 0162 } 0163 } 0164 0165 void ToolTipManager::previewFailed() 0166 { 0167 if (!m_toolTipRequested) { 0168 return; 0169 } 0170 QPalette pal; 0171 for (auto state : {QPalette::Active, QPalette::Inactive, QPalette::Disabled}) { 0172 pal.setBrush(state, QPalette::WindowText, pal.toolTipText()); 0173 pal.setBrush(state, QPalette::Window, pal.toolTipBase()); 0174 } 0175 iconLoader->self.setCustomPalette(pal); 0176 const QPixmap pixmap = KDE::icon(m_item.iconName(), &iconLoader->self).pixmap(128, 128); 0177 m_fileMetaDataWidget->setPreview(pixmap); 0178 if (!m_showToolTipTimer->isActive()) { 0179 showToolTip(); 0180 } 0181 } 0182 0183 void ToolTipManager::slotMetaDataRequestFinished() 0184 { 0185 if (!m_toolTipRequested) { 0186 return; 0187 } 0188 0189 m_metaDataRequested = false; 0190 0191 if (!m_showToolTipTimer->isActive()) { 0192 showToolTip(); 0193 } 0194 } 0195 0196 void ToolTipManager::showToolTip() 0197 { 0198 Q_ASSERT(m_toolTipRequested); 0199 if (m_appliedWaitCursor) { 0200 QApplication::restoreOverrideCursor(); 0201 m_appliedWaitCursor = false; 0202 } 0203 0204 if (m_fileMetaDataWidget->preview().isNull() || m_metaDataRequested) { 0205 Q_ASSERT(!m_appliedWaitCursor); 0206 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); 0207 m_appliedWaitCursor = true; 0208 return; 0209 } 0210 0211 // Adjust the size to get a proper sizeHint() 0212 m_fileMetaDataWidget->adjustSize(); 0213 if (!m_tooltipWidget) { 0214 m_tooltipWidget.reset(new KToolTipWidget()); 0215 } 0216 m_tooltipWidget->showBelow(m_itemRect, m_fileMetaDataWidget, m_transientParent); 0217 // At this point KToolTipWidget adopted our parent-less metadata widget. 0218 m_fileMetaDatWidgetOwnershipTransferred = true; 0219 0220 m_toolTipRequested = false; 0221 } 0222 0223 #include "moc_tooltipmanager.cpp"