Warning, file /plasma/systemsettings/app/ToolTips/tooltipmanager.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 "MenuItem.h" 0010 0011 #include <QAbstractItemView> 0012 #include <QApplication> 0013 #include <QGridLayout> 0014 #include <QLabel> 0015 #include <QRect> 0016 #include <QScrollBar> 0017 #include <QStyle> 0018 #include <QTimer> 0019 0020 #include <KIconLoader> 0021 #include <KLocalizedString> 0022 #include <KToolTipWidget> 0023 0024 class IconLoaderSingleton 0025 { 0026 public: 0027 IconLoaderSingleton() = default; 0028 0029 KIconLoader self; 0030 }; 0031 0032 Q_GLOBAL_STATIC(IconLoaderSingleton, privateIconLoaderSelf) 0033 0034 class ToolTipManager::Private 0035 { 0036 public: 0037 Private() 0038 : tooltip(nullptr) 0039 , view(nullptr) 0040 , timer(nullptr) 0041 , delay(QApplication::style()->styleHint(QStyle::SH_ToolTip_WakeUpDelay)) 0042 { 0043 } 0044 0045 KToolTipWidget *tooltip = nullptr; 0046 QAbstractItemView *view = nullptr; 0047 QTimer *timer = nullptr; 0048 QModelIndex item; 0049 QRect itemRect; 0050 int delay; 0051 }; 0052 0053 ToolTipManager::ToolTipManager(QAbstractItemView *parent) 0054 : QObject(parent) 0055 , d(new ToolTipManager::Private) 0056 { 0057 d->view = parent; 0058 d->tooltip = new KToolTipWidget(d->view); 0059 d->tooltip->setHideDelay(0); 0060 0061 connect(parent, &QAbstractItemView::viewportEntered, this, &ToolTipManager::hideToolTip); 0062 connect(parent, &QAbstractItemView::entered, this, &ToolTipManager::requestToolTip); 0063 0064 d->timer = new QTimer(this); 0065 d->timer->setSingleShot(true); 0066 connect(d->timer, &QTimer::timeout, this, &ToolTipManager::prepareToolTip); 0067 0068 // When the mousewheel is used, the items don't get a hovered indication 0069 // (Qt-issue #200665). To assure that the tooltip still gets hidden, 0070 // the scrollbars are observed. 0071 connect(parent->horizontalScrollBar(), &QAbstractSlider::valueChanged, this, &ToolTipManager::hideToolTip); 0072 connect(parent->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &ToolTipManager::hideToolTip); 0073 0074 d->view->viewport()->installEventFilter(this); 0075 } 0076 0077 ToolTipManager::~ToolTipManager() 0078 { 0079 delete d; 0080 } 0081 0082 bool ToolTipManager::eventFilter(QObject *watched, QEvent *event) 0083 { 0084 if (watched == d->view->viewport()) { 0085 switch (event->type()) { 0086 case QEvent::Leave: 0087 case QEvent::MouseButtonPress: 0088 hideToolTip(); 0089 break; 0090 default: 0091 break; 0092 } 0093 } 0094 0095 return QObject::eventFilter(watched, event); 0096 } 0097 0098 void ToolTipManager::requestToolTip(const QModelIndex &index) 0099 { 0100 // only request a tooltip for the name column and when no selection or 0101 // drag & drop operation is done (indicated by the left mouse button) 0102 if (!(QApplication::mouseButtons() & Qt::LeftButton)) { 0103 d->tooltip->hide(); 0104 0105 d->itemRect = d->view->visualRect(index); 0106 const QPoint pos = d->view->viewport()->mapToGlobal(d->itemRect.topLeft()); 0107 d->itemRect.moveTo(pos); 0108 d->item = index; 0109 d->timer->start(d->delay); 0110 } else { 0111 hideToolTip(); 0112 } 0113 } 0114 0115 void ToolTipManager::hideToolTip() 0116 { 0117 d->timer->stop(); 0118 d->tooltip->hideLater(); 0119 } 0120 0121 void ToolTipManager::prepareToolTip() 0122 { 0123 showToolTip(d->item); 0124 } 0125 0126 void ToolTipManager::showToolTip(const QModelIndex &menuItem) 0127 { 0128 if (QApplication::mouseButtons() & Qt::LeftButton) { 0129 return; 0130 } 0131 0132 QWidget *tip = createTipContent(menuItem); 0133 0134 d->tooltip->showBelow(d->itemRect, tip, d->view->nativeParentWidget()->windowHandle()); 0135 0136 connect(d->tooltip, &KToolTipWidget::hidden, tip, &QObject::deleteLater); 0137 } 0138 0139 QWidget *ToolTipManager::createTipContent(QModelIndex item) 0140 { 0141 auto loader = KIconLoader::global(); 0142 const QSize dialogIconSize = QSize(loader->currentSize(KIconLoader::Dialog), loader->currentSize(KIconLoader::Dialog)); 0143 const QSize toolbarIconSize = QSize(loader->currentSize(KIconLoader::MainToolbar), loader->currentSize(KIconLoader::MainToolbar)); 0144 0145 auto tipContent = new QWidget(); 0146 auto tipLayout = new QGridLayout(); 0147 tipLayout->setAlignment(Qt::AlignLeft); 0148 0149 QLayout *primaryLine = generateToolTipLine(&item, tipContent, dialogIconSize, true); 0150 primaryLine->setAlignment(Qt::AlignLeft); 0151 tipLayout->addLayout(primaryLine, 0, 0, Qt::AlignLeft); 0152 0153 for (int done = 0; d->view->model()->rowCount(item) > done; done = 1 + done) { 0154 QModelIndex childItem = d->view->model()->index(done, 0, item); 0155 QLayout *subLine = generateToolTipLine(&childItem, tipContent, toolbarIconSize, false); 0156 subLine->setAlignment(Qt::AlignLeft); 0157 tipLayout->addLayout(subLine, done + 2, 0, Qt::AlignLeft); 0158 } 0159 0160 tipLayout->setVerticalSpacing(tipContent->fontMetrics().height() / 3); 0161 tipContent->setLayout(tipLayout); 0162 0163 if (d->view->model()->rowCount(item) > 0) { 0164 auto separatorLine = new QFrame(tipContent); 0165 separatorLine->setFrameStyle(QFrame::HLine); 0166 tipLayout->addWidget(separatorLine, 1, 0); 0167 } 0168 0169 return tipContent; 0170 } 0171 0172 QLayout *ToolTipManager::generateToolTipLine(QModelIndex *item, QWidget *toolTip, QSize iconSize, bool comment) 0173 { 0174 // Get MenuItem 0175 auto menuItem = d->view->model()->data(*item, Qt::UserRole).value<MenuItem *>(); 0176 0177 QString text = menuItem->name(); 0178 if (comment) { 0179 text = QStringLiteral("<b>%1</b>").arg(menuItem->name()); 0180 0181 // Generate text 0182 text += QStringLiteral("<br />"); 0183 if (!menuItem->comment().isEmpty()) { 0184 text += menuItem->comment(); 0185 } else { 0186 int childCount = d->view->model()->rowCount(*item); 0187 text += i18np("Contains 1 item", "Contains %1 items", childCount); 0188 } 0189 } 0190 auto textLabel = new QLabel(toolTip); 0191 textLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0192 textLabel->setForegroundRole(QPalette::ToolTipText); 0193 textLabel->setText(text); 0194 0195 // Get icon 0196 QPalette pal = textLabel->palette(); 0197 for (auto state : {QPalette::Active, QPalette::Inactive, QPalette::Disabled}) { 0198 pal.setBrush(state, QPalette::WindowText, pal.toolTipText()); 0199 pal.setBrush(state, QPalette::Window, pal.toolTipBase()); 0200 } 0201 0202 privateIconLoaderSelf->self.setCustomPalette(pal); 0203 0204 QIcon icon = KDE::icon(menuItem->iconName(), &privateIconLoaderSelf->self); 0205 auto iconLabel = new QLabel(toolTip); 0206 iconLabel->setPixmap(icon.pixmap(iconSize)); 0207 iconLabel->setMaximumSize(iconSize); 0208 0209 // Generate layout 0210 auto layout = new QHBoxLayout(); 0211 layout->setSpacing(textLabel->fontMetrics().height() / 3); 0212 layout->setAlignment(Qt::AlignLeft); 0213 layout->addWidget(iconLabel, Qt::AlignLeft); 0214 layout->addWidget(textLabel, Qt::AlignLeft); 0215 0216 return layout; 0217 } 0218 0219 #include "moc_tooltipmanager.cpp"