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.
This commit is contained in:
Clinton Stimpson 2007-11-03 10:30:52 -04:00
parent c139a096c7
commit 77ad85a6ab
13 changed files with 461 additions and 264 deletions

View File

@ -6,7 +6,6 @@ IF(NOT QT4_FOUND)
MESSAGE(SEND_ERROR "Failed to find Qt 4.3 or greater.") MESSAGE(SEND_ERROR "Failed to find Qt 4.3 or greater.")
ELSE(NOT QT4_FOUND) ELSE(NOT QT4_FOUND)
SET(QT_USE_QTMAIN TRUE)
INCLUDE(${QT_USE_FILE}) INCLUDE(${QT_USE_FILE})
SET(SRCS SET(SRCS
@ -18,7 +17,6 @@ ELSE(NOT QT4_FOUND)
QCMakeCacheView.cxx QCMakeCacheView.cxx
QCMakeCacheView.h QCMakeCacheView.h
) )
QT4_WRAP_UI(UI_SRCS QT4_WRAP_UI(UI_SRCS
CMakeSetupDialog.ui CMakeSetupDialog.ui
) )
@ -30,13 +28,16 @@ ELSE(NOT QT4_FOUND)
QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc) QT4_ADD_RESOURCES(RC_SRCS CMakeSetup.qrc)
SET(SRCS ${SRCS} ${UI_SRCS} ${MOC_SRCS} ${RC_SRCS}) 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_BINARY_DIR})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
ADD_EXECUTABLE(QtDialog WIN32 MACOSX_BUNDLE ${SRCS}) ADD_EXECUTABLE(QtDialog WIN32 MACOSX_BUNDLE ${SRCS})
TARGET_LINK_LIBRARIES(QtDialog CMakeLib ${QT_LIBRARIES}) TARGET_LINK_LIBRARIES(QtDialog CMakeLib ${QT_QTMAIN_LIBRARY} ${QT_LIBRARIES})
ADD_DEPENDENCIES(QtDialog cmake)
ENDIF(NOT QT4_FOUND) ENDIF(NOT QT4_FOUND)

View File

@ -26,6 +26,7 @@ int main(int argc, char** argv)
QApplication app(argc, argv); QApplication app(argc, argv);
app.setApplicationName("CMakeSetup"); app.setApplicationName("CMakeSetup");
app.setOrganizationName("Kitware"); app.setOrganizationName("Kitware");
app.setWindowIcon(QIcon(":/Icons/CMakeSetup.png"));
// TODO handle CMake args // TODO handle CMake args

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 358 B

After

Width:  |  Height:  |  Size: 358 B

View File

@ -1,5 +1,5 @@
<RCC> <RCC>
<qresource prefix="/Icons" > <qresource prefix="/Icons" >
<file>CMakeSetupDialog.png</file> <file>CMakeSetup.png</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "CMakeSetup.ico"

View File

@ -21,6 +21,9 @@
#include <QThread> #include <QThread>
#include <QProgressBar> #include <QProgressBar>
#include <QMessageBox> #include <QMessageBox>
#include <QStatusBar>
#include <QToolButton>
#include <QDialogButtonBox>
#include "QCMake.h" #include "QCMake.h"
#include "QCMakeCacheView.h" #include "QCMakeCacheView.h"
@ -44,9 +47,17 @@ protected:
CMakeSetupDialog::CMakeSetupDialog() CMakeSetupDialog::CMakeSetupDialog()
{ {
// create the GUI // 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 = new QProgressBar();
this->ProgressBar->setRange(0,100); 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); this->statusBar()->addPermanentWidget(this->ProgressBar);
// start the cmake worker thread // start the cmake worker thread
@ -64,36 +75,26 @@ void CMakeSetupDialog::initialize()
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,
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())); this, SLOT(doConfigure()));
QObject::connect(this, SIGNAL(configure()),
this->CMakeThread->CMakeInstance, SLOT(configure()));
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)),
this, SLOT(doOk())); 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())); this, SLOT(doCancel()));
QObject::connect(this, SIGNAL(cancel()),
this->CMakeThread->CMakeInstance, SLOT(interrupt()));
QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)), QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)),
this, SLOT(doSourceBrowse())); this, SLOT(doSourceBrowse()));
QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)), QObject::connect(this->BrowseBinaryDirectoryButton, SIGNAL(clicked(bool)),
this, SLOT(doBinaryBrowse())); this, SLOT(doBinaryBrowse()));
QObject::connect(this->BinaryDirectory, SIGNAL(textChanged(QString)), QObject::connect(this->BinaryDirectory, SIGNAL(editTextChanged(QString)),
this->CMakeThread->CMakeInstance, SLOT(setBinaryDirectory(QString))); this->CMakeThread->CMakeInstance, SLOT(setBinaryDirectory(QString)));
QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(sourceDirChanged(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*)), QObject::connect(this->CMakeThread->CMakeInstance, SIGNAL(error(QString, QString, bool*)),
this, SLOT(error(QString,QString,bool*)), Qt::BlockingQueuedConnection); 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() CMakeSetupDialog::~CMakeSetupDialog()
@ -116,49 +127,119 @@ CMakeSetupDialog::~CMakeSetupDialog()
void CMakeSetupDialog::doConfigure() void CMakeSetupDialog::doConfigure()
{ {
emit this->propertiesChanged(this->CacheValues->cacheModel()->properties()); this->InterruptButton->setEnabled(true);
emit this->configure(); 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) void CMakeSetupDialog::finishConfigure(int error)
{ {
this->InterruptButton->setEnabled(false);
this->setEnabledState(true);
this->ProgressBar->reset(); this->ProgressBar->reset();
this->statusBar()->showMessage("Configure Done", 2000); this->statusBar()->showMessage(tr("Configure Done"), 2000);
if(error != 0) if(error != 0)
{ {
bool dummy; QMessageBox::critical(this, tr("Error"),
this->error("Error", "Error in configuration process, project files may be invalid", &dummy); tr("Error in configuration process, project files may be invalid"),
} QMessageBox::Ok);
}
} }
void CMakeSetupDialog::finishGenerate(int error) void CMakeSetupDialog::finishGenerate(int error)
{ {
this->InterruptButton->setEnabled(false);
this->setEnabledState(true);
this->ProgressBar->reset(); this->ProgressBar->reset();
this->statusBar()->showMessage("Generate Done", 2000); this->statusBar()->showMessage(tr("Generate Done"), 2000);
if(error != 0) if(error != 0)
{ {
bool dummy; QMessageBox::critical(this, tr("Error"),
this->error("Error", "Error in generation process, project files may be invalid", &dummy); tr("Error in generation process, project files may be invalid"),
} QMessageBox::Ok);
}
else
{
QApplication::quit();
}
} }
void CMakeSetupDialog::doOk() 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() 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() 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() 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()) if(!dir.isEmpty())
{ {
this->updateSourceDirectory(dir); this->updateSourceDirectory(dir);
@ -172,7 +253,8 @@ void CMakeSetupDialog::updateSourceDirectory(const QString& dir)
void CMakeSetupDialog::doBinaryBrowse() 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()) if(!dir.isEmpty())
{ {
this->setBinaryDirectory(dir); this->setBinaryDirectory(dir);
@ -182,18 +264,16 @@ void CMakeSetupDialog::doBinaryBrowse()
void CMakeSetupDialog::setBinaryDirectory(const QString& dir) void CMakeSetupDialog::setBinaryDirectory(const QString& dir)
{ {
if(dir != this->BinaryDirectory->currentText()) if(dir != this->BinaryDirectory->currentText())
{ {
this->Output->clear();
this->BinaryDirectory->setEditText(dir); this->BinaryDirectory->setEditText(dir);
} }
} }
void CMakeSetupDialog::showProgress(const QString& msg, float percent) 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) 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::StandardButton btn =
QMessageBox::critical(this, title, message, QMessageBox::Ok | QMessageBox::Cancel); QMessageBox::critical(this, title, message, QMessageBox::Ok | QMessageBox::Cancel);
if(btn == QMessageBox::Cancel) if(btn == QMessageBox::Cancel)
{ {
*cancel = false; *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);
} }

View File

@ -22,6 +22,7 @@
class QCMakeThread; class QCMakeThread;
class CMakeCacheModel; class CMakeCacheModel;
class QProgressBar; class QProgressBar;
class QToolButton;
/// Qt user interface for CMake /// Qt user interface for CMake
class CMakeSetupDialog : public QMainWindow, public Ui::CMakeSetupDialog class CMakeSetupDialog : public QMainWindow, public Ui::CMakeSetupDialog
@ -31,18 +32,13 @@ public:
CMakeSetupDialog(); CMakeSetupDialog();
~CMakeSetupDialog(); ~CMakeSetupDialog();
signals:
void configure();
void ok();
void cancel();
void propertiesChanged(const QCMakeCachePropertyList&);
protected slots: protected slots:
void initialize(); void initialize();
void doConfigure(); void doConfigure();
void doOk(); void doOk();
void doCancel(); void doCancel();
void doHelp(); void doHelp();
void doInterrupt();
void finishConfigure(int error); void finishConfigure(int error);
void finishGenerate(int error); void finishGenerate(int error);
void error(const QString& title, const QString& message, bool* cancel); void error(const QString& title, const QString& message, bool* cancel);
@ -51,13 +47,13 @@ protected slots:
void doBinaryBrowse(); void doBinaryBrowse();
void updateSourceDirectory(const QString& dir); void updateSourceDirectory(const QString& dir);
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);
protected: protected:
QCMakeThread* CMakeThread; QCMakeThread* CMakeThread;
QProgressBar* ProgressBar; QProgressBar* ProgressBar;
QToolButton* InterruptButton;
}; };

View File

@ -1,82 +1,83 @@
<ui version="4.0" > <ui version="4.0" >
<class>CMakeSetupDialog</class> <class>CMakeSetupDialog</class>
<widget class="QMainWindow" name="CMakeSetupDialog" > <widget class="QWidget" name="CMakeSetupDialog" >
<property name="geometry" > <property name="geometry" >
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>650</width> <width>673</width>
<height>505</height> <height>460</height>
</rect> </rect>
</property> </property>
<property name="windowTitle" > <layout class="QGridLayout" >
<string>CMakeSetup</string> <item row="0" column="0" >
</property> <widget class="QFrame" name="frame" >
<property name="windowIcon" > <property name="frameShape" >
<iconset resource="CMakeSetup.qrc" >:/Icons/CMakeSetupDialog.png</iconset> <enum>QFrame::NoFrame</enum>
</property> </property>
<widget class="QWidget" name="centralwidget" > <property name="frameShadow" >
<layout class="QGridLayout" > <enum>QFrame::Raised</enum>
<item row="0" column="0" > </property>
<widget class="QFrame" name="frame" > <layout class="QVBoxLayout" >
<property name="frameShape" > <property name="leftMargin" >
<enum>QFrame::NoFrame</enum> <number>0</number>
</property> </property>
<property name="frameShadow" > <property name="topMargin" >
<enum>QFrame::Raised</enum> <number>0</number>
</property> </property>
<layout class="QGridLayout" > <property name="rightMargin" >
<property name="leftMargin" > <number>0</number>
<number>0</number> </property>
</property> <property name="bottomMargin" >
<property name="topMargin" > <number>0</number>
<number>0</number> </property>
</property> <item>
<property name="rightMargin" > <layout class="QGridLayout" >
<number>0</number> <item row="0" column="0" >
</property> <widget class="QLabel" name="label" >
<property name="bottomMargin" > <property name="text" >
<number>0</number> <string>Where is the source code:</string>
</property> </property>
<item row="0" column="0" > </widget>
<widget class="QLabel" name="label" > </item>
<property name="text" > <item row="0" column="1" >
<string>Where is the source code:</string> <widget class="QLineEdit" name="SourceDirectory" />
</property> </item>
</widget> <item row="0" column="2" >
</item> <widget class="QPushButton" name="BrowseSourceDirectoryButton" >
<item row="0" column="1" > <property name="text" >
<widget class="QLineEdit" name="SourceDirectory" /> <string>Browse...</string>
</item> </property>
<item row="0" column="2" > </widget>
<widget class="QPushButton" name="BrowseSourceDirectoryButton" > </item>
<property name="text" > <item row="1" column="0" >
<string>Browse...</string> <widget class="QLabel" name="label_2" >
</property> <property name="text" >
</widget> <string>Where to build the binaries:</string>
</item> </property>
<item row="1" column="0" > </widget>
<widget class="QLabel" name="label_2" > </item>
<property name="text" > <item row="1" column="1" >
<string>Where to build the binaries:</string> <widget class="QComboBox" name="BinaryDirectory" >
</property> <property name="editable" >
</widget> <bool>true</bool>
</item> </property>
<item row="1" column="1" > </widget>
<widget class="QComboBox" name="BinaryDirectory" > </item>
<property name="editable" > <item row="1" column="2" >
<bool>true</bool> <widget class="QPushButton" name="BrowseBinaryDirectoryButton" >
</property> <property name="text" >
</widget> <string>Browse...</string>
</item> </property>
<item row="1" column="2" > </widget>
<widget class="QPushButton" name="BrowseBinaryDirectoryButton" > </item>
<property name="text" > </layout>
<string>Browse...</string> </item>
</property> <item>
</widget> <widget class="QSplitter" name="splitter" >
</item> <property name="orientation" >
<item row="2" column="0" colspan="3" > <enum>Qt::Vertical</enum>
</property>
<widget class="QCMakeCacheView" name="CacheValues" > <widget class="QCMakeCacheView" name="CacheValues" >
<property name="alternatingRowColors" > <property name="alternatingRowColors" >
<bool>true</bool> <bool>true</bool>
@ -85,61 +86,65 @@
<enum>QAbstractItemView::SelectRows</enum> <enum>QAbstractItemView::SelectRows</enum>
</property> </property>
</widget> </widget>
</item> <widget class="QTextEdit" name="Output" >
<item row="3" column="0" colspan="3" > <property name="lineWrapMode" >
<layout class="QHBoxLayout" > <enum>QTextEdit::NoWrap</enum>
<item> </property>
<widget class="QPushButton" name="configureButton" > <property name="readOnly" >
<property name="text" > <bool>true</bool>
<string>Configure</string> </property>
</property> </widget>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="generateButton" > <layout class="QHBoxLayout" >
<property name="text" > <item>
<string>Ok</string> <widget class="QPushButton" name="ConfigureButton" >
</property> <property name="text" >
</widget> <string>Configure</string>
</item> </property>
<item> </widget>
<widget class="QPushButton" name="cancelButton" > </item>
<property name="text" > <item>
<string>Cancel</string> <widget class="QPushButton" name="GenerateButton" >
</property> <property name="text" >
</widget> <string>Ok</string>
</item> </property>
<item> </widget>
<spacer> </item>
<property name="orientation" > <item>
<enum>Qt::Horizontal</enum> <widget class="QPushButton" name="CancelButton" >
</property> <property name="text" >
<property name="sizeHint" > <string>Cancel</string>
<size> </property>
<width>40</width> </widget>
<height>20</height> </item>
</size> <item>
</property> <widget class="QPushButton" name="HelpButton" >
</spacer> <property name="text" >
</item> <string>Help</string>
</layout> </property>
</item> </widget>
</layout> </item>
</widget> <item>
</item> <spacer>
</layout> <property name="orientation" >
</widget> <enum>Qt::Horizontal</enum>
<widget class="QMenuBar" name="menubar" > </property>
<property name="geometry" > <property name="sizeHint" >
<rect> <size>
<x>0</x> <width>40</width>
<y>0</y> <height>20</height>
<width>650</width> </size>
<height>29</height> </property>
</rect> </spacer>
</property> </item>
</widget> </layout>
<widget class="QStatusBar" name="statusbar" /> </item>
</layout>
</widget>
</item>
</layout>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -118,9 +118,17 @@ void QCMake::setProperties(const QCMakeCachePropertyList& props)
{ {
if ( it.Find(prop.Key.toAscii().data()) ) 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() QCMakeCachePropertyList QCMake::properties()
@ -147,14 +155,7 @@ QCMakeCachePropertyList QCMake::properties()
if(i.GetType() == cmCacheManager::BOOL) if(i.GetType() == cmCacheManager::BOOL)
{ {
prop.Type = QCMakeCacheProperty::BOOL; prop.Type = QCMakeCacheProperty::BOOL;
if(cmSystemTools::IsOn(prop.Value.toAscii().data())) prop.Value = cmSystemTools::IsOn(i.GetValue());
{
prop.Value = QString("ON");
}
else
{
prop.Value = QString("OFF");
}
} }
else if(i.GetType() == cmCacheManager::PATH) else if(i.GetType() == cmCacheManager::PATH)
{ {
@ -183,7 +184,14 @@ void QCMake::interrupt()
void QCMake::progressCallback(const char* msg, float percent, void* cd) void QCMake::progressCallback(const char* msg, float percent, void* cd)
{ {
QCMake* self = reinterpret_cast<QCMake*>(cd); QCMake* self = reinterpret_cast<QCMake*>(cd);
emit self->progressChanged(msg, percent); if(percent >= 0)
{
emit self->progressChanged(msg, percent);
}
else
{
emit self->outputMessage(msg);
}
QCoreApplication::processEvents(); QCoreApplication::processEvents();
} }

View File

@ -20,17 +20,19 @@
#include <QObject> #include <QObject>
#include <QString> #include <QString>
#include <QVariant>
#include <QList> #include <QList>
#include <QMetaType> #include <QMetaType>
class cmake; 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 struct QCMakeCacheProperty
{ {
enum PropertyType { BOOL, PATH, FILEPATH, STRING }; enum PropertyType { BOOL, PATH, FILEPATH, STRING };
QString Key; QString Key;
QString Value; QVariant Value;
QString Help; QString Help;
PropertyType Type; PropertyType Type;
bool Advanced; bool Advanced;
@ -41,9 +43,9 @@ Q_DECLARE_METATYPE(QCMakeCacheProperty)
typedef QList<QCMakeCacheProperty> QCMakeCachePropertyList; typedef QList<QCMakeCacheProperty> QCMakeCachePropertyList;
Q_DECLARE_METATYPE(QCMakeCachePropertyList) Q_DECLARE_METATYPE(QCMakeCachePropertyList)
// Qt API for CMake library. /// Qt API for CMake library.
// Wrapper like class allows for easier integration with /// Wrapper like class allows for easier integration with
// Qt features such as, signal/slot connections, multi-threading, etc.. /// Qt features such as, signal/slot connections, multi-threading, etc..
class QCMake : public QObject class QCMake : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -52,31 +54,53 @@ public:
~QCMake(); ~QCMake();
public slots: public slots:
/// load the cache file in a directory
void loadCache(const QString& dir); void loadCache(const QString& dir);
/// set the source directory containing the source
void setSourceDirectory(const QString& dir); void setSourceDirectory(const QString& dir);
/// set the binary directory to build in
void setBinaryDirectory(const QString& dir); void setBinaryDirectory(const QString& dir);
/// set the desired generator to use
void setGenerator(const QString& generator); void setGenerator(const QString& generator);
/// do the configure step
void configure(); void configure();
/// generate the files
void generate(); void generate();
/// set the property values
void setProperties(const QCMakeCachePropertyList&); void setProperties(const QCMakeCachePropertyList&);
/// interrupt the configure or generate process
void interrupt(); void interrupt();
public: public:
/// get the list of cache properties
QCMakeCachePropertyList properties(); QCMakeCachePropertyList properties();
/// get the current binary directory
QString binaryDirectory(); QString binaryDirectory();
/// get the current source directory
QString sourceDirectory(); QString sourceDirectory();
/// get the current generator
QString generator(); QString generator();
/// get the available generators
QStringList availableGenerators();
signals: signals:
/// signal when properties change (during read from disk or configure process)
void propertiesChanged(const QCMakeCachePropertyList& vars); void propertiesChanged(const QCMakeCachePropertyList& vars);
/// signal when the generator changes
void generatorChanged(const QString& gen); void generatorChanged(const QString& gen);
/// signal when there is an error message
void error(const QString& title, const QString& message, bool*); 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); void sourceDirChanged(const QString& dir);
/// signal for progress events
void progressChanged(const QString& msg, float percent); void progressChanged(const QString& msg, float percent);
/// signal when configure is done
void configureDone(int error); void configureDone(int error);
/// signal when generate is done
void generateDone(int error); void generateDone(int error);
void configureReady(); /// signal when there is an output message
void generateReady(); void outputMessage(const QString& msg);
protected: protected:
cmake* CMakeInstance; cmake* CMakeInstance;

View File

@ -24,7 +24,7 @@
#include <QEvent> #include <QEvent>
QCMakeCacheView::QCMakeCacheView(QWidget* p) QCMakeCacheView::QCMakeCacheView(QWidget* p)
: QTableView(p) : QTableView(p), Init(false)
{ {
QCMakeCacheModel* m = new QCMakeCacheModel(this); QCMakeCacheModel* m = new QCMakeCacheModel(this);
this->setModel(m); this->setModel(m);
@ -35,16 +35,17 @@ QCMakeCacheView::QCMakeCacheView(QWidget* p)
this->setItemDelegate(delegate); 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 // initialize the table view column size
int colWidth = this->columnWidth(0) + this->columnWidth(1); int colWidth = this->columnWidth(0) + this->columnWidth(1);
this->setColumnWidth(0, colWidth/2); this->setColumnWidth(0, colWidth/2);
this->setColumnWidth(1, colWidth/2); this->setColumnWidth(1, colWidth/2);
this->Init = true;
} }
return QTableView::event(e); return QTableView::showEvent(e);
} }
QCMakeCacheModel* QCMakeCacheView::cacheModel() const QCMakeCacheModel* QCMakeCacheView::cacheModel() const
@ -52,8 +53,42 @@ QCMakeCacheModel* QCMakeCacheView::cacheModel() const
return qobject_cast<QCMakeCacheModel*>(this->model()); return qobject_cast<QCMakeCacheModel*>(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) 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) void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props)
{ {
this->Properties = props; this->Properties = props;
this->reset(); this->reset();
this->IsDirty = false;
} }
QCMakeCachePropertyList QCMakeCacheModel::properties() const QCMakeCachePropertyList QCMakeCacheModel::properties() const
@ -80,25 +121,40 @@ int QCMakeCacheModel::columnCount ( const QModelIndex & parent ) const
QVariant QCMakeCacheModel::data ( const QModelIndex & index, int role ) const QVariant QCMakeCacheModel::data ( const QModelIndex & index, int role ) const
{ {
if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
return this->Properties[index.row()].Key; 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)) 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) else if(role == QCMakeCacheModel::HelpRole)
{ {
return this->Properties[index.row()].Help; return this->Properties[index.row()].Help;
} }
else if(role == QCMakeCacheModel::TypeRole) else if(role == QCMakeCacheModel::TypeRole)
{ {
return this->Properties[index.row()].Type; return this->Properties[index.row()].Type;
} }
else if(role == QCMakeCacheModel::AdvancedRole) else if(role == QCMakeCacheModel::AdvancedRole)
{ {
return this->Properties[index.row()].Advanced; return this->Properties[index.row()].Advanced;
} }
return QVariant(); return QVariant();
} }
@ -110,39 +166,59 @@ QModelIndex QCMakeCacheModel::parent ( const QModelIndex & index ) const
int QCMakeCacheModel::rowCount ( const QModelIndex & parent ) const int QCMakeCacheModel::rowCount ( const QModelIndex & parent ) const
{ {
if(parent.isValid()) if(parent.isValid())
{
return 0; return 0;
}
return this->Properties.count(); return this->Properties.count();
} }
QVariant QCMakeCacheModel::headerData ( int section, Qt::Orientation orient, int role ) const QVariant QCMakeCacheModel::headerData ( int section, Qt::Orientation orient, int role ) const
{ {
// return header labels
if(role == Qt::DisplayRole && orient == Qt::Horizontal) if(role == Qt::DisplayRole && orient == Qt::Horizontal)
{ {
return section == 0 ? "Name" : "Value"; return section == 0 ? "Name" : "Value";
} }
return QVariant(); return QVariant();
} }
Qt::ItemFlags QCMakeCacheModel::flags ( const QModelIndex& index ) const 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) if(index.column() == 1)
{ {
return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled; f |= Qt::ItemIsEditable;
} // booleans are editable in place
return Qt::ItemIsSelectable | Qt::ItemIsEnabled; if(this->Properties[index.row()].Type == QCMakeCacheProperty::BOOL)
{
f |= Qt::ItemIsUserCheckable;
}
}
return f;
} }
bool QCMakeCacheModel::setData ( const QModelIndex & index, const QVariant& value, int role ) bool QCMakeCacheModel::setData ( const QModelIndex & index, const QVariant& value, int role )
{ {
if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole)) if(index.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
this->Properties[index.row()].Key = value.toString(); 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)) else if(index.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
{ {
this->Properties[index.row()].Value = value.toString(); 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; return false;
} }
@ -158,23 +234,24 @@ QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* parent,
{ {
QVariant type = index.data(QCMakeCacheModel::TypeRole); QVariant type = index.data(QCMakeCacheModel::TypeRole);
if(type == QCMakeCacheProperty::BOOL) if(type == QCMakeCacheProperty::BOOL)
{ {
return new QCMakeCacheBoolEditor(index.data().toString(), parent); return NULL;
} }
else if(type == QCMakeCacheProperty::PATH) 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) else if(type == QCMakeCacheProperty::FILEPATH)
{ {
} return new QCMakeCachePathEditor(index.data().toString(), true, parent);
}
return new QLineEdit(parent); return new QLineEdit(parent);
} }
QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, QWidget* p) QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, bool fp, QWidget* p)
: QWidget(p), LineEdit(this) : QWidget(p), LineEdit(this), IsFilePath(fp)
{ {
QHBoxLayout* l = new QHBoxLayout(this); QHBoxLayout* l = new QHBoxLayout(this);
l->setMargin(0); l->setMargin(0);
@ -192,17 +269,19 @@ QCMakeCachePathEditor::QCMakeCachePathEditor(const QString& file, QWidget* p)
void QCMakeCachePathEditor::chooseFile() 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()) if(!path.isEmpty())
{ {
this->LineEdit.setText(path); this->LineEdit.setText(path);
} }
}
QString QCMakeCachePathEditor::value() const
{
return this->LineEdit.text();
} }

View File

@ -20,7 +20,7 @@
#include <QTableView> #include <QTableView>
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QComboBox> #include <QCheckBox>
#include <QLineEdit> #include <QLineEdit>
#include <QItemDelegate> #include <QItemDelegate>
@ -38,7 +38,9 @@ public:
QCMakeCacheModel* cacheModel() const; QCMakeCacheModel* cacheModel() const;
protected: protected:
bool event(QEvent*); QModelIndex moveCursor(CursorAction, Qt::KeyboardModifiers);
void showEvent(QShowEvent* e);
bool Init;
}; };
/// Qt model class for cache properties /// Qt model class for cache properties
@ -55,6 +57,7 @@ public slots:
void setProperties(const QCMakeCachePropertyList& props); void setProperties(const QCMakeCachePropertyList& props);
public: public:
// satisfy [pure] virtuals
int columnCount ( const QModelIndex & parent ) const; int columnCount ( const QModelIndex & parent ) const;
QVariant data ( const QModelIndex & index, int role ) const; QVariant data ( const QModelIndex & index, int role ) const;
QModelIndex parent ( const QModelIndex & index ) const; QModelIndex parent ( const QModelIndex & index ) const;
@ -63,10 +66,14 @@ public:
Qt::ItemFlags flags ( const QModelIndex& index ) const; Qt::ItemFlags flags ( const QModelIndex& index ) const;
bool setData ( const QModelIndex& index, const QVariant& value, int role ); 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; QCMakeCachePropertyList properties() const;
protected: protected:
QCMakeCachePropertyList Properties; QCMakeCachePropertyList Properties;
bool IsDirty;
}; };
/// Qt delegate class for interaction (or other customization) with cache properties /// Qt delegate class for interaction (or other customization) with cache properties
@ -75,41 +82,23 @@ class QCMakeCacheModelDelegate : public QItemDelegate
Q_OBJECT Q_OBJECT
public: public:
QCMakeCacheModelDelegate(QObject* p); 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 /// Editor widget for editing paths or file paths
class QCMakeCachePathEditor : public QWidget class QCMakeCachePathEditor : public QWidget
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString value READ value USER true) Q_PROPERTY(QString value READ value USER true)
public: public:
QCMakeCachePathEditor(const QString& file, QWidget* p); QCMakeCachePathEditor(const QString& file, bool isFilePath, QWidget* p);
QString value() const; QString value() const { return this->LineEdit->text(); }
protected slots: protected slots:
void chooseFile(); void chooseFile();
protected: protected:
QLineEdit LineEdit; QLineEdit LineEdit;
}; bool IsFilePath;
/// 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);
}
}; };
#endif #endif