Rework of the outputview interface

Andreas Pakulat apaku at gmx.de
Fri Jun 8 16:43:50 UTC 2007


Hi,

as Matt suggested some time ago, I reworked the outputview to more
closely follow the MVC pattern.

The outputview now has a much simpler interface, registering a new view
with title, setting a model for that view and emitting a signal whenever
an index in the view is activated.

Also this adds a really simple OutputModel for convience, it just
provides 2 slots to connect to ProcessLineMaker or the new
ExecuteCommand class on top of a QStandardItemModel. This is not meant
to get extended, unless we find that various outputview-users do the
same thing in their custom models. Really just convenience (thats also
why it lacks api docs, I will add these before commit of course)

Last but not least there's the new ExecuteCommand class, it provides
simplified signals on top of QProcess to make it easier to execute
commands for the outputview. I've put it into util because it can be
used for other things as well (if you only need the output and
failed/completed signal). For more complex needs QProcess (or the
proposed KProcess from Oswald) can be used.

2 things that are missing:

a) context menu access for the outputviews
b) removing a view (and letting the user clean up their data)

I will do both tomorrow, adding a viewClosed() signal to IOutputView and
checking where we need to implement customContextMenu().

Please review and post your comments. The first patch is for the
platform, including porting svn plugin. The second patch is for KDevelop
itself, I only ported the qmake builder as the make builder is
relatively complex already and I don't have time today for that. (first
patch is too large so I needed to compress it)

Andreas

-- 
You will have good luck and overcome many hardships.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: outputview_model_patch.gz
Type: application/x-gunzip
Size: 10896 bytes
Desc: not available
URL: <http://mail.kde.org/pipermail/kdevelop-devel/attachments/20070608/6b94d2f1/attachment.bin>
-------------- next part --------------
Index: buildtools/builders/qmakebuilder/qmakebuilder.cpp
===================================================================
--- buildtools/builders/qmakebuilder/qmakebuilder.cpp	(Revision 672852)
+++ buildtools/builders/qmakebuilder/qmakebuilder.cpp	(Arbeitskopie)
@@ -24,13 +24,17 @@
 #include <config.h>
 
 #include <QtCore/QStringList>
+#include <QtCore/QSignalMapper>
 
+
 #include <projectmodel.h>
 
 #include <iproject.h>
 #include <icore.h>
 #include <iplugincontroller.h>
 #include <ioutputview.h>
+#include <outputmodel.h>
+#include <executecommand.h>
 #include <QtDesigner/QExtensionFactory>
 
 #include <kgenericfactory.h>
@@ -49,28 +53,24 @@
                             QMakeBuilderFactory( "kdevqmakebuilder" ) )
 
 QMakeBuilder::QMakeBuilder(QObject *parent, const QStringList &)
-    : KDevelop::IPlugin(QMakeBuilderFactory::componentData(), parent)
+    : KDevelop::IPlugin(QMakeBuilderFactory::componentData(), parent),
+      m_failedMapper( new QSignalMapper( this ) ),
+      m_completedMapper( new QSignalMapper( this ) )
 {
     KDEV_USE_EXTENSION_INTERFACE( KDevelop::IProjectBuilder )
     KDEV_USE_EXTENSION_INTERFACE( IQMakeBuilder )
-    IPlugin* i = core()->pluginController()->pluginForExtension("org.kdevelop.IOutputView");
+    m_failedMapper = new QSignalMapper(this);
+    connect(m_failedMapper, SIGNAL(mapped(const QString& )),
+            this, SLOT(errored(const QString&)));
+    m_completedMapper = new QSignalMapper(this);
+    connect(m_completedMapper, SIGNAL(mapped(const QString& )),
+            this, SLOT(completed(const QString&)));
+    IPlugin* i = core()->pluginController()->pluginForExtension("org.kdevelop.IMakeBuilder");
     if( i )
     {
-        KDevelop::IOutputView* view = i->extension<KDevelop::IOutputView>();
+        IMakeBuilder* view = i->extension<IMakeBuilder>();
         if( view )
         {
-            connect(i, SIGNAL(commandFinished(const QString &)),
-                this, SLOT(commandFinished(const QString &)));
-            connect(i, SIGNAL(commandFailed(const QString &)),
-                this, SLOT(commandFailed(const QString &)));
-        }
-    }
-    i = core()->pluginController()->pluginForExtension("org.kdevelop.IMakeBuilder");
-    if( i )
-    {
-        KDevelop::IOutputView* view = i->extension<KDevelop::IOutputView>();
-        if( view )
-        {
             connect(i, SIGNAL(built(KDevelop::ProjectBaseItem*)),
                 this, SLOT(built(KDevelop::ProjectBaseItem*)));
             connect(i, SIGNAL(failed(KDevelop::ProjectBaseItem*)),
@@ -95,15 +95,30 @@
         KDevelop::IOutputView* view = i->extension<KDevelop::IOutputView>();
         if( view )
         {
-            QStringList cmd;
+
+            QString id = view->registerView(i18n("QMake: %1", dom->project()->name() ) );
+            m_ids << id;
+            m_models[id] = new KDevelop::OutputModel(this);
+            view->setModel( id, m_models[id] );
+            m_items[id] = dom;
+            QString cmd;
             KSharedConfig::Ptr cfg = dom->project()->projectConfiguration();
             KConfigGroup group(cfg.data(), "QMake Builder");
             kDebug(9024) << "Reading setting: " << group.readEntry("QMake Binary") << endl;
             KUrl v = group.readEntry("QMake Binary", KUrl( "file:///usr/bin/qmake" ) );
 //             kDebug(9024) << v << v.type() << v.userType() << endl;
-            cmd << v.toLocalFile();
-            m_queue << QPair<QStringList, KDevelop::ProjectBaseItem*>( cmd, dom );
-            view->queueCommand( item->url(), cmd, QMap<QString, QString>() );
+            cmd = v.toLocalFile();
+            m_cmds[id] = new KDevelop::ExecuteCommand(cmd, this);
+            connect(m_cmds[id], SIGNAL(receivedStandardError(const QStringList&)),
+                    m_models[id], SLOT(appendLines(const QStringList&) ) );
+            connect(m_cmds[id], SIGNAL(receivedStandardOutput(const QStringList&)),
+                    m_models[id], SLOT(appendLines(const QStringList&) ) );
+            m_failedMapper->setMapping( m_cmds[id], id );
+            m_completedMapper->setMapping( m_cmds[id], id );
+            m_cmds[id]->setWorkingDirectory( dom->project()->folder().toLocalFile() );
+            connect( m_cmds[id], SIGNAL( failed() ), m_failedMapper, SLOT(map()));
+            connect( m_cmds[id], SIGNAL( completed() ), m_completedMapper, SLOT(map()));
+            m_cmds[id]->start();
             return true;
         }
     }
@@ -116,45 +131,30 @@
     return false;
 }
 
-void QMakeBuilder::commandFinished(const QString &command)
+void QMakeBuilder::completed(const QString &id)
 {
-    kDebug(9024) << "command finished " << command << endl;
-    if( !m_queue.isEmpty() )
+    kDebug(9024) << "command finished " << id << endl;
+    if( m_items.contains(id))
     {
-        kDebug(9024) << "queue not empty" << endl;
-        QPair< QStringList, KDevelop::ProjectBaseItem* > pair = m_queue.front();
-
-        if( pair.first.join(" ") == command )
+        IPlugin* i = core()->pluginController()->pluginForExtension("org.kdevelop.IMakeBuilder");
+        if( i )
         {
-            kDebug(9024) << "found command" << endl;
-            m_queue.pop_front();
-            IPlugin* i = core()->pluginController()->pluginForExtension("org.kdevelop.IMakeBuilder");
-            if( i )
+            IMakeBuilder* builder = i->extension<IMakeBuilder>();
+            if( builder )
             {
-                IMakeBuilder* builder = i->extension<IMakeBuilder>();
-                if( builder )
-                {
-                    kDebug(9024) << "Building with make" << endl;
-                    builder->build(pair.second);
-                }else kDebug(9024) << "Make builder not with extension" << endl;
-            }
-            else kDebug(9024) << "Make builder not found" << endl;
-        }
+                kDebug(9024) << "Building with make" << endl;
+                builder->build(m_items[id]);
+            }else kDebug(9024) << "Make builder not with extension" << endl;
+        } else kDebug(9024) << "Make builder not found" << endl;
     }
 }
 
-void QMakeBuilder::commandFailed(const QString &command)
+void QMakeBuilder::errored(const QString &id)
 {
-    if( !m_queue.isEmpty() )
-    {
-        QPair<QStringList, KDevelop::ProjectBaseItem*> pair = m_queue.front();
-        if( pair.first.join(" ") == command )
-        {
-            m_queue.pop_front();
-            emit failed(pair.second);
-        }
-    }
+    if( m_items.contains(id))
+        emit failed(m_items[id]);
 }
 
 #include "qmakebuilder.moc"
-// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
+
+//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle;
Index: buildtools/builders/qmakebuilder/qmakebuilder.h
===================================================================
--- buildtools/builders/qmakebuilder/qmakebuilder.h	(Revision 672852)
+++ buildtools/builders/qmakebuilder/qmakebuilder.h	(Arbeitskopie)
@@ -27,8 +27,13 @@
 #include <QtCore/QPair>
 
 class QStringList;
+class QSignalMapper;
 class KDialog;
-namespace KDevelop{ class ProjectBaseItem; }
+namespace KDevelop{
+    class ProjectBaseItem;
+    class ExecuteCommand;
+    class OutputModel;
+}
 
 /**
 @author Andreas Pakulat
@@ -50,13 +55,18 @@
     void built(KDevelop::ProjectBaseItem*);
     void failed(KDevelop::ProjectBaseItem*);
 private Q_SLOTS:
-    void commandFinished(const QString &command);
-    void commandFailed(const QString &command);
+    void completed(const QString &id);
+    void errored(const QString &id);
 
 private:
-    QList< QPair< QStringList, KDevelop::ProjectBaseItem*> > m_queue;
+    QStringList m_ids;
+    QMap< QString, KDevelop::ExecuteCommand* > m_cmds;
+    QMap< QString, KDevelop::ProjectBaseItem* > m_items;
+    QMap< QString, KDevelop::OutputModel* > m_models;
+    QSignalMapper* m_failedMapper;
+    QSignalMapper* m_completedMapper;
 };
 
 #endif // QMAKEBUILDER_H
 
-// kate: space-indent on; indent-width 4; tab-width: 4; replace-tabs on; auto-insert-doxygen on
+//kate: space-indent on; indent-width 4; replace-tabs on; auto-insert-doxygen on; indent-mode cstyle;
Index: buildtools/builders/qmakebuilder/CMakeLists.txt
===================================================================
--- buildtools/builders/qmakebuilder/CMakeLists.txt	(Revision 672852)
+++ buildtools/builders/qmakebuilder/CMakeLists.txt	(Arbeitskopie)
@@ -4,6 +4,7 @@
     ${KDEVPLATFORM_INCLUDE_DIR}
     ${KDEVPLATFORM_INCLUDE_DIR}/interfaces
     ${KDEVPLATFORM_INCLUDE_DIR}/outputview
+    ${KDEVPLATFORM_INCLUDE_DIR}/util
     ${KDEVPLATFORM_INCLUDE_DIR}/project
     ${KDEVPLATFORM_INCLUDE_DIR}/project/interfaces
     )
@@ -22,6 +23,8 @@
         ${KDE4_KDEUI_LIBS}
         ${QT_QTDESIGNER_LIBRARY}
         ${KDEVPLATFORM_INTERFACES_LIBRARY}
+        ${KDEVPLATFORM_OUTPUTVIEW_LIBRARY}
+        ${KDEVPLATFORM_UTIL_LIBRARY}
         ${KDEVPLATFORM_PROJECT_LIBRARY}
 )
 
Index: buildtools/builders/CMakeLists.txt
===================================================================
--- buildtools/builders/CMakeLists.txt	(Revision 672852)
+++ buildtools/builders/CMakeLists.txt	(Arbeitskopie)
@@ -1,4 +1,4 @@
 
-add_subdirectory(makebuilder)
+#add_subdirectory(makebuilder)
 macro_optional_add_subdirectory(qmakebuilder)
 


More information about the KDevelop-devel mailing list