/*************************************************************************** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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, TQT_SIGNAL( selected( const TQString & ) ), this, TQT_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, TQT_SLOT(addTemplateToFavourites())); m_favouritesMenu = new TDEPopupMenu(favourites_iconview); m_favouritesMenu->insertItem(i18n("&Remove Favorite"), this, TQT_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 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, TQT_TQOBJECT(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, TQT_SIGNAL(activated(int)), this, TQT_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::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 = "%1%2%3"; tempProjectDomSource = tempProjectDomSource.arg( author_edit->text() ).arg( email_edit->text() ).arg( version_edit->text() ); TQDomDocument tempProjectDom; tempProjectDom.setContent( tempProjectDomSource ); TQValueList::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::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::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::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::Iterator mapIt( m_pCurrentAppInfo->subMap.begin() ); for( ; mapIt != m_pCurrentAppInfo->subMap.end(); ++mapIt ) { TQString escaped( mapIt.data() ); escaped.replace( "&", "&" ); escaped.replace( "<", "<" ); escaped.replace( ">", ">" ); 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 #include #include 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 &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 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() + ".tdevelop" ); // 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::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 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 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 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 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 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 ait(m_appsInfo); for (; ait.current(); ++ait) { ait.current()->item->setVisible(m_profileSupport->isInTemplateList(ait.current()->templateName)); } TQDictIterator 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" // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;