2009-02-25 09:15:00 +01:00
/**************************************************************************
2008-12-02 12:01:29 +01:00
* *
* * This file is part of Qt Creator
* *
2010-03-05 11:25:49 +01:00
* * Copyright ( c ) 2010 Nokia Corporation and / or its subsidiary ( - ies ) .
2008-12-02 12:01:29 +01:00
* *
2009-06-17 00:01:27 +10:00
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
2008-12-02 12:01:29 +01:00
* *
2009-02-25 09:15:00 +01:00
* * Commercial Usage
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * Licensees holding valid Qt Commercial licenses may use this file in
* * accordance with the Qt Commercial License Agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
* * a written agreement between you and Nokia .
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * GNU Lesser General Public License Usage
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * Alternatively , this file may be used under the terms of the GNU Lesser
* * General Public License version 2.1 as published by the Free Software
* * Foundation and appearing in the file LICENSE . LGPL included in the
* * packaging of this file . Please review the following information to
* * ensure the GNU Lesser General Public License version 2.1 requirements
* * will be met : http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * If you are unsure which license is appropriate for your use , please
2009-08-14 09:30:56 +02:00
* * contact the sales department at http : //qt.nokia.com/contact.
2008-12-02 12:01:29 +01:00
* *
2009-02-25 09:15:00 +01:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-02 15:08:31 +01:00
2008-12-02 12:01:29 +01:00
# include "formeditorplugin.h"
2009-05-08 16:11:49 +02:00
# include "qtcreatorintegration.h"
2008-12-02 12:01:29 +01:00
# include "formeditorw.h"
# include "formwindoweditor.h"
2009-12-03 16:23:15 +01:00
# include "codemodelhelpers.h"
2008-12-02 12:01:29 +01:00
# include <cpptools/cppmodelmanagerinterface.h>
# include <cplusplus/Symbols.h>
# include <cplusplus/Overview.h>
# include <cplusplus/CoreTypes.h>
# include <cplusplus/Name.h>
# include <cplusplus/Names.h>
# include <cplusplus/Literals.h>
# include <cplusplus/Scope.h>
# include <cplusplus/Control.h>
# include <cplusplus/LookupContext.h>
# include <coreplugin/icore.h>
# include <coreplugin/editormanager/editormanager.h>
2009-01-19 12:39:20 +01:00
# include <extensionsystem/pluginmanager.h>
2008-12-02 12:01:29 +01:00
# include <texteditor/basetexteditor.h>
# include <texteditor/itexteditable.h>
2009-11-18 10:31:16 +01:00
# include <projectexplorer/projectexplorer.h>
# include <projectexplorer/session.h>
2008-12-02 12:01:29 +01:00
# include <QtDesigner/QDesignerFormWindowInterface>
2008-12-16 16:39:19 +01:00
# include <QtGui/QMessageBox>
2008-12-02 12:01:29 +01:00
2008-12-16 16:39:19 +01:00
# include <QtCore/QFileInfo>
2008-12-02 12:01:29 +01:00
# include <QtCore/QDebug>
2008-12-18 17:19:54 +01:00
enum { indentation = 4 } ;
2008-12-16 16:39:19 +01:00
2008-12-02 12:01:29 +01:00
using namespace Designer : : Internal ;
using namespace CPlusPlus ;
using namespace TextEditor ;
2008-12-16 16:39:19 +01:00
static QString msgClassNotFound ( const QString & uiClassName , const QList < Document : : Ptr > & docList )
{
QString files ;
foreach ( const Document : : Ptr & doc , docList ) {
if ( ! files . isEmpty ( ) )
files + = QLatin1String ( " , " ) ;
files + = doc - > fileName ( ) ;
}
2009-05-08 16:11:49 +02:00
return QtCreatorIntegration : : tr ( " The class definition of '%1' could not be found in %2. " ) . arg ( uiClassName , files ) ;
2008-12-16 16:39:19 +01:00
}
2008-12-18 17:19:54 +01:00
static inline CppTools : : CppModelManagerInterface * cppModelManagerInstance ( )
{
2009-01-20 11:52:04 +01:00
return ExtensionSystem : : PluginManager : : instance ( )
- > getObject < CppTools : : CppModelManagerInterface > ( ) ;
2008-12-18 17:19:54 +01:00
}
2009-05-08 16:11:49 +02:00
QtCreatorIntegration : : QtCreatorIntegration ( QDesignerFormEditorInterface * core , FormEditorW * parent ) :
2008-12-02 12:01:29 +01:00
qdesigner_internal : : QDesignerIntegration ( core , : : qobject_cast < QObject * > ( parent ) ) ,
m_few ( parent )
{
setResourceFileWatcherBehaviour ( QDesignerIntegration : : ReloadSilently ) ;
setResourceEditingEnabled ( false ) ;
setSlotNavigationEnabled ( true ) ;
2008-12-11 13:43:11 +01:00
connect ( this , SIGNAL ( navigateToSlot ( QString , QString , QStringList ) ) ,
this , SLOT ( slotNavigateToSlot ( QString , QString , QStringList ) ) ) ;
2008-12-02 12:01:29 +01:00
}
2009-05-08 16:11:49 +02:00
void QtCreatorIntegration : : updateSelection ( )
2008-12-02 12:01:29 +01:00
{
if ( FormWindowEditor * afww = m_few - > activeFormWindow ( ) )
afww - > updateFormWindowSelectionHandles ( true ) ;
qdesigner_internal : : QDesignerIntegration : : updateSelection ( ) ;
}
2009-05-08 16:11:49 +02:00
QWidget * QtCreatorIntegration : : containerWindow ( QWidget * /*widget*/ ) const
2008-12-02 12:01:29 +01:00
{
FormWindowEditor * fw = m_few - > activeFormWindow ( ) ;
if ( ! fw )
return 0 ;
return fw - > integrationContainer ( ) ;
}
2008-12-18 17:19:54 +01:00
static QList < Document : : Ptr > findDocumentsIncluding ( const CPlusPlus : : Snapshot & docTable ,
const QString & fileName , bool checkFileNameOnly )
2008-12-02 12:01:29 +01:00
{
QList < Document : : Ptr > docList ;
2008-12-18 17:19:54 +01:00
foreach ( const Document : : Ptr & doc , docTable ) { // we go through all documents
const QStringList includes = doc - > includedFiles ( ) ;
foreach ( const QString & include , includes ) {
2008-12-11 13:43:11 +01:00
if ( checkFileNameOnly ) {
const QFileInfo fi ( include ) ;
if ( fi . fileName ( ) = = fileName ) { // we are only interested in docs which includes fileName only
docList . append ( doc ) ;
}
} else {
if ( include = = fileName )
docList . append ( doc ) ;
2008-12-02 12:01:29 +01:00
}
}
}
return docList ;
}
2009-03-12 11:44:30 +01:00
// Does klass inherit baseClass?
static bool inherits ( const Overview & o , const Class * klass , const QString & baseClass )
{
const int baseClassCount = klass - > baseClassCount ( ) ;
for ( int b = 0 ; b < baseClassCount ; b + + )
if ( o . prettyName ( klass - > baseClassAt ( b ) - > name ( ) ) = = baseClass )
return true ;
return false ;
}
2008-12-18 17:19:54 +01:00
// Check for a class name where haystack is a member class of an object.
// So, haystack can be shorter (can have some namespaces omitted because of a
// "using namespace" declaration, for example, comparing
// "foo::Ui::form", against "using namespace foo; Ui::form".
2008-12-11 13:43:11 +01:00
2008-12-18 17:19:54 +01:00
static bool matchMemberClassName ( const QString & needle , const QString & hayStack )
{
if ( needle = = hayStack )
return true ;
if ( ! needle . endsWith ( hayStack ) )
return false ;
// Check if there really is a separator "::"
const int separatorPos = needle . size ( ) - hayStack . size ( ) - 1 ;
return separatorPos > 1 & & needle . at ( separatorPos ) = = QLatin1Char ( ' : ' ) ;
}
2008-12-02 12:01:29 +01:00
2009-03-12 11:44:30 +01:00
// Find class definition in namespace (that is, the outer class
// containing a member of the desired class type) or inheriting the desired class
// in case of forms using the Multiple Inheritance approach
2008-12-18 17:19:54 +01:00
static const Class * findClass ( const Namespace * parentNameSpace , const QString & className , QString * namespaceName )
{
2009-01-21 12:07:19 +01:00
if ( Designer : : Constants : : Internal : : debug )
2008-12-18 17:19:54 +01:00
qDebug ( ) < < Q_FUNC_INFO < < className ;
const Overview o ;
const unsigned namespaceMemberCount = parentNameSpace - > memberCount ( ) ;
for ( unsigned i = 0 ; i < namespaceMemberCount ; i + + ) { // we go through all namespace members
const Symbol * sym = parentNameSpace - > memberAt ( i ) ;
// we have found a class - we are interested in classes only
if ( const Class * cl = sym - > asClass ( ) ) {
2009-03-12 11:44:30 +01:00
// 1) we go through class members
2008-12-18 17:19:54 +01:00
const unsigned classMemberCount = cl - > memberCount ( ) ;
2009-03-12 11:44:30 +01:00
for ( unsigned j = 0 ; j < classMemberCount ; j + + )
2008-12-18 17:19:54 +01:00
if ( const Declaration * decl = cl - > memberAt ( j ) - > asDeclaration ( ) ) {
// we want to know if the class contains a member (so we look into
// a declaration) of uiClassName type
const NamedType * nt = decl - > type ( ) - > asNamedType ( ) ;
2008-12-02 12:01:29 +01:00
// handle pointers to member variables
if ( PointerType * pt = decl - > type ( ) - > asPointerType ( ) )
nt = pt - > elementType ( ) - > asNamedType ( ) ;
2008-12-18 17:19:54 +01:00
if ( nt & & matchMemberClassName ( className , o . prettyName ( nt - > name ( ) ) ) )
2008-12-02 12:01:29 +01:00
return cl ;
2008-12-18 17:19:54 +01:00
} // decl
2009-03-12 11:44:30 +01:00
// 2) does it inherit the desired class
if ( inherits ( o , cl , className ) )
return cl ;
2008-12-18 17:19:54 +01:00
} else {
// Check namespaces
if ( const Namespace * ns = sym - > asNamespace ( ) ) {
QString tempNS = * namespaceName ;
tempNS + = o . prettyName ( ns - > name ( ) ) ;
tempNS + = QLatin1String ( " :: " ) ;
if ( const Class * cl = findClass ( ns , className , & tempNS ) ) {
* namespaceName = tempNS ;
return cl ;
2008-12-02 12:01:29 +01:00
}
2008-12-18 17:19:54 +01:00
} // member is namespave
} // member is no class
} // for members
2008-12-02 12:01:29 +01:00
return 0 ;
}
2008-12-18 17:19:54 +01:00
static const Function * findDeclaration ( const Class * cl , const QString & functionName )
2008-12-02 12:01:29 +01:00
{
2008-12-11 13:43:11 +01:00
const QString funName = QString : : fromUtf8 ( QMetaObject : : normalizedSignature ( functionName . toUtf8 ( ) ) ) ;
2008-12-18 17:19:54 +01:00
const unsigned mCount = cl - > memberCount ( ) ;
// we are interested only in declarations (can be decl of method or of a field)
// we are only interested in declarations of methods
const Overview overview ;
for ( unsigned j = 0 ; j < mCount ; j + + ) { // go through all members
if ( const Declaration * decl = cl - > memberAt ( j ) - > asDeclaration ( ) )
2009-02-09 17:44:06 +01:00
if ( const Function * fun = decl - > type ( ) - > asFunctionType ( ) ) {
2008-12-18 17:19:54 +01:00
// Format signature
QString memberFunction = overview . prettyName ( fun - > name ( ) ) ;
memberFunction + = QLatin1Char ( ' ( ' ) ;
const uint aCount = fun - > argumentCount ( ) ;
for ( uint i = 0 ; i < aCount ; i + + ) { // we build argument types string
const Argument * arg = fun - > argumentAt ( i ) - > asArgument ( ) ;
2008-12-11 13:43:11 +01:00
if ( i > 0 )
memberFunction + = QLatin1Char ( ' , ' ) ;
memberFunction + = overview . prettyType ( arg - > type ( ) ) ;
}
memberFunction + = QLatin1Char ( ' ) ' ) ;
// we compare normalized signatures
memberFunction = QString : : fromUtf8 ( QMetaObject : : normalizedSignature ( memberFunction . toUtf8 ( ) ) ) ;
if ( memberFunction = = funName ) // we match function names and argument lists
2008-12-02 12:01:29 +01:00
return fun ;
}
}
return 0 ;
}
// TODO: remove me, see below
2008-12-18 17:19:54 +01:00
static bool isCompatible ( const Name * name , const Name * otherName )
2008-12-02 12:01:29 +01:00
{
2008-12-18 17:19:54 +01:00
if ( const NameId * nameId = name - > asNameId ( ) ) {
if ( const TemplateNameId * otherTemplId = otherName - > asTemplateNameId ( ) )
2008-12-02 12:01:29 +01:00
return nameId - > identifier ( ) - > isEqualTo ( otherTemplId - > identifier ( ) ) ;
2008-12-18 17:19:54 +01:00
} else if ( const TemplateNameId * templId = name - > asTemplateNameId ( ) ) {
if ( const NameId * otherNameId = otherName - > asNameId ( ) )
2008-12-02 12:01:29 +01:00
return templId - > identifier ( ) - > isEqualTo ( otherNameId - > identifier ( ) ) ;
}
return name - > isEqualTo ( otherName ) ;
}
// TODO: remove me, see below
2008-12-18 17:19:54 +01:00
static bool isCompatible ( const Function * definition , const Symbol * declaration , const QualifiedNameId * declarationName )
2008-12-02 12:01:29 +01:00
{
2009-02-09 17:44:06 +01:00
Function * declTy = declaration - > type ( ) - > asFunctionType ( ) ;
2008-12-02 12:01:29 +01:00
if ( ! declTy )
return false ;
2009-12-01 12:46:15 +01:00
const Name * definitionName = definition - > name ( ) ;
if ( const QualifiedNameId * q = definitionName - > asQualifiedNameId ( ) ) {
2008-12-02 12:01:29 +01:00
if ( ! isCompatible ( q - > unqualifiedNameId ( ) , declaration - > name ( ) ) )
return false ;
else if ( q - > nameCount ( ) > declarationName - > nameCount ( ) )
return false ;
else if ( declTy - > argumentCount ( ) ! = definition - > argumentCount ( ) )
return false ;
else if ( declTy - > isConst ( ) ! = definition - > isConst ( ) )
return false ;
else if ( declTy - > isVolatile ( ) ! = definition - > isVolatile ( ) )
return false ;
for ( unsigned i = 0 ; i < definition - > argumentCount ( ) ; + + i ) {
Symbol * arg = definition - > argumentAt ( i ) ;
Symbol * otherArg = declTy - > argumentAt ( i ) ;
if ( ! arg - > type ( ) . isEqualTo ( otherArg - > type ( ) ) )
return false ;
}
for ( unsigned i = 0 ; i ! = q - > nameCount ( ) ; + + i ) {
2009-12-01 12:46:15 +01:00
const Name * n = q - > nameAt ( q - > nameCount ( ) - i - 1 ) ;
const Name * m = declarationName - > nameAt ( declarationName - > nameCount ( ) - i - 1 ) ;
2008-12-02 12:01:29 +01:00
if ( ! isCompatible ( n , m ) )
return false ;
}
return true ;
} else {
// ### TODO: implement isCompatible for unqualified name ids.
}
return false ;
}
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this method
2008-12-18 17:19:54 +01:00
static Document : : Ptr findDefinition ( const Function * functionDeclaration , int * line )
2008-12-02 12:01:29 +01:00
{
2008-12-18 17:19:54 +01:00
CppTools : : CppModelManagerInterface * cppModelManager = cppModelManagerInstance ( ) ;
2008-12-02 12:01:29 +01:00
if ( ! cppModelManager )
return Document : : Ptr ( ) ;
2009-12-01 12:46:15 +01:00
QVector < const Name * > qualifiedName ;
2008-12-02 12:01:29 +01:00
Scope * scope = functionDeclaration - > scope ( ) ;
for ( ; scope ; scope = scope - > enclosingScope ( ) ) {
if ( scope - > isClassScope ( ) | | scope - > isNamespaceScope ( ) ) {
if ( scope - > owner ( ) & & scope - > owner ( ) - > name ( ) ) {
2009-12-01 12:46:15 +01:00
const Name * scopeOwnerName = scope - > owner ( ) - > name ( ) ;
if ( const QualifiedNameId * q = scopeOwnerName - > asQualifiedNameId ( ) ) {
2008-12-02 12:01:29 +01:00
for ( unsigned i = 0 ; i < q - > nameCount ( ) ; + + i ) {
qualifiedName . prepend ( q - > nameAt ( i ) ) ;
2008-12-18 17:19:54 +01:00
}
2008-12-02 12:01:29 +01:00
} else {
qualifiedName . prepend ( scopeOwnerName ) ;
}
}
}
}
qualifiedName . append ( functionDeclaration - > name ( ) ) ;
Control control ;
2009-12-01 12:46:15 +01:00
const QualifiedNameId * q = control . qualifiedNameId ( & qualifiedName [ 0 ] , qualifiedName . size ( ) ) ;
2008-12-02 12:01:29 +01:00
LookupContext context ( & control ) ;
2008-12-12 10:07:58 +01:00
const Snapshot documents = cppModelManager - > snapshot ( ) ;
2008-12-02 12:01:29 +01:00
foreach ( Document : : Ptr doc , documents ) {
QList < Scope * > visibleScopes ;
visibleScopes . append ( doc - > globalSymbols ( ) ) ;
visibleScopes = context . expand ( visibleScopes ) ;
foreach ( Scope * visibleScope , visibleScopes ) {
Symbol * symbol = 0 ;
2009-12-01 12:46:15 +01:00
if ( const NameId * nameId = q - > unqualifiedNameId ( ) - > asNameId ( ) )
2008-12-02 12:01:29 +01:00
symbol = visibleScope - > lookat ( nameId - > identifier ( ) ) ;
2009-12-01 12:46:15 +01:00
else if ( const DestructorNameId * dtorId = q - > unqualifiedNameId ( ) - > asDestructorNameId ( ) )
2008-12-02 12:01:29 +01:00
symbol = visibleScope - > lookat ( dtorId - > identifier ( ) ) ;
2009-12-01 12:46:15 +01:00
else if ( const TemplateNameId * templNameId = q - > unqualifiedNameId ( ) - > asTemplateNameId ( ) )
2008-12-02 12:01:29 +01:00
symbol = visibleScope - > lookat ( templNameId - > identifier ( ) ) ;
2009-12-01 12:46:15 +01:00
else if ( const OperatorNameId * opId = q - > unqualifiedNameId ( ) - > asOperatorNameId ( ) )
2008-12-02 12:01:29 +01:00
symbol = visibleScope - > lookat ( opId - > kind ( ) ) ;
// ### cast operators
for ( ; symbol ; symbol = symbol - > next ( ) ) {
if ( ! symbol - > isFunction ( ) )
continue ;
else if ( ! isCompatible ( symbol - > asFunction ( ) , functionDeclaration , q ) )
continue ;
* line = symbol - > line ( ) ; // TODO: shift the line so that we are inside a function. Maybe just find the nearest '{'?
return doc ;
}
}
}
return Document : : Ptr ( ) ;
}
2009-09-02 15:38:02 +02:00
static bool isEndingQuote ( const QString & contents , int quoteIndex )
{
bool endingQuote = true ;
if ( quoteIndex > 0 ) {
int previous = 1 ;
while ( contents . at ( quoteIndex - previous ) = = QLatin1Char ( ' \\ ' ) ) {
previous + + ;
endingQuote = ! endingQuote ;
}
}
return endingQuote ;
}
2008-12-11 13:43:11 +01:00
// TODO: Wait for robust Roberto's code using AST or whatever for that. Current implementation is hackish.
static int findClassEndPosition ( const QString & headerContents , int classStartPosition )
{
const QString contents = headerContents . mid ( classStartPosition ) ; // we start serching from the beginning of class declaration
// We need to find the position of class closing "}"
int openedBlocksCount = 0 ; // counter of nested {} blocks
int idx = 0 ; // index of current position in the contents
while ( true ) {
if ( idx < 0 | | idx > = contents . length ( ) ) // indexOf returned -1, that means we don't have closing comment mark
break ;
if ( contents . mid ( idx , 2 ) = = QLatin1String ( " // " ) ) {
idx = contents . indexOf ( QLatin1Char ( ' \n ' ) , idx + 2 ) + 1 ; // drop everything up to the end of line
} else if ( contents . mid ( idx , 2 ) = = QLatin1String ( " /* " ) ) {
2009-11-13 08:48:28 +01:00
idx = contents . indexOf ( QLatin1String ( " */ " ) , idx + 2 ) + 2 ; // drop everything up to the nearest */
2008-12-11 13:43:11 +01:00
} else if ( contents . mid ( idx , 4 ) = = QLatin1String ( " ' \\ \" ' " ) ) {
idx + = 4 ; // drop it
} else if ( contents . at ( idx ) = = QLatin1Char ( ' \" ' ) ) {
do {
idx = contents . indexOf ( QLatin1Char ( ' \" ' ) , idx + 1 ) ; // drop everything up to the nearest "
2009-11-13 08:48:28 +01:00
} while ( idx > 0 & & ! isEndingQuote ( contents , idx ) ) ; // if the nearest " is preceded by \ (or by \\\ or by \\\\\, but not by \\ nor \\\\) we find next one
2008-12-11 13:43:11 +01:00
if ( idx < 0 )
break ;
idx + + ;
} else {
if ( contents . at ( idx ) = = QLatin1Char ( ' { ' ) ) {
openedBlocksCount + + ;
} else if ( contents . at ( idx ) = = QLatin1Char ( ' } ' ) ) {
openedBlocksCount - - ;
if ( openedBlocksCount = = 0 ) {
return classStartPosition + idx ;
}
}
idx + + ;
}
}
return - 1 ;
}
2008-12-18 17:19:54 +01:00
static inline ITextEditable * editableAt ( const QString & fileName , int line , int column )
{
return qobject_cast < ITextEditable * > ( TextEditor : : BaseTextEditor : : openEditorAt ( fileName , line , column ) ) ;
}
static void addDeclaration ( const QString & docFileName , const Class * cl , const QString & functionName )
2008-12-02 12:01:29 +01:00
{
2008-12-18 17:19:54 +01:00
QString declaration = QLatin1String ( " void " ) ;
declaration + = functionName ;
declaration + = QLatin1String ( " ; \n " ) ;
// functionName comes already with argument names (if designer managed to
// do that). First, let's try to find any method which is a private slot
// (then we don't need to add "private slots:" statement)
const unsigned mCount = cl - > memberCount ( ) ;
for ( unsigned j = 0 ; j < mCount ; j + + ) { // go through all members
if ( const Declaration * decl = cl - > memberAt ( j ) - > asDeclaration ( ) )
2009-02-09 17:44:06 +01:00
if ( const Function * fun = decl - > type ( ) - > asFunctionType ( ) ) {
2008-12-18 17:19:54 +01:00
// we are only interested in declarations of methods.
2008-12-02 12:01:29 +01:00
if ( fun - > isSlot ( ) & & fun - > isPrivate ( ) ) {
2009-03-31 15:09:02 +02:00
const int line = fun - > line ( ) ; // this is the beginning of function name: "void ^foo(...)"
2009-03-12 11:44:30 +01:00
const int column = fun - > column ( ) ;
if ( ITextEditable * editable = editableAt ( docFileName , line , column ) ) {
2009-03-31 15:09:02 +02:00
unsigned dl , dc ; // this position is the beginning of return value: "^void foo(...)"
decl - > getStartPosition ( & dl , & dc ) ;
2010-01-11 10:22:55 +01:00
dc - - ; // if the first character in line is 'v' coming from "void" getStartPosition returns 1, not 0, so we always decrement it.
2009-03-31 15:09:02 +02:00
editable - > gotoLine ( dl , dc ) ;
2009-03-12 11:44:30 +01:00
editable - > position ( ITextEditor : : StartOfLine ) ;
2009-03-31 15:09:02 +02:00
const QString indentation = QString ( dc , QLatin1Char ( ' ' ) ) ;
editable - > insert ( declaration + indentation ) ;
2009-03-12 11:44:30 +01:00
}
2008-12-02 12:01:29 +01:00
return ;
}
}
}
2008-12-11 13:43:11 +01:00
// We didn't find any method under "private slots:", let's add "private slots:". Below code
// adds "private slots:" by the end of the class definition.
2008-12-18 17:19:54 +01:00
if ( ITextEditable * editable = editableAt ( docFileName , cl - > line ( ) , cl - > column ( ) ) ) {
2008-12-11 13:43:11 +01:00
int classEndPosition = findClassEndPosition ( editable - > contents ( ) , editable - > position ( ) ) ;
if ( classEndPosition > = 0 ) {
int line , column ;
editable - > convertPosition ( classEndPosition , & line , & column ) ; // converts back position into a line and column
editable - > gotoLine ( line , column ) ; // go to position (we should be just before closing } of the class)
2008-12-18 17:19:54 +01:00
editable - > insert ( QLatin1String ( " \n private slots: \n " ) + declaration ) ;
2008-12-11 13:43:11 +01:00
}
}
}
2008-12-18 17:19:54 +01:00
static Document : : Ptr addDefinition ( const CPlusPlus : : Snapshot & docTable ,
const QString & headerFileName , const QString & className ,
const QString & functionName , int * line )
2008-12-11 13:43:11 +01:00
{
2008-12-18 17:19:54 +01:00
QString definition = QLatin1String ( " \n void " ) ;
definition + = className ;
definition + = QLatin1String ( " :: " ) ;
definition + = functionName ;
definition + = QLatin1String ( " \n { \n " ) ;
definition + = QString ( indentation , QLatin1Char ( ' ' ) ) ;
definition + = QLatin1String ( " \n } \n " ) ;
2008-12-11 13:43:11 +01:00
// we find all documents which include headerFileName
2008-12-18 17:19:54 +01:00
const QList < Document : : Ptr > docList = findDocumentsIncluding ( docTable , headerFileName , false ) ;
2008-12-11 13:43:11 +01:00
if ( docList . isEmpty ( ) )
return Document : : Ptr ( ) ;
QFileInfo headerFI ( headerFileName ) ;
2009-03-20 16:13:46 +01:00
const QString headerBaseName = headerFI . completeBaseName ( ) ;
2008-12-18 17:19:54 +01:00
foreach ( const Document : : Ptr & doc , docList ) {
const QFileInfo sourceFI ( doc - > fileName ( ) ) ;
2010-03-04 09:33:28 +01:00
// we take only those documents which have the same filename
if ( headerBaseName = = sourceFI . baseName ( ) ) {
2008-12-18 17:19:54 +01:00
if ( ITextEditable * editable = editableAt ( doc - > fileName ( ) , 0 , 0 ) ) {
2008-12-11 13:43:11 +01:00
const QString contents = editable - > contents ( ) ;
int column ;
editable - > convertPosition ( contents . length ( ) , line , & column ) ;
editable - > gotoLine ( * line , column ) ;
2008-12-18 17:19:54 +01:00
editable - > insert ( definition ) ;
2008-12-11 13:43:11 +01:00
* line + = 1 ;
}
return doc ;
}
}
return Document : : Ptr ( ) ;
2008-12-02 12:01:29 +01:00
}
2008-12-18 17:19:54 +01:00
// Insert the parameter names into a signature, "void foo(bool)" ->
// "void foo(bool checked)"
2008-12-11 13:43:11 +01:00
static QString addParameterNames ( const QString & functionSignature , const QStringList & parameterNames )
{
2008-12-18 17:19:54 +01:00
const int firstParen = functionSignature . indexOf ( QLatin1Char ( ' ( ' ) ) ;
QString functionName = functionSignature . left ( firstParen + 1 ) ;
QString argumentsString = functionSignature . mid ( firstParen + 1 ) ;
const int lastParen = argumentsString . lastIndexOf ( QLatin1Char ( ' ) ' ) ) ;
if ( lastParen ! = - 1 )
argumentsString . truncate ( lastParen ) ;
2008-12-11 13:43:11 +01:00
const QStringList arguments = argumentsString . split ( QLatin1Char ( ' , ' ) , QString : : SkipEmptyParts ) ;
2008-12-18 17:19:54 +01:00
const int pCount = parameterNames . count ( ) ;
const int aCount = arguments . count ( ) ;
for ( int i = 0 ; i < aCount ; + + i ) {
2008-12-11 13:43:11 +01:00
if ( i > 0 )
functionName + = QLatin1String ( " , " ) ;
functionName + = arguments . at ( i ) ;
2008-12-18 17:19:54 +01:00
if ( i < pCount ) {
functionName + = QLatin1Char ( ' ' ) ;
functionName + = parameterNames . at ( i ) ;
}
2008-12-11 13:43:11 +01:00
}
functionName + = QLatin1Char ( ' ) ' ) ;
return functionName ;
}
2008-12-18 17:19:54 +01:00
// Recursively find a class definition in the document passed on or in its
// included files (going down [maxIncludeDepth] includes) and return a pair
// of <Class*, Document>.
typedef QPair < const Class * , Document : : Ptr > ClassDocumentPtrPair ;
static ClassDocumentPtrPair
findClassRecursively ( const CPlusPlus : : Snapshot & docTable ,
const Document : : Ptr & doc , const QString & className ,
unsigned maxIncludeDepth , QString * namespaceName )
{
2009-01-21 12:07:19 +01:00
if ( Designer : : Constants : : Internal : : debug )
2009-03-12 11:44:30 +01:00
qDebug ( ) < < Q_FUNC_INFO < < doc - > fileName ( ) < < className < < maxIncludeDepth ;
2008-12-18 17:19:54 +01:00
// Check document
if ( const Class * cl = findClass ( doc - > globalNamespace ( ) , className , namespaceName ) )
return ClassDocumentPtrPair ( cl , doc ) ;
if ( maxIncludeDepth ) {
// Check the includes
const unsigned recursionMaxIncludeDepth = maxIncludeDepth - 1u ;
foreach ( const QString & include , doc - > includedFiles ( ) ) {
2009-12-07 10:54:27 +01:00
const CPlusPlus : : Snapshot : : const_iterator it = docTable . find ( include ) ;
if ( it ! = docTable . end ( ) ) {
2008-12-18 17:19:54 +01:00
const Document : : Ptr includeDoc = it . value ( ) ;
const ClassDocumentPtrPair irc = findClassRecursively ( docTable , it . value ( ) , className , recursionMaxIncludeDepth , namespaceName ) ;
if ( irc . first )
return irc ;
}
}
}
return ClassDocumentPtrPair ( 0 , Document : : Ptr ( ) ) ;
}
2008-12-16 16:39:19 +01:00
2009-05-08 16:11:49 +02:00
void QtCreatorIntegration : : slotNavigateToSlot ( const QString & objectName , const QString & signalSignature ,
2008-12-11 13:43:11 +01:00
const QStringList & parameterNames )
2008-12-16 16:39:19 +01:00
{
QString errorMessage ;
if ( ! navigateToSlot ( objectName , signalSignature , parameterNames , & errorMessage ) & & ! errorMessage . isEmpty ( ) ) {
2008-12-18 17:19:54 +01:00
QMessageBox : : warning ( m_few - > designerEditor ( ) - > topLevel ( ) , tr ( " Error finding/adding a slot. " ) , errorMessage ) ;
2008-12-16 16:39:19 +01:00
}
}
2008-12-18 17:19:54 +01:00
// Build name of the class as generated by uic, insert Ui namespace
// "foo::bar::form" -> "foo::bar::Ui::form"
static inline QString uiClassName ( QString formObjectName )
{
const int indexOfScope = formObjectName . lastIndexOf ( QLatin1String ( " :: " ) ) ;
2009-03-31 15:40:35 +02:00
const int uiNameSpaceInsertionPos = indexOfScope > = 0 ? indexOfScope + 2 : 0 ;
2008-12-18 17:19:54 +01:00
formObjectName . insert ( uiNameSpaceInsertionPos , QLatin1String ( " Ui:: " ) ) ;
return formObjectName ;
}
2009-03-12 11:44:30 +01:00
// Goto slot invoked by the designer context menu. Either navigates
// to an existing slot function or create a new one.
2009-05-08 16:11:49 +02:00
bool QtCreatorIntegration : : navigateToSlot ( const QString & objectName ,
2008-12-16 16:39:19 +01:00
const QString & signalSignature ,
const QStringList & parameterNames ,
QString * errorMessage )
2008-12-02 12:01:29 +01:00
{
const QString currentUiFile = m_few - > activeFormWindow ( ) - > file ( ) - > fileName ( ) ;
2009-12-03 16:23:15 +01:00
#if 0
return Designer : : Internal : : navigateToSlot ( currentUiFile , objectName , signalSignature , parameterNames , errorMessage ) ;
# endif
2008-12-11 13:43:11 +01:00
// TODO: we should pass to findDocumentsIncluding an absolute path to generated .h file from ui.
// Currently we are guessing the name of ui_<>.h file and pass the file name only to the findDocumentsIncluding().
2008-12-02 12:01:29 +01:00
// The idea is that the .pro file knows if the .ui files is inside, and the .pro file knows it will
// be generating the ui_<>.h file for it, and the .pro file knows what the generated file's name and its absolute path will be.
// So we should somehow get that info from project manager (?)
const QFileInfo fi ( currentUiFile ) ;
2009-03-20 16:13:46 +01:00
const QString uicedName = QLatin1String ( " ui_ " ) + fi . completeBaseName ( ) + QLatin1String ( " .h " ) ;
2008-12-02 12:01:29 +01:00
2009-11-18 10:31:16 +01:00
// Retrieve code model snapshot restricted to project of ui file.
const ProjectExplorer : : Project * uiProject = ProjectExplorer : : ProjectExplorerPlugin : : instance ( ) - > session ( ) - > projectForFile ( currentUiFile ) ;
if ( ! uiProject ) {
* errorMessage = tr ( " Internal error: No project could be found for %1. " ) . arg ( currentUiFile ) ;
return false ;
}
CPlusPlus : : Snapshot docTable = cppModelManagerInstance ( ) - > snapshot ( ) ;
2009-12-07 10:54:27 +01:00
CPlusPlus : : Snapshot newDocTable ;
for ( CPlusPlus : : Snapshot : : iterator it = docTable . begin ( ) ; it ! = docTable . end ( ) ; + + it ) {
2009-11-18 10:31:16 +01:00
const ProjectExplorer : : Project * project = ProjectExplorer : : ProjectExplorerPlugin : : instance ( ) - > session ( ) - > projectForFile ( it . key ( ) ) ;
2009-12-07 10:54:27 +01:00
if ( project = = uiProject )
newDocTable . insert ( it . value ( ) ) ;
2009-11-18 10:31:16 +01:00
}
2009-12-07 10:54:27 +01:00
docTable = newDocTable ;
2009-03-12 11:44:30 +01:00
// take all docs, find the ones that include the ui_xx.h.
2008-12-18 17:19:54 +01:00
QList < Document : : Ptr > docList = findDocumentsIncluding ( docTable , uicedName , true ) ; // change to false when we know the absolute path to generated ui_<>.h file
2008-12-16 16:39:19 +01:00
2009-01-21 12:07:19 +01:00
if ( Designer : : Constants : : Internal : : debug )
qDebug ( ) < < Q_FUNC_INFO < < objectName < < signalSignature < < " Looking for " < < uicedName < < " returned " < < docList . size ( ) ;
2008-12-16 16:39:19 +01:00
if ( docList . isEmpty ( ) ) {
2009-03-12 11:44:30 +01:00
* errorMessage = tr ( " No documents matching '%1' could be found. \n Rebuilding the project might help. " ) . arg ( uicedName ) ;
2008-12-16 16:39:19 +01:00
return false ;
}
2008-12-02 12:01:29 +01:00
QDesignerFormWindowInterface * fwi = m_few - > activeFormWindow ( ) - > formWindow ( ) ;
2008-12-18 17:19:54 +01:00
const QString uiClass = uiClassName ( fwi - > mainContainer ( ) - > objectName ( ) ) ;
2008-12-02 12:01:29 +01:00
2009-01-21 12:07:19 +01:00
if ( Designer : : Constants : : Internal : : debug )
2008-12-18 17:19:54 +01:00
qDebug ( ) < < " Checking docs for " < < uiClass ;
2009-03-12 11:44:30 +01:00
// Find the class definition (ui class defined as member or base class)
// in the file itself or in the directly included files (order 1).
2008-12-18 17:19:54 +01:00
QString namespaceName ;
2009-02-03 19:46:22 +01:00
const Class * cl = 0 ;
2008-12-18 17:19:54 +01:00
Document : : Ptr doc ;
foreach ( const Document : : Ptr & d , docList ) {
const ClassDocumentPtrPair cd = findClassRecursively ( docTable , d , uiClass , 1u , & namespaceName ) ;
if ( cd . first ) {
cl = cd . first ;
doc = cd . second ;
break ;
}
}
if ( ! cl ) {
* errorMessage = msgClassNotFound ( uiClass , docList ) ;
return false ;
}
2008-12-16 16:39:19 +01:00
2008-12-18 17:19:54 +01:00
Overview o ;
const QString className = namespaceName + o . prettyName ( cl - > name ( ) ) ;
2009-03-12 11:44:30 +01:00
if ( Designer : : Constants : : Internal : : debug )
qDebug ( ) < < " Found class " < < className < < doc - > fileName ( ) ;
2008-12-18 17:19:54 +01:00
const QString functionName = QLatin1String ( " on_ " ) + objectName + QLatin1Char ( ' _ ' ) + signalSignature ;
const QString functionNameWithParameterNames = addParameterNames ( functionName , parameterNames ) ;
2009-01-21 12:07:19 +01:00
if ( Designer : : Constants : : Internal : : debug )
qDebug ( ) < < Q_FUNC_INFO < < " Found " < < uiClass < < doc - > fileName ( ) < < " checking " < < functionName < < functionNameWithParameterNames ;
2008-12-18 17:19:54 +01:00
int line = 0 ;
Document : : Ptr sourceDoc ;
if ( const Function * fun = findDeclaration ( cl , functionName ) ) {
sourceDoc = findDefinition ( fun , & line ) ;
if ( ! sourceDoc ) {
// add function definition to cpp file
sourceDoc = addDefinition ( docTable , doc - > fileName ( ) , className , functionNameWithParameterNames , & line ) ;
2008-12-02 12:01:29 +01:00
}
2008-12-18 17:19:54 +01:00
} else {
// add function declaration to cl
addDeclaration ( doc - > fileName ( ) , cl , functionNameWithParameterNames ) ;
// add function definition to cpp file
sourceDoc = addDefinition ( docTable , doc - > fileName ( ) , className , functionNameWithParameterNames , & line ) ;
2008-12-02 12:01:29 +01:00
}
2008-12-18 17:19:54 +01:00
if ( ! sourceDoc ) {
* errorMessage = tr ( " Unable to add the method definition. " ) ;
return false ;
}
// jump to function definition, position within code
TextEditor : : BaseTextEditor : : openEditorAt ( sourceDoc - > fileName ( ) , line + 2 , indentation ) ;
return true ;
}