/***************************************************************************
 *   Copyright (C) 2001-2002 by Bernd Gehrmann                             *
 *   bernd@kdevelop.org                                                    *
 *   Copyright (C) 2001 by Sandy Meier                                     *
 *   smeier@kdevelop.org                                                   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "appwizarddlg.h"

#include <tqvbox.h>
#include <tqbuttongroup.h>
#include <tqcombobox.h>
#include <tqtabwidget.h>
#include <tqwidgetstack.h>
#include <tqdir.h>
#include <tqfileinfo.h>
#include <tqgrid.h>
#include <tqheader.h>
#include <tqmap.h>
#include <tqmultilineedit.h>
#include <tqpushbutton.h>
#include <tqradiobutton.h>
#include <tqregexp.h>
#include <tqtextstream.h>
#include <tqtextview.h>
#include <tqtoolbutton.h>
#include <tqtooltip.h>
#include <tqvalidator.h>
#include <tqtimer.h>
#include <tdelistview.h>
#include <kiconview.h>
#include <tdeconfig.h>
#include <kdebug.h>
#include <tdeglobal.h>
#include <tdeglobalsettings.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kprocess.h>
#include <kstandarddirs.h>
#include <tdetempfile.h>
#include <kiconloader.h>
#include <tdefiledialog.h>
#include <tdefile.h>
#include <tdeapplication.h>
#include <tdepopupmenu.h>

#include <ktrader.h>
#include <tdeparts/componentfactory.h>
#include <tdeio/netaccess.h>
#include <tqfile.h>
#include <kmacroexpander.h>
#include <karchive.h>
#include <ktar.h>
#include <ktempdir.h>
#include <tdefileitem.h>
#include <tdeio/chmodjob.h>

#include <tqlayout.h>

#include "domutil.h"
#include "kdevversioncontrol.h"
#include "kdevmakefrontend.h"
#include "kdevpartcontroller.h"
#include "kdevplugincontroller.h"
#include "kdevappfrontend.h"
#include "kdevplugininfo.h"
#include "kdevlicense.h"
#include "kdevcore.h"
#include "appwizardfactory.h"
#include "appwizardpart.h"
#include "filepropspage.h"
#include "misc.h"
#include "profilesupport.h"
#include "filetemplate.h"
#include "settings.h"

#include "blockingkprocess.h"

#include "profileengine.h"
#include "profile.h"

#include "propeditor/property.h"
#include "propeditor/multiproperty.h"
#include "propeditor/propertylist.h"
#include "propeditor/propertyeditor.h"

AppWizardDialog::AppWizardDialog(AppWizardPart *part, TQWidget *parent, const char *name)
    : AppWizardDialogBase(parent, name,true), m_pCurrentAppInfo(0),
	m_profileSupport(new ProfileSupport(part))
{
	kdDebug( 9010 ) << "  ** AppWizardDialog::AppWizardDialog()" << endl;

	m_customOptions = 0L;
	loadLicenses();
    connect( this, TQ_SIGNAL( selected( const TQString & ) ), this, TQ_SLOT( pageChanged() ) );

	helpButton()->hide();
    templates_listview->header()->hide();
	templates_listview->setColumnWidthMode(0, TQListView::Maximum);	//to provide horiz scrollbar.

	m_templatesMenu = new TDEPopupMenu(templates_listview);
	m_templatesMenu->insertItem(i18n("&Add to Favorites"), this, TQ_SLOT(addTemplateToFavourites()));

	m_favouritesMenu = new TDEPopupMenu(favourites_iconview);
	m_favouritesMenu->insertItem(i18n("&Remove Favorite"), this, TQ_SLOT(removeFavourite()));

    m_pathIsValid=false;
    m_part = part;
    m_projectLocationWasChanged=false;
    m_appsInfo.setAutoDelete(true);
    m_tempFiles.setAutoDelete(true);

    TDEConfig *config = kapp->config();

	//config->setGroup("AppWizard");
	//templates_tabwidget->setCurrentPage(config->readNumEntry("CurrentTab", 0));

	config->setGroup("General Options");
    TQString defaultProjectsDir = config->readPathEntry("DefaultProjectsDir", TQDir::homeDirPath()+"/");

    TDEStandardDirs *dirs = AppWizardFactory::instance()->dirs();
    TQStringList m_templateNames = dirs->findAllResources("apptemplates", TQString(), false, true);

    kdDebug(9010) << "Templates: " << endl;
    TQStringList categories;

    TQStringList::Iterator it;
    for (it = m_templateNames.begin(); it != m_templateNames.end(); ++it) {
        kdDebug(9010) << (*it) << endl;

        ApplicationInfo *info = new ApplicationInfo;
		info->propValues = new PropertyLib::PropertyList();
		info->templateFile = TDEGlobal::dirs()->findResource("apptemplates", *it);
        info->templateName = (*it);

		TDEConfig templateConfig(info->templateFile);
        templateConfig.setGroup("General");

        info->name = templateConfig.readEntry("Name");
        info->icon = templateConfig.readEntry("Icon");
        info->comment = templateConfig.readEntry("Comment");
        info->fileTemplates = templateConfig.readEntry("FileTemplates");
        info->openFilesAfterGeneration = templateConfig.readListEntry("ShowFilesAfterGeneration");
        TQString destDir = templateConfig.readPathEntry("DefaultDestinatonDir", defaultProjectsDir);
        destDir.replace(TQRegExp("HOMEDIR"), TQDir::homeDirPath());
        info->defaultDestDir = destDir;
        TQString category = templateConfig.readEntry("Category");
        // format category to a unique status
        if (category.right(1) == "/")
            category.remove(category.length()-1, 1); // remove /
        if (category.left(1) != "/")
            category.prepend("/"); // prepend /
        categories.append(category);
        info->category = category;
		info->sourceArchive = templateConfig.readEntry("Archive");

		// Grab includes list
		TQStringList groups = templateConfig.groupList();
		groups.remove("General");
		TQStringList::Iterator group = groups.begin();
		for(  ; group != groups.end(); ++group)
		{
			templateConfig.setGroup( (*group) );
			TQString type = templateConfig.readEntry("Type").lower();
			if( type == "include" )  // Add value
			{
				info->includes.append( templateConfig.readEntry( "File" ) );
				kdDebug(9010) << "Adding: " << templateConfig.readEntry( "File" ) << endl;
			}
		}

		// Build builtins map to bootstrap.
		TQString source = kdevRoot( info->templateName );
		info->subMap.insert("tdevelop", source );

		// Add includes to the main template...
		TQStringList::Iterator include = info->includes.begin();
		for( ; include != info->includes.end(); ++include)
		{
			if( !(*include).isEmpty() )
			{
				TQString file = KMacroExpander::expandMacros( ( *include ), info->subMap);
				TDEConfig tmpCfg( file );
				tmpCfg.copyTo( "", &templateConfig);
				kdDebug(9010) << "Merging: " << tmpCfg.name() << endl;
			}
		}

		groups = templateConfig.groupList();  // Must get this again since its changed!
		group = groups.begin();
		for(  ; group != groups.end(); ++group)
		{
			templateConfig.setGroup( (*group) );
			TQString type = templateConfig.readEntry("Type", "value").lower();
			kdDebug(9010) << "Reading " <<  (*group) << " of type " << type << endl;
			if( type == "value" )  // Add value
			{
				TQString name = templateConfig.readEntry( "Value" );
				TQString label = templateConfig.readEntry( "Comment" );
				TQString type = templateConfig.readEntry( "ValueType", "String" );
				TQVariant::Type variantType = TQVariant::nameToType( type.latin1());
				TQVariant value = templateConfig.readPropertyEntry( "Default", variantType );
				value.cast( variantType );  // fix this in tdelibs...
				if( !name.isEmpty() && !label.isEmpty() )
					info->propValues->addProperty( new PropertyLib::Property( (int)variantType, name, label, value ) );

			}
			else if( type == "install" ) // copy dir
			{
				installFile file;
				file.source = templateConfig.readPathEntry("Source");
				file.dest = templateConfig.readPathEntry("Dest");
				file.process = templateConfig.readBoolEntry("Process",true);
				file.isXML = templateConfig.readBoolEntry("EscapeXML",false);
				file.option = templateConfig.readEntry("Option");
				info->fileList.append(file);
			}
			else if( type == "install archive" )
			{
				installArchive arch;
				arch.source = templateConfig.readPathEntry("Source");
				arch.dest = templateConfig.readPathEntry("Dest");
				arch.process = templateConfig.readBoolEntry("Process",true);
				arch.option = templateConfig.readEntry("Option", "" );
				info->archList.append(arch);
			}
			else if( type == "mkdir" )
			{
				installDir dir;
				dir.dir = templateConfig.readPathEntry("Dir");
				dir.option = templateConfig.readEntry("Option", "" );
				dir.perms = templateConfig.readNumEntry("Perms", 0777 );
				info->dirList.append(dir);
			}
			else if( type == "finishcmd" )
			{
                                info->finishCmd=templateConfig.readPathEntry("Command");
                                info->finishCmdDir=templateConfig.readPathEntry("Directory");
			}
			else if( type == "ui")
			{
				TQString name = templateConfig.readPathEntry("File");
				info->customUI = name;
			}
			else if( type == "message" )
			{
				info->message = templateConfig.readEntry( "Comment" );
			}
		}


        m_appsInfo.append(info);
    }

    // Insert categories into list view
    categories.sort();
    for (it = categories.begin(); it != categories.end(); ++it)
        insertCategoryIntoTreeView(*it);

    // Insert items into list view
    TQPtrListIterator<ApplicationInfo> ait(m_appsInfo);
    for (; ait.current(); ++ait) {
        TQListViewItem *item = m_categoryMap.find(ait.current()->category);
        if (item)
		{
            item = new TDEListViewItem(item, ait.current()->name);
			item->setPixmap(0, SmallIcon("tdevelop"));
		}
        else
            kdDebug(9010) << "Error can't find category in categoryMap: "
                          << ait.current()->category << endl;
        ait.current()->item = item;
    }

	//Load favourites from config
	populateFavourites();

	TQString author, email;
    AppWizardUtil::guessAuthorAndEmail(&author, &email);
    author_edit->setText(author);
    email_edit->setText(email);
    TQToolTip::add( dest_edit->button(), i18n("Choose projects directory") );
    dest_edit->setURL(defaultProjectsDir);
    dest_edit->setMode(KFile::Directory|KFile::ExistingOnly|KFile::LocalOnly);

    loadVcs();

    //    addPage(m_sdi_fileprops_page,"Class/File Properties");

    //    licenseChanged();

    setNextEnabled(generalPage, false);

//    TQRegExp appname_regexp ("[a-zA-Z][a-zA-Z0-9_]*"); //Non-Unicode version
    /* appname will start with a letter, and will contain letters,
       digits or underscores. */
    TQRegExp appname_regexp ("[a-zA-Z][a-zA-Z0-9_]*");
    // How about names like "__" or "123" for project name? Are they legal?
    TQRegExpValidator *appname_edit_validator;
    appname_edit_validator = new TQRegExpValidator (appname_regexp,
                                                   appname_edit,
                                                   "AppNameValidator");
    appname_edit->setValidator(appname_edit_validator);

    // insert the licenses into the license_combo
    TQDict< KDevLicense > lics( licenses() );
    TQDictIterator< KDevLicense > dit(lics);
    int idx=1;
    for( ; dit.current(); ++dit )
    {
        license_combo->insertItem( dit.currentKey(), idx++ );
        if( dit.currentKey() == "GPL" )
            license_combo->setCurrentItem( idx - 1 );
    }

	connect( license_combo, TQ_SIGNAL(activated(int)), this, TQ_SLOT(licenseChanged()) );

	m_custom_options_layout = new TQHBoxLayout( custom_options );
	m_custom_options_layout->setAutoAdd(true);

	showTemplates(false);
}

AppWizardDialog::~AppWizardDialog()
{}

void AppWizardDialog::loadVcs()
{
	m_vcsForm = new VcsForm();

	int i=0;
	m_vcsForm->combo->insertItem( i18n("no version control system", "None"), i );
	m_vcsForm->stack->addWidget( 0, i++ );

	// We query for all vcs integrators for KDevelop
	TDETrader::OfferList offers = TDETrader::self()->query("TDevelop/VCSIntegrator", "");
	TDETrader::OfferList::const_iterator serviceIt = offers.begin();
	for (; serviceIt != offers.end(); ++serviceIt)
	{
		KService::Ptr service = *serviceIt;
		kdDebug(9010) << "AppWizardDialog::loadVcs: creating vcs integrator "
			<< service->name() << endl;

		KLibFactory *factory = KLibLoader::self()->factory(TQFile::encodeName(service->library()));
		if (!factory) {
			TQString errorMessage = KLibLoader::self()->lastErrorMessage();
			kdDebug(9010) << "There was an error loading the module " << service->name() << endl <<
			"The diagnostics is:" << endl << errorMessage << endl;
			continue;
		}
		TQStringList args;
		TQObject *obj = factory->create(0, service->name().latin1(),
									"KDevVCSIntegrator", args);
		KDevVCSIntegrator *integrator = (KDevVCSIntegrator*) obj;

		if (!integrator)
			kdDebug(9010) << "    failed to create vcs integrator " << service->name() << endl;
		else
		{
			kdDebug(9010) << "    success" << endl;

			TQString vcsName = service->property("X-TDevelop-VCS").toString();
			m_vcsForm->combo->insertItem(vcsName, i);
			m_integrators.insert(vcsName, integrator);

			VCSDialog *vcs = integrator->integrator(m_vcsForm->stack);
			if (vcs)
			{
				m_integratorDialogs[i] = vcs;
				TQWidget *w = vcs->self();
				if (w)
					m_vcsForm->stack->addWidget(w, i++);
				else
					kdDebug(9010) << "    integrator widget is 0" << endl;
			}
			else
				kdDebug(9010) << "    integrator is 0" << endl;
		}
	}

	addPage(m_vcsForm, i18n("Version Control System"));
}

void AppWizardDialog::updateNextButtons()
{
	bool validGeneralPage = m_pCurrentAppInfo
							&& !appname_edit->text().isEmpty()
							&& m_pathIsValid;
	bool validPropsPage = !version_edit->text().isEmpty()
							&& !author_edit->text().isEmpty();

	setFinishEnabled(m_lastPage, validGeneralPage && validPropsPage);
	nextButton()->setEnabled(
		currentPage() == generalPage ? validGeneralPage : validPropsPage );
}

void AppWizardDialog::textChanged()
{
//    licenseChanged();

    updateNextButtons();
}

void AppWizardDialog::licenseChanged()
{
	TQValueList<AppWizardFileTemplate>::Iterator it;
	if( license_combo->currentItem() == 0 )
	{
		for (it = m_fileTemplates.begin(); it != m_fileTemplates.end(); ++it)
		{
			TQMultiLineEdit *edit = (*it).edit;
			edit->setText( TQString() );
		}
	} else {
		KDevLicense* lic = licenses()[ license_combo->currentText() ];
		for (it = m_fileTemplates.begin(); it != m_fileTemplates.end(); ++it) {
			TQString style = (*it).style;
			TQMultiLineEdit *edit = (*it).edit;

			KDevFile::CommentingStyle commentStyle = KDevFile::CPPStyle;
			if (style == "PStyle") {
				commentStyle = KDevFile::PascalStyle;
			} else if (style == "AdaStyle") {
				commentStyle = KDevFile::AdaStyle;
			} else if (style == "ShellStyle") {
				commentStyle = KDevFile::BashStyle;
			} else if (style == "XMLStyle") {
				commentStyle = KDevFile::XMLStyle;
			}

			TQString text;
			text = lic->assemble( commentStyle, author_edit->text(), email_edit->text() , 0 );
			edit->setText(text);
		}
	}
}

TQString AppWizardDialog::kdevRoot(const TQString &templateName ) const
{
	TQString source;
    TQFileInfo finfo(templateName);
    TQDir dir(finfo.dir());
    dir.cdUp();
    return dir.absPath();
}

void AppWizardDialog::accept()
{
    TQFileInfo fi(finalLoc_label->text());
    // check /again/ whether the dir already exists; maybe users create it in the meantime
    if (fi.exists() ) {
        KMessageBox::sorry(this, i18n("The directory you have chosen as the location for "
                                      "the project already exists."));
        showPage(generalPage);
        appname_edit->setFocus();
        projectLocationChanged();
        return;
    }

    if( !TQFileInfo(dest_edit->url()).isWritable()  ){
        KMessageBox::sorry(this, i18n("The directory you have chosen as the location for "
                                      "the project is not writeable."));
        showPage(generalPage);
        appname_edit->setFocus();
        projectLocationChanged();
        return;
    }

	TQString source = kdevRoot( m_pCurrentAppInfo->templateName );

	// Unpack template archive to temp dir, and get the name
	kdDebug(9010) << "Unpacking archive to temp dir" << endl;
	KTempDir archDir;
	archDir.setAutoDelete(true);
	KTar templateArchive( source + "/" + m_pCurrentAppInfo->sourceArchive, "application/x-gzip" );
	if( templateArchive.open( IO_ReadOnly ) )
	{
		//templateArchive.directory()->copyTo(archDir.name(), true);
		unpackArchive(templateArchive.directory(), archDir.name(), false);
	}
	else
	{
		KMessageBox::sorry(this, i18n("The template %1 cannot be opened.").arg( source + "/" + m_pCurrentAppInfo->sourceArchive ) );
		templateArchive.close();
		return;
	}
	templateArchive.close();

	kdDebug(9010) << "build macro map" << endl;
	// Build KMacroExpander map
	//m_customOptions->dataForm()->fillPropertyMap(&m_pCurrentAppInfo->subMap);
	PropertyLib::PropertyList::Iterator idx = m_pCurrentAppInfo->propValues->begin();
	for( ; idx != m_pCurrentAppInfo->propValues->end(); ++idx)
		m_pCurrentAppInfo->subMap.insert( idx.data()->name(), idx.data()->value().toString() );

	m_pCurrentAppInfo->subMap.insert("src", archDir.name() );
	m_pCurrentAppInfo->subMap.insert("dest", finalLoc_label->text() );
	m_pCurrentAppInfo->subMap.insert("APPNAME", appname_edit->text() );
	m_pCurrentAppInfo->subMap.insert("APPNAMELC", appname_edit->text().lower() );
	m_pCurrentAppInfo->subMap.insert("APPNAMESC", TQString(appname_edit->text()[0]).upper() + appname_edit->text().mid(1));
	m_pCurrentAppInfo->subMap.insert("APPNAMEUC", appname_edit->text().upper() );
	m_pCurrentAppInfo->subMap.insert("AUTHOR", author_edit->text() );
	m_pCurrentAppInfo->subMap.insert("EMAIL", email_edit->text() );
	m_pCurrentAppInfo->subMap.insert("VERSION", version_edit->text());
	m_pCurrentAppInfo->subMap.insert( "I18N", "i18n" );
	m_pCurrentAppInfo->subMap.insert("YEAR", TQString::number( TQDate::currentDate().year() ) );

	// This isn't too pretty, but we have several templates that use TDEAboutData::License_${LICENSE}
	// and unsurprisingly, TDEAboutData doesn't cover every imaginable case.
	// These are the licenses known to KDE-3.2 TDEAboutData, KDevelop doesn't have all of these as prepared options today
	TQString license = license_combo->currentText();
	if ( license == "GPL" || license == "GPL_V2" || license == "LGPL" || license == "LGPL_V2"||
		license == "BSD" || license == "NCSA" || license == "MIT" || license == "Artistic" || 
		license == "QPL" || license == "TQPL_V1_0" )
	{
		m_pCurrentAppInfo->subMap.insert("LICENSE", license );
	}
	else
	{
		m_pCurrentAppInfo->subMap.insert("LICENSE", "Custom" );
	}


	TQStringList cleanUpSubstMap;
	cleanUpSubstMap << "src" << "I18N" << "tdevelop";


	kdDebug(9010) << "add template files" << endl;
	// Add template files to the fileList
	installDir templateDir;
	templateDir.dir = "%{dest}/templates";
	m_pCurrentAppInfo->dirList.prepend(templateDir);

	installDir baseDir;
	baseDir.dir = "%{dest}";
	m_pCurrentAppInfo->dirList.prepend( baseDir );

	// This is too silly for words, but it's either this or reimplementing FileTemplate
	TQString tempProjectDomSource = "<!DOCTYPE kdevelop><kdevelop><general><author>%1</author><email>%2</email><version>%3</version></general></kdevelop>";
	tempProjectDomSource = tempProjectDomSource.arg( author_edit->text() ).arg( email_edit->text() ).arg( version_edit->text() );
	TQDomDocument tempProjectDom;
	tempProjectDom.setContent( tempProjectDomSource );

    TQValueList<AppWizardFileTemplate>::Iterator it;
    for (it = m_fileTemplates.begin(); it != m_fileTemplates.end(); ++it) {
        KTempFile *tempFile = new KTempFile();
        m_tempFiles.append(tempFile);

		TQString templateText( FileTemplate::makeSubstitutions( tempProjectDom, (*it).edit->text() ) );
		TQFile f;
		f.open(IO_WriteOnly, tempFile->handle());
		TQTextStream temps(&f);
		temps.setEncoding(TQTextStream::UnicodeUTF8);
		temps << templateText;
		f.flush();
		TQString templateName( TQString( "%1_TEMPLATE" ).arg( (*it).suffix ).upper() );
		cleanUpSubstMap << templateName;
		m_pCurrentAppInfo->subMap.insert( templateName, KMacroExpander::expandMacros(templateText , m_pCurrentAppInfo->subMap)  );

		installFile file;
		file.source = tempFile->name();
		file.dest = TQString( "%{dest}/templates/%1" ).arg( (*it).suffix );
		file.process = true;
		file.isXML = false;
		m_pCurrentAppInfo->fileList.append( file );
    }

	// Add license file to the file list
	TQString licenseFile, licenseName = i18n("Custom");

    if( license_combo->currentItem() != 0 )
    {
        licenseName = license_combo->currentText();
        KDevLicense* lic = licenses()[ licenseName ];
        if( lic )
        {
            TQStringList files( lic->copyFiles() );
			TQStringList::Iterator it = files.begin();
			for( ; it != files.end(); ++it )
			{
				installFile file;
				file.source = TQString( "%{tdevelop}/template-common/%1" ).arg( *it );
				file.dest = TQString("%{dest}/%1").arg( *it );
				file.process = true;
				file.isXML = false;
				m_pCurrentAppInfo->fileList.append( file );
			}

			m_pCurrentAppInfo->subMap.insert("LICENSEFILE", files.first()  );
        }
    }

	// Run macro expander on both the dir map and file maps
	TQValueList<installFile>::Iterator fileIt = m_pCurrentAppInfo->fileList.begin();
	for( ; fileIt != m_pCurrentAppInfo->fileList.end(); ++fileIt)
	{
		(*fileIt).source = KMacroExpander::expandMacros((*fileIt).source , m_pCurrentAppInfo->subMap);
		kdDebug(9010) << "Updating file dest: " << (*fileIt).dest << " with " << KMacroExpander::expandMacros((*fileIt).dest , m_pCurrentAppInfo->subMap) << endl;
		(*fileIt).dest = KMacroExpander::expandMacros((*fileIt).dest , m_pCurrentAppInfo->subMap);
	}

	TQValueList<installArchive>::Iterator archIt = m_pCurrentAppInfo->archList.begin();
	for( ; archIt != m_pCurrentAppInfo->archList.end(); ++archIt)
	{
		(*archIt).source = KMacroExpander::expandMacros((*archIt).source , m_pCurrentAppInfo->subMap);
		(*archIt).dest = KMacroExpander::expandMacros((*archIt).dest , m_pCurrentAppInfo->subMap);
	}

	TQValueList<installDir>::Iterator dirIt = m_pCurrentAppInfo->dirList.begin();
	for( ; dirIt != m_pCurrentAppInfo->dirList.end(); ++dirIt)
	{
		(*dirIt).dir = KMacroExpander::expandMacros((*dirIt).dir , m_pCurrentAppInfo->subMap);
	}

    if( !m_pCurrentAppInfo->finishCmd.isEmpty() )
    {
        m_pCurrentAppInfo->finishCmd = KMacroExpander::expandMacros(
                m_pCurrentAppInfo->finishCmd, m_pCurrentAppInfo->subMap );
        m_pCurrentAppInfo->finishCmdDir = KMacroExpander::expandMacros(
                m_pCurrentAppInfo->finishCmdDir, m_pCurrentAppInfo->subMap );
    }

	TQMap<TQString,TQString>::Iterator mapIt( m_pCurrentAppInfo->subMap.begin() );
	for( ; mapIt != m_pCurrentAppInfo->subMap.end(); ++mapIt )
	{
		TQString escaped( mapIt.data() );
		escaped.replace( "&", "&amp;" );
		escaped.replace( "<", "&lt;" );
		escaped.replace( ">", "&gt;" );
		m_pCurrentAppInfo->subMapXML.insert( mapIt.key(), escaped );
	}

	// Create dirs
	dirIt = m_pCurrentAppInfo->dirList.begin();
	for( ; dirIt != m_pCurrentAppInfo->dirList.end(); ++dirIt)
	{
		kdDebug( 9010 ) << "Process dir " << (*dirIt).dir  << endl;
		if( m_pCurrentAppInfo->subMap[(*dirIt).option] != "false" )
		{
			if( ! TDEIO::NetAccess::mkdir( (*dirIt).dir, this ) )
			{
				KMessageBox::sorry(this, i18n("The directory %1 cannot be created.").arg( (*dirIt).dir ) );
				return;
			}
		}
	}
	// Unpack archives
	archIt = m_pCurrentAppInfo->archList.begin();
	for( ; archIt != m_pCurrentAppInfo->archList.end(); ++archIt)
	{
		if( m_pCurrentAppInfo->subMap[(*archIt).option] != "false" )
		{
			kdDebug( 9010 ) << "unpacking archive " << (*archIt).source << endl;
			KTar archive( (*archIt).source, "application/x-gzip" );
			if( archive.open( IO_ReadOnly ) )
			{
				unpackArchive( archive.directory(), (*archIt).dest, (*archIt).process );
			}
			else
			{
				KMessageBox::sorry(this, i18n("The archive %1 cannot be opened.").arg( (*archIt).source ) );
				archive.close();
				return;
			}
			archive.close();
		}

	}

	// Copy files & Process
	fileIt = m_pCurrentAppInfo->fileList.begin();
	for( ; fileIt != m_pCurrentAppInfo->fileList.end(); ++fileIt)
	{
		kdDebug( 9010 ) << "Process file " << (*fileIt).source << endl;
		if( m_pCurrentAppInfo->subMap[(*fileIt).option] != "false" )
		{
			if( !copyFile( *fileIt ) )
			{
				KMessageBox::sorry(this, i18n("The file %1 cannot be created.").arg( (*fileIt).dest) );
				return;
			}
			setPermissions(*fileIt);
		}
	}
    // if dir still does not exist
    if (!fi.dir().exists()) {
      KMessageBox::sorry(this, i18n("The directory above the chosen location does not exist and cannot be created."));
      showPage(generalPage);
      dest_edit->setFocus();
      return;
    }

//	KMessageBox::information(this, KMacroExpander::expandMacros(m_pCurrentAppInfo->message, m_pCurrentAppInfo->subMap));

	TQStringList::Iterator cleanIt = cleanUpSubstMap.begin();
	for(;cleanIt != cleanUpSubstMap.end(); ++cleanIt )
	{
		m_pCurrentAppInfo->subMap.remove( *cleanIt );
	}

      if  (!m_pCurrentAppInfo->finishCmd.isEmpty())
      {
        BlockingTDEProcess proc;
        proc.setWorkingDirectory( m_pCurrentAppInfo->finishCmdDir );
        proc.setUseShell( true );
        proc << "cd" << m_pCurrentAppInfo->finishCmdDir << "&&";
        proc << m_pCurrentAppInfo->finishCmd;
        kdDebug(9010) << "Executing:" << proc.args() << endl;
        proc.start( TDEProcess::NotifyOnExit );
        if( !proc.isRunning() && !proc.normalExit() )
        {
            kdDebug(9010) << "Couldn't execute: " << proc.args() << endl;
        }
      }



	int id = m_vcsForm->stack->id(m_vcsForm->stack->visibleWidget());
	if (id)
	{
		VCSDialog *vcs = m_integratorDialogs[id];
		if (vcs)
		{
			kdDebug(9010) << "vcs integrator dialog is ready" << endl;
			vcs->accept();
		}
		else
			kdDebug(9010) << "no vcs integrator dialog" << endl;
	}
	else
		kdDebug(9010) << "vcs integrator wasn't selected" << endl;

	openAfterGeneration();
	TQWizard::accept();
}

bool AppWizardDialog::copyFile( const installFile& file )
{
	kdDebug(9010) << "Copying file" << file.dest << endl;
	return
		copyFile( file.source, file.dest, file.isXML, file.process );
}

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

bool AppWizardDialog::copyFile( const TQString &source, const TQString &dest, bool isXML, bool process )
{
	kdDebug( 9010 ) << "Copy: " << source << " to " << dest << endl;
	if( process )
	{
		// Process the file and save it at the destFile location
		TQFile inputFile( source);
		TQFile outputFile( dest );

		const TQMap<TQString,TQString> &subMap = isXML ?
			m_pCurrentAppInfo->subMapXML : m_pCurrentAppInfo->subMap;
		if( inputFile.open( IO_ReadOnly ) && outputFile.open(IO_WriteOnly) )
		{
			TQTextStream input( &inputFile );
			input.setEncoding(TQTextStream::UnicodeUTF8);
			TQTextStream output( &outputFile );
			output.setEncoding(TQTextStream::UnicodeUTF8);
			while( !input.atEnd() )
				output << KMacroExpander::expandMacros(input.readLine(), subMap) << "\n";
			// Preserve file mode...
			struct stat fmode;
			::fstat( inputFile.handle(), &fmode);
			::fchmod( outputFile.handle(), fmode.st_mode );

		}
		else
		{
			inputFile.close();
			outputFile.close();
			return false;
		}
	}
	else
	{
		// Copy the source file to the destFile.
		return TDEIO::NetAccess::copy( source, dest, this );
	}
	return true;
}

void AppWizardDialog::unpackArchive( const KArchiveDirectory *dir, const TQString &dest, bool process )
{
	TDEIO::NetAccess::mkdir( dest , this );
	kdDebug(9010) << "Dir : " << dir->name() << " at " << dest << endl;
	TQStringList entries = dir->entries();
	kdDebug(9010) << "Entries : " << entries.join(",") << endl;

	KTempDir tdir;

	TQStringList::Iterator entry = entries.begin();
	for( ; entry != entries.end(); ++entry )
	{

		if( dir->entry( (*entry) )->isDirectory()  )
		{
			const KArchiveDirectory *file = (KArchiveDirectory *)dir->entry( (*entry) );
			unpackArchive( file , dest + "/" + file->name(), process);
		}
		else if( dir->entry( (*entry) )->isFile()  )
		{
			const KArchiveFile *file = (KArchiveFile *) dir->entry( (*entry) );
			if( !process )
			{
				file->copyTo( dest );
				setPermissions(file, dest + "/" + file->name());
			}
			else
			{
				file->copyTo(tdir.name());
				// assume that an archive does not contain XML files
				// ( where should we currently get that info from? )
				if ( !copyFile( TQDir::cleanDirPath(tdir.name()+"/"+file->name()), dest + "/" + file->name(), false, process ) )
				{
					KMessageBox::sorry(this, i18n("The file %1 cannot be created.").arg( dest) );
					return;
				}
				setPermissions(file, dest + "/" + file->name());
			}
		}
	}
	tdir.unlink();
}

void AppWizardDialog::templatesTreeViewClicked(TQListViewItem *item)
{
	if( m_customOptions )
		delete m_customOptions;

    // Delete old file template pages
    while (!m_fileTemplates.isEmpty()) {
        TQMultiLineEdit *edit = m_fileTemplates.first().edit;
        removePage(edit);
        delete edit;
        m_fileTemplates.remove(m_fileTemplates.begin());
    }
    m_lastPage = 0;

    ApplicationInfo *info = templateForItem(item);
    if (info) {
        m_pCurrentAppInfo = info;
        if (!info->icon.isEmpty()) {
            TQFileInfo fi(info->templateName);
            TQDir dir(fi.dir());
            dir.cdUp();
            TQPixmap pm;
            pm.load(dir.filePath(info->icon));
            icon_label->setPixmap(pm);
        } else {
            icon_label->clear();
        }
        desc_textview->setText(info->comment);
//        dest_edit->setURL(info->defaultDestDir);
        m_projectLocationWasChanged = false;
        //projectNameChanged(); // set the dest new

		// Populate new custom options form
		m_customOptions = new PropertyLib::PropertyEditor( custom_options );
		m_customOptions->populateProperties(info->propValues);


        // Create new file template pages
        TQStringList l = TQStringList::split(",", info->fileTemplates);
        if (l.empty()) //if the app template doesn't show file templates, we need to set another m_lastPage, aleXXX
           m_lastPage=m_vcsForm;

        TQStringList::ConstIterator it = l.begin();
        while (it != l.end()) {
            AppWizardFileTemplate fileTemplate;
            fileTemplate.suffix = *it;
            ++it;
            if (it != l.end()) {
                fileTemplate.style = *it;
                ++it;
            } else
                fileTemplate.style = "";

            TQMultiLineEdit *edit = new TQMultiLineEdit(this);
            edit->setWordWrap(TQTextEdit::NoWrap);
            edit->setFont(TDEGlobalSettings::fixedFont());
            if (it == l.end())
                m_lastPage = edit;
            fileTemplate.edit = edit;
            addPage(edit, i18n("Template for .%1 Files").arg(fileTemplate.suffix));
            m_fileTemplates.append(fileTemplate);
        }
        licenseChanged();	// to populate the template views
        textChanged(); // update Next button state
    } else {
	m_customOptions=0;
        m_pCurrentAppInfo=0;
        icon_label->clear();
        desc_textview->clear();
        nextButton()->setEnabled(false);
    }
}


void AppWizardDialog::destButtonClicked(const TQString& dir)
{
    if(!dir.isEmpty()) {

        // set new location as default project dir?
        TDEConfig *config = kapp->config();
        config->setGroup("General Options");
        TQDir defPrjDir( config->readPathEntry("DefaultProjectsDir", TQDir::homeDirPath()) );
        TQDir newDir (dir);
        kdDebug(9010) << "DevPrjDir == newdir?: " << defPrjDir.absPath() << " == " << newDir.absPath() << endl;
        if (defPrjDir != newDir) {
            if (KMessageBox::questionYesNo(this, i18n("Set default project location to: %1?").arg( newDir.absPath() ),
                                           i18n("New Project"), i18n("Set"), i18n("Do Not Set")) == KMessageBox::Yes)
            {
                config->writePathEntry("DefaultProjectsDir", newDir.absPath() + "/");
                config->sync();
            }
        }
    }
}


void AppWizardDialog::projectNameChanged()
{
    // Location was already edited by hand => don't change
}


void AppWizardDialog::projectLocationChanged()
{
  // Jakob Simon-Gaarde: Got tired of the anoying bug with the appname/location confussion.
  // This version insures WYSIWYG and checks pathvalidity
  finalLoc_label->setText(dest_edit->url() + (dest_edit->url().right(1)=="/" ? "":"/") + appname_edit->text());
  TQDir qd(dest_edit->url());
  TQFileInfo fi(dest_edit->url() + "/" + appname_edit->text());
  if (!qd.exists() || appname_edit->displayText().isEmpty()||fi.exists())
  {
    if (!fi.exists() || appname_edit->displayText().isEmpty()) {
      finalLoc_label->setText(finalLoc_label->text() + i18n("invalid location", " (invalid)"));
    } else {
      finalLoc_label->setText(finalLoc_label->text() + i18n(" (dir/file already exists)"));
    }
    m_pathIsValid=false;
  } else {
    m_pathIsValid=true;
  }
  updateNextButtons();
}


void AppWizardDialog::insertCategoryIntoTreeView(const TQString &completeCategoryPath)
{
    kdDebug(9010) << "TemplateCategory: " << completeCategoryPath << endl;
    TQStringList categories = TQStringList::split("/", completeCategoryPath);
    TQString category ="";
    TQListViewItem* pParentItem=0;

    TQStringList::ConstIterator it;
    for (it = categories.begin(); it != categories.end(); ++it) {
        category = category + "/" + *it;
        TQListViewItem *item = m_categoryMap.find(category);
        if (!item) { // not found, create it
            if (!pParentItem)
                pParentItem = new TDEListViewItem(templates_listview,*it);
            else
                pParentItem = new TDEListViewItem(pParentItem,*it);

            pParentItem->setPixmap(0, SmallIcon("folder"));
            //pParentItem->setOpen(true);
            kdDebug(9010) << "Category: " << category << endl;
            m_categoryMap.insert(category,pParentItem);
            m_categoryItems.append(pParentItem);
        } else {
            pParentItem = item;
        }
    }
}


ApplicationInfo *AppWizardDialog::templateForItem(TQListViewItem *item)
{
    TQPtrListIterator<ApplicationInfo> it(m_appsInfo);
    for (; it.current(); ++it)
        if (it.current()->item == item)
            return it.current();

    return 0;
}

void AppWizardDialog::openAfterGeneration()
{
	TQString projectFile( finalLoc_label->text() + "/" + appname_edit->text().lower() + ".kdevelop" );

	// Read the DOM of the newly created project
	TQFile file( projectFile );
	if( !file.open( IO_ReadOnly ) )
		return;
	TQDomDocument projectDOM;

	int errorLine, errorCol;
	TQString errorMsg;
	bool success = projectDOM.setContent( &file, &errorMsg, &errorLine, &errorCol);
	file.close();
	if ( !success )
	{
		KMessageBox::sorry( 0, i18n("This is not a valid project file.\n"
				"XML error in line %1, column %2:\n%3")
				.arg(errorLine).arg(errorCol).arg(errorMsg));
		return;
	}

	// DOM Modifications go here
	DomUtil::writeMapEntry( projectDOM, "substmap", m_pCurrentAppInfo->subMap );

	//save the selected vcs
	TDETrader::OfferList offers = TDETrader::self()->query("TDevelop/VCSIntegrator", TQString("[X-TDevelop-VCS]=='%1'").arg(m_vcsForm->combo->currentText()));
	if (offers.count() == 1)
	{
		KService::Ptr service = offers.first();
		DomUtil::writeEntry(projectDOM, "/general/versioncontrol", service->property("X-TDevelop-VCSPlugin").toString());
	}

	// figure out what plugins we should disable by default
	TQString profileName = DomUtil::readEntry( projectDOM, "general/profile" );
	if ( profileName.isEmpty() )
	{
		TQString language = DomUtil::readEntry( projectDOM, "general/primarylanguage" );
		TQStringList keywords = DomUtil::readListEntry( projectDOM, "general/keywords", "keyword" );

		profileName = Settings::profileByAttributes( language, keywords );
	}

	ProfileEngine & engine = m_part->pluginController()->engine();
	Profile * profile = engine.findProfile( profileName );

	TQStringList disableList;
	Profile::EntryList disableEntryList = profile->list( Profile::ExplicitDisable );
	for ( Profile::EntryList::const_iterator it = disableEntryList.constBegin(); it != disableEntryList.constEnd(); ++it )
	{
		disableList << (*it).name;
	}

	TQStringList projectIgnoreparts = DomUtil::readListEntry( projectDOM, "/general/ignoreparts", "part" );
	projectIgnoreparts += disableList;
	DomUtil::writeListEntry( projectDOM, "/general/ignoreparts", "part", projectIgnoreparts );

	DomUtil::writeEntry( projectDOM, "/general/projectname", appname_edit->text() );

	// write the dom back
	if( !file.open( IO_WriteOnly ) )
		return;
	TQTextStream ts( &file );
	ts.setEncoding(TQTextStream::UnicodeUTF8);
	ts << projectDOM.toString(2);
	file.close();

	// open the new project
	m_part->core()->openProject( projectFile );

	// calculate the list of files to open after generation and use
	// timer to queue opening (so that files will not be opened before the project
	// which is also queued by ProjectManager )
	KURL::List urlsToOpen;
	TQStringList::Iterator it = m_pCurrentAppInfo->openFilesAfterGeneration.begin();
	for( ; it != m_pCurrentAppInfo->openFilesAfterGeneration.end(); ++it )
	{
		TQString fileName( *it );
		if ( !fileName.isNull() )
		{
			fileName = KMacroExpander::expandMacros(fileName, m_pCurrentAppInfo->subMap);
			urlsToOpen.append(KURL::fromPathOrURL(fileName));
		}
	}
	m_part->openFilesAfterGeneration(urlsToOpen);
}

void AppWizardDialog::pageChanged()
{
	kdDebug(9010) << "AppWizardDialog::pageChanged()" << endl;
	projectLocationChanged();
	if (currentPage() == m_lastPage)
		finishButton()->setDefault(true);


	//it is possible that project name was changed - we need to update all vcs integrator dialogs
	for (TQMap<int, VCSDialog*>::iterator it = m_integratorDialogs.begin();
		it != m_integratorDialogs.end(); ++it)
		(*it)->init(getProjectName(), getProjectLocation());
}

void AppWizardDialog::addTemplateToFavourites()
{
	addFavourite(templates_listview->currentItem());
}

void AppWizardDialog::addFavourite(TQListViewItem* item, TQString favouriteName)
{
	if(item->childCount())
		return;

	ApplicationInfo* info = templateForItem(item);

	if(!info->favourite)
	{
		info->favourite = new TDEIconViewItem(favourites_iconview,
											((favouriteName=="")?info->name:favouriteName),
											DesktopIcon("tdevelop"));

		info->favourite->setRenameEnabled(true);
	}
}

ApplicationInfo* AppWizardDialog::findFavouriteInfo(TQIconViewItem* item)
{
    TQPtrListIterator<ApplicationInfo> info(m_appsInfo);
    for (; info.current(); ++info)
        if (info.current()->favourite == item)
            return info.current();

	return 0;
}

void AppWizardDialog::favouritesIconViewClicked( TQIconViewItem* item)
{
	ApplicationInfo* info = findFavouriteInfo(item);
	templatesTreeViewClicked(info->item);
}

void AppWizardDialog::removeFavourite()
{
	TQIconViewItem* curFavourite = favourites_iconview->currentItem();

	//remove reference to favourite from associated appinfo
	TQPtrListIterator<ApplicationInfo> info(m_appsInfo);
	for (; info.current(); ++info)
	{
        if(info.current()->favourite && info.current()->favourite == curFavourite)
		{
			info.current()->favourite = 0;
		}
	}

	//remove favourite from iconview
	delete curFavourite;
	curFavourite=0;
	favourites_iconview->sort();	//re-arrange all items.
}

void AppWizardDialog::populateFavourites()
{
	TDEConfig* config = kapp->config();
	config->setGroup("AppWizard");

	//favourites are stored in config as a list of templates and a seperate
	//list of icon names.
	TQStringList templatesList = config->readPathListEntry("FavTemplates");
	TQStringList iconNamesList = config->readListEntry("FavNames");

	TQStringList::Iterator curTemplate = templatesList.begin();
	TQStringList::Iterator curIconName = iconNamesList.begin();
	while(curTemplate != templatesList.end())
	{
		TQPtrListIterator<ApplicationInfo> info(m_appsInfo);
		for (; info.current(); ++info)
		{
			if(info.current()->templateName == *curTemplate)
			{
				addFavourite(info.current()->item, *curIconName);
				break;
			}
		}
		curTemplate++;
		curIconName++;
	}
}

void AppWizardDialog::done(int r)
{
	//need to save the template for each favourite and
	//it's icon name.  We have a one list for the templates
	//and one for the names.

	TQStringList templatesList;
	TQStringList iconNamesList;

	//Built the stringlists for each template that has a favourite.
	TQPtrListIterator<ApplicationInfo> it(m_appsInfo);
	for (; it.current(); ++it)
	{
        if(it.current()->favourite)
		{
			templatesList.append(it.current()->templateName);
			iconNamesList.append(it.current()->favourite->text());
		}
	}

	TDEConfig* config = kapp->config();
	config->setGroup("AppWizard");
	config->writePathEntry("FavTemplates", templatesList);
	config->writeEntry("FavNames", iconNamesList);
	//config->writeEntry("CurrentTab", templates_tabwidget->currentPageIndex());
	config->sync();

	TQDialog::done(r);
}

void AppWizardDialog::templatesContextMenu(TQListViewItem* item, const TQPoint& point, int)
{
	if(item && !item->childCount())
		m_templatesMenu->popup(point);
}

void AppWizardDialog::favouritesContextMenu(TQIconViewItem* item, const TQPoint& point)
{
	if(item)
		m_favouritesMenu->popup(point);
}

void AppWizardDialog::setPermissions(const KArchiveFile *source, TQString dest)
{
	kdDebug(9010) << "AppWizardDialog::setPermissions(const KArchiveFile *source, TQString dest)" << endl;
	kdDebug(9010) << "	dest: " << dest << endl;

	if (source->permissions() & 00100)
	{
		kdDebug(9010) << "source is executable" << endl;
		TDEIO::UDSEntry entry;
		KURL kurl = KURL::fromPathOrURL(dest);
		if (TDEIO::NetAccess::stat(kurl, entry, 0))
		{
			KFileItem it(entry, kurl);
			int mode = it.permissions();
			kdDebug(9010) << "stat shows permissions: " << mode << endl;
			TDEIO::chmod(KURL::fromPathOrURL(dest), mode | 00100 );
		}
	}
}

void AppWizardDialog::setPermissions(const installFile &file)
{
	kdDebug(9010) << "AppWizardDialog::setPermissions(const installFile &file)" << endl;
	kdDebug(9010) << "	dest: " << file.dest << endl;

	TDEIO::UDSEntry sourceentry;
	KURL sourceurl = KURL::fromPathOrURL(file.source);
	if (TDEIO::NetAccess::stat(sourceurl, sourceentry, 0))
	{
		KFileItem sourceit(sourceentry, sourceurl);
		int sourcemode = sourceit.permissions();
		if (sourcemode & 00100)
		{
			kdDebug(9010) << "source is executable" << endl;
			TDEIO::UDSEntry entry;
			KURL kurl = KURL::fromPathOrURL(file.dest);
			if (TDEIO::NetAccess::stat(kurl, entry, 0))
			{
				KFileItem it(entry, kurl);
				int mode = it.permissions();
				kdDebug(9010) << "stat shows permissions: " << mode << endl;
				TDEIO::chmod(KURL::fromPathOrURL(file.dest), mode | 00100 );
			}
		}
	}
}

TQDict<KDevLicense> AppWizardDialog::licenses()
{
	return m_licenses;
}

void AppWizardDialog::loadLicenses()
{
	// kdDebug(9010) << "======================== Entering loadLicenses" << endl;
	TDEStandardDirs* dirs = TDEGlobal::dirs();
	dirs->addResourceType( "licenses", TDEStandardDirs::kde_default( "data" ) + "tdevelop/licenses/" );
	TQStringList licNames = dirs->findAllResources( "licenses", TQString(), false, true );

	TQStringList::Iterator it;
	for (it = licNames.begin(); it != licNames.end(); ++it)
	{
		TQString licPath( dirs->findResource( "licenses", *it ) );
		kdDebug(9010) << "Loading license file: " << licPath << endl;
		TQString licName = licPath.mid( licPath.findRev('/') + 1 );
		KDevLicense* lic = new KDevLicense( licName, licPath );
		m_licenses.insert( licName, lic );
	}
	// kdDebug(9010) << "======================== Done loadLicenses" << endl;
}

void AppWizardDialog::showTemplates(bool all)
{
	if (all)
	{
		TQListViewItemIterator it(templates_listview);
		while ( it.current() ) {
			it.current()->setVisible(true);
			++it;
		}
	}
	else
	{
		TQPtrListIterator<ApplicationInfo> ait(m_appsInfo);
		for (; ait.current(); ++ait)
		{
			ait.current()->item->setVisible(m_profileSupport->isInTemplateList(ait.current()->templateName));
		}

		TQDictIterator<TQListViewItem> dit(m_categoryMap);
		for (; dit.current(); ++dit)
		{
			//checking whether all children are not visible
			kdDebug(9010) << "check: " << dit.current()->text(0) << endl;
			bool visible = false;
			TQListViewItemIterator it(dit.current());
			while ( it.current() ) {
				if ((it.current()->childCount() == 0) && it.current()->isVisible())
				{
					kdDebug(9010) << "	visible: " << it.current()->text(0) << endl;
					visible = true;
					break;
				}
				++it;
			}
			dit.current()->setVisible(visible);
		}
		checkAndHideItems(templates_listview);
	}
}

void AppWizardDialog::checkAndHideItems(TQListView *view)
{
	TQListViewItem *item = view->firstChild();
	while (item)
	{
		if (!m_categoryItems.contains(item))
			continue;
		checkAndHideItems(item);
		item = item->nextSibling();
	}
}

bool AppWizardDialog::checkAndHideItems(TQListViewItem *item)
{
	if (!m_categoryItems.contains(item))
		return !item->isVisible();
	TQListViewItem *child = item->firstChild();
	bool hide = true;
	while (child)
	{
		hide = hide && checkAndHideItems(child);
		child = child->nextSibling();
	}
	kdDebug(9010) << "check_: " << item->text(0) << " hide: " <<  hide << endl;
	if (hide)
	{
		item->setVisible(false);
		return true;
	}
	return false;
}

#include "appwizarddlg.moc"
