File indexing completed on 2024-04-28 04:34:22

0001 /***************************************************************************
0002  *   Copyright 2009 Sandro Andrade <sandroandrade@kde.org>                 *
0003  *                                                                         *
0004  *   This program is free software; you can redistribute it and/or modify  *
0005  *   it under the terms of the GNU Library General Public License as       *
0006  *   published by the Free Software Foundation; either version 2 of the    *
0007  *   License, or (at your option) any later version.                       *
0008  *                                                                         *
0009  *   This program is distributed in the hope that it will be useful,       *
0010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0012  *   GNU General Public License for more details.                          *
0013  *                                                                         *
0014  *   You should have received a copy of the GNU Library General Public     *
0015  *   License along with this program; if not, write to the                 *
0016  *   Free Software Foundation, Inc.,                                       *
0017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0018  ***************************************************************************/
0019 
0020 #include "kdevcontrolflowgraphviewplugin.h"
0021 
0022 #include <QAction>
0023 
0024 #include <KLocale>
0025 #include <KAboutData>
0026 #include <KMessageBox>
0027 #include <KGenericFactory>
0028 
0029 #include <interfaces/icore.h>
0030 #include <interfaces/context.h>
0031 #include <interfaces/iproject.h>
0032 #include <interfaces/idocument.h>
0033 #include <interfaces/iuicontroller.h>
0034 #include <interfaces/iruncontroller.h>
0035 #include <interfaces/iprojectcontroller.h>
0036 #include <interfaces/ilanguagecontroller.h>
0037 #include <interfaces/idocumentcontroller.h>
0038 #include <interfaces/contextmenuextension.h>
0039 
0040 #include <language/duchain/codemodel.h>
0041 #include <language/duchain/declaration.h>
0042 #include <language/duchain/classdeclaration.h>
0043 #include <language/duchain/types/functiontype.h>
0044 #include <language/duchain/functiondefinition.h>
0045 #include <language/duchain/persistentsymboltable.h>
0046 #include <language/duchain/classfunctiondeclaration.h>
0047 
0048 #include <language/interfaces/codecontext.h>
0049 
0050 #include <language/backgroundparser/parsejob.h>
0051 #include <language/backgroundparser/backgroundparser.h>
0052 
0053 #include <project/projectmodel.h>
0054 
0055 #include <KTextEditor/Document>
0056 
0057 #include "duchaincontrolflow.h"
0058 #include "dotcontrolflowgraph.h"
0059 #include "controlflowgraphview.h"
0060 #include "duchaincontrolflowjob.h"
0061 
0062 using namespace KDevelop;
0063 
0064 K_PLUGIN_FACTORY(ControlFlowGraphViewFactory, registerPlugin<KDevControlFlowGraphViewPlugin>();)
0065 K_EXPORT_PLUGIN(ControlFlowGraphViewFactory(KAboutData("kdevcontrolflowgraphview","kdevcontrolflowgraph", ki18n("Control Flow Graph"), "0.1", ki18n("Control flow graph support in KDevelop"), KAboutData::License_GPL)))
0066 
0067 class KDevControlFlowGraphViewFactory: public KDevelop::IToolViewFactory{
0068 public:
0069     KDevControlFlowGraphViewFactory(KDevControlFlowGraphViewPlugin *plugin) : m_plugin(plugin) {}
0070     virtual QWidget* create(QWidget *parent = 0)
0071     {
0072         return new ControlFlowGraphView(m_plugin, parent);
0073     }
0074     virtual Qt::DockWidgetArea defaultPosition()
0075     {
0076         return Qt::BottomDockWidgetArea;
0077     }
0078     virtual QString id() const
0079     {
0080         return "org.kdevelop.ControlFlowGraphView";
0081     }
0082 private:
0083     KDevControlFlowGraphViewPlugin *m_plugin;
0084 };
0085 
0086 KDevControlFlowGraphViewPlugin::KDevControlFlowGraphViewPlugin (QObject *parent, const QVariantList &)
0087 :
0088 KDevelop::IPlugin (ControlFlowGraphViewFactory::componentData(), parent),
0089 m_toolViewFactory(new KDevControlFlowGraphViewFactory(this)),
0090 m_activeToolView(0),
0091 m_project(0),
0092 m_abort(false)
0093 {
0094     core()->uiController()->addToolView(i18n("Control Flow Graph"), m_toolViewFactory);
0095 
0096     QObject::connect(core()->documentController(), SIGNAL(textDocumentCreated(KDevelop::IDocument*)),
0097                      SLOT(textDocumentCreated(KDevelop::IDocument*)));
0098     QObject::connect(core()->projectController(), SIGNAL(projectOpened(KDevelop::IProject*)),
0099                      SLOT(projectOpened(KDevelop::IProject*)));
0100     QObject::connect(core()->projectController(), SIGNAL(projectClosed(KDevelop::IProject*)),
0101                      SLOT(projectClosed(KDevelop::IProject*)));
0102     QObject::connect(core()->languageController()->backgroundParser(), SIGNAL(parseJobFinished(KDevelop::ParseJob*)),
0103                      SLOT(parseJobFinished(KDevelop::ParseJob*)));
0104                      
0105     m_exportControlFlowGraph = new QAction(i18n("Export Control Flow Graph"), this);
0106     connect(m_exportControlFlowGraph, SIGNAL(triggered(bool)), SLOT(slotExportControlFlowGraph(bool)), Qt::UniqueConnection);
0107 
0108     m_exportClassControlFlowGraph = new QAction(i18n("Export Class Control Flow Graph"), this);
0109     connect(m_exportClassControlFlowGraph, SIGNAL(triggered(bool)), SLOT(slotExportClassControlFlowGraph(bool)), Qt::UniqueConnection);
0110 
0111     m_exportProjectControlFlowGraph = new QAction(i18n("Export Project Control Flow Graph"), this);
0112     connect(m_exportProjectControlFlowGraph, SIGNAL(triggered(bool)), SLOT(slotExportProjectControlFlowGraph(bool)), Qt::UniqueConnection);
0113 }
0114 
0115 KDevControlFlowGraphViewPlugin::~KDevControlFlowGraphViewPlugin()
0116 {
0117 }
0118 
0119 QString KDevControlFlowGraphViewPlugin::statusName() const
0120 {
0121     return i18n("Control Flow Graph");    
0122 }
0123 
0124 void KDevControlFlowGraphViewPlugin::unload()
0125 {
0126     // When calling removeToolView all existing views are destroyed and their destructor invoke unRegisterToolView.
0127     core()->uiController()->removeToolView(m_toolViewFactory);
0128 }
0129 
0130 void KDevControlFlowGraphViewPlugin::registerToolView(ControlFlowGraphView *view)
0131 {
0132     m_toolViews << view;
0133 }
0134 
0135 void KDevControlFlowGraphViewPlugin::unRegisterToolView(ControlFlowGraphView *view)
0136 {
0137     m_toolViews.removeAll(view);
0138 }
0139 
0140 QPointer<ControlFlowGraphFileDialog> KDevControlFlowGraphViewPlugin::exportControlFlowGraph(ControlFlowGraphFileDialog::OpeningMode mode)
0141 {
0142     QPointer<ControlFlowGraphFileDialog> fileDialog = new ControlFlowGraphFileDialog(KUrl(), "*.png|PNG (Portable Network Graphics)\n*.jpg *.jpeg|JPG \\/ JPEG (Joint Photographic Expert Group)\n*.gif|GIF (Graphics Interchange Format)\n*.svg *.svgz|SVG (Scalable Vector Graphics)\n*.dia|DIA (Dia Structured Diagrams)\n*.fig|FIG\n*.pdf|PDF (Portable Document Format)\n*.dot|DOT (Graph Description Language)", (QWidget *) ICore::self()->uiController()->activeMainWindow(), i18n("Export Control Flow Graph"), mode);
0143     if (fileDialog->exec() == QDialog::Accepted)
0144     {
0145         if (fileDialog)
0146         {
0147             QString fileName = fileDialog->selectedFile();
0148             if (!fileName.isEmpty())
0149                 return fileDialog;
0150         }
0151     }
0152     return 0;
0153 }
0154 
0155 KDevelop::ContextMenuExtension
0156 KDevControlFlowGraphViewPlugin::contextMenuExtension(KDevelop::Context* context)
0157 {
0158     KDevelop::ContextMenuExtension extension;
0159 
0160     if (context->hasType(Context::CodeContext) || context->hasType(Context::EditorContext))
0161     {
0162         KDevelop::DeclarationContext *codeContext = dynamic_cast<KDevelop::DeclarationContext*>(context);
0163 
0164         if (!codeContext)
0165             return extension;
0166 
0167         DUChainReadLocker readLock(DUChain::lock());
0168         Declaration *declaration(codeContext->declaration().data());
0169 
0170         // Insert action for generating control flow graph from method
0171         if (declaration && declaration->type<KDevelop::FunctionType>() && (declaration->isDefinition() || FunctionDefinition::definition(declaration)))
0172         {
0173             m_exportControlFlowGraph->setData(QVariant::fromValue(DUChainBasePointer(declaration)));
0174             extension.addAction(KDevelop::ContextMenuExtension::ExtensionGroup, m_exportControlFlowGraph);
0175         }
0176         // Insert action for generating control flow graph for the whole class
0177         else if (declaration && declaration->kind() == Declaration::Type &&
0178                 declaration->internalContext() &&
0179                 declaration->internalContext()->type() == DUContext::Class)
0180         {
0181             m_exportClassControlFlowGraph->setData(QVariant::fromValue(DUChainBasePointer(declaration)));
0182             extension.addAction(KDevelop::ContextMenuExtension::ExtensionGroup, m_exportClassControlFlowGraph);
0183         }
0184     }
0185     else if (context->hasType(Context::ProjectItemContext))
0186     {
0187         KDevelop::ProjectItemContext *projectItemContext = dynamic_cast<KDevelop::ProjectItemContext*>(context);
0188         if (projectItemContext)
0189         {
0190             QList<ProjectBaseItem *> items = projectItemContext->items();
0191             foreach(ProjectBaseItem *item, items)
0192             {
0193                 ProjectFolderItem *folder = item->folder();
0194                 if (folder && !folder->parent())
0195                 {
0196                     m_exportProjectControlFlowGraph->setData(QVariant::fromValue(folder->project()->name()));
0197                     extension.addAction(KDevelop::ContextMenuExtension::ExtensionGroup, m_exportProjectControlFlowGraph);
0198                 }
0199             }
0200         }
0201     }
0202     return extension;
0203 }
0204 
0205 void KDevControlFlowGraphViewPlugin::projectOpened(KDevelop::IProject* project)
0206 {
0207     Q_UNUSED(project);
0208     foreach (ControlFlowGraphView *controlFlowGraphView, m_toolViews)
0209         controlFlowGraphView->setProjectButtonsEnabled(true);
0210     refreshActiveToolView();
0211 }
0212 
0213 void KDevControlFlowGraphViewPlugin::projectClosed(KDevelop::IProject* project)
0214 {
0215     Q_UNUSED(project);
0216     if (core()->projectController()->projectCount() == 0)
0217     {
0218         foreach (ControlFlowGraphView *controlFlowGraphView, m_toolViews)
0219         {
0220             controlFlowGraphView->setProjectButtonsEnabled(false);
0221             controlFlowGraphView->newGraph();
0222         }
0223     }
0224     refreshActiveToolView();
0225 }
0226 
0227 void KDevControlFlowGraphViewPlugin::parseJobFinished(KDevelop::ParseJob* parseJob)
0228 {
0229     if (core()->documentController()->activeDocument() &&
0230         parseJob->document().toUrl() == core()->documentController()->activeDocument()->url())
0231         refreshActiveToolView();
0232 }
0233 
0234 void KDevControlFlowGraphViewPlugin::textDocumentCreated(KDevelop::IDocument *document)
0235 {
0236     connect(document->textDocument(), SIGNAL(viewCreated(KTextEditor::Document*, KTextEditor::View*)),
0237             SLOT(viewCreated(KTextEditor::Document*, KTextEditor::View*)));
0238 }
0239 
0240 void KDevControlFlowGraphViewPlugin::viewCreated(KTextEditor::Document *document, KTextEditor::View *view)
0241 {
0242     Q_UNUSED(document);
0243     connect(view, SIGNAL(cursorPositionChanged(KTextEditor::View*, KTextEditor::Cursor)),
0244             SLOT(cursorPositionChanged(KTextEditor::View*, KTextEditor::Cursor)));
0245     connect(view, SIGNAL(destroyed(QObject*)), SLOT(viewDestroyed(QObject*)));
0246     connect(view, SIGNAL(focusIn(KTextEditor::View*)), SLOT(focusIn(KTextEditor::View*)));
0247 }
0248 
0249 void KDevControlFlowGraphViewPlugin::viewDestroyed(QObject *object)
0250 {
0251     Q_UNUSED(object);
0252     if (!core()->documentController()->activeDocument() && m_activeToolView)
0253         m_activeToolView->newGraph();
0254 }
0255 
0256 void KDevControlFlowGraphViewPlugin::focusIn(KTextEditor::View *view)
0257 {
0258     if (view)
0259         cursorPositionChanged(view, view->cursorPosition());
0260 }
0261 
0262 void KDevControlFlowGraphViewPlugin::cursorPositionChanged(KTextEditor::View *view, const KTextEditor::Cursor &cursor)
0263 {
0264     if (m_activeToolView)
0265         m_activeToolView->cursorPositionChanged(view, cursor);
0266 }
0267 
0268 void KDevControlFlowGraphViewPlugin::refreshActiveToolView()
0269 {
0270     if (m_activeToolView)
0271         m_activeToolView->refreshGraph();
0272 }
0273 
0274 void KDevControlFlowGraphViewPlugin::slotExportControlFlowGraph(bool value)
0275 {
0276     // Export graph for a given function
0277     Q_UNUSED(value);
0278 
0279     if (m_duchainControlFlow || m_dotControlFlowGraph)
0280     {
0281         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("There is a graph being currently exported. Please stop it before requiring a new one"));
0282         return;
0283     }
0284 
0285     DUChainReadLocker lock(DUChain::lock());
0286 
0287     Q_ASSERT(qobject_cast<QAction *>(sender()));
0288     QAction *action = static_cast<QAction *>(sender());
0289     Q_ASSERT(action->data().canConvert<DUChainBasePointer>());
0290     DeclarationPointer declarationPointer = qvariant_cast<DUChainBasePointer>(action->data()).dynamicCast<Declaration>();
0291 
0292     Declaration *declaration = declarationPointer.data();
0293     if (!declaration)
0294     {
0295         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("Could not generate function control flow graph"));
0296         return;
0297     }
0298 
0299     if (!declaration->isDefinition())
0300     {
0301         declaration = FunctionDefinition::definition(declaration);
0302         if (!declaration || !declaration->internalContext())
0303         {
0304             KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("Could not generate control flow graph"));
0305             return;
0306         }
0307     }
0308     if ((m_fileDialog = exportControlFlowGraph()))
0309     {
0310         DUChainControlFlowJob *job = new DUChainControlFlowJob(declaration->qualifiedIdentifier().toString(), this);
0311         job->setControlFlowJobType(DUChainControlFlowInternalJob::ControlFlowJobBatchForFunction);
0312         m_ideclaration = IndexedDeclaration(declaration);
0313         connect (job, SIGNAL(result(KJob*)), SLOT(generationDone(KJob*)));
0314         ICore::self()->runController()->registerJob(job);
0315     }
0316     action->setData(QVariant::fromValue(DUChainBasePointer()));
0317 }
0318 
0319 void KDevControlFlowGraphViewPlugin::slotExportClassControlFlowGraph(bool value)
0320 {
0321     // Export graph for all functions of a given class - individual per-function graphs will be merged
0322     Q_UNUSED(value);
0323 
0324     if (m_duchainControlFlow || m_dotControlFlowGraph)
0325     {
0326         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("There is a graph being currently exported. Please stop it before requiring a new one"));
0327         return;
0328     }
0329 
0330     DUChainReadLocker lock(DUChain::lock());
0331 
0332     Q_ASSERT(qobject_cast<QAction *>(sender()));
0333     QAction *action = static_cast<QAction *>(sender());
0334     Q_ASSERT(action->data().canConvert<DUChainBasePointer>());
0335     DeclarationPointer declarationPointer = qvariant_cast<DUChainBasePointer>(action->data()).dynamicCast<Declaration>();
0336 
0337     Declaration *declaration = declarationPointer.data();
0338     if (!declaration)
0339     {
0340         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("Could not generate class control flow graph"));
0341         return;
0342     }
0343 
0344     if ((m_fileDialog = exportControlFlowGraph(ControlFlowGraphFileDialog::ForClassConfigurationButtons)))
0345     {
0346         DUChainControlFlowJob *job = new DUChainControlFlowJob(declaration->qualifiedIdentifier().toString(), this);
0347         job->setControlFlowJobType(DUChainControlFlowInternalJob::ControlFlowJobBatchForClass);
0348         m_ideclaration = IndexedDeclaration(declaration);
0349         connect (job, SIGNAL(result(KJob*)), SLOT(generationDone(KJob*)));
0350         ICore::self()->runController()->registerJob(job);
0351     }
0352     action->setData(QVariant::fromValue(DUChainBasePointer()));
0353 }
0354 
0355 void KDevControlFlowGraphViewPlugin::slotExportProjectControlFlowGraph(bool value)
0356 {
0357     // Export graph for all classes of a given project - individual per-class graphs will be merged
0358     Q_UNUSED(value);
0359 
0360     if (m_duchainControlFlow || m_dotControlFlowGraph)
0361     {
0362         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("There is a graph being currently exported. Please stop it before requiring a new one"));
0363         return;
0364     }
0365 
0366     Q_ASSERT(qobject_cast<QAction *>(sender()));
0367     QAction *action = static_cast<QAction *>(sender());
0368     Q_ASSERT(action->data().canConvert<QString>());
0369     QString projectName = qvariant_cast<QString>(action->data());
0370 
0371     if (projectName.isEmpty())
0372     {
0373         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("Could not generate project control flow graph - project name empty"));
0374         return;
0375     }
0376 
0377     IProject *project = core()->projectController()->findProjectByName(projectName);
0378 
0379     if (!project)
0380     {
0381         KMessageBox::error((QWidget *) core()->uiController()->activeMainWindow(), i18n("Could not generate project control flow graph - project not found"));
0382         return;
0383     }
0384 
0385     if ((m_fileDialog = exportControlFlowGraph(ControlFlowGraphFileDialog::ForClassConfigurationButtons)))
0386     {
0387         DUChainControlFlowJob *job = new DUChainControlFlowJob(projectName, this);
0388         job->setControlFlowJobType(DUChainControlFlowInternalJob::ControlFlowJobBatchForProject);
0389         m_project = project;
0390         connect (job, SIGNAL(result(KJob*)), SLOT(generationDone(KJob*)));
0391         ICore::self()->runController()->registerJob(job);
0392     }
0393     action->setData(QVariant::fromValue(QString()));
0394 }
0395 
0396 void KDevControlFlowGraphViewPlugin::generateControlFlowGraph()
0397 {
0398     DUChainReadLocker readLock(DUChain::lock());
0399 
0400     Declaration *declaration = m_ideclaration.data();
0401     if (!declaration)
0402         return;
0403 
0404     m_abort = false;
0405     m_dotControlFlowGraph = new DotControlFlowGraph;
0406     m_duchainControlFlow = new DUChainControlFlow(m_dotControlFlowGraph);
0407 
0408     configureDuchainControlFlow(m_duchainControlFlow, m_dotControlFlowGraph, m_fileDialog);
0409 
0410     m_duchainControlFlow->generateControlFlowForDeclaration(m_ideclaration, IndexedTopDUContext(declaration->topContext()), IndexedDUContext(declaration->internalContext()));
0411     exportGraph();
0412 }
0413 
0414 void KDevControlFlowGraphViewPlugin::generateClassControlFlowGraph()
0415 {
0416     DUChainReadLocker readLock(DUChain::lock());
0417 
0418     Declaration *declaration = m_ideclaration.data();
0419     if (!declaration)
0420         return;
0421 
0422     m_abort = false;
0423     m_dotControlFlowGraph = new DotControlFlowGraph;
0424     m_duchainControlFlow = new DUChainControlFlow(m_dotControlFlowGraph);
0425     
0426     configureDuchainControlFlow(m_duchainControlFlow, m_dotControlFlowGraph, m_fileDialog);
0427 
0428     if (!declaration->isForwardDeclaration() && declaration->internalContext())
0429     {
0430         int i = 0;
0431         int max = declaration->internalContext()->localDeclarations().size();
0432         // For each function declaration
0433         ClassFunctionDeclaration *functionDeclaration;
0434         foreach (Declaration *decl, declaration->internalContext()->localDeclarations())
0435         {
0436             if (m_abort)
0437                 break;
0438 
0439             emit showProgress(this, 0, max-1, i);
0440             emit showMessage(this, i18n("Generating graph for function %1", decl->identifier().toString()));
0441             ++i;
0442             if ((functionDeclaration = dynamic_cast<ClassFunctionDeclaration *>(decl)))
0443             {
0444                 Declaration *functionDefinition = FunctionDefinition::definition(functionDeclaration);
0445                 if (functionDefinition)
0446                     m_duchainControlFlow->generateControlFlowForDeclaration(IndexedDeclaration(functionDefinition), IndexedTopDUContext(functionDefinition->topContext()), IndexedDUContext(functionDefinition->internalContext()));
0447             }
0448         }
0449     }
0450     if (!m_abort)
0451     {
0452         emit showMessage(this, i18n("Saving file %1", m_fileDialog->selectedFile()));
0453         exportGraph();
0454     }
0455     emit hideProgress(this);
0456     emit clearMessage(this);
0457 }
0458 
0459 void KDevControlFlowGraphViewPlugin::generateProjectControlFlowGraph()
0460 {
0461     if (!m_project)
0462         return;
0463 
0464     m_abort = false;
0465     m_dotControlFlowGraph = new DotControlFlowGraph;
0466     m_duchainControlFlow = new DUChainControlFlow(m_dotControlFlowGraph);
0467 
0468     configureDuchainControlFlow(m_duchainControlFlow, m_dotControlFlowGraph, m_fileDialog);
0469 
0470     DUChainReadLocker readLock(DUChain::lock());
0471 
0472     int i = 0;
0473     int max = m_project->fileSet().size();
0474     // For each source file
0475     foreach(const IndexedString &file, m_project->fileSet())
0476     {
0477         emit showProgress(this, 0, max-1, i);
0478         ++i;
0479 
0480         uint codeModelItemCount = 0;
0481         const CodeModelItem *codeModelItems = 0;
0482         CodeModel::self().items(file, codeModelItemCount, codeModelItems);
0483         
0484         for (uint codeModelItemIndex = 0; codeModelItemIndex < codeModelItemCount; ++codeModelItemIndex)
0485         {
0486             const CodeModelItem &item = codeModelItems[codeModelItemIndex];
0487             
0488             if ((item.kind & CodeModelItem::Class) && !item.id.identifier().last().toString().isEmpty())
0489             {
0490                 uint declarationCount = 0;
0491                 const IndexedDeclaration *declarations = 0;
0492                 PersistentSymbolTable::self().declarations(item.id.identifier(), declarationCount, declarations);
0493                 // For each class declaration
0494                 for (uint j = 0; j < declarationCount; ++j)
0495                 {
0496                     Declaration *declaration = dynamic_cast<Declaration *>(declarations[j].declaration());
0497                     if (declaration && !declaration->isForwardDeclaration() && declaration->internalContext())
0498                     {
0499                         // For each function declaration
0500                         ClassFunctionDeclaration *functionDeclaration;
0501                         foreach (Declaration *decl, declaration->internalContext()->localDeclarations())
0502                         {
0503                             emit showMessage(this, i18n("Generating graph for %1 - %2", file.str(), decl->qualifiedIdentifier().toString()));
0504                             if ((functionDeclaration = dynamic_cast<ClassFunctionDeclaration *>(decl)))
0505                             {
0506                                 if (m_abort)
0507                                     break;
0508                                 
0509                                 Declaration *functionDefinition = FunctionDefinition::definition(functionDeclaration);
0510                                 if (functionDefinition)
0511                                     m_duchainControlFlow->generateControlFlowForDeclaration(IndexedDeclaration(functionDefinition), IndexedTopDUContext(functionDefinition->topContext()), IndexedDUContext(functionDefinition->internalContext()));
0512                             }
0513                         }
0514                         if (m_abort)
0515                             break;
0516                     }
0517                 }
0518                 if (m_abort)
0519                     break;
0520             }
0521         }
0522         if (m_abort)
0523             break;
0524     }
0525     if (!m_abort)
0526     {
0527         emit showMessage(this, i18n("Saving file %1", m_fileDialog->selectedFile()));
0528         exportGraph();
0529     }
0530     m_project = 0;
0531     emit hideProgress(this);
0532     emit clearMessage(this);
0533 }
0534 
0535 void KDevControlFlowGraphViewPlugin::requestAbort()
0536 {
0537     m_abort = true;
0538 }
0539 
0540 void KDevControlFlowGraphViewPlugin::setActiveToolView(ControlFlowGraphView *activeToolView)
0541 {
0542     m_activeToolView = activeToolView;
0543     refreshActiveToolView();
0544 }
0545 
0546 void KDevControlFlowGraphViewPlugin::generationDone(KJob *job)
0547 {
0548     job->deleteLater();
0549 
0550     delete m_dotControlFlowGraph;
0551     delete m_duchainControlFlow;
0552 
0553     if (!m_abort)
0554         KMessageBox::information((QWidget *) (core()->uiController()->activeMainWindow()),
0555                                  i18n("Control flow graph exported"),
0556                                  i18n("Export Control Flow Graph"));
0557 }
0558 
0559 void KDevControlFlowGraphViewPlugin::exportGraph()
0560 {
0561     DotControlFlowGraph::mutex.lock();
0562     m_dotControlFlowGraph->exportGraph(m_fileDialog->selectedFile());
0563     DotControlFlowGraph::mutex.unlock();
0564 }
0565 
0566 void KDevControlFlowGraphViewPlugin::configureDuchainControlFlow(DUChainControlFlow *duchainControlFlow, DotControlFlowGraph *dotControlFlowGraph, ControlFlowGraphFileDialog *fileDialog)
0567 {
0568     duchainControlFlow->setControlFlowMode(fileDialog->controlFlowMode());
0569     duchainControlFlow->setClusteringModes(fileDialog->clusteringModes());
0570     duchainControlFlow->setMaxLevel(fileDialog->maxLevel());
0571     duchainControlFlow->setUseFolderName(fileDialog->useFolderName());
0572     duchainControlFlow->setUseShortNames(fileDialog->useShortNames());
0573     duchainControlFlow->setDrawIncomingArcs(fileDialog->drawIncomingArcs());
0574 
0575     dotControlFlowGraph->prepareNewGraph();
0576 }