/*************************************************************************** * Copyright (C) 2001-2002 by Bernd Gehrmann * * bernd@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 "importdlg.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 "kdevcore.h" #include "kdevversioncontrol.h" #include "kdevplugincontroller.h" #include "domutil.h" #include "settings.h" #include "profile.h" #include "profileengine.h" #include "appwizardfactory.h" #include "appwizardpart.h" #include "misc.h" ImportDialog::ImportDialog(AppWizardPart *part, TQWidget *parent, const char *name) : ImportDialogBase(parent, name, true), m_part(part) { TQString author, email; AppWizardUtil::guessAuthorAndEmail(&author, &email); author_edit->setText(author); email_edit->setText(email); TQToolTip::add( urlinput_edit->button(), i18n("Choose directory to import") ); urlinput_edit->setMode(KFile::Directory|KFile::ExistingOnly|KFile::LocalOnly); TDEStandardDirs *dirs = AppWizardFactory::instance()->dirs(); importNames = dirs->findAllResources("appimports", TQString(), false, true); importNames.sort(); TQStringList::ConstIterator it; for (it = importNames.begin(); it != importNames.end(); ++it) { TDEConfig config(TDEGlobal::dirs()->findResource("appimports", *it)); config.setGroup("General"); TQString type = config.readEntry("Comment"); project_combo->insertItem(type); if (config.hasGroup("Infrastructure")) { config.setGroup("Infrastructure"); m_infrastructure[type].isOn = true; m_infrastructure[type].comment = config.readEntry("Comment"); m_infrastructure[type].command = config.readEntry("Command"); m_infrastructure[type].existingPattern = config.readEntry("ExistingProjectPattern"); } else m_infrastructure[type].isOn = false; } infrastructureBox->setEnabled(false); setProjectType("c"); connect( name_edit, TQT_SIGNAL( textChanged ( const TQString & ) ), this, TQT_SLOT( slotProjectNameChanged( const TQString & ) ) ); // scanAvailableVCS(); connect( fetchModuleButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotFetchModulesFromRepository()) ); connect(urlinput_edit, TQT_SIGNAL(urlSelected(const TQString& )), this, TQT_SLOT(dirChanged())); connect(urlinput_edit, TQT_SIGNAL(returnPressed(const TQString& )), this, TQT_SLOT(dirChanged())); slotProjectNameChanged( name_edit->text() ); } ImportDialog::~ImportDialog() {} void ImportDialog::slotProjectNameChanged( const TQString &_text ) { ok_button->setEnabled( !_text.isEmpty() && !urlinput_edit->url().contains( TQRegExp("\\s") ) ); } void ImportDialog::accept() { TQDir dir(urlinput_edit->url()); if (urlinput_edit->url().isEmpty() || !dir.exists()) { KMessageBox::sorry(this, i18n("You have to choose a directory.")); return; } TQString projectName = name_edit->text(); if (projectName.isEmpty()) { KMessageBox::sorry(this, i18n("You have to choose a project name.")); return; } for (uint i=0; i < projectName.length(); ++i) if (!projectName[i].isLetterOrNumber() && projectName[i] != '_') { KMessageBox::sorry(this, i18n("Your application name should only contain letters and numbers.")); return; } if (infrastructureBox->isVisible() && infrastructureBox->isChecked()) createProjectInfrastructure(); // TQString author = author_edit->text(); // TQString email = email_edit->text(); TQFileInfo finfo(importNames[project_combo->currentItem()]); TQDir importdir(finfo.dir()); importdir.cdUp(); TQFile src(importdir.filePath("importfiles/" + finfo.fileName() + ".tdevelop")); kdDebug(9010) << "Import template " << src.name() << endl; if (!src.open(IO_ReadOnly)) { KMessageBox::sorry(this, i18n("Cannot open project template.")); return; } // Read the DOM of the newly created project TQDomDocument projectDOM; int errorLine, errorCol; TQString errorMsg; bool success = projectDOM.setContent( &src, &errorMsg, &errorLine, &errorCol); src.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; } DomUtil::writeEntry( projectDOM, "/general/author", author_edit->text() ); DomUtil::writeEntry( projectDOM, "/general/email" , email_edit->text() ); DomUtil::writeEntry( projectDOM, "/general/projectname", name_edit->text() ); if ( !projectVersion.isNull()){ DomUtil::writeEntry( projectDOM, "/general/version", projectVersion ); } else { DomUtil::writeEntry( projectDOM, "/general/version", "1" ); } // 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; } DomUtil::writeListEntry( projectDOM, "/general/ignoreparts", "part", disableList ); // write the dom back TQFile dest(dir.filePath(projectName + ".tdevelop")); if (!dest.open(IO_WriteOnly)) { KMessageBox::sorry(this, i18n("Cannot write the project file.")); return; } TQTextStream ts( &dest ); ts.setEncoding(TQTextStream::UnicodeUTF8); ts << projectDOM.toString(2); dest.close(); // TQTextStream srcstream(&src); // TQTextStream deststream(&dest); // // while (!srcstream.atEnd()) { // TQString line = srcstream.readLine(); // line.replace(TQRegExp("\\$APPNAMELC\\$"), projectName); // line.replace(TQRegExp("\\$AUTHOR\\$"), author); // line.replace(TQRegExp("\\$EMAIL\\$"), email); // deststream << line << endl; // } // // dest.close(); // src.close(); m_part->core()->openProject(dir.filePath(projectName + ".tdevelop")); kdDebug(9010) << "OPENING PROJECT: " << dir.filePath(projectName + ".tdevelop") << endl; TQDialog::accept(); } // Checks if the directory dir and all of its subdirectories // (one level recursion) have files that follow patterns // patterns is comma-separated static bool dirHasFiles(TQDir &dir, const TQString &patterns) { TQStringList::ConstIterator pit, sit; TQStringList patternList = TQStringList::split(",", patterns); for (pit = patternList.begin(); pit != patternList.end(); ++pit) { if (!dir.entryList(*pit, TQDir::Files).isEmpty()) { kdDebug(9010) << "Has files " << (*pit) << endl; return true; } } TQStringList subdirList = dir.entryList("*", TQDir::Dirs); for (sit = subdirList.begin(); sit != subdirList.end(); ++sit) { TQDir subdir(dir); subdir.cd(*sit); for (pit = patternList.begin(); pit != patternList.end(); ++pit) { if (!subdir.entryList(*pit, TQDir::Files).isEmpty()) { kdDebug(9010) << "Has files " << (*pit) << " in " << (*sit) << endl; return true; } } } return false; } void ImportDialog::dirChanged() { kdDebug(9010) << "ImportDialog::dirChanged" << endl; TQString dirName = urlinput_edit->url(); TQDir dir(dirName); if (!dir.exists()) return; if ( dirName.contains( TQRegExp("\\s") ) ) { ok_button->setEnabled( false ); return; }else { ok_button->setEnabled( true ); } // KDevelop legacy project? TQStringList files = dir.entryList("*.kdevprj"); if (!files.isEmpty()) { scanLegacyKDevelopProject(dir.absFilePath(files.first())); return; } // Studio legacy project? files = dir.entryList("*.studio"); if (!files.isEmpty()) { scanLegacyStudioProject(dir.absFilePath(files.first())); return; } // Automake based? if ( dir.exists("configure.in.in")|| dir.exists("configure.ac")|| dir.exists("configure.in")) { scanAutomakeProject(dirName); return; } // Remove any characters from the dirName that would be invalid in a project name TQString projectName(dir.dirName().replace(TQRegExp("[^a-zA-Z0-9_]"), "_")); // Set the project name name_edit->setText(projectName); // TQMake based? files = dir.entryList("*.pro"); if (!files.isEmpty()) { setProjectType("qtqmake"); return; } // C++? if (dirHasFiles(dir, "*.cpp,*.c++,*.cxx,*.C,*.cc,*.ocl")) { setProjectType("cpp"); return; } // Fortran? if (dirHasFiles(dir, "*.f77,*.f,*.for,*.ftn")) { setProjectType("fortran"); return; } // Python? if (dirHasFiles(dir, "*.py")) { setProjectType("python"); return; } // Perl? if (dirHasFiles(dir, "*.pl,*.pm")) { setProjectType("perl"); return; } } void ImportDialog::scanLegacyKDevelopProject(const TQString &fileName) { kdDebug(9010) << "Scanning legacy KDevelop project file " << fileName << endl; KSimpleConfig config(fileName, true); config.setGroup("General"); author_edit->setText(config.readEntry("author")); email_edit->setText(config.readEntry("email")); name_edit->setText(config.readEntry("project_name")); TQString legacyType = config.readEntry("project_type"); if (TQStringList::split(",", "normal_kde,normal_kde2,kde2_normal,mdi_kde2").contains(legacyType)) setProjectType("kde"); else if (legacyType == "normal_gnome") setProjectType("gnome"); else if (legacyType == "normal_empty") setProjectType("cpp-auto"); else setProjectType("cpp"); } void ImportDialog::scanLegacyStudioProject(const TQString &fileName) { kdDebug(9010) << "Scanning legacy studio project file " << fileName << endl; // Not much to do here... KSimpleConfig config(fileName, true); config.setGroup("kdestudio"); name_edit->setText(config.readEntry("Name")); } void ImportDialog::scanAutomakeProject(const TQString &dirName) { kdDebug(9010) << "Scanning automake project directory " << dirName << endl; bool stop = false; if (TQFile::exists(dirName + "/admin/am_edit")) { setProjectType("kde"); stop = true; } else if (TQFile::exists(dirName + "/macros/gnome.m4")) { setProjectType("gnome"); stop = true; } else { setProjectType("c-auto"); } // if we get an authors file, use it. TQFile af(dirName + "/AUTHORS"); if (af.open(IO_ReadOnly)){ TQTextStream astream(&af); TQRegExp authorre("(.*)<(.*)>"); while (!astream.atEnd()) { TQString s = astream.readLine(); if (authorre.search(s) != -1) { author_edit->setText(authorre.cap(1).stripWhiteSpace()); email_edit->setText(authorre.cap(2).stripWhiteSpace()); break; } } af.close(); } // we ignore old AC_INIT that had no version.. // only match the if there is a comma and at least two args.. // AC_INIT (package, version, [bug-report], [tarname]) TQRegExp ac_init("^AC_INIT\\s*\\(\\s*([^,]+),([^,\\)]+)(.*)"); // AM_INIT_AUTOMAKE([OPTIONS]) // example: AM_INIT_AUTOMAKE([gnits 1.5 no-define dist-bzip2]) TQRegExp am_autoSpace("^AM_INIT_AUTOMAKE\\s{0,}\\(\\s{0,}([\\[\\s]{0,}[^\\s]+)\\s+([^\\s\\)\\]]+)(.*)"); // AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) TQRegExp am_autoComma("^AM_INIT_AUTOMAKE\\s*\\(\\s*([^,]+),([^,\\)]+)(.*)"); // look for version in a define. // AC_DEFINE(VERSION, "5.6") TQRegExp ac_define("^AC_DEFINE\\s*\\(\\s*[^,]+,([^\\)]+)"); TQRegExp version("(\\bversion\\b)"); version.setCaseSensitive(FALSE); TQTextStream cstream; // try for configure.in.in, configure.in, then configure.ac TQFile configInIn(dirName + "/configure.in.in"); TQFile configIn(dirName+"/configure.in"); TQFile configAc(dirName+"/configure.ac"); if (configInIn.open(IO_ReadOnly)){ cstream.setDevice(TQT_TQIODEVICE(&configInIn)); while (!cstream.atEnd()) { TQString line = cstream.readLine(); if ( ac_init.search(line) >= 0){ projectVersion=ac_init.cap(2).stripWhiteSpace(); } else if ( am_autoComma.search(line) >= 0 ){ projectVersion=am_autoComma.cap(2).stripWhiteSpace(); } else if ( am_autoSpace.search(line) >= 0 ){ projectVersion=am_autoSpace.cap(2).stripWhiteSpace(); } else if ( ac_define.search(line) >=0 && version.search(line) >=0) { projectVersion=ac_define.cap(2).stripWhiteSpace(); } } configInIn.close(); } if (configIn.open(IO_ReadOnly)){ cstream.setDevice(TQT_TQIODEVICE(&configIn)); } else{ if (configAc.open(IO_ReadOnly)){ cstream.setDevice(TQT_TQIODEVICE(&configAc)); } else{ return; } } TQRegExp namere("\\s*AM_INIT_AUTOMAKE\\((.*),.*\\).*"); TQRegExp cppre("\\s*AC_PROG_CXX"); TQRegExp f77re("\\s*AC_PROG_F77"); while (!cstream.atEnd()) { TQString line = cstream.readLine(); if ( ac_init.search(line) >= 0){ projectVersion=ac_init.cap(2).stripWhiteSpace(); } else if ( am_autoComma.search(line) >= 0 ){ projectVersion=am_autoComma.cap(2).stripWhiteSpace(); } else if ( am_autoSpace.search(line) >= 0 ){ projectVersion=am_autoSpace.cap(2).stripWhiteSpace(); } else if ( ac_define.search(line) >=0 && version.search(line) >=0) { projectVersion=ac_define.cap(2).stripWhiteSpace(); } if (namere.search(line) == 0) name_edit->setText(namere.cap(1).stripWhiteSpace()); if (!stop) continue; else if (cppre.search(line) == 0) setProjectType("cpp-auto"); else if (f77re.search(line) == 0) setProjectType("fortran-auto"); } if ( configIn.isOpen()) configIn.close(); if ( configAc.isOpen()) configAc.close(); } void ImportDialog::setProjectType(const TQString &type) { kdDebug(9010) << "Setting project type " << type << endl; TQString suffix = "/" + type; int suffixLength = suffix.length(); int i=0; TQStringList::ConstIterator it; for (it = importNames.begin(); it != importNames.end(); ++it) { if ((*it).right(suffixLength) == suffix) { project_combo->setCurrentItem(i); break; } ++i; } } /* void ImportDialog::scanAvailableVCS() { // vcsCombo->insertStringList( m_part->registeredVersionControls() ); int i = 0; TDETrader::OfferList offers = TDETrader::self()->query("TDevelop/VersionControl"); TDETrader::OfferList::const_iterator it = offers.begin(); while( it != offers.end() ) { vcsCombo->insertItem( (*it)->genericName(), i++ ); ++it; } } */ /* void ImportDialog::slotFinishedCheckout( TQString destinationDir ) { urlinput_edit->setURL( destinationDir ); setCursor( KCursor::arrowCursor() ); // setEnabled( true ); } */ /* void ImportDialog::slotFetchModulesFromRepository() { KDevVersionControl *vcs = m_part->versionControlByName( vcsCombo->currentText() ); if (!vcs) return; setCursor( KCursor::waitCursor() ); // setEnabled( false ); connect( vcs, TQT_SIGNAL(finishedFetching(TQString)), this, TQT_SLOT(slotFinishedCheckout(TQString)) ); //restore cursor if we can't fetch repository if ( !vcs->fetchFromRepository() ) setCursor( KCursor::arrowCursor() ); } */ void ImportDialog::projectTypeChanged( const TQString &type ) { if (m_infrastructure[type].isOn) { infrastructureBox->setEnabled(true); infrastructureBox->setText(m_infrastructure[type].comment); } else { infrastructureBox->setEnabled(false); infrastructureBox->setText(i18n("Generate build system infrastrucure")); } } void ImportDialog::createProjectInfrastructure( ) { kdDebug(9010) << "ImportDialog::createProjectInfrastructure" << endl; InfrastructureCmd cmd = m_infrastructure[project_combo->currentText()]; if (!cmd.isOn) return; TQDir dir (urlinput_edit->url()); TQStringList files = dir.entryList(cmd.existingPattern); if (!files.isEmpty()) { if (KMessageBox::questionYesNo(this, i18n("Project infrastrucure already exists in target directory.\nGenerate new project infrastructure and overwrite old?"), TQString(), i18n("Generate"), i18n("Do Not Generate")) == KMessageBox::No) return; } TQString command = "cd " + urlinput_edit->url() + " && " + cmd.command; kdDebug(9010) << "executing " << command.ascii() << endl; system(command.ascii()); } void ImportDialog::projectTypeChanged( int type ) { projectTypeChanged(project_combo->text(type)); } #include "importdlg.moc"