ENH: Prompt user for generator when there is none.

Many minor improvements, bug fixes, and style fixes.
This commit is contained in:
Clinton Stimpson 2007-11-05 13:20:54 -05:00
parent 7bd73d3e0d
commit cfa723d457
7 changed files with 300 additions and 140 deletions

View File

@ -31,6 +31,7 @@ int main(int argc, char** argv)
// TODO handle CMake args // TODO handle CMake args
CMakeSetupDialog dialog; CMakeSetupDialog dialog;
dialog.setWindowTitle("CMakeSetup");
dialog.show(); dialog.show();
return app.exec(); return app.exec();

View File

@ -18,32 +18,46 @@
#include "CMakeSetupDialog.h" #include "CMakeSetupDialog.h"
#include <QFileDialog> #include <QFileDialog>
#include <QThread>
#include <QProgressBar> #include <QProgressBar>
#include <QMessageBox> #include <QMessageBox>
#include <QStatusBar> #include <QStatusBar>
#include <QToolButton> #include <QToolButton>
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QCloseEvent> #include <QCloseEvent>
#include <QCoreApplication>
#include "QCMake.h" #include "QCMake.h"
#include "QCMakeCacheView.h" #include "QCMakeCacheView.h"
// QCMake instance on a thread QCMakeThread::QCMakeThread(QObject* p)
class QCMakeThread : public QThread : QThread(p), CMakeInstance(NULL)
{ {
public: }
QCMakeThread(QObject* p) : QThread(p) { }
QCMake* CMakeInstance;
protected: QCMake* QCMakeThread::cmakeInstance() const
virtual void run() {
{ return this->CMakeInstance;
}
void QCMakeThread::processEvents()
{
QCoreApplication::processEvents();
}
void QCMakeThread::run()
{
this->CMakeInstance = new QCMake; this->CMakeInstance = new QCMake;
// make the cmake thread to process events it receives from the GUI thread
QObject::connect(this->CMakeInstance, SIGNAL(progressChanged(QString, float)),
this, SLOT(processEvents()), Qt::DirectConnection);
QObject::connect(this->CMakeInstance, SIGNAL(outputMessage(QString)),
this, SLOT(processEvents()), Qt::DirectConnection);
// emit that this cmake thread is ready for use
emit this->cmakeInitialized();
this->exec(); this->exec();
delete this->CMakeInstance; delete this->CMakeInstance;
} this->CMakeInstance = NULL;
}; }
CMakeSetupDialog::CMakeSetupDialog() CMakeSetupDialog::CMakeSetupDialog()
{ {
@ -65,25 +79,26 @@ CMakeSetupDialog::CMakeSetupDialog()
// start the cmake worker thread // start the cmake worker thread
this->CMakeThread = new QCMakeThread(this); this->CMakeThread = new QCMakeThread(this);
// TODO does this guarantee the QCMake instance is created before initialize is called? QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()),
QObject::connect(this->CMakeThread, SIGNAL(started()), this, SLOT(initialize()), Qt::QueuedConnection);
this, SLOT(initialize()));
this->CMakeThread->start(); this->CMakeThread->start();
} }
void CMakeSetupDialog::initialize() void CMakeSetupDialog::initialize()
{ {
// now the cmake worker thread is running, lets make our connections to it // now the cmake worker thread is running, lets make our connections to it
QObject::connect(this->CMakeThread->CMakeInstance, QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(propertiesChanged(const QCMakeCachePropertyList&)), SIGNAL(propertiesChanged(const QCMakeCachePropertyList&)),
this->CacheValues->cacheModel(), this->CacheValues->cacheModel(),
SLOT(setProperties(const QCMakeCachePropertyList&))); SLOT(setProperties(const QCMakeCachePropertyList&)));
QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)), QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)),
this, SLOT(doConfigure())); this, SLOT(doConfigure()));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(configureDone(int)), QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(configureDone(int)),
this, SLOT(finishConfigure(int))); this, SLOT(finishConfigure(int)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(generateDone(int)), QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(generateDone(int)),
this, SLOT(finishGenerate(int))); this, SLOT(finishGenerate(int)));
QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)),
@ -98,25 +113,31 @@ void CMakeSetupDialog::initialize()
this, SLOT(doBinaryBrowse())); this, SLOT(doBinaryBrowse()));
QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)), QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
this->CMakeThread->CMakeInstance, SLOT(setBinaryDirectory(QString))); this, SLOT(setBinaryDirectory(QString)));
QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)), QObject::connect(this->SourceDirectory, SIGNAL(textChanged(QString)),
this->CMakeThread->CMakeInstance, SLOT(setSourceDirectory(QString))); this->CMakeThread->cmakeInstance(),
SLOT(setSourceDirectory(QString)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(sourceDirChanged(QString)), QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(sourceDirChanged(QString)),
this, SLOT(updateSourceDirectory(QString))); this, SLOT(updateSourceDirectory(QString)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(progressChanged(QString, float)), QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(progressChanged(QString, float)),
this, SLOT(showProgress(QString,float))); this, SLOT(showProgress(QString,float)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(error(QString, QString, bool*)), QObject::connect(this->CMakeThread->cmakeInstance(),
this, SLOT(error(QString,QString,bool*)), Qt::BlockingQueuedConnection); SIGNAL(error(QString, QString, bool*)),
this, SLOT(error(QString,QString,bool*)),
Qt::BlockingQueuedConnection);
QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)), QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)),
this->CMakeThread->CMakeInstance, SLOT(interrupt())); this->CMakeThread->cmakeInstance(), SLOT(interrupt()));
QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)), QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)),
this, SLOT(doInterrupt())); this, SLOT(doInterrupt()));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(outputMessage(QString)), QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(outputMessage(QString)),
this->Output, SLOT(append(QString))); this->Output, SLOT(append(QString)));
QObject::connect(this->HelpButton, SIGNAL(clicked(bool)), QObject::connect(this->HelpButton, SIGNAL(clicked(bool)),
@ -135,36 +156,45 @@ void CMakeSetupDialog::doConfigure()
QDir dir(this->BinaryDirectory->currentText()); QDir dir(this->BinaryDirectory->currentText());
if(!dir.exists()) if(!dir.exists())
{ {
QString message = tr("Build directory does not exist, should I create it?\n\n" QString message = tr("Build directory does not exist, "
"should I create it?\n\n"
"Directory: "); "Directory: ");
message += this->BinaryDirectory->currentText(); message += this->BinaryDirectory->currentText();
QString title = tr("Create Directory"); QString title = tr("Create Directory");
QMessageBox::StandardButton btn = QMessageBox::StandardButton btn;
QMessageBox::information(this, title, message, QMessageBox::Yes | QMessageBox::No); btn = QMessageBox::information(this, title, message,
QMessageBox::Yes | QMessageBox::No);
if(btn == QMessageBox::No) if(btn == QMessageBox::No)
{ {
return; return;
} }
dir.mkpath("."); dir.mkpath(".");
} }
// prompt for generator if one doesn't exist
if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
{
this->promptForGenerator();
}
this->InterruptButton->setEnabled(true); this->InterruptButton->setEnabled(true);
this->setEnabledState(false); this->setEnabledState(false);
this->Output->clear(); this->Output->clear();
QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance, QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"setProperties", Qt::QueuedConnection, "setProperties", Qt::QueuedConnection,
Q_ARG(QCMakeCachePropertyList, Q_ARG(QCMakeCachePropertyList,
this->CacheValues->cacheModel()->properties())); this->CacheValues->cacheModel()->properties()));
QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance, QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"configure", Qt::QueuedConnection); "configure", Qt::QueuedConnection);
} }
void CMakeSetupDialog::finishConfigure(int error) void CMakeSetupDialog::finishConfigure(int err)
{ {
this->InterruptButton->setEnabled(false); this->InterruptButton->setEnabled(false);
this->setEnabledState(true); this->setEnabledState(true);
this->ProgressBar->reset(); this->ProgressBar->reset();
this->statusBar()->showMessage(tr("Configure Done"), 2000); this->statusBar()->showMessage(tr("Configure Done"), 2000);
if(error != 0) if(err != 0)
{ {
QMessageBox::critical(this, tr("Error"), QMessageBox::critical(this, tr("Error"),
tr("Error in configuration process, project files may be invalid"), tr("Error in configuration process, project files may be invalid"),
@ -172,13 +202,13 @@ void CMakeSetupDialog::finishConfigure(int error)
} }
} }
void CMakeSetupDialog::finishGenerate(int error) void CMakeSetupDialog::finishGenerate(int err)
{ {
this->InterruptButton->setEnabled(false); this->InterruptButton->setEnabled(false);
this->setEnabledState(true); this->setEnabledState(true);
this->ProgressBar->reset(); this->ProgressBar->reset();
this->statusBar()->showMessage(tr("Generate Done"), 2000); this->statusBar()->showMessage(tr("Generate Done"), 2000);
if(error != 0) if(err != 0)
{ {
QMessageBox::critical(this, tr("Error"), QMessageBox::critical(this, tr("Error"),
tr("Error in generation process, project files may be invalid"), tr("Error in generation process, project files may be invalid"),
@ -195,19 +225,27 @@ void CMakeSetupDialog::doOk()
this->InterruptButton->setEnabled(true); this->InterruptButton->setEnabled(true);
this->setEnabledState(false); this->setEnabledState(false);
this->Output->clear(); this->Output->clear();
QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance, QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"generate", Qt::QueuedConnection); "generate", Qt::QueuedConnection);
} }
void CMakeSetupDialog::closeEvent(QCloseEvent* e) void CMakeSetupDialog::closeEvent(QCloseEvent* e)
{ {
// don't close if we're busy
if(this->InterruptButton->isEnabled())
{
e->ignore();
}
// prompt for close if there are unsaved changes
if(this->CacheValues->cacheModel()->isDirty()) if(this->CacheValues->cacheModel()->isDirty())
{ {
QString message = tr("You have changed options but not rebuilt, " QString message = tr("You have changed options but not rebuilt, "
"are you sure you want to exit?"); "are you sure you want to exit?");
QString title = tr("Confirm Exit"); QString title = tr("Confirm Exit");
QMessageBox::StandardButton btn = QMessageBox::StandardButton btn;
QMessageBox::critical(this, title, message, QMessageBox::Yes | QMessageBox::No); btn = QMessageBox::critical(this, title, message,
QMessageBox::Yes | QMessageBox::No);
if(btn == QMessageBox::No) if(btn == QMessageBox::No)
{ {
e->ignore(); e->ignore();
@ -217,30 +255,31 @@ void CMakeSetupDialog::closeEvent(QCloseEvent* e)
void CMakeSetupDialog::doHelp() void CMakeSetupDialog::doHelp()
{ {
QString msg = tr("CMake is used to configure and generate build files for" QString msg = tr("CMake is used to configure and generate build files for "
"software projects. The basic steps for configuring a project are as" "software projects. The basic steps for configuring a project are as "
"follows:\r\n\r\n1. Select the source directory for the project. This should" "follows:\r\n\r\n1. Select the source directory for the project. This should "
"contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the build" "contain the CMakeLists.txt files for the project.\r\n\r\n2. Select the build "
"directory for the project. This is the directory where the project will be" "directory for the project. This is the directory where the project will be "
"built. It can be the same or a different directory than the source" "built. It can be the same or a different directory than the source "
"directory. For easy clean up, a separate build directory is recommended." "directory. For easy clean up, a separate build directory is recommended. "
"CMake will create the directory if it does not exist.\r\n\r\n3. Once the" "CMake will create the directory if it does not exist.\r\n\r\n3. Once the "
"source and binary directories are selected, it is time to press the" "source and binary directories are selected, it is time to press the "
"Configure button. This will cause CMake to read all of the input files and" "Configure button. This will cause CMake to read all of the input files and "
"discover all the variables used by the project. The first time a variable" "discover all the variables used by the project. The first time a variable "
"is displayed it will be in Red. Users should inspect red variables making" "is displayed it will be in Red. Users should inspect red variables making "
"sure the values are correct. For some projects the Configure process can" "sure the values are correct. For some projects the Configure process can "
"be iterative, so continue to press the Configure button until there are no" "be iterative, so continue to press the Configure button until there are no "
"longer red entries.\r\n\r\n4. Once there are no longer red entries, you" "longer red entries.\r\n\r\n4. Once there are no longer red entries, you "
"should click the OK button. This will write the build files to the build" "should click the OK button. This will write the build files to the build "
"directory and exit CMake."); "directory and exit CMake.");
QDialog dialog; QDialog dialog;
dialog.setWindowTitle(tr("CMakeSetup Help"));
QVBoxLayout* l = new QVBoxLayout(&dialog); QVBoxLayout* l = new QVBoxLayout(&dialog);
QLabel* label = new QLabel(&dialog); QLabel* lab = new QLabel(&dialog);
l->addWidget(label); l->addWidget(lab);
label->setText(msg); lab->setText(msg);
label->setWordWrap(true); lab->setWordWrap(true);
QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok, QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
Qt::Horizontal, &dialog); Qt::Horizontal, &dialog);
QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
@ -276,7 +315,7 @@ void CMakeSetupDialog::doBinaryBrowse()
{ {
QString dir = QFileDialog::getExistingDirectory(this, QString dir = QFileDialog::getExistingDirectory(this,
tr("Enter Path to Build"), this->BinaryDirectory->currentText()); tr("Enter Path to Build"), this->BinaryDirectory->currentText());
if(!dir.isEmpty()) if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
{ {
this->setBinaryDirectory(dir); this->setBinaryDirectory(dir);
} }
@ -284,12 +323,11 @@ void CMakeSetupDialog::doBinaryBrowse()
void CMakeSetupDialog::setBinaryDirectory(const QString& dir) void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
{ {
if(dir != this->BinaryDirectory->currentText()) this->CacheValues->cacheModel()->clear();
{
this->CacheValues->cacheModel()->setProperties(QCMakeCachePropertyList());
this->Output->clear(); this->Output->clear();
this->BinaryDirectory->setEditText(dir); this->BinaryDirectory->setEditText(dir);
} QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
} }
void CMakeSetupDialog::showProgress(const QString& msg, float percent) void CMakeSetupDialog::showProgress(const QString& msg, float percent)
@ -298,10 +336,12 @@ void CMakeSetupDialog::showProgress(const QString& msg, float percent)
this->ProgressBar->setValue(qRound(percent * 100)); this->ProgressBar->setValue(qRound(percent * 100));
} }
void CMakeSetupDialog::error(const QString& title, const QString& message, bool* cancel) void CMakeSetupDialog::error(const QString& title, const QString& message,
bool* cancel)
{ {
QMessageBox::StandardButton btn = QMessageBox::StandardButton btn;
QMessageBox::critical(this, title, message, QMessageBox::Ok | QMessageBox::Cancel); btn = QMessageBox::critical(this, title, message,
QMessageBox::Ok | QMessageBox::Cancel);
if(btn == QMessageBox::Cancel) if(btn == QMessageBox::Cancel)
{ {
*cancel = false; *cancel = false;
@ -318,7 +358,28 @@ void CMakeSetupDialog::setEnabledState(bool enabled)
this->ConfigureButton->setEnabled(enabled); this->ConfigureButton->setEnabled(enabled);
this->GenerateButton->setEnabled(enabled); this->GenerateButton->setEnabled(enabled);
this->CancelButton->setEnabled(enabled); this->CancelButton->setEnabled(enabled);
this->HelpButton->setEnabled(enabled);
} }
void CMakeSetupDialog::promptForGenerator()
{
QStringList gens = this->CMakeThread->cmakeInstance()->availableGenerators();
QDialog dialog;
dialog.setWindowTitle(tr("CMakeSetup choose generator"));
QLabel* lab = new QLabel(&dialog);
lab->setText(tr("Please select what build system you want CMake to generate files for.\n"
"You should select the tool that you will use to build the project.\n"
"Press OK once you have made your selection."));
QComboBox* combo = new QComboBox(&dialog);
combo->addItems(gens);
QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
Qt::Horizontal, &dialog);
QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
QVBoxLayout* l = new QVBoxLayout(&dialog);
l->addWidget(lab);
l->addWidget(combo);
l->addWidget(btns);
dialog.exec();
this->CMakeThread->cmakeInstance()->setGenerator(combo->currentText());
}

View File

@ -15,8 +15,12 @@
=========================================================================*/ =========================================================================*/
#ifndef CMakeSetupDialog_h
#define CMakeSetupDialog_h
#include "QCMake.h" #include "QCMake.h"
#include <QMainWindow> #include <QMainWindow>
#include <QThread>
#include "ui_CMakeSetupDialog.h" #include "ui_CMakeSetupDialog.h"
class QCMakeThread; class QCMakeThread;
@ -48,6 +52,7 @@ protected slots:
void setBinaryDirectory(const QString& dir); void setBinaryDirectory(const QString& dir);
void showProgress(const QString& msg, float percent); void showProgress(const QString& msg, float percent);
void setEnabledState(bool); void setEnabledState(bool);
void promptForGenerator();
protected: protected:
void closeEvent(QCloseEvent*); void closeEvent(QCloseEvent*);
@ -57,3 +62,23 @@ protected:
QToolButton* InterruptButton; QToolButton* InterruptButton;
}; };
// QCMake instance on a thread
class QCMakeThread : public QThread
{
Q_OBJECT
public:
QCMakeThread(QObject* p);
QCMake* cmakeInstance() const;
signals:
void cmakeInitialized();
protected slots:
void processEvents();
protected:
virtual void run();
QCMake* CMakeInstance;
};
#endif // CMakeSetupDialog_h

View File

@ -17,18 +17,19 @@
#include "QCMake.h" #include "QCMake.h"
#include <QCoreApplication>
#include <QDir> #include <QDir>
#include <QCoreApplication>
#include "cmake.h" #include "cmake.h"
#include "cmCacheManager.h" #include "cmCacheManager.h"
#include "cmSystemTools.h" #include "cmSystemTools.h"
#include "cmExternalMakefileProjectGenerator.h"
QCMake::QCMake(QObject* p) QCMake::QCMake(QObject* p)
: QObject(p) : QObject(p)
{ {
static int metaId = qRegisterMetaType<QCMakeCacheProperty>(); qRegisterMetaType<QCMakeCacheProperty>();
static int metaIdList = qRegisterMetaType<QCMakeCachePropertyList>(); qRegisterMetaType<QCMakeCachePropertyList>();
QDir appDir(QCoreApplication::applicationDirPath()); QDir appDir(QCoreApplication::applicationDirPath());
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
@ -46,6 +47,14 @@ QCMake::QCMake(QObject* p)
this->CMakeInstance = new cmake; this->CMakeInstance = new cmake;
this->CMakeInstance->SetProgressCallback(QCMake::progressCallback, this); this->CMakeInstance->SetProgressCallback(QCMake::progressCallback, this);
std::vector<std::string> generators;
this->CMakeInstance->GetRegisteredGenerators(generators);
std::vector<std::string>::iterator iter;
for(iter = generators.begin(); iter != generators.end(); ++iter)
{
this->AvailableGenerators.append(QString::fromStdString(*iter));
}
} }
QCMake::~QCMake() QCMake::~QCMake()
@ -74,7 +83,17 @@ void QCMake::setBinaryDirectory(const QString& dir)
{ {
cmCacheManager *cachem = this->CMakeInstance->GetCacheManager(); cmCacheManager *cachem = this->CMakeInstance->GetCacheManager();
this->BinaryDirectory = dir; this->BinaryDirectory = dir;
this->CMakeInstance->GetCacheManager()->LoadCache(dir.toLocal8Bit().data()); this->setGenerator(QString());
if(!this->CMakeInstance->GetCacheManager()->LoadCache(dir.toLocal8Bit().data()))
{
QDir testDir(dir);
if(testDir.exists("CMakeCache.txt"))
{
cmSystemTools::Error("There is a CMakeCache.txt file for the current binary "
"tree but cmake does not have permission to read it. "
"Please check the permissions of the directory you are trying to run CMake on.");
}
}
QCMakeCachePropertyList props = this->properties(); QCMakeCachePropertyList props = this->properties();
emit this->propertiesChanged(props); emit this->propertiesChanged(props);
cmCacheManager::CacheIterator itm = cachem->NewIterator(); cmCacheManager::CacheIterator itm = cachem->NewIterator();
@ -82,12 +101,24 @@ void QCMake::setBinaryDirectory(const QString& dir)
{ {
setSourceDirectory(itm.GetValue()); setSourceDirectory(itm.GetValue());
} }
if ( itm.Find("CMAKE_GENERATOR"))
{
const char* extraGen = cachem->GetCacheValue("CMAKE_EXTRA_GENERATOR");
std::string curGen = cmExternalMakefileProjectGenerator::
CreateFullGeneratorName(itm.GetValue(), extraGen);
this->setGenerator(QString::fromStdString(curGen));
}
} }
} }
void QCMake::setGenerator(const QString& generator) void QCMake::setGenerator(const QString& gen)
{ {
if(this->Generator != gen)
{
this->Generator = gen;
emit this->generatorChanged(this->Generator);
}
} }
void QCMake::configure() void QCMake::configure()
@ -97,23 +128,23 @@ void QCMake::configure()
this->CMakeInstance->SetHomeOutputDirectory(this->BinaryDirectory.toAscii().data()); this->CMakeInstance->SetHomeOutputDirectory(this->BinaryDirectory.toAscii().data());
this->CMakeInstance->SetStartOutputDirectory(this->BinaryDirectory.toAscii().data()); this->CMakeInstance->SetStartOutputDirectory(this->BinaryDirectory.toAscii().data());
this->CMakeInstance->SetGlobalGenerator( this->CMakeInstance->SetGlobalGenerator(
this->CMakeInstance->CreateGlobalGenerator("Unix Makefiles")); // TODO this->CMakeInstance->CreateGlobalGenerator(this->Generator.toAscii().data()));
this->CMakeInstance->SetCMakeCommand(this->CMakeExecutable.toAscii().data()); this->CMakeInstance->SetCMakeCommand(this->CMakeExecutable.toAscii().data());
this->CMakeInstance->LoadCache(); this->CMakeInstance->LoadCache();
cmSystemTools::ResetErrorOccuredFlag(); cmSystemTools::ResetErrorOccuredFlag();
int error = this->CMakeInstance->Configure(); int err = this->CMakeInstance->Configure();
emit this->propertiesChanged(this->properties()); emit this->propertiesChanged(this->properties());
emit this->configureDone(error); emit this->configureDone(err);
} }
void QCMake::generate() void QCMake::generate()
{ {
cmSystemTools::ResetErrorOccuredFlag(); cmSystemTools::ResetErrorOccuredFlag();
int error = this->CMakeInstance->Generate(); int err = this->CMakeInstance->Generate();
emit this->generateDone(error); emit this->generateDone(err);
} }
void QCMake::setProperties(const QCMakeCachePropertyList& props) void QCMake::setProperties(const QCMakeCachePropertyList& props)
@ -137,7 +168,7 @@ void QCMake::setProperties(const QCMakeCachePropertyList& props)
cachem->SaveCache(this->BinaryDirectory.toAscii().data()); cachem->SaveCache(this->BinaryDirectory.toAscii().data());
} }
QCMakeCachePropertyList QCMake::properties() QCMakeCachePropertyList QCMake::properties() const
{ {
QCMakeCachePropertyList ret; QCMakeCachePropertyList ret;
@ -198,12 +229,22 @@ void QCMake::progressCallback(const char* msg, float percent, void* cd)
{ {
emit self->outputMessage(msg); emit self->outputMessage(msg);
} }
QCoreApplication::processEvents();
} }
void QCMake::errorCallback(const char* msg, const char* title, bool& stop, void* cd) void QCMake::errorCallback(const char* msg, const char* title,
bool& stop, void* cd)
{ {
QCMake* self = reinterpret_cast<QCMake*>(cd); QCMake* self = reinterpret_cast<QCMake*>(cd);
emit self->error(title, msg, &stop); emit self->error(title, msg, &stop);
} }
QString QCMake::generator() const
{
return this->Generator;
}
QStringList QCMake::availableGenerators() const
{
return this->AvailableGenerators;
}

View File

@ -26,6 +26,7 @@
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QList> #include <QList>
#include <QStringList>
#include <QMetaType> #include <QMetaType>
class cmake; class cmake;
@ -40,8 +41,14 @@ struct QCMakeCacheProperty
QString Help; QString Help;
PropertyType Type; PropertyType Type;
bool Advanced; bool Advanced;
bool operator==(const QCMakeCacheProperty& other) const { return this->Key == other.Key; } bool operator==(const QCMakeCacheProperty& other) const
bool operator<(const QCMakeCacheProperty& other) const { return this->Key < other.Key; } {
return this->Key == other.Key;
}
bool operator<(const QCMakeCacheProperty& other) const
{
return this->Key < other.Key;
}
}; };
// make types usable with QVariant // make types usable with QVariant
@ -79,15 +86,15 @@ public slots:
public: public:
/// get the list of cache properties /// get the list of cache properties
QCMakeCachePropertyList properties(); QCMakeCachePropertyList properties() const;
/// get the current binary directory /// get the current binary directory
QString binaryDirectory(); QString binaryDirectory() const;
/// get the current source directory /// get the current source directory
QString sourceDirectory(); QString sourceDirectory() const;
/// get the current generator /// get the current generator
QString generator(); QString generator() const;
/// get the available generators /// get the available generators
QStringList availableGenerators(); QStringList availableGenerators() const;
signals: signals:
/// signal when properties change (during read from disk or configure process) /// signal when properties change (during read from disk or configure process)
@ -112,11 +119,13 @@ protected:
cmake* CMakeInstance; cmake* CMakeInstance;
static void progressCallback(const char* msg, float percent, void* cd); static void progressCallback(const char* msg, float percent, void* cd);
static void errorCallback(const char* msg, const char* title, bool&, void* cd); static void errorCallback(const char* msg, const char* title,
bool&, void* cd);
QString SourceDirectory; QString SourceDirectory;
QString BinaryDirectory; QString BinaryDirectory;
QString Generator; QString Generator;
QStringList AvailableGenerators;
QString CMakeExecutable; QString CMakeExecutable;
}; };

View File

@ -22,17 +22,28 @@
#include <QHBoxLayout> #include <QHBoxLayout>
#include <QHeaderView> #include <QHeaderView>
#include <QEvent> #include <QEvent>
#include <QFileInfo>
#include <QStyle>
#include <QKeyEvent>
QCMakeCacheView::QCMakeCacheView(QWidget* p) QCMakeCacheView::QCMakeCacheView(QWidget* p)
: QTableView(p), Init(false) : QTableView(p), Init(false)
{ {
// hook up our model
QCMakeCacheModel* m = new QCMakeCacheModel(this); QCMakeCacheModel* m = new QCMakeCacheModel(this);
this->setModel(m); this->setModel(m);
this->horizontalHeader()->setStretchLastSection(true);
this->verticalHeader()->hide();
// our delegate for creating our editors
QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this); QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
this->setItemDelegate(delegate); this->setItemDelegate(delegate);
// set up headers and sizes
int h = 0;
QFontMetrics met(this->font());
h = qMax(met.height(), this->style()->pixelMetric(QStyle::PM_IndicatorHeight));
this->verticalHeader()->setDefaultSectionSize(h + 4);
this->horizontalHeader()->setStretchLastSection(true);
this->verticalHeader()->hide();
} }
void QCMakeCacheView::showEvent(QShowEvent* e) void QCMakeCacheView::showEvent(QShowEvent* e)
@ -106,6 +117,11 @@ static uint qHash(const QCMakeCacheProperty& p)
return qHash(p.Key); return qHash(p.Key);
} }
void QCMakeCacheModel::clear()
{
this->setProperties(QCMakeCachePropertyList());
}
void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props) void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props)
{ {
QSet<QCMakeCacheProperty> newProps = props.toSet(); QSet<QCMakeCacheProperty> newProps = props.toSet();
@ -132,63 +148,63 @@ QCMakeCachePropertyList QCMakeCacheModel::properties() const
return this->Properties; return this->Properties;
} }
int QCMakeCacheModel::columnCount (const QModelIndex& /*parent*/ ) const int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const
{ {
return 2; return 2;
} }
QVariant QCMakeCacheModel::data (const QModelIndex& index, int role) const QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const
{ {
if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
return this->Properties[index.row()].Key; return this->Properties[idx.row()].Key;
} }
else if(index.column() == 0 && role == Qt::ToolTipRole) else if(idx.column() == 0 && role == Qt::ToolTipRole)
{ {
return this->data(index, Qt::DisplayRole).toString() + "\n" + return this->data(idx, Qt::DisplayRole).toString() + "\n" +
this->data(index, QCMakeCacheModel::HelpRole).toString(); this->data(idx, QCMakeCacheModel::HelpRole).toString();
} }
else if(index.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
if(this->Properties[index.row()].Type != QCMakeCacheProperty::BOOL) if(this->Properties[idx.row()].Type != QCMakeCacheProperty::BOOL)
{ {
return this->Properties[index.row()].Value; return this->Properties[idx.row()].Value;
} }
} }
else if(index.column() == 1 && role == Qt::CheckStateRole) else if(idx.column() == 1 && role == Qt::CheckStateRole)
{ {
if(this->Properties[index.row()].Type == QCMakeCacheProperty::BOOL) if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
{ {
return this->Properties[index.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked; return this->Properties[idx.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked;
} }
} }
else if(role == QCMakeCacheModel::HelpRole) else if(role == QCMakeCacheModel::HelpRole)
{ {
return this->Properties[index.row()].Help; return this->Properties[idx.row()].Help;
} }
else if(role == QCMakeCacheModel::TypeRole) else if(role == QCMakeCacheModel::TypeRole)
{ {
return this->Properties[index.row()].Type; return this->Properties[idx.row()].Type;
} }
else if(role == QCMakeCacheModel::AdvancedRole) else if(role == QCMakeCacheModel::AdvancedRole)
{ {
return this->Properties[index.row()].Advanced; return this->Properties[idx.row()].Advanced;
} }
else if(role == Qt::BackgroundRole && index.row()+1 <= this->NewCount) else if(role == Qt::BackgroundRole && idx.row()+1 <= this->NewCount)
{ {
return QBrush(QColor(255,100,100)); return QBrush(QColor(255,100,100));
} }
return QVariant(); return QVariant();
} }
QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*index*/) const QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const
{ {
return QModelIndex(); return QModelIndex();
} }
int QCMakeCacheModel::rowCount (const QModelIndex& parent) const int QCMakeCacheModel::rowCount (const QModelIndex& p) const
{ {
if(parent.isValid()) if(p.isValid())
{ {
return 0; return 0;
} }
@ -205,15 +221,15 @@ QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int
return QVariant(); return QVariant();
} }
Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& index) const Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const
{ {
Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable; Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
// all column 1's are editable // all column 1's are editable
if(index.column() == 1) if(idx.column() == 1)
{ {
f |= Qt::ItemIsEditable; f |= Qt::ItemIsEditable;
// booleans are editable in place // booleans are editable in place
if(this->Properties[index.row()].Type == QCMakeCacheProperty::BOOL) if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
{ {
f |= Qt::ItemIsUserCheckable; f |= Qt::ItemIsUserCheckable;
} }
@ -222,25 +238,25 @@ Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& index) const
} }
bool QCMakeCacheModel::setData (const QModelIndex& index, const QVariant& value, int role) bool QCMakeCacheModel::setData (const QModelIndex& idx, const QVariant& value, int role)
{ {
if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
this->Properties[index.row()].Key = value.toString(); this->Properties[idx.row()].Key = value.toString();
this->IsDirty = true; this->IsDirty = true;
emit this->dataChanged(index, index); emit this->dataChanged(idx, idx);
} }
else if(index.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
this->Properties[index.row()].Value = value.toString(); this->Properties[idx.row()].Value = value.toString();
this->IsDirty = true; this->IsDirty = true;
emit this->dataChanged(index, index); emit this->dataChanged(idx, idx);
} }
else if(index.column() == 1 && (role == Qt::CheckStateRole)) else if(idx.column() == 1 && (role == Qt::CheckStateRole))
{ {
this->Properties[index.row()].Value = value.toInt() == Qt::Checked; this->Properties[idx.row()].Value = value.toInt() == Qt::Checked;
this->IsDirty = true; this->IsDirty = true;
emit this->dataChanged(index, index); emit this->dataChanged(idx, idx);
} }
return false; return false;
} }
@ -252,28 +268,28 @@ QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
{ {
} }
QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* parent, QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,
const QStyleOptionViewItem&, const QModelIndex& index) const const QStyleOptionViewItem&, const QModelIndex& idx) const
{ {
QVariant type = index.data(QCMakeCacheModel::TypeRole); QVariant type = idx.data(QCMakeCacheModel::TypeRole);
if(type == QCMakeCacheProperty::BOOL) if(type == QCMakeCacheProperty::BOOL)
{ {
return NULL; return NULL;
} }
else if(type == QCMakeCacheProperty::PATH) else if(type == QCMakeCacheProperty::PATH)
{ {
return new QCMakeCachePathEditor(index.data().toString(), false, parent); return new QCMakeCachePathEditor(idx.data().toString(), false, p);
} }
else if(type == QCMakeCacheProperty::FILEPATH) else if(type == QCMakeCacheProperty::FILEPATH)
{ {
return new QCMakeCachePathEditor(index.data().toString(), true, parent); return new QCMakeCachePathEditor(idx.data().toString(), true, p);
} }
return new QLineEdit(parent); return new QLineEdit(p);
} }
QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp,
QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp, QWidget* p) QWidget* p)
: QWidget(p), LineEdit(this), IsFilePath(fp) : QWidget(p), LineEdit(this), IsFilePath(fp)
{ {
QHBoxLayout* l = new QHBoxLayout(this); QHBoxLayout* l = new QHBoxLayout(this);
@ -286,6 +302,7 @@ QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp, QWidg
QObject::connect(tb, SIGNAL(clicked(bool)), QObject::connect(tb, SIGNAL(clicked(bool)),
this, SLOT(chooseFile())); this, SLOT(chooseFile()));
this->LineEdit.setText(file); this->LineEdit.setText(file);
this->LineEdit.selectAll();
tb->setFocusProxy(&this->LineEdit); tb->setFocusProxy(&this->LineEdit);
this->setFocusProxy(&this->LineEdit); this->setFocusProxy(&this->LineEdit);
} }
@ -295,11 +312,14 @@ void QCMakeCachePathEditor::chooseFile()
QString path; QString path;
if(this->IsFilePath) if(this->IsFilePath)
{ {
path = QFileDialog::getOpenFileName(this, "TODO"); QFileInfo info(this->value());
path = QFileDialog::getOpenFileName(this, tr("Select File"),
info.absolutePath());
} }
else else
{ {
path = QFileDialog::getExistingDirectory(this, "TODO", this->value()); path = QFileDialog::getExistingDirectory(this, tr("Select Path"),
this->value());
} }
if(!path.isEmpty()) if(!path.isEmpty())
{ {

View File

@ -55,6 +55,7 @@ public:
public slots: public slots:
void setProperties(const QCMakeCachePropertyList& props); void setProperties(const QCMakeCachePropertyList& props);
void clear();
public: public:
// satisfy [pure] virtuals // satisfy [pure] virtuals
@ -77,14 +78,16 @@ protected:
bool IsDirty; bool IsDirty;
}; };
/// Qt delegate class for interaction (or other customization) with cache properties /// Qt delegate class for interaction (or other customization)
/// with cache properties
class QCMakeCacheModelDelegate : public QItemDelegate class QCMakeCacheModelDelegate : public QItemDelegate
{ {
Q_OBJECT Q_OBJECT
public: public:
QCMakeCacheModelDelegate(QObject* p); QCMakeCacheModelDelegate(QObject* p);
/// create our own editors for cache properties /// create our own editors for cache properties
QWidget* createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const; QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option,
const QModelIndex& index ) const;
}; };
/// Editor widget for editing paths or file paths /// Editor widget for editing paths or file paths