2012-10-02 09:12:39 +02:00
/****************************************************************************
2008-12-02 12:01:29 +01:00
* *
2015-01-14 18:07:15 +01:00
* * Copyright ( C ) 2015 The Qt Company Ltd .
* * Contact : http : //www.qt.io/licensing
2008-12-02 12:01:29 +01:00
* *
2012-10-02 09:12:39 +02:00
* * This file is part of Qt Creator .
2008-12-02 12:01:29 +01:00
* *
2012-10-02 09:12:39 +02:00
* * Commercial License Usage
* * Licensees holding valid commercial Qt licenses may use this file in
* * accordance with the commercial license agreement provided with the
* * Software or , alternatively , in accordance with the terms contained in
2015-01-14 18:07:15 +01:00
* * a written agreement between you and The Qt Company . For licensing terms and
* * conditions see http : //www.qt.io/terms-conditions. For further information
2014-10-01 13:21:18 +02:00
* * use the contact form at http : //www.qt.io/contact-us.
2008-12-02 14:17:16 +01:00
* *
2009-02-25 09:15:00 +01:00
* * GNU Lesser General Public License Usage
2012-10-02 09:12:39 +02:00
* * Alternatively , this file may be used under the terms of the GNU Lesser
2014-10-01 13:21:18 +02:00
* * General Public License version 2.1 or version 3 as published by the Free
* * Software Foundation and appearing in the file LICENSE . LGPLv21 and
* * LICENSE . LGPLv3 included in the packaging of this file . Please review the
* * following information to ensure the GNU Lesser General Public License
* * requirements will be met : https : //www.gnu.org/licenses/lgpl.html and
* * http : //www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
2012-10-02 09:12:39 +02:00
* *
2015-01-14 18:07:15 +01:00
* * In addition , as a special exception , The Qt Company gives you certain additional
* * rights . These rights are described in The Qt Company LGPL Exception
2010-12-17 16:01:08 +01:00
* * version 1.1 , included in the file LGPL_EXCEPTION . txt in this package .
* *
2012-10-02 09:12:39 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-02 15:08:31 +01:00
2013-03-12 12:15:01 +01:00
# include "qtcreatorintegration.h"
2010-03-10 10:21:52 +01:00
# include "formwindoweditor.h"
2008-12-02 12:01:29 +01:00
# include "formeditorw.h"
2010-03-09 17:01:34 +01:00
# include "editordata.h"
2010-03-10 10:21:52 +01:00
# include <widgethost.h>
2013-08-29 16:36:42 +02:00
# include <designer/cpp/formclasswizardpage.h>
2008-12-02 12:01:29 +01:00
2014-09-15 00:12:27 +02:00
# include <cpptools/cppmodelmanager.h>
2010-08-23 15:05:20 +02:00
# include <cpptools/cpptoolsconstants.h>
2014-07-30 16:29:02 +02:00
# include <cpptools/cppworkingcopy.h>
2010-09-30 12:09:38 +02:00
# include <cpptools/insertionpointlocator.h>
2012-01-20 14:43:21 +01:00
# include <cpptools/symbolfinder.h>
2008-12-02 12:01:29 +01:00
# include <cplusplus/Overview.h>
# include <coreplugin/icore.h>
2014-09-26 09:14:03 +02:00
# include <texteditor/texteditor.h>
2009-11-18 10:31:16 +01:00
# include <projectexplorer/projectexplorer.h>
# include <projectexplorer/session.h>
2010-03-09 17:01:34 +01:00
# include <utils/qtcassert.h>
2008-12-02 12:01:29 +01:00
2012-02-15 10:42:41 +01:00
# include <QDesignerFormWindowInterface>
# include <QDesignerFormEditorInterface>
2008-12-02 12:01:29 +01:00
2012-02-15 10:42:41 +01:00
# include <QMessageBox>
2008-12-02 12:01:29 +01:00
2012-02-15 10:42:41 +01:00
# include <QFileInfo>
# include <QDir>
# include <QDebug>
# include <QUrl>
2008-12-02 12:01:29 +01:00
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 ;
2013-09-05 11:46:07 +02:00
using namespace ProjectExplorer ;
2008-12-02 12:01:29 +01:00
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 ) {
2011-10-17 14:21:06 +02:00
files + = QLatin1Char ( ' \n ' ) ;
files + = QDir : : toNativeSeparators ( doc - > fileName ( ) ) ;
2008-12-16 16:39:19 +01:00
}
2011-10-17 14:21:06 +02:00
return QtCreatorIntegration : : tr (
2014-04-17 14:09:47 +02:00
" The class containing \" %1 \" could not be found in %2. \n "
2011-10-17 14:21:06 +02:00
" Please verify the #include-directives. " )
. arg ( uiClassName , files ) ;
2008-12-16 16:39:19 +01:00
}
2014-09-03 16:03:35 +02:00
QtCreatorIntegration : : QtCreatorIntegration ( QDesignerFormEditorInterface * core , QObject * parent )
: QDesignerIntegration ( core , parent )
2008-12-02 12:01:29 +01:00
{
2011-05-19 11:30:38 +02:00
setResourceFileWatcherBehaviour ( ReloadResourceFileSilently ) ;
Feature f = features ( ) ;
f | = SlotNavigationFeature ;
f & = ~ ResourceEditorFeature ;
setFeatures ( f ) ;
2015-02-03 11:26:40 +01:00
connect ( this , static_cast < void ( QDesignerIntegrationInterface : : * )
( const QString & , const QString & , const QStringList & ) >
( & QDesignerIntegrationInterface : : navigateToSlot ) ,
2015-01-30 10:19:13 +01:00
this , & QtCreatorIntegration : : slotNavigateToSlot ) ;
connect ( this , & QtCreatorIntegration : : helpRequested ,
this , & QtCreatorIntegration : : slotDesignerHelpRequested ) ;
2010-08-23 15:05:20 +02:00
slotSyncSettingsToDesigner ( ) ;
connect ( Core : : ICore : : instance ( ) , SIGNAL ( saveSettingsRequested ( ) ) ,
this , SLOT ( slotSyncSettingsToDesigner ( ) ) ) ;
2010-05-28 15:58:55 +02:00
}
void QtCreatorIntegration : : slotDesignerHelpRequested ( const QString & manual , const QString & document )
{
// Pass on as URL.
2010-06-11 13:11:37 +02:00
emit creatorHelpRequested ( QUrl ( QString : : fromLatin1 ( " qthelp://com.trolltech.%1/qdoc/%2 " )
. arg ( manual , document ) ) ) ;
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
{
2014-09-03 16:03:35 +02:00
if ( SharedTools : : WidgetHost * host = FormEditorW : : activeWidgetHost ( ) )
host - > updateFormWindowSelectionHandles ( true ) ;
2011-05-19 11:30:38 +02:00
QDesignerIntegration : : updateSelection ( ) ;
2008-12-02 12:01:29 +01:00
}
2009-05-08 16:11:49 +02:00
QWidget * QtCreatorIntegration : : containerWindow ( QWidget * /*widget*/ ) const
2008-12-02 12:01:29 +01:00
{
2014-09-03 16:03:35 +02:00
if ( SharedTools : : WidgetHost * host = FormEditorW : : activeWidgetHost ( ) )
return host - > integrationContainer ( ) ;
2010-03-09 17:01:34 +01:00
return 0 ;
2008-12-02 12:01:29 +01:00
}
2013-04-02 11:28:11 +02:00
static QList < Document : : Ptr > findDocumentsIncluding ( const Snapshot & docTable ,
2008-12-18 17:19:54 +01:00
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
2013-07-24 17:21:13 +02:00
const QList < Document : : Include > includes = doc - > resolvedIncludes ( )
+ doc - > unresolvedIncludes ( ) ;
foreach ( const Document : : Include & include , includes ) {
2008-12-11 13:43:11 +01:00
if ( checkFileNameOnly ) {
2013-07-24 17:21:13 +02:00
const QFileInfo fi ( include . unresolvedFileName ( ) ) ;
2008-12-11 13:43:11 +01:00
if ( fi . fileName ( ) = = fileName ) { // we are only interested in docs which includes fileName only
docList . append ( doc ) ;
}
} else {
2013-07-24 17:21:13 +02:00
if ( include . resolvedFileName ( ) = = fileName )
2008-12-11 13:43:11 +01:00
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 ;
}
2013-11-20 17:24:07 +01:00
QString fullyQualifiedName ( const LookupContext & context , const Name * name , Scope * scope )
2008-12-18 17:19:54 +01:00
{
2013-11-20 17:24:07 +01:00
if ( ! name | | ! scope )
return QString ( ) ;
const QList < LookupItem > items = context . lookup ( name , scope ) ;
if ( items . isEmpty ( ) ) { // "ui_xxx.h" might not be generated and nothing is forward declared.
return Overview ( ) . prettyName ( name ) ;
} else {
Symbol * symbol = items . first ( ) . declaration ( ) ;
return Overview ( ) . prettyName ( LookupContext : : fullyQualifiedName ( symbol ) ) ;
}
return QString ( ) ;
2008-12-18 17:19:54 +01:00
}
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
2013-11-20 17:24:07 +01:00
static const Class * findClass ( const Namespace * parentNameSpace , const LookupContext & context ,
const QString & className , QString * namespaceName )
2008-12-18 17:19:54 +01:00
{
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 ( ) ;
2011-04-19 15:42:14 +02:00
for ( unsigned i = 0 ; i < namespaceMemberCount ; + + i ) { // we go through all namespace members
2008-12-18 17:19:54 +01:00
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 ( ) ;
2011-04-19 15:42:14 +02:00
for ( unsigned j = 0 ; j < classMemberCount ; + + j )
2013-11-20 17:24:07 +01:00
if ( Declaration * decl = cl - > memberAt ( j ) - > asDeclaration ( ) ) {
2008-12-18 17:19:54 +01:00
// we want to know if the class contains a member (so we look into
// a declaration) of uiClassName type
2013-11-20 17:24:07 +01:00
QString nameToMatch ;
if ( const NamedType * nt = decl - > type ( ) - > asNamedType ( ) ) {
nameToMatch = fullyQualifiedName ( context , nt - > name ( ) ,
decl - > enclosingScope ( ) ) ;
2008-12-02 12:01:29 +01:00
// handle pointers to member variables
2013-11-20 17:24:07 +01:00
} else if ( PointerType * pt = decl - > type ( ) - > asPointerType ( ) ) {
if ( NamedType * nt = pt - > elementType ( ) - > asNamedType ( ) ) {
nameToMatch = fullyQualifiedName ( context , nt - > name ( ) ,
decl - > enclosingScope ( ) ) ;
}
}
if ( ! nameToMatch . isEmpty ( ) & & className = = nameToMatch )
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 ( " :: " ) ;
2013-11-20 17:24:07 +01:00
if ( const Class * cl = findClass ( ns , context , className , & tempNS ) ) {
2008-12-18 17:19:54 +01:00
* 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 ;
}
2010-05-11 14:14:36 +02:00
static 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 ( ) ;
2013-10-07 13:34:40 +02:00
// we are interested only in declarations (can be decl of function or of a field)
// we are only interested in declarations of functions
2008-12-18 17:19:54 +01:00
const Overview overview ;
2011-05-10 15:19:38 +02:00
for ( unsigned j = 0 ; j < mCount ; + + j ) { // go through all members
2010-05-11 14:14:36 +02:00
if ( Declaration * decl = cl - > memberAt ( j ) - > asDeclaration ( ) )
if ( 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 ;
}
2013-10-07 13:34:40 +02:00
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this function
2010-05-11 14:14:36 +02:00
static Document : : Ptr findDefinition ( Function * functionDeclaration , int * line )
2008-12-02 12:01:29 +01:00
{
2015-02-15 23:13:28 +02:00
CppTools : : CppModelManager * cppModelManager = CppTools : : CppModelManager : : instance ( ) ;
const Snapshot snapshot = cppModelManager - > snapshot ( ) ;
CppTools : : SymbolFinder symbolFinder ;
if ( Function * fun = symbolFinder . findMatchingDefinition ( functionDeclaration , snapshot ) ) {
if ( line )
* line = fun - > line ( ) ;
2008-12-18 17:19:54 +01:00
2015-02-15 23:13:28 +02:00
return snapshot . document ( QString : : fromUtf8 ( fun - > fileName ( ) , fun - > fileNameLength ( ) ) ) ;
2008-12-02 12:01:29 +01:00
}
return Document : : Ptr ( ) ;
}
2014-07-23 19:10:38 +02:00
static inline BaseTextEditor * editorAt ( const QString & fileName , int line , int column )
2008-12-18 17:19:54 +01:00
{
2014-07-23 19:10:38 +02:00
return qobject_cast < BaseTextEditor * > ( Core : : EditorManager : : openEditorAt ( fileName , line , column ,
2013-05-31 12:52:53 +02:00
Core : : Id ( ) ,
Core : : EditorManager : : DoNotMakeVisible ) ) ;
2008-12-18 17:19:54 +01:00
}
2010-09-27 18:01:04 +02:00
static void addDeclaration ( const Snapshot & snapshot ,
const QString & fileName ,
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 " ) ;
2010-09-30 12:09:38 +02:00
CppTools : : CppRefactoringChanges refactoring ( snapshot ) ;
2011-08-17 11:35:57 +02:00
CppTools : : InsertionPointLocator find ( refactoring ) ;
2010-09-30 12:09:38 +02:00
const CppTools : : InsertionLocation loc = find . methodDeclarationInClass (
fileName , cl , CppTools : : InsertionPointLocator : : PrivateSlot ) ;
2010-07-27 17:02:12 +02:00
//
2010-07-28 17:33:21 +02:00
//! \todo change this to use the Refactoring changes.
2010-07-27 17:02:12 +02:00
//
2014-07-23 19:10:38 +02:00
if ( BaseTextEditor * editor = editorAt ( fileName , loc . line ( ) , loc . column ( ) - 1 ) ) {
2014-08-27 11:57:32 +02:00
QTextCursor tc = editor - > textCursor ( ) ;
int pos = tc . position ( ) ;
tc . beginEditBlock ( ) ;
tc . insertText ( loc . prefix ( ) + declaration + loc . suffix ( ) ) ;
tc . setPosition ( pos , QTextCursor : : KeepAnchor ) ;
editor - > textDocument ( ) - > autoIndent ( tc ) ;
tc . endEditBlock ( ) ;
2008-12-11 13:43:11 +01:00
}
}
2013-04-02 11:28:11 +02:00
static Document : : Ptr addDefinition ( const Snapshot & docTable ,
2010-09-27 18:01:04 +02:00
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 ( ) ) {
2010-07-28 12:16:28 +02:00
//
2010-07-28 17:33:21 +02:00
//! \todo change this to use the Refactoring changes.
2010-07-28 12:16:28 +02:00
//
2014-07-23 19:10:38 +02:00
if ( BaseTextEditor * editor = editorAt ( doc - > fileName ( ) , 0 , 0 ) ) {
2010-07-28 12:09:50 +02:00
//
2010-07-28 17:33:21 +02:00
//! \todo use the InsertionPointLocator to insert at the correct place.
2010-07-28 12:16:28 +02:00
// (we'll have to extend that class first to do definition insertions)
2010-07-28 12:09:50 +02:00
2014-07-23 19:10:38 +02:00
const QString contents = editor - > textDocument ( ) - > plainText ( ) ;
2008-12-11 13:43:11 +01:00
int column ;
2014-07-23 19:10:38 +02:00
editor - > convertPosition ( contents . length ( ) , line , & column ) ;
editor - > gotoLine ( * line , column ) ;
editor - > 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
}
2010-12-06 14:07:59 +01:00
static QString addConstRefIfNeeded ( const QString & argument )
{
if ( argument . startsWith ( QLatin1String ( " const " ) )
| | argument . endsWith ( QLatin1Char ( ' & ' ) )
| | argument . endsWith ( QLatin1Char ( ' * ' ) ) )
return argument ;
// for those types we don't want to add "const &"
static const QStringList nonConstRefs = QStringList ( )
< < QLatin1String ( " bool " )
< < QLatin1String ( " int " )
< < QLatin1String ( " uint " )
< < QLatin1String ( " float " )
< < QLatin1String ( " double " )
< < QLatin1String ( " long " )
< < QLatin1String ( " short " )
< < QLatin1String ( " char " )
< < QLatin1String ( " signed " )
< < QLatin1String ( " unsigned " )
< < QLatin1String ( " qint64 " )
< < QLatin1String ( " quint64 " ) ;
for ( int i = 0 ; i < nonConstRefs . count ( ) ; i + + ) {
const QString nonConstRef = nonConstRefs . at ( i ) ;
if ( argument = = nonConstRef | | argument . startsWith ( nonConstRef + QLatin1Char ( ' ' ) ) )
return argument ;
}
return QLatin1String ( " const " ) + argument + QLatin1Char ( ' & ' ) ;
}
static QString formatArgument ( const QString & argument )
{
QString formattedArgument = argument ;
int i = argument . count ( ) ;
while ( i > 0 ) { // from the end of the "argument" string
i - - ;
const QChar c = argument . at ( i ) ; // take the char
if ( c ! = QLatin1Char ( ' * ' ) & & c ! = QLatin1Char ( ' & ' ) ) { // if it's not the * or &
formattedArgument . insert ( i + 1 , QLatin1Char ( ' ' ) ) ; // insert space after that char or just append space (to separate it from the parameter name)
break ;
}
}
return formattedArgument ;
}
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 ( " , " ) ;
2010-12-06 14:07:59 +01:00
const QString argument = addConstRefIfNeeded ( arguments . at ( i ) ) ;
functionName + = formatArgument ( argument ) ;
2008-12-18 17:19:54 +01:00
if ( i < pCount ) {
2010-12-06 11:51:47 +01:00
// prepare parameterName
QString parameterName = parameterNames . at ( i ) ;
if ( parameterName . isEmpty ( ) ) {
const QString generatedName = QLatin1String ( " arg " ) + QString : : number ( i + 1 ) ;
if ( ! parameterNames . contains ( generatedName ) )
parameterName = generatedName ;
}
// add parameterName if not empty
2010-12-06 14:07:59 +01:00
if ( ! parameterName . isEmpty ( ) )
2010-12-06 11:51:47 +01:00
functionName + = parameterName ;
2008-12-18 17:19:54 +01:00
}
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
2013-11-20 17:24:07 +01:00
findClassRecursively ( const LookupContext & context , const QString & className ,
2008-12-18 17:19:54 +01:00
unsigned maxIncludeDepth , QString * namespaceName )
{
2013-11-20 17:24:07 +01:00
const Document : : Ptr doc = context . thisDocument ( ) ;
const Snapshot docTable = context . snapshot ( ) ;
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
2013-11-20 17:24:07 +01:00
if ( const Class * cl = findClass ( doc - > globalNamespace ( ) , context , className , namespaceName ) )
2008-12-18 17:19:54 +01:00
return ClassDocumentPtrPair ( cl , doc ) ;
if ( maxIncludeDepth ) {
// Check the includes
const unsigned recursionMaxIncludeDepth = maxIncludeDepth - 1u ;
foreach ( const QString & include , doc - > includedFiles ( ) ) {
2013-04-02 11:28:11 +02:00
const Snapshot : : const_iterator it = docTable . find ( include ) ;
2009-12-07 10:54:27 +01:00
if ( it ! = docTable . end ( ) ) {
2008-12-18 17:19:54 +01:00
const Document : : Ptr includeDoc = it . value ( ) ;
2013-11-20 17:24:07 +01:00
LookupContext context ( includeDoc , docTable ) ;
const ClassDocumentPtrPair irc = findClassRecursively ( context , className ,
recursionMaxIncludeDepth , namespaceName ) ;
2008-12-18 17:19:54 +01:00
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 ;
Remove braces for single lines of conditions
#!/usr/bin/env ruby
Dir.glob('**/*.cpp') { |file|
# skip ast (excluding paste, astpath, and canv'ast'imer)
next if file =~ /ast[^eip]|keywords\.|qualifiers|preprocessor|names.cpp/i
s = File.read(file)
next if s.include?('qlalr')
orig = s.dup
s.gsub!(/\n *if [^\n]*{\n[^\n]*\n\s+}(\s+else if [^\n]* {\n[^\n]*\n\s+})*(\s+else {\n[^\n]*\n\s+})?\n/m) { |m|
res = $&
if res =~ /^\s*(\/\/|[A-Z_]{3,})/ # C++ comment or macro (Q_UNUSED, SDEBUG), do not touch braces
res
else
res.gsub!('} else', 'else')
res.gsub!(/\n +} *\n/m, "\n")
res.gsub(/ *{$/, '')
end
}
s.gsub!(/ *$/, '')
File.open(file, 'wb').write(s) if s != orig
}
Change-Id: I3b30ee60df0986f66c02132c65fc38a3fbb6bbdc
Reviewed-by: hjk <qthjk@ovi.com>
2013-01-08 03:32:53 +02:00
if ( ! navigateToSlot ( objectName , signalSignature , parameterNames , & errorMessage ) & & ! errorMessage . isEmpty ( ) )
2014-09-03 16:03:35 +02:00
QMessageBox : : warning ( FormEditorW : : 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 ;
}
2013-04-02 11:28:11 +02:00
static Document : : Ptr getParsedDocument ( const QString & fileName ,
2014-07-30 16:29:02 +02:00
CppTools : : WorkingCopy & workingCopy ,
2013-04-02 11:28:11 +02:00
Snapshot & snapshot )
2010-07-27 17:02:12 +02:00
{
2013-08-19 15:47:51 +02:00
QByteArray src ;
2010-07-27 17:02:12 +02:00
if ( workingCopy . contains ( fileName ) ) {
src = workingCopy . source ( fileName ) ;
} else {
2011-03-30 15:15:15 +02:00
Utils : : FileReader reader ;
if ( reader . fetch ( fileName ) ) // ### FIXME error reporting
2013-08-19 15:47:51 +02:00
src = QString : : fromLocal8Bit ( reader . data ( ) ) . toUtf8 ( ) ;
2010-07-27 17:02:12 +02:00
}
2012-10-11 16:16:01 +02:00
Document : : Ptr doc = snapshot . preprocessedDocument ( src , fileName ) ;
2010-07-27 17:02:12 +02:00
doc - > check ( ) ;
2010-09-27 18:01:04 +02:00
snapshot . insert ( doc ) ;
2010-07-27 17:02:12 +02:00
return doc ;
}
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
{
2011-03-31 08:59:04 +02:00
typedef QMap < int , Document : : Ptr > DocumentMap ;
2015-02-02 00:37:38 +02:00
const Utils : : FileName currentUiFile = FormEditorW : : activeEditor ( ) - > document ( ) - > filePath ( ) ;
2009-12-03 16:23:15 +01:00
#if 0
2015-02-02 00:37:38 +02:00
return Designer : : Internal : : navigateToSlot ( currentUiFile . toString ( ) , objectName ,
signalSignature , parameterNames , errorMessage ) ;
2009-12-03 16:23:15 +01:00
# 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 (?)
2015-02-02 00:37:38 +02:00
const QFileInfo fi = currentUiFile . toFileInfo ( ) ;
2011-03-31 08:59:04 +02:00
const QString uiFolder = fi . absolutePath ( ) ;
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
2013-07-24 17:21:13 +02:00
// Retrieve code model snapshot restricted to project of ui file or the working copy.
2014-09-15 00:12:27 +02:00
Snapshot docTable = CppTools : : CppModelManager : : instance ( ) - > snapshot ( ) ;
2013-04-02 11:28:11 +02:00
Snapshot newDocTable ;
2013-09-05 11:46:07 +02:00
const Project * uiProject = SessionManager : : projectForFile ( currentUiFile ) ;
2013-07-24 17:21:13 +02:00
if ( uiProject ) {
2014-11-27 12:11:46 +01:00
for ( Snapshot : : const_iterator i = docTable . begin ( ) , ei = docTable . end ( ) ; i ! = ei ; + + i ) {
2015-02-02 00:37:38 +02:00
const Project * project = SessionManager : : projectForFile ( i . key ( ) ) ;
2013-07-24 17:21:13 +02:00
if ( project = = uiProject )
2014-11-27 12:11:46 +01:00
newDocTable . insert ( i . value ( ) ) ;
2013-07-24 17:21:13 +02:00
}
} else {
2014-07-30 16:29:02 +02:00
const CppTools : : WorkingCopy workingCopy =
2014-09-15 00:12:27 +02:00
CppTools : : CppModelManager : : instance ( ) - > workingCopy ( ) ;
2014-11-27 10:49:18 +01:00
const Utils : : FileName configFileName =
Utils : : FileName : : fromString ( CppTools : : CppModelManager : : configurationFileName ( ) ) ;
QHashIterator < Utils : : FileName , QPair < QByteArray , unsigned > > it = workingCopy . iterator ( ) ;
2013-07-24 17:21:13 +02:00
while ( it . hasNext ( ) ) {
it . next ( ) ;
2014-11-27 10:49:18 +01:00
const Utils : : FileName & fileName = it . key ( ) ;
if ( fileName ! = configFileName )
2015-02-01 19:19:32 +02:00
newDocTable . insert ( docTable . document ( fileName ) ) ;
2013-07-24 17:21:13 +02:00
}
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.
2011-03-31 08:59:04 +02:00
// Sort into a map, putting the ones whose path closely matches the ui-folder path
// first in case there are project subdirectories that contain identical file names.
const QList < Document : : Ptr > docList = findDocumentsIncluding ( docTable , uicedName , true ) ; // change to false when we know the absolute path to generated ui_<>.h file
DocumentMap docMap ;
foreach ( const Document : : Ptr & d , docList ) {
const QFileInfo docFi ( d - > fileName ( ) ) ;
docMap . insert ( qAbs ( docFi . absolutePath ( ) . compare ( uiFolder , Qt : : CaseInsensitive ) ) , d ) ;
}
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 ( ) ;
2011-03-31 08:59:04 +02:00
if ( docMap . isEmpty ( ) ) {
2014-04-17 14:09:47 +02: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
2014-09-03 16:03:35 +02:00
QDesignerFormWindowInterface * fwi = FormEditorW : : activeWidgetHost ( ) - > formWindow ( ) ;
2008-12-02 12:01:29 +01:00
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 ;
2011-03-31 08:59:04 +02:00
foreach ( const Document : : Ptr & d , docMap ) {
2013-11-20 17:24:07 +01:00
LookupContext context ( d , docTable ) ;
const ClassDocumentPtrPair cd = findClassRecursively ( context , uiClass , 1u , & namespaceName ) ;
2008-12-18 17:19:54 +01:00
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 ;
2010-05-11 14:14:36 +02:00
if ( Function * fun = findDeclaration ( cl , functionName ) ) {
2008-12-18 17:19:54 +01:00
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
2014-07-30 16:29:02 +02:00
CppTools : : WorkingCopy workingCopy =
2014-09-15 00:12:27 +02:00
CppTools : : CppModelManager : : instance ( ) - > workingCopy ( ) ;
2010-09-27 18:01:04 +02:00
const QString fileName = doc - > fileName ( ) ;
getParsedDocument ( fileName , workingCopy , docTable ) ;
addDeclaration ( docTable , fileName , cl , functionNameWithParameterNames ) ;
2008-12-18 17:19:54 +01:00
// add function definition to cpp file
2010-09-27 18:01:04 +02:00
sourceDoc = addDefinition ( docTable , 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
2013-05-30 17:26:51 +02:00
Core : : EditorManager : : openEditorAt ( sourceDoc - > fileName ( ) , line + 2 , indentation ) ;
2008-12-18 17:19:54 +01:00
return true ;
}
2010-08-23 15:05:20 +02:00
void QtCreatorIntegration : : slotSyncSettingsToDesigner ( )
{
// Set promotion-relevant parameters on integration.
2013-08-30 16:38:57 +02:00
setHeaderSuffix ( Core : : MimeDatabase : : preferredSuffixByType ( QLatin1String ( CppTools : : Constants : : CPP_HEADER_MIMETYPE ) ) ) ;
2010-08-23 15:05:20 +02:00
setHeaderLowercase ( FormClassWizardPage : : lowercaseHeaderFiles ( ) ) ;
}