/*************************************************************************** * Copyright (C) 2003 Alexander Dymo * * cloudtemple@mksat.net * * * * 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 "pascalproject_part.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "domutil.h" #include "kdevcore.h" #include "kdevmainwindow.h" #include "kdevmakefrontend.h" #include "kdevappfrontend.h" #include "kdevpartcontroller.h" #include "kdevlanguagesupport.h" #include "kdevcompileroptions.h" #include "runoptionswidget.h" #include "envvartools.h" #include "pascalproject_widget.h" #include "pascalprojectoptionsdlg.h" #include "pascalglobaloptionsdlg.h" #include typedef KDevGenericFactory PascalProjectFactory; static const KDevPluginInfo data("kdevpascalproject"); K_EXPORT_COMPONENT_FACTORY( libkdevpascalproject, PascalProjectFactory( data ) ) PascalProjectPart::PascalProjectPart(QObject *parent, const char *name, const QStringList& ) :KDevBuildTool(&data, parent, name ? name : "PascalProjectPart" ) { setInstance(PascalProjectFactory::instance()); setXMLFile("kdevpascalproject.rc"); KAction *action; action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8, this, SLOT(slotBuild()), actionCollection(), "build_build" ); action->setToolTip(i18n("Build project")); action->setWhatsThis(i18n("Build project

Runs the compiler on a main source file of the project. " "The compiler and the main source file can be set in project settings, Pascal Compiler tab.")); action = new KAction( i18n("Execute Program"), "exec", 0, this, SLOT(slotExecute()), actionCollection(), "build_execute" ); action->setToolTip(i18n("Execute program")); action->setWhatsThis(i18n("Execute program

Executes the main program specified in project settings, Run options tab. " "If nothing is set, the binary file with the same name as the main source file name is executed.")); connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)), this, SLOT(projectConfigWidget(KDialogBase*)) ); connect( core(), SIGNAL(configWidget(KDialogBase*)), this, SLOT(configWidget(KDialogBase*)) ); // m_widget = new PascalProjectWidget(this); // QWhatsThis::add(m_widget, i18n("WHAT DOES THIS PART DO?")); // now you decide what should happen to the widget. Take a look at kdevcore.h // or at other plugins how to embed it. // if you want to embed your widget as an outputview, simply uncomment // the following line. // mainWindow()->embedOutputView( m_widget, "name that should appear", "enter a tooltip" ); } PascalProjectPart::~PascalProjectPart() { // delete m_widget; } /** * @todo This should really be merged with FileTreeWidget::matchesHidePattern() * and put in its own class. Currently this is repeated in scriptprojectpart.cpp, pascalproject_part.cpp, adaproject_part.cpp */ static bool matchesPattern(const QString &fileName, const QStringList &patternList) { QStringList::ConstIterator it; for (it = patternList.begin(); it != patternList.end(); ++it) { QRegExp re(*it, true, true); if (re.search(fileName) == 0 && re.matchedLength() == (int)fileName.length()) return true; } return false; } void PascalProjectPart::openProject(const QString &dirName, const QString &projectName) { m_buildDir = dirName; m_projectDir = dirName; m_projectName = projectName; QDomDocument &dom = *projectDom(); // Set the default directory radio to "executable" if (DomUtil::readEntry(dom, "/kdevpascalproject/run/directoryradio") == "" ) { DomUtil::writeEntry(dom, "/kdevpascalproject/run/directoryradio", "executable"); } loadProjectConfig(); // Put all files from all subdirectories into file list QValueStack s; int prefixlen = m_projectDir.length()+1; s.push(m_projectDir); QStringList includepatternList; if ( languageSupport() ) { KMimeType::List list = languageSupport()->mimeTypes(); KMimeType::List::Iterator it = list.begin(); while( it != list.end() ){ includepatternList += (*it)->patterns(); ++it; } } QString excludepatterns = "*~"; QStringList excludepatternList = QStringList::split(",", excludepatterns); QDir dir; do { dir.setPath(s.pop()); kdDebug(9033) << "Examining: " << dir.path() << endl; const QFileInfoList *dirEntries = dir.entryInfoList(); QPtrListIterator it(*dirEntries); for (; it.current(); ++it) { QString fileName = it.current()->fileName(); if (fileName == "." || fileName == "..") continue; QString path = it.current()->absFilePath(); if (it.current()->isDir()) { kdDebug(9033) << "Pushing: " << path << endl; s.push(path); } else { if (matchesPattern(path, includepatternList) && !matchesPattern(path, excludepatternList)) { kdDebug(9033) << "Adding: " << path << endl; m_sourceFiles.append(path.mid(prefixlen)); } else { kdDebug(9033) << "Ignoring: " << path << endl; } } } } while (!s.isEmpty()); KDevProject::openProject( dirName, projectName ); } void PascalProjectPart::closeProject() { } /** Retuns a PairList with the run environment variables */ DomUtil::PairList PascalProjectPart::runEnvironmentVars() const { return DomUtil::readPairListEntry(*projectDom(), "/kdevpascalproject/run/envvars", "envvar", "name", "value"); } /** Retuns the currently selected run directory * The returned string can be: * if run/directoryradio == executable * The directory where the executable is * if run/directoryradio == build * The directory where the executable is relative to build directory * if run/directoryradio == custom * The custom directory absolute path */ QString PascalProjectPart::runDirectory() const { QString cwd = defaultRunDirectory("kdevpascalproject"); if (cwd.isEmpty()) cwd = buildDirectory(); return cwd; } /** Retuns the currently selected main program * The returned string can be: * if run/directoryradio == executable * The executable name * if run/directoryradio == build * The path to executable relative to build directory * if run/directoryradio == custom or relative == false * The absolute path to executable */ QString PascalProjectPart::mainProgram() const { QDomDocument * dom = projectDom(); if ( !dom ) return QString(); QString DomMainProgram = DomUtil::readEntry( *dom, "/kdevpascalproject/run/mainprogram"); if ( DomMainProgram.isEmpty() ) return QString(); if ( DomMainProgram.startsWith("/") ) // assume absolute path { return DomMainProgram; } else // assume project relative path { return projectDirectory() + "/" + DomMainProgram; } return QString(); } /** Retuns a QString with the debug command line arguments */ QString PascalProjectPart::debugArguments() const { return DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/globaldebugarguments"); } /** Retuns a QString with the run command line arguments */ QString PascalProjectPart::runArguments() const { return DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/programargs"); } QString PascalProjectPart::mainSource() const { return projectDirectory() + "/" + m_mainSource; } void PascalProjectPart::setMainSource(QString fullPath) { QString olddir = activeDirectory(); m_mainSource = fullPath.replace(QRegExp(QString(projectDirectory() + QString("/"))),""); emit activeDirectoryChanged( olddir, activeDirectory() ); } QString PascalProjectPart::projectDirectory() const { return m_projectDir; } QString PascalProjectPart::projectName() const { return m_projectName; } QString PascalProjectPart::activeDirectory() const { QFileInfo fi(mainSource()); return fi.dirPath(true).replace(QRegExp(projectDirectory()),""); } QString PascalProjectPart::buildDirectory() const { QFileInfo fi(mainSource()); return fi.dirPath(true); } void PascalProjectPart::listOfFiles(QStringList &result, QString path) const { QDir d(path); if (!d.exists()) return; QFileInfoList *entries = const_cast(d.entryInfoList(QDir::Dirs | QDir::Files | QDir::Hidden)); for (QFileInfo *it = entries->first(); it; it = entries->next()) { if ((it->isDir()) && (it->filePath() != path)) { // qWarning("entering dir %s", it->dirPath().latin1()); listOfFiles(result, it->dirPath()); } else { // qWarning("adding to result: %s", it->filePath().latin1()); result << it->filePath(); } } } QStringList PascalProjectPart::allFiles() const { // QStringList files; // listOfFiles(files, projectDirectory()); // return files; return m_sourceFiles; } void PascalProjectPart::addFile(const QString& /*fileName*/) { } void PascalProjectPart::addFiles(const QStringList& /*fileList*/) { } void PascalProjectPart::removeFile(const QString& /*fileName*/) { } void PascalProjectPart::removeFiles(const QStringList& /*fileList*/) { } void PascalProjectPart::slotBuild() { if (partController()->saveAllFiles()==false) return; //user cancelled QString cmdline = m_compilerExec + " " + m_compilerOpts + " "; if (cmdline.isEmpty()) { KMessageBox::sorry(0, i18n("Could not find pascal compiler.\nCheck if your compiler settings are correct.")); return; } QFileInfo fi(mainSource()); cmdline += fi.fileName(); QString dircmd = "cd "; dircmd += KProcess::quote(buildDirectory()); dircmd += " && "; makeFrontend()->queueCommand(buildDirectory(), dircmd + cmdline); } void PascalProjectPart::slotExecute() { partController()->saveAllFiles(); QDomDocument &dom = *(projectDom()); bool runInTerminal = DomUtil::readBoolEntry(dom, "/kdevpascalproject/run/terminal", true); // Get the run environment variables pairs into the environstr string // in the form of: "ENV_VARIABLE=ENV_VALUE" // Note that we quote the variable value due to the possibility of // embedded spaces DomUtil::PairList envvars = DomUtil::readPairListEntry(*projectDom(), "/kdevpascalproject/run/envvars", "envvar", "name", "value"); QString environstr; DomUtil::PairList::ConstIterator it; for (it = envvars.begin(); it != envvars.end(); ++it) { environstr += (*it).first; environstr += "="; environstr += EnvVarTools::quote((*it).second); environstr += " "; } QString program = mainProgram(); program.prepend(environstr); program += " " + DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/programargs"); appFrontend()->startAppCommand(buildDirectory(), program, runInTerminal); } void PascalProjectPart::changedFiles( const QStringList & fileList ) { KDevProject::changedFiles(fileList); } void PascalProjectPart::changedFile( const QString & fileName ) { KDevProject::changedFile(fileName); } void PascalProjectPart::projectConfigWidget( KDialogBase * dlg ) { QVBox *vbox; vbox = dlg->addVBoxPage(i18n("Pascal Compiler")); PascalProjectOptionsDlg *w = new PascalProjectOptionsDlg(this, vbox); connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) ); connect( dlg, SIGNAL(okClicked()), this, SLOT(loadProjectConfig()) ); vbox = dlg->addVBoxPage(i18n("Run Options"), i18n("Run Options"), BarIcon( "make", KIcon::SizeMedium )); RunOptionsWidget *w3 = new RunOptionsWidget(*projectDom(), "/kdevpascalproject", buildDirectory(), vbox); connect( dlg, SIGNAL(okClicked()), w3, SLOT(accept()) ); } void PascalProjectPart::loadProjectConfig( ) { QDomDocument &dom = *(projectDom()); QString config = DomUtil::readEntry(dom, "/kdevpascalproject/general/useconfiguration", "default"); m_mainSource = DomUtil::readEntry(dom, QString("/kdevpascalproject/configurations/") + config + QString("/mainsource") ); m_compilerOpts = DomUtil::readEntry(dom, QString("/kdevpascalproject/configurations/") + config + QString("/compileroptions")); m_compilerExec = DomUtil::readEntry(dom, QString("/kdevpascalproject/configurations/") + config + QString("/compilerexec")); if (m_compilerExec.isEmpty()) { KTrader::OfferList offers = KTrader::self()->query("KDevelop/CompilerOptions", "[X-KDevelop-Language] == 'Pascal'"); QValueList::ConstIterator it; for (it = offers.begin(); it != offers.end(); ++it) { if ((*it)->property("X-KDevelop-Default").toBool()) { m_compilerExec = (*it)->exec(); break; } } } } void PascalProjectPart::configWidget( KDialogBase * dlg ) { QVBox *vbox; vbox = dlg->addVBoxPage(i18n("Pascal Compiler")); PascalGlobalOptionsDlg *w = new PascalGlobalOptionsDlg(this, vbox); connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) ); } KDevCompilerOptions *PascalProjectPart::createCompilerOptions(const QString &name) { KService::Ptr service = KService::serviceByDesktopName(name); if (!service) { kdDebug() << "Can't find service " << name; return 0; } KLibFactory *factory = KLibLoader::self()->factory(QFile::encodeName(service->library())); if (!factory) { QString errorMessage = KLibLoader::self()->lastErrorMessage(); KMessageBox::error(0, i18n("There was an error loading the module %1.\n" "The diagnostics is:\n%2").arg(service->name()).arg(errorMessage)); exit(1); } QStringList args; QVariant prop = service->property("X-KDevelop-Args"); if (prop.isValid()) args = QStringList::split(" ", prop.toString()); QObject *obj = factory->create(this, service->name().latin1(), "KDevCompilerOptions", args); if (!obj->inherits("KDevCompilerOptions")) { kdDebug() << "Component does not inherit KDevCompilerOptions" << endl; return 0; } KDevCompilerOptions *dlg = (KDevCompilerOptions*) obj; return dlg; } QString PascalProjectPart::defaultOptions( const QString compiler ) const { KConfig *config = KGlobal::config(); config->setGroup("Pascal Compiler"); return config->readPathEntry(compiler); } #include "pascalproject_part.moc" /*! \fn PascalProjectPart::distFiles() const */ QStringList PascalProjectPart::distFiles() const { QStringList sourceList = allFiles(); // Scan current source directory for any .pro files. QString projectDir = projectDirectory(); QDir dir(projectDir); QStringList files = dir.entryList( "Makefile"); return sourceList + files; }