aboutsummaryrefslogtreecommitdiffstats
path: root/src/app/config-ui
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@digia.com>2013-08-08 18:11:06 +0200
committerChristian Kandeler <christian.kandeler@digia.com>2013-08-12 10:07:21 +0200
commit35182b6576585f3b2f38c66350fe33a12b031f58 (patch)
tree80f659f8b6561b127e724cb9f1faf863b4e54aa6 /src/app/config-ui
parent0f9b7cbbbe7c4f7335b6a851b133dec4f9c72d73 (diff)
Add editing capabilities to config-ui application.
Configuration entries can be added and removed, and their values as well as their names can be changed. The latter feature means the GUI interface is now actually more powerful than the command-line version. Change-Id: Ic95954fe7bcae727448d25cfba833792ba47b5cb Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
Diffstat (limited to 'src/app/config-ui')
-rw-r--r--src/app/config-ui/mainwindow.cpp64
-rw-r--r--src/app/config-ui/mainwindow.h4
-rw-r--r--src/app/config-ui/settingsmodel.cpp156
-rw-r--r--src/app/config-ui/settingsmodel.h9
4 files changed, 218 insertions, 15 deletions
diff --git a/src/app/config-ui/mainwindow.cpp b/src/app/config-ui/mainwindow.cpp
index 1ea3729b5..2b997fe65 100644
--- a/src/app/config-ui/mainwindow.cpp
+++ b/src/app/config-ui/mainwindow.cpp
@@ -35,13 +35,20 @@
#include <QKeySequence>
#include <QMenu>
#include <QMenuBar>
+#include <QMessageBox>
+#include <QModelIndex>
+#include <QPoint>
+#include <QString>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_model = new SettingsModel(this);
ui->treeView->setModel(m_model);
+ ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->treeView, SIGNAL(expanded(QModelIndex)), SLOT(adjustColumns()));
+ connect(ui->treeView, SIGNAL(customContextMenuRequested(QPoint)),
+ SLOT(provideContextMenu(QPoint)));
adjustColumns();
QMenu * const fileMenu = menuBar()->addMenu(tr("&File"));
@@ -50,6 +57,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
QAction * const reloadAction = new QAction(tr("&Reload"), this);
reloadAction->setShortcut(Qt::CTRL | Qt::Key_R);
connect(reloadAction, SIGNAL(triggered()), SLOT(reloadSettings()));
+ QAction * const saveAction = new QAction(tr("&Save"), this);
+ saveAction->setShortcut(Qt::CTRL | Qt::Key_S);
+ connect(saveAction, SIGNAL(triggered()), SLOT(saveSettings()));
QAction * const expandAllAction = new QAction(tr("&Expand All"), this);
expandAllAction->setShortcut(Qt::CTRL | Qt::Key_E);
connect(expandAllAction, SIGNAL(triggered()), SLOT(expandAll()));
@@ -58,9 +68,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(collapseAllAction, SIGNAL(triggered()), SLOT(collapseAll()));
QAction * const exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcut(Qt::CTRL | Qt::Key_Q);
- connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+ connect(exitAction, SIGNAL(triggered()), SLOT(exit()));
fileMenu->addAction(reloadAction);
+ fileMenu->addAction(saveAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
@@ -93,5 +104,56 @@ void MainWindow::collapseAll()
void MainWindow::reloadSettings()
{
+ if (m_model->hasUnsavedChanges()) {
+ const QMessageBox::StandardButton answer = QMessageBox::question(this,
+ tr("Unsaved Changes"),
+ tr("You have unsaved changes. Do you want to discard them?"));
+ if (answer != QMessageBox::Yes)
+ return;
+ }
m_model->reload();
}
+
+void MainWindow::saveSettings()
+{
+ m_model->save();
+}
+
+void MainWindow::exit()
+{
+ if (m_model->hasUnsavedChanges()) {
+ const QMessageBox::StandardButton answer = QMessageBox::question(this,
+ tr("Unsaved Changes"),
+ tr("You have unsaved changes. Do you want to save them now?"));
+ if (answer == QMessageBox::Yes)
+ m_model->save();
+ }
+ qApp->quit();
+}
+
+void MainWindow::provideContextMenu(const QPoint &pos)
+{
+ const QModelIndex index = ui->treeView->indexAt(pos);
+ if (index.isValid() && index.column() != m_model->keyColumn())
+ return;
+ const QString settingsKey = m_model->data(index).toString();
+
+ QMenu contextMenu;
+ QAction addKeyAction(this);
+ QAction removeKeyAction(this);
+ if (index.isValid()) {
+ addKeyAction.setText(tr("Add new key below '%1'").arg(settingsKey));
+ removeKeyAction.setText(tr("Remove key '%1' and all its sub-keys").arg(settingsKey));
+ contextMenu.addAction(&addKeyAction);
+ contextMenu.addAction(&removeKeyAction);
+ } else {
+ addKeyAction.setText(tr("Add new top-level key"));
+ contextMenu.addAction(&addKeyAction);
+ }
+
+ const QAction *action = contextMenu.exec(ui->treeView->mapToGlobal(pos));
+ if (action == &addKeyAction)
+ m_model->addNewKey(index);
+ else if (action == &removeKeyAction)
+ m_model->removeKey(index);
+}
diff --git a/src/app/config-ui/mainwindow.h b/src/app/config-ui/mainwindow.h
index e793f69dd..cd365c86e 100644
--- a/src/app/config-ui/mainwindow.h
+++ b/src/app/config-ui/mainwindow.h
@@ -33,6 +33,7 @@
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
+class QPoint;
QT_END_NAMESPACE
class SettingsModel;
@@ -50,6 +51,9 @@ private slots:
void expandAll();
void collapseAll();
void reloadSettings();
+ void saveSettings();
+ void exit();
+ void provideContextMenu(const QPoint &pos);
private:
Ui::MainWindow *ui;
diff --git a/src/app/config-ui/settingsmodel.cpp b/src/app/config-ui/settingsmodel.cpp
index 1eef5073f..9f58ac121 100644
--- a/src/app/config-ui/settingsmodel.cpp
+++ b/src/app/config-ui/settingsmodel.cpp
@@ -38,6 +38,9 @@ struct Node
Node() : parent(0) {}
~Node() { qDeleteAll(children); }
+ QString uniqueChildName() const;
+ bool hasDirectChildWithName(const QString &name) const;
+
QString name;
QString value;
Node *parent;
@@ -48,15 +51,19 @@ class SettingsModel::SettingsModelPrivate
{
public:
void readSettings();
- void addNode(qbs::Settings *settings, Node *parentNode, const QString &fullyQualifiedName);
+ void addNode(Node *parentNode, const QString &fullyQualifiedName);
+ void doSave(const Node *node, const QString &prefix);
Node *indexToNode(const QModelIndex &index);
Node rootNode;
+ SettingsPtr settings;
+ bool dirty;
};
SettingsModel::SettingsModel(QObject *parent)
: QAbstractItemModel(parent), d(new SettingsModelPrivate)
{
+ d->settings = qbsSettings();
d->readSettings();
}
@@ -72,11 +79,63 @@ void SettingsModel::reload()
endResetModel();
}
+void SettingsModel::save()
+{
+ if (!d->dirty)
+ return;
+ d->settings->clear();
+ d->doSave(&d->rootNode, QString());
+ d->dirty = false;
+}
+
+void SettingsModel::addNewKey(const QModelIndex &parent)
+{
+ Node *parentNode = d->indexToNode(parent);
+ if (!parentNode)
+ return;
+ Node * const newNode = new Node;
+ newNode->parent = parentNode;
+ newNode->name = parentNode->uniqueChildName();
+ beginInsertRows(parent, parentNode->children.count(), parentNode->children.count());
+ parentNode->children << newNode;
+ endInsertRows();
+ d->dirty = true;
+}
+
+void SettingsModel::removeKey(const QModelIndex &index)
+{
+ Node * const node = d->indexToNode(index);
+ if (!node || node == &d->rootNode)
+ return;
+ const int positionInParent = node->parent->children.indexOf(node);
+ beginRemoveRows(parent(index), positionInParent, positionInParent);
+ node->parent->children.removeAt(positionInParent);
+ delete node;
+ endRemoveRows();
+ d->dirty = true;
+}
+
+bool SettingsModel::hasUnsavedChanges() const
+{
+ return d->dirty;
+}
+
Qt::ItemFlags SettingsModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::ItemFlags();
- return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+ const Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
+ if (index.column() == keyColumn())
+ return flags | Qt::ItemIsEditable;
+ if (index.column() == valueColumn()) {
+ const Node * const node = d->indexToNode(index);
+ if (!node)
+ return Qt::ItemFlags();
+
+ // Only leaf nodes have values.
+ return node->children.isEmpty() ? flags | Qt::ItemIsEditable : flags;
+ }
+ return Qt::ItemFlags();
}
QVariant SettingsModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -85,9 +144,11 @@ QVariant SettingsModel::headerData(int section, Qt::Orientation orientation, int
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
- if (section == 0)
+ if (section == keyColumn())
return tr("Key");
- return tr("Value");
+ if (section == valueColumn())
+ return tr("Value");
+ return QVariant();
}
int SettingsModel::columnCount(const QModelIndex &parent) const
@@ -107,13 +168,40 @@ int SettingsModel::rowCount(const QModelIndex &parent) const
QVariant SettingsModel::data(const QModelIndex &index, int role) const
{
- if (role != Qt::DisplayRole)
+ if (role != Qt::DisplayRole && role != Qt::EditRole)
return QVariant();
- const Node * const node = static_cast<Node *>(index.internalPointer());
- Q_ASSERT(node);
- if (index.column() == 0)
+ const Node * const node = d->indexToNode(index);
+ if (!node)
+ return QVariant();
+ if (index.column() == keyColumn())
return node->name;
- return node->value;
+ if (index.column() == valueColumn() && node->children.isEmpty())
+ return node->value;
+ return QVariant();
+}
+
+bool SettingsModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || role != Qt::EditRole)
+ return false;
+ Node * const node = d->indexToNode(index);
+ if (!node)
+ return false;
+ const QString valueString = value.toString();
+ QString *toChange = 0;
+ if (index.column() == keyColumn() && !valueString.isEmpty()
+ && !node->parent->hasDirectChildWithName(valueString)) {
+ toChange = &node->name;
+ } else if (index.column() == valueColumn() && valueString != node->value) {
+ toChange = &node->value;
+ }
+
+ if (toChange) {
+ *toChange = valueString;
+ emit dataChanged(index, index);
+ d->dirty = true;
+ }
+ return toChange;
}
QModelIndex SettingsModel::index(int row, int column, const QModelIndex &parent) const
@@ -142,24 +230,64 @@ void SettingsModel::SettingsModelPrivate::readSettings()
{
qDeleteAll(rootNode.children);
rootNode.children.clear();
- SettingsPtr settings = qbsSettings();
foreach (const QString &topLevelKey, settings->directChildren(QString()))
- addNode(settings.data(), &rootNode, topLevelKey);
+ addNode(&rootNode, topLevelKey);
+ dirty = false;
}
-void SettingsModel::SettingsModelPrivate::addNode(qbs::Settings *settings, Node *parentNode,
+void SettingsModel::SettingsModelPrivate::addNode(Node *parentNode,
const QString &fullyQualifiedName)
{
Node * const node = new Node;
node->name = fullyQualifiedName.mid(fullyQualifiedName.lastIndexOf(QLatin1Char('.')) + 1);
- node->value = settings->value(fullyQualifiedName).toStringList().join(QLatin1String(","));
+ node->value = settingsValueToRepresentation(settings->value(fullyQualifiedName));
node->parent = parentNode;
parentNode->children << node;
foreach (const QString &childKey, settings->directChildren(fullyQualifiedName))
- addNode(settings, node, fullyQualifiedName + QLatin1Char('.') + childKey);
+ addNode(node, fullyQualifiedName + QLatin1Char('.') + childKey);
+ dirty = true;
+}
+
+void SettingsModel::SettingsModelPrivate::doSave(const Node *node, const QString &prefix)
+{
+ if (node->children.isEmpty()) {
+ settings->setValue(prefix + node->name, representationToSettingsValue(node->value));
+ return;
+ }
+
+ const QString newPrefix = prefix + node->name + QLatin1Char('.');
+ foreach (const Node * const child, node->children)
+ doSave(child, newPrefix);
}
Node *SettingsModel::SettingsModelPrivate::indexToNode(const QModelIndex &index)
{
return index.isValid() ? static_cast<Node *>(index.internalPointer()) : &rootNode;
}
+
+
+QString Node::uniqueChildName() const
+{
+ QString newName = QLatin1String("newkey");
+ bool unique;
+ do {
+ unique = true;
+ foreach (const Node *childNode, children) {
+ if (childNode->name == newName) {
+ unique = false;
+ newName += QLatin1Char('_');
+ break;
+ }
+ }
+ } while (!unique);
+ return newName;
+}
+
+bool Node::hasDirectChildWithName(const QString &name) const
+{
+ foreach (const Node * const child, children) {
+ if (child->name == name)
+ return true;
+ }
+ return false;
+}
diff --git a/src/app/config-ui/settingsmodel.h b/src/app/config-ui/settingsmodel.h
index 1052196e2..510ff1f5d 100644
--- a/src/app/config-ui/settingsmodel.h
+++ b/src/app/config-ui/settingsmodel.h
@@ -35,13 +35,22 @@ public:
SettingsModel(QObject *parent = 0);
~SettingsModel();
+ int keyColumn() const { return 0; }
+ int valueColumn() const { return 1; }
+ bool hasUnsavedChanges() const;
+
void reload();
+ void save();
+
+ void addNewKey(const QModelIndex &parent);
+ void removeKey(const QModelIndex &index);
Qt::ItemFlags flags(const QModelIndex &index) const;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
QModelIndex parent(const QModelIndex &child) const;