/*************************************************************************** * 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(TQObject *parent, const char *name, const TQStringList& ) :KDevBuildTool(&data, parent, name ? name : "PascalProjectPart" ) { setInstance(PascalProjectFactory::instance()); setXMLFile("kdevpascalproject.rc"); KAction *action; action = new KAction( i18n("&Build Project"), "make_tdevelop", Key_F8, this, TQT_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, TQT_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(), TQT_SIGNAL(projectConfigWidget(KDialogBase*)), this, TQT_SLOT(projectConfigWidget(KDialogBase*)) ); connect( core(), TQT_SIGNAL(configWidget(KDialogBase*)), this, TQT_SLOT(configWidget(KDialogBase*)) ); // m_widget = new PascalProjectWidget(this); // TQWhatsThis::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 TQString &fileName, const TQStringList &patternList) { TQStringList::ConstIterator it; for (it = patternList.begin(); it != patternList.end(); ++it) { TQRegExp re(*it, true, true); if (re.search(fileName) == 0 && re.matchedLength() == (int)fileName.length()) return true; } return false; } void PascalProjectPart::openProject(const TQString &dirName, const TQString &projectName) { m_buildDir = dirName; m_projectDir = dirName; m_projectName = projectName; TQDomDocument &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 TQValueStack s; int prefixlen = m_projectDir.length()+1; s.push(m_projectDir); TQStringList includepatternList; if ( languageSupport() ) { KMimeType::List list = languageSupport()->mimeTypes(); KMimeType::List::Iterator it = list.begin(); while( it != list.end() ){ includepatternList += (*it)->patterns(); ++it; } } TQString excludepatterns = "*~"; TQStringList excludepatternList = TQStringList::split(",", excludepatterns); TQDir dir; do { dir.setPath(s.pop()); kdDebug(9033) << "Examining: " << dir.path() << endl; const TQFileInfoList *dirEntries = dir.entryInfoList(); TQPtrListIterator it(*dirEntries); for (; it.current(); ++it) { TQString fileName = it.current()->fileName(); if (fileName == "." || fileName == "..") continue; TQString 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 */ TQString PascalProjectPart::runDirectory() const { TQString 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 */ TQString PascalProjectPart::mainProgram() const { TQDomDocument * dom = projectDom(); if ( !dom ) return TQString(); TQString DomMainProgram = DomUtil::readEntry( *dom, "/kdevpascalproject/run/mainprogram"); if ( DomMainProgram.isEmpty() ) return TQString(); if ( DomMainProgram.startsWith("/") ) // assume absolute path { return DomMainProgram; } else // assume project relative path { return projectDirectory() + "/" + DomMainProgram; } return TQString(); } /** Retuns a TQString with the debug command line arguments */ TQString PascalProjectPart::debugArguments() const { return DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/globaldebugarguments"); } /** Retuns a TQString with the run command line arguments */ TQString PascalProjectPart::runArguments() const { return DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/programargs"); } TQString PascalProjectPart::mainSource() const { return projectDirectory() + "/" + m_mainSource; } void PascalProjectPart::setMainSource(TQString fullPath) { TQString olddir = activeDirectory(); m_mainSource = fullPath.replace(TQRegExp(TQString(projectDirectory() + TQString("/"))),""); emit activeDirectoryChanged( olddir, activeDirectory() ); } TQString PascalProjectPart::projectDirectory() const { return m_projectDir; } TQString PascalProjectPart::projectName() const { return m_projectName; } TQString PascalProjectPart::activeDirectory() const { TQFileInfo fi(mainSource()); return fi.dirPath(true).replace(TQRegExp(projectDirectory()),""); } TQString PascalProjectPart::buildDirectory() const { TQFileInfo fi(mainSource()); return fi.dirPath(true); } void PascalProjectPart::listOfFiles(TQStringList &result, TQString path) const { TQDir d(path); if (!d.exists()) return; TQFileInfoList *entries = const_cast(d.entryInfoList(TQDir::Dirs | TQDir::Files | TQDir::Hidden)); for (TQFileInfo *it = entries->first(); it; it = entries->next()) { if ((it->isDir()) && (it->filePath() != path)) { // tqWarning("entering dir %s", it->dirPath().latin1()); listOfFiles(result, it->dirPath()); } else { // tqWarning("adding to result: %s", it->filePath().latin1()); result << it->filePath(); } } } TQStringList PascalProjectPart::allFiles() const { // TQStringList files; // listOfFiles(files, projectDirectory()); // return files; return m_sourceFiles; } void PascalProjectPart::addFile(const TQString& /*fileName*/) { } void PascalProjectPart::addFiles(const TQStringList& /*fileList*/) { } void PascalProjectPart::removeFile(const TQString& /*fileName*/) { } void PascalProjectPart::removeFiles(const TQStringList& /*fileList*/) { } void PascalProjectPart::slotBuild() { if (partController()->saveAllFiles()==false) return; //user cancelled TQString 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; } TQFileInfo fi(mainSource()); cmdline += fi.fileName(); TQString dircmd = "cd "; dircmd += KProcess::quote(buildDirectory()); dircmd += " && "; makeFrontend()->queueCommand(buildDirectory(), dircmd + cmdline); } void PascalProjectPart::slotExecute() { partController()->saveAllFiles(); TQDomDocument &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"); TQString environstr; DomUtil::PairList::ConstIterator it; for (it = envvars.begin(); it != envvars.end(); ++it) { environstr += (*it).first; environstr += "="; environstr += EnvVarTools::quote((*it).second); environstr += " "; } TQString program = mainProgram(); program.prepend(environstr); program += " " + DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/programargs"); appFrontend()->startAppCommand(buildDirectory(), program, runInTerminal); } void PascalProjectPart::changedFiles( const TQStringList & fileList ) { KDevProject::changedFiles(fileList); } void PascalProjectPart::changedFile( const TQString & fileName ) { KDevProject::changedFile(fileName); } void PascalProjectPart::projectConfigWidget( KDialogBase * dlg ) { TQVBox *vbox; vbox = dlg->addVBoxPage(i18n("Pascal Compiler")); PascalProjectOptionsDlg *w = new PascalProjectOptionsDlg(this, vbox); connect( dlg, TQT_SIGNAL(okClicked()), w, TQT_SLOT(accept()) ); connect( dlg, TQT_SIGNAL(okClicked()), this, TQT_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, TQT_SIGNAL(okClicked()), w3, TQT_SLOT(accept()) ); } void PascalProjectPart::loadProjectConfig( ) { TQDomDocument &dom = *(projectDom()); TQString config = DomUtil::readEntry(dom, "/kdevpascalproject/general/useconfiguration", "default"); m_mainSource = DomUtil::readEntry(dom, TQString("/kdevpascalproject/configurations/") + config + TQString("/mainsource") ); m_compilerOpts = DomUtil::readEntry(dom, TQString("/kdevpascalproject/configurations/") + config + TQString("/compileroptions")); m_compilerExec = DomUtil::readEntry(dom, TQString("/kdevpascalproject/configurations/") + config + TQString("/compilerexec")); if (m_compilerExec.isEmpty()) { KTrader::OfferList offers = KTrader::self()->query("KDevelop/CompilerOptions", "[X-KDevelop-Language] == 'Pascal'"); TQValueList::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 ) { TQVBox *vbox; vbox = dlg->addVBoxPage(i18n("Pascal Compiler")); PascalGlobalOptionsDlg *w = new PascalGlobalOptionsDlg(this, vbox); connect( dlg, TQT_SIGNAL(okClicked()), w, TQT_SLOT(accept()) ); } KDevCompilerOptions *PascalProjectPart::createCompilerOptions(const TQString &name) { KService::Ptr service = KService::serviceByDesktopName(name); if (!service) { kdDebug() << "Can't find service " << name; return 0; } KLibFactory *factory = KLibLoader::self()->factory(TQFile::encodeName(service->library())); if (!factory) { TQString 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); } TQStringList args; TQVariant prop = service->property("X-KDevelop-Args"); if (prop.isValid()) args = TQStringList::split(" ", prop.toString()); TQObject *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; } TQString PascalProjectPart::defaultOptions( const TQString compiler ) const { KConfig *config = KGlobal::config(); config->setGroup("Pascal Compiler"); return config->readPathEntry(compiler); } #include "pascalproject_part.moc" /*! \fn PascalProjectPart::distFiles() const */ TQStringList PascalProjectPart::distFiles() const { TQStringList sourceList = allFiles(); // Scan current source directory for any .pro files. TQString projectDir = projectDirectory(); TQDir dir(projectDir); TQStringList files = dir.entryList( "Makefile"); return sourceList + files; }