From 77ad85a6ab00959b972f5f2ad86382e2161b92b6 Mon Sep 17 00:00:00 2001 From: Clinton Stimpson Date: Sat, 3 Nov 2007 10:30:52 -0400 Subject: [PATCH] ENH: Add interrupt button near progress bar. Implement help button. Implement cancel button. Add scrollable output window. Replace ON/OFF & combobox editors with checkboxes. Tab/backtab in cache table jumps between values (not names and values) Add tooltips to show help strings. Add application icon and qtmain for Windows. BUG: Fix save of cache values on configure. --- Source/QtDialog/CMakeLists.txt | 9 +- Source/QtDialog/CMakeSetup.cxx | 1 + Source/QtDialog/CMakeSetup.ico | Bin 0 -> 24542 bytes .../{CMakeSetupDialog.png => CMakeSetup.png} | Bin Source/QtDialog/CMakeSetup.qrc | 2 +- Source/QtDialog/CMakeSetup.rc | 1 + Source/QtDialog/CMakeSetupDialog.cxx | 173 +++++++++--- Source/QtDialog/CMakeSetupDialog.h | 12 +- Source/QtDialog/CMakeSetupDialog.ui | 253 +++++++++--------- Source/QtDialog/QCMake.cxx | 28 +- Source/QtDialog/QCMake.h | 38 ++- Source/QtDialog/QCMakeCacheView.cxx | 169 ++++++++---- Source/QtDialog/QCMakeCacheView.h | 39 +-- 13 files changed, 461 insertions(+), 264 deletions(-) create mode 100644 Source/QtDialog/CMakeSetup.ico rename Source/QtDialog/{CMakeSetupDialog.png => CMakeSetup.png} (100%) create mode 100644 Source/QtDialog/CMakeSetup.rc 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 0000000000000000000000000000000000000000..90fbdacd8824766c7c58d9fcd2e97fa30d76044f GIT binary patch literal 24542 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 literal 0 HcmV?d00001 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