File indexing completed on 2024-05-05 16:46:55
0001 /* 0002 SPDX-FileCopyrightText: 2006-2007 Andreas Pakulat <apaku@gmx.de> 0003 SPDX-FileCopyrightText: 2007 Dukju Ahn <dukjuahn@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "standardoutputview.h" 0009 #include "outputwidget.h" 0010 #include "toolviewdata.h" 0011 #include "debug.h" 0012 0013 #include <QAbstractItemDelegate> 0014 #include <QAbstractItemModel> 0015 #include <QAction> 0016 #include <QList> 0017 0018 #include <KLocalizedString> 0019 0020 #include <interfaces/icore.h> 0021 #include <interfaces/iuicontroller.h> 0022 0023 #include <sublime/view.h> 0024 #include <sublime/area.h> 0025 #include <sublime/controller.h> 0026 #include <sublime/document.h> 0027 0028 class OutputViewFactory : public KDevelop::IToolViewFactory{ 0029 public: 0030 explicit OutputViewFactory(const ToolViewData* data): m_data(data) {} 0031 QWidget* create(QWidget *parent = nullptr) override 0032 { 0033 return new OutputWidget( parent, m_data ); 0034 } 0035 Qt::DockWidgetArea defaultPosition() const override 0036 { 0037 return Qt::BottomDockWidgetArea; 0038 } 0039 void viewCreated( Sublime::View* view ) override 0040 { 0041 m_data->views << view; 0042 } 0043 QString id() const override 0044 { 0045 //NOTE: id must be unique, see e.g. https://bugs.kde.org/show_bug.cgi?id=287093 0046 return QStringLiteral("org.kdevelop.OutputView.%1").arg(m_data->toolViewId); 0047 } 0048 private: 0049 const ToolViewData *m_data; 0050 }; 0051 0052 StandardOutputView::StandardOutputView(QObject *parent, const QVariantList &) 0053 : KDevelop::IPlugin(QStringLiteral("kdevstandardoutputview"), parent) 0054 { 0055 connect(KDevelop::ICore::self()->uiController()->controller(), &Sublime::Controller::aboutToRemoveView, 0056 this, &StandardOutputView::removeSublimeView); 0057 0058 } 0059 0060 void StandardOutputView::removeSublimeView( Sublime::View* v ) 0061 { 0062 auto it = m_toolViews.begin(); 0063 while (it != m_toolViews.end()) { 0064 ToolViewData* d = it.value(); 0065 bool isErased = false; 0066 if( d->views.contains(v) ) 0067 { 0068 if( d->views.count() == 1 ) 0069 { 0070 isErased = true; 0071 it = m_toolViews.erase(it); 0072 m_ids.removeAll( d->toolViewId ); 0073 delete d; 0074 } else 0075 { 0076 d->views.removeAll(v); 0077 } 0078 } 0079 if (!isErased) { 0080 ++it; 0081 } 0082 } 0083 } 0084 0085 StandardOutputView::~StandardOutputView() 0086 { 0087 } 0088 0089 int StandardOutputView::standardToolView( KDevelop::IOutputView::StandardToolView view ) 0090 { 0091 const auto standardViewIt = m_standardViews.constFind(view); 0092 if (standardViewIt != m_standardViews.constEnd()) { 0093 return *standardViewIt; 0094 } 0095 0096 int ret = -1; 0097 switch( view ) 0098 { 0099 case KDevelop::IOutputView::BuildView: 0100 ret = registerToolView(QByteArrayLiteral("Build"), i18nc("@title:window", "Build"), 0101 KDevelop::IOutputView::HistoryView, QIcon::fromTheme(QStringLiteral("run-build")), 0102 KDevelop::IOutputView::AddFilterAction); 0103 break; 0104 case KDevelop::IOutputView::RunView: 0105 ret = registerToolView(QByteArrayLiteral("Run"), i18nc("@title:window", "Run"), 0106 KDevelop::IOutputView::MultipleView, QIcon::fromTheme(QStringLiteral("system-run")), 0107 KDevelop::IOutputView::AddFilterAction); 0108 break; 0109 case KDevelop::IOutputView::DebugView: 0110 ret = registerToolView(QByteArrayLiteral("Debug"), i18nc("@title:window", "Debug"), 0111 KDevelop::IOutputView::MultipleView, QIcon::fromTheme(QStringLiteral("debug-step-into")), 0112 KDevelop::IOutputView::AddFilterAction); 0113 break; 0114 case KDevelop::IOutputView::TestView: 0115 // TODO: pass QByteArrayLiteral("Test") instead of QByteArray() and make the settings work. 0116 // The settings are disabled for the Test output tool view, because all Test output views are currently 0117 // unclosable and there is only one output tool view option right now: output view number limit, which 0118 // automatically closes its views and has no effect if the views are not closable. 0119 // AllowUserClose output view behavior is enabled by default, but 3 output jobs - CompileAnalyzeJob, 0120 // cppcheck::Job and Heaptrack::Job - disable it by calling `setBehaviours(KDevelop::IOutputView::AutoScroll);`. 0121 // 1cd05dd39bb67cbec7ce39a0237b64fb42e5fc95 introduced the first unclosable view in the cppcheck plugin with 0122 // no surviving explanation. Other Test output views followed the example later. Ideally all output views should 0123 // become closable, if there is no good reason to prevent closing and destroying them. 0124 ret = registerToolView(QByteArray(), i18nc("@title:window", "Test"), KDevelop::IOutputView::HistoryView, 0125 QIcon::fromTheme(QStringLiteral("system-run"))); 0126 break; 0127 case KDevelop::IOutputView::VcsView: 0128 ret = registerToolView(QByteArrayLiteral("VersionControl"), i18nc("@title:window", "Version Control"), 0129 KDevelop::IOutputView::HistoryView, QIcon::fromTheme(QStringLiteral("system-run"))); 0130 break; 0131 } 0132 0133 Q_ASSERT(ret != -1); 0134 m_standardViews[view] = ret; 0135 return ret; 0136 } 0137 0138 int StandardOutputView::registerToolView(const QByteArray& configSubgroupName, const QString& title, 0139 KDevelop::IOutputView::ViewType type, const QIcon& icon, Options option, 0140 const QList<QAction*>& actionList) 0141 { 0142 // try to reuse existing tool view 0143 for (ToolViewData* d : qAsConst(m_toolViews)) { 0144 if ( d->type == type && d->title == title ) { 0145 return d->toolViewId; 0146 } 0147 } 0148 0149 // register new tool view 0150 const int newid = m_ids.isEmpty() ? 0 : (m_ids.last() + 1); 0151 qCDebug(PLUGIN_STANDARDOUTPUTVIEW) << "Registering view" << title << "with type:" << type << "id:" << newid; 0152 auto* tvdata = new ToolViewData( this ); 0153 tvdata->toolViewId = newid; 0154 tvdata->configSubgroupName = configSubgroupName; 0155 tvdata->type = type; 0156 tvdata->title = title; 0157 tvdata->icon = icon; 0158 tvdata->plugin = this; 0159 tvdata->option = option; 0160 tvdata->actionList = actionList; 0161 core()->uiController()->addToolView( title, new OutputViewFactory( tvdata ) ); 0162 m_ids << newid; 0163 m_toolViews[newid] = tvdata; 0164 return newid; 0165 } 0166 0167 int StandardOutputView::registerOutputInToolView( int toolViewId, 0168 const QString& title, 0169 KDevelop::IOutputView::Behaviours behaviour ) 0170 { 0171 const auto toolViewIt = m_toolViews.constFind(toolViewId); 0172 if (toolViewIt == m_toolViews.constEnd()) 0173 return -1; 0174 int newid; 0175 if( m_ids.isEmpty() ) 0176 { 0177 newid = 0; 0178 } else 0179 { 0180 newid = m_ids.last()+1; 0181 } 0182 m_ids << newid; 0183 (*toolViewIt)->addOutput(newid, title, behaviour); 0184 return newid; 0185 } 0186 0187 void StandardOutputView::raiseOutput(int outputId) 0188 { 0189 for (const auto* toolViewData : qAsConst(m_toolViews)) { 0190 if (toolViewData->outputdata.contains(outputId)) { 0191 for (Sublime::View* v : qAsConst(toolViewData->views)) { 0192 if( v->hasWidget() ) 0193 { 0194 auto* w = qobject_cast<OutputWidget*>( v->widget() ); 0195 w->raiseOutput( outputId ); 0196 v->requestRaise(); 0197 } 0198 } 0199 } 0200 // TODO: not break here? 0201 } 0202 } 0203 0204 void StandardOutputView::setModel( int outputId, QAbstractItemModel* model ) 0205 { 0206 OutputData* outputData = nullptr; 0207 for (const auto* toolViewData : qAsConst(m_toolViews)) { 0208 const auto& outputDataMap = toolViewData->outputdata; 0209 auto outputDataIt = outputDataMap.find(outputId); 0210 if (outputDataIt != outputDataMap.end()) { 0211 outputData = outputDataIt.value(); 0212 break; 0213 } 0214 } 0215 if (!outputData) { 0216 qCDebug(PLUGIN_STANDARDOUTPUTVIEW) << "Trying to set model on unknown view-id:" << outputId; 0217 } else { 0218 outputData->setModel(model); 0219 } 0220 } 0221 0222 void StandardOutputView::setDelegate( int outputId, QAbstractItemDelegate* delegate ) 0223 { 0224 OutputData* outputData = nullptr; 0225 for (const auto* toolViewData : qAsConst(m_toolViews)) { 0226 const auto& outputDataMap = toolViewData->outputdata; 0227 auto outputDataIt = outputDataMap.find(outputId); 0228 if (outputDataIt != outputDataMap.end()) { 0229 outputData = outputDataIt.value(); 0230 break; 0231 } 0232 } 0233 if (!outputData) { 0234 qCDebug(PLUGIN_STANDARDOUTPUTVIEW) << "Trying to set model on unknown view-id:" << outputId; 0235 } else { 0236 outputData->setDelegate(delegate); 0237 } 0238 } 0239 0240 void StandardOutputView::removeToolView(int toolViewId) 0241 { 0242 const auto toolViewIt = m_toolViews.find(toolViewId); 0243 if (toolViewIt != m_toolViews.end()) { 0244 ToolViewData* td = *toolViewIt; 0245 const auto views = td->views; 0246 for (Sublime::View* view : views) { 0247 if( view->hasWidget() ) 0248 { 0249 auto* outputWidget = qobject_cast<OutputWidget*>( view->widget() ); 0250 for (auto it = td->outputdata.keyBegin(), end = td->outputdata.keyEnd(); it != end; ++it) { 0251 outputWidget->removeOutput(*it); 0252 } 0253 } 0254 for (Sublime::Area* area : KDevelop::ICore::self()->uiController()->controller()->allAreas()) { 0255 area->removeToolView( view ); 0256 } 0257 } 0258 delete td; 0259 m_toolViews.erase(toolViewIt); 0260 emit toolViewRemoved(toolViewId); 0261 } 0262 } 0263 0264 OutputWidget* StandardOutputView::outputWidgetForId( int outputId ) const 0265 { 0266 for (ToolViewData* td : m_toolViews) { 0267 if( td->outputdata.contains( outputId ) ) 0268 { 0269 for (Sublime::View* view : qAsConst(td->views)) { 0270 if( view->hasWidget() ) 0271 return qobject_cast<OutputWidget*>( view->widget() ); 0272 } 0273 } 0274 } 0275 return nullptr; 0276 } 0277 0278 void StandardOutputView::scrollOutputTo( int outputId, const QModelIndex& idx ) 0279 { 0280 OutputWidget* widget = outputWidgetForId( outputId ); 0281 if( widget ) 0282 widget->scrollToIndex( idx ); 0283 } 0284 0285 void StandardOutputView::removeOutput( int outputId ) 0286 { 0287 for (ToolViewData* td : qAsConst(m_toolViews)) { 0288 const auto outputIt = td->outputdata.find(outputId); 0289 if (outputIt != td->outputdata.end()) { 0290 for (Sublime::View* view : qAsConst(td->views)) { 0291 if( view->hasWidget() ) 0292 qobject_cast<OutputWidget*>( view->widget() )->removeOutput( outputId ); 0293 } 0294 td->outputdata.erase(outputIt); 0295 } 0296 } 0297 } 0298 0299 void StandardOutputView::setTitle(int outputId, const QString& title) 0300 { 0301 OutputWidget* widget = outputWidgetForId(outputId); 0302 if (widget) { 0303 widget->setTitle(outputId, title); 0304 } 0305 } 0306 0307 #include "moc_standardoutputview.cpp"