File indexing completed on 2024-05-12 05:46:36
0001 /*************************************************************************** 0002 * Copyright 2011 Marco Martin <mart@kde.org> * 0003 * Copyright 2011 Artur Duque de Souza <asouza@kde.org> * 0004 * Copyright 2013 Sebastian Kügler <sebas@kde.org> * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 * This program is distributed in the hope that it will be useful, * 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0014 * GNU General Public License for more details. * 0015 * * 0016 * You should have received a copy of the GNU General Public License * 0017 * along with this program; if not, write to the * 0018 * Free Software Foundation, Inc., * 0019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * 0020 ***************************************************************************/ 0021 0022 #include "tooltip.h" 0023 #include "tooltipdialog.h" 0024 0025 #include <QQmlEngine> 0026 #include <QQuickItem> 0027 #include <QDebug> 0028 0029 #include "framesvgitem.h" 0030 #include <kwindoweffects.h> 0031 #include <KDirWatch> 0032 0033 ToolTipDialog *ToolTip::s_dialog = nullptr; 0034 int ToolTip::s_dialogUsers = 0; 0035 0036 ToolTip::ToolTip(QQuickItem *parent) 0037 : QQuickItem(parent), 0038 m_tooltipsEnabledGlobally(false), 0039 m_containsMouse(false), 0040 m_location(Plasma::Types::Floating), 0041 m_textFormat(Qt::AutoText), 0042 m_active(true), 0043 m_interactive(false), 0044 m_usingDialog(false) 0045 { 0046 setAcceptHoverEvents(true); 0047 setFiltersChildMouseEvents(true); 0048 0049 m_showTimer = new QTimer(this); 0050 m_showTimer->setSingleShot(true); 0051 connect(m_showTimer, &QTimer::timeout, this, &ToolTip::showToolTip); 0052 0053 loadSettings(); 0054 0055 const QString configFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + QStringLiteral("/plasmarc"); 0056 KDirWatch::self()->addFile(configFile); 0057 QObject::connect(KDirWatch::self(), &KDirWatch::created, this, &ToolTip::settingsChanged); 0058 QObject::connect(KDirWatch::self(), &KDirWatch::dirty, this, &ToolTip::settingsChanged); 0059 } 0060 0061 ToolTip::~ToolTip() 0062 { 0063 if (s_dialog && s_dialog->owner() == this) { 0064 s_dialog->setVisible(false); 0065 } 0066 0067 if (m_usingDialog) { 0068 --s_dialogUsers; 0069 } 0070 0071 if (s_dialogUsers == 0) { 0072 delete s_dialog; 0073 s_dialog = nullptr; 0074 } 0075 } 0076 0077 void ToolTip::settingsChanged(const QString &file) 0078 { 0079 if (!file.endsWith(QLatin1String("plasmarc"))) { 0080 return; 0081 } 0082 0083 KSharedConfig::openConfig(QStringLiteral("plasmarc"))->reparseConfiguration(); 0084 loadSettings(); 0085 } 0086 0087 void ToolTip::loadSettings() 0088 { 0089 KConfigGroup cfg = KConfigGroup(KSharedConfig::openConfig(QStringLiteral("plasmarc")), "PlasmaToolTips"); 0090 m_interval = cfg.readEntry("Delay", 700); 0091 m_tooltipsEnabledGlobally = (m_interval > 0); 0092 } 0093 0094 QQuickItem *ToolTip::mainItem() const 0095 { 0096 return m_mainItem.data(); 0097 } 0098 0099 ToolTipDialog *ToolTip::tooltipDialogInstance() 0100 { 0101 if (!s_dialog) { 0102 s_dialog = new ToolTipDialog; 0103 s_dialogUsers = 1; 0104 } 0105 0106 if (!m_usingDialog) { 0107 s_dialogUsers++; 0108 m_usingDialog = true; 0109 } 0110 0111 return s_dialog; 0112 } 0113 0114 void ToolTip::setMainItem(QQuickItem *mainItem) 0115 { 0116 if (m_mainItem.data() != mainItem) { 0117 m_mainItem = mainItem; 0118 0119 emit mainItemChanged(); 0120 0121 if (!isValid() && s_dialog && s_dialog->owner() == this) { 0122 s_dialog->setVisible(false); 0123 } 0124 } 0125 } 0126 0127 void ToolTip::showToolTip() 0128 { 0129 if (!m_active) { 0130 return; 0131 } 0132 0133 emit aboutToShow(); 0134 0135 ToolTipDialog *dlg = tooltipDialogInstance(); 0136 0137 if (!mainItem()) { 0138 setMainItem(dlg->loadDefaultItem()); 0139 } 0140 0141 // Unset the dialog's old contents before reparenting the dialog. 0142 dlg->setMainItem(nullptr); 0143 0144 Plasma::Types::Location location = m_location; 0145 if (m_location == Plasma::Types::Floating) { 0146 QQuickItem *p = parentItem(); 0147 while (p) { 0148 if (p->property("location").isValid()) { 0149 location = (Plasma::Types::Location)p->property("location").toInt(); 0150 break; 0151 } 0152 p = p->parentItem(); 0153 } 0154 } 0155 0156 if (mainItem()) { 0157 mainItem()->setProperty("toolTip", QVariant::fromValue(this)); 0158 mainItem()->setVisible(true); 0159 } 0160 0161 dlg->setOwner(this); 0162 dlg->setLocation(location); 0163 dlg->setVisualParent(this); 0164 dlg->setMainItem(mainItem()); 0165 dlg->setInteractive(m_interactive); 0166 dlg->setVisible(true); 0167 } 0168 0169 QString ToolTip::mainText() const 0170 { 0171 return m_mainText; 0172 } 0173 0174 void ToolTip::setMainText(const QString &mainText) 0175 { 0176 if (mainText == m_mainText) { 0177 return; 0178 } 0179 0180 m_mainText = mainText; 0181 emit mainTextChanged(); 0182 0183 if (!isValid() && s_dialog && s_dialog->owner() == this) { 0184 s_dialog->setVisible(false); 0185 } 0186 } 0187 0188 QString ToolTip::subText() const 0189 { 0190 return m_subText; 0191 } 0192 0193 void ToolTip::setSubText(const QString &subText) 0194 { 0195 if (subText == m_subText) { 0196 return; 0197 } 0198 0199 m_subText = subText; 0200 emit subTextChanged(); 0201 0202 if (!isValid() && s_dialog && s_dialog->owner() == this) { 0203 s_dialog->setVisible(false); 0204 } 0205 } 0206 0207 int ToolTip::textFormat() const 0208 { 0209 return m_textFormat; 0210 } 0211 0212 void ToolTip::setTextFormat(int format) 0213 { 0214 if (m_textFormat == format) { 0215 return; 0216 } 0217 0218 m_textFormat = format; 0219 emit textFormatChanged(); 0220 } 0221 0222 Plasma::Types::Location ToolTip::location() const 0223 { 0224 return m_location; 0225 } 0226 0227 void ToolTip::setLocation(Plasma::Types::Location location) 0228 { 0229 if (m_location == location) { 0230 return; 0231 } 0232 m_location = location; 0233 emit locationChanged(); 0234 } 0235 0236 void ToolTip::setActive(bool active) 0237 { 0238 if (m_active == active) { 0239 return; 0240 } 0241 0242 m_active = active; 0243 if (!active) { 0244 tooltipDialogInstance()->dismiss(); 0245 } 0246 emit activeChanged(); 0247 } 0248 0249 void ToolTip::setInteractive(bool interactive) 0250 { 0251 if (m_interactive == interactive) { 0252 return; 0253 } 0254 0255 m_interactive = interactive; 0256 0257 emit interactiveChanged(); 0258 } 0259 0260 void ToolTip::hideToolTip() 0261 { 0262 m_showTimer->stop(); 0263 tooltipDialogInstance()->dismiss(); 0264 } 0265 0266 QVariant ToolTip::icon() const 0267 { 0268 if (m_icon.isValid()) { 0269 return m_icon; 0270 } else { 0271 return QString(); 0272 } 0273 } 0274 0275 void ToolTip::setIcon(const QVariant &icon) 0276 { 0277 if (icon == m_icon) { 0278 return; 0279 } 0280 0281 m_icon = icon; 0282 emit iconChanged(); 0283 } 0284 0285 QVariant ToolTip::image() const 0286 { 0287 if (m_image.isValid()) { 0288 return m_image; 0289 } else { 0290 return QString(); 0291 } 0292 } 0293 0294 void ToolTip::setImage(const QVariant &image) 0295 { 0296 if (image == m_image) { 0297 return; 0298 } 0299 0300 m_image = image; 0301 emit imageChanged(); 0302 } 0303 0304 bool ToolTip::containsMouse() const 0305 { 0306 return m_containsMouse; 0307 } 0308 0309 void ToolTip::setContainsMouse(bool contains) 0310 { 0311 if (m_containsMouse != contains) { 0312 m_containsMouse = contains; 0313 emit containsMouseChanged(); 0314 } 0315 if (!contains) { 0316 tooltipDialogInstance()->dismiss(); 0317 } 0318 } 0319 0320 void ToolTip::hoverEnterEvent(QHoverEvent *event) 0321 { 0322 Q_UNUSED(event) 0323 setContainsMouse(true); 0324 0325 if (!m_tooltipsEnabledGlobally) { 0326 return; 0327 } 0328 0329 if (!isValid()) { 0330 return; 0331 } 0332 0333 if (tooltipDialogInstance()->isVisible()) { 0334 // We signal the tooltipmanager that we're "potentially interested, 0335 // and ask to keep it open for a bit, so other items get the chance 0336 // to update the content before the tooltip hides -- this avoids 0337 // flickering 0338 // It need to be considered only when other items can deal with tooltip area 0339 if (m_active) { 0340 tooltipDialogInstance()->keepalive(); 0341 //FIXME: showToolTip needs to be renamed in sync or something like that 0342 showToolTip(); 0343 } 0344 } else { 0345 m_showTimer->start(m_interval); 0346 } 0347 } 0348 0349 void ToolTip::hoverLeaveEvent(QHoverEvent *event) 0350 { 0351 Q_UNUSED(event) 0352 setContainsMouse(false); 0353 m_showTimer->stop(); 0354 } 0355 0356 bool ToolTip::childMouseEventFilter(QQuickItem *item, QEvent *event) 0357 { 0358 if (event->type() == QEvent::MouseButtonPress) { 0359 hideToolTip(); 0360 } 0361 return QQuickItem::childMouseEventFilter(item, event); 0362 } 0363 0364 bool ToolTip::isValid() const 0365 { 0366 return m_mainItem || !mainText().isEmpty() || !subText().isEmpty(); 0367 }