2012-10-02 09:12:39 +02:00
/****************************************************************************
2008-12-02 12:01:29 +01:00
* *
2013-01-28 17:12:19 +01:00
* * Copyright ( C ) 2013 Digia Plc and / or its subsidiary ( - ies ) .
2012-10-02 09:12:39 +02:00
* * Contact : http : //www.qt-project.org/legal
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
* * a written agreement between you and Digia . For licensing terms and
* * conditions see http : //qt.digia.com/licensing. For further information
* * use the contact form at http : //qt.digia.com/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
* * 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.
* *
* * In addition , as a special exception , Digia gives you certain additional
* * rights . These rights are described in the Digia Qt 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"
2010-08-23 15:05:20 +02:00
# include "formclasswizardpage.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>
2008-12-02 12:01:29 +01:00
2010-08-23 15:05:20 +02:00
# include <cpptools/cpptoolsconstants.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>
# include <texteditor/basetexteditor.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 ;
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 (
" The class containing '%1' could not be found in %2. \n "
" Please verify the #include-directives. " )
. arg ( uiClassName , files ) ;
2008-12-16 16:39:19 +01:00
}
2009-05-08 16:11:49 +02:00
QtCreatorIntegration : : QtCreatorIntegration ( QDesignerFormEditorInterface * core , FormEditorW * parent ) :
2011-05-19 11:30:38 +02:00
# if QT_VERSION >= 0x050000
QDesignerIntegration ( core , parent ) ,
# else
qdesigner_internal : : QDesignerIntegration ( core , parent ) ,
# endif
2008-12-02 12:01:29 +01:00
m_few ( parent )
{
2011-05-19 11:30:38 +02:00
# if QT_VERSION >= 0x050000
setResourceFileWatcherBehaviour ( ReloadResourceFileSilently ) ;
Feature f = features ( ) ;
f | = SlotNavigationFeature ;
f & = ~ ResourceEditorFeature ;
setFeatures ( f ) ;
# else
2008-12-02 12:01:29 +01:00
setResourceFileWatcherBehaviour ( QDesignerIntegration : : ReloadSilently ) ;
setResourceEditingEnabled ( false ) ;
setSlotNavigationEnabled ( true ) ;
2011-05-19 11:30:38 +02:00
# endif
2012-03-05 22:30:59 +01:00
connect ( this , SIGNAL ( navigateToSlot ( QString , QString , QStringList ) ) ,
this , SLOT ( slotNavigateToSlot ( QString , QString , QStringList ) ) ) ;
2010-05-28 15:58:55 +02:00
connect ( this , SIGNAL ( helpRequested ( QString , QString ) ) ,
this , SLOT ( slotDesignerHelpRequested ( QString , QString ) ) ) ;
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
{
2010-03-09 17:01:34 +01:00
if ( const EditorData ed = m_few - > activeEditor ( ) )
2010-03-10 10:21:52 +01:00
ed . widgetHost - > updateFormWindowSelectionHandles ( true ) ;
2011-05-19 11:30:38 +02:00
# if QT_VERSION >= 0x050000
QDesignerIntegration : : updateSelection ( ) ;
# else
2008-12-02 12:01:29 +01:00
qdesigner_internal : : QDesignerIntegration : : updateSelection ( ) ;
2011-05-19 11:30:38 +02:00
# endif
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
{
2010-03-09 17:01:34 +01:00
if ( const EditorData ed = m_few - > activeEditor ( ) )
2010-03-10 10:21:52 +01:00
return ed . widgetHost - > 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
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
2013-04-02 11:28:11 +02:00
static const Class * findClass ( const Namespace * parentNameSpace ,
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 )
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 ;
}
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 ( ) ;
// 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 ;
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 ;
}
// TODO: remove me, this is taken from cppeditor.cpp. Find some common place for this method
2010-05-11 14:14:36 +02:00
static Document : : Ptr findDefinition ( Function * functionDeclaration , int * line )
2008-12-02 12:01:29 +01:00
{
2013-04-02 11:28:11 +02:00
if ( CppTools : : CppModelManagerInterface * cppModelManager = CppTools : : CppModelManagerInterface : : instance ( ) ) {
2010-05-11 14:14:36 +02:00
const Snapshot snapshot = cppModelManager - > snapshot ( ) ;
2012-01-23 16:08:01 +01:00
CppTools : : SymbolFinder symbolFinder ;
2013-05-14 11:04:38 +02:00
if ( Function * fun = symbolFinder . findMatchingDefinition ( functionDeclaration , snapshot ) ) {
2010-05-11 14:14:36 +02:00
if ( line )
2013-05-14 11:04:38 +02:00
* line = fun - > line ( ) ;
2008-12-18 17:19:54 +01:00
2013-05-14 11:04:38 +02:00
return snapshot . document ( QString : : fromUtf8 ( fun - > fileName ( ) , fun - > fileNameLength ( ) ) ) ;
2008-12-02 12:01:29 +01:00
}
}
return Document : : Ptr ( ) ;
}
2011-02-21 16:02:26 +01:00
static inline ITextEditor * editableAt ( const QString & fileName , int line , int column )
2008-12-18 17:19:54 +01:00
{
2013-05-30 17:26:51 +02:00
return qobject_cast < ITextEditor * > ( Core : : EditorManager : : openEditorAt ( fileName , line , column ) ) ;
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
//
2011-02-21 16:02:26 +01:00
if ( ITextEditor * editable = editableAt ( fileName , loc . line ( ) , loc . column ( ) - 1 ) ) {
BaseTextEditorWidget * editor = qobject_cast < BaseTextEditorWidget * > ( editable - > widget ( ) ) ;
2010-07-27 17:02:12 +02:00
if ( editor ) {
QTextCursor tc = editor - > textCursor ( ) ;
int pos = tc . position ( ) ;
tc . beginEditBlock ( ) ;
2010-07-28 12:09:50 +02:00
tc . insertText ( loc . prefix ( ) + declaration + loc . suffix ( ) ) ;
2010-07-27 17:02:12 +02:00
tc . setPosition ( pos , QTextCursor : : KeepAnchor ) ;
editor - > indentInsertedText ( 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
//
2011-02-21 16:02:26 +01:00
if ( ITextEditor * editable = editableAt ( 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
2013-04-18 18:21:17 +02:00
const QString contents = editable - > textDocument ( ) - > contents ( ) ;
2008-12-11 13:43:11 +01:00
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
}
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-04-02 11:28:11 +02:00
findClassRecursively ( const Snapshot & docTable ,
2008-12-18 17:19:54 +01:00
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 ( ) ) {
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 ( ) ;
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 ;
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 ( ) )
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 ;
}
2013-04-02 11:28:11 +02:00
static Document : : Ptr getParsedDocument ( const QString & fileName ,
CppTools : : CppModelManagerInterface : : WorkingCopy & workingCopy ,
Snapshot & snapshot )
2010-07-27 17:02:12 +02:00
{
QString src ;
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
src = QString : : fromLocal8Bit ( reader . data ( ) ) ; // ### FIXME encoding
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 ;
2010-03-09 17:01:34 +01:00
const EditorData ed = m_few - > activeEditor ( ) ;
2012-04-17 08:01:25 +02:00
QTC_ASSERT ( ed , return false ) ;
2012-02-14 16:43:51 +01:00
const QString currentUiFile = ed . formWindowEditor - > document ( ) - > 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 ) ;
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
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 ;
}
2013-04-02 11:28:11 +02:00
Snapshot docTable = CppTools : : CppModelManagerInterface : : instance ( ) - > snapshot ( ) ;
Snapshot newDocTable ;
2009-12-07 10:54:27 +01:00
2013-04-02 11:28:11 +02:00
for ( 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.
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 ( ) ) {
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
2010-03-10 10:21:52 +01:00
QDesignerFormWindowInterface * fwi = ed . widgetHost - > 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 ) {
2008-12-18 17:19:54 +01:00
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 ;
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
2013-04-02 11:28:11 +02:00
CppTools : : CppModelManagerInterface : : WorkingCopy workingCopy =
CppTools : : CppModelManagerInterface : : 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 ( )
{
2011-09-28 09:52:21 +02:00
# if QT_VERSION > 0x040800
2010-08-23 15:05:20 +02:00
// Set promotion-relevant parameters on integration.
2012-01-24 15:36:40 +01:00
const Core : : MimeDatabase * mdb = Core : : ICore : : mimeDatabase ( ) ;
2010-08-23 15:05:20 +02:00
setHeaderSuffix ( mdb - > preferredSuffixByType ( QLatin1String ( CppTools : : Constants : : CPP_HEADER_MIMETYPE ) ) ) ;
setHeaderLowercase ( FormClassWizardPage : : lowercaseHeaderFiles ( ) ) ;
# endif
}