You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/buildtools/pascal/pascalproject_part.cpp

494 lines
16 KiB

/***************************************************************************
* 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 <tqdom.h>
#include <tqfileinfo.h>
#include <tqdir.h>
#include <tqvaluestack.h>
#include <tqregexp.h>
#include <tqvbox.h>
#include <tqlabel.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kaction.h>
#include <kdevgenericfactory.h>
#include <kdebug.h>
#include <kdialogbase.h>
#include <kmessagebox.h>
#include <klibloader.h>
#include <kservice.h>
#include <kconfig.h>
#include <kdeversion.h>
#include <kprocess.h>
#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 <kdevplugininfo.h>
typedef KDevGenericFactory<PascalProjectPart> PascalProjectFactory;
static const KDevPluginInfo data("kdevpascalproject");
K_EXPORT_COMPONENT_FACTORY( libkdevpascalproject, PascalProjectFactory( data ) )
PascalProjectPart::PascalProjectPart(TQObject *tqparent, const char *name, const TQStringList& )
:KDevBuildTool(&data, tqparent, name ? name : "PascalProjectPart" )
{
setInstance(PascalProjectFactory::instance());
setXMLFile("kdevpascalproject.rc");
KAction *action;
action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8,
this, TQT_SLOT(slotBuild()),
actionCollection(), "build_build" );
action->setToolTip(i18n("Build project"));
action->setWhatsThis(i18n("<b>Build project</b><p>Runs the compiler on a main source file of the project. "
"The compiler and the main source file can be set in project settings, <b>Pascal Compiler</b> tab."));
action = new KAction( i18n("Execute Program"), "exec", 0,
this, TQT_SLOT(slotExecute()),
actionCollection(), "build_execute" );
action->setToolTip(i18n("Execute program"));
action->setWhatsThis(i18n("<b>Execute program</b><p>Executes the main program specified in project settings, <b>Run options</b> 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<TQString> 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<TQFileInfo> 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.tqreplace(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).tqreplace(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<TQFileInfoList*>(d.entryInfoList(TQDir::Dirs | TQDir::Files | TQDir::Hidden));
for (TQFileInfo *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();
}
}
}
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<KService::Ptr>::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").tqarg(service->name()).tqarg(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;
}