00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "trollprojectpart.h"
00017
00018 #include <qdir.h>
00019 #include <qfileinfo.h>
00020 #include <qwhatsthis.h>
00021 #include <kdeversion.h>
00022 #include <kdebug.h>
00023 #include <kdialogbase.h>
00024 #include <kiconloader.h>
00025 #include <klocale.h>
00026 #include <kmessagebox.h>
00027 #include <qmessagebox.h>
00028 #include <kdevgenericfactory.h>
00029 #include <kaction.h>
00030 #include <kparts/part.h>
00031 #include <kprocess.h>
00032 #include <makeoptionswidget.h>
00033
00034
00035 #include "domutil.h"
00036 #include "kdevcore.h"
00037 #include "kdevmainwindow.h"
00038 #include "kdevmakefrontend.h"
00039 #include "kdevappfrontend.h"
00040 #include "kdevpartcontroller.h"
00041 #include "trollprojectwidget.h"
00042 #include "runoptionswidget.h"
00043 #include "config.h"
00044 #include "envvartools.h"
00045
00046
00047 typedef KDevGenericFactory<TrollProjectPart> TrollProjectFactory;
00048 static const KAboutData data("kdevtrollproject", I18N_NOOP("QMake Manager"), "1.0");
00049 K_EXPORT_COMPONENT_FACTORY( libkdevtrollproject, TrollProjectFactory( &data ) )
00050
00051 TrollProjectPart::TrollProjectPart(QObject *parent, const char *name, const QStringList& args )
00052 : KDevProject("TrollProject", "trollproject", parent, name ? name : "TrollProjectPart")
00053 {
00054 setInstance(TrollProjectFactory::instance());
00055
00056 if ( args.count() == 1 && args[0] == "TMake" )
00057 m_tmakeProject = true;
00058 else
00059 m_tmakeProject = false;
00060
00061 setXMLFile("kdevtrollproject.rc");
00062
00063 m_executeAfterBuild = false;
00064
00065 m_widget = new TrollProjectWidget(this);
00066 m_widget->setIcon(SmallIcon("make"));
00067 m_widget->setCaption(i18n("QMake Manager"));
00068 QWhatsThis::add(m_widget, i18n("<b>QMake manager</b><p>"
00069 "The QMake manager project tree consists of two parts. The 'overview' "
00070 "in the upper half shows the subprojects, each one having a "
00071 ".pro file. The 'details' view in the lower half shows the "
00072 "list of files for the active subproject selected in the overview."));
00073
00074 mainWindow()->embedSelectViewRight(m_widget, i18n("QMake Manager"), i18n("QMake manager"));
00075
00076 KAction *action;
00077
00078 const QIconSet icon(SmallIcon("compfile"));
00079 action = new KAction( i18n("Compile &File"), "compfile", 0,
00080 m_widget, SLOT(slotBuildFile()),
00081 actionCollection(),"build_compilefile" );
00082 action->setToolTip(i18n("Compile file"));
00083 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>"
00084 "Environment variables and make arguments can be specified "
00085 "in the project settings dialog, <b>Make Options</b> tab."));
00086
00087
00088 action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8,
00089 m_widget, SLOT(slotBuildProject()),
00090 actionCollection(), "build_build_project" );
00091 action->setToolTip(i18n("Build project"));
00092 action->setWhatsThis(i18n("<b>Build project</b><p>Runs <b>make</b> from the project directory.<br>"
00093 "Environment variables and make arguments can be specified "
00094 "in the project settings dialog, <b>Make Options</b> tab."));
00095
00096 action = new KAction( i18n("&Rebuild Project"),"rebuild" , 0,
00097 m_widget, SLOT(slotRebuildProject()),
00098 actionCollection(),"build_rebuild_project" );
00099 action->setToolTip(i18n("Rebuild project"));
00100 action->setWhatsThis(i18n("<b>Rebuild project</b><p>Runs <b>make clean</b> and then <b>make</b> from the project directory.<br>"
00101 "Environment variables and make arguments can be specified "
00102 "in the project settings dialog, <b>Make Options</b> tab."));
00103
00104 action = new KAction( i18n("&Clean Project"), 0,
00105 m_widget, SLOT(slotCleanProject()),
00106 actionCollection(), "build_clean_project" );
00107 action->setToolTip(i18n("Clean project"));
00108 action->setWhatsThis(i18n("<b>Clean project</b><p>Runs <b>make clean</b> command from the project directory.<br>"
00109 "Environment variables and make arguments can be specified "
00110 "in the project settings dialog, <b>Make Options</b> tab."));
00111
00112 action = new KAction( i18n("Execute Main Program"), "exec", SHIFT+Key_F9,
00113 m_widget, SLOT(slotExecuteProject()),
00114 actionCollection(), "build_execute_project" );
00115 action->setToolTip(i18n("Execute main program"));
00116 action->setWhatsThis(i18n("<b>Execute program</b><p>Executes the main program specified in project settings, <b>Run Options</b> tab."));
00117
00118
00119
00120
00121
00122 action = new KAction( i18n("&Build Subproject"), "make_kdevelop", Key_F7,
00123 m_widget, SLOT(slotBuildTarget()),
00124 actionCollection(), "build_build_target" );
00125 action->setToolTip(i18n("Build subproject"));
00126 action->setWhatsThis(i18n("<b>Build subproject</b><p>Runs <b>make</b> from the current subproject directory. "
00127 "Current subproject is a subproject selected in <b>QMake manager</b> 'overview' window.<br>"
00128 "Environment variables and make arguments can be specified "
00129 "in the project settings dialog, <b>Make Options</b> tab."));
00130
00131 action = new KAction( i18n("&Rebuild Subproject"), "rebuild", 0,
00132 m_widget, SLOT(slotRebuildTarget()),
00133 actionCollection(),"build_rebuild_target" );
00134 action->setToolTip(i18n("Rebuild subproject"));
00135 action->setWhatsThis(i18n("<b>Rebuild subproject</b><p>Runs <b>make clean</b> and then <b>make</b> from the current subproject directory. "
00136 "Current subproject is a subproject selected in <b>QMake manager</b> 'overview' window.<br>"
00137 "Environment variables and make arguments can be specified "
00138 "in the project settings dialog, <b>Make Options</b> tab."));
00139
00140 action = new KAction( i18n("&Clean Subproject"), 0,
00141 m_widget, SLOT(slotCleanTarget()),
00142 actionCollection(), "build_clean_target" );
00143 action->setToolTip(i18n("Clean subproject"));
00144 action->setWhatsThis(i18n("<b>Clean subproject</b><p>Runs <b>make clean</b> from the current subproject directory. "
00145 "Current subproject is a subproject selected in <b>QMake manager</b> 'overview' window.<br>"
00146 "Environment variables and make arguments can be specified "
00147 "in the project settings dialog, <b>Make Options</b> tab."));
00148
00149 action = new KAction( i18n("Execute Subproject"), "exec", 0,
00150 m_widget, SLOT(slotExecuteTarget()),
00151 actionCollection(), "build_execute_target" );
00152 action->setToolTip(i18n("Execute subproject"));
00153 action->setWhatsThis(i18n("<b>Execute subproject</b><p>Executes the target program for the currently selected subproject. "
00154 "This action is allowed only if a type of the subproject is 'application'. The type of the subproject can be "
00155 "defined in <b>Subproject Settings</b> dialog (open it from the subproject context menu)."));
00156
00157 connect( core(), SIGNAL(projectConfigWidget(KDialogBase*)),
00158 this, SLOT(projectConfigWidget(KDialogBase*)) );
00159
00160 connect( makeFrontend(), SIGNAL(commandFinished(const QString&)),
00161 this, SLOT(slotCommandFinished(const QString&)) );
00162
00163 m_qmakeHeader = i18n("# File generated by kdevelop's qmake manager. \n"
00164 "# ------------------------------------------- \n"
00165 "# Subdir relative project main directory: %s\n"
00166 "# Target is %s %s\n");
00167
00168 m_availableQtDirList = availableQtDirList();
00169 m_defaultQtDir = ::getenv( "QTDIR" );
00170 if( m_defaultQtDir.isEmpty() && !m_availableQtDirList.isEmpty() )
00171 m_defaultQtDir = m_availableQtDirList.front();
00172 }
00173
00174
00175 TrollProjectPart::~TrollProjectPart()
00176 {
00177 if (m_widget)
00178 mainWindow()->removeView(m_widget);
00179 delete m_widget;
00180 }
00181
00182 QString TrollProjectPart::makeEnvironment()
00183 {
00184
00185
00186
00187
00188 DomUtil::PairList envvars =
00189 DomUtil::readPairListEntry(*projectDom(), "/kdevtrollproject/make/envvars", "envvar", "name", "value");
00190
00191 QString environstr;
00192 DomUtil::PairList::ConstIterator it;
00193 bool hasQtDir = false;
00194 for (it = envvars.begin(); it != envvars.end(); ++it) {
00195 if( (*it).first == "QTDIR" )
00196 hasQtDir = true;
00197
00198 environstr += (*it).first;
00199 environstr += "=";
00200
00201
00202
00203
00204
00205
00206
00207 environstr += EnvVarTools::quote((*it).second);
00208 environstr += " ";
00209 }
00210
00211 if( !hasQtDir && !m_defaultQtDir.isEmpty() )
00212 {
00213 environstr += QString( "QTDIR=" ) + EnvVarTools::quote( m_defaultQtDir ) + QString( " " );
00214 }
00215
00216 return environstr;
00217 }
00218
00219 void TrollProjectPart::projectConfigWidget(KDialogBase *dlg)
00220 {
00221 QVBox *vbox;
00222 vbox = dlg->addVBoxPage(i18n("Run Options"));
00223 RunOptionsWidget *optdlg = new RunOptionsWidget(*projectDom(), "/kdevtrollproject", buildDirectory(), vbox);
00224
00225 vbox = dlg->addVBoxPage(i18n("Make Options"));
00226 MakeOptionsWidget *w4 = new MakeOptionsWidget(*projectDom(), "/kdevtrollproject", vbox);
00227 connect( dlg, SIGNAL(okClicked()), w4, SLOT(accept()) );
00228
00229 connect( dlg, SIGNAL(okClicked()), optdlg, SLOT(accept()) );
00230 }
00231
00232
00233 void TrollProjectPart::openProject(const QString &dirName, const QString &projectName)
00234 {
00235 m_widget->openProject(dirName);
00236 m_projectName = projectName;
00237
00238 QDomDocument &dom = *projectDom();
00239
00240 if (DomUtil::readEntry(dom, "/kdevtrollproject/run/directoryradio") == "" ) {
00241 DomUtil::writeEntry(dom, "/kdevtrollproject/run/directoryradio", "executable");
00242 }
00243
00244 KDevProject::openProject( dirName, projectName );
00245 }
00246
00247
00248 void TrollProjectPart::closeProject()
00249 {
00250 m_widget->closeProject();
00251 }
00252
00253
00254 QString TrollProjectPart::projectDirectory() const
00255 {
00256 return m_widget->projectDirectory();
00257 }
00258
00259
00260 QString TrollProjectPart::buildDirectory() const
00261 {
00262 return m_widget->projectDirectory();
00263 }
00264
00265 QString TrollProjectPart::projectName() const
00266 {
00267 return m_projectName;
00268 }
00269
00270
00272 DomUtil::PairList TrollProjectPart::runEnvironmentVars() const
00273 {
00274 return DomUtil::readPairListEntry(*projectDom(), "/kdevtrollproject/run/envvars", "envvar", "name", "value");
00275 }
00276
00277
00287 QString TrollProjectPart::runDirectory() const
00288 {
00289 QDomDocument &dom = *projectDom();
00290
00291 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevtrollproject/run/directoryradio");
00292 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevtrollproject/run/mainprogram");
00293
00294 if ( directoryRadioString == "build" )
00295 return buildDirectory();
00296
00297 if ( directoryRadioString == "custom" )
00298 return DomUtil::readEntry(dom, "/kdevtrollproject/run/customdirectory");
00299
00300 int pos = DomMainProgram.findRev('/');
00301 if (pos != -1)
00302 return buildDirectory() + "/" + DomMainProgram.left(pos);
00303
00304 if ( DomMainProgram.isEmpty() )
00305 {
00306 return m_widget->subprojectDirectory();
00307 }
00308 return buildDirectory() + "/" + DomMainProgram;
00309
00310 }
00311
00312
00322 QString TrollProjectPart::mainProgram(bool relative) const
00323 {
00324 QDomDocument &dom = *projectDom();
00325
00326 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevtrollproject/run/directoryradio");
00327 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevtrollproject/run/mainprogram");
00328
00329 if ( directoryRadioString == "custom" )
00330 return DomMainProgram;
00331
00332 if ( relative == false && !DomMainProgram.isEmpty() )
00333 return buildDirectory() + "/" + DomMainProgram;
00334
00335 if ( directoryRadioString == "executable" ) {
00336 int pos = DomMainProgram.findRev('/');
00337 if (pos != -1)
00338 return DomMainProgram.mid(pos+1);
00339
00340 if ( DomMainProgram.isEmpty() )
00341 {
00342 return runDirectory() + "/" + m_widget->getCurrentOutputFilename();
00343 }
00344 return DomMainProgram;
00345 }
00346 else
00347 return DomMainProgram;
00348 }
00349
00350
00352 QString TrollProjectPart::runArguments() const
00353 {
00354 return DomUtil::readEntry(*projectDom(), "/kdevtrollproject/run/programargs");
00355 }
00356
00357
00358 QString TrollProjectPart::activeDirectory() const
00359 {
00360 QDomDocument &dom = *projectDom();
00361
00362 return DomUtil::readEntry(dom, "/kdevtrollproject/general/activedir");
00363 }
00364
00365
00366 QStringList TrollProjectPart::allFiles() const
00367 {
00368 return m_widget->allFiles();
00369 }
00370
00371
00372 void TrollProjectPart::addFile(const QString &fileName)
00373 {
00374 QStringList fileList;
00375 fileList.append ( fileName );
00376
00377 this->addFiles ( fileList );
00378 }
00379
00380 void TrollProjectPart::addFiles ( const QStringList &fileList )
00381 {
00382 QStringList files = fileList;
00383 for (QStringList::iterator it = files.begin(); it != files.end(); ++it)
00384
00385 if (!isProjectFile(projectDirectory() + "/" + (*it)))
00386 *it = projectDirectory() + "/" + (*it);
00387
00388 m_widget->addFiles(files);
00389
00390
00391 }
00392
00393 void TrollProjectPart::removeFile(const QString & )
00394 {
00396
00397
00398
00399
00400 }
00401
00402 void TrollProjectPart::removeFiles ( const QStringList& fileList )
00403 {
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 emit removedFilesFromProject ( fileList );
00415 }
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 void TrollProjectPart::startQMakeCommand(const QString &dir)
00469 {
00470 QFileInfo fi(dir);
00471
00472 QString cmdline = QString::fromLatin1( isTMakeProject() ? "tmake " : "qmake " );
00473
00474 QDir d(dir);
00475 QStringList l = d.entryList("*.pro");
00476
00477 cmdline += l.count()?l[0]:(fi.baseName() + ".pro");
00478
00479
00480
00481 QString dircmd = "cd ";
00482 dircmd += KProcess::quote(dir);
00483 dircmd += " && ";
00484
00485 cmdline.prepend(makeEnvironment());
00486 makeFrontend()->queueCommand(dir, dircmd + cmdline);
00487 }
00488
00489 void TrollProjectPart::queueCmd(const QString &dir, const QString &cmd)
00490 {
00491 makeFrontend()->queueCommand(dir, cmd);
00492 }
00493
00494 void TrollProjectPart::slotCommandFinished( const QString& command )
00495 {
00496 Q_UNUSED( command );
00497
00498 if( m_buildCommand != command )
00499 return;
00500
00501 m_buildCommand = QString::null;
00502
00503 m_timestamp.clear();
00504 QStringList fileList = allFiles();
00505 QStringList::Iterator it = fileList.begin();
00506 while( it != fileList.end() ){
00507 QString fileName = *it;
00508 ++it;
00509
00510 m_timestamp[ fileName ] = QFileInfo( projectDirectory(), fileName ).lastModified();
00511 }
00512
00513 emit projectCompiled();
00514
00515 if( m_executeAfterBuild ){
00516 m_widget->slotExecuteProject();
00517 m_executeAfterBuild = false;
00518 }
00519 }
00520
00521 bool TrollProjectPart::isDirty()
00522 {
00523 QStringList fileList = allFiles();
00524 QStringList::Iterator it = fileList.begin();
00525 while( it != fileList.end() ){
00526 QString fileName = *it;
00527 ++it;
00528
00529 QMap<QString, QDateTime>::Iterator it = m_timestamp.find( fileName );
00530 QDateTime t = QFileInfo( projectDirectory(), fileName ).lastModified();
00531 if( it == m_timestamp.end() || *it != t ){
00532 return true;
00533 }
00534 }
00535
00536 return false;
00537 }
00538
00539 KDevProject::Options TrollProjectPart::options( ) const
00540 {
00541 return UsesQMakeBuildSystem;
00542 }
00543
00544 bool TrollProjectPart::isValidQtDir( const QString& path ) const
00545 {
00546 return QFile::exists( path + "/include/qt.h" );
00547 }
00548
00549 QStringList TrollProjectPart::availableQtDirList() const
00550 {
00551 QStringList qtdirs, lst;
00552 qtdirs.push_back( ::getenv("QTDIR") );
00553 qtdirs.push_back( "/usr/lib/qt3" );
00554 qtdirs.push_back( "/usr/lib/qt" );
00555 qtdirs.push_back( "/usr/share/qt3" );
00556
00557 for( QStringList::Iterator it=qtdirs.begin(); it!=qtdirs.end(); ++it )
00558 {
00559 QString qtdir = *it;
00560 if( !qtdir.isEmpty() && isValidQtDir(qtdir) )
00561 lst.push_back( qtdir );
00562 }
00563 return lst;
00564 }
00565
00566 QStringList recursiveProFind( const QString &currDir, const QString &baseDir )
00567 {
00568 kdDebug() << "Dir " << currDir << endl;
00569 QStringList fileList;
00570
00571 if( !currDir.contains( "/..") && !currDir.contains("/.") )
00572 {
00573 QDir dir(currDir);
00574 QStringList dirList = dir.entryList(QDir::Dirs );
00575 QStringList::Iterator idx = dirList.begin();
00576 for( ; idx != dirList.end(); ++idx )
00577 {
00578 fileList += recursiveProFind( currDir + "/" + (*idx),baseDir );
00579 }
00580 QStringList newFiles = dir.entryList("*.pro *.PRO");
00581 idx = newFiles.begin();
00582 for( ; idx != newFiles.end(); ++idx )
00583 {
00584 QString file = currDir + "/" + (*idx);
00585 fileList.append( file.remove( baseDir ) );
00586 }
00587 }
00588
00589
00590 return fileList;
00591 }
00592
00596 QStringList TrollProjectPart::distFiles() const
00597 {
00598 QStringList sourceList = allFiles();
00599
00600 QString projectDir = projectDirectory();
00601 QStringList files = recursiveProFind( projectDir, projectDir + "/" );
00602 return sourceList + files;
00603 }
00604
00605 #include "trollprojectpart.moc"
00606
00607
00608