00001 #include <qapplication.h>
00002 #include <qfile.h>
00003 #include <qfileinfo.h>
00004 #include <qpopupmenu.h>
00005 #include <qvbox.h>
00006 #include <qtable.h>
00007 #include <qtextstream.h>
00008 #include <qvaluestack.h>
00009 #include <qdir.h>
00010
00011
00012 #include <kdevgenericfactory.h>
00013 #include <kdebug.h>
00014 #include <kaction.h>
00015 #include <kpopupmenu.h>
00016 #include <kdialogbase.h>
00017 #include <klineedit.h>
00018 #include <kcombobox.h>
00019 #include <keditlistbox.h>
00020 #include <kurlrequester.h>
00021
00022
00023 #include <kdevcore.h>
00024 #include <kdevmakefrontend.h>
00025
00026
00027 #include "antoptionswidget.h"
00028 #include "classpathwidget.h"
00029
00030
00031 #include "antprojectpart.h"
00032
00033
00034 typedef KDevGenericFactory<AntProjectPart> AntProjectFactory;
00035 static const KAboutData data("kdevantproject", I18N_NOOP("Build Tool"), "1.0");
00036 K_EXPORT_COMPONENT_FACTORY(libkdevantproject, AntProjectFactory( &data ))
00037
00038
00039 AntOptions::AntOptions()
00040 : m_buildXML("build.xml"), m_verbosity(AntOptions::Quiet)
00041 {
00042 }
00043
00044
00045 AntProjectPart::AntProjectPart(QObject *parent, const char *name, const QStringList &)
00046 : KDevProject("AntProject", "antproject", parent, name ? name : "AntProjectPart")
00047 {
00048 setInstance(AntProjectFactory::instance());
00049
00050 setXMLFile("kdevantproject.rc");
00051
00052 m_buildProjectAction = new KAction(i18n("&Build Project"), "make_kdevelop", Key_F8,
00053 this, SLOT(slotBuild()),
00054 actionCollection(), "build_build" );
00055 m_buildProjectAction->setToolTip(i18n("Build project"));
00056 m_buildProjectAction->setWhatsThis(i18n("<b>Build project</b><p>Executes <b>ant dist</b> command to build the project."));
00057
00058 KActionMenu *menu = new KActionMenu(i18n("Build &Target"),
00059 actionCollection(), "build_target" );
00060 menu->setToolTip(i18n("Build target"));
00061 menu->setWhatsThis(i18n("<b>Build target</b><p>Executes <b>ant target_name</b> command to build the specified target."));
00062
00063 m_targetMenu = menu->popupMenu();
00064
00065 connect(m_targetMenu, SIGNAL(activated(int)), this, SLOT(slotTargetMenuActivated(int)));
00066 connect(core(), SIGNAL(projectConfigWidget(KDialogBase*)), this, SLOT(projectConfigWidget(KDialogBase*)));
00067 connect(core(), SIGNAL(contextMenu(QPopupMenu *, const Context *)), this, SLOT(contextMenu(QPopupMenu *, const Context *)));
00068
00069 m_antOptionsWidget = 0;
00070 }
00071
00072
00073 AntProjectPart::~AntProjectPart()
00074 {
00075 }
00076
00077
00078 void AntProjectPart::openProject(const QString &dirName, const QString &projectName)
00079 {
00080 m_projectDirectory = dirName;
00081 m_projectName = projectName;
00082
00083 QDomDocument &dom = *projectDom();
00084
00086 if (DomUtil::readEntry(dom, "/kdevantproject/run/directoryradio") == "" ) {
00087 DomUtil::writeEntry(dom, "/kdevantproject/run/directoryradio", "executable");
00088 }
00089
00091 m_antOptions.m_buildXML = "build.xml";
00092
00093 parseBuildXML();
00094
00095 fillMenu();
00096
00097 QFile f(dirName + "/" + projectName + ".filelist");
00098 if (f.open(IO_ReadOnly))
00099 {
00100 QTextStream stream(&f);
00101 while (!stream.atEnd())
00102 {
00103 QString s = stream.readLine();
00104 if (!s.startsWith("#"))
00105 m_sourceFiles << s;
00106 }
00107 }
00108 else
00109 populateProject();
00110
00111 KDevProject::openProject( dirName, projectName );
00112 }
00113
00114
00115 void AntProjectPart::populateProject()
00116 {
00117 QApplication::setOverrideCursor(Qt::waitCursor);
00118
00119 QValueStack<QString> s;
00120 int prefixlen = m_projectDirectory.length()+1;
00121 s.push(m_projectDirectory);
00122
00123 QDir dir;
00124 do
00125 {
00126 dir.setPath(s.pop());
00127 kdDebug() << "Examining: " << dir.path() << endl;
00128 const QFileInfoList *dirEntries = dir.entryInfoList();
00129 QPtrListIterator<QFileInfo> it(*dirEntries);
00130 for (; it.current(); ++it)
00131 {
00132 QString fileName = it.current()->fileName();
00133 if (fileName == "." || fileName == "..")
00134 continue;
00135 QString path = it.current()->absFilePath();
00136 if (it.current()->isDir())
00137 {
00138 kdDebug() << "Pushing: " << path << endl;
00139 s.push(path);
00140 }
00141 else
00142 {
00143 kdDebug() << "Adding: " << path << endl;
00144 m_sourceFiles.append(path.mid(prefixlen));
00145 }
00146 }
00147 }
00148 while (!s.isEmpty());
00149
00150 QApplication::restoreOverrideCursor();
00151 }
00152
00153
00154 void AntProjectPart::closeProject()
00155 {
00156 m_projectDirectory = "";
00157 m_projectName = "";
00158 m_buildProjectAction->setEnabled(false);
00159
00160 m_targetMenu->clear();
00161
00162 m_antOptions = AntOptions();
00163
00164 QFile f(m_projectDirectory + "/" + m_projectName + ".filelist");
00165 if (!f.open(IO_WriteOnly))
00166 return;
00167
00168 QTextStream stream(&f);
00169 stream << "# KDevelop Ant Project File List" << endl;
00170
00171 QStringList::ConstIterator it;
00172 for (it = m_sourceFiles.begin(); it != m_sourceFiles.end(); ++it)
00173 stream << (*it) << endl;
00174 f.close();
00175 }
00176
00177
00178 QString AntProjectPart::projectDirectory() const
00179 {
00180 return m_projectDirectory;
00181 }
00182
00183
00184 QString AntProjectPart::buildDirectory() const
00185 {
00186 return m_projectDirectory;
00187 }
00188
00189 QString AntProjectPart::projectName() const
00190 {
00191 return m_projectName;
00192 }
00193
00194
00196 DomUtil::PairList AntProjectPart::runEnvironmentVars() const
00197 {
00199 return DomUtil::readPairListEntry(*projectDom(), "/kdevantproject/run/envvars", "envvar", "name", "value");
00200 }
00201
00202
00212 QString AntProjectPart::runDirectory() const
00213 {
00214 return buildDirectory();
00216
00217 QDomDocument &dom = *projectDom();
00218
00220 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevantproject/run/directoryradio");
00221 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevantproject/run/mainprogram");
00222
00223 if ( directoryRadioString == "build" )
00224 return buildDirectory();
00225
00226 if ( directoryRadioString == "custom" )
00227 return DomUtil::readEntry(dom, "/kdevantproject/run/customdirectory");
00228
00229 int pos = DomMainProgram.findRev('/');
00230 if (pos != -1)
00231 return buildDirectory() + "/" + DomMainProgram.left(pos);
00232
00233 return buildDirectory() + "/" + DomMainProgram;
00234
00235 }
00236
00237
00247 QString AntProjectPart::mainProgram(bool relative) const
00248 {
00249 return QString::null;
00250
00252 QDomDocument &dom = *projectDom();
00253
00255 QString directoryRadioString = DomUtil::readEntry(dom, "/kdevantproject/run/directoryradio");
00256 QString DomMainProgram = DomUtil::readEntry(dom, "/kdevantproject/run/mainprogram");
00257
00258 if ( directoryRadioString == "custom" )
00259 return DomMainProgram;
00260
00261 if ( relative == false )
00262 return buildDirectory() + "/" + DomMainProgram;
00263
00264 if ( directoryRadioString == "executable" ) {
00265 int pos = DomMainProgram.findRev('/');
00266 if (pos != -1)
00267 return DomMainProgram.mid(pos+1);
00268 return DomMainProgram;
00269 }
00270 else
00271 return DomMainProgram;
00272 }
00273
00274
00276 QString AntProjectPart::runArguments() const
00277 {
00279 return DomUtil::readEntry(*projectDom(), "/kdevantproject/run/programargs");
00280 }
00281
00282
00283 QString AntProjectPart::activeDirectory() const
00284 {
00286
00287
00288
00289
00290
00291 return QString("");
00292 }
00293
00294
00295 QStringList AntProjectPart::allFiles() const
00296 {
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 return m_sourceFiles;
00315 }
00316
00317
00318 void AntProjectPart::addFile(const QString &fileName)
00319 {
00320 QStringList fileList;
00321 fileList.append ( fileName );
00322
00323 this->addFiles ( fileList );
00324 }
00325
00326 void AntProjectPart::addFiles ( const QStringList& fileList )
00327 {
00328 QStringList::ConstIterator it;
00329
00330 for ( it = fileList.begin(); it != fileList.end(); ++it )
00331 {
00332 m_sourceFiles.append (*it );
00333 }
00334
00335 kdDebug() << "Emitting addedFilesToProject" << endl;
00336 emit addedFilesToProject(fileList);
00337 }
00338
00339 void AntProjectPart::removeFile(const QString &fileName)
00340 {
00341 QStringList fileList;
00342 fileList.append ( fileName );
00343
00344 this->removeFiles ( fileList );
00345 }
00346
00347 void AntProjectPart::removeFiles ( const QStringList& fileList )
00348 {
00349 kdDebug() << "Emitting removedFilesFromProject" << endl;
00350 emit removedFilesFromProject(fileList);
00351
00352 QStringList::ConstIterator it;
00353
00354 for ( it = fileList.begin(); it != fileList.end(); ++it )
00355 {
00356 m_sourceFiles.remove ( *it );
00357 }
00358 }
00359
00360 void AntProjectPart::parseBuildXML()
00361 {
00362 m_antOptions.m_targets.clear();
00363 m_antOptions.m_properties.clear();
00364 m_antOptions.m_defineProperties.clear();
00365
00366
00367 QFile bf(m_projectDirectory + "/" + m_antOptions.m_buildXML);
00368 if (!bf.open(IO_ReadOnly))
00369 return;
00370
00371
00372 QDomDocument dom;
00373 if (!dom.setContent(&bf))
00374 {
00375 bf.close();
00376 return;
00377 }
00378 bf.close();
00379
00380 m_projectName = dom.documentElement().attribute("name", m_projectName);
00381 m_antOptions.m_defaultTarget = dom.documentElement().attribute("default", "");
00382
00383 QDomNode node = dom.documentElement().firstChild();
00384 while (!node.isNull())
00385 {
00386 if (node.toElement().tagName() == "target")
00387 {
00388 if (m_antOptions.m_defaultTarget.isEmpty())
00389 m_antOptions.m_defaultTarget = node.toElement().attribute("name");
00390 m_antOptions.m_targets.append(node.toElement().attribute("name"));
00391 }
00392 else if (node.toElement().tagName() == "property")
00393 {
00394 m_antOptions.m_properties.insert(node.toElement().attribute("name"), node.toElement().attribute("value"));
00395 m_antOptions.m_defineProperties.insert(node.toElement().attribute("name"), false);
00396 }
00397
00400
00401 node = node.nextSibling();
00402 }
00403 }
00404
00405
00406 void AntProjectPart::fillMenu()
00407 {
00408 m_buildProjectAction->setEnabled(!m_antOptions.m_defaultTarget.isEmpty());
00409
00410 m_targetMenu->clear();
00411 int id = 0;
00412 QStringList::ConstIterator it;
00413 for (it = m_antOptions.m_targets.begin(); it != m_antOptions.m_targets.end(); ++it)
00414 m_targetMenu->insertItem(*it, id++);
00415 }
00416
00417
00418 void AntProjectPart::slotBuild()
00419 {
00420 ant(m_antOptions.m_defaultTarget);
00421 }
00422
00423
00424 void AntProjectPart::slotTargetMenuActivated(int id)
00425 {
00426 ant(m_antOptions.m_targets[id]);
00427 }
00428
00429
00430 void AntProjectPart::ant(const QString &target)
00431 {
00432 QString cmd = "%0 cd %1 && ant %2 -buildfile %3 %4 %5";
00433
00434 QString verb = "";
00435 switch (m_antOptions.m_verbosity)
00436 {
00437 case AntOptions::Quiet:
00438 verb = "-quiet";
00439 break;
00440 case AntOptions::Verbose:
00441 verb = "-verbose";
00442 break;
00443 default:
00444 verb = "-debug";
00445 break;
00446 }
00447
00448 QString options = "";
00449 QMap<QString,QString>::Iterator it;
00450 for (it = m_antOptions.m_properties.begin(); it != m_antOptions.m_properties.end(); ++it)
00451 if (m_antOptions.m_defineProperties[it.key()])
00452 options += "-D" + it.key() + "=\"" + it.data() + "\" ";
00453
00454 QString cp;
00455 if (!m_classPath.count() == 0)
00456 cp = "CLASSPATH="+m_classPath.join(":");
00457
00458 makeFrontend()->queueCommand(m_projectDirectory, cmd.arg(cp).arg(m_projectDirectory).arg(target).arg(m_antOptions.m_buildXML).arg(verb).arg(options));
00459 }
00460
00461
00462 void AntProjectPart::projectConfigWidget(KDialogBase *dlg)
00463 {
00464 QVBox *vbox = dlg->addVBoxPage(i18n("Ant Options"));
00465 m_antOptionsWidget = new AntOptionsWidget(vbox);
00466
00467 m_antOptionsWidget->BuildXML->setURL(m_antOptions.m_buildXML);
00468
00469 switch (m_antOptions.m_verbosity)
00470 {
00471 case AntOptions::Quiet:
00472 m_antOptionsWidget->Verbosity->setCurrentItem(0);
00473 break;
00474 case AntOptions::Verbose:
00475 m_antOptionsWidget->Verbosity->setCurrentItem(1);
00476 break;
00477 default:
00478 m_antOptionsWidget->Verbosity->setCurrentItem(2);
00479 break;
00480 }
00481
00482 m_antOptionsWidget->Properties->setNumRows(m_antOptions.m_properties.count());
00483 m_antOptionsWidget->Properties->setNumCols(2);
00484
00485 QMap<QString,QString>::Iterator it;
00486 int i=0;
00487 for (it = m_antOptions.m_properties.begin(); it != m_antOptions.m_properties.end(); ++it)
00488 {
00489 QCheckTableItem *citem = new QCheckTableItem(m_antOptionsWidget->Properties, it.key());
00490 citem->setChecked(m_antOptions.m_defineProperties[it.key()]);
00491 m_antOptionsWidget->Properties->setItem(i,0, citem);
00492 QTableItem *item = new QTableItem(m_antOptionsWidget->Properties, QTableItem::WhenCurrent, it.data());
00493 m_antOptionsWidget->Properties->setItem(i,1, item);
00494 ++i;
00495 }
00496
00497 connect(dlg, SIGNAL(okClicked()), this, SLOT(optionsAccepted()));
00498
00499 vbox = dlg->addVBoxPage(i18n("Classpath"));
00500 m_classPathWidget = new ClassPathWidget(vbox);
00501
00502 m_classPathWidget->ClassPath->insertStringList(m_classPath);
00503 }
00504
00505
00506 void AntProjectPart::optionsAccepted()
00507 {
00508 if (!m_antOptionsWidget || !m_classPathWidget)
00509 return;
00510
00511 m_antOptions.m_buildXML = m_antOptionsWidget->BuildXML->url();
00512
00513 switch (m_antOptionsWidget->Verbosity->currentItem())
00514 {
00515 case 1:
00516 m_antOptions.m_verbosity = AntOptions::Verbose;
00517 break;
00518 case 2:
00519 m_antOptions.m_verbosity = AntOptions::Debug;
00520 break;
00521 default:
00522 m_antOptions.m_verbosity = AntOptions::Quiet;
00523 break;
00524 }
00525
00526 for (int i=0; i<m_antOptionsWidget->Properties->numRows(); ++i)
00527 {
00528 QString key = m_antOptionsWidget->Properties->text(i,0);
00529 m_antOptions.m_properties.replace(key, m_antOptionsWidget->Properties->text(i,1));
00530 kdDebug() << "PROP: " << key << " = " << m_antOptionsWidget->Properties->text(i,1);
00531
00532 QCheckTableItem *item =(QCheckTableItem*) m_antOptionsWidget->Properties->item(i,0);
00533 m_antOptions.m_defineProperties.replace(key, item->isChecked());
00534 }
00535
00536 m_classPath = m_classPathWidget->ClassPath->items();
00537
00538 m_antOptionsWidget = 0;
00539 m_classPathWidget = 0;
00540 }
00541
00542
00543 void AntProjectPart::contextMenu(QPopupMenu *popup, const Context *context)
00544 {
00545 if (!context->hasType( Context::FileContext ))
00546 return;
00547
00548 const FileContext *fcontext = static_cast<const FileContext*>(context);
00549 if (fcontext->isDirectory())
00550 return;
00551
00552 m_contextFileName = fcontext->fileName();
00553 bool inProject = project()->allFiles().contains(m_contextFileName.mid ( project()->projectDirectory().length() + 1 ) );
00554 QString popupstr = QFileInfo(m_contextFileName).fileName();
00555 if (m_contextFileName.startsWith(projectDirectory()+ "/"))
00556 m_contextFileName.remove(0, projectDirectory().length()+1);
00557
00558 popup->insertSeparator();
00559 if (inProject)
00560 {
00561 int id = popup->insertItem( i18n("Remove %1 From Project").arg(popupstr),
00562 this, SLOT(slotRemoveFromProject()) );
00563 popup->setWhatsThis(id, i18n("<b>Remove from project</b><p>Removes current file from the project."));
00564 }
00565 else
00566 {
00567 int id = popup->insertItem( i18n("Add %1 to Project").arg(popupstr),
00568 this, SLOT(slotAddToProject()) );
00569 popup->setWhatsThis(id, i18n("<b>Add to project</b><p>Adds current file from the project."));
00570 }
00571 }
00572
00573
00574 void AntProjectPart::slotAddToProject()
00575 {
00576 QStringList fileList;
00577 fileList.append ( m_contextFileName );
00578 addFiles ( fileList );
00579 }
00580
00581
00582 void AntProjectPart::slotRemoveFromProject()
00583 {
00584 QStringList fileList;
00585 fileList.append ( m_contextFileName );
00586 removeFiles ( fileList );
00587 }
00588
00589
00590 #include "antprojectpart.moc"
00591
00592
00596 QStringList AntProjectPart::distFiles() const
00597 {
00598 QStringList sourceList = allFiles();
00599
00600 QString projectDir = projectDirectory();
00601 QDir dir(projectDir);
00602 QStringList files = dir.entryList( "build.xml");
00603 return sourceList + files;
00604 }