00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <qdom.h>
00012 #include <qfileinfo.h>
00013 #include <qdir.h>
00014 #include <qvaluestack.h>
00015 #include <qregexp.h>
00016 #include <qvbox.h>
00017 #include <qlabel.h>
00018
00019 #include <kiconloader.h>
00020 #include <klocale.h>
00021 #include <kaction.h>
00022 #include <kdevgenericfactory.h>
00023 #include <kdebug.h>
00024 #include <kdialogbase.h>
00025 #include <kmessagebox.h>
00026 #include <klibloader.h>
00027 #include <kservice.h>
00028 #include <kconfig.h>
00029 #include <kdeversion.h>
00030 #include <kprocess.h>
00031
00032 #include "domutil.h"
00033 #include "kdevcore.h"
00034 #include "kdevmainwindow.h"
00035 #include "kdevmakefrontend.h"
00036 #include "kdevappfrontend.h"
00037 #include "kdevpartcontroller.h"
00038 #include "kdevlanguagesupport.h"
00039 #include "kdevcompileroptions.h"
00040 #include "runoptionswidget.h"
00041 #include "envvartools.h"
00042
00043 #include "pascalproject_widget.h"
00044 #include "pascalproject_part.h"
00045 #include "pascalprojectoptionsdlg.h"
00046 #include "pascalglobaloptionsdlg.h"
00047
00048 typedef KDevGenericFactory<PascalProjectPart> PascalProjectFactory;
00049 static const KAboutData data("kdevpascalproject", I18N_NOOP("Build Tool"), "1.0");
00050 K_EXPORT_COMPONENT_FACTORY( libkdevpascalproject, PascalProjectFactory( &data ) )
00051
00052 PascalProjectPart::PascalProjectPart(QObject *parent, const char *name, const QStringList& )
00053 :KDevProject("PascalProject", "pascalproject", parent, name ? name : "PascalProjectPart" )
00054 {
00055 setInstance(PascalProjectFactory::instance());
00056 setXMLFile("kdevpascalproject.rc");
00057
00058 KAction *action;
00059 action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8,
00060 this, SLOT(slotBuild()),
00061 actionCollection(), "build_build" );
00062 action->setToolTip(i18n("Build project"));
00063 action->setWhatsThis(i18n("<b>Build project</b><p>Runs the compiler on a main source file of the project. "
00064 "The compiler and the main source file can be set in project settings, <b>Pascal Compiler</b> tab."));
00065 action = new KAction( i18n("Execute Program"), "exec", 0,
00066 this, SLOT(slotExecute()),
00067 actionCollection(), "build_execute" );
00068 action->setToolTip(i18n("Execute program"));
00069 action->setWhatsThis(i18n("<b>Execute program</b><p>Executes the main program specified in project settings, <b>Run options</b> tab. "
00070 "If nothing is set, the binary file with the same name as the main source file name is executed."));
00071
00072 connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
00073 this, SLOT(projectConfigWidget(KDialogBase*)) );
00074
00075 connect( core(), SIGNAL(configWidget(KDialogBase*)),
00076 this, SLOT(configWidget(KDialogBase*)) );
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 }
00091
00092 PascalProjectPart::~PascalProjectPart()
00093 {
00094
00095 }
00096
00101 static bool matchesPattern(const QString &fileName, const QStringList &patternList)
00102 {
00103 QStringList::ConstIterator it;
00104 for (it = patternList.begin(); it != patternList.end(); ++it) {
00105 QRegExp re(*it, true, true);
00106 if (re.search(fileName) == 0 && re.matchedLength() == (int)fileName.length())
00107 return true;
00108 }
00109
00110 return false;
00111 }
00112
00113 void PascalProjectPart::openProject(const QString &dirName, const QString &projectName)
00114 {
00115 m_buildDir = dirName;
00116 m_projectDir = dirName;
00117 m_projectName = projectName;
00118
00119 QDomDocument &dom = *projectDom();
00120
00121 if (DomUtil::readEntry(dom, "/kdevpascalproject/run/directoryradio") == "" ) {
00122 DomUtil::writeEntry(dom, "/kdevpascalproject/run/directoryradio", "executable");
00123 }
00124
00125 loadProjectConfig();
00126
00127
00128 QValueStack<QString> s;
00129 int prefixlen = m_projectDir.length()+1;
00130 s.push(m_projectDir);
00131
00132 QStringList includepatternList;
00133 if ( languageSupport() )
00134 {
00135 KMimeType::List list = languageSupport()->mimeTypes();
00136 KMimeType::List::Iterator it = list.begin();
00137 while( it != list.end() ){
00138 includepatternList += (*it)->patterns();
00139 ++it;
00140 }
00141 }
00142 QString excludepatterns = "*~";
00143 QStringList excludepatternList = QStringList::split(",", excludepatterns);
00144
00145 QDir dir;
00146 do {
00147 dir.setPath(s.pop());
00148 kdDebug(9033) << "Examining: " << dir.path() << endl;
00149 const QFileInfoList *dirEntries = dir.entryInfoList();
00150 QPtrListIterator<QFileInfo> it(*dirEntries);
00151 for (; it.current(); ++it) {
00152 QString fileName = it.current()->fileName();
00153 if (fileName == "." || fileName == "..")
00154 continue;
00155 QString path = it.current()->absFilePath();
00156 if (it.current()->isDir()) {
00157 kdDebug(9033) << "Pushing: " << path << endl;
00158 s.push(path);
00159 }
00160 else {
00161 if (matchesPattern(path, includepatternList)
00162 && !matchesPattern(path, excludepatternList)) {
00163 kdDebug(9033) << "Adding: " << path << endl;
00164 m_sourceFiles.append(path.mid(prefixlen));
00165 } else {
00166 kdDebug(9033) << "Ignoring: " << path << endl;
00167 }
00168 }
00169 }
00170 } while (!s.isEmpty());
00171
00172 KDevProject::openProject( dirName, projectName );
00173 }
00174
00175 void PascalProjectPart::closeProject()
00176 {
00177 }
00178
00180 DomUtil::PairList PascalProjectPart::runEnvironmentVars() const
00181 {
00182 return DomUtil::readPairListEntry(*projectDom(), "/kdevpascalproject/run/envvars", "envvar", "name", "value");
00183 }
00184
00185
00195 QString PascalProjectPart::runDirectory() const
00196 {
00197 QDomDocument &dom = *projectDom();
00198
00199 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevpascalproject/run/directoryradio");
00200 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevpascalproject/run/mainprogram");
00201
00202 if ( directoryRadioString == "build" )
00203 return buildDirectory();
00204
00205 if ( directoryRadioString == "custom" )
00206 return DomUtil::readEntry(dom, "/kdevpascalproject/run/customdirectory");
00207
00208 int pos = DomMainProgram.findRev('/');
00209 if (pos != -1)
00210 return buildDirectory() + "/" + DomMainProgram.left(pos);
00211
00212 return buildDirectory() + "/" + DomMainProgram;
00213
00214 }
00215
00216
00226 QString PascalProjectPart::mainProgram(bool relative) const
00227 {
00228 QDomDocument &dom = *projectDom();
00229 QString configMainProg = DomUtil::readEntry(dom, "/kdevpascalproject/run/mainprogram", "");
00230 if (configMainProg.isEmpty())
00231 {
00232 QFileInfo fi(mainSource());
00233 return buildDirectory() + "/" + fi.baseName();
00234 }
00235 else
00236 return QDir::cleanDirPath(projectDirectory() + "/" + configMainProg);
00237
00239 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevpascalproject/run/directoryradio");
00240 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevpascalproject/run/mainprogram");
00241
00242 if ( directoryRadioString == "custom" )
00243 return DomMainProgram;
00244
00245 if ( relative == false )
00246 return buildDirectory() + "/" + DomMainProgram;
00247
00248 if ( directoryRadioString == "executable" ) {
00249 int pos = DomMainProgram.findRev('/');
00250 if (pos != -1)
00251 return DomMainProgram.mid(pos+1);
00252 return DomMainProgram;
00253 }
00254 else
00255 return DomMainProgram;
00256 }
00257
00258
00260 QString PascalProjectPart::runArguments() const
00261 {
00262 return DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/programargs");
00263 }
00264
00265 QString PascalProjectPart::mainSource() const
00266 {
00267 return projectDirectory() + "/" + m_mainSource;
00268 }
00269
00270 void PascalProjectPart::setMainSource(QString fullPath)
00271 {
00272 m_mainSource = fullPath.replace(QRegExp(QString(projectDirectory() + QString("/"))),"");
00273 }
00274
00275 QString PascalProjectPart::projectDirectory() const
00276 {
00277 return m_projectDir;
00278 }
00279
00280 QString PascalProjectPart::projectName() const
00281 {
00282 return m_projectName;
00283 }
00284
00285 QString PascalProjectPart::activeDirectory() const
00286 {
00287 QFileInfo fi(mainSource());
00288 return fi.dirPath(true).replace(QRegExp(projectDirectory()),"");
00289 }
00290
00291 QString PascalProjectPart::buildDirectory() const
00292 {
00293 QFileInfo fi(mainSource());
00294 return fi.dirPath(true);
00295 }
00296
00297 void PascalProjectPart::listOfFiles(QStringList &result, QString path) const
00298 {
00299 QDir d(path);
00300 if (!d.exists())
00301 return;
00302 QFileInfoList *entries = const_cast<QFileInfoList*>(d.entryInfoList(QDir::Dirs | QDir::Files | QDir::Hidden));
00303 for (QFileInfo *it = entries->first(); it; it = entries->next())
00304 {
00305 if ((it->isDir()) && (it->filePath() != path))
00306 {
00307
00308 listOfFiles(result, it->dirPath());
00309 }
00310 else
00311 {
00312
00313 result << it->filePath();
00314 }
00315 }
00316 }
00317
00318 QStringList PascalProjectPart::allFiles() const
00319 {
00320
00321
00322
00323
00324
00325 return m_sourceFiles;
00326 }
00327
00328 void PascalProjectPart::addFile(const QString& )
00329 {
00330 }
00331
00332 void PascalProjectPart::addFiles(const QStringList& )
00333 {
00334 }
00335
00336 void PascalProjectPart::removeFile(const QString& )
00337 {
00338 }
00339
00340 void PascalProjectPart::removeFiles(const QStringList& )
00341 {
00342 }
00343
00344 void PascalProjectPart::slotBuild()
00345 {
00346 partController()->saveAllFiles();
00347
00348 QString cmdline = m_compilerExec + " " + m_compilerOpts + " ";
00349
00350 if (cmdline.isEmpty())
00351 {
00352 KMessageBox::sorry(0, i18n("Could not find pascal compiler.\nCheck if your compiler settings are correct."));
00353 return;
00354 }
00355
00356 QFileInfo fi(mainSource());
00357 cmdline += fi.fileName();
00358
00359 QString dircmd = "cd ";
00360 dircmd += KProcess::quote(buildDirectory());
00361 dircmd += " && ";
00362
00363 makeFrontend()->queueCommand(buildDirectory(), dircmd + cmdline);
00364 }
00365
00366 void PascalProjectPart::slotExecute()
00367 {
00368 partController()->saveAllFiles();
00369
00370 QDomDocument &dom = *(projectDom());
00371 bool runInTerminal = DomUtil::readBoolEntry(dom, "/kdevpascalproject/run/terminal", true);
00372
00373
00374
00375
00376
00377 DomUtil::PairList envvars =
00378 DomUtil::readPairListEntry(*projectDom(), "/kdevpascalproject/run/envvars", "envvar", "name", "value");
00379
00380 QString environstr;
00381 DomUtil::PairList::ConstIterator it;
00382 for (it = envvars.begin(); it != envvars.end(); ++it) {
00383 environstr += (*it).first;
00384 environstr += "=";
00385
00386
00387
00388
00389
00390
00391
00392 environstr += EnvVarTools::quote((*it).second);
00393 environstr += " ";
00394 }
00395
00396 QString program = mainProgram();
00397 program.prepend(environstr);
00398 program += " " + DomUtil::readEntry(*projectDom(), "/kdevpascalproject/run/programargs");
00399
00400 appFrontend()->startAppCommand(buildDirectory(), program, runInTerminal);
00401 }
00402
00403 void PascalProjectPart::changedFiles( const QStringList & fileList )
00404 {
00405 KDevProject::changedFiles(fileList);
00406 }
00407
00408 void PascalProjectPart::changedFile( const QString & fileName )
00409 {
00410 KDevProject::changedFile(fileName);
00411 }
00412
00413 void PascalProjectPart::projectConfigWidget( KDialogBase * dlg )
00414 {
00415 QVBox *vbox;
00416 vbox = dlg->addVBoxPage(i18n("Pascal Compiler"));
00417 PascalProjectOptionsDlg *w = new PascalProjectOptionsDlg(this, vbox);
00418 connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) );
00419 connect( dlg, SIGNAL(okClicked()), this, SLOT(loadProjectConfig()) );
00420
00421 vbox = dlg->addVBoxPage(i18n("Run Options"));
00422 RunOptionsWidget *w3 = new RunOptionsWidget(*projectDom(), "/kdevpascalproject", buildDirectory(), vbox);
00423 w3->mainprogram_label->setText(i18n("Main program (relative to project directory):"));
00424 connect( dlg, SIGNAL(okClicked()), w3, SLOT(accept()) );
00425
00426 }
00427
00428 void PascalProjectPart::loadProjectConfig( )
00429 {
00430 QDomDocument &dom = *(projectDom());
00431
00432 QString config = DomUtil::readEntry(dom, "/kdevpascalproject/general/useconfiguration", "default");
00433 m_mainSource = DomUtil::readEntry(dom, QString("/kdevpascalproject/configurations/") + config + QString("/mainsource") );
00434 m_compilerOpts = DomUtil::readEntry(dom, QString("/kdevpascalproject/configurations/") + config + QString("/compileroptions"));
00435 m_compilerExec = DomUtil::readEntry(dom, QString("/kdevpascalproject/configurations/") + config + QString("/compilerexec"));
00436
00437 if (m_compilerExec.isEmpty())
00438 {
00439 KTrader::OfferList offers = KTrader::self()->query("KDevelop/CompilerOptions", "[X-KDevelop-Language] == 'Pascal'");
00440 QValueList<KService::Ptr>::ConstIterator it;
00441 for (it = offers.begin(); it != offers.end(); ++it) {
00442 if ((*it)->property("X-KDevelop-Default").toBool()) {
00443 m_compilerExec = (*it)->exec();
00444 break;
00445 }
00446 }
00447 }
00448 }
00449
00450 void PascalProjectPart::configWidget( KDialogBase * dlg )
00451 {
00452 QVBox *vbox;
00453 vbox = dlg->addVBoxPage(i18n("Pascal Compiler"));
00454 PascalGlobalOptionsDlg *w = new PascalGlobalOptionsDlg(this, vbox);
00455 connect( dlg, SIGNAL(okClicked()), w, SLOT(accept()) );
00456 }
00457
00458 KDevCompilerOptions *PascalProjectPart::createCompilerOptions(const QString &name)
00459 {
00460 KService::Ptr service = KService::serviceByDesktopName(name);
00461 if (!service) {
00462 kdDebug() << "Can't find service " << name;
00463 return 0;
00464 }
00465
00466 KLibFactory *factory = KLibLoader::self()->factory(QFile::encodeName(service->library()));
00467 if (!factory) {
00468 QString errorMessage = KLibLoader::self()->lastErrorMessage();
00469 KMessageBox::error(0, i18n("There was an error loading the module %1.\n"
00470 "The diagnostics is:\n%2").arg(service->name()).arg(errorMessage));
00471 exit(1);
00472 }
00473
00474 QStringList args;
00475 QVariant prop = service->property("X-KDevelop-Args");
00476 if (prop.isValid())
00477 args = QStringList::split(" ", prop.toString());
00478
00479 QObject *obj = factory->create(this, service->name().latin1(),
00480 "KDevCompilerOptions", args);
00481
00482 if (!obj->inherits("KDevCompilerOptions")) {
00483 kdDebug() << "Component does not inherit KDevCompilerOptions" << endl;
00484 return 0;
00485 }
00486 KDevCompilerOptions *dlg = (KDevCompilerOptions*) obj;
00487
00488 return dlg;
00489 }
00490
00491 QString PascalProjectPart::defaultOptions( const QString compiler ) const
00492 {
00493 KConfig *config = KGlobal::config();
00494 config->setGroup("Pascal Compiler");
00495 return config->readPathEntry(compiler);
00496 }
00497
00498 #include "pascalproject_part.moc"
00499
00500
00504 QStringList PascalProjectPart::distFiles() const
00505 {
00506 QStringList sourceList = allFiles();
00507
00508 QString projectDir = projectDirectory();
00509 QDir dir(projectDir);
00510 QStringList files = dir.entryList( "Makefile");
00511 return sourceList + files;
00512 }