/* connect.cc */ #include "connect.h" #include "property.h" #include "tree.h" #include "trace.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef PARSER #include "ast.h" #include "parser.h" #include "parsesession.h" #include "control.h" #include "rpp/chartools.h" #include "cppeditorintegrator.h" #include "dumpchain.h" #endif #include "trace.h" // using namespace KDevelop; /* ----------------------------------------------------------------------- */ namespace ConnectModule { /* ----------------------------------------------------------------------- */ KAboutData aboutData ("connect", // application name "connect", // catalog name ki18n ("Connect Plugin"), // displayable program name "0.1", // version ki18n ("Simple connect plugin"), // short description KAboutData::License_GPL); K_PLUGIN_FACTORY (ConnectPluginFactory, registerPlugin ();) K_EXPORT_PLUGIN (ConnectPluginFactory (aboutData)) /* ----------------------------------------------------------------------- */ ConnectPlugin::ConnectPlugin (QObject *parent, const QVariantList & args) : KDevelop::IPlugin (ConnectPluginFactory::componentData(), parent), m_mainWindow (NULL), m_connectFactory (NULL), m_propertyFactory (NULL), m_traceFactory (NULL) { Q_UNUSED (args) // std::cout << std::endl; // std::cout << " **** CONNECT INIT **** " << std::endl; // std::cout << std::endl; kDebug () << " ---- CONNECT INIT ---- "; setXMLFile ("connect.rc"); m_connectFactory = new ConnectFactory (this); core()->uiController()->addToolView (i18n ("Connect"), m_connectFactory); m_propertyFactory = new PropertyFactory (); core()->uiController()->addToolView (i18n ("Properties"), m_propertyFactory); m_treeFactory = new TreeFactory (); core()->uiController()->addToolView (i18n ("Tree"), m_treeFactory); m_traceFactory = new_trace_factory (); core()->uiController()->addToolView ("Connect Trace", m_traceFactory); KActionCollection * actions = actionCollection (); KAction * action = actions->addAction ("connect_run"); action->setText (i18n ("Connect Plugin")); connect (action, SIGNAL (triggered (bool)), this, SLOT (run ())); } ConnectPlugin::~ConnectPlugin() { } void ConnectPlugin::unload() { core()->uiController()->removeToolView (m_connectFactory); core()->uiController()->removeToolView (m_propertyFactory); core()->uiController()->removeToolView (m_treeFactory); core()->uiController()->removeToolView (m_traceFactory); } /* ----------------------------------------------------------------------- */ void ConnectPlugin::run () { // std::cout << std::endl; // std::cout << " **** CONNECT RUN **** " << std::endl; // std::cout << std::endl; kDebug () << " ---- CONNECT RUN ---- "; trace ("connect run"); } /* ----------------------------------------------------------------------- */ ConnectWidget::ConnectWidget (QWidget* parent) : QWidget (parent), m_tree (new QTreeWidget (this)), m_editSlot (NULL), m_doc (NULL), m_topContext (NULL), m_session (NULL) { setObjectName ("ConnectView"); setWindowTitle (i18n ("Connect")); setWindowIcon (SmallIcon ("code-class")); // m_tree->header()->setResizeMode (0, QHeaderView::ResizeToContents); // m_tree->header()->setStretchLastSection (false); m_tree->header()->hide(); m_tree->setIndentation(10); QVBoxLayout* vbox = new QVBoxLayout (this); vbox->setMargin (0); vbox->addWidget (m_tree); setLayout (vbox); setWhatsThis (i18n ("Connect")); connect (KDevelop::ICore::self()->documentController(), SIGNAL (documentClosed (KDevelop::IDocument*)), this, SLOT (documentClosed (KDevelop::IDocument*))); connect (KDevelop::ICore::self()->documentController(), SIGNAL (documentActivated (KDevelop::IDocument*)), this, SLOT (documentActivated (KDevelop::IDocument*))); connect (m_tree, SIGNAL (itemDoubleClicked (QTreeWidgetItem*, int)), this, SLOT (treeDoubleClick (QTreeWidgetItem*, int))); m_editSlot = new KAction (this); m_editSlot->setText (i18n ("Edit Slot")); m_editSlot->setIcon (KIcon ("slot")); connect (m_editSlot, SIGNAL (triggered (bool)), this, SLOT (editSlot())); } ConnectWidget::~ConnectWidget() { } /* ----------------------------------------------------------------------- */ void ConnectWidget::contextMenuEvent (QContextMenuEvent* e) { QMenu *menu = new QMenu (this); ConnectItem * item = dynamic_cast (m_tree->currentItem ()); if (item != NULL && item->kind == SignalNode) menu->addAction (m_editSlot); if (!menu->actions().isEmpty()) menu->exec (QCursor::pos()); } void ConnectWidget::treeDoubleClick (QTreeWidgetItem* tree_item, int column) { trace ("connect - tree double click"); ConnectItem * item = dynamic_cast (tree_item); if (item != NULL && item->kind == SignalNode) editSlot (); } void ConnectWidget::editSlot () { trace ("connect - edit slot"); ConnectItem * item = dynamic_cast (m_tree->currentItem ()); if (item != NULL) { trace ("connect - tree item: " + item->text (0)); bool ok = false; ConnectItem * cls = NULL; ConnectItem * field = NULL; ConnectItem * signal = NULL; signal = item; if (signal != NULL && signal->kind == SignalNode) { field = dynamic_cast (signal->parent()); if (field != NULL && field->kind == FieldNode) { cls = dynamic_cast (field->parent()); if (cls != NULL && cls->kind == ClassNode) { ok = true; } } } if (ok) { QString eol = "\n"; QString method = "on_" + field->id + "_" + signal->id; QString text = "void " + cls->id + "::" + method + " ()" + eol + "{" + eol + "}" + eol; KTextEditor::Document * document = m_doc->textDocument(); KTextEditor::Cursor cursor = document->documentEnd(); document->insertText (cursor, text); const KDevelop::Declaration * decl = cls->cachedDecl.data(); if (decl != NULL) { KDevelop::DUContext * context = decl->internalContext (); KDevelop::RangeInRevision r = context->range(); KTextEditor::Range t = context->transformFromLocalRevision (r).textRange(); QString text = "void " + method + " ();" + eol ; document->insertText (t.end(), text); } ConnectItem * init = cls->init; if (init != NULL) { KDevelop::DUContext * context = init->cachedContext.data (); if (context != NULL) { KDevelop::RangeInRevision r = context->range(); KTextEditor::Range t = context->transformFromLocalRevision (r).textRange(); QString text = "connect (" + field->id + ", " + "SIGNAL (" + signal->id + "()), " + "this, " + "SLOT (" + method + "()));" ; document->insertText (t.end(), text); } } } } } /* ----------------------------------------------------------------------- */ #ifdef PARSER ConnectItem * ConnectWidget::showText (QTreeWidgetItem * branch, QString text) { ConnectItem * item = new ConnectItem (); branch->addChild (item); item->setText (0, text); return item; } ConnectItem * ConnectWidget::showAST (QTreeWidgetItem * branch, QString title, AST * ast) { // from kdevelop-4.5.1/languages/cpp/cppduchain/dumpchain.cpp QString nodeText = m_session->stringForNode (ast); return showText (branch, title + " : " + nodeText); } void ConnectWidget::showStatement (QTreeWidgetItem * branch, StatementAST * stat) { QString func_name; int func_arg_count = 0; QString func_arg [4]; if (stat != NULL && stat->kind == AST::Kind_ExpressionStatement) { ExpressionStatementAST * exprStat = static_cast (stat); ExpressionAST * expr = exprStat->expression; if (expr != NULL && expr->kind == AST::Kind_PostfixExpression) { PostfixExpressionAST * postfix = static_cast (expr); if (postfix->sub_expressions->count() == 1) { ExpressionAST * sub = postfix->sub_expressions->at(0)->element; if (sub != NULL && sub->kind == AST::Kind_FunctionCall) { FunctionCallAST * func = static_cast (sub); func_name = m_session->stringForNode(postfix->expression).trimmed(); ExpressionAST * args = func->arguments; if (args != NULL && args->kind == AST::Kind_InitializerList) { InitializerListAST * list = static_cast (args); int arg_count = list->clauses->count(); for (int inx = 0; inx < arg_count; inx ++) { InitializerClauseAST * arg = list->clauses->at(inx)->element; if (inx < 4) func_arg [inx] = m_session->stringForNode(arg).trimmed(); } } } } } } if (func_name != "") { ConnectItem * item = showText (branch, "function call " + func_name); for (int i = 0; i < 4; i ++) if (i < func_arg_count) showText (item, "argument " + func_arg [i]); } } void ConnectWidget::showStatements (QTreeWidgetItem * branch, AST * ast) { if (ast != NULL && ast->kind == AST::Kind_CompoundStatement) { CompoundStatementAST * comp = static_cast (ast); if (comp->statements != NULL) { const ListNode * it = comp->statements->toFront(); const ListNode * end = it; do { showStatement (branch, it->element); it = it->next; } while (it != end); } } } void ConnectWidget::showFunction (ConnectItem * branch, const KDevelop::ClassFunctionDeclaration * decl) { KDevelop::DUContext * context = NULL; KDevelop::DUContext * above = decl->context (); foreach (KDevelop::DUContext * child, above->childContexts()) if (child->owner() == decl) context = child; if (context) { branch->cachedContext = context; KDevelop::RangeInRevision r = context->range(); KTextEditor::Range t = context->transformFromLocalRevision (r).textRange(); QString src = m_doc->textDocument()->text(t); // from kdevelop/languages/cpp/cppduchain/expressionparser.cpp ParseSession session; Control control; Cpp::DumpChain dumper; Parser parser (& control); QByteArray source = src.toAscii (); session.setContentsAndGenerateLocationTable (tokenizeFromByteArray (source)); AST * ast = parser.parseStatement (&session); if (ast != NULL) { #if 0 kDebug () << "===== AST:"; // DumpChain uses debug area 9007 dumper.dump (ast, &session); #endif m_session = & session; showStatements (branch, ast); m_session = NULL; } } } #endif /* ----------------------------------------------------------------------- */ const QString initFunc = "initConnections"; void ConnectWidget::showInitFunc (ConnectItem * branch, const KDevelop::Declaration * decl) { const KDevelop::ClassFunctionDeclaration * func = dynamic_cast (decl); if (func != NULL && func->identifier().toString() == initFunc) { ConnectItem * item = new ConnectItem (); branch->addChild (item); branch->init = item; item->setIcon (0, KDevelop::DUChainUtils::iconForDeclaration (decl)); item->setText (0, decl->toString()); #ifdef PARSER showFunction (item, func); #endif } } /* ----------------------------------------------------------------------- */ void ConnectWidget::showSignal (QTreeWidgetItem * branch, const KDevelop::Declaration * decl) { const KDevelop::ClassFunctionDeclaration * func = dynamic_cast (decl); if (func != NULL && func->isSignal ()) { ConnectItem * item = new ConnectItem (); item->kind = SignalNode; item->id = decl->identifier().toString(); item->cachedDecl = decl; branch->addChild (item); item->setIcon (0, KDevelop::DUChainUtils::iconForDeclaration (decl)); item->setText (0, decl->toString()); } } void ConnectWidget::showSignals (QTreeWidgetItem * branch, const KDevelop::Declaration * cls_decl) { // show signals from class and base classes KDevelop::DUContext * cls_context = cls_decl->internalContext (); if (cls_context != NULL) { QVector list = cls_context->localDeclarations (); foreach (const KDevelop::Declaration * sub, list) { showSignal (branch, sub); } foreach (const KDevelop::DUContext::Import & import, cls_context->importedParentContexts()) { KDevelop::DUContext* baseContext = import.context (m_topContext); if (baseContext && baseContext->type() == KDevelop::DUContext::Class) { KDevelop::Declaration * baseClassDeclaration = baseContext->owner(); if (baseClassDeclaration) { // Add the base class showSignals (branch, baseClassDeclaration); } } } } } void ConnectWidget::showItem (QTreeWidgetItem * branch, const KDevelop::Declaration * decl) { // show member declarations which are pointers to classes if (decl != NULL) { QString id = decl->identifier().toString(); QString txt = ""; KDevelop::AbstractType::Ptr type = decl->abstractType(); if (type) { KDevelop::PointerType::Ptr ptr_type = type.cast(); if (ptr_type) { KDevelop::AbstractType::Ptr base_type = ptr_type->baseType(); if (base_type) { KDevelop::StructureType::Ptr cls_type = base_type.cast(); if (cls_type) { txt = " : pointer to " + cls_type->toString (); KDevelop::Declaration * cls_decl = cls_type->declaration (m_topContext); if (cls_decl) { ConnectItem * item = new ConnectItem (); item->kind = FieldNode; item->id = id; item->cachedDecl = decl; branch->addChild (item); item->setIcon (0, KDevelop::DUChainUtils::iconForDeclaration (decl)); item->setText (0, id + txt); item->setToolTip (0, decl->comment()); showSignals (item, cls_decl); } } } } } } } /* ----------------------------------------------------------------------- */ void ConnectWidget::showDecl (QTreeWidgetItem * branch, const KDevelop::Declaration * decl, bool nested) { if (decl != NULL) { ConnectItem * item = new ConnectItem (); if (branch == NULL) m_tree->addTopLevelItem (item); else branch->addChild (item); item->setIcon (0, KDevelop::DUChainUtils::iconForDeclaration (decl)); item->setText (0, decl->toString()); // item->setToolTip (0, decl->comment()); // from kdevplatform/plugins/classbrowser/classmodelnode.cpp, ClassNode::updateClassDeclarations() KDevelop::DUContext * context = decl->internalContext (); if (context != NULL) { KDevelop::DUContext::ContextType type = context->type (); if (type == KDevelop::DUContext::Class) { item->kind = ClassNode; item->id = decl->identifier().toString(); // !? item->cachedDecl = decl; QVector list = context->localDeclarations (); foreach (const KDevelop::Declaration * sub, list) { showItem (item, sub); if (! nested) showInitFunc (item, sub); } // from kdevplatform/plugins/classbrowser/classmodelnode.cpp, BaseClassesFolderNode::populateNode() foreach (const KDevelop::DUContext::Import & import, context->importedParentContexts()) { KDevelop::DUContext* baseContext = import.context (decl->topContext()); if (baseContext && baseContext->type() == KDevelop::DUContext::Class) { KDevelop::Declaration * baseClassDeclaration = baseContext->owner(); if (baseClassDeclaration) { // Add the base class. showDecl (item, baseClassDeclaration, true); } } } } if (type == KDevelop::DUContext::Global || type == KDevelop::DUContext::Namespace) { foreach (KDevelop::DUContext * child, context->childContexts()) showDecl (item, child->owner()); } } } } /* ----------------------------------------------------------------------- */ void ConnectWidget::display () { m_tree->clear (); m_doc = NULL; m_topContext = NULL; KDevelop::DUChainReadLocker lock (KDevelop::DUChain::lock()); KDevelop::IDocument* doc = KDevelop::ICore::self()->documentController()->activeDocument(); if (doc && doc->textDocument() && doc->textDocument()->activeView()) { KDevelop::TopDUContext* topContext = KDevelop::DUChainUtils::standardContextForUrl (doc->url()); if (topContext != NULL) { m_doc = doc; m_topContext = topContext; foreach (KDevelop::DUContext * child, topContext->childContexts()) showDecl (NULL, child->owner ()); } } lock.unlock (); } /* ----------------------------------------------------------------------- */ void ConnectWidget::documentActivated (KDevelop::IDocument * doc) { display (); } void ConnectWidget::documentClosed (KDevelop::IDocument * doc) { display (); } /* ----------------------------------------------------------------------- */ } // end of namespace #include "connect.moc"