2010-03-12 11:20:32 +01:00
/**************************************************************************
* *
* * This file is part of Qt Creator
* *
* * Copyright ( c ) 2010 Nokia Corporation and / or its subsidiary ( - ies ) .
* *
* * Contact : Nokia Corporation ( qt - info @ nokia . com )
* *
* * Commercial Usage
* *
* * 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 .
* *
* * GNU Lesser General Public License Usage
* *
* * 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.
* *
* * If you are unsure which license is appropriate for your use , please
* * contact the sales department at http : //qt.nokia.com/contact.
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "customwizard.h"
# include "customwizardparameters.h"
# include "customwizardpage.h"
# include "projectexplorer.h"
# include "baseprojectwizarddialog.h"
# include <coreplugin/icore.h>
2010-03-19 11:26:56 +01:00
# include <coreplugin/messagemanager.h>
# include <extensionsystem/pluginmanager.h>
2010-03-12 11:20:32 +01:00
# include <utils/qtcassert.h>
# include <QtCore/QDebug>
# include <QtCore/QFile>
# include <QtCore/QMap>
# include <QtCore/QDir>
# include <QtCore/QFileInfo>
2010-03-31 14:48:08 +02:00
# include <QtCore/QCoreApplication>
2010-03-12 11:20:32 +01:00
static const char templatePathC [ ] = " templates/wizards " ;
static const char configFileC [ ] = " wizard.xml " ;
namespace ProjectExplorer {
struct CustomWizardPrivate {
2010-03-22 15:33:33 +01:00
CustomWizardPrivate ( ) : m_context ( new Internal : : CustomWizardContext ) { }
2010-03-12 11:20:32 +01:00
QSharedPointer < Internal : : CustomWizardParameters > m_parameters ;
2010-03-22 15:33:33 +01:00
QSharedPointer < Internal : : CustomWizardContext > m_context ;
2010-03-17 15:17:03 +01:00
static int verbose ;
2010-03-12 11:20:32 +01:00
} ;
2010-03-17 15:17:03 +01:00
int CustomWizardPrivate : : verbose = 0 ;
2010-03-12 11:20:32 +01:00
CustomWizard : : CustomWizard ( const Core : : BaseFileWizardParameters & baseFileParameters ,
QObject * parent ) :
Core : : BaseFileWizard ( baseFileParameters , parent ) ,
d ( new CustomWizardPrivate )
{
}
CustomWizard : : ~ CustomWizard ( )
{
delete d ;
}
2010-03-17 15:17:03 +01:00
void CustomWizard : : setVerbose ( int v )
{
CustomWizardPrivate : : verbose = v ;
}
int CustomWizard : : verbose ( )
{
return CustomWizardPrivate : : verbose ;
}
2010-03-12 11:20:32 +01:00
void CustomWizard : : setParameters ( const CustomWizardParametersPtr & p )
{
d - > m_parameters = p ;
}
// Add a wizard page with an id, visibly warn if something goes wrong.
2010-03-31 14:48:08 +02:00
static inline void addWizardPage ( Utils : : Wizard * w , QWizardPage * p , int id )
2010-03-12 11:20:32 +01:00
{
2010-03-31 14:48:08 +02:00
int addedPageId = 0 ;
2010-03-12 11:20:32 +01:00
if ( id = = - 1 ) {
2010-03-31 14:48:08 +02:00
addedPageId = w - > addPage ( p ) ;
2010-03-12 11:20:32 +01:00
} else {
if ( w - > pageIds ( ) . contains ( id ) ) {
qWarning ( " Page %d already present in custom wizard dialog, defaulting to add. " , id ) ;
2010-03-31 14:48:08 +02:00
addedPageId = w - > addPage ( p ) ;
2010-03-12 11:20:32 +01:00
} else {
w - > setPage ( id , p ) ;
2010-03-31 14:48:08 +02:00
addedPageId = id ;
2010-03-12 11:20:32 +01:00
}
}
2010-03-31 14:48:08 +02:00
w - > wizardProgress ( ) - > item ( addedPageId ) - > setTitle ( QCoreApplication : : translate ( " ProjectExplorer::CustomWizard " , " Details " , " Default short title for custom wizard page to be shown in the progress pane of the wizard. " ) ) ;
2010-03-12 11:20:32 +01:00
}
// Initialize a wizard with a custom file page.
2010-03-31 14:48:08 +02:00
void CustomWizard : : initWizardDialog ( Utils : : Wizard * wizard , const QString & defaultPath ,
2010-03-12 11:20:32 +01:00
const WizardPageList & extensionPages ) const
{
QTC_ASSERT ( ! parameters ( ) . isNull ( ) , return ) ;
2010-03-22 15:33:33 +01:00
d - > m_context - > reset ( ) ;
Internal : : CustomWizardPage * customPage = new Internal : : CustomWizardPage ( d - > m_context , parameters ( ) - > fields ) ;
2010-03-12 11:20:32 +01:00
customPage - > setPath ( defaultPath ) ;
addWizardPage ( wizard , customPage , parameters ( ) - > firstPageId ) ;
if ( ! parameters ( ) - > fieldPageTitle . isEmpty ( ) )
customPage - > setTitle ( parameters ( ) - > fieldPageTitle ) ;
foreach ( QWizardPage * ep , extensionPages )
2010-03-31 14:48:08 +02:00
BaseFileWizard : : applyExtensionPageShortTitle ( wizard , wizard - > addPage ( ep ) ) ;
2010-03-12 11:20:32 +01:00
Core : : BaseFileWizard : : setupWizard ( wizard ) ;
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-12 11:20:32 +01:00
qDebug ( ) < < " initWizardDialog " < < wizard < < wizard - > pageIds ( ) ;
}
QWizard * CustomWizard : : createWizardDialog ( QWidget * parent ,
const QString & defaultPath ,
const WizardPageList & extensionPages ) const
{
QTC_ASSERT ( ! d - > m_parameters . isNull ( ) , return 0 ) ;
2010-03-31 14:48:08 +02:00
Utils : : Wizard * wizard = new Utils : : Wizard ( parent ) ;
2010-03-12 11:20:32 +01:00
initWizardDialog ( wizard , defaultPath , extensionPages ) ;
return wizard ;
}
// Read out files and store contents with field contents replaced.
static inline bool createFile ( Internal : : CustomWizardFile cwFile ,
const QString & sourceDirectory ,
const QString & targetDirectory ,
const CustomProjectWizard : : FieldReplacementMap & fm ,
Core : : GeneratedFiles * files ,
QString * errorMessage )
{
const QChar slash = QLatin1Char ( ' / ' ) ;
const QString sourcePath = sourceDirectory + slash + cwFile . source ;
2010-03-22 15:33:33 +01:00
// Field replacement on target path
Internal : : CustomWizardContext : : replaceFields ( fm , & cwFile . target ) ;
2010-03-12 11:20:32 +01:00
const QString targetPath = QDir : : toNativeSeparators ( targetDirectory + slash + cwFile . target ) ;
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-12 11:20:32 +01:00
qDebug ( ) < < " generating " < < targetPath < < sourcePath < < fm ;
QFile file ( sourcePath ) ;
if ( ! file . open ( QIODevice : : ReadOnly | QIODevice : : Text ) ) {
* errorMessage = QString : : fromLatin1 ( " Cannot open %1: %2 " ) . arg ( sourcePath , file . errorString ( ) ) ;
return false ;
}
2010-03-22 15:33:33 +01:00
// Field replacement on contents
2010-03-12 11:20:32 +01:00
QString contents = QString : : fromLocal8Bit ( file . readAll ( ) ) ;
if ( ! contents . isEmpty ( ) & & ! fm . isEmpty ( ) )
2010-03-22 15:33:33 +01:00
Internal : : CustomWizardContext : : replaceFields ( fm , & contents ) ;
2010-03-12 11:20:32 +01:00
Core : : GeneratedFile generatedFile ;
generatedFile . setContents ( contents ) ;
generatedFile . setPath ( targetPath ) ;
2010-04-16 15:55:32 +02:00
Core : : GeneratedFile : : Attributes attributes = 0 ;
if ( cwFile . openEditor )
attributes | = Core : : GeneratedFile : : OpenEditorAttribute ;
if ( cwFile . openProject )
attributes | = Core : : GeneratedFile : : OpenProjectAttribute ;
generatedFile . setAttributes ( attributes ) ;
2010-03-12 11:20:32 +01:00
files - > push_back ( generatedFile ) ;
return true ;
}
// Helper to find a specific wizard page of a wizard by type.
template < class WizardPage >
WizardPage * findWizardPage ( const QWizard * w )
{
foreach ( int pageId , w - > pageIds ( ) )
if ( WizardPage * wp = qobject_cast < WizardPage * > ( w - > page ( pageId ) ) )
return wp ;
return 0 ;
}
Core : : GeneratedFiles CustomWizard : : generateFiles ( const QWizard * dialog , QString * errorMessage ) const
{
// Look for the Custom field page to find the path
const Internal : : CustomWizardPage * cwp = findWizardPage < Internal : : CustomWizardPage > ( dialog ) ;
QTC_ASSERT ( cwp , return Core : : GeneratedFiles ( ) )
QString path = cwp - > path ( ) ;
2010-03-22 15:33:33 +01:00
const FieldReplacementMap fieldMap = replacementMap ( dialog ) ;
if ( CustomWizardPrivate : : verbose ) {
QString logText ;
QTextStream str ( & logText ) ;
str < < " CustomWizard::generateFiles: " < < path < < ' \n ' ;
const FieldReplacementMap : : const_iterator cend = fieldMap . constEnd ( ) ;
for ( FieldReplacementMap : : const_iterator it = fieldMap . constBegin ( ) ; it ! = cend ; + + it )
str < < " ' " < < it . key ( ) < < " ' -> ' " < < it . value ( ) < < " ' \n " ;
qWarning ( " %s " , qPrintable ( logText ) ) ;
}
2010-03-12 11:20:32 +01:00
return generateWizardFiles ( path , fieldMap , errorMessage ) ;
}
Core : : GeneratedFiles CustomWizard : : generateWizardFiles ( const QString & targetPath ,
const FieldReplacementMap & fieldReplacementMap ,
QString * errorMessage ) const
{
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-12 11:20:32 +01:00
qDebug ( ) < < " Replacements " < < fieldReplacementMap ;
// Create files
Core : : GeneratedFiles rc ;
foreach ( const Internal : : CustomWizardFile & file , d - > m_parameters - > files )
if ( ! createFile ( file , d - > m_parameters - > directory , targetPath , fieldReplacementMap , & rc , errorMessage ) )
return Core : : GeneratedFiles ( ) ;
return rc ;
}
2010-03-22 15:33:33 +01:00
// Create a replacement map of static base fields + wizard dialog fields
CustomWizard : : FieldReplacementMap CustomWizard : : replacementMap ( const QWizard * w ) const
2010-03-12 11:20:32 +01:00
{
2010-03-22 15:33:33 +01:00
FieldReplacementMap fieldReplacementMap = d - > m_context - > baseReplacements ;
2010-03-12 11:20:32 +01:00
foreach ( const Internal : : CustomWizardField & field , d - > m_parameters - > fields ) {
const QString value = w - > field ( field . name ) . toString ( ) ;
fieldReplacementMap . insert ( field . name , value ) ;
}
return fieldReplacementMap ;
}
CustomWizard : : CustomWizardParametersPtr CustomWizard : : parameters ( ) const
{
return d - > m_parameters ;
}
2010-03-22 15:33:33 +01:00
CustomWizard : : CustomWizardContextPtr CustomWizard : : context ( ) const
{
return d - > m_context ;
}
2010-03-12 11:20:32 +01:00
// Static factory map
typedef QMap < QString , QSharedPointer < ICustomWizardFactory > > CustomWizardFactoryMap ;
Q_GLOBAL_STATIC ( CustomWizardFactoryMap , customWizardFactoryMap )
void CustomWizard : : registerFactory ( const QString & name , const ICustomWizardFactoryPtr & f )
{
customWizardFactoryMap ( ) - > insert ( name , f ) ;
}
CustomWizard * CustomWizard : : createWizard ( const CustomWizardParametersPtr & p , const Core : : BaseFileWizardParameters & b )
{
CustomWizard * rc = 0 ;
if ( p - > klass . isEmpty ( ) ) {
// Use defaults for empty class names
switch ( b . kind ( ) ) {
case Core : : IWizard : : ProjectWizard :
rc = new CustomProjectWizard ( b ) ;
break ;
case Core : : IWizard : : FileWizard :
case Core : : IWizard : : ClassWizard :
rc = new CustomWizard ( b ) ;
break ;
}
} else {
// Look up class name in map
const CustomWizardFactoryMap : : const_iterator it = customWizardFactoryMap ( ) - > constFind ( p - > klass ) ;
if ( it ! = customWizardFactoryMap ( ) - > constEnd ( ) )
rc = it . value ( ) - > create ( b ) ;
}
if ( ! rc ) {
qWarning ( " Unable to create custom wizard for class %s. " , qPrintable ( p - > klass ) ) ;
return 0 ;
}
rc - > setParameters ( p ) ;
return rc ;
}
2010-03-19 11:26:56 +01:00
// Format all wizards for display
static QString listWizards ( )
{
typedef QMultiMap < QString , const Core : : IWizard * > CategoryWizardMap ;
// Sort by category via multimap
QString rc ;
QTextStream str ( & rc ) ;
CategoryWizardMap categoryWizardMap ;
foreach ( const Core : : IWizard * w , Core : : IWizard : : allWizards ( ) )
categoryWizardMap . insert ( w - > category ( ) , w ) ;
str < < " ### Registered wizards ( " < < categoryWizardMap . size ( ) < < " ) \n " ;
// Format
QString lastCategory ;
const CategoryWizardMap : : const_iterator cend = categoryWizardMap . constEnd ( ) ;
for ( CategoryWizardMap : : const_iterator it = categoryWizardMap . constBegin ( ) ; it ! = cend ; + + it ) {
const Core : : IWizard * wizard = it . value ( ) ;
if ( it . key ( ) ! = lastCategory ) {
lastCategory = it . key ( ) ;
str < < " \n Category: ' " < < lastCategory < < " ' / ' " < < wizard - > displayCategory ( ) < < " ' \n " ;
}
str < < " Id: ' " < < wizard - > id ( ) < < " ' / ' " < < wizard - > displayName ( ) < < " ' Kind: "
< < wizard - > kind ( ) < < " \n Class: " < < wizard - > metaObject ( ) - > className ( )
< < " Description: ' " < < wizard - > description ( ) < < " ' \n " ;
}
return rc ;
}
2010-03-12 11:20:32 +01:00
// Scan the subdirectories of the template directory for directories
// containing valid configuration files and parse them into wizards.
QList < CustomWizard * > CustomWizard : : createWizards ( )
{
QList < CustomWizard * > rc ;
QString errorMessage ;
2010-03-19 11:26:56 +01:00
QString verboseLog ;
2010-03-12 11:20:32 +01:00
const QString templateDirName = Core : : ICore : : instance ( ) - > resourcePath ( ) +
QLatin1Char ( ' / ' ) + QLatin1String ( templatePathC ) ;
2010-03-19 11:26:56 +01:00
2010-03-12 11:20:32 +01:00
const QDir templateDir ( templateDirName ) ;
2010-03-19 11:26:56 +01:00
if ( CustomWizardPrivate : : verbose )
verboseLog = QString : : fromLatin1 ( " ### CustomWizard: Checking '%1' \n " ) . arg ( templateDirName ) ;
2010-03-12 11:20:32 +01:00
if ( ! templateDir . exists ( ) ) {
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-12 11:20:32 +01:00
qWarning ( " Custom project template path %s does not exist. " , qPrintable ( templateDir . absolutePath ( ) ) ) ;
return rc ;
}
const QList < QFileInfo > dirs = templateDir . entryInfoList ( QDir : : Dirs | QDir : : Readable | QDir : : NoDotAndDotDot ,
QDir : : Name | QDir : : IgnoreCase ) ;
const QString configFile = QLatin1String ( configFileC ) ;
// Check and parse config file in each directory.
foreach ( const QFileInfo & dirFi , dirs ) {
const QDir dir ( dirFi . absoluteFilePath ( ) ) ;
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-19 11:26:56 +01:00
verboseLog + = QString : : fromLatin1 ( " CustomWizard: Scanning %1 \n " ) . arg ( dirFi . absoluteFilePath ( ) ) ;
2010-03-12 11:20:32 +01:00
if ( dir . exists ( configFile ) ) {
CustomWizardParametersPtr parameters ( new Internal : : CustomWizardParameters ) ;
Core : : BaseFileWizardParameters baseFileParameters ;
if ( parameters - > parse ( dir . absoluteFilePath ( configFile ) , & baseFileParameters , & errorMessage ) ) {
parameters - > directory = dir . absolutePath ( ) ;
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-19 11:26:56 +01:00
verboseLog + = parameters - > toString ( ) ;
2010-03-12 11:20:32 +01:00
if ( CustomWizard * w = createWizard ( parameters , baseFileParameters ) )
rc . push_back ( w ) ;
} else {
qWarning ( " Failed to initialize custom project wizard in %s: %s " ,
qPrintable ( dir . absolutePath ( ) ) , qPrintable ( errorMessage ) ) ;
}
2010-03-17 15:17:03 +01:00
} else {
if ( CustomWizardPrivate : : verbose )
2010-03-19 11:26:56 +01:00
if ( CustomWizardPrivate : : verbose )
verboseLog + = QString : : fromLatin1 ( " CustomWizard: '%1' not found \n " ) . arg ( qPrintable ( configFile ) ) ;
2010-03-12 11:20:32 +01:00
}
}
2010-03-19 11:26:56 +01:00
if ( CustomWizardPrivate : : verbose ) { // Print to output pane for Windows.
verboseLog + = listWizards ( ) ;
qWarning ( " %s " , qPrintable ( verboseLog ) ) ;
Core : : ICore : : instance ( ) - > messageManager ( ) - > printToOutputPanePopup ( verboseLog ) ;
}
2010-03-12 11:20:32 +01:00
return rc ;
}
// --------------- CustomProjectWizard
CustomProjectWizard : : CustomProjectWizard ( const Core : : BaseFileWizardParameters & baseFileParameters ,
QObject * parent ) :
CustomWizard ( baseFileParameters , parent )
{
}
QWizard * CustomProjectWizard : : createWizardDialog ( QWidget * parent ,
const QString & defaultPath ,
const WizardPageList & extensionPages ) const
{
QTC_ASSERT ( ! parameters ( ) . isNull ( ) , return 0 ) ;
BaseProjectWizardDialog * projectDialog = new BaseProjectWizardDialog ( parent ) ;
initProjectWizardDialog ( projectDialog , defaultPath , extensionPages ) ;
return projectDialog ;
}
void CustomProjectWizard : : initProjectWizardDialog ( BaseProjectWizardDialog * w ,
const QString & defaultPath ,
const WizardPageList & extensionPages ) const
{
2010-03-22 15:33:33 +01:00
const CustomWizardParametersPtr pa = parameters ( ) ;
QTC_ASSERT ( ! pa . isNull ( ) , return ) ;
const CustomWizardContextPtr ctx = context ( ) ;
ctx - > reset ( ) ;
2010-03-31 14:48:08 +02:00
if ( ! displayName ( ) . isEmpty ( ) )
w - > setWindowTitle ( displayName ( ) ) ;
2010-03-22 15:33:33 +01:00
if ( ! pa - > fields . isEmpty ( ) ) {
Internal : : CustomWizardFieldPage * cp = new Internal : : CustomWizardFieldPage ( ctx , pa - > fields ) ;
2010-03-12 11:20:32 +01:00
addWizardPage ( w , cp , parameters ( ) - > firstPageId ) ;
2010-03-22 15:33:33 +01:00
if ( ! pa - > fieldPageTitle . isEmpty ( ) )
cp - > setTitle ( pa - > fieldPageTitle ) ;
2010-03-12 11:20:32 +01:00
}
foreach ( QWizardPage * ep , extensionPages )
2010-03-31 14:48:08 +02:00
BaseFileWizard : : applyExtensionPageShortTitle ( w , w - > addPage ( ep ) ) ;
2010-03-12 11:20:32 +01:00
w - > setPath ( defaultPath ) ;
w - > setProjectName ( BaseProjectWizardDialog : : uniqueProjectName ( defaultPath ) ) ;
2010-03-22 15:33:33 +01:00
connect ( w , SIGNAL ( introPageLeft ( QString , QString ) ) , this , SLOT ( introPageLeft ( QString , QString ) ) ) ;
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-12 11:20:32 +01:00
qDebug ( ) < < " initProjectWizardDialog " < < w < < w - > pageIds ( ) ;
}
Core : : GeneratedFiles CustomProjectWizard : : generateFiles ( const QWizard * w , QString * errorMessage ) const
{
const BaseProjectWizardDialog * dialog = qobject_cast < const BaseProjectWizardDialog * > ( w ) ;
QTC_ASSERT ( dialog , return Core : : GeneratedFiles ( ) )
const QString targetPath = dialog - > path ( ) + QLatin1Char ( ' / ' ) + dialog - > projectName ( ) ;
// Add project name as macro.
2010-03-22 15:33:33 +01:00
FieldReplacementMap fieldReplacementMap = replacementMap ( dialog ) ;
2010-03-12 11:20:32 +01:00
fieldReplacementMap . insert ( QLatin1String ( " ProjectName " ) , dialog - > projectName ( ) ) ;
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-03-12 11:20:32 +01:00
qDebug ( ) < < " CustomProjectWizard::generateFiles " < < dialog < < targetPath < < fieldReplacementMap ;
return generateWizardFiles ( targetPath , fieldReplacementMap , errorMessage ) ;
}
2010-04-16 15:55:32 +02:00
bool CustomProjectWizard : : postGenerateOpen ( const Core : : GeneratedFiles & l , QString * errorMessage )
{
// Post-Generate: Open the project and the editors as desired
foreach ( const Core : : GeneratedFile & file , l ) {
if ( file . attributes ( ) & Core : : GeneratedFile : : OpenProjectAttribute ) {
if ( ! ProjectExplorer : : ProjectExplorerPlugin : : instance ( ) - > openProject ( file . path ( ) ) ) {
if ( errorMessage )
* errorMessage = tr ( " The project %1 could not be opened. " ) . arg ( file . path ( ) ) ;
return false ;
}
}
}
return BaseFileWizard : : postGenerateOpenEditors ( l , errorMessage ) ;
}
2010-03-12 11:20:32 +01:00
bool CustomProjectWizard : : postGenerateFiles ( const QWizard * , const Core : : GeneratedFiles & l , QString * errorMessage )
{
2010-03-17 15:17:03 +01:00
if ( CustomWizardPrivate : : verbose )
2010-04-16 15:55:32 +02:00
qDebug ( ) < < " CustomProjectWizard::postGenerateFiles() " ;
return CustomProjectWizard : : postGenerateOpen ( l , errorMessage ) ;
2010-03-12 11:20:32 +01:00
}
2010-03-22 15:33:33 +01:00
void CustomProjectWizard : : introPageLeft ( const QString & project , const QString & /* path */ )
{
// Make '%ProjectName%' available in base replacements.
context ( ) - > baseReplacements . insert ( QLatin1String ( " ProjectName " ) , project ) ;
}
2010-03-12 11:20:32 +01:00
} // namespace ProjectExplorer