KDevelop API Documentation

customprojectpart.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2001-2002 by Bernd Gehrmann                             *
00003  *   bernd@kdevelop.org                                                    *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  ***************************************************************************/
00011 
00012 #include "customprojectpart.h"
00013 
00014 #include <qapplication.h>
00015 #include <qdir.h>
00016 #include <qfileinfo.h>
00017 #include <qpopupmenu.h>
00018 #include <qregexp.h>
00019 #include <qstringlist.h>
00020 #include <qtabwidget.h>
00021 #include <qvaluestack.h>
00022 #include <qvbox.h>
00023 #include <qwhatsthis.h>
00024 #include <qdom.h>
00025 
00026 #include <kaction.h>
00027 #include <kdebug.h>
00028 #include <kdialogbase.h>
00029 #include <kdevgenericfactory.h>
00030 #include <kiconloader.h>
00031 #include <klocale.h>
00032 #include <kmainwindow.h>
00033 #include <kmessagebox.h>
00034 #include <kparts/part.h>
00035 #include <kpopupmenu.h>
00036 #include <kdeversion.h>
00037 #include <kprocess.h>
00038 
00039 #include "domutil.h"
00040 #include "kdevcore.h"
00041 #include "kdevmainwindow.h"
00042 #include "kdevmakefrontend.h"
00043 #include "kdevappfrontend.h"
00044 #include "kdevpartcontroller.h"
00045 #include "runoptionswidget.h"
00046 #include "makeoptionswidget.h"
00047 #include "custombuildoptionswidget.h"
00048 #include "custommakeconfigwidget.h"
00049 #include "config.h"
00050 #include "envvartools.h"
00051 #include "urlutil.h"
00052 
00053 
00054 typedef KDevGenericFactory<CustomProjectPart> CustomProjectFactory;
00055 static const KAboutData data("kdevcustomproject", I18N_NOOP("Build Tool"), "1.0");
00056 K_EXPORT_COMPONENT_FACTORY( libkdevcustomproject, CustomProjectFactory( &data ) )
00057 
00058 CustomProjectPart::CustomProjectPart(QObject *parent, const char *name, const QStringList &)
00059     : KDevProject("CustomProject", "customproject", parent, name ? name : "CustomProjectPart")
00060     , m_lastCompilationFailed(false)
00061 {
00062     setInstance(CustomProjectFactory::instance());
00063     setXMLFile("kdevcustomproject.rc");
00064 
00065     m_executeAfterBuild = false;
00066 
00067     KAction *action;
00068 
00069     action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8,
00070                           this, SLOT(slotBuild()),
00071                           actionCollection(), "build_build" );
00072     action->setToolTip(i18n("Build project"));
00073     action->setWhatsThis(i18n("<b>Build project</b><p>Runs <b>make</b> from the project directory.<br>"
00074                               "Environment variables and make arguments can be specified "
00075                               "in the project settings dialog, <b>Build Options</b> tab."));
00076 
00077     action = new KAction( i18n("Compile &File"), "make_kdevelop",
00078                           this, SLOT(slotCompileFile()),
00079                           actionCollection(), "build_compilefile" );
00080     action->setToolTip(i18n("Compile file"));
00081     action->setWhatsThis(i18n("<b>Compile file</b><p>Runs <b>make filename.o</b> command from the directory where 'filename' is the name of currently opened file.<br>"
00082                               "Environment variables and make arguments can be specified "
00083                               "in the project settings dialog, <b>Build Options</b> tab."));
00084 
00085     action = new KAction( i18n("&Clean Project"), 0,
00086                           this, SLOT(slotClean()),
00087                           actionCollection(), "build_clean" );
00088     action->setToolTip(i18n("Clean project"));
00089     action->setWhatsThis(i18n("<b>Clean project</b><p>Runs <b>make clean</b> command from the project directory.<br>"
00090                               "Environment variables and make arguments can be specified "
00091                               "in the project settings dialog, <b>Build Options</b> tab."));
00092 
00093     action = new KAction( i18n("Execute Program"), "exec", 0,
00094                           this, SLOT(slotExecute()),
00095                           actionCollection(), "build_execute" );
00096     action->setToolTip(i18n("Execute program"));
00097     action->setWhatsThis(i18n("<b>Execute program</b><p>Executes the main program specified in project settings, <b>Run Options</b> tab. "
00098                             "If it is not specified then the active target is used to determine the application to run."));
00099 
00100     KActionMenu *menu = new KActionMenu( i18n("Build &Target"),
00101                                          actionCollection(), "build_target" );
00102     m_targetMenu = menu->popupMenu();
00103     menu->setToolTip(i18n("Build target"));
00104     menu->setWhatsThis(i18n("<b>Build target</b><p>Runs <b>make targetname</b> from the project directory (targetname is the name of the target selected).<br>"
00105                             "Environment variables and make arguments can be specified "
00106                             "in the project settings dialog, <b>Build Options</b> tab."));
00107 
00108     m_makeEnvironmentsSelector = new KSelectAction( i18n("Make &Environment"),0,
00109                             actionCollection(), "build_make_environment" );
00110     m_makeEnvironmentsSelector->setToolTip(i18n("Make environment"));
00111     m_makeEnvironmentsSelector->setWhatsThis(i18n("<b>Make Environment</b><p> Choose the set of environment variables to be passed on to make.<br>"
00112                             "Environment variables can be specified in the project "
00113                             "settings dialog, <b>Build Options</b> tab."));
00114 
00115     connect( m_targetMenu, SIGNAL(aboutToShow()),
00116              this, SLOT(updateTargetMenu()) );
00117     connect( m_targetMenu, SIGNAL(activated(int)),
00118              this, SLOT(targetMenuActivated(int)) );
00119     connect( m_makeEnvironmentsSelector->popupMenu(), SIGNAL(aboutToShow()),
00120              this, SLOT(updateMakeEnvironmentsMenu()) );
00121     connect( m_makeEnvironmentsSelector->popupMenu(), SIGNAL(activated(int)),
00122              this, SLOT(makeEnvironmentsMenuActivated(int)) );
00123     connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
00124              this, SLOT(projectConfigWidget(KDialogBase*)) );
00125     connect( core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)),
00126              this, SLOT(contextMenu(QPopupMenu *, const Context *)) );
00127 
00128     connect( makeFrontend(), SIGNAL(commandFinished(const QString&)),
00129              this, SLOT(slotCommandFinished(const QString&)) );
00130     connect( makeFrontend(), SIGNAL(commandFailed(const QString&)),
00131              this, SLOT(slotCommandFailed(const QString&)) );
00132 }
00133 
00134 
00135 CustomProjectPart::~CustomProjectPart()
00136 {}
00137 
00138 
00139 void CustomProjectPart::projectConfigWidget(KDialogBase *dlg)
00140 {
00141     QVBox *vbox;
00142     vbox = dlg->addVBoxPage(i18n("Run Options"));
00143     RunOptionsWidget *w1 = new RunOptionsWidget(*projectDom(), "/kdevcustomproject", buildDirectory(), vbox);
00144     connect( dlg, SIGNAL(okClicked()), w1, SLOT(accept()) );
00145     vbox = dlg->addVBoxPage(i18n("Build Options"));
00146     QTabWidget *buildtab = new QTabWidget(vbox);
00147 
00148     CustomBuildOptionsWidget *w2 = new CustomBuildOptionsWidget(*projectDom(), buildtab);
00149     connect( dlg, SIGNAL(okClicked()), w2, SLOT(accept()) );
00150     buildtab->addTab(w2, i18n("&Build"));
00151 
00152     CustomMakeConfigWidget *w3 = new CustomMakeConfigWidget(this, "/kdevcustomproject", buildtab);
00153     buildtab->addTab(w3, i18n("Ma&ke"));
00154     w2->setMakeOptionsWidget(buildtab, w3);
00155     connect( dlg, SIGNAL(okClicked()), w3, SLOT(accept()) );
00156 }
00157 
00158 
00159 void CustomProjectPart::contextMenu(QPopupMenu *popup, const Context *context)
00160 {
00161     if (!context->hasType( Context::FileContext ))
00162         return;
00163 
00164     const FileContext *fcontext = static_cast<const FileContext*>(context);
00165     if (fcontext->isDirectory()) {
00166         // remember the name of the directory
00167         m_contextDirName = fcontext->fileName();
00168         m_contextDirName = m_contextDirName.mid ( project()->projectDirectory().length() + 1 );
00169         popup->insertSeparator();
00170         int id = popup->insertItem( i18n("Make Active Directory"),
00171                            this, SLOT(slotChooseActiveDirectory()) );
00172         popup->setWhatsThis(id, i18n("<b>Make active directory</b><p>"
00173         "Chooses this directory as the destination for new files created using wizards "
00174         "like the <i>New Class</i> wizard."));
00175         return;
00176     }
00177     m_contextAddFiles.clear();
00178     m_contextRemoveFiles.clear();
00179 
00180     if( fcontext->urls().size() == 1 )
00181     {
00182         QString contextFileName = URLUtil::canonicalPath(fcontext->fileName());
00183         bool inProject = project()->isProjectFile(contextFileName);
00184         QString popupstr = QFileInfo(contextFileName).fileName();
00185         if (contextFileName.startsWith(projectDirectory()+ "/"))
00186             contextFileName.remove(0, projectDirectory().length()+1);
00187 
00188         popup->insertSeparator();
00189         if (inProject)
00190         {
00191         m_contextRemoveFiles << contextFileName;
00192             int id = popup->insertItem( i18n("Remove %1 From Project").arg(popupstr),
00193                                this, SLOT(slotRemoveFromProject()) );
00194             popup->setWhatsThis(id, i18n("<b>Remove from project</b><p>Removes current file from the list of files in project. "
00195                 "Note that the file should be manually excluded from corresponding makefile or build.xml."));
00196         }
00197         else
00198         {
00199         m_contextAddFiles << contextFileName;
00200             int id = popup->insertItem( i18n("Add %1 to Project").arg(popupstr),
00201                                this, SLOT(slotAddToProject()) );
00202             popup->setWhatsThis(id, i18n("<b>Add to project</b><p>Adds current file to the list of files in project. "
00203                 "Note that the file should be manually added to corresponding makefile or build.xml."));
00204         }
00205     }
00206     else   // more than one file
00207     {
00208         const KURL::List urls = fcontext->urls();
00209     for (KURL::List::ConstIterator it = urls.begin(); it != urls.end(); ++it)
00210     {
00211         if ((*it).isLocalFile())
00212         {
00213             QString path(URLUtil::canonicalPath((*it).path()));
00214         QString relPath( path );
00215                 if (relPath.startsWith(projectDirectory()+ "/"))
00216                     relPath.remove(0, projectDirectory().length()+1);
00217         if (project()->isProjectFile(path))
00218             m_contextRemoveFiles << relPath;
00219         else
00220             m_contextAddFiles << relPath;
00221         }
00222     }
00223 
00224         if (m_contextAddFiles.size() > 0)
00225     {
00226             int id = popup->insertItem( i18n("Add Selected Files to Project"),
00227                                this, SLOT(slotAddToProject()) );
00228             popup->setWhatsThis(id, i18n("<b>Add to project</b><p>Adds selected files to the list of files in project. "
00229                 "Note that the files should be manually added to corresponding makefile or build.xml."));
00230     }
00231 
00232     if (m_contextRemoveFiles.size() > 0)
00233     {
00234             int id = popup->insertItem( i18n("Remove Selected Files From Project"),
00235                                this, SLOT(slotRemoveFromProject()) );
00236             popup->setWhatsThis(id, i18n("<b>Remove from project</b><p>Removes selected files from the list of files in project. "
00237                 "Note that the files should be manually excluded from corresponding makefile or build.xml."));
00238     }
00239     }
00240 }
00241 
00242 
00243 void CustomProjectPart::slotAddToProject()
00244 {
00245     addFiles(m_contextAddFiles);
00246 }
00247 
00248 
00249 void CustomProjectPart::slotRemoveFromProject()
00250 {
00251     removeFiles(m_contextRemoveFiles);
00252 }
00253 
00254 
00255 void CustomProjectPart::slotChooseActiveDirectory()
00256 {
00257     QDomDocument &dom = *projectDom();
00258     DomUtil::writeEntry(dom, "/kdevcustomproject/general/activedir", m_contextDirName);
00259 }
00260 
00261 
00262 void CustomProjectPart::openProject(const QString &dirName, const QString &projectName)
00263 {
00264     m_projectDirectory = dirName;
00265     m_projectName = projectName;
00266 
00267     QDomDocument &dom = *projectDom();
00268     // Set the default directory radio to "executable"
00269     if (DomUtil::readEntry(dom, "/kdevcustomproject/run/directoryradio") == "" ) {
00270         DomUtil::writeEntry(dom, "/kdevcustomproject/run/directoryradio", "executable");
00271     }
00272 
00273     /*this entry is currently only created by the cmake kdevelop3 project generator
00274      in order to support completely-out-of-source builds, where nothing, not
00275      even the kdevelop project files are created in the source directory, Alex <neundorf@kde.org>
00276      */
00277     QString filelistDir=DomUtil::readEntry(dom, "/kdevcustomproject/filelistdirectory");
00278     if (filelistDir.isEmpty())
00279        filelistDir=dirName;
00280 
00281     QFile f(filelistDir + "/" + projectName + ".filelist");
00282     if (f.open(IO_ReadOnly)) {
00283         QTextStream stream(&f);
00284         while (!stream.atEnd()) {
00285             QString s = stream.readLine();
00286             if (!s.startsWith("#"))
00287                 m_sourceFiles << s;
00288         }
00289     } else {
00290         int r = KMessageBox::questionYesNo(mainWindow()->main(),
00291                                            i18n("This project does not contain any files yet.\n"
00292                                                 "Populate it with all C/C++/Java files below "
00293                                                 "the project directory?"));
00294         if (r == KMessageBox::Yes)
00295             populateProject();
00296     }
00297 
00298     // check if there is an old envvars entry (from old project file with single make environment)
00299     QDomElement el =
00300         DomUtil::elementByPath( dom , "/kdevcustomproject/make/envvars");
00301     if (!el.isNull()) {
00302         QDomElement envs = DomUtil::createElementByPath( dom , "/kdevcustomproject/make/environments");
00303         DomUtil::makeEmpty(envs);
00304         el.setTagName("default");
00305         envs.appendChild(el);
00306     }
00307 
00308     KDevProject::openProject( dirName, projectName );
00309 }
00310 
00311 
00312 void CustomProjectPart::populateProject()
00313 {
00314     QApplication::setOverrideCursor(Qt::waitCursor);
00315 
00316     QValueStack<QString> s;
00317     int prefixlen = m_projectDirectory.length()+1;
00318     s.push(m_projectDirectory);
00319 
00320     QDir dir;
00321     do {
00322         dir.setPath(s.pop());
00323         kdDebug(9025) << "Examining: " << dir.path() << endl;
00324         const QFileInfoList *dirEntries = dir.entryInfoList();
00325         if ( dirEntries )
00326         {
00327             QPtrListIterator<QFileInfo> it(*dirEntries);
00328             for (; it.current(); ++it) {
00329                 QString fileName = it.current()->fileName();
00330                 if (fileName == "." || fileName == "..")
00331                     continue;
00332                 QString path = it.current()->absFilePath();
00333                 if (it.current()->isDir()) {
00334                     kdDebug(9025) << "Pushing: " << path << endl;
00335                     s.push(path);
00336                 }
00337                 else {
00338                         kdDebug(9025) << "Adding: " << path << endl;
00339                     m_sourceFiles.append(path.mid(prefixlen));
00340                 }
00341             }
00342         }
00343     } while (!s.isEmpty());
00344 
00345     QApplication::restoreOverrideCursor();
00346 }
00347 
00348 
00349 void CustomProjectPart::closeProject()
00350 {
00351     saveProject();
00352 }
00353 
00354 void CustomProjectPart::saveProject()
00355 {
00356     QFile f(m_projectDirectory + "/" + m_projectName + ".filelist");
00357     if (!f.open(IO_WriteOnly))
00358         return;
00359 
00360     QTextStream stream(&f);
00361     stream << "# KDevelop Custom Project File List" << endl;
00362 
00363     QStringList::ConstIterator it;
00364     for (it = m_sourceFiles.begin(); it != m_sourceFiles.end(); ++it)
00365         stream << (*it) << endl;
00366     f.close();
00367 }
00368 
00369 
00370 QString CustomProjectPart::projectDirectory() const
00371 {
00372     return m_projectDirectory;
00373 }
00374 
00375 
00376 QString CustomProjectPart::projectName() const
00377 {
00378     return m_projectName;
00379 }
00380 
00381 
00383 DomUtil::PairList CustomProjectPart::runEnvironmentVars() const
00384 {
00385     return DomUtil::readPairListEntry(*projectDom(), "/kdevcustomproject/run/envvars", "envvar", "name", "value");
00386 }
00387 
00388 
00398 QString CustomProjectPart::runDirectory() const
00399 {
00400     QDomDocument &dom = *projectDom();
00401 
00402     QString directoryRadioString = DomUtil::readEntry(dom, "/kdevcustomproject/run/directoryradio");
00403     QString DomMainProgram = DomUtil::readEntry(dom, "/kdevcustomproject/run/mainprogram");
00404 
00405     if ( directoryRadioString == "build" )
00406         return buildDirectory();
00407 
00408     if ( directoryRadioString == "custom" )
00409         return DomUtil::readEntry(dom, "/kdevcustomproject/run/customdirectory");
00410 
00411     int pos = DomMainProgram.findRev('/');
00412     if (pos != -1)
00413         return buildDirectory() + "/" + DomMainProgram.left(pos);
00414 
00415     return buildDirectory() + "/" + DomMainProgram;
00416 
00417 }
00418 
00419 
00429 QString CustomProjectPart::mainProgram(bool relative) const
00430 {
00431     QDomDocument &dom = *projectDom();
00432 
00433     QString directoryRadioString = DomUtil::readEntry(dom, "/kdevcustomproject/run/directoryradio");
00434     QString DomMainProgram = DomUtil::readEntry(dom, "/kdevcustomproject/run/mainprogram");
00435 
00436     if ( directoryRadioString == "custom" )
00437         return DomMainProgram;
00438 
00439     if ( relative == false )
00440         return buildDirectory() + "/" + DomMainProgram;
00441 
00442     if ( directoryRadioString == "executable" ) {
00443         int pos = DomMainProgram.findRev('/');
00444         if (pos != -1)
00445             return DomMainProgram.mid(pos+1);
00446         return DomMainProgram;
00447     }
00448     else
00449         return DomMainProgram;
00450 }
00451 
00453 QString CustomProjectPart::runArguments() const
00454 {
00455     return DomUtil::readEntry(*projectDom(), "/kdevcustomproject/run/programargs");
00456 }
00457 
00458 QString CustomProjectPart::activeDirectory() const
00459 {
00460     QDomDocument &dom = *projectDom();
00461     return DomUtil::readEntry(dom, "/kdevcustomproject/general/activedir");
00462 }
00463 
00464 
00465 QStringList CustomProjectPart::allFiles() const
00466 {
00467 //     QStringList res;
00468 //
00469 //     QStringList::ConstIterator it;
00470 //     for (it = m_sourceFiles.begin(); it != m_sourceFiles.end(); ++it) {
00471 //         QString fileName = *it;
00472 //         if (!fileName.startsWith("/")) {
00473 //             fileName.prepend("/");
00474 //             fileName.prepend(m_projectDirectory);
00475 //         }
00476 //         res += fileName;
00477 //     }
00478 //
00479 //     return res;
00480 
00481     // return all files relative to the project directory!
00482     return m_sourceFiles;
00483 }
00484 
00485 
00486 void CustomProjectPart::addFile(const QString &fileName)
00487 {
00488     QStringList fileList;
00489     fileList.append ( fileName );
00490 
00491     this->addFiles ( fileList );
00492 }
00493 
00494 void CustomProjectPart::addFiles ( const QStringList& fileList )
00495 {
00496     QStringList::ConstIterator it;
00497 
00498     for ( it = fileList.begin(); it != fileList.end(); ++it )
00499     {
00500         m_sourceFiles.append ( *it );
00501     }
00502     
00503     saveProject();
00504 
00505     kdDebug(9025) << "Emitting addedFilesToProject" << endl;
00506     emit addedFilesToProject ( fileList );
00507 }
00508 
00509 void CustomProjectPart::removeFile(const QString &fileName)
00510 {
00511     QStringList fileList;
00512     fileList.append ( fileName );
00513 
00514     this->removeFiles( fileList );
00515 }
00516 
00517 void CustomProjectPart::removeFiles ( const QStringList& fileList )
00518 {
00519     kdDebug(9025) << "Emitting removedFilesFromProject" << endl;
00520     emit removedFilesFromProject ( fileList );
00521 
00522     QStringList::ConstIterator it;
00523 
00524     for ( it = fileList.begin(); it != fileList.end(); ++it )
00525     {
00526         m_sourceFiles.remove ( *it );
00527     }
00528     
00529     saveProject();
00530 }
00531 
00532 QString CustomProjectPart::buildDirectory() const
00533 {
00534     QString dir = DomUtil::readEntry(*projectDom(), "/kdevcustomproject/build/builddir");
00535     return dir.isEmpty()? projectDirectory() : dir;
00536 }
00537 
00538 
00539 QString CustomProjectPart::makeEnvironment() const
00540 {
00541     // Get the make environment variables pairs into the environstr string
00542     // in the form of: "ENV_VARIABLE=ENV_VALUE"
00543     // Note that we quote the variable value due to the possibility of
00544     // embedded spaces
00545     DomUtil::PairList envvars =
00546         DomUtil::readPairListEntry(*projectDom(), "/kdevcustomproject/make/environments/" + currentMakeEnvironment(), "envvar", "name", "value");
00547 
00548     QString environstr;
00549     DomUtil::PairList::ConstIterator it;
00550     for (it = envvars.begin(); it != envvars.end(); ++it) {
00551         environstr += (*it).first;
00552         environstr += "=";
00553         environstr += EnvVarTools::quote((*it).second);
00554         environstr += " ";
00555     }
00556     return environstr;
00557 }
00558 
00559 
00560 void CustomProjectPart::startMakeCommand(const QString &dir, const QString &target)
00561 {
00562     partController()->saveAllFiles();
00563 
00564     QDomDocument &dom = *projectDom();
00565     bool ant = DomUtil::readEntry(dom, "/kdevcustomproject/build/buildtool") == "ant";
00566 
00567     QString cmdline;
00568     if (ant) {
00569         cmdline = "ant";
00570     } else {
00571         cmdline = DomUtil::readEntry(dom, "/kdevcustomproject/make/makebin");
00572         if (cmdline.isEmpty())
00573             cmdline = MAKE_COMMAND;
00574         if (!DomUtil::readBoolEntry(dom, "/kdevcustomproject/make/abortonerror"))
00575             cmdline += " -k";
00576         int jobs = DomUtil::readIntEntry(dom, "/kdevcustomproject/make/numberofjobs");
00577         if (jobs != 0) {
00578             cmdline += " -j";
00579             cmdline += QString::number(jobs);
00580         }
00581         if (DomUtil::readBoolEntry(dom, "/kdevcustomproject/make/dontact"))
00582             cmdline += " -n";
00583         cmdline += " " + DomUtil::readEntry(dom, "/kdevcustomproject/make/makeoptions");
00584     }
00585 
00586     cmdline += " ";
00587     cmdline += target;
00588 
00589     QString dircmd = "cd ";
00590     dircmd += KProcess::quote(dir);
00591     dircmd += " && ";
00592 
00593     int prio = DomUtil::readIntEntry(dom, "/kdevcustomproject/make/prio");
00594     QString nice;
00595     if (prio != 0) {
00596         nice = QString("nice -n%1 ").arg(prio);
00597     }
00598 
00599     cmdline.prepend(nice);
00600     cmdline.prepend(makeEnvironment());
00601     m_buildCommand = dircmd + cmdline;
00602     makeFrontend()->queueCommand(dir, dircmd + cmdline);
00603 }
00604 
00605 
00606 void CustomProjectPart::slotBuild()
00607 {
00608     m_lastCompilationFailed = false;
00609     startMakeCommand(buildDirectory(), QString::fromLatin1(""));
00610 }
00611 
00612 
00613 void CustomProjectPart::slotCompileFile()
00614 {
00615     KParts::ReadWritePart *part = dynamic_cast<KParts::ReadWritePart*>(partController()->activePart());
00616     if (!part || !part->url().isLocalFile())
00617         return;
00618 
00619     QString fileName = part->url().path();
00620     QFileInfo fi(fileName);
00621     QString sourceDir = fi.dirPath();
00622     QString baseName = fi.baseName(true);
00623     kdDebug(9020) << "Compiling " << fileName
00624                   << "in dir " << sourceDir
00625                   << " with baseName " << baseName << endl;
00626 
00627     // What would be nice: In case of non-recursive build system, climb up from
00628     // the source dir until a Makefile is found
00629 
00630     QString buildDir = sourceDir;
00631     QString target = baseName + ".o";
00632     kdDebug(9020) << "builddir " << buildDir << ", target " << target << endl;
00633 
00634     startMakeCommand(buildDir, target);
00635 }
00636 
00637 
00638 void CustomProjectPart::slotClean()
00639 {
00640     startMakeCommand(buildDirectory(), QString::fromLatin1("clean"));
00641 }
00642 
00643 
00644 void CustomProjectPart::slotExecute()
00645 {
00646     partController()->saveAllFiles();
00647 
00648     if( DomUtil::readBoolEntry(*projectDom(), "/kdevcustomproject/run/autocompile", true) && isDirty() ){
00649         m_executeAfterBuild = true;
00650         slotBuild();
00651         return;
00652     }
00653 
00654     // Get the run environment variables pairs into the environstr string
00655     // in the form of: "ENV_VARIABLE=ENV_VALUE"
00656     // Note that we quote the variable value due to the possibility of
00657     // embedded spaces
00658     DomUtil::PairList envvars = runEnvironmentVars();
00659     QString environstr;
00660     DomUtil::PairList::ConstIterator it;
00661     for (it = envvars.begin(); it != envvars.end(); ++it) {
00662         environstr += (*it).first;
00663         environstr += "=";
00664         environstr += EnvVarTools::quote((*it).second);
00665         environstr += " ";
00666     }
00667 
00668     if (mainProgram(true).isEmpty())
00669     // Do not execute non executable targets
00670         return;
00671 
00672     QString program = environstr;
00673     // Adds the ./ that is necessary to execute the program in bash shells
00674     if (!mainProgram(true).startsWith("/"))
00675         program += "./";
00676     program += mainProgram(true);
00677     program += " " + runArguments();
00678 
00679     bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevcustomproject/run/terminal");
00680 
00681     kdDebug(9025) << "runDirectory: <" << runDirectory() << ">" <<endl;
00682     kdDebug(9025) << "environstr  : <" << environstr << ">" <<endl;
00683     kdDebug(9025) << "mainProgram : <" << mainProgram(true) << ">" <<endl;
00684     kdDebug(9025) << "runArguments: <" << runArguments() << ">" <<endl;
00685 
00686     appFrontend()->startAppCommand(runDirectory(), program, inTerminal);
00687 }
00688 
00689 
00690 void CustomProjectPart::updateTargetMenu()
00691 {
00692     m_targets.clear();
00693     m_targetMenu->clear();
00694 
00695     QDomDocument &dom = *projectDom();
00696     bool ant = DomUtil::readEntry(dom, "/kdevcustomproject/build/buildtool") == "ant";
00697 
00698     if (ant) {
00699         QFile f(buildDirectory() + "/build.xml");
00700         if (!f.open(IO_ReadOnly)) {
00701             kdDebug(9025) << "No build file" << endl;
00702             return;
00703         }
00704         QDomDocument dom;
00705         if (!dom.setContent(&f)) {
00706             kdDebug(9025) << "Build script not valid xml" << endl;
00707             f.close();
00708             return;
00709         }
00710         f.close();
00711 
00712         QDomNode node = dom.documentElement().firstChild();
00713         while (!node.isNull()) {
00714             if (node.toElement().tagName() == "target")
00715                 m_targets.append(node.toElement().attribute("name"));
00716             node = node.nextSibling();
00717         }
00718     } else {
00719         kdDebug(9025) << "Trying to load a makefile... " << endl;
00720         QFile f(buildDirectory() + "/Makefile");
00721     if (!f.exists())
00722         f.setName( buildDirectory() + "/makefile" );
00723         if (!f.open(IO_ReadOnly)) {
00724             kdDebug(9025) << "No Makefile" << endl;
00725             return;
00726         }
00727         QTextStream stream(&f);
00728         //QRegExp re(".PHONY\\s*:(.*)");
00729     QRegExp re("^([^($%.#][^)\\s]+):.*$");
00730     re.setMinimal(true);
00731     QString str = "";
00732         while (!stream.atEnd()) {
00733             QString str = stream.readLine();
00734             // Read all continuation lines
00735         // kdDebug(9025) << "Trying: " << str.simplifyWhiteSpace() << endl;
00736             //while (str.right(1) == "\\" && !stream.atEnd()) {
00737             //    str.remove(str.length()-1, 1);
00738             //    str += stream.readLine();
00739             //}
00740             if (re.search(str) != -1)
00741             {
00742                 QString tmpTarget=re.cap(1).simplifyWhiteSpace();
00743             kdDebug(9025) << "Adding target: " << tmpTarget << endl;
00744                 if (m_targets.find(tmpTarget)==m_targets.end())
00745                    m_targets += tmpTarget;
00746             }
00747         }
00748         f.close();
00749         m_targets.sort();
00750     }
00751 
00752     int id = 0;
00753     QStringList::ConstIterator it;
00754     for (it = m_targets.begin(); it != m_targets.end(); ++it)
00755         m_targetMenu->insertItem(*it, id++);
00756 }
00757 
00758 
00759 void CustomProjectPart::targetMenuActivated(int id)
00760 {
00761     QString target = m_targets[id];
00762     startMakeCommand(buildDirectory(), target);
00763 }
00764 
00765 void CustomProjectPart::updateMakeEnvironmentsMenu()
00766 {
00767     QDomDocument &dom = *projectDom();
00768     bool makeUsed = (DomUtil::readEntry(dom, "/kdevcustomproject/build/buildtool") == "make");
00769     if (makeUsed) {
00770         QStringList l = allMakeEnvironments();
00771         m_makeEnvironmentsSelector->setItems(l);
00772         m_makeEnvironmentsSelector->setCurrentItem(l.findIndex(currentMakeEnvironment()));
00773     }
00774     else {
00775         m_makeEnvironmentsSelector->clear();
00776     }
00777     /*
00778     m_makeEnvironmentsMenu->clear();
00779     QDomDocument &dom = *projectDom();
00780 
00781         QStringList environments = allMakeEnvironments();
00782         QStringList::ConstIterator it;
00783         int id = 0;
00784         for (it = environments.begin(); it != environments.end(); ++it)
00785             m_makeEnvironmentsMenu->insertItem(*it, id++);
00786     }
00787     */
00788 }
00789 
00790 void CustomProjectPart::makeEnvironmentsMenuActivated(int id)
00791 {
00792     QDomDocument &dom = *projectDom();
00793     QString environment = allMakeEnvironments()[id];
00794     DomUtil::writeEntry(dom, "/kdevcustomproject/make/selectedenvironment", environment);
00795 }
00796 
00797 void CustomProjectPart::slotCommandFinished( const QString& command )
00798 {
00799     kdDebug(9020) << "CustomProjectPart::slotProcessFinished()" << endl;
00800 
00801     if( m_buildCommand != command )
00802         return;
00803 
00804     m_buildCommand = QString::null;
00805 
00806     m_timestamp.clear();
00807     QStringList fileList = allFiles();
00808     QStringList::Iterator it = fileList.begin();
00809     while( it != fileList.end() ){
00810         QString fileName = *it;
00811         ++it;
00812 
00813         m_timestamp[ fileName ] = QFileInfo( projectDirectory(), fileName ).lastModified();
00814     }
00815 
00816     emit projectCompiled();
00817 
00818     if( m_executeAfterBuild ){
00819         slotExecute();
00820         m_executeAfterBuild = false;
00821     }
00822 }
00823 
00824 void CustomProjectPart::slotCommandFailed( const QString& /*command*/ )
00825 {
00826     kdDebug(9020) << k_funcinfo << endl;
00827 
00828     m_lastCompilationFailed = true;
00829 }
00830 
00831 bool CustomProjectPart::isDirty()
00832 {
00833     if (m_lastCompilationFailed) return true;
00834 
00835     QStringList fileList = allFiles();
00836     QStringList::Iterator it = fileList.begin();
00837     while( it != fileList.end() ){
00838         QString fileName = *it;
00839         ++it;
00840 
00841         QMap<QString, QDateTime>::Iterator it = m_timestamp.find( fileName );
00842         QDateTime t = QFileInfo( projectDirectory(), fileName ).lastModified();
00843         if( it == m_timestamp.end() || *it != t ){
00844             return true;
00845         }
00846     }
00847 
00848     return false;
00849 }
00850 
00851 
00852 QStringList CustomProjectPart::allMakeEnvironments() const
00853 {
00854     QDomDocument &dom = *projectDom();
00855 
00856     QStringList allConfigs;
00857 
00858     QDomNode node =
00859         DomUtil::elementByPath( dom , "/kdevcustomproject/make/environments");
00860     // extract the names of the different make environments
00861     QDomElement childEl = node.firstChild().toElement();
00862     while (!childEl.isNull()) {
00863         QString config = childEl.tagName();
00864         allConfigs.append(config);
00865         childEl = childEl.nextSibling().toElement();
00866     }
00867     if (allConfigs.isEmpty())
00868         allConfigs.append("default");
00869 
00870     return allConfigs;
00871 }
00872 
00873 
00874 QString CustomProjectPart::currentMakeEnvironment() const
00875 {
00876     QStringList allEnvs = allMakeEnvironments();
00877     QDomDocument &dom = *projectDom();
00878     QString environment = DomUtil::readEntry(dom, "/kdevcustomproject/make/selectedenvironment");
00879     if (environment.isEmpty() || !allEnvs.contains(environment ))
00880         environment  = allEnvs[0];
00881     return environment;
00882 }
00883 
00884 
00885 #include "customprojectpart.moc"
00886 
00887 
00891 QStringList CustomProjectPart::distFiles() const
00892 {
00893     QStringList sourceList = allFiles();
00894     // Scan current source directory for any .pro files.
00895     QString projectDir = projectDirectory();
00896     QDir dir(projectDir);
00897     QStringList files = dir.entryList( "*README*");
00898     return sourceList + files;
00899 }
KDE Logo
This file is part of the documentation for KDevelop Version 3.1.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Feb 22 09:22:22 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003