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
CMakeSetupDialog dialog;
dialog.setWindowTitle("CMakeSetup");
dialog.show();
return app.exec();

View File

@ -18,32 +18,46 @@
#include "CMakeSetupDialog.h"
#include <QFileDialog>
#include <QThread>
#include <QProgressBar>
#include <QMessageBox>
#include <QStatusBar>
#include <QToolButton>
#include <QDialogButtonBox>
#include <QCloseEvent>
#include <QCoreApplication>
#include "QCMake.h"
#include "QCMakeCacheView.h"
// QCMake instance on a thread
class QCMakeThread : public QThread
QCMakeThread::QCMakeThread(QObject* p)
: QThread(p), CMakeInstance(NULL)
{
public:
QCMakeThread(QObject* p) : QThread(p) { }
QCMake* CMakeInstance;
}
protected:
virtual void run()
{
this->CMakeInstance = new QCMake;
this->exec();
delete this->CMakeInstance;
}
};
QCMake* QCMakeThread::cmakeInstance() const
{
return this->CMakeInstance;
}
void QCMakeThread::processEvents()
{
QCoreApplication::processEvents();
}
void QCMakeThread::run()
{
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();
delete this->CMakeInstance;
this->CMakeInstance = NULL;
}
CMakeSetupDialog::CMakeSetupDialog()
{
@ -65,25 +79,26 @@ CMakeSetupDialog::CMakeSetupDialog()
// start the cmake worker thread
this->CMakeThread = new QCMakeThread(this);
// TODO does this guarantee the QCMake instance is created before initialize is called?
QObject::connect(this->CMakeThread, SIGNAL(started()),
this, SLOT(initialize()));
QObject::connect(this->CMakeThread, SIGNAL(cmakeInitialized()),
this, SLOT(initialize()), Qt::QueuedConnection);
this->CMakeThread->start();
}
void CMakeSetupDialog::initialize()
{
// 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&)),
this->CacheValues->cacheModel(),
SLOT(setProperties(const QCMakeCachePropertyList&)));
QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)),
this, SLOT(doConfigure()));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(configureDone(int)),
QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(configureDone(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)));
QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)),
@ -98,25 +113,31 @@ void CMakeSetupDialog::initialize()
this, SLOT(doBinaryBrowse()));
QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
this->CMakeThread->CMakeInstance, SLOT(setBinaryDirectory(QString)));
this, SLOT(setBinaryDirectory(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)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(progressChanged(QString, float)),
QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(progressChanged(QString, float)),
this, SLOT(showProgress(QString,float)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(error(QString, QString, bool*)),
this, SLOT(error(QString,QString,bool*)), Qt::BlockingQueuedConnection);
QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(error(QString, QString, bool*)),
this, SLOT(error(QString,QString,bool*)),
Qt::BlockingQueuedConnection);
QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)),
this->CMakeThread->CMakeInstance, SLOT(interrupt()));
this->CMakeThread->cmakeInstance(), SLOT(interrupt()));
QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)),
this, SLOT(doInterrupt()));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(outputMessage(QString)),
QObject::connect(this->CMakeThread->cmakeInstance(),
SIGNAL(outputMessage(QString)),
this->Output, SLOT(append(QString)));
QObject::connect(this->HelpButton, SIGNAL(clicked(bool)),
@ -135,36 +156,45 @@ void CMakeSetupDialog::doConfigure()
QDir dir(this->BinaryDirectory->currentText());
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: ");
message += this->BinaryDirectory->currentText();
QString title = tr("Create Directory");
QMessageBox::StandardButton btn =
QMessageBox::information(this, title, message, QMessageBox::Yes | QMessageBox::No);
QMessageBox::StandardButton btn;
btn = QMessageBox::information(this, title, message,
QMessageBox::Yes | QMessageBox::No);
if(btn == QMessageBox::No)
{
return;
}
dir.mkpath(".");
}
// prompt for generator if one doesn't exist
if(this->CMakeThread->cmakeInstance()->generator().isEmpty())
{
this->promptForGenerator();
}
this->InterruptButton->setEnabled(true);
this->setEnabledState(false);
this->Output->clear();
QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance,
QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"setProperties", Qt::QueuedConnection,
Q_ARG(QCMakeCachePropertyList,
this->CacheValues->cacheModel()->properties()));
QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance,
QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"configure", Qt::QueuedConnection);
}
void CMakeSetupDialog::finishConfigure(int error)
void CMakeSetupDialog::finishConfigure(int err)
{
this->InterruptButton->setEnabled(false);
this->setEnabledState(true);
this->ProgressBar->reset();
this->statusBar()->showMessage(tr("Configure Done"), 2000);
if(error != 0)
if(err != 0)
{
QMessageBox::critical(this, tr("Error"),
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->setEnabledState(true);
this->ProgressBar->reset();
this->statusBar()->showMessage(tr("Generate Done"), 2000);
if(error != 0)
if(err != 0)
{
QMessageBox::critical(this, tr("Error"),
tr("Error in generation process, project files may be invalid"),
@ -195,19 +225,27 @@ void CMakeSetupDialog::doOk()
this->InterruptButton->setEnabled(true);
this->setEnabledState(false);
this->Output->clear();
QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance,
QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"generate", Qt::QueuedConnection);
}
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())
{
QString message = tr("You have changed options but not rebuilt, "
"are you sure you want to exit?");
QString title = tr("Confirm Exit");
QMessageBox::StandardButton btn =
QMessageBox::critical(this, title, message, QMessageBox::Yes | QMessageBox::No);
QMessageBox::StandardButton btn;
btn = QMessageBox::critical(this, title, message,
QMessageBox::Yes | QMessageBox::No);
if(btn == QMessageBox::No)
{
e->ignore();
@ -217,30 +255,31 @@ void CMakeSetupDialog::closeEvent(QCloseEvent* e)
void CMakeSetupDialog::doHelp()
{
QString msg = tr("CMake is used to configure and generate build files for"
"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"
"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"
"built. It can be the same or a different directory than the source"
"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"
"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"
"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"
"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"
"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"
QString msg = tr("CMake is used to configure and generate build files for "
"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 "
"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 "
"built. It can be the same or a different directory than the source "
"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 "
"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 "
"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 "
"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 "
"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 "
"directory and exit CMake.");
QDialog dialog;
dialog.setWindowTitle(tr("CMakeSetup Help"));
QVBoxLayout* l = new QVBoxLayout(&dialog);
QLabel* label = new QLabel(&dialog);
l->addWidget(label);
label->setText(msg);
label->setWordWrap(true);
QLabel* lab = new QLabel(&dialog);
l->addWidget(lab);
lab->setText(msg);
lab->setWordWrap(true);
QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok,
Qt::Horizontal, &dialog);
QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept()));
@ -276,7 +315,7 @@ void CMakeSetupDialog::doBinaryBrowse()
{
QString dir = QFileDialog::getExistingDirectory(this,
tr("Enter Path to Build"), this->BinaryDirectory->currentText());
if(!dir.isEmpty())
if(!dir.isEmpty() && dir != this->BinaryDirectory->currentText())
{
this->setBinaryDirectory(dir);
}
@ -284,12 +323,11 @@ void CMakeSetupDialog::doBinaryBrowse()
void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
{
if(dir != this->BinaryDirectory->currentText())
{
this->CacheValues->cacheModel()->setProperties(QCMakeCachePropertyList());
this->Output->clear();
this->BinaryDirectory->setEditText(dir);
}
this->CacheValues->cacheModel()->clear();
this->Output->clear();
this->BinaryDirectory->setEditText(dir);
QMetaObject::invokeMethod(this->CMakeThread->cmakeInstance(),
"setBinaryDirectory", Qt::QueuedConnection, Q_ARG(QString, dir));
}
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));
}
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::critical(this, title, message, QMessageBox::Ok | QMessageBox::Cancel);
QMessageBox::StandardButton btn;
btn = QMessageBox::critical(this, title, message,
QMessageBox::Ok | QMessageBox::Cancel);
if(btn == QMessageBox::Cancel)
{
*cancel = false;
@ -318,7 +358,28 @@ void CMakeSetupDialog::setEnabledState(bool enabled)
this->ConfigureButton->setEnabled(enabled);
this->GenerateButton->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 <QMainWindow>
#include <QThread>
#include "ui_CMakeSetupDialog.h"
class QCMakeThread;
@ -48,6 +52,7 @@ protected slots:
void setBinaryDirectory(const QString& dir);
void showProgress(const QString& msg, float percent);
void setEnabledState(bool);
void promptForGenerator();
protected:
void closeEvent(QCloseEvent*);
@ -57,3 +62,23 @@ protected:
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 <QCoreApplication>
#include <QDir>
#include <QCoreApplication>
#include "cmake.h"
#include "cmCacheManager.h"
#include "cmSystemTools.h"
#include "cmExternalMakefileProjectGenerator.h"
QCMake::QCMake(QObject* p)
: QObject(p)
{
static int metaId = qRegisterMetaType<QCMakeCacheProperty>();
static int metaIdList = qRegisterMetaType<QCMakeCachePropertyList>();
qRegisterMetaType<QCMakeCacheProperty>();
qRegisterMetaType<QCMakeCachePropertyList>();
QDir appDir(QCoreApplication::applicationDirPath());
#if defined(Q_OS_WIN)
@ -46,6 +47,14 @@ QCMake::QCMake(QObject* p)
this->CMakeInstance = new cmake;
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()
@ -74,7 +83,17 @@ void QCMake::setBinaryDirectory(const QString& dir)
{
cmCacheManager *cachem = this->CMakeInstance->GetCacheManager();
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();
emit this->propertiesChanged(props);
cmCacheManager::CacheIterator itm = cachem->NewIterator();
@ -82,12 +101,24 @@ void QCMake::setBinaryDirectory(const QString& dir)
{
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()
@ -97,23 +128,23 @@ void QCMake::configure()
this->CMakeInstance->SetHomeOutputDirectory(this->BinaryDirectory.toAscii().data());
this->CMakeInstance->SetStartOutputDirectory(this->BinaryDirectory.toAscii().data());
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->LoadCache();
cmSystemTools::ResetErrorOccuredFlag();
int error = this->CMakeInstance->Configure();
int err = this->CMakeInstance->Configure();
emit this->propertiesChanged(this->properties());
emit this->configureDone(error);
emit this->configureDone(err);
}
void QCMake::generate()
{
cmSystemTools::ResetErrorOccuredFlag();
int error = this->CMakeInstance->Generate();
emit this->generateDone(error);
int err = this->CMakeInstance->Generate();
emit this->generateDone(err);
}
void QCMake::setProperties(const QCMakeCachePropertyList& props)
@ -137,7 +168,7 @@ void QCMake::setProperties(const QCMakeCachePropertyList& props)
cachem->SaveCache(this->BinaryDirectory.toAscii().data());
}
QCMakeCachePropertyList QCMake::properties()
QCMakeCachePropertyList QCMake::properties() const
{
QCMakeCachePropertyList ret;
@ -198,12 +229,22 @@ void QCMake::progressCallback(const char* msg, float percent, void* cd)
{
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);
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 <QVariant>
#include <QList>
#include <QStringList>
#include <QMetaType>
class cmake;
@ -40,8 +41,14 @@ struct QCMakeCacheProperty
QString Help;
PropertyType Type;
bool Advanced;
bool operator==(const QCMakeCacheProperty& other) const { return this->Key == other.Key; }
bool operator<(const QCMakeCacheProperty& other) const { return this->Key < other.Key; }
bool operator==(const QCMakeCacheProperty& other) const
{
return this->Key == other.Key;
}
bool operator<(const QCMakeCacheProperty& other) const
{
return this->Key < other.Key;
}
};
// make types usable with QVariant
@ -79,15 +86,15 @@ public slots:
public:
/// get the list of cache properties
QCMakeCachePropertyList properties();
QCMakeCachePropertyList properties() const;
/// get the current binary directory
QString binaryDirectory();
QString binaryDirectory() const;
/// get the current source directory
QString sourceDirectory();
QString sourceDirectory() const;
/// get the current generator
QString generator();
QString generator() const;
/// get the available generators
QStringList availableGenerators();
QStringList availableGenerators() const;
signals:
/// signal when properties change (during read from disk or configure process)
@ -112,11 +119,13 @@ protected:
cmake* CMakeInstance;
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 BinaryDirectory;
QString Generator;
QStringList AvailableGenerators;
QString CMakeExecutable;
};

View File

@ -22,17 +22,28 @@
#include <QHBoxLayout>
#include <QHeaderView>
#include <QEvent>
#include <QFileInfo>
#include <QStyle>
#include <QKeyEvent>
QCMakeCacheView::QCMakeCacheView(QWidget* p)
: QTableView(p), Init(false)
{
// hook up our model
QCMakeCacheModel* m = new QCMakeCacheModel(this);
this->setModel(m);
this->horizontalHeader()->setStretchLastSection(true);
this->verticalHeader()->hide();
// our delegate for creating our editors
QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
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)
@ -106,6 +117,11 @@ static uint qHash(const QCMakeCacheProperty& p)
return qHash(p.Key);
}
void QCMakeCacheModel::clear()
{
this->setProperties(QCMakeCachePropertyList());
}
void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props)
{
QSet<QCMakeCacheProperty> newProps = props.toSet();
@ -132,63 +148,63 @@ QCMakeCachePropertyList QCMakeCacheModel::properties() const
return this->Properties;
}
int QCMakeCacheModel::columnCount (const QModelIndex& /*parent*/ ) const
int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const
{
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" +
this->data(index, QCMakeCacheModel::HelpRole).toString();
return this->data(idx, Qt::DisplayRole).toString() + "\n" +
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)
{
return this->Properties[index.row()].Help;
return this->Properties[idx.row()].Help;
}
else if(role == QCMakeCacheModel::TypeRole)
{
return this->Properties[index.row()].Type;
return this->Properties[idx.row()].Type;
}
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 QVariant();
}
QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*index*/) const
QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const
{
return QModelIndex();
}
int QCMakeCacheModel::rowCount (const QModelIndex& parent) const
int QCMakeCacheModel::rowCount (const QModelIndex& p) const
{
if(parent.isValid())
if(p.isValid())
{
return 0;
}
@ -205,15 +221,15 @@ QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int
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;
// all column 1's are editable
if(index.column() == 1)
if(idx.column() == 1)
{
f |= Qt::ItemIsEditable;
// booleans are editable in place
if(this->Properties[index.row()].Type == QCMakeCacheProperty::BOOL)
if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
{
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;
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;
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;
emit this->dataChanged(index, index);
emit this->dataChanged(idx, idx);
}
return false;
}
@ -252,28 +268,28 @@ QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
{
}
QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* parent,
const QStyleOptionViewItem&, const QModelIndex& index) const
QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,
const QStyleOptionViewItem&, const QModelIndex& idx) const
{
QVariant type = index.data(QCMakeCacheModel::TypeRole);
QVariant type = idx.data(QCMakeCacheModel::TypeRole);
if(type == QCMakeCacheProperty::BOOL)
{
return NULL;
}
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)
{
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, QWidget* p)
QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp,
QWidget* p)
: QWidget(p), LineEdit(this), IsFilePath(fp)
{
QHBoxLayout* l = new QHBoxLayout(this);
@ -286,6 +302,7 @@ QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp, QWidg
QObject::connect(tb, SIGNAL(clicked(bool)),
this, SLOT(chooseFile()));
this->LineEdit.setText(file);
this->LineEdit.selectAll();
tb->setFocusProxy(&this->LineEdit);
this->setFocusProxy(&this->LineEdit);
}
@ -295,11 +312,14 @@ void QCMakeCachePathEditor::chooseFile()
QString path;
if(this->IsFilePath)
{
path = QFileDialog::getOpenFileName(this, "TODO");
QFileInfo info(this->value());
path = QFileDialog::getOpenFileName(this, tr("Select File"),
info.absolutePath());
}
else
{
path = QFileDialog::getExistingDirectory(this, "TODO", this->value());
path = QFileDialog::getExistingDirectory(this, tr("Select Path"),
this->value());
}
if(!path.isEmpty())
{

View File

@ -55,6 +55,7 @@ public:
public slots:
void setProperties(const QCMakeCachePropertyList& props);
void clear();
public:
// satisfy [pure] virtuals
@ -77,14 +78,16 @@ protected:
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
{
Q_OBJECT
public:
QCMakeCacheModelDelegate(QObject* p);
/// 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