diff --git a/Source/QtDialog/CMakeLists.txt b/Source/QtDialog/CMakeLists.txt index 540887c2d..81c36cf2d 100644 --- a/Source/QtDialog/CMakeLists.txt +++ b/Source/QtDialog/CMakeLists.txt @@ -6,7 +6,6 @@ IF(NOT QT4_FOUND) MESSAGE(SEND_ERROR "Failed to find Qt 4.3 or greater.") ELSE(NOT QT4_FOUND) - SET(QT_USE_QTMAIN TRUE) INCLUDE(${QT_USE_FILE}) SET(SRCS @@ -18,7 +17,6 @@ ELSE(NOT QT4_FOUND) QCMakeCacheView.cxx QCMakeCacheView.h ) - QT4_WRAP_UI(UI_SRCS CMakeSetupDialog.ui ) @@ -30,13 +28,16 @@ ELSE(NOT QT4_FOUND) QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc) SET(SRCS ${SRCS} ${UI_SRCS} ${MOC_SRCS} ${RC_SRCS}) + IF(WIN32) + SET(SRCS ${SRCS} CMakeSetup.rc) + ENDIF(WIN32) + # TODO Mac OS X icon INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) ADD_EXECUTABLE(QtDialog WIN32 MACOSX_BUNDLE ${SRCS}) - TARGET_LINK_LIBRARIES(QtDialog CMakeLib ${QT_LIBRARIES}) - ADD_DEPENDENCIES(QtDialog cmake) + TARGET_LINK_LIBRARIES(QtDialog CMakeLib ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES}) ENDIF(NOT QT4_FOUND) diff --git a/Source/QtDialog/CMakeSetup.cxx b/Source/QtDialog/CMakeSetup.cxx index 9b4f28b4d..5ae5c428f 100644 --- a/Source/QtDialog/CMakeSetup.cxx +++ b/Source/QtDialog/CMakeSetup.cxx @@ -26,6 +26,7 @@ int main(int argc, char** argv) QApplication app(argc, argv); app.setApplicationName("CMakeSetup"); app.setOrganizationName("Kitware"); + app.setWindowIcon(QIcon(":/Icons/CMakeSetup.png")); // TODO handle CMake args diff --git a/Source/QtDialog/CMakeSetup.ico b/Source/QtDialog/CMakeSetup.ico new file mode 100644 index 000000000..90fbdacd8 Binary files /dev/null and b/Source/QtDialog/CMakeSetup.ico differ diff --git a/Source/QtDialog/CMakeSetupDialog.png b/Source/QtDialog/CMakeSetup.png similarity index 100% rename from Source/QtDialog/CMakeSetupDialog.png rename to Source/QtDialog/CMakeSetup.png diff --git a/Source/QtDialog/CMakeSetup.qrc b/Source/QtDialog/CMakeSetup.qrc index 14357e036..88d634014 100644 --- a/Source/QtDialog/CMakeSetup.qrc +++ b/Source/QtDialog/CMakeSetup.qrc @@ -1,5 +1,5 @@ - CMakeSetupDialog.png + CMakeSetup.png diff --git a/Source/QtDialog/CMakeSetup.rc b/Source/QtDialog/CMakeSetup.rc new file mode 100644 index 000000000..fcc887ddb --- /dev/null +++ b/Source/QtDialog/CMakeSetup.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "CMakeSetup.ico" diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index d54c7cfd5..36fdb6fda 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include "QCMake.h" #include "QCMakeCacheView.h" @@ -44,9 +47,17 @@ protected: CMakeSetupDialog::CMakeSetupDialog() { // create the GUI - this->setupUi(this); + this->resize(700, 500); + QWidget* cont = new QWidget(this); + this->setupUi(cont); + this->setCentralWidget(cont); this->ProgressBar = new QProgressBar(); this->ProgressBar->setRange(0,100); + this->InterruptButton = new QToolButton(); + this->InterruptButton->setEnabled(false); + this->InterruptButton->setIcon( + this->style()->standardPixmap(QStyle::SP_DialogCancelButton)); + this->statusBar()->addPermanentWidget(this->InterruptButton); this->statusBar()->addPermanentWidget(this->ProgressBar); // start the cmake worker thread @@ -64,36 +75,26 @@ void CMakeSetupDialog::initialize() SIGNAL(propertiesChanged(const QCMakeCachePropertyList&)), this->CacheValues->cacheModel(), SLOT(setProperties(const QCMakeCachePropertyList&))); - QObject::connect(this, - SIGNAL(propertiesChanged(const QCMakeCachePropertyList&)), - this->CMakeThread->CMakeInstance, - SLOT(setProperties(const QCMakeCachePropertyList&))); - QObject::connect(this->configureButton, SIGNAL(clicked(bool)), + QObject::connect(this->ConfigureButton, SIGNAL(clicked(bool)), this, SLOT(doConfigure())); - QObject::connect(this, SIGNAL(configure()), - this->CMakeThread->CMakeInstance, SLOT(configure())); QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(configureDone(int)), this, SLOT(finishConfigure(int))); QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(generateDone(int)), this, SLOT(finishGenerate(int))); - QObject::connect(this->generateButton, SIGNAL(clicked(bool)), + QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), this, SLOT(doOk())); - QObject::connect(this, SIGNAL(ok()), - this->CMakeThread->CMakeInstance, SLOT(generate())); - QObject::connect(this->cancelButton, SIGNAL(clicked(bool)), + QObject::connect(this->CancelButton, SIGNAL(clicked(bool)), this, SLOT(doCancel())); - QObject::connect(this, SIGNAL(cancel()), - this->CMakeThread->CMakeInstance, SLOT(interrupt())); QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)), this, SLOT(doSourceBrowse())); QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)), this, SLOT(doBinaryBrowse())); - QObject::connect(this->BinaryDirectory, SIGNAL(textChanged(QString)), + QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)), this->CMakeThread->CMakeInstance, SLOT(setBinaryDirectory(QString))); QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(sourceDirChanged(QString)), @@ -105,6 +106,16 @@ void CMakeSetupDialog::initialize() 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())); + QObject::connect(this->InterruptButton, SIGNAL(clicked(bool)), + this, SLOT(doInterrupt())); + + QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(outputMessage(QString)), + this->Output, SLOT(append(QString))); + + QObject::connect(this->HelpButton, SIGNAL(clicked(bool)), + this, SLOT(doHelp())); } CMakeSetupDialog::~CMakeSetupDialog() @@ -116,49 +127,119 @@ CMakeSetupDialog::~CMakeSetupDialog() void CMakeSetupDialog::doConfigure() { - emit this->propertiesChanged(this->CacheValues->cacheModel()->properties()); - emit this->configure(); + this->InterruptButton->setEnabled(true); + this->setEnabledState(false); + this->Output->clear(); + QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance, + "setProperties", Qt::QueuedConnection, + Q_ARG(QCMakeCachePropertyList, + this->CacheValues->cacheModel()->properties())); + QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance, + "configure", Qt::QueuedConnection); } void CMakeSetupDialog::finishConfigure(int error) { + this->InterruptButton->setEnabled(false); + this->setEnabledState(true); this->ProgressBar->reset(); - this->statusBar()->showMessage("Configure Done", 2000); + this->statusBar()->showMessage(tr("Configure Done"), 2000); if(error != 0) - { - bool dummy; - this->error("Error", "Error in configuration process, project files may be invalid", &dummy); - } + { + QMessageBox::critical(this, tr("Error"), + tr("Error in configuration process, project files may be invalid"), + QMessageBox::Ok); + } } void CMakeSetupDialog::finishGenerate(int error) { + this->InterruptButton->setEnabled(false); + this->setEnabledState(true); this->ProgressBar->reset(); - this->statusBar()->showMessage("Generate Done", 2000); + this->statusBar()->showMessage(tr("Generate Done"), 2000); if(error != 0) - { - bool dummy; - this->error("Error", "Error in generation process, project files may be invalid", &dummy); - } + { + QMessageBox::critical(this, tr("Error"), + tr("Error in generation process, project files may be invalid"), + QMessageBox::Ok); + } + else + { + QApplication::quit(); + } } void CMakeSetupDialog::doOk() { - emit this->ok(); + this->InterruptButton->setEnabled(true); + this->setEnabledState(false); + this->Output->clear(); + QMetaObject::invokeMethod(this->CMakeThread->CMakeInstance, + "generate", Qt::QueuedConnection); } void CMakeSetupDialog::doCancel() { - emit this->cancel(); + 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::Ok | QMessageBox::Cancel); + if(btn == QMessageBox::Cancel) + { + return; + } + } + + QApplication::quit(); } 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" + "directory and exit CMake."); + + QDialog dialog; + QVBoxLayout* l = new QVBoxLayout(&dialog); + QLabel* label = new QLabel(&dialog); + l->addWidget(label); + label->setText(msg); + label->setWordWrap(true); + QDialogButtonBox* btns = new QDialogButtonBox(QDialogButtonBox::Ok, + Qt::Horizontal, &dialog); + QObject::connect(btns, SIGNAL(accepted()), &dialog, SLOT(accept())); + l->addWidget(btns); + dialog.exec(); +} + +void CMakeSetupDialog::doInterrupt() +{ + this->InterruptButton->setEnabled(false); + this->statusBar()->showMessage(tr("Interrupting...")); } void CMakeSetupDialog::doSourceBrowse() { - QString dir = QFileDialog::getExistingDirectory(this, "TODO", this->SourceDirectory->text()); + QString dir = QFileDialog::getExistingDirectory(this, + tr("Enter Path to Source"), this->SourceDirectory->text()); if(!dir.isEmpty()) { this->updateSourceDirectory(dir); @@ -172,7 +253,8 @@ void CMakeSetupDialog::updateSourceDirectory(const QString& dir) void CMakeSetupDialog::doBinaryBrowse() { - QString dir = QFileDialog::getExistingDirectory(this, "TODO", this->BinaryDirectory->currentText()); + QString dir = QFileDialog::getExistingDirectory(this, + tr("Enter Path to Build"), this->BinaryDirectory->currentText()); if(!dir.isEmpty()) { this->setBinaryDirectory(dir); @@ -182,18 +264,16 @@ void CMakeSetupDialog::doBinaryBrowse() void CMakeSetupDialog::setBinaryDirectory(const QString& dir) { if(dir != this->BinaryDirectory->currentText()) - { + { + this->Output->clear(); this->BinaryDirectory->setEditText(dir); - } + } } void CMakeSetupDialog::showProgress(const QString& msg, float percent) { - if(percent >= 0) - { - this->statusBar()->showMessage(msg); - this->ProgressBar->setValue(qRound(percent * 100)); - } + this->statusBar()->showMessage(msg); + this->ProgressBar->setValue(qRound(percent * 100)); } void CMakeSetupDialog::error(const QString& title, const QString& message, bool* cancel) @@ -201,9 +281,22 @@ void CMakeSetupDialog::error(const QString& title, const QString& message, bool* QMessageBox::StandardButton btn = QMessageBox::critical(this, title, message, QMessageBox::Ok | QMessageBox::Cancel); if(btn == QMessageBox::Cancel) - { + { *cancel = false; - } + } +} + +void CMakeSetupDialog::setEnabledState(bool enabled) +{ + this->CacheValues->setEnabled(enabled); + this->SourceDirectory->setEnabled(enabled); + this->BrowseSourceDirectoryButton->setEnabled(enabled); + this->BinaryDirectory->setEnabled(enabled); + this->BrowseBinaryDirectoryButton->setEnabled(enabled); + this->ConfigureButton->setEnabled(enabled); + this->GenerateButton->setEnabled(enabled); + this->CancelButton->setEnabled(enabled); + this->HelpButton->setEnabled(enabled); } diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index 5ae32cde3..7dec6077a 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -22,6 +22,7 @@ class QCMakeThread; class CMakeCacheModel; class QProgressBar; +class QToolButton; /// Qt user interface for CMake class CMakeSetupDialog : public QMainWindow, public Ui::CMakeSetupDialog @@ -31,18 +32,13 @@ public: CMakeSetupDialog(); ~CMakeSetupDialog(); -signals: - void configure(); - void ok(); - void cancel(); - void propertiesChanged(const QCMakeCachePropertyList&); - protected slots: void initialize(); void doConfigure(); void doOk(); void doCancel(); void doHelp(); + void doInterrupt(); void finishConfigure(int error); void finishGenerate(int error); void error(const QString& title, const QString& message, bool* cancel); @@ -51,13 +47,13 @@ protected slots: void doBinaryBrowse(); void updateSourceDirectory(const QString& dir); void setBinaryDirectory(const QString& dir); - void showProgress(const QString& msg, float percent); + void setEnabledState(bool); protected: QCMakeThread* CMakeThread; QProgressBar* ProgressBar; - + QToolButton* InterruptButton; }; diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui index 9080f98e6..3942eb185 100644 --- a/Source/QtDialog/CMakeSetupDialog.ui +++ b/Source/QtDialog/CMakeSetupDialog.ui @@ -1,82 +1,83 @@ CMakeSetupDialog - + 0 0 - 650 - 505 + 673 + 460 - - CMakeSetup - - - :/Icons/CMakeSetupDialog.png - - - - - - - QFrame::NoFrame + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 - - QFrame::Raised + + 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Where is the source code: - - - - - - - - - - Browse... - - - - - - - Where to build the binaries: - - - - - - - true - - - - - - - Browse... - - - - + + 0 + + + 0 + + + + + + + Where is the source code: + + + + + + + + + + Browse... + + + + + + + Where to build the binaries: + + + + + + + true + + + + + + + Browse... + + + + + + + + + Qt::Vertical + true @@ -85,61 +86,65 @@ QAbstractItemView::SelectRows - - - - - - - Configure - - - - - - - Ok - - - - - - - Cancel - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - 0 - 0 - 650 - 29 - - - - + + + QTextEdit::NoWrap + + + true + + + + + + + + + + Configure + + + + + + + Ok + + + + + + + Cancel + + + + + + + Help + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + diff --git a/Source/QtDialog/QCMake.cxx b/Source/QtDialog/QCMake.cxx index f75050c09..a81d6af55 100644 --- a/Source/QtDialog/QCMake.cxx +++ b/Source/QtDialog/QCMake.cxx @@ -118,9 +118,17 @@ void QCMake::setProperties(const QCMakeCachePropertyList& props) { if ( it.Find(prop.Key.toAscii().data()) ) { - it.SetValue(prop.Value.toAscii().data()); + if(prop.Value.type() == QVariant::Bool) + { + it.SetValue(prop.Value.toBool() ? "ON" : "OFF"); + } + else + { + it.SetValue(prop.Value.toString().toAscii().data()); + } } } + cachem->SaveCache(this->BinaryDirectory.toAscii().data()); } QCMakeCachePropertyList QCMake::properties() @@ -147,14 +155,7 @@ QCMakeCachePropertyList QCMake::properties() if(i.GetType() == cmCacheManager::BOOL) { prop.Type = QCMakeCacheProperty::BOOL; - if(cmSystemTools::IsOn(prop.Value.toAscii().data())) - { - prop.Value = QString("ON"); - } - else - { - prop.Value = QString("OFF"); - } + prop.Value = cmSystemTools::IsOn(i.GetValue()); } else if(i.GetType() == cmCacheManager::PATH) { @@ -183,7 +184,14 @@ void QCMake::interrupt() void QCMake::progressCallback(const char* msg, float percent, void* cd) { QCMake* self = reinterpret_cast(cd); - emit self->progressChanged(msg, percent); + if(percent >= 0) + { + emit self->progressChanged(msg, percent); + } + else + { + emit self->outputMessage(msg); + } QCoreApplication::processEvents(); } diff --git a/Source/QtDialog/QCMake.h b/Source/QtDialog/QCMake.h index 15c13ec8c..38d94e699 100644 --- a/Source/QtDialog/QCMake.h +++ b/Source/QtDialog/QCMake.h @@ -20,17 +20,19 @@ #include #include +#include #include #include class cmake; -// struct to represent cache properties in Qt +/// struct to represent cache properties in Qt +/// Value is of type String or Bool struct QCMakeCacheProperty { enum PropertyType { BOOL, PATH, FILEPATH, STRING }; QString Key; - QString Value; + QVariant Value; QString Help; PropertyType Type; bool Advanced; @@ -41,9 +43,9 @@ Q_DECLARE_METATYPE(QCMakeCacheProperty) typedef QList QCMakeCachePropertyList; Q_DECLARE_METATYPE(QCMakeCachePropertyList) -// Qt API for CMake library. -// Wrapper like class allows for easier integration with -// Qt features such as, signal/slot connections, multi-threading, etc.. +/// Qt API for CMake library. +/// Wrapper like class allows for easier integration with +/// Qt features such as, signal/slot connections, multi-threading, etc.. class QCMake : public QObject { Q_OBJECT @@ -52,31 +54,53 @@ public: ~QCMake(); public slots: + /// load the cache file in a directory void loadCache(const QString& dir); + /// set the source directory containing the source void setSourceDirectory(const QString& dir); + /// set the binary directory to build in void setBinaryDirectory(const QString& dir); + /// set the desired generator to use void setGenerator(const QString& generator); + /// do the configure step void configure(); + /// generate the files void generate(); + /// set the property values void setProperties(const QCMakeCachePropertyList&); + /// interrupt the configure or generate process void interrupt(); public: + /// get the list of cache properties QCMakeCachePropertyList properties(); + /// get the current binary directory QString binaryDirectory(); + /// get the current source directory QString sourceDirectory(); + /// get the current generator QString generator(); + /// get the available generators + QStringList availableGenerators(); signals: + /// signal when properties change (during read from disk or configure process) void propertiesChanged(const QCMakeCachePropertyList& vars); + /// signal when the generator changes void generatorChanged(const QString& gen); + /// signal when there is an error message void error(const QString& title, const QString& message, bool*); + /// signal when the source directory changes (binary directory already + /// containing a CMakeCache.txt file) void sourceDirChanged(const QString& dir); + /// signal for progress events void progressChanged(const QString& msg, float percent); + /// signal when configure is done void configureDone(int error); + /// signal when generate is done void generateDone(int error); - void configureReady(); - void generateReady(); + /// signal when there is an output message + void outputMessage(const QString& msg); protected: cmake* CMakeInstance; diff --git a/Source/QtDialog/QCMakeCacheView.cxx b/Source/QtDialog/QCMakeCacheView.cxx index a0040c732..9f25b8287 100644 --- a/Source/QtDialog/QCMakeCacheView.cxx +++ b/Source/QtDialog/QCMakeCacheView.cxx @@ -24,7 +24,7 @@ #include QCMakeCacheView::QCMakeCacheView(QWidget* p) - : QTableView(p) + : QTableView(p), Init(false) { QCMakeCacheModel* m = new QCMakeCacheModel(this); this->setModel(m); @@ -35,16 +35,17 @@ QCMakeCacheView::QCMakeCacheView(QWidget* p) this->setItemDelegate(delegate); } -bool QCMakeCacheView::event(QEvent* e) +void QCMakeCacheView::showEvent(QShowEvent* e) { - if(e->type() == QEvent::Polish) + if(!this->Init) { // initialize the table view column size int colWidth = this->columnWidth(0) + this->columnWidth(1); this->setColumnWidth(0, colWidth/2); this->setColumnWidth(1, colWidth/2); + this->Init = true; } - return QTableView::event(e); + return QTableView::showEvent(e); } QCMakeCacheModel* QCMakeCacheView::cacheModel() const @@ -52,8 +53,42 @@ QCMakeCacheModel* QCMakeCacheView::cacheModel() const return qobject_cast(this->model()); } +QModelIndex QCMakeCacheView::moveCursor(CursorAction act, + Qt::KeyboardModifiers mod) +{ + // tab through values only (not names) + QModelIndex current = this->currentIndex(); + if(act == MoveNext) + { + if(!current.isValid()) + { + return this->model()->index(0, 1); + } + else if(current.column() == 0) + { + return this->model()->index(current.row(), 1); + } + else + { + return this->model()->index(current.row()+1, 1); + } + } + else if(act == MovePrevious) + { + if(!current.isValid()) + { + return this->model()->index(0, 1); + } + else + { + return this->model()->index(current.row()-1, 1); + } + } + return QTableView::moveCursor(act, mod); +} + QCMakeCacheModel::QCMakeCacheModel(QObject* p) - : QAbstractTableModel(p) + : QAbstractTableModel(p), IsDirty(false) { } @@ -61,10 +96,16 @@ QCMakeCacheModel::~QCMakeCacheModel() { } +bool QCMakeCacheModel::isDirty() const +{ + return this->IsDirty; +} + void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props) { this->Properties = props; this->reset(); + this->IsDirty = false; } QCMakeCachePropertyList QCMakeCacheModel::properties() const @@ -80,25 +121,40 @@ int QCMakeCacheModel::columnCount ( const QModelIndex & parent ) const QVariant QCMakeCacheModel::data ( const QModelIndex & index, int role ) const { if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) - { + { return this->Properties[index.row()].Key; - } + } + else if(index.column() == 0 && role == Qt::ToolTipRole) + { + return this->data(index, Qt::DisplayRole).toString() + "\n" + + this->data(index, QCMakeCacheModel::HelpRole).toString(); + } else if(index.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) - { - return this->Properties[index.row()].Value; - } + { + if(this->Properties[index.row()].Type != QCMakeCacheProperty::BOOL) + { + return this->Properties[index.row()].Value; + } + } + else if(index.column() == 1 && role == Qt::CheckStateRole) + { + if(this->Properties[index.row()].Type == QCMakeCacheProperty::BOOL) + { + return this->Properties[index.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked; + } + } else if(role == QCMakeCacheModel::HelpRole) - { + { return this->Properties[index.row()].Help; - } + } else if(role == QCMakeCacheModel::TypeRole) - { + { return this->Properties[index.row()].Type; - } + } else if(role == QCMakeCacheModel::AdvancedRole) - { + { return this->Properties[index.row()].Advanced; - } + } return QVariant(); } @@ -110,39 +166,59 @@ QModelIndex QCMakeCacheModel::parent ( const QModelIndex & index ) const int QCMakeCacheModel::rowCount ( const QModelIndex & parent ) const { if(parent.isValid()) + { return 0; + } return this->Properties.count(); } QVariant QCMakeCacheModel::headerData ( int section, Qt::Orientation orient, int role ) const { + // return header labels if(role == Qt::DisplayRole && orient == Qt::Horizontal) - { + { return section == 0 ? "Name" : "Value"; - } + } return QVariant(); } Qt::ItemFlags QCMakeCacheModel::flags ( const QModelIndex& index ) const { + Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + // all column 1's are editable if(index.column() == 1) - { - return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; - } - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; + { + f |= Qt::ItemIsEditable; + // booleans are editable in place + if(this->Properties[index.row()].Type == QCMakeCacheProperty::BOOL) + { + f |= Qt::ItemIsUserCheckable; + } + } + return f; } bool QCMakeCacheModel::setData ( const QModelIndex & index, const QVariant& value, int role ) { if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) - { + { this->Properties[index.row()].Key = value.toString(); - } + this->IsDirty = true; + emit this->dataChanged(index, index); + } else if(index.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole)) - { + { this->Properties[index.row()].Value = value.toString(); - } + this->IsDirty = true; + emit this->dataChanged(index, index); + } + else if(index.column() == 1 && (role == Qt::CheckStateRole)) + { + this->Properties[index.row()].Value = value.toInt() == Qt::Checked; + this->IsDirty = true; + emit this->dataChanged(index, index); + } return false; } @@ -158,23 +234,24 @@ QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* parent, { QVariant type = index.data(QCMakeCacheModel::TypeRole); if(type == QCMakeCacheProperty::BOOL) - { - return new QCMakeCacheBoolEditor(index.data().toString(), parent); - } + { + return NULL; + } else if(type == QCMakeCacheProperty::PATH) - { - return new QCMakeCachePathEditor(index.data().toString(), parent); - } + { + return new QCMakeCachePathEditor(index.data().toString(), false, parent); + } else if(type == QCMakeCacheProperty::FILEPATH) - { - } + { + return new QCMakeCachePathEditor(index.data().toString(), true, parent); + } return new QLineEdit(parent); } -QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, QWidget* p) - : QWidget(p), LineEdit(this) +QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp, QWidget* p) + : QWidget(p), LineEdit(this), IsFilePath(fp) { QHBoxLayout* l = new QHBoxLayout(this); l->setMargin(0); @@ -192,17 +269,19 @@ QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, QWidget* p) void QCMakeCachePathEditor::chooseFile() { - QString path = QFileDialog::getExistingDirectory(this, "TODO", this->value()); + QString path; + if(this->IsFilePath) + { + path = QFileDialog::getOpenFileName(this, "TODO"); + } + else + { + path = QFileDialog::getExistingDirectory(this, "TODO", this->value()); + } if(!path.isEmpty()) - { + { this->LineEdit.setText(path); - } -} - -QString QCMakeCachePathEditor::value() const -{ - return this->LineEdit.text(); + } } - diff --git a/Source/QtDialog/QCMakeCacheView.h b/Source/QtDialog/QCMakeCacheView.h index da71de137..692f45121 100644 --- a/Source/QtDialog/QCMakeCacheView.h +++ b/Source/QtDialog/QCMakeCacheView.h @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -38,7 +38,9 @@ public: QCMakeCacheModel* cacheModel() const; protected: - bool event(QEvent*); + QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers); + void showEvent(QShowEvent* e); + bool Init; }; /// Qt model class for cache properties @@ -55,6 +57,7 @@ public slots: void setProperties(const QCMakeCachePropertyList& props); public: + // satisfy [pure] virtuals int columnCount ( const QModelIndex & parent ) const; QVariant data ( const QModelIndex & index, int role ) const; QModelIndex parent ( const QModelIndex & index ) const; @@ -63,10 +66,14 @@ public: Qt::ItemFlags flags ( const QModelIndex& index ) const; bool setData ( const QModelIndex& index, const QVariant& value, int role ); + // flag if a cache property has been modified + bool isDirty() const; + // get the properties QCMakeCachePropertyList properties() const; protected: QCMakeCachePropertyList Properties; + bool IsDirty; }; /// Qt delegate class for interaction (or other customization) with cache properties @@ -75,41 +82,23 @@ 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; }; -/// Editor widget for editing paths +/// Editor widget for editing paths or file paths class QCMakeCachePathEditor : public QWidget { Q_OBJECT Q_PROPERTY(QString value READ value USER true) public: - QCMakeCachePathEditor(const QString& file, QWidget* p); - QString value() const; + QCMakeCachePathEditor(const QString& file, bool isFilePath, QWidget* p); + QString value() const { return this->LineEdit->text(); } protected slots: void chooseFile(); protected: QLineEdit LineEdit; -}; - -/// Editor widget for editing file paths -class QCMakeCacheFilePathEditor : public QWidget -{ -}; - -/// Editor widget for editing booleans -class QCMakeCacheBoolEditor : public QComboBox -{ - Q_OBJECT - Q_PROPERTY(QString value READ currentText USER true) -public: - QCMakeCacheBoolEditor(const QString& val, QWidget* p) - : QComboBox(p) - { - this->addItem("ON"); - this->addItem("OFF"); - this->setCurrentIndex(val == "ON" ? 0 : 1); - } + bool IsFilePath; }; #endif