diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | 114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch) | |
tree | acaf47eb0fa12142d3896416a69e74cbf5a72242 /parts/classview | |
download | tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'parts/classview')
-rw-r--r-- | parts/classview/Makefile.am | 27 | ||||
-rw-r--r-- | parts/classview/README.dox | 53 | ||||
-rw-r--r-- | parts/classview/classtooldlg.cpp | 373 | ||||
-rw-r--r-- | parts/classview/classtooldlg.h | 98 | ||||
-rw-r--r-- | parts/classview/classtoolwidget.cpp | 159 | ||||
-rw-r--r-- | parts/classview/classtoolwidget.h | 41 | ||||
-rw-r--r-- | parts/classview/classtreebase.cpp | 637 | ||||
-rw-r--r-- | parts/classview/classtreebase.h | 242 | ||||
-rw-r--r-- | parts/classview/classviewpart.cpp | 279 | ||||
-rw-r--r-- | parts/classview/classviewpart.h | 99 | ||||
-rw-r--r-- | parts/classview/classviewwidget.cpp | 1295 | ||||
-rw-r--r-- | parts/classview/classviewwidget.h | 414 | ||||
-rw-r--r-- | parts/classview/digraphview.cpp | 414 | ||||
-rw-r--r-- | parts/classview/digraphview.h | 66 | ||||
-rw-r--r-- | parts/classview/hierarchydlg.cpp | 276 | ||||
-rw-r--r-- | parts/classview/hierarchydlg.h | 61 | ||||
-rw-r--r-- | parts/classview/kdevclassview.desktop | 82 | ||||
-rw-r--r-- | parts/classview/kdevclassview.rc | 20 | ||||
-rw-r--r-- | parts/classview/navigator.cpp | 539 | ||||
-rw-r--r-- | parts/classview/navigator.h | 91 | ||||
-rw-r--r-- | parts/classview/viewcombos.cpp | 214 | ||||
-rw-r--r-- | parts/classview/viewcombos.h | 84 |
22 files changed, 5564 insertions, 0 deletions
diff --git a/parts/classview/Makefile.am b/parts/classview/Makefile.am new file mode 100644 index 00000000..de0de499 --- /dev/null +++ b/parts/classview/Makefile.am @@ -0,0 +1,27 @@ +# Here resides the class view part. + +INCLUDES = -I$(top_srcdir)/lib/compat -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/interfaces/extensions \ + -I$(top_srcdir)/lib/interfaces/external -I$(top_srcdir)/lib/util -I$(top_srcdir)/lib/widgets $(all_includes) + +kde_module_LTLIBRARIES = libkdevclassview.la +libkdevclassview_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN) +libkdevclassview_la_LIBADD = $(top_builddir)/lib/libkdevelop.la $(top_builddir)/lib/widgets/libkdevwidgets.la $(LIB_KHTML) $(top_builddir)/lib/interfaces/extensions/libkdevextensions.la + +libkdevclassview_la_SOURCES = classviewpart.cpp classviewwidget.cpp \ + digraphview.cpp hierarchydlg.cpp navigator.cpp viewcombos.cpp + +METASOURCES = AUTO + +servicedir = $(kde_servicesdir) +service_DATA = kdevclassview.desktop + +rcdir = $(kde_datadir)/kdevclassview +rc_DATA = kdevclassview.rc + + +QTDIR = /home/bernd/kdesrc/qt-copy + +foo: digraphview.cpp digraphview.h + $(QTDIR)/bin/moc digraphview.h > digraphview.moc ; \ + g++ digraphview.cpp -I$(QTDIR)/include -L$(QTDIR)/lib -L/usr/X11R6/lib -lqt -lX11 -lXext -o foo +noinst_HEADERS = viewcombos.h navigator.h diff --git a/parts/classview/README.dox b/parts/classview/README.dox new file mode 100644 index 00000000..78049424 --- /dev/null +++ b/parts/classview/README.dox @@ -0,0 +1,53 @@ +/** \class ClassViewPart +Put a brief description here, the brief description ends at the first dot. +Put a more detailed description of your part in these lines. It can span +over several lines. You can even use some html commands in these lines like: +<code>This is code</code>, html links <a href="http://somelocation">link text</a>, +and images. + +\authors <a href="mailto:$EMAIL$">$AUTHOR$</a> +\authors <a href="mailto:2nd author AT provider.com">2nd author full name</a> +... +\authors <a href="mailto:nth author AT provider.com">nth author full name</a> + +\maintainer <a href="mailto:$EMAIL$">$AUTHOR$</a> +\maintainer <a href="mailto:2nd maintainer AT provider.com">2nd maintainer full name</a> +... +\maintainer <a href="mailto:nth maintainer AT provider.com">nth maintainer full name</a> + +\feature Describe the first feature +\feature Describe the second feature +... +\feature Describe the last feature + +\bug bugs in <a href="http://bugs.kde.org/buglist.cgi?product=kdevelop&component=classview&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&order=Bug+Number">classview component at Bugzilla database</a> +\bug Describe a the 1st bug that you know of, but probably hasn't been reported yet. +.. +\bug Describe a the nth bug that you know of, but probably hasn't been reported yet. + +\requirement Describe a the 1st requirement of your part. +\requirement Describe a the 2nd requirement of your part. +... +\requirement Describe a the nth requirement of your part. + +\todo Describe a the 1st TODO of your part. +\todo Describe a the 2nd TODO of your part. +... +\todo Describe a the nth TODO of your part. + +\faq <b>First frequenly asked question about your part ?</b> Answer. +\faq <b>Second frequenly asked question about your part ?</b> Answer. +... +\faq <b>Last frequenly asked question about your part ?</b> Answer. + +\note First note text. +\note Second note text. +... +\note Last note text. + +\warning First warning text. +\warning Second warning text. +... +\warning Last warning text. + +*/ diff --git a/parts/classview/classtooldlg.cpp b/parts/classview/classtooldlg.cpp new file mode 100644 index 00000000..91ed28fc --- /dev/null +++ b/parts/classview/classtooldlg.cpp @@ -0,0 +1,373 @@ +/*************************************************************************** + * Copyright (C) 1999 by Jonas Nordin * + * [email protected] * + * Copyright (C) 2000-2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "classtooldlg.h" + +#include <qlistbox.h> +#include <qpushbutton.h> +#include <qtooltip.h> +#include <kdialog.h> +#include <kiconloader.h> +#include <klocale.h> + +#include "kdevlanguagesupport.h" +#include "classstore.h" +#include "parsedclass.h" +#include "classviewpart.h" + + +ClassToolDialog::ClassToolDialog( ClassViewPart *part ) + : QWidget(0, "class tool dialog") +{ + currentOperation = ViewNone; + comboAccess = (PIAccess)-1; + currentClass = 0; + m_part = part; + + class_combo = new QComboBox(false, this); + + QPushButton *close_button = new KPushButton(KStdGuiItem::close(), this); + + parents_button = new QToolButton(this); + parents_button->setPixmap( UserIcon("CTparents", KIcon::DefaultState, ClassViewFactory::instance()) ); + parents_button->setToggleButton(true); + parents_button->setFixedSize(parents_button->sizeHint()); + QToolTip::add(parents_button, i18n("Show parents")); + + children_button = new QToolButton(this); + children_button->setPixmap( UserIcon("CTchildren", KIcon::DefaultState, ClassViewFactory::instance()) ); + children_button->setToggleButton(true); + children_button->setFixedSize(children_button->sizeHint()); + QToolTip::add(children_button, i18n("Show children")); + + clients_button = new QToolButton(this); + clients_button->setPixmap( UserIcon("CTclients", KIcon::DefaultState, ClassViewFactory::instance()) ); + clients_button->setToggleButton(true); + clients_button->setFixedSize(clients_button->sizeHint()); + QToolTip::add(clients_button, i18n("Show clients")); + + suppliers_button = new QToolButton(this); + suppliers_button->setPixmap( UserIcon("CTsuppliers", KIcon::DefaultState, ClassViewFactory::instance()) ); + suppliers_button->setToggleButton(true); + suppliers_button->setFixedSize(suppliers_button->sizeHint()); + QToolTip::add(suppliers_button, i18n("Show suppliers")); + + methods_button = new QToolButton(this); + methods_button->setPixmap( UserIcon("CVpublic_meth", KIcon::DefaultState, ClassViewFactory::instance()) ); + methods_button->setToggleButton(true); + methods_button->setFixedSize(methods_button->sizeHint()); + QToolTip::add(methods_button, i18n("Show methods")); + + attributes_button = new QToolButton(this); + attributes_button->setPixmap( UserIcon("CVpublic_var", KIcon::DefaultState, ClassViewFactory::instance()) ); + attributes_button->setToggleButton(true); + attributes_button->setFixedSize(attributes_button->sizeHint()); + QToolTip::add(attributes_button, i18n("Show attributes")); + + access_combo = new QComboBox(false, this, "access combo"); + access_combo->setMinimumWidth(100); + access_combo->setSizeLimit(10); + access_combo->insertItem(i18n("member access","All")); + access_combo->insertItem(i18n("member access","Public")); + access_combo->insertItem(i18n("member access","Protected")); + access_combo->insertItem(i18n("member access","Private")); + access_combo->insertItem(i18n("member access","Package")); + + class_tree = new ClassToolWidget(part, this); + // classTree->setMinimumSize( 500, 400 ); + + QVBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint()); + QHBoxLayout *firstrowLayout = new QHBoxLayout(); + QHBoxLayout *secondrowLayout = new QHBoxLayout(); + layout->addLayout(firstrowLayout); + layout->addLayout(secondrowLayout); + + firstrowLayout->addWidget(class_combo, 1); + firstrowLayout->addWidget(close_button, 0); + + secondrowLayout->addWidget(parents_button); + secondrowLayout->addWidget(children_button); + secondrowLayout->addWidget(clients_button); + secondrowLayout->addWidget(suppliers_button); + secondrowLayout->addStretch(); + secondrowLayout->addWidget(methods_button); + secondrowLayout->addWidget(attributes_button); + secondrowLayout->addWidget(access_combo); + + layout->addWidget(class_tree, 10); + + connect( class_combo, SIGNAL(activated(const QString&)), + this, SLOT(slotClassComboChoice(const QString&)) ); + connect( close_button, SIGNAL(clicked()), + this, SLOT(slotClose()) ); + connect( access_combo, SIGNAL(activated(const QString&)), + this, SLOT(slotAccessComboChoice(const QString&)) ); + connect( parents_button, SIGNAL(clicked()), SLOT(viewParents())); + connect( children_button, SIGNAL(clicked()), SLOT(viewChildren())); + connect( clients_button, SIGNAL(clicked()), SLOT(viewClients())); + connect( suppliers_button, SIGNAL(clicked()), SLOT(viewSuppliers())); + connect( methods_button, SIGNAL(clicked()), SLOT(viewMethods())); + connect( attributes_button, SIGNAL(clicked()), SLOT(viewAttributes())); + + connect( part, SIGNAL(setLanguageSupport(KDevLanguageSupport*)), + this, SLOT(setLanguageSupport(KDevLanguageSupport*)) ); + + m_part->registerClassToolDialog(this); +} + + +ClassToolDialog::~ClassToolDialog() +{ + m_part->unregisterClassToolDialog(this); +} + + +void ClassToolDialog::setLanguageSupport(KDevLanguageSupport *ls) +{ + if (ls) { + disconnect(ls, 0, this, 0); + connect(ls, SIGNAL(updatedSourceInfo()), this, SLOT(refresh())); + } else + refresh(); + + currentOperation = ViewNone; +} + + +void ClassToolDialog::setClassName(const QString &name) +{ + if ( class_combo->count() == 0 ) refresh(); + + QListBox *lb = class_combo->listBox(); + + for (int i=0; i < (int)lb->count(); ++i) + if (lb->text(i) == name) { + class_combo->setCurrentItem(i); + break; + } + + if (!name.isEmpty()) + currentClass = m_part->classStore()->getClassByName(name); + else + currentClass = 0; +} + + +void ClassToolDialog::viewNone() +{ + currentOperation = ViewNone; + refresh(); +} + + +/** View the parents of the current class. */ +void ClassToolDialog::viewParents() +{ + currentOperation = ViewParents; + refresh(); +} + + +/** View the children of the current class. */ +void ClassToolDialog::viewChildren() +{ + currentOperation = ViewChildren; + refresh(); +} + + +/** View all classes that has this class as an attribute. */ +void ClassToolDialog::viewClients() +{ + currentOperation = ViewClients; + refresh(); +} + + +/** View all classes that this class has as attributes. */ +void ClassToolDialog::viewSuppliers() +{ + currentOperation = ViewSuppliers; + refresh(); +} + + +/** View methods in this class and parents. */ +void ClassToolDialog::viewMethods() +{ + currentOperation = ViewMethods; + refresh(); +} + + +/** View attributes in this class and parents. */ +void ClassToolDialog::viewAttributes() +{ + currentOperation = ViewAttributes; + refresh(); +} + + +void ClassToolDialog::slotAccessComboChoice(const QString &str) +{ + if( str == i18n("member access","All") ) + comboAccess = (PIAccess)-1; + else if( str == i18n("member access","Public") ) + comboAccess = PIE_PUBLIC; + else if( str == i18n("member access","Protected") ) + comboAccess = PIE_PROTECTED; + else if( str == i18n("member access","Private") ) + comboAccess = PIE_PRIVATE; + else if( str == i18n("member access","Package") ) + comboAccess = PIE_PACKAGE; + + // Update the view if the choice affected the data. + if (currentOperation == ViewMethods || currentOperation == ViewAttributes) + buildTree(); +} + + +void ClassToolDialog::slotClose() +{ + delete this; + // QTimer::singleShot(0, this, SLOT(delayedClose())); +} + + +void ClassToolDialog::delayedClose() +{ + delete this; +} + + +void ClassToolDialog::slotClassComboChoice(const QString &str) +{ + setClassName(str); + refresh(); +} + + +void ClassToolDialog::refresh() +{ + // Clear the combo box and fill it with the new items. + // Try to select the previously selected class + + QString oldName = class_combo->currentText(); + + class_combo->clear(); + QStringList list = m_part->classStore()->getSortedClassNameList(); + class_combo->insertStringList(list); + setClassName(oldName); + + // Rebuild the tree and caption/button state + buildTree(); +} + + +/** Change the caption depending on the current operation. */ +void ClassToolDialog::updateCaptionAndButtons() +{ + QString caption; + QToolButton *button; + + switch (currentOperation) + { + case ViewParents: + button = parents_button; + caption = i18n("Parents"); + break; + case ViewChildren: + button = children_button; + caption = i18n("Children"); + break; + case ViewClients: + button = clients_button; + caption = i18n("Clients"); + break; + case ViewSuppliers: + button = suppliers_button; + caption = i18n("Suppliers"); + break; + case ViewMethods: + button = methods_button; + caption = i18n("%1 Methods").arg(access_combo->currentText()); + break; + case ViewAttributes: + button = attributes_button; + caption = i18n("%1 Attributes").arg(access_combo->currentText()); + break; + default: + button = 0; + caption = i18n("Class Tool Dialog"); + break; + } + + parents_button->setOn(false); + children_button->setOn(false); + clients_button->setOn(false); + suppliers_button->setOn(false); + methods_button->setOn(false); + attributes_button->setOn(false); + + if (button) { + button->setOn(true); + setCaption(i18n("%1 of Class %2").arg(caption).arg(currentClass->name())); + } else + setCaption(caption); +} + + +void ClassToolDialog::buildTree() +{ + if (!currentClass) + currentOperation = ViewNone; + + updateCaptionAndButtons(); + + class_tree->clear(); + + switch (currentOperation) + { + case ViewParents: + class_tree->insertClassAndClasses(currentClass, currentClass->parents); + break; + case ViewChildren: + { + QValueList<ParsedClass*> list = m_part->classStore()->getClassesByParent(currentClass->name()); + class_tree->insertClassAndClasses(currentClass, list); + } + break; + case ViewClients: + { + QValueList<ParsedClass*> list = m_part->classStore()->getClassClients(currentClass->name()); + class_tree->insertClassAndClasses(currentClass, list); + } + break; + case ViewSuppliers: + { + QValueList<ParsedClass*> list = m_part->classStore()->getClassSuppliers(currentClass->name()); + class_tree->insertClassAndClasses(currentClass, list); + } + break; + case ViewMethods: + class_tree->insertAllClassMethods(currentClass, comboAccess); + break; + case ViewAttributes: + class_tree->insertAllClassAttributes(currentClass, comboAccess); + break; + default: + break; + } +} + +#include "classtooldlg.moc" diff --git a/parts/classview/classtooldlg.h b/parts/classview/classtooldlg.h new file mode 100644 index 00000000..1ab8b5c1 --- /dev/null +++ b/parts/classview/classtooldlg.h @@ -0,0 +1,98 @@ +/*************************************************************************** + * Copyright (C) 1999 by Jonas Nordin * + * [email protected] * + * Copyright (C) 2000-2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _CLASSTOOLDLG_H_ +#define _CLASSTOOLDLG_H_ + +#include <qdialog.h> +#include <qlabel.h> +#include <qtoolbutton.h> +#include <qcombobox.h> +#include <qlayout.h> +#include "classtoolwidget.h" +#include "parseditem.h" + +class ClassViewPart; +class ClassStore; +class ParsedClass; + + +class ClassToolDialog : public QWidget +{ + Q_OBJECT + +public: + enum Operations { ViewParents, ViewChildren, ViewClients, ViewSuppliers, + ViewMethods, ViewAttributes, ViewNone }; + + ClassToolDialog( ClassViewPart *part ); + ~ClassToolDialog(); + + void setClassName(const QString &name); + +public slots: + + /** View nothing. */ + void viewNone(); + /** View the parents of the current class. */ + void viewParents(); + /** View the children of the current class. */ + void viewChildren(); + /** View all classes that has this class as an attribute. */ + void viewClients(); + /** View all classes that this class has as attributes. */ + void viewSuppliers(); + /** View methods in this class and parents. */ + void viewMethods(); + /** View attributes in this class and parents. */ + void viewAttributes(); + +private slots: + void setLanguageSupport(KDevLanguageSupport *ls); + void refresh(); + + void delayedClose(); + void slotClose(); + void slotAccessComboChoice(const QString &str); + void slotClassComboChoice(const QString &str); + + +private: + void updateCaptionAndButtons(); + void buildTree(); + + ClassToolWidget *class_tree; + QComboBox *class_combo; + + QToolButton *parents_button; + QToolButton *children_button; + QToolButton *clients_button; + QToolButton *suppliers_button; + QToolButton *methods_button; + QToolButton *attributes_button; + QComboBox *access_combo; + + /** Store that holds all classes in the system. */ + ClassStore *m_store; + KDevLanguageSupport *m_ls; + ClassViewPart *m_part; + + /** The class we are currently viewing. */ + ParsedClass *currentClass; + /** The current exportstatus selected in the combo. */ + PIAccess comboAccess; + /** Stores what operation the user selected last. */ + Operations currentOperation; +}; + +#endif diff --git a/parts/classview/classtoolwidget.cpp b/parts/classview/classtoolwidget.cpp new file mode 100644 index 00000000..f800bd15 --- /dev/null +++ b/parts/classview/classtoolwidget.cpp @@ -0,0 +1,159 @@ +/*************************************************************************** + * Copyright (C) 1999 by Jonas Nordin * + * [email protected] * + * Copyright (C) 2000-2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "classtoolwidget.h" + +#include <kconfig.h> +#include <klocale.h> +#include <kglobal.h> +#include <kpopupmenu.h> +#include "classstore.h" + + +ClassToolWidget::ClassToolWidget(ClassViewPart *part, QWidget *parent) + : ClassTreeBase(part, parent, "class tool widget") +{} + + +ClassToolWidget::~ClassToolWidget() +{} + + +KPopupMenu *ClassToolWidget::createPopup() +{ + KPopupMenu *popup = contextItem? contextItem->createPopup() : 0; + if (!popup) { + popup = new KPopupMenu(this); + popup->insertTitle(i18n("Class Tool")); + } + + return popup; +} + + +void ClassToolWidget::insertClassAndClasses(ParsedClass *parsedClass, QValueList<ParsedClass*> classList) +{ + ClassTreeItem *root = new ClassTreeClassItem(this, 0, parsedClass); + + ClassTreeItem *lastItem = 0; + + QValueList<ParsedClass*>::ConstIterator it; + for (it = classList.begin(); it != classList.end(); ++it) { + lastItem = new ClassTreeClassItem(root, lastItem, *it); + lastItem->setExpandable(false); + } + + if (!root->firstChild()) + root->setExpandable(false); + else + root->setOpen(true); +} + + +void ClassToolWidget::insertClassAndClasses(ParsedClass *parsedClass, const QPtrList<ParsedParent> &parentList) +{ + ClassTreeItem *root = new ClassTreeClassItem(this, 0, parsedClass); + + ClassTreeItem *lastItem = 0; + + QPtrListIterator<ParsedParent> it(parentList); + for (; it.current(); ++it) { + ParsedClass *parentClass = m_part->classStore()->getClassByName((*it)->name()); + lastItem = new ClassTreeClassItem(root, lastItem, parentClass); + lastItem->setExpandable(false); + } + + if (!root->firstChild()) + root->setExpandable(false); + else + root->setOpen(true); +} + + +void ClassToolWidget::addClassAndAttributes(ParsedClass *parsedClass, PIAccess filter, ClassTreeItem **lastItem) +{ + *lastItem = new ClassTreeClassItem(this, *lastItem, parsedClass); + + ClassTreeItem *ilastItem = 0; + + QValueList<ParsedAttribute*> attrList = parsedClass->getSortedAttributeList(); + QValueList<ParsedAttribute*>::ConstIterator it; + for (it = attrList.begin(); it != attrList.end(); ++it) { + if (filter == (PIAccess)-1 || filter == (*it)->access()) + ilastItem = new ClassTreeAttrItem(*lastItem, ilastItem, *it); + } + + if (!(*lastItem)->firstChild()) + (*lastItem)->setExpandable(false); + else + (*lastItem)->setOpen(true); +} + + +void ClassToolWidget::addClassAndMethods(ParsedClass *parsedClass, PIAccess filter, ClassTreeItem **lastItem) +{ + *lastItem = new ClassTreeClassItem(this, *lastItem, parsedClass); + + ClassTreeItem *ilastItem = 0; + + QValueList<ParsedMethod*> methodList = parsedClass->getSortedMethodList(); + QValueList<ParsedMethod*>::ConstIterator it; + for (it = methodList.begin(); it != methodList.end(); ++it) { + if (filter == (PIAccess)-1 || filter == (*it)->access()) + ilastItem = new ClassTreeMethodItem(*lastItem, ilastItem, *it); + } + + if (!(*lastItem)->firstChild()) + (*lastItem)->setExpandable(false); + else + (*lastItem)->setOpen(true); +} + + +void ClassToolWidget::insertAllClassMethods(ParsedClass *parsedClass, PIAccess filter) +{ + ClassTreeItem *lastItem = 0; + + // First treat all parents. + for ( ParsedParent *pParent = parsedClass->parents.first(); + pParent != 0; + pParent = parsedClass->parents.next() ) + { + ParsedClass *parentClass = m_part->classStore()->getClassByName(pParent->name()); + if (parentClass) + addClassAndMethods(parentClass, filter, &lastItem); + } + + // Add the current class + addClassAndMethods(parsedClass, filter, &lastItem); +} + + +void ClassToolWidget::insertAllClassAttributes(ParsedClass *parsedClass, PIAccess filter) +{ + ClassTreeItem *lastItem = 0; + // First treat all parents. + for ( ParsedParent *pParent = parsedClass->parents.first(); + pParent != 0; + pParent = parsedClass->parents.next() ) + { + ParsedClass *parentClass = m_part->classStore()->getClassByName(pParent->name()); + if (parentClass) + addClassAndAttributes(parentClass, filter, &lastItem); + } + + // Add the current class + addClassAndAttributes(parsedClass, filter, &lastItem); +} + +#include "classtoolwidget.moc" diff --git a/parts/classview/classtoolwidget.h b/parts/classview/classtoolwidget.h new file mode 100644 index 00000000..75119e8f --- /dev/null +++ b/parts/classview/classtoolwidget.h @@ -0,0 +1,41 @@ +/*************************************************************************** + * Copyright (C) 1999 by Jonas Nordin * + * [email protected] * + * Copyright (C) 2000-2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _CLASSTOOLWIDGET_H_ +#define _CLASSTOOLWIDGET_H_ + +#include "classtreebase.h" + + +class ClassToolWidget : public ClassTreeBase +{ + Q_OBJECT + +public: + ClassToolWidget(ClassViewPart *part, QWidget *parent=0); + ~ClassToolWidget(); + + void insertClassAndClasses(ParsedClass *parsedClass, QValueList<ParsedClass*> classList); + void insertClassAndClasses(ParsedClass *parsedClass, const QPtrList<ParsedParent> &parentList); + void insertAllClassMethods(ParsedClass *parsedClass, PIAccess filter); + void insertAllClassAttributes(ParsedClass *parsedClass, PIAccess filter); + +protected: + virtual KPopupMenu *createPopup(); + +private: + void addClassAndAttributes(ParsedClass *parsedClass, PIAccess filter, ClassTreeItem **lastItem); + void addClassAndMethods(ParsedClass *parsedClass, PIAccess filter, ClassTreeItem **lastItem); +}; + +#endif diff --git a/parts/classview/classtreebase.cpp b/parts/classview/classtreebase.cpp new file mode 100644 index 00000000..f5c0f4b9 --- /dev/null +++ b/parts/classview/classtreebase.cpp @@ -0,0 +1,637 @@ +/*************************************************************************** + * Copyright (C) 1999 by Jonas Nordin * + * [email protected] * + * Copyright (C) 2000-2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "classtreebase.h" + +#include <qtooltip.h> +#include <qheader.h> +#include <qregexp.h> +#include <kdebug.h> +#include <kconfig.h> +#include <kpopupmenu.h> +#include <klocale.h> +#include <kiconloader.h> + +#include "kdevcore.h" +#include "kdevlanguagesupport.h" +#include "kdevmainwindow.h" +#include "kdevpartcontroller.h" +#include "classstore.h" + +#include "classviewpart.h" +#include "classtooldlg.h" + +KPopupMenu *ClassTreeItem::createPopup() +{ + if (!m_item || m_item->itemType() == PIT_SCOPE) + return 0; + + KDevLanguageSupport::Features features = classTree()->m_part->languageSupport()->features(); + + KPopupMenu *popup = new KPopupMenu(); + if (features & KDevLanguageSupport::Declarations) + popup->insertItem( i18n("Go to Declaration"), classTree(), SLOT(slotGotoDeclaration()) ); + if (m_item->itemType() == PIT_METHOD) + popup->insertItem( i18n("Go to Definition"), classTree(), SLOT(slotGotoImplementation()) ); + + QString title; + switch(m_item->itemType()) { + case PIT_CLASS: + { + title = i18n("Class"); + bool hasAddMethod = features & KDevLanguageSupport::AddMethod; + bool hasAddAttribute = features & KDevLanguageSupport::AddAttribute; + if (hasAddMethod) + popup->insertItem( i18n("Add Method..."), classTree(), SLOT(slotAddMethod())); + if (hasAddAttribute) + popup->insertItem( i18n("Add Attribute..."), classTree(), SLOT(slotAddAttribute())); + popup->insertSeparator(); + popup->insertItem( i18n("Parent Classes..."), classTree(), SLOT(slotClassBaseClasses())); + popup->insertItem( i18n("Child Classes..."), classTree(), SLOT(slotClassDerivedClasses())); + popup->insertItem( i18n("Class Tool..."), classTree(), SLOT(slotClassTool())); + } + break; + case PIT_STRUCT: + title = i18n("Struct"); + break; + case PIT_ATTRIBUTE: + if (m_item->isGlobal()) + title = i18n("Variable"); + else + title = i18n("Attribute"); + break; + case PIT_METHOD: + if (static_cast<ParsedMethod*>(m_item)->isSlot()) + title = i18n("Slot"); + else if (static_cast<ParsedMethod*>(m_item)->isSignal()) + title = i18n("Signal"); + else if (m_item->isGlobal()) + title = i18n("Function"); + else + title = i18n("Method"); + break; + default: + ; + } + popup->insertSeparator(); + popup->insertTitle(title, -1, 0); + + return popup; +} + + +QString ClassTreeItem::scopedText() const +{ + if (m_item) + return m_item->path(); + + return QString::null; +} + + +void ClassTreeItem::getDeclaration(QString *toFile, int *toLine) +{ + if (m_item) { + *toFile = m_item->declaredInFile(); + *toLine = m_item->declaredOnLine(); + } +} + + +void ClassTreeItem::getImplementation(QString *toFile, int *toLine) +{ + if (m_item) { + *toFile = m_item->definedInFile(); + *toLine = m_item->definedOnLine(); + } +} + + +QString ClassTreeItem::text( int ) const +{ + if (m_item) + return m_item->asString(); + return QString::null; +} + + +QString ClassTreeItem::tipText() const +{ + // Purposefully avoid virtual dispatch here + return ClassTreeItem::text(0); +} + + +void ClassTreeOrganizerItem::init() +{ + setExpandable(true); + setPixmap(0, SmallIcon("folder")); +} + + +void ClassTreeScopeItem::init() +{ + setExpandable(true); + setPixmap(0, UserIcon("CVnamespace", KIcon::DefaultState, ClassViewFactory::instance())); +} + + +QString ClassTreeScopeItem::text( int col ) const +{ + if (!m_item) + return QString::null; + if (m_item->name().isEmpty()) + return i18n("Global"); + return ClassTreeItem::text( col ); +} + + +void ClassTreeScopeItem::setOpen(bool o) +{ + if ( !m_item) + return; + + kdDebug(9003) << (o? "Open scope item" : "Close scope item") << endl; + if (o && childCount() == 0) { + + ParsedScopeContainer *pScope = static_cast<ParsedScopeContainer*>(m_item); + ClassTreeItem *lastItem = 0; + + // Ok, this is a hack... + KDevLanguageSupport::Features features = classTree()->m_part->languageSupport()->features(); + + // Add namespaces + QValueList<ParsedScopeContainer*> scopeList = pScope->getSortedScopeList(); + QValueList<ParsedScopeContainer*>::ConstIterator it; + for (it = scopeList.begin(); it != scopeList.end(); ++it) + lastItem = new ClassTreeScopeItem(this, lastItem, *it); + + if (features & KDevLanguageSupport::Classes) { + // Add classes + QValueList<ParsedClass*> classList = pScope->getSortedClassList(); + QValueList<ParsedClass*>::ConstIterator it; + for (it = classList.begin(); it != classList.end(); ++it) + lastItem = new ClassTreeClassItem(this, lastItem, *it); + } + + if (features & KDevLanguageSupport::Structs) { + // Add structs + QValueList<ParsedClass*> structList = pScope->getSortedStructList(); + QValueList<ParsedClass*>::ConstIterator it; + for (it = structList.begin(); it != structList.end(); ++it) + lastItem = new ClassTreeClassItem(this, lastItem, *it, true); + } + + if (features & KDevLanguageSupport::Functions) { + // Add functions + QValueList<ParsedMethod*> methodList = pScope->getSortedMethodList(); + QValueList<ParsedMethod*>::ConstIterator it; + for (it = methodList.begin(); it != methodList.end(); ++it) + lastItem = new ClassTreeMethodItem(this, lastItem, *it); + } + + if (features & KDevLanguageSupport::Variables) { + // Add attributes + QValueList<ParsedAttribute*> attrList = pScope->getSortedAttributeList(); + QValueList<ParsedAttribute*>::ConstIterator it; + for (it = attrList.begin(); it != attrList.end(); ++it) + lastItem = new ClassTreeAttrItem(this, lastItem, *it); + } + + } + + ClassTreeItem::setOpen(o); +} + + +void ClassTreeClassItem::init() +{ + setExpandable(true); + setPixmap(0, UserIcon(m_isStruct ? "CVstruct" : "CVclass", KIcon::DefaultState, ClassViewFactory::instance())); +} + + +void ClassTreeClassItem::setOpen(bool o) +{ + if ( !m_item ) + return; + kdDebug(9003) << (o? "Open class item" : "Close class item") << endl; + if (o && childCount() == 0) { + + ParsedClass *pClass = static_cast<ParsedClass*>(m_item); + ClassTreeItem *lastItem = 0; + + // Add nested classes + QValueList<ParsedClass*> classList = pClass->getSortedClassList(); + QValueList<ParsedClass*>::ConstIterator classIt; + for (classIt = classList.begin(); classIt != classList.end(); ++classIt) + lastItem = new ClassTreeClassItem(this, lastItem, *classIt); + + // Add nested structs + QValueList<ParsedClass*> structList = pClass->getSortedStructList(); + QValueList<ParsedClass*>::ConstIterator structIt; + for (structIt = structList.begin(); structIt != structList.end(); ++structIt) + lastItem = new ClassTreeClassItem(this, lastItem, *structIt, true); + + // Add methods + QValueList<ParsedMethod*> methodList = pClass->getSortedMethodList(); + QValueList<ParsedMethod*>::ConstIterator methodIt; + for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) + lastItem = new ClassTreeMethodItem(this, lastItem, *methodIt); + + // Add slots + QValueList<ParsedMethod*> slotList = pClass->getSortedSlotList(); + QValueList<ParsedMethod*>::ConstIterator slotIt; + for (slotIt = slotList.begin(); slotIt != slotList.end(); ++slotIt) + lastItem = new ClassTreeMethodItem(this, lastItem, *slotIt); + + // Add signals + QValueList<ParsedMethod*> signalList = pClass->getSortedSignalList(); + QValueList<ParsedMethod*>::ConstIterator signalIt; + for (signalIt = signalList.begin(); signalIt != signalList.end(); ++signalIt) + lastItem = new ClassTreeMethodItem(this, lastItem, *signalIt); + + // Add attributes + QValueList<ParsedAttribute*> attrList = pClass->getSortedAttributeList(); + QValueList<ParsedAttribute*>::ConstIterator attrIt; + for (attrIt = attrList.begin(); attrIt != attrList.end(); ++attrIt) + lastItem = new ClassTreeAttrItem(this, lastItem, *attrIt); + + } + + ClassTreeItem::setOpen(o); +} + +ClassTreeMethodItem::ClassTreeMethodItem(ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedMethod *parsedMethod) + : ClassTreeItem(parent, lastSibling, parsedMethod) +{ + QString icon; + + if ( !parsedMethod ) + return; + + if (parsedMethod->isSignal()) + icon = "CVpublic_signal"; + else if (parsedMethod->isSlot()) { + if (parsedMethod->isPublic()) + icon = "CVpublic_slot"; + else if (parsedMethod->isProtected()) + icon = "CVprotected_slot"; + else + icon = "CVprivate_slot"; + } + else if (parsedMethod->isPublic()) + icon = "CVpublic_meth"; + else if (parsedMethod->isProtected()) + icon = "CVprotected_meth"; + else if (parsedMethod->isPrivate()) + icon = "CVprivate_meth"; + else if (parsedMethod->isPackage()) + icon = "CVpackage_meth"; + else + icon = "CVglobal_meth"; + + setPixmap(0, UserIcon(icon, KIcon::DefaultState, ClassViewFactory::instance())); +} + +QString ClassTreeMethodItem::text( int ) const +{ + QString str; + + if ( !m_item ) + return QString::null; + + ParsedMethod* method = static_cast<ParsedMethod*>(m_item); + + str = method->name(); + + if( method->arguments.count() > 0 ) { + str += "( "; + for ( ParsedArgument *arg = method->arguments.first(); arg != NULL; arg = method->arguments.next() ) { + if ( arg != method->arguments.getFirst() ) + str += ", "; + + str += arg->toString(); + } + str += " )"; + } else { + str += "()"; + } + + if( method->isConst() ) + str += " const"; + + return str; +} + + +ClassTreeAttrItem::ClassTreeAttrItem(ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedAttribute *parsedAttr) + : ClassTreeItem(parent, lastSibling, parsedAttr) +{ + QString icon; + + if ( !parsedAttr ) + return; + + if (parsedAttr->isPublic()) + icon = "CVpublic_var"; + else if (parsedAttr->isProtected()) + icon = "CVprotected_var"; + else if (parsedAttr->isPrivate()) + icon = "CVprivate_var"; + else if (parsedAttr->isPackage()) + icon = "CVpackage_var"; + else + icon = "CVglobal_var"; + + setPixmap(0, UserIcon(icon, KIcon::DefaultState, ClassViewFactory::instance())); +} + + +QString ClassTreeAttrItem::text( int ) const +{ + if ( !m_item ) + return QString::null; + return m_item->name(); +} + +ClassTreeScriptItem::ClassTreeScriptItem(ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedScript *parsedScript) + : ClassTreeItem(parent, lastSibling, parsedScript) +{ + QString icon; + + if ( !parsedScript ) + return; + + setExpandable(true); + + //need a icon for scripts + icon = "CVpublic_var"; + setPixmap(0, UserIcon(icon, KIcon::DefaultState, ClassViewFactory::instance())); +} + + +QString ClassTreeScriptItem::text( int ) const +{ + if ( !m_item ) + return QString::null; + return m_item->name(); +} + +void ClassTreeScriptItem::setOpen(bool o) +{ + if ( !m_item ) + return; + kdDebug(9003) << (o? "Open script item" : "Close script item") << endl; + if (o && childCount() == 0) { + + ParsedScript *pClass = static_cast<ParsedScript*>(m_item); + ClassTreeItem *lastItem = 0; + + // Add methods + QValueList<ParsedMethod*> methodList = pClass->getSortedMethodList(); + QValueList<ParsedMethod*>::ConstIterator methodIt; + for (methodIt = methodList.begin(); methodIt != methodList.end(); ++methodIt) + lastItem = new ClassTreeMethodItem(this, lastItem, *methodIt); + + // Add attributes + QValueList<ParsedAttribute*> attrList = pClass->getSortedAttributeList(); + QValueList<ParsedAttribute*>::ConstIterator attrIt; + for (attrIt = attrList.begin(); attrIt != attrList.end(); ++attrIt) + lastItem = new ClassTreeAttrItem(this, lastItem, *attrIt); + + } + + ClassTreeItem::setOpen(o); +} + + +class ClassToolTip : public QToolTip +{ +public: + ClassToolTip( QWidget *parent ) + : QToolTip(parent) + {} + +protected: + void maybeTip(const QPoint &p); +}; + + +void ClassToolTip::maybeTip(const QPoint &p) +{ + ClassTreeBase *ctw = static_cast<ClassTreeBase*>(parentWidget()); + + QListViewItem *item = ctw->itemAt(p); + QRect r = ctw->itemRect(item); + + if (item && r.isValid()) { + ClassTreeItem *ctitem = static_cast<ClassTreeItem*>(item); + QString str = ctitem->tipText(); + if (!str.isEmpty()) + tip(r, str); + } +} + + +ClassTreeBase::ClassTreeBase(ClassViewPart *part, QWidget *parent, const char *name) + : KListView(parent, name) +{ + setFocusPolicy(ClickFocus); + setRootIsDecorated(true); + setResizeMode(QListView::LastColumn); + setSorting(-1); + header()->hide(); + addColumn(QString::null); + + (void) new ClassToolTip(this); + + connect( this, SIGNAL(executed(QListViewItem*)), + this, SLOT(slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(mouseButtonPressed(int, QListViewItem*, const QPoint&, int)), + this, SLOT(slotItemPressed(int, QListViewItem*)) ); + connect( this, SIGNAL(returnPressed( QListViewItem*)), + SLOT( slotItemExecuted(QListViewItem*)) ); + connect( this, SIGNAL(contextMenuRequested(QListViewItem*, const QPoint&, int)), + this, SLOT(slotContextMenuRequested(QListViewItem*, const QPoint&)) ); + + m_part = part; +} + + +ClassTreeBase::~ClassTreeBase() +{} + + +ClassTreeBase::TreeState ClassTreeBase::treeState() const +{ + TreeState state; + + ClassTreeBase *that = const_cast<ClassTreeBase*>(this); + QListViewItemIterator it(that); + for (; it.current(); ++it) + if (it.current()->isOpen()) { + QStringList path; + QListViewItem *item = it.current(); + while (item) { + path.prepend(item->text(0)); + item = item->parent(); + } + state.append(path); + } + + return state; +} + + +void ClassTreeBase::setTreeState(TreeState state) +{ + TreeStateIterator tsit; + for (tsit = state.begin(); tsit != state.end(); ++tsit) { + QListViewItemIterator it(this); + for (; it.current(); ++it) { + QStringList path; + QListViewItem *item = it.current(); + while (item) { + path.prepend(item->text(0)); + item = item->parent(); + } + if (*tsit == path) { + it.current()->setOpen(true); + break; + } + } + } +} + + + + +void ClassTreeBase::slotItemExecuted( QListViewItem* item ) +{ + if (!item) + return; + + // toggle open state for parents + if (item->childCount() > 0) + setOpen(item, !isOpen(item)); + + // We assume here that ALL (!) items in the list view + // are ClassTreeItem's + ClassTreeItem *ctitem = static_cast<ClassTreeItem*>(item); + if (ctitem->isOrganizer()) + return; + + QString toFile; + int toLine = -1; + if (dynamic_cast<ClassTreeClassItem*>(item)) { + ctitem->getDeclaration(&toFile, &toLine); + } + else { + ctitem->getImplementation(&toFile, &toLine); + } + m_part->partController()->editDocument(toFile, toLine); + m_part->mainWindow()->lowerView(this); +} + + +void ClassTreeBase::slotItemPressed(int button, QListViewItem *item) +{ + if (!item) + return; + + // We assume here that ALL (!) items in the list view + // are ClassTreeItem's + ClassTreeItem *ctitem = static_cast<ClassTreeItem*>(item); + if (ctitem->isOrganizer()) + return; + + if (button == MidButton) { + QString toFile; + int toLine = -1; + ctitem->getDeclaration(&toFile, &toLine); + m_part->partController()->editDocument(toFile, toLine); + m_part->mainWindow()->lowerView(this); + } +} + +void ClassTreeBase::slotContextMenuRequested(QListViewItem *item, const QPoint &p) +{ + contextItem = static_cast<ClassTreeItem*>(item); + + KPopupMenu *popup = createPopup(); + popup->exec(p); + delete popup; +} + +void ClassTreeBase::slotGotoDeclaration() +{ + QString toFile; + int toLine = -1; + + contextItem->getDeclaration(&toFile, &toLine); + m_part->partController()->editDocument(toFile, toLine); +} + + +void ClassTreeBase::slotGotoImplementation() +{ + QString toFile; + int toLine = -1; + + contextItem->getImplementation(&toFile, &toLine); + m_part->partController()->editDocument(toFile, toLine); +} + + +void ClassTreeBase::slotAddMethod() +{ + if (m_part->languageSupport()) + m_part->languageSupport()->addMethod(contextItem->scopedText()); +} + + +void ClassTreeBase::slotAddAttribute() +{ + if (m_part->languageSupport()) + m_part->languageSupport()->addAttribute(contextItem->scopedText()); +} + + +void ClassTreeBase::slotClassBaseClasses() +{ + ClassToolDialog *dlg = new ClassToolDialog(m_part); + dlg->setClassName(contextItem->scopedText()); + dlg->viewParents(); +} + + +void ClassTreeBase::slotClassDerivedClasses() +{ + ClassToolDialog *dlg = new ClassToolDialog(m_part); + dlg->setClassName(contextItem->scopedText()); + dlg->viewChildren(); +} + + +void ClassTreeBase::slotClassTool() +{ + ClassToolDialog *dlg = new ClassToolDialog(m_part); + dlg->setClassName(contextItem->scopedText()); + dlg->viewNone(); +} + +#include "classtreebase.moc" diff --git a/parts/classview/classtreebase.h b/parts/classview/classtreebase.h new file mode 100644 index 00000000..e019bcc2 --- /dev/null +++ b/parts/classview/classtreebase.h @@ -0,0 +1,242 @@ +/*************************************************************************** + * Copyright (C) 1999 by Jonas Nordin * + * [email protected] * + * Copyright (C) 2000-2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _CLASSTREEBASE_H_ +#define _CLASSTREEBASE_H_ + +#include <klistview.h> +#include "parseditem.h" +#include "parsedscopecontainer.h" +#include "parsedclass.h" +#include "parsedmethod.h" +#include "parsedattribute.h" +#include "classviewpart.h" +#include "parsedscript.h" + +class ClassTreeItem; +class KPopupMenu; + + +class ClassTreeBase : public KListView +{ + Q_OBJECT + +public: + ClassTreeBase( ClassViewPart *part, QWidget *parent=0, const char *name=0 ); + ~ClassTreeBase(); + +protected: + typedef QValueList<QStringList> TreeState; + typedef QValueList<QStringList>::Iterator TreeStateIterator; + TreeState treeState() const; + void setTreeState(TreeState state); + + ClassTreeItem *contextItem; + virtual KPopupMenu *createPopup() = 0; + +private slots: + void slotItemExecuted(QListViewItem*); + void slotItemPressed(int button, QListViewItem *item); + void slotContextMenuRequested(QListViewItem *item, const QPoint &p); + void slotGotoDeclaration(); + void slotGotoImplementation(); + void slotAddMethod(); + void slotAddAttribute(); + void slotClassBaseClasses(); + void slotClassDerivedClasses(); + void slotClassTool(); + +protected: + ClassViewPart *m_part; + friend class ClassTreeItem; + friend class ClassTreeScopeItem; +}; + + +class ClassTreeItem : public QListViewItem, public NotifyClient +{ +public: + ClassTreeItem( ClassTreeBase *parent, ClassTreeItem *lastSibling, ParsedItem *parsedItem ) + : QListViewItem(parent, lastSibling), NotifyClient(), m_item(parsedItem) + { + init(); + } + ClassTreeItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, ParsedItem *parsedItem ) + : QListViewItem(parent, lastSibling), NotifyClient(), m_item(parsedItem) + { + init(); + } + ClassTreeItem( const ClassTreeItem& other ) + : QListViewItem( other.parent(), other.nextSibling()), NotifyClient() + { + m_item = other.m_item; + init(); + } + ClassTreeItem& operator=( const ClassTreeItem& other ) + { + m_item = other.m_item; + init(); + return *this; + } + ~ClassTreeItem() + { + if ( m_item ) + m_item->unregisterNotifyClient( (NotifyClient*)this ); + } + + // m_item has been deleted. + void notify() { m_item = 0; } + + KPopupMenu *createPopup(); + bool isOrganizer() { return !m_item; } + void init() + { + if ( m_item ) + m_item->registerNotifyClient( (NotifyClient*)this ); + } + + void getDeclaration(QString *toFile, int *toLine); + void getImplementation(QString *toFile, int *toLine); + + virtual QString scopedText() const; + virtual QString text( int ) const; + virtual QString tipText() const; + +protected: + ClassTreeBase *classTree() + { return static_cast<ClassTreeBase*>(listView()); } + ParsedItem *m_item; +}; + + +class ClassTreeOrganizerItem : public ClassTreeItem +{ +public: + ClassTreeOrganizerItem( ClassTreeBase *parent, ClassTreeItem *lastSibling, + const QString &text ) + : ClassTreeItem(parent, lastSibling, 0 ) + , m_text( text ) + { init(); } + ClassTreeOrganizerItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, + const QString &text ) + : ClassTreeItem(parent, lastSibling, 0 ) + , m_text( text ) + { init(); } + ~ClassTreeOrganizerItem() + {} + + virtual QString text( int ) const { return m_text; } + +private: + QString m_text; + + void init(); +}; + + +class ClassTreeScopeItem : public ClassTreeItem +{ +public: + ClassTreeScopeItem( ClassTreeBase *parent, ClassTreeItem *lastSibling, + ParsedScopeContainer *parsedScope ) + : ClassTreeItem(parent, lastSibling, parsedScope) + { + init(); + } + ClassTreeScopeItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedScopeContainer *parsedScope ) + : ClassTreeItem(parent, lastSibling, parsedScope) + { + init(); + } + ~ClassTreeScopeItem() + { + } + + virtual QString text( int ) const; + virtual void setOpen(bool o); + +private: + void init(); +}; + + +class ClassTreeClassItem : public ClassTreeItem +{ +public: + ClassTreeClassItem( ClassTreeBase *parent, ClassTreeItem *lastSibling, + ParsedClass *parsedClass, bool isStruct=false ) + : ClassTreeItem(parent, lastSibling, parsedClass), m_isStruct( isStruct ) + { + init(); + } + ClassTreeClassItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedClass *parsedClass, bool isStruct=false ) + : ClassTreeItem(parent, lastSibling, parsedClass), m_isStruct( isStruct ) + { + init(); + } + ~ClassTreeClassItem() + { + } + + virtual void setOpen(bool o); + +private: + void init(); + +private: + bool m_isStruct; +}; + + +class ClassTreeMethodItem : public ClassTreeItem +{ +public: + ClassTreeMethodItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedMethod *parsedMethod ); + ~ClassTreeMethodItem() + { + } + + virtual QString text( int ) const; +}; + + +class ClassTreeAttrItem : public ClassTreeItem +{ +public: + ClassTreeAttrItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedAttribute *parsedAttr ); + ~ClassTreeAttrItem() + { + } + + virtual QString text( int ) const; +}; + +class ClassTreeScriptItem : public ClassTreeItem +{ +public: + ClassTreeScriptItem( ClassTreeItem *parent, ClassTreeItem *lastSibling, + ParsedScript *parsedScript ); + ~ClassTreeScriptItem() + { + } + + virtual QString text( int ) const; + virtual void setOpen(bool o); +}; + + +#endif diff --git a/parts/classview/classviewpart.cpp b/parts/classview/classviewpart.cpp new file mode 100644 index 00000000..b37ed50b --- /dev/null +++ b/parts/classview/classviewpart.cpp @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2003 Roberto Raggi ([email protected]) + * Copyright (C) 2003 Alexander Dymo ([email protected]) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#include <qwhatsthis.h> +#include <qlistview.h> +#include <qfileinfo.h> +#include <qlineedit.h> + +#include <kiconloader.h> +#include <klocale.h> +#include <kdevgenericfactory.h> +#include <kpopupmenu.h> +#include <kdebug.h> +#include <kmimetype.h> + +#include <kdevcore.h> +#include <kdevmainwindow.h> +#include <kdevlanguagesupport.h> +#include <kcomboview.h> +#include <kdevpartcontroller.h> +#include <kdevproject.h> +#include <urlutil.h> +#include <kdevplugininfo.h> + +#include <codemodel.h> +#include <codemodel_utils.h> + +#include "classviewwidget.h" +#include "classviewpart.h" +#include "hierarchydlg.h" +#include "navigator.h" + +#include "klistviewaction.h" + +#include <ktexteditor/document.h> +#include <ktexteditor/editinterface.h> +#include <ktexteditor/view.h> +#include <ktexteditor/selectioninterface.h> +#include <ktexteditor/viewcursorinterface.h> +#include <ktexteditor/clipboardinterface.h> + + +class FunctionCompletion : public CustomCompleter { + public: + FunctionCompletion() { + setOrder( Insertion ); + }; + typedef QMap<QString, QString> FuncMap; + FuncMap nameMap; /// real -> short + FuncMap revNameMap; /// short -> real + + static const QString processName( QString function ) { + QString args; + QString fScope; + int cutpos; + + if((cutpos = function.find('(')) != -1) { + args = function.right( function.length() - cutpos ); + function = function.left( cutpos ); + } else { + return function; + } + if((cutpos = function.findRev(':')) != -1 || (cutpos = function.findRev('.')) != -1) { + fScope = function.left( cutpos + 1 ); + function = function.right( function.length() - cutpos - 1); + } + + return function; + } + + virtual void addItem ( const QString &item ) { + QString newItemName = item; + KCompletion::addItem(newItemName); + QString tx = processName( item ); + tx += " \"" + item + "\""; + nameMap[item] = tx; + revNameMap[tx] = item; + if(tx.length() == 0) { + kdDebug() << "function-name-extraction failed with \"" << item << "\"" << endl; + }else{ + KCompletion::addItem( tx ); + kdDebug() << "addding \"" << item << "\" as \"" << tx << "\"" << endl; + } + KCompletion::addItem( item ); + } + + virtual void removeItem ( const QString &item ) { + FuncMap::iterator it = nameMap.find( item ); + if( it != nameMap.end() ) { + KCompletion::removeItem( *it ); + revNameMap.remove( *it ); + nameMap.remove( it ); + } + } + + virtual void clear() { + nameMap.clear(); + revNameMap.clear(); + KCompletion::clear(); + } + + virtual void postProcessMatch ( QString *match ) const { + FuncMap::const_iterator it = revNameMap.find( *match ); + if( it != revNameMap.end() ) { + *match = *it; + } + }; + + virtual void postProcessMatches ( QStringList *matches ) const { + QStringList::iterator it = matches->begin(); + + while( it != matches->end() ) { + postProcessMatch( &(*it) ); + ++it; + } + } + + virtual void postProcessMatches ( KCompletionMatches *matches ) const { + } +}; + + +typedef KDevGenericFactory<ClassViewPart> ClassViewFactory; +static const KDevPluginInfo data("kdevclassview"); +K_EXPORT_COMPONENT_FACTORY( libkdevclassview, ClassViewFactory( data ) ) + +ClassViewPart::ClassViewPart(QObject *parent, const char *name, const QStringList& ) + :/// KDevPlugin( &data, parent, name ? name : "ClassViewPart" ), + KDevCodeBrowserFrontend( &data, parent, name ? name : "ClassViewPart" ), + m_activeDocument(0), m_activeView(0), m_activeSelection(0), m_activeEditor(0), m_activeViewCursor(0), m_hierarchyDlg(0) +{ + setInstance(ClassViewFactory::instance()); + setXMLFile("kdevclassview.rc"); + + navigator = new Navigator(this); + + setupActions(); + + m_widget = new ClassViewWidget(this); + m_widget->setIcon( SmallIcon("view_tree") ); + m_widget->setCaption(i18n("Class Browser")); + mainWindow()->embedSelectView( m_widget, i18n("Classes"), i18n("Class browser") ); + QWhatsThis::add(m_widget, i18n("<b>Class browser</b><p>" + "The class browser shows all namespaces, classes and namespace and class members in a project.")); + + connect( core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) ); + connect( core(), SIGNAL(projectClosed()), this, SLOT(slotProjectClosed()) ); + connect( core(), SIGNAL(languageChanged()), this, SLOT(slotProjectOpened()) ); + connect( partController(), SIGNAL(activePartChanged(KParts::Part*)), + this, SLOT(activePartChanged(KParts::Part*))); +} + +bool ClassViewPart::jumpedToItem( ItemDom item ) { + if(!m_widget) return false; + return m_widget->selectItem(item); +} + +ClassViewPart::~ClassViewPart() +{ + mainWindow()->removeView( m_widget ); + delete (ClassViewWidget*) m_widget; + delete m_hierarchyDlg; +} + +void ClassViewPart::slotProjectOpened( ) +{ + connect( languageSupport(), SIGNAL(updatedSourceInfo()), navigator, SLOT(refresh()) ); + connect( languageSupport(), SIGNAL(addedSourceInfo(const QString& )), navigator, SLOT(addFile(const QString& ))); + navigator->refresh(); +} + +void ClassViewPart::slotProjectClosed( ) +{ +// navigator->refresh(); +// disconnect( languageSupport(), SIGNAL(updatedSourceInfo()), navigator, SLOT(refresh()) ); +} + +void ClassViewPart::setupActions( ) +{ + m_functionsnav = new KListViewAction( new KComboView(true, 150, 0, "m_functionsnav_combo", new FunctionCompletion() ), i18n("Functions Navigation"), 0, 0, 0, actionCollection(), "functionsnav_combo", true ); + connect(m_functionsnav->view(), SIGNAL(activated(QListViewItem*)), navigator, SLOT(selectFunctionNav(QListViewItem*))); +// m_functionsnav->view()->setEditable(false); + connect(m_functionsnav->view(), SIGNAL(focusGranted()), navigator, SLOT(functionNavFocused())); + connect(m_functionsnav->view(), SIGNAL(focusLost()), navigator, SLOT(functionNavUnFocused())); + m_functionsnav->setToolTip(i18n("Functions in file")); + m_functionsnav->setWhatsThis(i18n("<b>Function navigator</b><p>Navigates over functions contained in the file.")); +// m_functionsnav->view()->setCurrentText(NAV_NODEFINITION); + m_functionsnav->view()->setDefaultText(NAV_NODEFINITION); + + new KAction( i18n("Focus Navigator"), 0, this, SLOT(slotFocusNavbar()), actionCollection(), "focus_navigator" ); + + if (langHasFeature(KDevLanguageSupport::Classes)) + { + KAction *ac = new KAction(i18n("Class Inheritance Diagram"), "view_tree", 0, this, SLOT(graphicalClassView()), actionCollection(), "inheritance_dia"); + ac->setToolTip(i18n("Class inheritance diagram")); + ac->setWhatsThis(i18n("<b>Class inheritance diagram</b><p>Displays inheritance relationship between classes in project. " + "Note, it does not display classes outside inheritance hierarchy.")); + } +} + +bool ClassViewPart::langHasFeature(KDevLanguageSupport::Features feature) +{ + bool result = false; + if (languageSupport()) + result = (feature & languageSupport()->features()); + return result; +} + +void ClassViewPart::graphicalClassView( ) +{ + if( !m_hierarchyDlg ) + m_hierarchyDlg = new HierarchyDialog(this); + m_hierarchyDlg->refresh(); + m_hierarchyDlg->show(); +} + +void ClassViewPart::refresh() { + if( navigator ) + navigator->refresh(); +} + +void ClassViewPart::activePartChanged( KParts::Part * part) +{ + navigator->stopTimer(); + if (m_activeView) + { + disconnect(m_activeView, SIGNAL(cursorPositionChanged()), + navigator, SLOT(slotCursorPositionChanged())); + } + + kdDebug() << "ClassViewPart::activePartChanged()" << endl; + + m_activeDocument = dynamic_cast<KTextEditor::Document*>( part ); + m_activeView = part ? dynamic_cast<KTextEditor::View*>( part->widget() ) : 0; + m_activeEditor = dynamic_cast<KTextEditor::EditInterface*>( part ); + m_activeSelection = dynamic_cast<KTextEditor::SelectionInterface*>( part ); + m_activeViewCursor = part ? dynamic_cast<KTextEditor::ViewCursorInterface*>( m_activeView ) : 0; + + m_activeFileName = QString::null; + + if (m_activeDocument) + { + m_activeFileName = URLUtil::canonicalPath( m_activeDocument->url().path() ); + navigator->refreshNavBars(m_activeFileName); + navigator->syncFunctionNavDelayed(200); +/* if ( languageSupport()->mimeTypes().find( + KMimeType::findByPath(m_activeFileName)) != languageSupport()->mimeTypes().end() ) + m_activeFileName = QString::null;*/ + } + if( m_activeViewCursor ) + { + connect(m_activeView, SIGNAL(cursorPositionChanged()), + navigator, SLOT(slotCursorPositionChanged()) ); + } +} +void ClassViewPart::slotFocusNavbar() +{ + m_functionsnav->view()->setFocus(); +} + +#include "classviewpart.moc" diff --git a/parts/classview/classviewpart.h b/parts/classview/classviewpart.h new file mode 100644 index 00000000..d10553e4 --- /dev/null +++ b/parts/classview/classviewpart.h @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2003 Roberto Raggi ([email protected]) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef __KDEVPART_CLASSVIEW_H__ +#define __KDEVPART_CLASSVIEW_H__ + +#include "kdevlanguagesupport.h" +#include "viewcombos.h" + +#include <qguardedptr.h> +#include <qmap.h> + +#include <kdevplugin.h> + +#include <codemodel.h> +#include <codebrowserfrontend.h> + +using namespace Extensions; + +namespace KParts { class Part; } +namespace KTextEditor +{ + class Document; + class View; + class EditInterface; + class SelectionInterface; + class ViewCursorInterface; +} + + +class ClassViewWidget; +class KListViewAction; +class QListViewItem; +class KToolBarPopupAction; +class NamespaceItem; +class Navigator; +class HierarchyDialog; +class ClassViewPart : public Extensions::KDevCodeBrowserFrontend +{ + Q_OBJECT +public: + ClassViewPart(QObject *parent, const char *name, const QStringList &); + virtual ~ClassViewPart(); + + bool langHasFeature(KDevLanguageSupport::Features feature); + + KListViewAction *m_functionsnav; + Navigator *navigator; + + inline ClassViewWidget* widget() { + return &( *m_widget ); + } + + virtual bool jumpedToItem( ItemDom item ); + +private slots: + void slotProjectOpened(); + void slotProjectClosed(); + void graphicalClassView(); + void refresh(); + void slotFocusNavbar(); + + void activePartChanged(KParts::Part*); + +private: + void setupActions(); + + QGuardedPtr<ClassViewWidget> m_widget; + + QString m_activeFileName; + KTextEditor::Document* m_activeDocument; + KTextEditor::View* m_activeView; + KTextEditor::SelectionInterface* m_activeSelection; + KTextEditor::EditInterface* m_activeEditor; + KTextEditor::ViewCursorInterface* m_activeViewCursor; + + HierarchyDialog* m_hierarchyDlg; + friend class Navigator; +}; + + +#endif diff --git a/parts/classview/classviewwidget.cpp b/parts/classview/classviewwidget.cpp new file mode 100644 index 00000000..f26f1b92 --- /dev/null +++ b/parts/classview/classviewwidget.cpp @@ -0,0 +1,1295 @@ +/* + * Copyright (C) 2003 Roberto Raggi ([email protected]) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Partially based on KDE Studio ClassListView http://www.thekompany.com/projects/kdestudio/ + */ + +#include "classviewpart.h" +#include "classviewwidget.h" + +#include <kiconloader.h> +#include <kinstance.h> +#include <kurl.h> +#include <kaction.h> +#include <kactionclasses.h> +#include <kpopupmenu.h> +#include <kconfig.h> + +#include <urlutil.h> +#include <kdevcore.h> +#include <kdevlanguagesupport.h> +#include <kdevproject.h> +#include <kdevpartcontroller.h> +#include <codemodel.h> +#include <codemodel_utils.h> + +#include <klocale.h> +#include <kdebug.h> + +#include <qheader.h> +#include <qdir.h> +#include <qstylesheet.h> +#include <qstringlist.h> + +// namespace ?!? + +ClassViewWidget::ClassViewWidget( ClassViewPart * part ) + : KListView( 0, "ClassViewWidget" ), QToolTip( viewport() ), m_part( part ), m_projectDirectoryLength( 0 ) +{ + addColumn( "" ); + header()->hide(); + setSorting( 0 ); + setRootIsDecorated( true ); + setAllColumnsShowFocus( true ); + + m_projectItem = 0; + + connect( this, SIGNAL(returnPressed(QListViewItem*)), this, SLOT(slotExecuted(QListViewItem*)) ); + connect( this, SIGNAL(executed(QListViewItem*)), this, SLOT(slotExecuted(QListViewItem*)) ); + connect( m_part->core(), SIGNAL(projectOpened()), this, SLOT(slotProjectOpened()) ); + connect( m_part->core(), SIGNAL(projectClosed()), this, SLOT(slotProjectClosed()) ); + connect( m_part->core(), SIGNAL(languageChanged()), this, SLOT(slotProjectOpened()) ); + + QStringList lst; + lst << i18n( "Group by Directories" ) << i18n( "Plain List" ) << i18n( "Java Like Mode" ); + m_actionViewMode = new KSelectAction( i18n("View Mode"), KShortcut(), m_part->actionCollection(), "classview_mode" ); + m_actionViewMode->setItems( lst ); + m_actionViewMode->setWhatsThis(i18n("<b>View mode</b><p>Class browser items can be grouped by directories, listed in a plain or java like view.")); + + m_actionNewClass = new KAction( i18n("New Class..."), KShortcut(), this, SLOT(slotNewClass()), + m_part->actionCollection(), "classview_new_class" ); + m_actionNewClass->setWhatsThis(i18n("<b>New class</b><p>Calls the <b>New Class</b> wizard.")); + + m_actionCreateAccessMethods = new KAction( i18n("Create get/set Methods"), KShortcut(), this, SLOT(slotCreateAccessMethods()), m_part->actionCollection(), "classview_create_access_methods" ); + + + m_actionAddMethod = new KAction( i18n("Add Method..."), KShortcut(), this, SLOT(slotAddMethod()), + m_part->actionCollection(), "classview_add_method" ); + m_actionAddMethod->setWhatsThis(i18n("<b>Add method</b><p>Calls the <b>New Method</b> wizard.")); + m_actionAddAttribute = new KAction( i18n("Add Attribute..."), KShortcut(), this, SLOT(slotAddAttribute()), + m_part->actionCollection(), "classview_add_attribute" ); + m_actionAddAttribute->setWhatsThis(i18n("<b>Add attribute</b><p>Calls the <b>New Attribute</b> wizard.")); + + m_actionOpenDeclaration = new KAction( i18n("Open Declaration"), KShortcut(), this, SLOT(slotOpenDeclaration()), + m_part->actionCollection(), "classview_open_declaration" ); + m_actionOpenDeclaration->setWhatsThis(i18n("<b>Open declaration</b><p>Opens a file where the selected item is declared and jumps to the declaration line.")); + m_actionOpenImplementation = new KAction( i18n("Open Implementation"), KShortcut(), this, SLOT(slotOpenImplementation()), + m_part->actionCollection(), "classview_open_implementation" ); + m_actionOpenImplementation->setWhatsThis(i18n("<b>Open implementation</b><p>Opens a file where the selected item is defined (implemented) and jumps to the definition line.")); + + m_actionFollowEditor = new KToggleAction( i18n("Follow Editor"), KShortcut(), this, SLOT(slotFollowEditor()), m_part->actionCollection(), "classview_follow_editor" ); + + KConfig* config = m_part->instance()->config(); + config->setGroup( "General" ); + setViewMode( config->readNumEntry( "ViewMode", KDevelop3ViewMode ) ); + m_doFollowEditor = config->readBoolEntry( "FollowEditor", false ); +} + +ClassViewWidget::~ClassViewWidget( ) +{ + KConfig* config = m_part->instance()->config(); + config->setGroup( "General" ); + config->writeEntry( "ViewMode", viewMode() ); + config->writeEntry( "FollowEditor", m_doFollowEditor ); + config->sync(); +} + +template <class ModelType, class ListItemType> + static bool selectItemG( ItemDom item, const QMap<KSharedPtr<ModelType>, ListItemType*>& map ) +{ + ModelType* c = dynamic_cast<ModelType*>( &(*item) ); + + if( c ) { + KSharedPtr<ModelType> d( c ); + typename QMap<KSharedPtr<ModelType>, ListItemType*>::ConstIterator it = map.find(d); + if( it != map.end() ) { + ( *it )->select(); + return true; + } + } + return false; +} + + +void ClassViewWidget::slotExecuted( QListViewItem* item ) +{ + if( ClassViewItem* cbitem = dynamic_cast<ClassViewItem*>( item ) ){ + if( cbitem->hasImplementation() ) + cbitem->openImplementation(); + else + cbitem->openDeclaration(); + } +} + +void ClassViewWidget::clear( ) +{ + KListView::clear(); + removedText.clear(); + m_projectItem = 0; +} + +void restoreOpenNodes( QStringList & list, QListViewItem * item ) +{ + if ( item && !list.isEmpty() ) + { + if ( item->text( 0 ) == list.first() ) + { + item->setOpen( true ); + list.pop_front(); + restoreOpenNodes( list, item->firstChild() ); + } + else + { + restoreOpenNodes( list, item->nextSibling() ); + } + } +} + +void storeOpenNodes( QValueList<QStringList> & openNodes, QStringList const & list, QListViewItem * item ) +{ + if ( item ) + { + if ( item->isOpen() ) + { + QStringList mylist( list ); + mylist << item->text( 0 ); + openNodes << mylist; + storeOpenNodes( openNodes, mylist, item->firstChild() ); + } + storeOpenNodes( openNodes, list, item->nextSibling() ); + } +} + +void ClassViewWidget::refresh() +{ + if( !m_part->project() ) + return; + + QValueList<QStringList> openNodes; + storeOpenNodes( openNodes, QStringList(), firstChild() ); + int scrollbarPos = verticalScrollBar()->value(); + + clear(); + m_projectItem = new FolderBrowserItem( this, this, m_part->project()->projectName() ); + m_projectItem->setOpen( true ); + blockSignals( true ); + + FileList fileList = m_part->codeModel()->fileList(); + FileList::Iterator it = fileList.begin(); + while( it != fileList.end() ){ + insertFile( (*it)->name() ); + ++it; + } + + QValueList<QStringList>::iterator itt = openNodes.begin(); + while ( itt != openNodes.end() ) + { + restoreOpenNodes ( *itt, firstChild() ); + ++itt; + } + verticalScrollBar()->setValue( scrollbarPos ); + + blockSignals( false ); +} + +void ClassViewWidget::slotProjectOpened( ) +{ + m_projectItem = new FolderBrowserItem( this, this, m_part->project()->projectName() ); + m_projectItem->setOpen( true ); + + m_projectDirectory = URLUtil::canonicalPath( m_part->project()->projectDirectory() ); + if( m_projectDirectory.isEmpty() ) + m_projectDirectory = m_part->project()->projectDirectory(); + + m_projectDirectoryLength = m_projectDirectory.length() + 1; + + connect( m_part->languageSupport(), SIGNAL(updatedSourceInfo()), + this, SLOT(refresh()) ); + connect( m_part->languageSupport(), SIGNAL(aboutToRemoveSourceInfo(const QString&)), + this, SLOT(removeFile(const QString&)) ); + connect( m_part->languageSupport(), SIGNAL(addedSourceInfo(const QString&)), + this, SLOT(insertFile(const QString&)) ); +} + +void ClassViewWidget::slotProjectClosed( ) +{ +} + + +void ClassViewWidget::insertFile( const QString& fileName ) +{ + QString fn = URLUtil::canonicalPath( fileName ); + //kdDebug() << "======================== insertFile(" << fn << ")" << endl; + + FileDom dom = m_part->codeModel()->fileByName( fn ); + if( !dom ) + return; + + fn = URLUtil::relativePathToFile(m_part->project()->projectDirectory(), fn); + QStringList path; + + switch( viewMode() ) + { + case KDevelop3ViewMode: + { + path = QStringList::split( "/", fn ); + path.pop_back(); + } + break; + + case KDevelop2ViewMode: + { + } + break; + + case JavaLikeViewMode: + { + QStringList l = QStringList::split( "/", fn ); + l.pop_back(); + + QString package = l.join("."); + if( !package.isEmpty() ) + path.push_back( package ); + } + break; + } + + m_projectItem->processFile( dom, path ); +} + +void ClassViewWidget::removeFile( const QString& fileName ) +{ + QString fn = URLUtil::canonicalPath( fileName ); + //kdDebug() << "======================== removeFile(" << fn << ")" << endl; + + FileDom dom = m_part->codeModel()->fileByName( fn ); + if( !dom ) + return; + + fn = URLUtil::relativePathToFile(m_part->project()->projectDirectory(), fn); + QStringList path; + + switch( viewMode() ) + { + case KDevelop3ViewMode: + { + path = QStringList::split( "/", fn ); + path.pop_back(); + } + break; + + case KDevelop2ViewMode: + { + } + break; + + case JavaLikeViewMode: + { + QStringList l = QStringList::split( "/", fn ); + l.pop_back(); + + QString package = l.join("."); + if( !package.isEmpty() ) + path.push_back( package ); + } + break; + } + + m_projectItem->processFile( dom, path, true ); +} + +void ClassViewWidget::contentsContextMenuEvent( QContextMenuEvent * ev ) +{ + KPopupMenu menu( this ); + + ClassViewItem* item = dynamic_cast<ClassViewItem*>( selectedItem() ); + + m_actionFollowEditor->plug( &menu ); + m_actionFollowEditor->setChecked( m_doFollowEditor ); + menu.insertSeparator(); + + m_actionOpenDeclaration->setEnabled( item && item->hasDeclaration() ); + m_actionOpenImplementation->setEnabled( item && item->hasImplementation() ); + + m_actionOpenDeclaration->plug( &menu ); + m_actionOpenImplementation->plug( &menu ); + menu.insertSeparator(); + + bool sep = false; + if( item && item->isClass() ){ + if( m_part->langHasFeature(KDevLanguageSupport::AddMethod) ) { + m_actionAddMethod->plug( &menu ); + sep = true; + } + + if( m_part->langHasFeature(KDevLanguageSupport::AddAttribute) ) { + m_actionAddAttribute->plug( &menu ); + sep = true; + } + } + + if (item && item->isVariable()){ + if( m_part->langHasFeature(KDevLanguageSupport::CreateAccessMethods) ) + m_actionCreateAccessMethods->plug( &menu ); + } + + if( item && item->model() ){ + CodeModelItemContext context( item->model() ); + m_part->core()->fillContextMenu( &menu, &context ); +// sep = true; + } + if (sep) + menu.insertSeparator(); + + int oldViewMode = viewMode(); + m_actionViewMode->plug( &menu ); + + menu.exec( ev->globalPos() ); + + if( viewMode() != oldViewMode ) + refresh(); + + ev->consume(); +} + +void ClassViewWidget::setViewMode( int mode ) { + m_actionViewMode->setCurrentItem( mode ); +} + +int ClassViewWidget::viewMode( ) const +{ + return m_actionViewMode->currentItem(); +} + +QString ClassViewItem::comment() { + return QString(); +} + +void ClassViewItem::select( ) { + setOpen(true); + listView()->setCurrentItem(this); + QListViewItem* c = firstChild(); + int size = 0; + if(c != 0) { + while(c->nextSibling()) { + c = c->nextSibling(); + size++; + } + listView()->ensureItemVisible(c); + } + listView()->ensureItemVisible(this); +} + + +bool ClassViewWidget::selectItem( ItemDom item ) { + if(!m_projectItem || !isVisible()) return false; + if(item->isFunctionDefinition() && dynamic_cast<FunctionDefinitionModel*>(&(*item)) != 0) { + FunctionList lst; + FileList fileList = m_part->codeModel()->fileList(); + CodeModelUtils::findFunctionDeclarations( FindOp2(FunctionDefinitionDom( (FunctionDefinitionModel*)&(*item) )), fileList, lst ); + if(lst.isEmpty()) return false; + + item = *lst.begin(); + } + + return m_projectItem->selectItem( item ); +} + + +QString NamespaceDomBrowserItem::comment() { + return m_dom->comment(); +} + +bool FolderBrowserItem::selectItem(ItemDom item) +{ + if(item->kind() == CodeModelItem::Class) { + if( selectItemG ( item, m_classes ) ) return true; + } + + if(item->kind() == CodeModelItem::Function) { + if( selectItemG ( item, m_functions ) ) return true; + } + + if(item->kind() == CodeModelItem::TypeAlias) { + if( selectItemG ( item, m_typeAliases ) ) return true; + } + + if(item->kind() == CodeModelItem::Variable) { + if( selectItemG ( item, m_variables ) ) return true; + } + + if(item->kind() == CodeModelItem::Namespace) { + ///searching for namespaces is currently not supported and not useful + } + + for( QMap<ClassDom, ClassDomBrowserItem*>::Iterator it = m_classes.begin(); it != m_classes.end(); ++it ) { + if( (*it)->selectItem(item) ) + return true; + } + + for( QMap<QString, NamespaceDomBrowserItem*>::Iterator it = m_namespaces.begin(); it != m_namespaces.end(); ++it ) { + if( (*it)->selectItem(item) ) + return true; + } + + for( QMap<QString, FolderBrowserItem*>::Iterator it = m_folders.begin(); it != m_folders.end(); ++it ) { + if( (*it)->selectItem(item) ) { + return true; + } + } + return false; +} + + +void FolderBrowserItem::processFile( FileDom file, QStringList& path, bool remove ) +{ + if( path.isEmpty() ){ + NamespaceList namespaceList = file->namespaceList(); + ClassList classList = file->classList(); + TypeAliasList typeAliasList = file->typeAliasList(); + FunctionList functionList = file->functionList(); + VariableList variableList = file->variableList(); + + for( NamespaceList::Iterator it=namespaceList.begin(); it!=namespaceList.end(); ++it ) + processNamespace( *it, remove ); + for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it ) + processClass( *it, remove ); + for( TypeAliasList::Iterator it=typeAliasList.begin(); it!=typeAliasList.end(); ++it ) + processTypeAlias( *it, remove ); + for( FunctionList::Iterator it=functionList.begin(); it!=functionList.end(); ++it ) + processFunction( *it, remove ); + for( VariableList::Iterator it=variableList.begin(); it!=variableList.end(); ++it ) + processVariable( *it, remove ); + + return; + } + + QString current = path.front(); + path.pop_front(); + + FolderBrowserItem* item = m_folders.contains( current ) ? m_folders[ current ] : 0; + if( !item ){ + if( remove ) + return; + + item = new FolderBrowserItem( m_widget, this, current ); + if( listView()->removedText.contains(current) ) + item->setOpen( true ); + m_folders.insert( current, item ); + } + + item->processFile( file, path, remove ); + + if( remove && item->childCount() == 0 ){ + m_folders.remove( current ); + if( item->isOpen() ){ + listView()->removedText << current; + } + delete( item ); + item = 0; + } +} + +void FolderBrowserItem::processNamespace( NamespaceDom ns, bool remove ) +{ + NamespaceDomBrowserItem* item = m_namespaces.contains( ns->name() ) ? m_namespaces[ ns->name() ] : 0; + if( !item ){ + if( remove ) + return; + + item = new NamespaceDomBrowserItem( this, ns ); + if( listView()->removedText.contains(ns->name()) ) + item->setOpen( true ); + m_namespaces.insert( ns->name(), item ); + } + + NamespaceList namespaceList = ns->namespaceList(); + ClassList classList = ns->classList(); + TypeAliasList typeAliasList = ns->typeAliasList(); + FunctionList functionList = ns->functionList(); + VariableList variableList = ns->variableList(); + + for( NamespaceList::Iterator it=namespaceList.begin(); it!=namespaceList.end(); ++it ) + item->processNamespace( *it, remove ); + for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it ) + item->processClass( *it, remove ); + for( TypeAliasList::Iterator it=typeAliasList.begin(); it!=typeAliasList.end(); ++it ) + item->processTypeAlias( *it, remove ); + for( FunctionList::Iterator it=functionList.begin(); it!=functionList.end(); ++it ) + item->processFunction( *it, remove ); + for( VariableList::Iterator it=variableList.begin(); it!=variableList.end(); ++it ) + item->processVariable( *it, remove ); + + if( remove && item->childCount() == 0 ){ + m_namespaces.remove( ns->name() ); + if( item->isOpen() ){ + listView()->removedText << ns->name(); + } + delete( item ); + item = 0; + } +} + +void FolderBrowserItem::processClass( ClassDom klass, bool remove ) +{ + ClassDomBrowserItem* item = m_classes.contains( klass ) ? m_classes[ klass ] : 0; + if( !item ){ + if( remove ) + return; + + item = new ClassDomBrowserItem( this, klass ); + if( listView()->removedText.contains(klass->name()) ) + item->setOpen( true ); + m_classes.insert( klass, item ); + } + + ClassList classList = klass->classList(); + TypeAliasList typeAliasList = klass->typeAliasList(); + FunctionList functionList = klass->functionList(); + VariableList variableList = klass->variableList(); + + for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it ) + item->processClass( *it, remove ); + for( TypeAliasList::Iterator it=typeAliasList.begin(); it!=typeAliasList.end(); ++it ) + item->processTypeAlias( *it, remove ); + for( FunctionList::Iterator it=functionList.begin(); it!=functionList.end(); ++it ) + item->processFunction( *it, remove ); + for( VariableList::Iterator it=variableList.begin(); it!=variableList.end(); ++it ) + item->processVariable( *it, remove ); + + if( remove && item->childCount() == 0 ){ + m_classes.remove( klass ); + if( item->isOpen() ){ + listView()->removedText << klass->name(); + } + delete( item ); + item = 0; + } +} + +void FolderBrowserItem::processTypeAlias( TypeAliasDom typeAlias, bool remove ) +{ + TypeAliasDomBrowserItem* item = m_typeAliases.contains( typeAlias ) ? m_typeAliases[ typeAlias ] : 0; + if( !item ){ + if( remove ) + return; + + item = new TypeAliasDomBrowserItem( this, typeAlias ); + if( listView()->removedText.contains(typeAlias->name()) ) + item->setOpen( true ); + m_typeAliases.insert( typeAlias, item ); + } + + if( remove && item->childCount() == 0 ){ + m_typeAliases.remove( typeAlias ); + if( item->isOpen() ){ + listView()->removedText << typeAlias->name(); + } + delete( item ); + item = 0; + } +} + +void FolderBrowserItem::processFunction( FunctionDom fun, bool remove ) +{ + FunctionDomBrowserItem* item = m_functions.contains( fun ) ? m_functions[ fun ] : 0; + if( !item ){ + if( remove ) + return; + + item = new FunctionDomBrowserItem( this, fun ); + m_functions.insert( fun, item ); + } + + if( remove ){ + m_functions.remove( fun ); + delete( item ); + item = 0; + } +} + +void FolderBrowserItem::processVariable( VariableDom var, bool remove ) +{ + VariableDomBrowserItem* item = m_variables.contains( var ) ? m_variables[ var ] : 0; + if( !item ){ + if( remove ) + return; + + item = new VariableDomBrowserItem( this, var ); + m_variables.insert( var, item ); + } + + if( remove ){ + m_variables.remove( var ); + delete( item ); + item = 0; + } +} + +// ------------------------------------------------------------------------ +bool NamespaceDomBrowserItem::selectItem( ItemDom item) +{ + if(item->kind() == CodeModelItem::Class) { + if( selectItemG ( item, m_classes ) ) return true; + } + + if(item->kind() == CodeModelItem::Function) { + if( selectItemG ( item, m_functions ) ) return true; + } + + if(item->kind() == CodeModelItem::TypeAlias) { + if( selectItemG ( item, m_typeAliases ) ) return true; + } + + if(item->kind() == CodeModelItem::Variable) { + if( selectItemG ( item, m_variables ) ) return true; + } + + if(item->kind() == CodeModelItem::Namespace) { + ///currently not neccessary.. + } + + for(QMap<ClassDom, ClassDomBrowserItem*>::Iterator it = m_classes.begin(); it != m_classes.end(); ++it) { + if( (*it)->selectItem(item) ) + return true; + } + + for(QMap<QString, NamespaceDomBrowserItem*>::Iterator it = m_namespaces.begin(); it != m_namespaces.end(); ++it) { + if( (*it)->selectItem(item) ) + return true; + } + return false; +} + + +void NamespaceDomBrowserItem::processNamespace( NamespaceDom ns, bool remove ) +{ + NamespaceDomBrowserItem* item = m_namespaces.contains( ns->name() ) ? m_namespaces[ ns->name() ] : 0; + if( !item ){ + if( remove ) + return; + + item = new NamespaceDomBrowserItem( this, ns ); + if( listView()->removedText.contains(ns->name()) ) + item->setOpen( true ); + m_namespaces.insert( ns->name(), item ); + } + + NamespaceList namespaceList = ns->namespaceList(); + ClassList classList = ns->classList(); + TypeAliasList typeAliasList = ns->typeAliasList(); + FunctionList functionList = ns->functionList(); + VariableList variableList = ns->variableList(); + + for( NamespaceList::Iterator it=namespaceList.begin(); it!=namespaceList.end(); ++it ) + item->processNamespace( *it, remove ); + for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it ) + item->processClass( *it, remove ); + for( TypeAliasList::Iterator it=typeAliasList.begin(); it!=typeAliasList.end(); ++it ) + item->processTypeAlias( *it, remove ); + for( FunctionList::Iterator it=functionList.begin(); it!=functionList.end(); ++it ) + item->processFunction( *it, remove ); + for( VariableList::Iterator it=variableList.begin(); it!=variableList.end(); ++it ) + item->processVariable( *it, remove ); + + if( remove && item->childCount() == 0 ){ + m_namespaces.remove( ns->name() ); + if( item->isOpen() ){ + listView()->removedText << ns->name(); + } + delete( item ); + item = 0; + } +} + +void NamespaceDomBrowserItem::processClass( ClassDom klass, bool remove ) +{ + ClassDomBrowserItem* item = m_classes.contains( klass ) ? m_classes[ klass ] : 0; + if( !item ){ + if( remove ) + return; + + item = new ClassDomBrowserItem( this, klass ); + if( listView()->removedText.contains(klass->name()) ) + item->setOpen( true ); + m_classes.insert( klass, item ); + } + + ClassList classList = klass->classList(); + TypeAliasList typeAliasList = klass->typeAliasList(); + FunctionList functionList = klass->functionList(); + VariableList variableList = klass->variableList(); + + for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it ) + item->processClass( *it, remove ); + for( TypeAliasList::Iterator it=typeAliasList.begin(); it!=typeAliasList.end(); ++it ) + item->processTypeAlias( *it, remove ); + for( FunctionList::Iterator it=functionList.begin(); it!=functionList.end(); ++it ) + item->processFunction( *it, remove ); + for( VariableList::Iterator it=variableList.begin(); it!=variableList.end(); ++it ) + item->processVariable( *it, remove ); + + if( remove && item->childCount() == 0 ){ + m_classes.remove( klass ); + if( item->isOpen() ){ + listView()->removedText << klass->name(); + } + delete( item ); + item = 0; + } +} + +void NamespaceDomBrowserItem::processTypeAlias( TypeAliasDom typeAlias, bool remove ) +{ + TypeAliasDomBrowserItem* item = m_typeAliases.contains( typeAlias ) ? m_typeAliases[ typeAlias ] : 0; + if( !item ){ + if( remove ) + return; + + item = new TypeAliasDomBrowserItem( this, typeAlias ); + if( listView()->removedText.contains(typeAlias->name()) ) + item->setOpen( true ); + m_typeAliases.insert( typeAlias, item ); + } + + if( remove && item->childCount() == 0 ){ + m_typeAliases.remove( typeAlias ); + if( item->isOpen() ){ + listView()->removedText << typeAlias->name(); + } + delete( item ); + item = 0; + } +} + +void NamespaceDomBrowserItem::processFunction( FunctionDom fun, bool remove ) +{ + FunctionDomBrowserItem* item = m_functions.contains( fun ) ? m_functions[ fun ] : 0; + if( !item ){ + if( remove ) + return; + + item = new FunctionDomBrowserItem( this, fun ); + m_functions.insert( fun, item ); + } + + if( remove ){ + m_functions.remove( fun ); + delete( item ); + item = 0; + } +} + +void NamespaceDomBrowserItem::processVariable( VariableDom var, bool remove ) +{ + VariableDomBrowserItem* item = m_variables.contains( var ) ? m_variables[ var ] : 0; + if( !item ){ + if( remove ) + return; + + item = new VariableDomBrowserItem( this, var ); + m_variables.insert( var, item ); + } + + if( remove ){ + m_variables.remove( var ); + delete( item ); + item = 0; + } +} + +// ------------------------------------------------------------------------ + + +bool ClassDomBrowserItem::selectItem(ItemDom item) +{ + if(item->kind() == CodeModelItem::Class) { + if( selectItemG ( item, m_classes ) ) return true; + } + + if(item->kind() == CodeModelItem::Function) { + if( selectItemG ( item, m_functions ) ) return true; + } + + if(item->kind() == CodeModelItem::TypeAlias) { + if( selectItemG ( item, m_typeAliases ) ) return true; + } + + if(item->kind() == CodeModelItem::Variable) { + if( selectItemG ( item, m_variables ) ) return true; + } + + for(QMap<ClassDom, ClassDomBrowserItem*>::Iterator it = m_classes.begin(); it != m_classes.end(); ++it) { + if( (*it)->selectItem(item) ) + return true; + } + return false; +} + + +void ClassDomBrowserItem::processClass( ClassDom klass, bool remove ) +{ + ClassDomBrowserItem* item = m_classes.contains( klass ) ? m_classes[ klass ] : 0; + if( !item ){ + if( remove ) + return; + + item = new ClassDomBrowserItem( this, klass ); + if( listView()->removedText.contains(klass->name()) ) + item->setOpen( true ); + m_classes.insert( klass, item ); + } + + ClassList classList = klass->classList(); + TypeAliasList typeAliasList = klass->typeAliasList(); + FunctionList functionList = klass->functionList(); + VariableList variableList = klass->variableList(); + + for( ClassList::Iterator it=classList.begin(); it!=classList.end(); ++it ) + item->processClass( *it, remove ); + for( TypeAliasList::Iterator it=typeAliasList.begin(); it!=typeAliasList.end(); ++it ) + item->processTypeAlias( *it, remove ); + for( FunctionList::Iterator it=functionList.begin(); it!=functionList.end(); ++it ) + item->processFunction( *it, remove ); + for( VariableList::Iterator it=variableList.begin(); it!=variableList.end(); ++it ) + item->processVariable( *it, remove ); + + if( remove && item->childCount() == 0 ){ + m_classes.remove( klass ); + if( item->isOpen() ){ + listView()->removedText << klass->name(); + } + delete( item ); + item = 0; + } +} + +void ClassDomBrowserItem::processTypeAlias( TypeAliasDom typeAlias, bool remove ) +{ + TypeAliasDomBrowserItem* item = m_typeAliases.contains( typeAlias ) ? m_typeAliases[ typeAlias ] : 0; + if( !item ){ + if( remove ) + return; + + item = new TypeAliasDomBrowserItem( this, typeAlias ); + if( listView()->removedText.contains(typeAlias->name()) ) + item->setOpen( true ); + m_typeAliases.insert( typeAlias, item ); + } + + if( remove && item->childCount() == 0 ){ + m_typeAliases.remove( typeAlias ); + if( item->isOpen() ){ + listView()->removedText << typeAlias->name(); + } + delete( item ); + item = 0; + } +} + +void ClassDomBrowserItem::processFunction( FunctionDom fun, bool remove ) +{ + FunctionDomBrowserItem* item = m_functions.contains( fun ) ? m_functions[ fun ] : 0; + if( !item ){ + if( remove ) + return; + + item = new FunctionDomBrowserItem( this, fun ); + m_functions.insert( fun, item ); + } + + if( remove ){ + m_functions.remove( fun ); + delete( item ); + item = 0; + } +} + +void ClassDomBrowserItem::processVariable( VariableDom var, bool remove ) +{ + VariableDomBrowserItem* item = m_variables.contains( var ) ? m_variables[ var ] : 0; + if( !item ){ + if( remove ) + return; + + item = new VariableDomBrowserItem( this, var ); + m_variables.insert( var, item ); + } + + if( remove ){ + m_variables.remove( var ); + delete( item ); + item = 0; + } +} + +void FolderBrowserItem::setup( ) +{ + ClassViewItem::setup(); + setPixmap( 0, SmallIcon("folder") ); + setExpandable( true ); +} + +void NamespaceDomBrowserItem::setup( ) +{ + ClassViewItem::setup(); + setPixmap( 0, UserIcon("CVnamespace", KIcon::DefaultState, listView()->m_part->instance()) ); + setExpandable( true ); + + QString txt = listView()->m_part->languageSupport()->formatModelItem(m_dom.data(), true); + setText( 0, txt ); +} + +void ClassDomBrowserItem::setup( ) +{ + ClassViewItem::setup(); + setPixmap( 0, UserIcon("CVclass", KIcon::DefaultState, listView()->m_part->instance()) ); + setExpandable( true ); + + QString txt = listView()->m_part->languageSupport()->formatModelItem(m_dom.data(), true); + setText( 0, txt ); +} + +void TypeAliasDomBrowserItem::setup( ) +{ + ClassViewItem::setup(); + setPixmap( 0, UserIcon("CVtypedef", KIcon::DefaultState, listView()->m_part->instance()) ); + setExpandable( false ); + + QString txt = listView()->m_part->languageSupport()->formatModelItem(m_dom.data(), true); + setText( 0, txt ); +} + +void FunctionDomBrowserItem::setup( ) +{ + ClassViewItem::setup(); + + QString iconName; + QString methodType; + + if ( m_dom->isSignal() ) + methodType = "signal"; + else if (m_dom->isSlot() ) + methodType = "slot"; + else + methodType = "meth"; + + if( m_dom->access() == CodeModelItem::Private ) + iconName = "CVprivate_" + methodType; + else if( m_dom->access() == CodeModelItem::Protected ) + iconName = "CVprotected_" + methodType; + else + iconName = "CVpublic_" + methodType; + + setPixmap( 0, UserIcon(iconName, KIcon::DefaultState, listView()->m_part->instance()) ); + + QString txt = listView()->m_part->languageSupport()->formatModelItem(m_dom.data(), true); + + item() = highlightFunctionName(txt, 1, m_styles); +} + +void FunctionDomBrowserItem::openDeclaration() +{ + int startLine, startColumn; + m_dom->getStartPosition( &startLine, &startColumn ); + listView()->m_part->partController()->editDocument( KURL(m_dom->fileName()), startLine ); +} + +void FunctionDomBrowserItem::openImplementation() +{ + FunctionDefinitionList lst; + FileList fileList = listView()->m_part->codeModel()->fileList(); + CodeModelUtils::findFunctionDefinitions( FindOp(m_dom), fileList, lst ); + + if( lst.isEmpty() ) + return; + + FunctionDefinitionDom fun; + QFileInfo fileInfo( m_dom->fileName() ); + QString path = fileInfo.dirPath( true ); + + for( FunctionDefinitionList::Iterator it=lst.begin(); it!=lst.end(); ++it ) + { + QFileInfo defFileInfo( (*it)->fileName() ); + QString defPath = defFileInfo.dirPath( true ); + + if( path != defPath ) + continue; + + if( defFileInfo.baseName() == fileInfo.baseName() ) { + fun = *it; + } else if( !fun ) { + fun = *it; + } + } + + if( !fun ) { + fun = lst.front(); + } + + int startLine, startColumn; + fun->getStartPosition( &startLine, &startColumn ); + listView()->m_part->partController()->editDocument( KURL(fun->fileName()), startLine ); +} + +void VariableDomBrowserItem::setup( ) +{ + ClassViewItem::setup(); + QString iconName; + if( m_dom->access() == CodeModelItem::Private ) + iconName = "CVprivate_var"; + else if( m_dom->access() == CodeModelItem::Protected ) + iconName = "CVprotected_var"; + else + iconName = "CVpublic_var"; + + setPixmap( 0, UserIcon(iconName, KIcon::DefaultState, listView()->m_part->instance()) ); + + QString txt = listView()->m_part->languageSupport()->formatModelItem(m_dom.data(), true); + setText( 0, txt ); +} + +void VariableDomBrowserItem::openDeclaration() +{ + int startLine, startColumn; + m_dom->getStartPosition( &startLine, &startColumn ); + + listView()->m_part->partController()->editDocument( KURL(m_dom->fileName()), startLine ); +} + +void VariableDomBrowserItem::openImplementation() +{ +} + +QString FolderBrowserItem::key( int , bool ) const +{ + return "0 " + text( 0 ); +} + +QString NamespaceDomBrowserItem::key( int , bool ) const +{ + return "1 " + text( 0 ); +} + +QString ClassDomBrowserItem::key( int , bool ) const +{ + return "2 " + text( 0 ); +} + +QString TypeAliasDomBrowserItem::key( int , bool ) const +{ + return "3 " + text( 0 ); +} + +QString FunctionDomBrowserItem::key( int , bool ) const +{ + return "4 " + text( 0 ); +} + +QString VariableDomBrowserItem::key( int , bool ) const +{ + return "5 " + text( 0 ); +} + +void ClassViewWidget::slotNewClass( ) +{ + if( m_part->languageSupport()->features() & KDevLanguageSupport::NewClass ) + m_part->languageSupport()->addClass(); +} + +void ClassViewWidget::slotAddMethod( ) +{ + if ( !selectedItem() ) return; + + if( m_part->languageSupport()->features() & KDevLanguageSupport::AddMethod ) + m_part->languageSupport()->addMethod( static_cast<ClassDomBrowserItem*>( selectedItem() )->dom() ); +} + +void ClassViewWidget::slotAddAttribute( ) +{ + if ( !selectedItem() ) return; + + if( m_part->languageSupport()->features() & KDevLanguageSupport::AddAttribute ) + m_part->languageSupport()->addAttribute( static_cast<ClassDomBrowserItem*>( selectedItem() )->dom() ); +} + +void ClassViewWidget::slotOpenDeclaration( ) +{ + if ( !selectedItem() ) return; + + static_cast<ClassViewItem*>( selectedItem() )->openDeclaration(); +} + +void ClassViewWidget::slotOpenImplementation( ) +{ + if ( !selectedItem() ) return; + + static_cast<ClassViewItem*>( selectedItem() )->openImplementation(); +} + +void ClassDomBrowserItem::openDeclaration( ) +{ + int startLine, startColumn; + m_dom->getStartPosition( &startLine, &startColumn ); + listView()->m_part->partController()->editDocument( KURL(m_dom->fileName()), startLine ); +} + +void TypeAliasDomBrowserItem::openDeclaration( ) +{ + int startLine, startColumn; + m_dom->getStartPosition( &startLine, &startColumn ); + listView()->m_part->partController()->editDocument( KURL(m_dom->fileName()), startLine ); +} + +bool FunctionDomBrowserItem::hasImplementation() const +{ + FunctionDefinitionList lst; + FileList fileList = listView()->m_part->codeModel()->fileList(); + CodeModelUtils::findFunctionDefinitions( FindOp(m_dom), fileList, lst ); + + return !lst.isEmpty(); +} + +void ClassViewWidget::maybeTip( QPoint const & p ) +{ + ClassViewItem * item = dynamic_cast<ClassViewItem*>( itemAt( p ) ); + if ( !item ) return; + + QString tooltip; + + if ( item->isNamespace() ) + { + NamespaceDomBrowserItem * nitem = dynamic_cast<NamespaceDomBrowserItem*>( item ); + if ( nitem ) + { + tooltip = nitem->dom()->scope().join("::") + "::" + nitem->dom()->name(); + } + } + else if ( item->isClass() ) + { + ClassDomBrowserItem * citem = dynamic_cast<ClassDomBrowserItem*>( item ); + if ( citem ) + { + tooltip = citem->dom()->scope().join("::") + "::" + + citem->dom()->name() + " : " + + citem->dom()->baseClassList().join(", "); + } + } + else if ( item->isFunction() ) + { + FunctionDomBrowserItem * fitem = dynamic_cast<FunctionDomBrowserItem*>( item ); + if ( fitem ) + { + QString access; + if ( fitem->dom()->access() == CodeModelItem::Private ) + access = "[private] "; + else if ( fitem->dom()->access() == CodeModelItem::Protected ) + access = "[protected] "; + else if ( fitem->dom()->access() == CodeModelItem::Public ) + access = "[public] "; + + QStringList arguments; + ArgumentList const & list = fitem->dom()->argumentList(); + ArgumentList::ConstIterator it( list.begin() ); + while ( it != list.end() ) + { + arguments << ((*it)->type() + " " + (*it)->name()); + ++it; + } + + QString strstatic = fitem->dom()->isStatic() ? QString( "[static] " ) : QString::null; + QString strsignal = fitem->dom()->isSignal() ? QString( "[signal] " ) : QString::null; + QString strslot = fitem->dom()->isSlot() ? QString( "[slot] " ) : QString::null; + QString strresult = !fitem->dom()->resultType().isEmpty() ? fitem->dom()->resultType() + " " : QString::null; + + QString strconstant = fitem->dom()->isConstant() ? QString( " [const]" ) : QString::null; + QString strabstract = fitem->dom()->isAbstract() ? QString( " [abstract]" ) : QString::null; + + tooltip = access + strstatic + strsignal + strslot + strresult + + fitem->dom()->scope().join("::") + "::" + fitem->dom()->name() + + "(" + arguments.join(", ") + ")" + strconstant + strabstract; + } + } + else if ( item->isVariable() ) + { + VariableDomBrowserItem * vitem = dynamic_cast<VariableDomBrowserItem*>( item ); + if ( vitem ) + { + QString access; + if ( vitem->dom()->access() == CodeModelItem::Private ) + access = "[private] "; + else if ( vitem->dom()->access() == CodeModelItem::Protected ) + access = "[protected] "; + else if ( vitem->dom()->access() == CodeModelItem::Public ) + access = "[public] "; + + QString strstatic = vitem->dom()->isStatic() ? QString( "[static] " ) : QString::null; + tooltip = access + strstatic + vitem->dom()->type() + " " + vitem->dom()->name(); + } + } + else if ( item->isTypeAlias() ) + { + if( TypeAliasDomBrowserItem * titem = dynamic_cast<TypeAliasDomBrowserItem*>( item ) ) + { + tooltip = QString( "[Type] " ) + titem->dom()->type() + " " + titem->dom()->name(); + } + } + + const int maxCommentSize = 300; + + if( !item->comment().isEmpty() ) { + tooltip += "\n"; + tooltip += item->comment().length() > maxCommentSize ? item->comment().left( maxCommentSize ) + " [...]" : item->comment(); + } + + kdDebug(0) << tooltip << endl; + + QRect r = itemRect( item ); + + if ( item && r.isValid() && !tooltip.isEmpty() ) + { + tip( r, QString("<qt><pre>") + QStyleSheet::escape( tooltip ) + QString("</pre></qt>") ); + } +} + +void ClassViewWidget::slotCreateAccessMethods( ) +{ + if ( !selectedItem() ) return; + + if( m_part->languageSupport()->features() & KDevLanguageSupport::CreateAccessMethods ) + { + VariableDomBrowserItem* item = dynamic_cast<VariableDomBrowserItem*>( selectedItem() ); + if (item == 0) + return; + + m_part->languageSupport()->createAccessMethods(static_cast<ClassModel*>(static_cast<ClassDomBrowserItem*>(item->parent())->dom()),static_cast<VariableModel*>(item->dom())); + } +} + +void ClassViewWidget::slotFollowEditor() +{ + m_doFollowEditor = m_actionFollowEditor->isChecked(); +} + +bool ClassViewWidget::doFollowEditor() +{ + return m_doFollowEditor; +} + + +#include "classviewwidget.moc" diff --git a/parts/classview/classviewwidget.h b/parts/classview/classviewwidget.h new file mode 100644 index 00000000..0e9fa04b --- /dev/null +++ b/parts/classview/classviewwidget.h @@ -0,0 +1,414 @@ +/* + * Copyright (C) 2003 Roberto Raggi ([email protected]) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. +// * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Partially based on KDE Studio ClassListView http://www.thekompany.com/projects/kdestudio/ + */ + +#ifndef __CLASSVIEW_WIDGET_H__ +#define __CLASSVIEW_WIDGET_H__ + +#include <klistview.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qmap.h> +#include <qtooltip.h> +#include <codemodel.h> +#include <fancylistviewitem.h> +#include <navigator.h> + +class KDevProject; +class ClassViewPart; +class ClassViewItem; +class FolderBrowserItem; +class NamespaceDomBrowserItem; +class ClassDomBrowserItem; +class TypeAliasDomBrowserItem; +class FunctionDomBrowserItem; +class VariableDomBrowserItem; +class KSelectAction; +class KToggleAction; + +class ClassViewWidget : public KListView, public QToolTip +{ + Q_OBJECT +public: + enum ViewMode + { + KDevelop3ViewMode = 0, + KDevelop2ViewMode, + JavaLikeViewMode + }; + +public: + ClassViewWidget( ClassViewPart *part ); + virtual ~ClassViewWidget(); + + int viewMode() const; + void setViewMode( int mode ); + + void clear(); + + bool selectItem(ItemDom item); + bool doFollowEditor(); + + inline TextPaintStyleStore& paintStyles() { + return m_paintStyles; + } + +private slots: + void slotNewClass(); + void slotAddMethod(); + void slotAddAttribute(); + void slotOpenDeclaration(); + void slotOpenImplementation(); + void slotCreateAccessMethods(); + void slotFollowEditor(); + +protected: + void contentsContextMenuEvent( QContextMenuEvent* ); + void maybeTip( QPoint const & ); + +private slots: + void slotProjectOpened(); + void slotProjectClosed(); + void refresh(); + void insertFile( const QString& fileName ); + void removeFile( const QString& fileName ); + void slotExecuted( QListViewItem* item ); + +private: + ClassViewPart* m_part; + QStringList removedText; + QString m_projectDirectory; + int m_projectDirectoryLength; + FolderBrowserItem* m_projectItem; + KSelectAction* m_actionViewMode; + KAction* m_actionNewClass; + KAction* m_actionAddMethod; + KAction* m_actionAddAttribute; + KAction* m_actionOpenDeclaration; + KAction* m_actionOpenImplementation; + KAction* m_actionCreateAccessMethods; + KToggleAction * m_actionFollowEditor; + bool m_doFollowEditor; + friend class ClassViewItem; + friend class FolderBrowserItem; + friend class NamespaceDomBrowserItem; + friend class ClassDomBrowserItem; + friend class TypeAliasDomBrowserItem; + friend class FunctionDomBrowserItem; + friend class VariableDomBrowserItem; + TextPaintStyleStore m_paintStyles; +}; + +class ClassViewItem: public FancyListViewItem +{ + private: +public: + ClassViewItem( QListView* parent, const QString& text=QString::null ) + : FancyListViewItem( static_cast<ClassViewWidget*>( parent )->m_paintStyles, parent, text ) {} + ClassViewItem( QListViewItem* parent, const QString& text=QString::null ) + : FancyListViewItem( static_cast<ClassViewWidget*>( parent->listView() )->m_paintStyles, parent, text ) {} + + virtual const CodeModelItem* model() const { return 0; } + + virtual bool isFolder() const { return false; } + virtual bool isFile() const { return false; } + virtual bool isNamespace() const { return false; } + virtual bool isClass() const { return false; } + virtual bool isFunction() const { return false; } + virtual bool isVariable() const { return false; } + virtual bool isTypeAlias() const { return false; } + + virtual bool hasDeclaration() const { return false; } + virtual bool hasImplementation() const { return false; } + + virtual void openDeclaration() {} + virtual void openImplementation() {} + + void select(); + + virtual QString comment(); + + ClassViewWidget* listView() { return static_cast<ClassViewWidget*>( QListViewItem::listView() ); } + const ClassViewWidget* listView() const { return static_cast<ClassViewWidget*>( QListViewItem::listView() ); } +}; + +class FolderBrowserItem: public ClassViewItem +{ +public: + FolderBrowserItem( ClassViewWidget* widget, QListView* parent, const QString& name=QString::null ) + : ClassViewItem( parent, name ), m_widget(widget) {} + FolderBrowserItem( ClassViewWidget* widget, QListViewItem* parent, const QString& name=QString::null ) + : ClassViewItem( parent, name ), m_widget(widget) {} + + virtual bool isFolder() const { return true; } + + void setup(); + QString key( int, bool ) const; + + void processFile( FileDom file, QStringList& path, bool remove=false ); + void processNamespace( NamespaceDom ns, bool remove=false ); + void processClass( ClassDom klass, bool remove=false ); + void processTypeAlias( TypeAliasDom typeAlias, bool remove=false ); + void processFunction( FunctionDom fun, bool remove=false ); + void processVariable( VariableDom var, bool remove=false ); + bool selectItem(ItemDom item); + +private: + QMap<QString, FolderBrowserItem*> m_folders; + QMap<QString, NamespaceDomBrowserItem*> m_namespaces; + QMap<ClassDom, ClassDomBrowserItem*> m_classes; + QMap<TypeAliasDom, TypeAliasDomBrowserItem*> m_typeAliases; + QMap<FunctionDom, FunctionDomBrowserItem*> m_functions; + QMap<VariableDom, VariableDomBrowserItem*> m_variables; + + ClassViewWidget* m_widget; +}; + +class NamespaceDomBrowserItem: public ClassViewItem +{ +public: + NamespaceDomBrowserItem( QListView* parent, NamespaceDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + NamespaceDomBrowserItem( QListViewItem* parent, NamespaceDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + + const CodeModelItem* model() const { return m_dom; } + + virtual bool isNamespace() const { return true; } + + void setup(); + QString key( int, bool ) const; + + void processNamespace( NamespaceDom ns, bool remove=false ); + void processClass( ClassDom klass, bool remove=false ); + void processTypeAlias( TypeAliasDom typeAlias, bool remove=false ); + void processFunction( FunctionDom fun, bool remove=false ); + void processVariable( VariableDom var, bool remove=false ); + bool selectItem( ItemDom item ); + virtual QString comment(); + + NamespaceDom dom() { return m_dom; } + +private: + NamespaceDom m_dom; + QMap<QString, NamespaceDomBrowserItem*> m_namespaces; + QMap<ClassDom, ClassDomBrowserItem*> m_classes; + QMap<TypeAliasDom, TypeAliasDomBrowserItem*> m_typeAliases; + QMap<FunctionDom, FunctionDomBrowserItem*> m_functions; + QMap<VariableDom, VariableDomBrowserItem*> m_variables; +}; + +class ClassDomBrowserItem: public ClassViewItem +{ +public: + ClassDomBrowserItem( QListView* parent, ClassDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + ClassDomBrowserItem( QListViewItem* parent, ClassDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + + const CodeModelItem* model() const { return m_dom; } + virtual bool isClass() const { return true; } + + virtual bool hasDeclaration() const { return true; } + virtual void openDeclaration(); + + void setup(); + QString key( int, bool ) const; + + void processClass( ClassDom klass, bool remove=false ); + void processTypeAlias( TypeAliasDom typeAlias, bool remove=false ); + void processFunction( FunctionDom fun, bool remove=false ); + void processVariable( VariableDom var, bool remove=false ); + + virtual QString comment() { + if( !m_dom ) return ""; + return m_dom->comment(); + } + + bool selectItem(ItemDom item); + ClassDom dom() { return m_dom; } + +private: + ClassDom m_dom; + QMap<ClassDom, ClassDomBrowserItem*> m_classes; + QMap<TypeAliasDom, TypeAliasDomBrowserItem*> m_typeAliases; + QMap<FunctionDom, FunctionDomBrowserItem*> m_functions; + QMap<VariableDom, VariableDomBrowserItem*> m_variables; +}; + +class TypeAliasDomBrowserItem: public ClassViewItem +{ +public: + TypeAliasDomBrowserItem( QListView* parent, TypeAliasDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + TypeAliasDomBrowserItem( QListViewItem* parent, TypeAliasDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + + const CodeModelItem* model() const { return m_dom; } + virtual bool isTypeAlias() const { return true; } + + virtual bool hasDeclaration() const { return true; } + virtual void openDeclaration(); + + virtual QString comment() { + if( !m_dom ) return ""; + return m_dom->comment(); + } + + void setup(); + QString key( int, bool ) const; + + TypeAliasDom dom() { return m_dom; } + +private: + TypeAliasDom m_dom; +}; + +class FunctionDomBrowserItem: public ClassViewItem +{ +public: + FunctionDomBrowserItem( QListView* parent, FunctionDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + FunctionDomBrowserItem( QListViewItem* parent, FunctionDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + + const CodeModelItem* model() const { return m_dom; } + virtual bool isFunction() const { return true; } + + virtual bool hasDeclaration() const { return true; } + virtual bool hasImplementation() const; + + virtual void openDeclaration(); + virtual void openImplementation(); + + virtual QString comment() { + if( !m_dom ) return ""; + return m_dom->comment(); + } + + void setup(); + QString key( int, bool ) const; + + FunctionDom dom() { return m_dom; } + +private: + FunctionDom m_dom; +}; + +class VariableDomBrowserItem: public ClassViewItem +{ +public: + VariableDomBrowserItem( QListView* parent, VariableDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + VariableDomBrowserItem( QListViewItem* parent, VariableDom dom ) + : ClassViewItem( parent, dom->name() ), m_dom( dom ) {} + + const CodeModelItem* model() const { return m_dom; } + virtual bool isVariable() const { return true; } + + virtual bool hasDeclaration() const { return true; } + virtual bool hasImplementation() const { return false; } + + virtual QString comment() { + if( !m_dom ) return ""; + return m_dom->comment(); + } + + virtual void openDeclaration(); + virtual void openImplementation(); + + void setup(); + QString key( int, bool ) const; + + VariableDom dom() { return m_dom; } + +private: + VariableDom m_dom; +}; + +struct FindOp2 ///a template would look nicer +{ + FindOp2( const FunctionDefinitionDom& dom ): m_dom( dom ) {} + + bool operator() ( const FunctionDom& def ) const + { + if( m_dom->name() != def->name() ) + return false; + + if( m_dom->isConstant() != m_dom->isConstant() ) + return false; + + QString scope1 = QString("::") + m_dom->scope().join("::"); + QString scope2 = QString("::") + def->scope().join("::"); + if( !scope1.endsWith(scope2) ) + return false; + + const ArgumentList args = m_dom->argumentList(); + const ArgumentList args2 = def->argumentList(); + if( args.size() != args2.size() ) + return false; + + for( uint i=0; i<args.size(); ++i ){ + if( args[i]->type() != args[i]->type() ) + return false; + } + + return true; + } + + private: + const FunctionDefinitionDom& m_dom; +}; + +struct FindOp +{ + FindOp( const FunctionDom& dom ): m_dom( dom ) {} + + bool operator() ( const FunctionDefinitionDom& def ) const + { + if( m_dom->name() != def->name() ) + return false; + + if( m_dom->isConstant() != m_dom->isConstant() ) + return false; + + QString scope1 = QString("::") + m_dom->scope().join("::"); + QString scope2 = QString("::") + def->scope().join("::"); + if( !scope1.endsWith(scope2) ) + return false; + + const ArgumentList args = m_dom->argumentList(); + const ArgumentList args2 = def->argumentList(); + if( args.size() != args2.size() ) + return false; + + for( uint i=0; i<args.size(); ++i ){ + if( args[i]->type() != args2[i]->type() ) + return false; + } + + return true; + } + +private: + const FunctionDom& m_dom; +}; + +#endif diff --git a/parts/classview/digraphview.cpp b/parts/classview/digraphview.cpp new file mode 100644 index 00000000..b566757f --- /dev/null +++ b/parts/classview/digraphview.cpp @@ -0,0 +1,414 @@ +/*************************************************************************** + * Copyright (C) 2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "digraphview.h" + +#include <math.h> +#include <stdlib.h> +#include <qapplication.h> +#include <qpainter.h> +#include <qpaintdevicemetrics.h> +#include <qtextstream.h> +#include <kglobal.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kstandarddirs.h> +#include <kglobalsettings.h> +#include <ktempfile.h> +#include <kdeversion.h> +#include <kdebug.h> + +struct DigraphNode +{ + int x; + int y; + int w; + int h; + QString name; +}; + + +struct DigraphEdge +{ + QPointArray points; +}; + + +DigraphView::DigraphView(QWidget *parent, const char *name) + : QScrollView(parent, name, WRepaintNoErase|WStaticContents|WResizeNoErase) +{ + viewport()->setBackgroundMode(PaletteBase); + + QPaintDeviceMetrics m(this); + xscale = m.logicalDpiX(); + yscale = m.logicalDpiY(); + + width = -1; + height = -1; + + nodes.setAutoDelete(true); + edges.setAutoDelete(true); + selNode = 0; +} + + +DigraphView::~DigraphView() +{ +} + + +int DigraphView::toXPixel(double x) +{ + return (int) (x*xscale); +} + + +int DigraphView::toYPixel(double y) +{ + return height - (int) (y*yscale); +} + + +void DigraphView::setRenderedExtent(double w, double h) +{ + width = (int) (w*xscale); + height = (int) (h*yscale); + resizeContents(width+1, height+1); +} + + +void DigraphView::addRenderedNode(const QString &name, + double x, double y, double w, double h) +{ + DigraphNode *node = new DigraphNode; + node->x = toXPixel(x); + node->y = toYPixel(y); + node->w = (int) (w*xscale); + node->h = (int) (h*yscale); + node->name = name; + nodes.append(node); +} + + +void DigraphView::addRenderedEdge(const QString &/*name1*/, const QString &/*name2*/, + QMemArray<double> coords) +{ + if (coords.count() < 4) + return; + + DigraphEdge *edge = new DigraphEdge; + edge->points.resize(coords.count()/2); + + for (uint i = 0; i < edge->points.count(); ++i) + edge->points[i] = QPoint(toXPixel(coords[2*i]), toYPixel(coords[2*i+1])); + + edges.append(edge); +} + + +void DigraphView::addEdge(const QString &name1, const QString &name2) +{ + QString line; + line = "\""; + line += name1; + line += "\" -> \""; + line += name2; + line += "\";"; + inputs.append(line); +} + + +void DigraphView::clear() +{ + nodes.clear(); + edges.clear(); + selNode = 0; + width = -1; + height = -1; + inputs.clear(); + viewport()->update(); +} + + +void DigraphView::setSelected(const QString &name) +{ + QPtrListIterator<DigraphNode> it(nodes); + for (; it.current(); ++it) { + if (it.current()->name == name) { + updateContents(selNode->x-selNode->w/2, selNode->y-selNode->h/2, + selNode->w, selNode->h); + selNode = it.current(); + updateContents(selNode->x-selNode->w/2, selNode->y-selNode->h/2, + selNode->w, selNode->h); + return; + } + } +} + + +void DigraphView::ensureVisible(const QString &name) +{ + QPtrListIterator<DigraphNode> it(nodes); + for (; it.current(); ++it) { + if (it.current()->name == name) { + QScrollView::ensureVisible((*it)->x, (*it)->y, (*it)->w, (*it)->h); + return; + } + } +} + + +QStringList DigraphView::splitLine(QString str) +{ + QStringList result; + + while (!str.isEmpty()) { + if (str[0] == '"') { + int pos = str.find('"', 1); + if (pos == -1) + pos = str.length(); + result << str.mid(1, pos-1); + str.remove(0, pos+1); + } else { + int pos = str.find(' '); + if (pos == -1) + pos = str.length(); + result << str.left(pos); + str.remove(0, pos+1); + } + uint i = 0; while (i<str.length() && str[i] == ' ') ++i; + str.remove(0, i); + } + + return result; +} + + +void DigraphView::parseDotResults(const QStringList &list) +{ + QStringList::ConstIterator it; + for (it = list.begin(); it != list.end(); ++it) { + QStringList tokens = splitLine(*it); + if (tokens.count() == 0) + continue; + if (tokens[0] == "graph") { + if (tokens.count() < 4) + continue; + setRenderedExtent(tokens[2].toDouble(), tokens[3].toDouble()); + } else if (tokens[0] == "node") { + if (tokens.count() < 6) + continue; + addRenderedNode(tokens[1], tokens[2].toDouble(), tokens[3].toDouble(), + tokens[4].toDouble(), tokens[5].toDouble()); + } else if (tokens[0] == "edge") { + if (tokens.count() < 8) + continue; + QMemArray<double> coords(tokens.count()-6); + for (uint i=0; i != tokens.count()-6; ++i) + coords[i] = tokens[i+4].toDouble(); + addRenderedEdge(tokens[1], tokens[2], coords); + } + } +} + + +void DigraphView::process( const QString& file, const QString& ext ) +{ + QString cmd = KGlobal::dirs()->findExe("dot"); + if (cmd.isEmpty()) { + KMessageBox::sorry(0, i18n("You do not have 'dot' installed.\nIt can be downloaded from www.graphviz.org.")); + return; + } + + QStringList results; + + KTempFile ifile, ofile; + QTextStream &is = *ifile.textStream(); + is << "digraph G {" << endl; + is << "rankdir=LR;" << endl; + is << "node [shape=box,fontname=Helvetica,fontsize=12];" << endl; + QStringList::Iterator it; + for (it = inputs.begin(); it != inputs.end(); ++it) + is << (*it) << endl; + is << "}" << endl; + ifile.close(); + + KProcess proc; + if( !file.isEmpty() && !ext.isEmpty() ) + { + proc << cmd << QString("-T")+ext << ifile.name() << "-o" << file; + kdDebug() << "Executing: " << cmd <<" "<<QString("-T")+ext <<" "<< ifile.name() << "-o"<<file << endl; + }else + { + proc << cmd << "-Tplain" << ifile.name() << "-o" << ofile.name(); + } + proc.start(KProcess::Block); + + if( !file.isEmpty() && !ext.isEmpty() ) + { + return; + } + + QTextStream &os = *ofile.textStream(); + while (!os.atEnd()) + results << os.readLine(); + ofile.close(); + + parseDotResults(results); + inputs.clear(); + + if (nodes.first()) + selNode = nodes.first(); + viewport()->update(); +} + +void DigraphView::drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph) +{ + QRect clipRect(clipx, clipy, clipw, cliph); + p->eraseRect(clipRect); + + p->setFont(KGlobalSettings::generalFont()); + QPtrListIterator<DigraphNode> it1(nodes); + for (; it1.current(); ++it1) { + QRect r((*it1)->x-(*it1)->w/2, (*it1)->y-(*it1)->h/2, (*it1)->w, (*it1)->h); + if (r.intersects(clipRect)) { + if (it1.current() == selNode) + p->fillRect(r, QBrush(lightGray, SolidPattern)); + else + p->drawRect(r); + p->drawText(r, AlignCenter, (*it1)->name); + } + } + p->setBrush(QBrush(black, SolidPattern)); + QPtrListIterator<DigraphEdge> it2(edges); + for (; it2.current(); ++it2) { + int n = (*it2)->points.count(); + for (int i=0; i+3 < n; i+=3) + { + QPointArray a(4); + QPointArray &b = (*it2)->points; + for (int j=0; j<4; ++j) + a.setPoint(j, b.point(i+j)); + if (a.boundingRect().intersects(clipRect)) + p->drawCubicBezier((*it2)->points, i); + } + QPoint p1 = (*it2)->points[n-2]; + QPoint p2 = (*it2)->points[n-1]; + QPoint d = p1-p2; + double l = sqrt(d.x()*d.x()+d.y()*d.y()); + double d11 = (10.0)/l*d.x(); + double d12 = (10.0)/l*d.y(); + double d21 = -(3.0/l)*d.y(); + double d22 = (3.0/l)*d.x(); + QPointArray triangle(3); + triangle[0] = p2 + QPoint((int)(d11+d21),(int)(d12+d22)); + triangle[1] = p2 + QPoint((int)(d11-d21),(int)(d12-d22)); + triangle[2] = p2; + p->drawPolygon(triangle, true); + } +} + + +void DigraphView::contentsMousePressEvent(QMouseEvent *e) +{ + QPtrListIterator<DigraphNode> it1(nodes); + for (; it1.current(); ++it1) { + QRect r((*it1)->x-(*it1)->w/2, (*it1)->y-(*it1)->h/2, (*it1)->w, (*it1)->h); + if (r.contains(e->pos())) { + if (selNode) { + QRect oldr(selNode->x-selNode->w/2, selNode->y-selNode->h/2, + selNode->w, selNode->h); + updateContents(oldr); + } + selNode = it1.current(); + emit selected(selNode->name); + updateContents(r); + } + + } +} + + +QSize DigraphView::sizeHint() const +{ + if (width == -1) + return QSize(100, 100); // arbitrary + + QSize dsize = KGlobalSettings::desktopGeometry(viewport()).size(); + kdDebug(9003) << "sizehint for inheritance diagram" << dsize << " " << width << " " << height << endl; + return QSize(width, height).boundedTo(QSize(dsize.width()*2/3, dsize.height()*2/3)); +} + + +#if 0 +int main(int argc, char **argv) +{ + QApplication app(argc, argv); + + DigraphView *dw = new DigraphView(0, "dot widget"); +dw->addEdge( "5th Edition", "6th Edition"); +dw->addEdge( "5th Edition", "PWB 1.0"); +dw->addEdge( "6th Edition", "LSX"); +dw->addEdge( "6th Edition", "1 BSD"); +dw->addEdge( "6th Edition", "Mini Unix"); +dw->addEdge( "6th Edition", "Wollongong"); +dw->addEdge( "6th Edition", "Interdata"); +dw->addEdge( "Interdata", "Unix/TS 3.0"); +dw->addEdge( "Interdata", "PWB 2.0"); +dw->addEdge( "Interdata", "7th Edition"); +dw->addEdge( "7th Edition", "8th Edition"); +dw->addEdge( "7th Edition", "32V"); +dw->addEdge( "7th Edition", "V7M"); +dw->addEdge( "7th Edition", "Ultrix-11"); +dw->addEdge( "7th Edition", "Xenix"); +dw->addEdge( "7th Edition", "UniPlus+"); +dw->addEdge( "V7M", "Ultrix-11"); +dw->addEdge( "8th Edition", "9th Edition"); +dw->addEdge( "1 BSD", "2 BSD"); +dw->addEdge( "2 BSD", "2.8 BSD"); +dw->addEdge( "2.8 BSD", "Ultrix-11"); +dw->addEdge( "2.8 BSD", "2.9 BSD"); +dw->addEdge( "32V", "3 BSD"); +dw->addEdge( "3 BSD", "4 BSD"); +dw->addEdge( "4 BSD", "4.1 BSD"); +dw->addEdge( "4.1 BSD", "4.2 BSD"); +dw->addEdge( "4.1 BSD", "2.8 BSD"); +dw->addEdge( "4.1 BSD", "8th Edition"); +dw->addEdge( "4.2 BSD", "4.3 BSD"); +dw->addEdge( "4.2 BSD", "Ultrix-32"); +dw->addEdge( "PWB 1.0", "PWB 1.2"); +dw->addEdge( "PWB 1.0", "USG 1.0"); +dw->addEdge( "PWB 1.2", "PWB 2.0"); +dw->addEdge( "USG 1.0", "CB Unix 1"); +dw->addEdge( "USG 1.0", "USG 2.0"); +dw->addEdge( "CB Unix 1", "CB Unix 2"); +dw->addEdge( "CB Unix 2", "CB Unix 3"); +dw->addEdge( "CB Unix 3", "Unix/TS++"); +dw->addEdge( "CB Unix 3", "PDP-11 Sys V"); +dw->addEdge( "USG 2.0", "USG 3.0"); +dw->addEdge( "USG 3.0", "Unix/TS 3.0"); +dw->addEdge( "PWB 2.0", "Unix/TS 3.0"); +dw->addEdge( "Unix/TS 1.0", "Unix/TS 3.0"); +dw->addEdge( "Unix/TS 3.0", "TS 4.0"); +dw->addEdge( "Unix/TS++", "TS 4.0"); +dw->addEdge( "CB Unix 3", "TS 4.0"); +dw->addEdge( "TS 4.0", "System V.0"); +dw->addEdge( "System V.0", "System V.2"); +dw->addEdge( "System V.2", "System V.3"); + dw->process(); + dw->show(); + + return app.exec(); +} +#endif + +#include "digraphview.moc" diff --git a/parts/classview/digraphview.h b/parts/classview/digraphview.h new file mode 100644 index 00000000..c5fb2a28 --- /dev/null +++ b/parts/classview/digraphview.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * Copyright (C) 2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _DIGRAPHVIEW_H_ +#define _DIGRAPHVIEW_H_ + +#include <qptrlist.h> +#include <qscrollview.h> +#include <qstringlist.h> +#include <qimage.h> + +class DigraphNode; +class DigraphEdge; + + +class DigraphView : public QScrollView +{ + Q_OBJECT + +public: + DigraphView(QWidget *parent, const char *name); + ~DigraphView(); + + void addEdge(const QString &name1, const QString &name2); + void process(const QString& file = "", const QString& ext = ""); + void clear(); + void setSelected(const QString &name); + void ensureVisible(const QString &name); + +signals: + void selected(const QString &name); + +protected: + virtual void drawContents(QPainter* p, int clipx, int clipy, int clipw, int cliph); + virtual void contentsMousePressEvent(QMouseEvent *e); + virtual QSize sizeHint() const; + +private: + int toXPixel(double x); + int toYPixel(double x); + + void setRenderedExtent(double w, double h); + void addRenderedNode(const QString &name, + double x, double y, double w, double h); + void addRenderedEdge(const QString &name1, const QString &name2, + QMemArray<double> coords); + static QStringList splitLine(QString str); + void parseDotResults(const QStringList &list); + + double xscale, yscale; + int width, height; + QStringList inputs; + QPtrList<DigraphNode> nodes; + QPtrList<DigraphEdge> edges; + DigraphNode *selNode; +}; + +#endif diff --git a/parts/classview/hierarchydlg.cpp b/parts/classview/hierarchydlg.cpp new file mode 100644 index 00000000..21a54031 --- /dev/null +++ b/parts/classview/hierarchydlg.cpp @@ -0,0 +1,276 @@ +/*************************************************************************** + * Copyright (C) 2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "hierarchydlg.h" + +#include <kdialog.h> +#include <klocale.h> +#include <kpushbutton.h> +#include <kstdguiitem.h> +#include <kfile.h> +#include <kfiledialog.h> +#include <kurlrequesterdlg.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include <qlayout.h> +#include <qfileinfo.h> +#include <qlistview.h> +#include <qapplication.h> +#include <qsplitter.h> + +#include "kdevlanguagesupport.h" +#include "kcomboview.h" + +#include "classviewpart.h" +//#include "classtoolwidget.h" +#include "digraphview.h" +#include "viewcombos.h" + + +HierarchyDialog::HierarchyDialog( ClassViewPart *part ) + : QDialog(0, "hierarchy dialog", false) +{ + class_combo = new KComboView(true, 150, this); + class_combo->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); +// class_combo->setMinimumWidth(150); + namespace_combo = new KComboView(true, 150, this); + namespace_combo->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); +// namespace_combo->setMinimumWidth(150); + + QPushButton *close_button = new KPushButton(KStdGuiItem::close(), this); + QPushButton *save_button = new KPushButton(KStdGuiItem::save(), this); + QPushButton *refresh_button = new KPushButton(i18n("Refresh"), this); + + QSplitter *splitter = new QSplitter(Vertical, this); + digraph = new DigraphView(splitter, "digraph view"); +// member_tree = new ClassToolWidget(part, splitter); + + QBoxLayout *layout = new QVBoxLayout(this, KDialog::marginHint(), KDialog::spacingHint()); + QBoxLayout *combo_layout = new QHBoxLayout(); + layout->addLayout(combo_layout); + combo_layout->addWidget(namespace_combo); + combo_layout->addWidget(class_combo); + combo_layout->addSpacing(60); + combo_layout->addWidget(refresh_button); + combo_layout->addWidget(save_button); + combo_layout->addWidget(close_button); + layout->addWidget(splitter); + + connect( namespace_combo, SIGNAL(activated(QListViewItem*)), + this, SLOT(slotNamespaceComboChoice(QListViewItem*)) ); + connect( class_combo, SIGNAL(activated(QListViewItem*)), + this, SLOT(slotClassComboChoice(QListViewItem*)) ); + connect( namespace_combo, SIGNAL(textChanged(const QString&)), + this, SLOT(slotNamespaceComboChoice(const QString&)) ); + connect( class_combo, SIGNAL(textChanged(const QString&)), + this, SLOT(slotClassComboChoice(const QString&)) ); + connect( close_button, SIGNAL(clicked()), + this, SLOT(hide()) ); + connect( save_button, SIGNAL(clicked()), + this, SLOT(save()) ); + connect( refresh_button, SIGNAL(clicked()), + this, SLOT(refresh()) ); + connect( digraph, SIGNAL(selected(const QString&)), + this, SLOT(classSelected(const QString&)) ); + + m_part = part; +// m_part->registerHierarchyDialog(this); + refresh(); +} + + +HierarchyDialog::~HierarchyDialog() +{ +// m_part->unregisterHierarchyDialog(this); +} + +void HierarchyDialog::save() +{ + KURLRequesterDlg dlg(QString::null, this, "save_inheritance"); + dlg.fileDialog()->setFilter("image/png image/jpeg image/bmp image/svg+xml"); + dlg.fileDialog()->setOperationMode( KFileDialog::Saving ); + dlg.fileDialog()->setMode( KFile::File | KFile::LocalOnly ); + dlg.urlRequester()->setMode( KFile::File | KFile::LocalOnly ); + if(dlg.exec() && dlg.selectedURL().isLocalFile()) + { + QFileInfo fi(dlg.selectedURL().pathOrURL()); + QApplication::setOverrideCursor( Qt::waitCursor ); + KDevLanguageSupport *ls = m_part->languageSupport(); + for (QMap<QString, ClassDom>::const_iterator it = classes.begin(); it != classes.end(); ++it) + { + kdDebug(9003) << "Adding class to graph: " << it.key() << endl; + QString formattedName = ls->formatClassName(it.key()); + QStringList baseClasses = it.data()->baseClassList(); + for (QStringList::const_iterator bit = baseClasses.begin(); bit != baseClasses.end(); ++bit) + { + QMap<QString, QString>::const_iterator baseIt = uclasses.find(*bit); + if (baseIt != uclasses.end()) + { + QString formattedParentName = ls->formatClassName(baseIt.data()); + digraph->addEdge(formattedParentName, formattedName); + } + } + } + digraph->process(fi.absFilePath(), fi.extension()); + QApplication::restoreOverrideCursor(); + } +} + +void HierarchyDialog::refresh() +{ + digraph->clear(); + classes.clear(); + uclasses.clear(); + ViewCombosOp::refreshNamespaces(m_part, namespace_combo); + processNamespace("", m_part->codeModel()->globalNamespace()); + + KDevLanguageSupport *ls = m_part->languageSupport(); + + for (QMap<QString, ClassDom>::const_iterator it = classes.begin(); it != classes.end(); ++it) + { + kdDebug(9003) << "Adding class to graph: " << it.key() << endl; + QString formattedName = ls->formatClassName(it.key()); + QStringList baseClasses = it.data()->baseClassList(); + for (QStringList::const_iterator bit = baseClasses.begin(); bit != baseClasses.end(); ++bit) + { + QMap<QString, QString>::const_iterator baseIt = uclasses.find(*bit); + if (baseIt != uclasses.end()) + { + QString formattedParentName = ls->formatClassName(baseIt.data()); + digraph->addEdge(formattedParentName, formattedName); + } + } + } + digraph->process(); +} + +void HierarchyDialog::setLanguageSupport(KDevLanguageSupport *ls) +{ + if (ls) + connect(ls, SIGNAL(updatedSourceInfo()), this, SLOT(refresh())); + else + refresh(); +} + + +void HierarchyDialog::slotClassComboChoice(QListViewItem * item) +{ + ClassItem *ci = dynamic_cast<ClassItem*>(item); + if (!ci) + return; + + KDevLanguageSupport *ls = m_part->languageSupport(); + + QString className = ls->formatClassName(uclasses[item->text(0)]); + digraph->setSelected(className); + digraph->ensureVisible(className); + classSelected(className); +} + +void HierarchyDialog::slotClassComboChoice( const QString& itemText ) +{ + QListViewItem* item = class_combo->listView()->firstChild(); + while( item ) + { + if( item->text(0) == itemText ) + { + ClassItem *ci = dynamic_cast<ClassItem*>(item); + if (!ci) + return; + + KDevLanguageSupport *ls = m_part->languageSupport(); + + QString className = ls->formatClassName(uclasses[item->text(0)]); + digraph->setSelected(className); + digraph->ensureVisible(className); + classSelected(className); + return; + } + item = item->nextSibling(); + } +} + +void HierarchyDialog::classSelected(const QString &/*className*/) +{ +/* ParsedClass *currentClass = m_part->classStore()->getClassByName(className); + member_tree->clear(); + if (currentClass) { + KDevLanguageSupport::Features features = m_part->languageSupport()->features(); + if (features & KDevLanguageSupport::Functions) + member_tree->insertAllClassMethods(currentClass, (PIAccess)-1); + if (features & KDevLanguageSupport::Variables) + member_tree->insertAllClassAttributes(currentClass, (PIAccess)-1); + }*/ +} + +void HierarchyDialog::slotNamespaceComboChoice( QListViewItem * item ) +{ + NamespaceItem *ni = dynamic_cast<NamespaceItem*>(item); + if (!ni) + return; + ViewCombosOp::refreshClasses(m_part, class_combo, ni->dom()->name()); +} + +void HierarchyDialog::slotNamespaceComboChoice( const QString& itemText ) +{ + QListViewItem* item = namespace_combo->listView()->firstChild(); + while( item ) + { + if( item->text(0) == itemText ) + { + NamespaceItem *ni = dynamic_cast<NamespaceItem*>(item); + if (!ni) + return; + ViewCombosOp::refreshClasses(m_part, class_combo, ni->dom()->name()); + return; + } + item = item->nextSibling(); + } +} + +void HierarchyDialog::processNamespace( QString prefix, NamespaceDom dom ) +{ + qWarning("processNamespace: prefix %s", prefix.latin1()); + QString prefixInc = prefix.isEmpty() ? "" : "."; +// QString nsprefix = dom->name().isEmpty() ? QString("") : prefixInc + dom->name(); + + NamespaceList namespaceList = dom->namespaceList(); + for (NamespaceList::const_iterator it = namespaceList.begin(); it != namespaceList.end(); ++it) + { + qWarning("about to processNamespace: prefix %s", (prefixInc + (*it)->name()).latin1()); + processNamespace(prefixInc + (*it)->name(), *it); + } + + ClassList classList = dom->classList(); + for (ClassList::const_iterator it = classList.begin(); it != classList.end(); ++it) + { + processClass(prefix, *it); + } +} + +void HierarchyDialog::processClass( QString prefix, ClassDom dom ) +{ + qWarning("processClass: prefix %s class %s", prefix.latin1(), dom->name().latin1()); + + QString prefixInc = prefix.isEmpty() ? "" : "."; + classes[prefix + prefixInc + dom->name()] = dom; + uclasses[dom->name()] = prefix + prefixInc + dom->name(); + + ClassList classList = dom->classList(); + for (ClassList::const_iterator it = classList.begin(); it != classList.end(); ++it) + { + processClass(prefix + prefixInc + dom->name(), *it); + } +} + +#include "hierarchydlg.moc" diff --git a/parts/classview/hierarchydlg.h b/parts/classview/hierarchydlg.h new file mode 100644 index 00000000..82cf2d4a --- /dev/null +++ b/parts/classview/hierarchydlg.h @@ -0,0 +1,61 @@ +/*************************************************************************** + * Copyright (C) 2001 by Bernd Gehrmann * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _HIERARCHYDLG_H_ +#define _HIERARCHYDLG_H_ + +#include <qdialog.h> + +#include "codemodel.h" + +class ClassViewPart; +class KDevLanguageSupport; +class DigraphView; +class ClassToolWidget; +class KComboView; +class QListViewItem; + +class HierarchyDialog : public QDialog +{ + Q_OBJECT + +public: + HierarchyDialog( ClassViewPart *part ); + ~HierarchyDialog(); +public slots: + void refresh(); + +private slots: + void setLanguageSupport(KDevLanguageSupport *ls); + void slotClassComboChoice(QListViewItem *item); + void slotNamespaceComboChoice(QListViewItem *item); + void slotClassComboChoice(const QString&); + void slotNamespaceComboChoice(const QString&); + void classSelected(const QString &className); + void save(); + +private: + void processNamespace(QString prefix, NamespaceDom dom); + void processClass(QString prefix, ClassDom dom); + + QMap<QString, ClassDom> classes; + //QMap<class name, fully qualified class name> + //like MyClass - MyNamespace.MyClass + QMap<QString, QString> uclasses; + + KComboView *namespace_combo; + KComboView *class_combo; + DigraphView *digraph; +// ClassToolWidget *member_tree; + ClassViewPart *m_part; +}; + +#endif diff --git a/parts/classview/kdevclassview.desktop b/parts/classview/kdevclassview.desktop new file mode 100644 index 00000000..08c0de1e --- /dev/null +++ b/parts/classview/kdevclassview.desktop @@ -0,0 +1,82 @@ +[Desktop Entry] +Type=Service +Exec=blubb +Comment=This plugin displays a graphical view of all the classes in the project, complete with methods and attributes, and provides a way of direct source navigation. +Comment[ca]=Aquest connector mostra una vista gràfica de totes les classes del projecte, completant-lo amb mètodes i atributs, i proporciona una forma de navegar directament a través del codi font. +Comment[da]=Dette plugin giver en grafisk visning af alle klasserne i projektet, fuldstændig med metoder og attributter og sørger for en måde at have direkte kildenavigation. +Comment[de]=Dieses Modul zeigt eine grafische Ansicht aller Klassen im Projekt, einschließlich der Methoden und Attribute und ermöglicht die Navigation in den betreffenden Quelltexten. +Comment[el]=Αυτό το πρόσθετο εμφανίζει μια γραφική προβολή όλων των κλάσεων του έργου, πλήρης με μεθόδους και χαρακτηριστικά, και προσφέρει μια μέθοδο απευθείας πλοήγησης στον κώδικα. +Comment[es]=Este complemento muestra una vista gráfica de todas las clases del proyecto, completándolo con métodos y atributos, y proporciona una forma de navegar directamente por el código fuente. +Comment[et]=See plugin näitab graafiliselt kõiki projekti klasse koos meetodite ja atribuutidega ning võimaldab nende vahel kiiresti liikuda. +Comment[eu]=Plugin honek proiektuak dituen klase guztien ikuspegi grafiko bat bistaratzen du, metodo eta atributuekin osatuta, eta iturburuen arteko nabigazio zuzena eskeintzen du. +Comment[fa]=این وصله یک نمای نگارهای از همۀ ردهها در پروژه را نمایش میدهد، با روشها و ویژگیها کامل میکند و یک راه ناوش مستقیم منبع فراهم میکند. +Comment[fr]=Ce module externe affiche une vue graphique de toutes les classes dans le projet, la complète avec des méthodes et des attributs, et offre un moyen de naviguer directement dans le source. +Comment[gl]=Esta extensión mostra unha vista gráfica de tódalas clases do proxecto, cos métodos e os atributos, e proporciona unha maneira para navegar o código directamente. +Comment[hu]=Bővítőmodul egy projekt osztályainak áttekintéséhez, a tagfüggvényekkel és az attribútumokkal együtt, navigálási lehetőséggel +Comment[it]=Questo plugin offre una rappresentazione grafica di tutte le classi nel progetto, complete con metodi e attributi, e fornisce un modo per la navigazione diretta nei sorgenti. +Comment[ja]=このプラグインは、プロジェクトの中のすべてのクラスを視覚的に表示します。また、メソッドや属性を補完し、直接的なソース操作を提供します。 +Comment[ms]=Plugin ini memaparkan paparan bergrafik bagi semua kelas dalam projek, lengkap dengan kaedah dan ciri, dan menyediakan kaedah kemudian sumber secara terus. +Comment[nds]=Dit Moduul wiest en graafsch Ansicht vun all Klassen vun en Projekt, komplett mit Metoden un Attributen, un stellt dat Stüern binnen de Borntexten praat. +Comment[ne]=यो प्लगइनले विधि र विशेषतासँग परियोजनामा सबै कक्षको ग्राफिकल दृश्य प्रर्दशन गर्दछ र प्रत्यक्ष स्रोत नेभिगेसनको उपाय प्रदान गर्दछ । +Comment[nl]=Deze plugin toont een grafische weergave van alle klassen in een project, compleet met methoden en attributen, en biedt directe navigatie hiertussen. +Comment[pl]=Ta wtyczka pokazuje graficzny widok wszystkich klas w projekcie z metodami i atrybutami oraz umożliwia bezpośrednią nawigację w kodzie źródłowym.. +Comment[pt]=Este 'plugin' mostra uma vista gráfica de todas as classes no projecto, completas com os métodos e atributos, oferecendo uma forma de navegação directa sobre o código. +Comment[pt_BR]=Este plug-in exibe uma visão gráfica de todas as classes no projeto, juntamente com métodos e atributos, e fornece uma maneira de navegar diretamente no código. +Comment[ru]=Этот модуль показывает список классов в проекте, включая методы и атрибуты, а также предоставляет возможности навигации по коду. +Comment[sk]=Modul zobrazí grafický pohľad na triedy v projekte, spolu s metódami a atribútmi, a umožní priamy prístup k zdrojovému kódu. +Comment[sr]=Овај прикључак приказује графички изглед свих класа у пројекту, заједно са методама и атрибутима, и обезбеђује начин директне навигације кроз изворни кôд. +Comment[sr@Latn]=Ovaj priključak prikazuje grafički izgled svih klasa u projektu, zajedno sa metodama i atributima, i obezbeđuje način direktne navigacije kroz izvorni kôd. +Comment[sv]=Insticksprogrammet visar en grafisk bild av alla klasser i ett projekt, tillsammans med metoder och egenskaper, och ger möjlighet till direkt navigering i källkoden. +Comment[ta]=இந்த சொருகி திட்டப்பணியில் உள்ள வகுப்புகளின், முறைகள் மற்றும் பண்புகளை உங்களுக்கு வரைகலை பார்வையில் அளிக்கும்,மற்றும் மூலத்தை வழி செலுத்த இது நேர்வழி அளிக்கும். +Comment[tg]=Ин модул рӯйхати синфҳоро дар лоиҳа намоиш медиҳад, ва боз методҳо ва атрибутҳо ва боз ҳам имкони кодро роҳ медиҳад. +Comment[tr]=Bu eklenti projedeki sınıfların bütün yöntem ve öznitelikleri ile grafiksel bir görünümü gösterir ve doğrudan kaynak dolaşımını sağlar. +Comment[zh_CN]=这个插件以图形显示工程中所有的类,包括完整的方法和属性,并提供浏览源文件的方法。 +Comment[zh_TW]=這個外掛程式顯示專案中所有類別、完整方法與屬性的圖形檢視,並提供源碼導覽。 +Name=KDevClassView +Name[da]=KDevelop klassevisning +Name[de]=Klassenansicht (KDevelop) +Name[hi]=के-डेव-क्लॉस-व्यू +Name[nds]=KlassKieker (KDevelop) +Name[pl]=KDevWidokKlas +Name[sk]=KDev pohľad na triedy +Name[sv]=KDevelop klassvisning +Name[tg]=Намоиши снфи KDev +Name[zh_TW]=KDevelop 類別檢視 +GenericName=Class View +GenericName[ca]=Visor de classes +GenericName[da]=Klassevisning +GenericName[de]=Klassenansicht +GenericName[el]=Προβολή κλάσεων +GenericName[es]=Visor de clases +GenericName[et]=Klasside vaade +GenericName[eu]=Klase ikuspegia +GenericName[fa]=نمای رده +GenericName[fr]=Vue des classes +GenericName[gl]=Vista de clases +GenericName[hi]=क्लॉस व्यू +GenericName[hu]=Osztálynézegető +GenericName[it]=Visualizza classe +GenericName[ja]=クラスビュー +GenericName[ms]=Paparan Kelas +GenericName[nds]=Klasskieker +GenericName[ne]=कक्ष दृश्य +GenericName[nl]=Klassenweergave +GenericName[pl]=Widok klas +GenericName[pt]=Vista de Classe +GenericName[pt_BR]=Visualizador de Classe +GenericName[ru]=Просмотр классов +GenericName[sk]=Pohľad na triedy +GenericName[sl]=Prikaz razreda +GenericName[sr]=Преглед класа +GenericName[sr@Latn]=Pregled klasa +GenericName[sv]=Klassvisning +GenericName[ta]=வகுப்புக்காட்சி +GenericName[tg]=Намоиши синфҳо +GenericName[tr]=Sınıf Görünümü +GenericName[zh_CN]=类查看器 +GenericName[zh_TW]=類別檢視 +ServiceTypes=KDevelop/CodeBrowserFrontend +X-KDE-Library=libkdevclassview +X-KDevelop-Version=5 +X-KDevelop-Scope=Project +X-KDevelop-Properties=CodeNavigation diff --git a/parts/classview/kdevclassview.rc b/parts/classview/kdevclassview.rc new file mode 100644 index 00000000..b5f7a9fb --- /dev/null +++ b/parts/classview/kdevclassview.rc @@ -0,0 +1,20 @@ +<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd"> +<kpartgui name="KDevClassView" version="10"> +<MenuBar> + <Menu name="project" > + <Action name="inheritance_dia" group="project_classes" /> + </Menu> +</MenuBar> +<Menu name="kdevhidden" > + <Action name="navigator_jump_to_next_function"/> + <Action name="navigator_jump_to_previous_function"/> +</Menu> + +<ToolBar name="browserToolBar"> + <text>Browser Toolbar</text> + <Separator/> + <Action name="classview_sync_with_editor" /> + <Action name="functionsnav_combo" /> +</ToolBar> +</kpartgui> + diff --git a/parts/classview/navigator.cpp b/parts/classview/navigator.cpp new file mode 100644 index 00000000..f0e2ff19 --- /dev/null +++ b/parts/classview/navigator.cpp @@ -0,0 +1,539 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * [email protected] * + * Portions Copyright (C) 2002-2003 by Roberto Raggi * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#include "navigator.h" + +#include <qtimer.h> + +#include <kconfig.h> +#include <kdebug.h> +#include <kiconloader.h> +#include <kapplication.h> +#include <ktexteditor/viewcursorinterface.h> + +#include <kcomboview.h> +#include <klistviewaction.h> +#include <kdevpartcontroller.h> +#include <kdevlanguagesupport.h> +#include <kdevmainwindow.h> +#include <codemodel_utils.h> +#include "classviewpart.h" +#include "classviewwidget.h" + +//using namespace Widgets; + +//#define BOLDFONTSMALLER + + +namespace +{ + template<class T> + QValueList<T> QValueList_reversed ( const QValueList<T> & list ) + { + QValueList<T> rList; + typename QValueList<T>::ConstIterator it = list.begin(); + while ( it != list.end() ) + { + rList.push_front ( *it ); + ++it; + } + return rList; + } +} + +struct NavOp +{ + NavOp(Navigator *navigator, const QString &fullName) + :m_navigator(navigator), m_fullName(fullName) {} + + bool operator() ( const FunctionDefinitionDom& def ) const + { + return (m_navigator->fullFunctionDefinitionName(def) == m_fullName); + } + bool operator() ( const FunctionDom& def ) const + { + return (m_navigator->fullFunctionDeclarationName(def) == m_fullName); + } + +private: + Navigator *m_navigator; + QString m_fullName; +}; + + + +class FunctionNavItem: public FancyListViewItem { +private: +public: + enum Type { Declaration, Definition }; + + FunctionNavItem(TextPaintStyleStore& styles, ClassViewPart *part, QListView *parent, QString name, Type type) + :FancyListViewItem(styles, parent, name, ""), m_part(part), m_type(type) {} + FunctionNavItem(TextPaintStyleStore& styles, ClassViewPart *part, QListViewItem *parent, QString name, Type type) + :FancyListViewItem(styles, parent, name, ""), m_part(part), m_type(type) {} + ~FunctionNavItem() {} + + virtual void setup() + { + FancyListViewItem::setup(); + setPixmap( 0, UserIcon("CVpublic_meth", KIcon::DefaultState, m_part->instance()) ); + } + Type type() { return m_type; } + +private: + ClassViewPart *m_part; + Type m_type; +}; + + +Navigator::Navigator(ClassViewPart *parent, const char *name) + : QObject(parent, name), m_part(parent) +{ + m_state = GoToDefinitions; + m_navNoDefinition = true; + + m_actionSyncWithEditor = new KAction( i18n("Sync ClassView"), "view_tree", KShortcut(), this, + SLOT(slotSyncWithEditor()), m_part->actionCollection(), "classview_sync_with_editor" ); + + KAction * action = new KAction( i18n("Jump to next function"), CTRL+ALT+Key_PageDown, this, + SLOT(slotJumpToNextFunction()), m_part->actionCollection(), "navigator_jump_to_next_function" ); + action->plug( &m_dummyActionWidget ); + + action = new KAction( i18n("Jump to previous function"), CTRL+ALT+Key_PageUp, this, + SLOT(slotJumpToPreviousFunction()), m_part->actionCollection(), "navigator_jump_to_previous_function" ); + action->plug( &m_dummyActionWidget ); + + m_syncTimer = new QTimer(this); + connect(m_syncTimer, SIGNAL(timeout()), this, SLOT(syncFunctionNav())); +} + +Navigator::~Navigator() +{ +} + +void Navigator::selectFunctionNav(QListViewItem *item) +{ + FunctionNavItem *nav = dynamic_cast<FunctionNavItem*>(item); + if (!nav) + return; + + FileDom file = m_part->codeModel()->fileByName(m_part->m_activeFileName); + if (!file) + return; + + switch (nav->type()) + { + case FunctionNavItem::Definition: //jump to definition + { + FileList files = file->wholeGroup(); + FunctionDefinitionList deflist; + CodeModelUtils::findFunctionDefinitions(NavOp(this, nav->text(0)), files, deflist); + if (deflist.count() < 1) + return; + + FunctionDefinitionDom fun = deflist.first(); + if (!fun) + return; + int startLine = 0, startColumn = 0; + fun->getStartPosition(&startLine, &startColumn); + m_part->partController()->editDocument(KURL(fun->fileName()), startLine); + break; + } + case FunctionNavItem::Declaration: //jump to declaration + { + FileList files = file->wholeGroup(); + FunctionList declist; + CodeModelUtils::findFunctionDeclarations(NavOp(this, nav->text(0)), files, declist); + if (declist.count() < 1) + return; + + FunctionDom fun = declist.first(); + if (!fun) + return; + int startLine = 0, startColumn = 0; + fun->getStartPosition(&startLine, &startColumn); + m_part->partController()->editDocument(KURL(fun->fileName()), startLine); + break; + } + } +} + +void Navigator::functionNavUnFocused() +{ + /*if (m_navNoDefinition) + m_part->m_functionsnav->view()->setCurrentText(NAV_NODEFINITION); + else*/ + if (m_part->m_functionsnav->view()->currentItem()) + m_part->m_functionsnav->view()->setCurrentText(m_part->m_functionsnav->view()->currentItem()->text(0)); + else + m_part->m_functionsnav->view()->setCurrentText(NAV_NODEFINITION); +} + +void Navigator::functionNavFocused() +{ + m_navNoDefinition = (m_part->m_functionsnav->view()->currentText() == NAV_NODEFINITION); + m_part->m_functionsnav->view()->setCurrentText(""); +} + +void Navigator::slotCursorPositionChanged() +{ + //FIXME: we assume that background parser delay is set globally in kdeveloprc file + //for all available language supports + //this is reasonable assumption because problem reporter should be the same for all languages + KConfig* config = kapp->config(); + config->setGroup( "General Options" ); + int m_delay = config->readNumEntry( "BgParserDelay", 500 ); + + m_syncTimer->changeInterval(500 >= m_delay+100 ? 500 : m_delay+100 ); +} + +void Navigator::stopTimer( ) +{ + m_syncTimer->stop(); +} + +void Navigator::syncFunctionNavDelayed(int delay) +{ + m_syncTimer->changeInterval(delay); +} + +void Navigator::syncFunctionNav() +{ + m_syncTimer->stop(); + + if (FunctionDom fun = currentFunction()) + { + if ( m_part->widget()->doFollowEditor() ) + { + ItemDom dom(fun); + m_part->jumpedToItem( dom ); + } + + if( !fun->isFunctionDefinition() ) { + if (m_functionNavDecls[fullFunctionDeclarationName(fun)]) + { + m_part->m_functionsnav->view()->blockSignals(true); + m_part->m_functionsnav->view()->setCurrentActiveItem(m_functionNavDecls[fullFunctionDeclarationName(fun)]); + m_part->m_functionsnav->view()->blockSignals(false); + } + } else { + if (m_functionNavDefs[fullFunctionDeclarationName(fun)]) + { + m_part->m_functionsnav->view()->blockSignals(true); + m_part->m_functionsnav->view()->setCurrentActiveItem(m_functionNavDefs[fullFunctionDeclarationName(fun)]); + m_part->m_functionsnav->view()->blockSignals(false); + } + } + } + else + m_part->m_functionsnav->view()->setCurrentText(NAV_NODEFINITION); +} + +void Navigator::refreshNavBars(const QString &activeFileName, bool clear) +{ + kdDebug(9003) << k_funcinfo << endl; + if (clear) + { + m_part->m_functionsnav->view()->clear(); + m_functionNavDefs.clear(); + m_functionNavDecls.clear(); + } + + FileDom file = m_part->codeModel()->fileByName(activeFileName); + if (!file) + return; + + QStringList toLeave; + + FunctionList list1 = CodeModelUtils::allFunctionsExhaustive(file); + FunctionList::const_iterator flEnd = list1.end(); + for (FunctionList::const_iterator it = list1.begin(); it != flEnd; ++it) + { + QString fullName = fullFunctionDeclarationName(*it); + + if (clear || !m_functionNavDecls[fullName] && m_part->m_functionsnav->view()->listView()) + { + FunctionNavItem *item = new FunctionNavItem(m_styles, m_part, + m_part->m_functionsnav->view()->listView(), fullName, + FunctionNavItem::Declaration); + m_functionNavDecls[fullName] = item; + item->setItem( 0, fullFunctionItem( *it ) ); + + m_part->m_functionsnav->view()->addItem(item); + } + toLeave << fullName; + } + kdDebug(9003) << k_funcinfo << "leave list: " << toLeave << endl; + + //remove items not in toLeave list + QMap<QString, QListViewItem*>::iterator it = m_functionNavDecls.begin(); + while ( it != m_functionNavDecls.end() ) + { + QMap<QString, QListViewItem*>::iterator it2 = it; + ++it; + if ( !toLeave.contains( it2.key() ) ) + { + if (it2.data()) + { + m_part->m_functionsnav->view()->removeItem(it2.data()); + } + m_functionNavDecls.remove(it2); + } + } + + toLeave.clear(); + FunctionDefinitionList list = CodeModelUtils::allFunctionDefinitionsExhaustive(file); + for (FunctionDefinitionList::const_iterator it = list.begin(); it != list.end(); ++it) + { + QString fullName = fullFunctionDefinitionName(*it); + + if (clear || !m_functionNavDefs[fullName]) + { + FunctionNavItem *item = new FunctionNavItem(m_styles, m_part, + m_part->m_functionsnav->view()->listView(), fullName, FunctionNavItem::Definition); + m_functionNavDefs[fullName] = item; + item->setItem( 0, fullFunctionItem( *it ) ); + m_part->m_functionsnav->view()->addItem(item); + } + + //remove unnecessary items with function declarations for which a definition item was created + if (m_functionNavDecls[fullName]) + { + m_part->m_functionsnav->view()->removeItem(m_functionNavDecls[fullName]); + m_functionNavDecls.remove(fullName); + } + + toLeave << fullName; + } + + kdDebug(9003) << k_funcinfo << "leave list: " << toLeave << endl; + //remove items not in toLeave list + QMap<QString, QListViewItem*>::iterator itt = m_functionNavDefs.begin(); + while ( itt != m_functionNavDefs.end() ) + { + QMap<QString, QListViewItem*>::iterator it2 = itt; + ++itt; + if ( !toLeave.contains( it2.key() ) ) + { + if (it2.data()) + { + m_part->m_functionsnav->view()->removeItem(it2.data()); + } + m_functionNavDefs.remove(it2); + } + } +} + +void Navigator::refresh() +{ + refreshNavBars(m_part->m_activeFileName, true); +} + +void Navigator::addFile(const QString & file) +{ + kdDebug(9003) << k_funcinfo << "file: " << file << endl; + if (file == m_part->m_activeFileName) + { + kdDebug(9003) << k_funcinfo << "processing active file" << endl; + refreshNavBars(m_part->m_activeFileName, false); + } +} + + + + +FunctionDom Navigator::currentFunction() +{ + if (!m_part->m_activeViewCursor) + return FunctionDom(); + + unsigned int line, column; + m_part->m_activeViewCursor->cursorPositionReal(&line, &column); + CodeModelUtils::CodeModelHelper hlp( m_part->codeModel(), m_part->codeModel()->fileByName( m_part->m_activeFileName) ); + return hlp.functionAt( line, column ); +} + + +///Some time this might be moved into the language-support-part, so each language +///can highlight as it likes +TextPaintItem highlightFunctionName(QString function, int type, TextPaintStyleStore& styles) { + TextPaintItem ret; + + if( !styles.hasStyle( type ) ) { + QFont font = styles.getStyle( 0 ).font; + + switch(type) { + case 1: + default: + font.setWeight( QFont::DemiBold ); + ///since bold makes the font a little bigger, make it smaller again +#ifdef BOLDFONTSMALLER + font.setPointSize( (font.pointSize() * 9) / 10 ); +#endif + } + + styles.addStyle( type, font ); + } + + QString args; + QString fScope; + int cutpos; + + if((cutpos = function.find('(')) != -1) { + args = function.right( function.length() - cutpos ); + function = function.left( cutpos ); + } else { + ret.addItem( function ); + return ret; + } + if((cutpos = function.findRev(':')) != -1 || (cutpos = function.findRev('.')) != -1) { + fScope = function.left( cutpos + 1 ); + function = function.right( function.length() - cutpos - 1); + } + if( !fScope.isEmpty() ) ret.addItem(fScope); + ret.addItem( function, type ); + if( !args.isEmpty() ) ret.addItem(args); + return ret; +} + + +template <class DomType> +TextPaintItem Navigator::fullFunctionItem(DomType fun) +{ + + QStringList scope = fun->scope(); + QString function = scope.join("."); + if (!function.isEmpty()) + function += "."; + function += m_part->languageSupport()->formatModelItem(fun, true); + function = m_part->languageSupport()->formatClassName(function); + + return highlightFunctionName(function, 1, m_styles); +} + +QString Navigator::fullFunctionDefinitionName(FunctionDefinitionDom fun) +{ + QStringList scope = fun->scope(); + QString funName = scope.join("."); + if (!funName.isEmpty()) + funName += "."; + funName += m_part->languageSupport()->formatModelItem(fun, true); + funName = m_part->languageSupport()->formatClassName(funName); + + return funName; +} + +QString Navigator::fullFunctionDeclarationName(FunctionDom fun) +{ + QStringList scope = fun->scope(); + QString funName = scope.join("."); + if (!funName.isEmpty()) + funName += "."; + funName += m_part->languageSupport()->formatModelItem(fun, true); + funName = m_part->languageSupport()->formatClassName(funName); + + return funName; +} + +void Navigator::slotSyncWithEditor() +{ + kdDebug(9003) << k_funcinfo << endl; + + if (FunctionDom fun = currentFunction()) + { + m_part->mainWindow()->raiseView( m_part->widget() ); + + ItemDom dom(fun); + m_part->jumpedToItem( dom ); + } +} + +void Navigator::slotJumpToNextFunction() +{ + kdDebug ( 9003 ) << k_funcinfo << endl; + + if ( !m_part->m_activeViewCursor ) return; + unsigned int currentLine, currentCol; + m_part->m_activeViewCursor->cursorPositionReal ( ¤tLine, ¤tCol ); + + QValueList<int> lines = functionStartLines(); + if ( lines.isEmpty() ) return; + + QValueList<int>::iterator it = lines.begin(); + while ( it != lines.end() ) + { + if ( *it > currentLine ) + { + KURL url; + url.setPath ( m_part->m_activeFileName ); + m_part->partController()->editDocument ( url, *it ); + break; + } + ++it; + } +} + +void Navigator::slotJumpToPreviousFunction() +{ + kdDebug ( 9003 ) << k_funcinfo << endl; + + if ( !m_part->m_activeViewCursor ) return; + unsigned int currentLine, currentCol; + m_part->m_activeViewCursor->cursorPositionReal ( ¤tLine, ¤tCol ); + + QValueList<int> lines = QValueList_reversed<int> ( functionStartLines() ); + if ( lines.isEmpty() ) return; + + QValueList<int>::iterator it = lines.begin(); + while ( it != lines.end() ) + { + if ( *it < currentLine ) + { + KURL url; + url.setPath ( m_part->m_activeFileName ); + m_part->partController()->editDocument ( url, *it ); + break; + } + ++it; + } +} + +QValueList<int> Navigator::functionStartLines() +{ + FileDom file = m_part->codeModel()->fileByName ( m_part->m_activeFileName ); + if ( !file ) return QValueList<int>(); + + QValueList<int> lines; + FunctionDefinitionList list = CodeModelUtils::allFunctionDefinitionsExhaustive ( file ); + FunctionDefinitionList::const_iterator it = list.begin(); + while ( it != list.end() ) + { + int line, col; + ( *it )->getStartPosition ( &line, &col ); + lines << line; + ++it; + } + qHeapSort ( lines ); + + return lines; +} + +#include "navigator.moc" diff --git a/parts/classview/navigator.h b/parts/classview/navigator.h new file mode 100644 index 00000000..0168ccca --- /dev/null +++ b/parts/classview/navigator.h @@ -0,0 +1,91 @@ +/*************************************************************************** + * Copyright (C) 2004 by Alexander Dymo * + * [email protected] * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ +#ifndef NAVIGATOR_H +#define NAVIGATOR_H + +#include <qobject.h> +#include <codemodel.h> +#include <qfont.h> +#include <fancylistviewitem.h> + +class TextPaintStyleStore; +class QTimer; +class ClassViewPart; +class QListViewItem; +class KAction; + +#define NAV_NODEFINITION "(no function)" + +class TextPaintItem; +TextPaintItem highlightFunctionName( QString function, int type, TextPaintStyleStore& styles ); + +class Navigator : public QObject +{ +Q_OBJECT +public: + enum NavigationState { GoToDefinitions, GoToDeclarations }; + + Navigator(ClassViewPart *parent, const char *name = 0); + ~Navigator(); + + void stopTimer(); + void refreshNavBars(const QString &activeFileName, bool clear = true); + + QString fullFunctionDefinitionName(FunctionDefinitionDom fun); + QString fullFunctionDeclarationName(FunctionDom fun); + + template <class DomType> + TextPaintItem fullFunctionItem(DomType fun); + +public slots: + void selectFunctionNav(QListViewItem *item); + void syncFunctionNav(); + void syncFunctionNavDelayed(int delay); + void functionNavFocused(); + void functionNavUnFocused(); + void slotCursorPositionChanged(); + void refresh(); + void addFile(const QString &file); + void slotSyncWithEditor(); + void slotJumpToNextFunction(); + void slotJumpToPreviousFunction(); + +protected: + + FunctionDom currentFunction(); + QValueList<int> functionStartLines(); + +private: + ClassViewPart *m_part; + QTimer *m_syncTimer; + NavigationState m_state; + + QWidget m_dummyActionWidget; + KAction* m_actionSyncWithEditor; + + bool m_navNoDefinition; + + QMap<QString, QListViewItem*> m_functionNavDefs; + QMap<QString, QListViewItem*> m_functionNavDecls; + + TextPaintStyleStore m_styles; +}; + +#endif diff --git a/parts/classview/viewcombos.cpp b/parts/classview/viewcombos.cpp new file mode 100644 index 00000000..fc4d02fc --- /dev/null +++ b/parts/classview/viewcombos.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2003 Alexander Dymo ([email protected]) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#include <kiconloader.h> +#include <klocale.h> +#include <kdebug.h> + +#include "klistviewaction.h" +#include "kcomboview.h" + +#include "viewcombos.h" +#include "classviewpart.h" + +NamespaceItem::NamespaceItem(ClassViewPart *part, QListView *parent, QString name, NamespaceDom dom) + :QListViewItem(parent, name), m_dom(dom), m_part(part) +{ +} + +NamespaceItem::NamespaceItem(ClassViewPart *part, QListViewItem *parent, QString name, NamespaceDom dom) + :QListViewItem(parent, name), m_dom(dom), m_part(part) +{ +} + +NamespaceItem::~ NamespaceItem( ) +{ +} + +NamespaceDom NamespaceItem::dom() const +{ + return m_dom; +} + +void NamespaceItem::setup() +{ + QListViewItem::setup(); + setPixmap( 0, UserIcon("CVnamespace", KIcon::DefaultState, m_part->instance()) ); +} + + +ClassItem::ClassItem(ClassViewPart *part, QListView *parent, QString name, ClassDom dom) + :QListViewItem(parent, name), m_dom(dom), m_part(part) +{ +} + +ClassItem::ClassItem(ClassViewPart *part, QListViewItem *parent, QString name, ClassDom dom) + :QListViewItem(parent, name), m_dom(dom), m_part(part) +{ +} + +ClassItem::~ ClassItem( ) +{ +} + +ClassDom ClassItem::dom() const +{ + return m_dom; +} + +void ClassItem::setup() +{ + QListViewItem::setup(); + setPixmap( 0, UserIcon("CVclass", KIcon::DefaultState, m_part->instance()) ); +} + + +FunctionItem::FunctionItem(ClassViewPart *part, QListView *parent, QString name, FunctionDom dom) + :QListViewItem(parent, name), m_dom(dom), m_part(part) +{ +} + +FunctionItem::FunctionItem(ClassViewPart *part, QListViewItem *parent, QString name, FunctionDom dom) + :QListViewItem(parent, name), m_dom(dom), m_part(part) +{ +} + +FunctionItem::~ FunctionItem( ) +{ +} + +FunctionDom FunctionItem::dom() const +{ + return m_dom; +} + +void FunctionItem::setup() +{ + QListViewItem::setup(); + QString iconName; + if( m_dom->access() == CodeModelItem::Private ) + iconName = "CVprivate_meth"; + else if( m_dom->access() == CodeModelItem::Protected ) + iconName = "CVprotected_meth"; + else + iconName = "CVpublic_meth"; + setPixmap( 0, UserIcon(iconName, KIcon::DefaultState, m_part->instance()) ); +} + + +namespace ViewCombosOp{ + +void refreshNamespaces(ClassViewPart *part, KComboView *view) +{ + view->clear(); + + NamespaceItem *global_item = new NamespaceItem( part, view->listView(), i18n("(Global Namespace)"), part->codeModel()->globalNamespace() ); + view->addItem(global_item); + global_item->setPixmap( 0, UserIcon("CVnamespace", KIcon::DefaultState, part->instance()) ); + NamespaceList namespaces = part->codeModel()->globalNamespace()->namespaceList(); + for (NamespaceList::const_iterator it = namespaces.begin(); it != namespaces.end(); ++it) + { + NamespaceItem *item = new NamespaceItem(part, view->listView(), part->languageSupport()->formatModelItem(*it), *it); + view->addItem(item); + item->setOpen(true); + } + view->setCurrentActiveItem(global_item); +} + +void refreshClasses(ClassViewPart *part, KComboView *view, const QString &dom) +{ + view->clear(); + + view->setCurrentText(EmptyClasses); + NamespaceDom nsdom; + if (dom == "::") + nsdom = part->codeModel()->globalNamespace(); + else + { + nsdom = namespaceByName(part->codeModel()->globalNamespace(), dom); + if (!nsdom) + return; + } + ClassList classes = nsdom->classList(); + for (ClassList::const_iterator it = classes.begin(); it != classes.end(); ++it) + { + ClassItem *item = new ClassItem(part, view->listView(), part->languageSupport()->formatModelItem(*it), *it); + view->addItem(item); + item->setOpen(true); + } +} + +void refreshFunctions(ClassViewPart *part, KComboView *view, const ClassDom & dom) +{ + view->clear(); + + view->setCurrentText(EmptyFunctions); + FunctionList functions = dom->functionList(); + for (FunctionList::const_iterator it = functions.begin(); it != functions.end(); ++it) + { + FunctionItem *item = new FunctionItem(part, view->listView(), part->languageSupport()->formatModelItem(*it, true), *it); + view->addItem(item); + item->setOpen(true); + } +} + +void refreshFunctions(ClassViewPart *part, KComboView *view, const QString & dom) +{ + view->clear(); + + view->setCurrentText(EmptyFunctions); + NamespaceDom nsdom; + if (dom == "::") + nsdom = part->codeModel()->globalNamespace(); + else + { + nsdom = namespaceByName(part->codeModel()->globalNamespace(), dom); + if (!nsdom) + return; + } + FunctionList functions = nsdom->functionList(); + for (FunctionList::const_iterator it = functions.begin(); it != functions.end(); ++it) + { + FunctionItem *item = new FunctionItem(part, view->listView(), part->languageSupport()->formatModelItem(*it, true), *it); + view->addItem(item); + item->setOpen(true); + } +} + + +} + +NamespaceDom ViewCombosOp::namespaceByName( NamespaceDom dom, QString name ) +{ + NamespaceDom result; + + result = dom->namespaceByName(name); + if (!result) + { + NamespaceList nslist = dom->namespaceList(); + for (NamespaceList::const_iterator it = nslist.begin(); it != nslist.end(); ++it) + { + result = namespaceByName(*it, name); + if (result) + break; + } + } + return result; +} + diff --git a/parts/classview/viewcombos.h b/parts/classview/viewcombos.h new file mode 100644 index 00000000..4734b856 --- /dev/null +++ b/parts/classview/viewcombos.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2003 Alexander Dymo ([email protected]) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +#ifndef VIEWCOMBOS_H +#define VIEWCOMBOS_H + +#include <klocale.h> + +#include <qlistview.h> + +#include "codemodel.h" + +class ClassViewPart; +class KComboView; + +const QString EmptyClasses = i18n("(Classes)"); +const QString EmptyFunctions = i18n("(Functions)"); + +class NamespaceItem: public QListViewItem{ +public: + NamespaceItem(ClassViewPart *part, QListView *parent, QString name, NamespaceDom dom); + NamespaceItem(ClassViewPart *part, QListViewItem *parent, QString name, NamespaceDom dom); + ~NamespaceItem(); + NamespaceDom dom() const; + virtual void setup(); +private: + NamespaceDom m_dom; + ClassViewPart *m_part; +}; + +class ClassItem: public QListViewItem{ +public: + ClassItem(ClassViewPart *part, QListView *parent, QString name, ClassDom dom); + ClassItem(ClassViewPart *part, QListViewItem *parent, QString name, ClassDom dom); + ~ClassItem(); + ClassDom dom() const; + virtual void setup(); +private: + ClassDom m_dom; + ClassViewPart *m_part; +}; + +class FunctionItem: public QListViewItem{ +public: + FunctionItem(ClassViewPart *part, QListView *parent, QString name, FunctionDom dom); + FunctionItem(ClassViewPart *part, QListViewItem *parent, QString name, FunctionDom dom); + ~FunctionItem(); + FunctionDom dom() const; + virtual void setup(); +private: + FunctionDom m_dom; + ClassViewPart *m_part; +}; + +namespace ViewCombosOp{ + +enum ProcessType {Refresh, Reload}; + +void refreshNamespaces(ClassViewPart *part, KComboView *view); +void refreshClasses(ClassViewPart *part, KComboView *view, const QString &dom); +void refreshFunctions(ClassViewPart *part, KComboView *view, const ClassDom & dom); +void refreshFunctions(ClassViewPart *part, KComboView *view, const QString & dom); + +NamespaceDom namespaceByName(NamespaceDom dom, QString name); + +} + +#endif |