File indexing completed on 2024-04-28 04:37:27
0001 /* 0002 SPDX-FileCopyrightText: 2007 Hamish Rodda <rodda@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "statusbar.h" 0008 #include "progresswidget/statusbarprogresswidget.h" 0009 #include "progresswidget/progressmanager.h" 0010 #include "progresswidget/progressdialog.h" 0011 0012 #include <QTimer> 0013 0014 #include <KColorScheme> 0015 #include <KSqueezedTextLabel> 0016 0017 #include <interfaces/istatus.h> 0018 #include <interfaces/ilanguagecontroller.h> 0019 #include <language/backgroundparser/backgroundparser.h> 0020 0021 #include <sublime/view.h> 0022 0023 #include "plugincontroller.h" 0024 #include "core.h" 0025 0026 namespace KDevelop 0027 { 0028 0029 StatusBar::StatusBar(QWidget* parent) 0030 : QStatusBar(parent) 0031 , m_timer(new QTimer(this)) 0032 , m_currentView(nullptr) 0033 { 0034 #ifdef Q_OS_MAC 0035 /* At time of writing this is only required for OSX and only has effect on OSX. 0036 ifdef for robustness to future platform dependent theme/widget changes 0037 https://phabricator.kde.org/D656 0038 */ 0039 setStyleSheet(QStringLiteral("QStatusBar{background:transparent;}")); 0040 #endif 0041 0042 m_timer->setSingleShot(true); 0043 connect(m_timer, &QTimer::timeout, this, &StatusBar::slotTimeout); 0044 connect(Core::self()->pluginController(), &IPluginController::pluginLoaded, this, &StatusBar::pluginLoaded); 0045 const QList<IPlugin*> plugins = Core::self()->pluginControllerInternal()->allPluginsForExtension(QStringLiteral("IStatus")); 0046 0047 for (IPlugin* plugin : plugins) { 0048 registerStatus(plugin); 0049 } 0050 0051 registerStatus(Core::self()->languageController()->backgroundParser()); 0052 0053 m_progressController = Core::self()->progressController(); 0054 m_progressDialog = new ProgressDialog(this, parent); // construct this first, then progressWidget 0055 m_progressDialog->setVisible(false); 0056 m_progressWidget = new StatusbarProgressWidget(m_progressDialog, this); 0057 0058 addPermanentWidget(m_progressWidget, 0); 0059 } 0060 0061 StatusBar::~StatusBar() = default; 0062 0063 void StatusBar::removeError(QWidget* w) 0064 { 0065 removeWidget(w); 0066 w->deleteLater(); 0067 } 0068 0069 void StatusBar::viewChanged(Sublime::View* view) 0070 { 0071 if (m_currentView) 0072 m_currentView->disconnect(this); 0073 0074 m_currentView = view; 0075 0076 if (view) { 0077 connect(view, &Sublime::View::statusChanged, this, &StatusBar::viewStatusChanged); 0078 QStatusBar::showMessage(view->viewStatus(), 0); 0079 0080 } 0081 } 0082 0083 void StatusBar::viewStatusChanged(Sublime::View* view) 0084 { 0085 QStatusBar::showMessage(view->viewStatus(), 0); 0086 } 0087 0088 void StatusBar::pluginLoaded(IPlugin* plugin) 0089 { 0090 if (qobject_cast<IStatus*>(plugin)) 0091 registerStatus(plugin); 0092 } 0093 0094 void StatusBar::registerStatus(QObject* status) 0095 { 0096 Q_ASSERT(qobject_cast<IStatus*>(status)); 0097 // can't convert this to new signal slot syntax, IStatus is not a QObject 0098 connect(status, SIGNAL(clearMessage(KDevelop::IStatus*)), 0099 SLOT(clearMessage(KDevelop::IStatus*))); 0100 connect(status, SIGNAL(showMessage(KDevelop::IStatus*,QString,int)), 0101 SLOT(showMessage(KDevelop::IStatus*,QString,int))); 0102 connect(status, SIGNAL(hideProgress(KDevelop::IStatus*)), 0103 SLOT(hideProgress(KDevelop::IStatus*))); 0104 connect(status, SIGNAL(showProgress(KDevelop::IStatus*,int,int,int)), 0105 SLOT(showProgress(KDevelop::IStatus*,int,int,int))); 0106 connect(status, SIGNAL(showErrorMessage(QString,int)), 0107 SLOT(showErrorMessage(QString,int))); 0108 } 0109 0110 QWidget* errorMessage(QWidget* parent, const QString& text) 0111 { 0112 auto* label = new KSqueezedTextLabel(parent); 0113 KStatefulBrush red(KColorScheme::Window, KColorScheme::NegativeText); 0114 QPalette pal = label->palette(); 0115 pal.setBrush(QPalette::WindowText, red.brush(label->palette())); 0116 label->setPalette(pal); 0117 label->setAlignment(Qt::AlignRight); 0118 label->setText(text); 0119 label->setToolTip(text); 0120 return label; 0121 } 0122 0123 QTimer* StatusBar::errorTimeout(QWidget* error, int timeout) 0124 { 0125 auto* timer = new QTimer(error); 0126 timer->setSingleShot(true); 0127 timer->setInterval(1000*timeout); 0128 connect(timer, &QTimer::timeout, this, [this, error](){ removeError(error); }); 0129 return timer; 0130 } 0131 0132 void StatusBar::showErrorMessage(const QString& message, int timeout) 0133 { 0134 QWidget* error = errorMessage(this, message); 0135 QTimer* timer = errorTimeout(error, timeout); 0136 addWidget(error); 0137 timer->start(); // triggers removeError() 0138 } 0139 0140 void StatusBar::slotTimeout() 0141 { 0142 QMutableHashIterator<IStatus*, Message> it = m_messages; 0143 0144 while (it.hasNext()) { 0145 it.next(); 0146 if (it.value().timeout) { 0147 it.value().timeout -= m_timer->interval(); 0148 if (it.value().timeout == 0) 0149 it.remove(); 0150 } 0151 } 0152 0153 updateMessage(); 0154 } 0155 0156 void StatusBar::updateMessage() 0157 { 0158 if (m_timer->isActive()) { 0159 m_timer->stop(); 0160 m_timer->setInterval(m_time.elapsed()); 0161 slotTimeout(); 0162 } 0163 0164 int timeout = 0; 0165 0166 QStringList messages; 0167 messages.reserve(m_messages.size()); 0168 for (const Message& m : qAsConst(m_messages)) { 0169 messages.append(m.text); 0170 0171 if (timeout) 0172 timeout = qMin(timeout, m.timeout); 0173 else 0174 timeout = m.timeout; 0175 } 0176 0177 if (!messages.isEmpty()) 0178 QStatusBar::showMessage(messages.join(QLatin1String("; "))); 0179 else 0180 QStatusBar::clearMessage(); 0181 0182 if (timeout) { 0183 m_time.start(); 0184 m_timer->start(timeout); 0185 } 0186 } 0187 0188 void StatusBar::clearMessage( IStatus* status ) 0189 { 0190 QTimer::singleShot(0, this, [this, status]() { 0191 const auto messageIt = m_messages.find(status); 0192 if (messageIt != m_messages.end()) { 0193 m_messages.erase(messageIt); 0194 updateMessage(); 0195 } 0196 }); 0197 } 0198 0199 void StatusBar::showMessage( IStatus* status, const QString & message, int timeout) 0200 { 0201 QPointer<QObject> context = dynamic_cast<QObject*>(status); 0202 QTimer::singleShot(0, this, [this, context, status, message, timeout]() { 0203 if (!context) 0204 return; 0205 const auto progressItemIt = m_progressItems.constFind(status); 0206 if (progressItemIt != m_progressItems.constEnd()) { 0207 ProgressItem* i = *progressItemIt; 0208 i->setStatus(message); 0209 } else { 0210 Message m; 0211 m.text = message; 0212 m.timeout = timeout; 0213 m_messages.insert(status, m); 0214 updateMessage(); 0215 } 0216 }); 0217 } 0218 0219 void StatusBar::hideProgress( IStatus* status ) 0220 { 0221 QTimer::singleShot(0, this, [this, status]() { 0222 const auto progressItemIt = m_progressItems.find(status); 0223 if (progressItemIt != m_progressItems.end()) { 0224 (*progressItemIt)->setComplete(); 0225 m_progressItems.erase(progressItemIt); 0226 } 0227 }); 0228 } 0229 0230 void StatusBar::showProgress( IStatus* status, int minimum, int maximum, int value) 0231 { 0232 QPointer<QObject> context = dynamic_cast<QObject*>(status); 0233 QTimer::singleShot(0, this, [this, context, status, minimum, maximum, value]() { 0234 if (!context) 0235 return; 0236 auto progressItemIt = m_progressItems.find(status); 0237 if (progressItemIt == m_progressItems.end()) { 0238 bool canBeCanceled = false; 0239 progressItemIt = m_progressItems.insert(status, m_progressController->createProgressItem( 0240 ProgressManager::createUniqueID(), status->statusName(), QString(), canBeCanceled)); 0241 } 0242 0243 ProgressItem* i = *progressItemIt; 0244 m_progressWidget->raise(); 0245 m_progressDialog->raise(); 0246 if( minimum == 0 && maximum == 0 ) { 0247 i->setUsesBusyIndicator( true ); 0248 } else { 0249 i->setUsesBusyIndicator( false ); 0250 i->setProgress( 100*value/maximum ); 0251 } 0252 }); 0253 } 0254 0255 } 0256 0257 #include "moc_statusbar.cpp"