00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include <config.h>
00016
00017 #include "autoprojectpart.h"
00018 #include "autolistviewitems.h"
00019 #include "configureoptionswidget.h"
00020 #include "addtranslationdlg.h"
00021 #include "addicondlg.h"
00022 #include "autoprojectwidget.h"
00023
00024 #include <qdom.h>
00025 #include <qdir.h>
00026 #include <qfileinfo.h>
00027 #include <qpopupmenu.h>
00028 #include <qstringlist.h>
00029 #include <qwhatsthis.h>
00030 #include <qregexp.h>
00031 #include <qgroupbox.h>
00032
00033 #include <kaction.h>
00034 #include <kdebug.h>
00035 #include <kdialogbase.h>
00036 #include <kiconloader.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039 #include <kparts/part.h>
00040 #include <kdeversion.h>
00041 #include <kprocess.h>
00042
00043 #include <domutil.h>
00044 #include <kdevcore.h>
00045 #include <kdevmakefrontend.h>
00046 #include <kdevappfrontend.h>
00047 #include <kdevmainwindow.h>
00048 #include <kdevpartcontroller.h>
00049 #include <makeoptionswidget.h>
00050 #include <runoptionswidget.h>
00051 #include <envvartools.h>
00052
00053 #include <configwidgetproxy.h>
00054
00055 #define CONFIGURE_OPTIONS 1
00056 #define RUN_OPTIONS 2
00057 #define MAKE_OPTIONS 3
00058
00059 static const KAboutData data("kdevautoproject", I18N_NOOP("Automake Manager"), "1.0");
00060
00061 K_EXPORT_COMPONENT_FACTORY( libkdevautoproject, AutoProjectFactory( &data ) )
00062
00063 AutoProjectPart::AutoProjectPart(QObject *parent, const char *name, const QStringList &args)
00064 : KDevProject("AutoProject", "make", parent, name ? name : "AutoProjectPart")
00065 , m_lastCompilationFailed(false)
00066 {
00067 setInstance(AutoProjectFactory::instance());
00068
00069 setXMLFile("kdevautoproject.rc");
00070
00071 m_executeAfterBuild = false;
00072 m_isKDE = (args[0] == "kde");
00073 m_needMakefileCvs = false;
00074
00075 m_widget = new AutoProjectWidget(this, m_isKDE);
00076 m_widget->setIcon(SmallIcon( icon() ));
00077 m_widget->setCaption(i18n("Automake Manager"));
00078 QWhatsThis::add(m_widget, i18n("<b>Automake manager</b><p>"
00079 "The project tree consists of two parts. The 'overview' "
00080 "in the upper half shows the subprojects, each one having a "
00081 "Makefile.am. The 'details' view in the lower half shows the "
00082 "targets and files for the subproject selected in the overview."));
00083
00084 mainWindow()->embedSelectViewRight(m_widget, i18n("Automake Manager"), i18n("Automake manager"));
00085
00086 KAction *action;
00087
00088 action = new KAction( i18n("Add Translation..."), 0,
00089 this, SLOT(slotAddTranslation()),
00090 actionCollection(), "project_addtranslation" );
00091 action->setToolTip(i18n("Add translation"));
00092 action->setWhatsThis(i18n("<b>Add translation</b><p>Creates .po file for the selected language."));
00093 action->setGroup("autotools");
00094
00095
00096
00097
00098
00099
00100 if (!m_isKDE)
00101 action->setEnabled(false);
00102
00103 action = new KAction( i18n("&Build Project"), "make_kdevelop", Key_F8,
00104 this, SLOT(slotBuild()),
00105 actionCollection(), "build_build" );
00106 action->setToolTip(i18n("Build project"));
00107 action->setWhatsThis(i18n("<b>Build project</b><p>Runs <b>make</b> from the project directory.<br>"
00108 "Environment variables and make arguments can be specified "
00109 "in the project settings dialog, <b>Make Options</b> tab."));
00110 action->setGroup("autotools");
00111
00112 action = new KAction( i18n("Build &Active Target"), "make_kdevelop", Key_F7,
00113 this, SLOT(slotBuildActiveTarget()),
00114 actionCollection(), "build_buildactivetarget" );
00115 action->setToolTip(i18n("Build active target"));
00116 action->setWhatsThis(i18n("<b>Build active target</b><p>Constructs a series of make commands to build an active target. "
00117 "Also builds dependent targets.<br>"
00118 "Environment variables and make arguments can be specified "
00119 "in the project settings dialog, <b>Make Options</b> tab."));
00120 action->setGroup("autotools");
00121
00122 action = new KAction( i18n("Compile &File"), "make_kdevelop",
00123 this, SLOT(slotCompileFile()),
00124 actionCollection(), "build_compilefile" );
00125 action->setToolTip(i18n("Compile file"));
00126 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>"
00127 "Environment variables and make arguments can be specified "
00128 "in the project settings dialog, <b>Make Options</b> tab."));
00129 action->setGroup("autotools");
00130
00131 action = new KAction( i18n("Run Configure"), 0,
00132 this, SLOT(slotConfigure()),
00133 actionCollection(), "build_configure" );
00134 action->setToolTip(i18n("Run configure"));
00135 action->setWhatsThis(i18n("<b>Run configure</b><p>Executes <b>configure</b> with flags, arguments "
00136 "and environment variables specified in the project settings dialog, "
00137 "<b>Configure Options</b> tab."));
00138 action->setGroup("autotools");
00139
00140 action = new KAction( i18n("Run automake && friends"), 0,
00141 this, SLOT(slotMakefilecvs()),
00142 actionCollection(), "build_makefilecvs" );
00143 action->setToolTip(i18n("Run automake && friends"));
00144 action->setWhatsThis(i18n("<b>Run automake && friends</b><p>Executes<br><b>make -f Makefile.cvs</b><br><b>./configure</b><br>commands from the project directory."));
00145 action->setGroup("autotools");
00146
00147 action = new KAction( i18n("Install"), 0,
00148 this, SLOT(slotInstall()),
00149 actionCollection(), "build_install" );
00150 action->setToolTip(i18n("Install"));
00151 action->setWhatsThis(i18n("<b>Install</b><p>Runs <b>make install</b> command from the project directory.<br>"
00152 "Environment variables and make arguments can be specified "
00153 "in the project settings dialog, <b>Make Options</b> tab."));
00154 action->setGroup("autotools");
00155
00156 action = new KAction( i18n("Install (as root user)"), 0,
00157 this, SLOT(slotInstallWithKdesu()),
00158 actionCollection(), "build_install_kdesu" );
00159 action->setToolTip(i18n("Install as root user"));
00160 action->setWhatsThis(i18n("<b>Install</b><p>Runs <b>make install</b> command from the project directory with root privileges.<br>"
00161 "It is executed via kdesu command.<br>"
00162 "Environment variables and make arguments can be specified "
00163 "in the project settings dialog, <b>Make Options</b> tab."));
00164 action->setGroup("autotools");
00165
00166 action = new KAction( i18n("&Clean Project"), 0,
00167 this, SLOT(slotClean()),
00168 actionCollection(), "build_clean" );
00169 action->setToolTip(i18n("Clean project"));
00170 action->setWhatsThis(i18n("<b>Clean project</b><p>Runs <b>make clean</b> command from the project directory.<br>"
00171 "Environment variables and make arguments can be specified "
00172 "in the project settings dialog, <b>Make Options</b> tab."));
00173 action->setGroup("autotools");
00174
00175 action = new KAction( i18n("&Distclean"), 0,
00176 this, SLOT(slotDistClean()),
00177 actionCollection(), "build_distclean" );
00178 action->setToolTip(i18n("Distclean"));
00179 action->setWhatsThis(i18n("<b>Distclean</b><p>Runs <b>make distclean</b> command from the project directory.<br>"
00180 "Environment variables and make arguments can be specified "
00181 "in the project settings dialog, <b>Make Options</b> tab."));
00182 action->setGroup("autotools");
00183
00184 action = new KAction( i18n("Make Messages && Merge"), 0,
00185 this, SLOT(slotMakeMessages()),
00186 actionCollection(), "build_messages" );
00187 action->setToolTip(i18n("Make messages && merge"));
00188 action->setWhatsThis(i18n("<b>Make messages && merge</b><p>Runs <b>make package-messages</b> command from the project directory.<br>"
00189 "Environment variables and make arguments can be specified "
00190 "in the project settings dialog, <b>Make Options</b> tab."));
00191 action->setGroup("autotools");
00192
00193 if (!m_isKDE)
00194 action->setEnabled(false);
00195
00196 buildConfigAction = new KSelectAction( i18n("Build Configuration"), 0,
00197 actionCollection(), "project_configuration" );
00198 buildConfigAction->setToolTip(i18n("Build configuration menu"));
00199 buildConfigAction->setWhatsThis(i18n("<b>Build configuration menu</b><p>Allows to switch between project build configurations.<br>"
00200 "Build configuration is a set of build and top source directory settings, "
00201 "configure flags and arguments, compiler flags, etc.<br>"
00202 "Modify build configurations in project settings dialog, <b>Configure Options</b> tab."));
00203 buildConfigAction->setGroup("autotools");
00204
00205 QDomDocument &dom = *projectDom();
00206 if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/run/disable_default")) {
00207
00208 action = new KAction( i18n("Execute Program"), "exec", SHIFT+Key_F9,
00209 this, SLOT(slotExecute()),
00210 actionCollection(), "build_execute" );
00211 action->setToolTip(i18n("Execute program"));
00212 action->setWhatsThis(i18n("<b>Execute program</b><p>Executes the main program specified in project settings, <b>Run Options</b> tab. "
00213 "If it is not specified then the active target is used to determine the application to run."));
00214 action->setGroup("autotools");
00215 }
00216
00217 connect( buildConfigAction, SIGNAL(activated(const QString&)),
00218 this, SLOT(slotBuildConfigChanged(const QString&)) );
00219 connect( buildConfigAction->popupMenu(), SIGNAL(aboutToShow()),
00220 this, SLOT(slotBuildConfigAboutToShow()) );
00221
00222
00223
00224 _configProxy = new ConfigWidgetProxy( core() );
00225 _configProxy->createProjectConfigPage( i18n("Configure Options"), CONFIGURE_OPTIONS, icon() );
00226 _configProxy->createProjectConfigPage( i18n("Run Options"), RUN_OPTIONS, icon() );
00227 _configProxy->createProjectConfigPage( i18n("Make Options"), MAKE_OPTIONS, icon() );
00228 connect( _configProxy, SIGNAL(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )), this, SLOT(insertConfigWidget(const KDialogBase*, QWidget*, unsigned int )) );
00229
00230
00231 connect( makeFrontend(), SIGNAL(commandFinished(const QString&)),
00232 this, SLOT(slotCommandFinished(const QString&)) );
00233 connect( makeFrontend(), SIGNAL(commandFailed(const QString&)),
00234 this, SLOT(slotCommandFailed(const QString&)) );
00235
00236 setWantautotools();
00237 }
00238
00239
00240 AutoProjectPart::~AutoProjectPart()
00241 {
00242 if (m_widget)
00243 mainWindow()->removeView(m_widget);
00244 delete m_widget;
00245 delete _configProxy;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 void AutoProjectPart::insertConfigWidget( const KDialogBase* dlg, QWidget * page, unsigned int pagenumber )
00274 {
00275 switch ( pagenumber )
00276 {
00277 case CONFIGURE_OPTIONS:
00278 {
00279 ConfigureOptionsWidget *w2 = new ConfigureOptionsWidget(this, page );
00280 connect( dlg, SIGNAL(okClicked()), w2, SLOT(accept()) );
00281 }
00282 break;
00283
00284 case RUN_OPTIONS:
00285 {
00286 QDomDocument &dom = *projectDom();
00287 if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/run/disable_default")) {
00288
00289 RunOptionsWidget *w3 = new RunOptionsWidget(*projectDom(), "/kdevautoproject", buildDirectory(), page );
00290 w3->programGroupBox->setTitle(i18n("Program (if empty automatically uses active target and active target's arguments)"));
00291 connect( dlg, SIGNAL(okClicked()), w3, SLOT(accept()) );
00292 }
00293 }
00294 break;
00295
00296 case MAKE_OPTIONS:
00297 {
00298 MakeOptionsWidget *w4 = new MakeOptionsWidget(*projectDom(), "/kdevautoproject", page );
00299 connect( dlg, SIGNAL(okClicked()), w4, SLOT(accept()) );
00300 }
00301 break;
00302 }
00303 }
00304
00305 void AutoProjectPart::openProject(const QString &dirName, const QString &projectName)
00306 {
00307 m_projectName = projectName;
00308 m_projectPath =dirName;
00309
00310 m_widget->openProject(dirName);
00311
00312 QDomDocument &dom = *projectDom();
00313 QString activeTarget = DomUtil::readEntry(dom, "/kdevautoproject/general/activetarget");
00314 kdDebug(9020) << "activeTarget " << activeTarget << endl;
00315 if (!activeTarget.isEmpty())
00316 m_widget->setActiveTarget(activeTarget);
00317
00318
00319 if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/run/disable_default") && DomUtil::readEntry(dom, "/kdevautoproject/run/directoryradio") == "" ) {
00320 DomUtil::writeEntry(dom, "/kdevautoproject/run/directoryradio", "executable");
00321 }
00322
00323 KDevProject::openProject( dirName, projectName );
00324 }
00325
00326
00327 void AutoProjectPart::closeProject()
00328 {
00329 m_widget->closeProject();
00330 }
00331
00332
00333 QString AutoProjectPart::projectDirectory() const
00334 {
00335 return m_projectPath;
00336 }
00337
00338
00339 QString AutoProjectPart::projectName() const
00340 {
00341 return m_projectName;
00342 }
00343
00344
00346 DomUtil::PairList AutoProjectPart::runEnvironmentVars() const
00347 {
00348 return DomUtil::readPairListEntry(*projectDom(), "/kdevautoproject/run/envvars", "envvar", "name", "value");
00349 }
00350
00351
00363 QString AutoProjectPart::runDirectory() const
00364 {
00365 QDomDocument &dom = *projectDom();
00366
00367 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevautoproject/run/directoryradio");
00368 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevautoproject/run/mainprogram");
00369
00370 if ( directoryRadioString == "build" )
00371 return buildDirectory();
00372
00373 if ( directoryRadioString == "custom" )
00374 return DomUtil::readEntry(dom, "/kdevautoproject/run/customdirectory");
00375
00376 if ( DomMainProgram.isEmpty() )
00377
00378 return buildDirectory() + "/" + activeDirectory();
00379
00380
00381 int pos = DomMainProgram.findRev('/');
00382 if (pos != -1)
00383 return buildDirectory() + "/" + DomMainProgram.left(pos);
00384 return buildDirectory() + "/" + DomMainProgram;
00385 }
00386
00387
00399 QString AutoProjectPart::mainProgram(bool relative) const
00400 {
00401 QDomDocument &dom = *projectDom();
00402
00403 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevautoproject/run/directoryradio");
00404 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevautoproject/run/mainprogram");
00405
00406 if ( DomMainProgram.isEmpty() ) {
00407
00408
00409
00410 TargetItem* titem = m_widget->activeTarget();
00411
00412 if ( !titem ) {
00413 kdDebug ( 9000 ) << "Error! : No Main Program was specified and there's no active target! -> Unable to determine the main program in AutoProjectPart::mainProgram()" << endl;
00414 return QString::null;
00415 }
00416
00417 if ( titem->primary != "PROGRAMS" ) {
00418 kdDebug ( 9000 ) << "Error! : No Main Program was specified and active target isn't binary (" << titem->primary << ") ! -> Unable to determine the main program in AutoProjectPart::mainProgram()" << endl;
00419 return QString::null;
00420 }
00421
00422 if (relative == false || directoryRadioString == "custom")
00423 return buildDirectory() + "/" + activeDirectory() + "/" + titem->name;
00424
00425 if ( directoryRadioString == "executable" )
00426 return titem->name;
00427
00428 return activeDirectory() + "/" + titem->name;
00429
00430 }
00431 else {
00432
00433 if ( directoryRadioString == "custom" )
00434 return DomMainProgram;
00435
00436 if ( relative == false )
00437 return buildDirectory() + "/" + DomMainProgram;
00438
00439 if ( directoryRadioString != "executable" )
00440 return DomMainProgram;
00441
00442 int pos = DomMainProgram.findRev('/');
00443 if (pos != -1)
00444 return DomMainProgram.mid(pos+1);
00445 return DomMainProgram;
00446 }
00447 }
00448
00449
00451 QString AutoProjectPart::runArguments() const
00452 {
00453 QDomDocument &dom = *projectDom();
00454
00455 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevautoproject/run/mainprogram");
00456 QString DomProgramArguments = DomUtil::readEntry(*projectDom(), "/kdevautoproject/run/programargs");
00457
00458 if ( DomMainProgram.isEmpty() && DomProgramArguments.isEmpty() )
00459
00460 if (m_widget->activeTarget())
00461 return DomUtil::readEntry(*projectDom(), "/kdevautoproject/run/runarguments/" + m_widget->activeTarget()->name);
00462 else
00463 return QString::null;
00464 else
00465 return DomProgramArguments;
00466 }
00467
00468
00469 QString AutoProjectPart::activeDirectory() const
00470 {
00471 return m_widget->activeDirectory();
00472 }
00473
00474
00475 QStringList AutoProjectPart::allFiles() const
00476 {
00477 return m_widget->allFiles();
00478 }
00479
00480
00481 void AutoProjectPart::setWantautotools()
00482 {
00483 QDomDocument &dom = *projectDom();
00484 QDomElement el = DomUtil::elementByPath(dom, "/kdevautoproject/make");
00485 if ( el.namedItem("envvars").isNull() ) {
00486 DomUtil::PairList list;
00487 list << DomUtil::Pair("WANT_AUTOCONF_2_5", "1");
00488 list << DomUtil::Pair("WANT_AUTOMAKE_1_6", "1");
00489 DomUtil::writePairListEntry(dom, "/kdevautoproject/make/envvars", "envvar", "name", "value", list);
00490 }
00491 }
00492
00493
00494 QString AutoProjectPart::makeEnvironment() const
00495 {
00496
00497
00498
00499
00500 DomUtil::PairList envvars =
00501 DomUtil::readPairListEntry(*projectDom(), "/kdevautoproject/make/envvars", "envvar", "name", "value");
00502
00503 QString environstr;
00504 DomUtil::PairList::ConstIterator it;
00505 for (it = envvars.begin(); it != envvars.end(); ++it) {
00506 environstr += (*it).first;
00507 environstr += "=";
00508
00509
00510
00511
00512
00513
00514
00515 environstr += EnvVarTools::quote((*it).second);
00516 environstr += " ";
00517 }
00518 return environstr;
00519 }
00520
00521
00522 void AutoProjectPart::addFile(const QString &fileName)
00523 {
00524 QStringList fileList;
00525 fileList.append ( fileName );
00526
00527 this->addFiles ( fileList );
00528 }
00529
00530 void AutoProjectPart::addFiles ( const QStringList& fileList )
00531 {
00532 QString directory, name;
00533 QStringList::ConstIterator it;
00534 bool messageBoxShown = false;
00535
00536 for ( it = fileList.begin(); it != fileList.end(); ++it )
00537 {
00538 int pos = ( *it ).findRev('/');
00539 if (pos != -1)
00540 {
00541 directory = ( *it ).left(pos);
00542 name = ( *it ).mid(pos+1);
00543 }
00544 else
00545 {
00546 directory = "";
00547 name = ( *it );
00548 }
00549
00550 if (directory != m_widget->activeDirectory() ||
00551 directory.isEmpty())
00552 {
00553 if ( !messageBoxShown )
00554 {
00555 KMessageBox::information(m_widget, i18n("The directory you selected is not the active directory.\n"
00556 "You should 'activate' the target you're currently working on in Automake Manager.\n"
00557 "Just right-click a target and choose 'Make Target Active'."),
00558 i18n ( "No Active Target Found" ), "No automake manager active target warning" );
00559 messageBoxShown = true;
00560 }
00561 }
00562 }
00563
00564 m_widget->addFiles(fileList);
00565 }
00566
00567 void AutoProjectPart::removeFile(const QString &fileName)
00568 {
00569 QStringList fileList;
00570 fileList.append ( fileName );
00571
00572 this->removeFiles ( fileList );
00573 }
00574
00575 void AutoProjectPart::removeFiles ( const QStringList& fileList )
00576 {
00578 m_widget->removeFiles ( fileList );
00579
00580 emit removedFilesFromProject ( fileList );
00581 }
00582
00583 QStringList AutoProjectPart::allBuildConfigs() const
00584 {
00585 QDomDocument &dom = *projectDom();
00586
00587 QStringList allConfigs;
00588 allConfigs.append("default");
00589
00590 QDomNode node = dom.documentElement().namedItem("kdevautoproject").namedItem("configurations");
00591 QDomElement childEl = node.firstChild().toElement();
00592 while (!childEl.isNull()) {
00593 QString config = childEl.tagName();
00594 kdDebug(9020) << "Found config " << config << endl;
00595 if (config != "default")
00596 allConfigs.append(config);
00597 childEl = childEl.nextSibling().toElement();
00598 }
00599
00600 return allConfigs;
00601 }
00602
00603
00604 QString AutoProjectPart::currentBuildConfig() const
00605 {
00606 QDomDocument &dom = *projectDom();
00607
00608 QString config = DomUtil::readEntry(dom, "/kdevautoproject/general/useconfiguration");
00609 if (config.isEmpty() || !allBuildConfigs().contains(config))
00610 config = "default";
00611
00612 return config;
00613 }
00614
00615
00616 QString AutoProjectPart::buildDirectory() const
00617 {
00618 QString prefix = "/kdevautoproject/configurations/" + currentBuildConfig() + "/";
00619
00620 QString builddir = DomUtil::readEntry(*projectDom(), prefix + "builddir");
00621 if (builddir.isEmpty())
00622 return topsourceDirectory();
00623 else if (builddir.startsWith("/"))
00624 return builddir;
00625 else
00626 return projectDirectory() + "/" + builddir;
00627 }
00628
00629 QString AutoProjectPart::topsourceDirectory() const
00630 {
00631 QString prefix = "/kdevautoproject/configurations/" + currentBuildConfig() + "/";
00632
00633 QString topsourcedir = DomUtil::readEntry(*projectDom(), prefix + "topsourcedir");
00634 if (topsourcedir.isEmpty())
00635 return projectDirectory();
00636 else if (topsourcedir.startsWith("/"))
00637 return topsourcedir;
00638 else
00639 return projectDirectory() + "/" + topsourcedir;
00640 }
00641
00642 QString AutoProjectPart::constructMakeCommandLine(const QString &dir, const QString &target) const
00643 {
00644
00645 QString preCommand;
00646 QFileInfo fi1();
00647 if ( !QFile::exists(dir + "/GNUmakefile") && !QFile::exists(dir + "/makefile")
00648 && ! QFile::exists(dir + "/Makefile") ) {
00649 if (!QFile::exists(buildDirectory() + "/configure")) {
00650 int r = KMessageBox::questionYesNo(m_widget, i18n("There is no Makefile in this directory\n"
00651 "and no configure script for this project.\n"
00652 "Run automake & friends and configure first?"));
00653 if (r == KMessageBox::No)
00654 return 0;
00655 preCommand = makefileCvsCommand();
00656 if (preCommand.isNull())
00657 return 0;
00658 preCommand += " && ";
00659 preCommand += configureCommand() + " && ";
00660 } else {
00661 int r = KMessageBox::questionYesNo(m_widget, i18n("There is no Makefile in this directory. Run 'configure' first?"));
00662 if (r == KMessageBox::No)
00663 return 0;
00664 preCommand = configureCommand() + " && ";
00665 }
00666 }
00667 QDomDocument &dom = *projectDom();
00668
00669 QString cmdline = DomUtil::readEntry(dom, "/kdevautoproject/make/makebin");
00670 int prio = DomUtil::readIntEntry(dom, "/kdevautoproject/make/prio");
00671 QString nice;
00672 kdDebug(9020) << "constructMakeCommandLine() nice = " << prio<< endl;
00673 if (prio != 0) {
00674 nice = QString("nice -n%1 ").arg(prio);
00675 }
00676
00677 if (cmdline.isEmpty())
00678 cmdline = MAKE_COMMAND;
00679 if (!DomUtil::readBoolEntry(dom, "/kdevautoproject/make/abortonerror"))
00680 cmdline += " -k";
00681 int jobs = DomUtil::readIntEntry(dom, "/kdevautoproject/make/numberofjobs");
00682 if (jobs != 0) {
00683 cmdline += " -j";
00684 cmdline += QString::number(jobs);
00685 }
00686 if (DomUtil::readBoolEntry(dom, "/kdevautoproject/make/dontact"))
00687 cmdline += " -n";
00688
00689 cmdline += " ";
00690 cmdline += target;
00691 cmdline.prepend(nice);
00692 cmdline.prepend(makeEnvironment());
00693
00694 QString dircmd = "cd ";
00695 dircmd += KProcess::quote(dir);
00696 dircmd += " && ";
00697
00698 return preCommand + dircmd + cmdline;
00699 }
00700
00701
00702 void AutoProjectPart::startMakeCommand(const QString &dir, const QString &target, bool withKdesu)
00703 {
00704 partController()->saveAllFiles();
00705
00706 m_buildCommand = constructMakeCommandLine(dir, target);
00707
00708 if (withKdesu)
00709 m_buildCommand = "kdesu -t -c '" + m_buildCommand + "'";
00710
00711 if (!m_buildCommand.isNull())
00712 makeFrontend()->queueCommand(dir, m_buildCommand);
00713 }
00714
00715
00718 void AutoProjectPart::queueInternalLibDependenciesBuild(TargetItem* titem)
00719 {
00720
00721 QString addstr = (titem->primary == "PROGRAMS")? titem->ldadd : titem->libadd;
00722 QStringList l2 = QStringList::split(QRegExp("[ \t]"), addstr);
00723 QString tdir;
00724 QString tname;
00725 QString tcmd;
00726 QStringList::Iterator l2it;
00727 for (l2it = l2.begin(); l2it != l2.end(); ++l2it) {
00728 QString dependency = *l2it;
00729 if (dependency.startsWith("$(top_builddir)/")) {
00730
00731 #if KDE_VERSION > 305
00732 dependency.remove("$(top_builddir)/");
00733 #else
00734 QString topBuildDirStr("$(top_builddir)/");
00735 int i = dependency.find(topBuildDirStr);
00736 if (i != -1) {
00737 dependency.remove(i, i + topBuildDirStr.length() - 1);
00738 }
00739 #endif
00740 tdir = buildDirectory();
00741 if (!tdir.endsWith("/") && !tdir.isEmpty())
00742 tdir += "/";
00743 int pos = dependency.findRev('/');
00744 if (pos == -1) {
00745 tname = dependency;
00746 } else {
00747 tdir += dependency.left(pos+1);
00748 tname = dependency.mid(pos+1);
00749 }
00750 kdDebug(9020) << "Scheduling : <" << tdir << "> target <" << tname << ">" << endl;
00751
00752
00753 SubprojectItem *spi = m_widget->subprojectItemForPath( dependency.left(pos) );
00754 if (spi) {
00755 QPtrList< TargetItem > tl = spi->targets;
00756
00757 TargetItem *ti = tl.first();
00758 do {
00759 if (ti->name == tname) {
00760
00761 queueInternalLibDependenciesBuild(ti);
00762 break;
00763 }
00764 ti = tl.next();
00765 } while (ti);
00766 }
00767
00768 tcmd = constructMakeCommandLine(tdir, tname);
00769 if (!tcmd.isNull()) {
00770 makeFrontend()->queueCommand( tdir, tcmd);
00771 }
00772 }
00773 }
00774 }
00775
00776
00777 void AutoProjectPart::slotBuild()
00778 {
00779
00780
00781 if( m_needMakefileCvs ){
00782 slotMakefilecvs();
00783 slotConfigure();
00784 m_needMakefileCvs = false;
00785 }
00786
00787 startMakeCommand(buildDirectory(), QString::fromLatin1(""));
00788 }
00789
00790
00791 void AutoProjectPart::buildTarget(QString relpath, TargetItem* titem)
00792 {
00793
00794 if ( !titem )
00795 return;
00796
00797
00798
00799
00800 QString name = titem->name;
00801 if ( titem->primary == "KDEDOCS" )
00802 name = "index.cache.bz2";
00803
00804
00805 QString path = buildDirectory();
00806 if (!path.endsWith("/") && !path.isEmpty())
00807 path += "/";
00808 if (relpath.at(0) == '/')
00809 path += relpath.mid(1);
00810 else
00811 path += relpath;
00812
00813
00814 partController()->saveAllFiles();
00815
00816
00817
00818 queueInternalLibDependenciesBuild(titem);
00819
00820
00821 QString tcmd = constructMakeCommandLine( path, name );
00822
00823
00824 if (!tcmd.isNull()) {
00825 m_buildCommand = tcmd;
00826 makeFrontend()->queueCommand( path, tcmd);
00827 }
00828 }
00829
00830
00831 void AutoProjectPart::slotBuildActiveTarget()
00832 {
00833
00834 TargetItem* titem = m_widget->activeTarget();
00835
00836 if ( !titem )
00837 return;
00838
00839
00840 buildTarget(activeDirectory(), titem);
00841 }
00842
00843
00844 void AutoProjectPart::slotCompileFile()
00845 {
00846 KParts::ReadWritePart *part = dynamic_cast<KParts::ReadWritePart*>(partController()->activePart());
00847 if (!part || !part->url().isLocalFile())
00848 return;
00849
00850 QString fileName = part->url().path();
00851 QFileInfo fi(fileName);
00852 QString sourceDir = fi.dirPath();
00853 QString baseName = fi.baseName(true);
00854 kdDebug(9020) << "Compiling " << fileName
00855 << " in dir " << sourceDir
00856 << " with baseName " << baseName << endl;
00857
00858 QString projectDir = projectDirectory();
00859 if (!sourceDir.startsWith(projectDir)) {
00860 KMessageBox::sorry(m_widget, i18n("Can only compile files in directories which belong to the project."));
00861 return;
00862 }
00863
00864 QString buildDir = buildDirectory() + sourceDir.mid(projectDir.length());
00865 QString target = baseName + ".lo";
00866 kdDebug(9020) << "builddir " << buildDir << ", target " << target << endl;
00867
00868 startMakeCommand(buildDir, target);
00869 }
00870
00871 QString AutoProjectPart::configureCommand() const
00872 {
00873 QDomDocument &dom = *projectDom();
00874 QString prefix = "/kdevautoproject/configurations/" + currentBuildConfig() + "/";
00875
00876 QString cmdline = "\"" + topsourceDirectory();
00877 cmdline += "/configure\"";
00878 QString cc = DomUtil::readEntry(dom, prefix + "ccompilerbinary");
00879 if (!cc.isEmpty())
00880 cmdline.prepend(QString("CC=%1 ").arg(cc));
00881 QString cflags = DomUtil::readEntry(dom, prefix + "cflags");
00882 if (!cflags.isEmpty())
00883 cmdline.prepend(QString("CFLAGS=\"%1\" ").arg(cflags));
00884 QString cxx = DomUtil::readEntry(dom, prefix + "cxxcompilerbinary");
00885 if (!cxx.isEmpty())
00886 cmdline.prepend(QString("CXX=%1 ").arg(cxx));
00887 QString cxxflags = DomUtil::readEntry(dom, prefix + "cxxflags");
00888 if (!cxxflags.isEmpty())
00889 cmdline.prepend(QString("CXXFLAGS=\"%1\" ").arg(cxxflags));
00890 QString f77 = DomUtil::readEntry(dom, prefix + "f77compilerbinary");
00891 if (!f77.isEmpty())
00892 cmdline.prepend(QString("F77=%1 ").arg(f77));
00893 QString fflags = DomUtil::readEntry(dom, prefix + "f77flags");
00894 if (!fflags.isEmpty())
00895 cmdline.prepend(QString("FFLAGS=\"%1\" ").arg(fflags));
00896 QString cppflags = DomUtil::readEntry(dom, prefix + "cppflags");
00897 if (!cppflags.isEmpty())
00898 cmdline.prepend(QString("CPPFLAGS=\"%1\" ").arg(cppflags));
00899 QString ldflags = DomUtil::readEntry(dom, prefix + "ldflags");
00900 if (!ldflags.isEmpty())
00901 cmdline.prepend(QString("LDFLAGS=\"%1\" ").arg(ldflags));
00902
00903 QString configargs = DomUtil::readEntry(dom, prefix + "configargs");
00904 if (!configargs.isEmpty()) {
00905 cmdline += " ";
00906 cmdline += configargs;
00907 }
00908
00909 DomUtil::PairList envvars =
00910 DomUtil::readPairListEntry(*projectDom(), prefix + "envvars", "envvar", "name", "value");
00911
00912 QString environstr;
00913 DomUtil::PairList::ConstIterator it;
00914 for (it = envvars.begin(); it != envvars.end(); ++it) {
00915 environstr += (*it).first;
00916 environstr += "=";
00917 environstr += EnvVarTools::quote((*it).second);
00918 environstr += " ";
00919 }
00920 cmdline.prepend(environstr);
00921
00922 QString builddir = buildDirectory();
00923 QString dircmd;
00924
00925
00926 if ( !QFile::exists(builddir)) {
00927 dircmd = "mkdir ";
00928 dircmd += KProcess::quote(builddir);
00929 dircmd += " && ";
00930 }
00931
00932
00933 dircmd += "cd ";
00934 dircmd += KProcess::quote(builddir);
00935 dircmd += " && ";
00936
00937 return dircmd + cmdline;
00938 }
00939
00940 void AutoProjectPart::slotConfigure()
00941 {
00942 QString cmdline = configureCommand();
00943 if (cmdline.isNull())
00944 return;
00945
00946 makeFrontend()->queueCommand(buildDirectory(), cmdline);
00947 }
00948
00949 QString AutoProjectPart::makefileCvsCommand() const
00950 {
00951 QString cmdline = DomUtil::readEntry(*projectDom(), "/kdevautoproject/make/makebin");
00952 if (cmdline.isEmpty())
00953 cmdline = MAKE_COMMAND;
00954
00955 int prio = DomUtil::readIntEntry(*projectDom(), "/kdevautoproject/make/prio");
00956 QString nice;
00957 kdDebug(9020) << "makefileCvsCommand() nice = " << prio<< endl;
00958 if (prio != 0) {
00959 nice = QString("nice -n%1 ").arg(prio);
00960 }
00961
00962 if (QFile::exists(topsourceDirectory() + "/Makefile.cvs"))
00963 cmdline += " -f Makefile.cvs";
00964 else if (QFile::exists(topsourceDirectory() + "/Makefile.dist"))
00965 cmdline += " -f Makefile.dist";
00966 else if (QFile::exists(topsourceDirectory() + "/autogen.sh"))
00967 cmdline = "./autogen.sh";
00968 else {
00969 KMessageBox::sorry(m_widget, i18n("There is neither a Makefile.cvs file nor an "
00970 "autogen.sh script in the project directory."));
00971 return QString::null;
00972 }
00973
00974 cmdline.prepend(nice);
00975 cmdline.prepend(makeEnvironment());
00976
00977 QString dircmd = "cd ";
00978 dircmd += KProcess::quote(topsourceDirectory());
00979 dircmd += " && ";
00980
00981 return dircmd + cmdline;
00982 }
00983
00984 void AutoProjectPart::slotMakefilecvs()
00985 {
00986 QString cmdline = makefileCvsCommand();
00987 if ( cmdline.isNull() )
00988 return;
00989
00990 makeFrontend()->queueCommand(projectDirectory(), cmdline);
00991 }
00992
00993
00994 void AutoProjectPart::slotInstall()
00995 {
00996 startMakeCommand(buildDirectory(), QString::fromLatin1("install"));
00997 }
00998
00999
01000 void AutoProjectPart::slotInstallWithKdesu()
01001 {
01002
01003
01004 slotBuild();
01005
01006
01007 startMakeCommand(buildDirectory(), QString::fromLatin1("install"), true);
01008 }
01009
01010
01011 void AutoProjectPart::slotClean()
01012 {
01013 startMakeCommand(buildDirectory(), QString::fromLatin1("clean"));
01014 }
01015
01016
01017 void AutoProjectPart::slotDistClean()
01018 {
01019 startMakeCommand(buildDirectory(), QString::fromLatin1("distclean"));
01020 }
01021
01022
01023 void AutoProjectPart::slotMakeMessages()
01024 {
01025 startMakeCommand(buildDirectory(), QString::fromLatin1("package-messages"));
01026 }
01027
01028
01035 void AutoProjectPart::slotExecute()
01036 {
01037 partController()->saveAllFiles();
01038 QDomDocument &dom = *projectDom();
01039
01040 if( DomUtil::readBoolEntry(dom, "/kdevautoproject/run/autocompile", true) && isDirty() ){
01041 m_executeAfterBuild = true;
01042 if ( DomUtil::readEntry(dom, "/kdevautoproject/run/mainprogram").isEmpty() )
01043
01044 slotBuildActiveTarget();
01045 else
01046
01047 slotBuild();
01048 return;
01049 }
01050
01051 if (appFrontend()->isRunning()) {
01052 if (KMessageBox::questionYesNo(m_widget, i18n("Your application is currently running. Do you want to restart it?"), i18n("Application already running"), i18n("&Restart application"), i18n("Do &Nothing")) == KMessageBox::No)
01053 return;
01054 connect(appFrontend(), SIGNAL(processExited()), SLOT(slotExecute2()));
01055 appFrontend()->stopApplication();
01056 return;
01057 }
01058
01059 slotExecute2();
01060 }
01061
01062 void AutoProjectPart::executeTarget(const QDir& dir, const TargetItem* titem)
01063 {
01064 partController()->saveAllFiles();
01065
01066 bool is_dirty = false;
01067 QDateTime t = QFileInfo(dir , titem->name ).lastModified();
01068 QPtrListIterator<FileItem> it( titem->sources );
01069 for( ; it.current() ; ++it )
01070 {
01071 if( t < QFileInfo(dir , (*it)->name).lastModified())
01072 is_dirty = true;
01073 }
01074
01075
01076 if( DomUtil::readBoolEntry(*projectDom(), "/kdevautoproject/run/autocompile", true) && is_dirty )
01077 {
01078 connect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotExecuteTargetAfterBuild(const QString&)) );
01079 connect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotNotExecuteTargetAfterBuildFailed(const QString&)) );
01080 m_executeTargetAfterBuild.first = dir;
01081 m_executeTargetAfterBuild.second = const_cast<TargetItem*>(titem);
01082
01083 QString relpath = dir.path().mid( projectDirectory().length() );
01084 buildTarget(relpath, const_cast<TargetItem*>(titem));
01085 return;
01086 }
01087
01088
01089 bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevautoproject/run/terminal");
01090
01091 QString program = environString();
01092 if(titem->name.startsWith("/"))
01093 program += "./";
01094 program += titem->name;
01095
01096 QString args = DomUtil::readEntry(*projectDom(), "/kdevautoproject/run/runarguments/" + titem->name);
01097
01098 program += " " + args;
01099
01100 appFrontend()->startAppCommand(dir.path(), program ,inTerminal);
01101
01102 }
01103
01104 void AutoProjectPart::slotExecuteTargetAfterBuild(const QString& command)
01105 {
01106
01107 if ( constructMakeCommandLine(m_executeTargetAfterBuild.first.path(), m_executeTargetAfterBuild.second->name) == command )
01108 {
01109 disconnect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotExecuteAfterTargetBuild()) );
01110 disconnect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotExecuteAfterTargetBuildFailed()) );
01111 executeTarget(m_executeTargetAfterBuild.first, m_executeTargetAfterBuild.second);
01112 }
01113
01114 }
01115
01116 void AutoProjectPart::slotNotExecuteTargetAfterBuildFailed(const QString& command)
01117 {
01118
01119 if ( constructMakeCommandLine(m_executeTargetAfterBuild.first.path(), m_executeTargetAfterBuild.second->name) == command )
01120 {
01121 disconnect( makeFrontend(), SIGNAL(commandFinished(const QString&)), this, SLOT(slotExecuteTargetAfterBuild()) );
01122 disconnect( makeFrontend(), SIGNAL(commandFailed(const QString&)), this, SLOT(slotNotExecuteTargetAfterBuildFailed()) );
01123 }
01124
01125 }
01126
01127
01128
01129
01130
01131
01132 QString AutoProjectPart::environString() const
01133 {
01134 DomUtil::PairList envvars = runEnvironmentVars();
01135 QString environstr;
01136 DomUtil::PairList::ConstIterator it;
01137 for (it = envvars.begin(); it != envvars.end(); ++it) {
01138 environstr += (*it).first;
01139 environstr += "=";
01140 environstr += EnvVarTools::quote((*it).second);
01141 environstr += " ";
01142 }
01143 return environstr;
01144 }
01145
01150 void AutoProjectPart::slotExecute2()
01151 {
01152 disconnect(appFrontend(), SIGNAL(processExited()), this, SLOT(slotExecute2()));
01153
01154 if (mainProgram(true).isEmpty())
01155
01156 return;
01157
01158 QString program = environString();
01159
01160 if (!mainProgram(true).startsWith("/"))
01161 program += "./";
01162 program += mainProgram(true);
01163 program += " " + runArguments();
01164
01165 bool inTerminal = DomUtil::readBoolEntry(*projectDom(), "/kdevautoproject/run/terminal");
01166
01167 kdDebug(9020) << "runDirectory: <" << runDirectory() << ">" <<endl;
01168 kdDebug(9020) << "environstr : <" << environString() << ">" <<endl;
01169 kdDebug(9020) << "mainProgram : <" << mainProgram(true) << ">" <<endl;
01170 kdDebug(9020) << "runArguments: <" << runArguments() << ">" <<endl;
01171
01172 appFrontend()->startAppCommand(runDirectory(), program, inTerminal);
01173 }
01174
01175
01176 void AutoProjectPart::slotAddTranslation()
01177 {
01178 AddTranslationDialog dlg(this, m_widget);
01179 dlg.exec();
01180 }
01181
01182
01183 void AutoProjectPart::slotBuildConfigChanged(const QString &config)
01184 {
01185 DomUtil::writeEntry(*projectDom(), "/kdevautoproject/general/useconfiguration", config);
01186 kdDebug(9020) << "Changed used configuration to " << config << endl;
01187 }
01188
01189
01190 void AutoProjectPart::slotBuildConfigAboutToShow()
01191 {
01192 QStringList l = allBuildConfigs();
01193 buildConfigAction->setItems(l);
01194 buildConfigAction->setCurrentItem(l.findIndex(currentBuildConfig()));
01195 }
01196
01197 void AutoProjectPart::restorePartialProjectSession ( const QDomElement* el )
01198 {
01199 m_widget->restoreSession ( el );
01200 }
01201
01202 void AutoProjectPart::savePartialProjectSession ( QDomElement* el )
01203 {
01204 QDomDocument domDoc = el->ownerDocument();
01205
01206 KMessageBox::information ( 0, "Hallo, Welt!" );
01207
01208 kdDebug ( 9000 ) << "*********************************************** 1) AutoProjectPart::savePartialProjectSession()" << endl;
01209
01210 if ( domDoc.isNull() )
01211 {
01212 kdDebug ( 9000 ) << "*********************************************** 2) AutoProjectPart::savePartialProjectSession()" << endl;
01213 return;
01214 }
01215
01216 kdDebug ( 9000 ) << "*********************************************** 3) AutoProjectPart::savePartialProjectSession()" << endl;
01217
01218 m_widget->saveSession ( el );
01219 }
01220
01221 void AutoProjectPart::slotCommandFinished( const QString& command )
01222 {
01223 kdDebug(9020) << k_funcinfo << endl;
01224
01225 if( m_buildCommand != command )
01226 return;
01227
01228 m_buildCommand = QString::null;
01229
01230 m_timestamp.clear();
01231 QStringList fileList = allFiles();
01232 QStringList::Iterator it = fileList.begin();
01233 while( it != fileList.end() ){
01234 QString fileName = *it;
01235 ++it;
01236
01237 m_timestamp[ fileName ] = QFileInfo( projectDirectory(), fileName ).lastModified();
01238 }
01239
01240 emit projectCompiled();
01241
01242
01243 m_lastCompilationFailed = false;
01244
01245 if( m_executeAfterBuild ){
01246 slotExecute();
01247 m_executeAfterBuild = false;
01248 }
01249 }
01250
01251 void AutoProjectPart::slotCommandFailed( const QString& )
01252 {
01253 kdDebug(9020) << k_funcinfo << endl;
01254
01255 m_lastCompilationFailed = true;
01256 }
01257
01258 bool AutoProjectPart::isDirty()
01259 {
01260 if (m_lastCompilationFailed) return true;
01261
01262 QStringList fileList = allFiles();
01263 QStringList::Iterator it = fileList.begin();
01264 while( it != fileList.end() ){
01265 QString fileName = *it;
01266 ++it;
01267
01268 QMap<QString, QDateTime>::Iterator it = m_timestamp.find( fileName );
01269 QDateTime t = QFileInfo( projectDirectory(), fileName ).lastModified();
01270 if( it == m_timestamp.end() || *it != t ){
01271 return true;
01272 }
01273 }
01274
01275 return false;
01276 }
01277
01278 void AutoProjectPart::needMakefileCvs( )
01279 {
01280 m_needMakefileCvs = true;
01281 }
01282
01283 bool AutoProjectPart::isKDE() const
01284 {
01285 return m_isKDE;
01286 }
01287
01288 KDevProject::Options AutoProjectPart::options() const
01289 {
01290 return UsesAutotoolsBuildSystem;
01291 }
01292
01293 QStringList recursiveATFind( const QString &currDir, const QString &baseDir )
01294 {
01295 kdDebug() << "Dir " << currDir << endl;
01296 QStringList fileList;
01297
01298 if( !currDir.contains( "/..") && !currDir.contains("/.") )
01299 {
01300 QDir dir(currDir);
01301 QStringList dirList = dir.entryList(QDir::Dirs );
01302 QStringList::Iterator idx = dirList.begin();
01303 for( ; idx != dirList.end(); ++idx )
01304 {
01305 fileList += recursiveATFind( currDir + "/" + (*idx),baseDir );
01306 }
01307 QStringList newFiles = dir.entryList("*.am *.in");
01308 idx = newFiles.begin();
01309 for( ; idx != newFiles.end(); ++idx )
01310 {
01311 QString file = currDir + "/" + (*idx);
01312 fileList.append( file.remove( baseDir ) );
01313 }
01314 }
01315
01316
01317 return fileList;
01318 }
01319
01323 QStringList AutoProjectPart::distFiles() const
01324 {
01325 QStringList sourceList = allFiles();
01326
01327 QString projectDir = projectDirectory();
01328 QDir dir(projectDir);
01329 QDir admin(projectDir +"/admin");
01330 QStringList files = dir.entryList( "Makefile.cvs Makefile.am configure* INSTALL README NEWS TODO ChangeLog COPYING AUTHORS stamp-h.in");
01331 QStringList adminFiles = admin.entryList(QDir::Files);
01332 QStringList::Iterator idx = adminFiles.begin();
01333 for( ; idx != adminFiles.end(); ++idx)
01334 {
01335 files.append( "admin/" + (*idx) );
01336 }
01337 QStringList srcDirs = dir.entryList(QDir::Dirs);
01338 idx = srcDirs.begin();
01339 for(; idx != srcDirs.end(); ++idx)
01340 {
01341 sourceList += recursiveATFind( projectDirectory() + "/" + (*idx), projectDirectory());
01342 }
01343 return sourceList + files;
01344 }
01345 #include "autoprojectpart.moc"
01346
01347
01348