# HG changeset patch
# User mandel
# Date 1245113498 0
# Node ID ea0861a37bf6c6b599491d214f35cb1cb46a7c2b
# Parent 4d1c5d1d1bbffcf0bb969a5f6fbe341b31566c0b
add editabletreemodel, still buggy
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/CMakeLists.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/CMakeLists.txt Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,1 @@
+build_example(editabletreemodel main.d mainwindow.d treeitem.d treemodel.d ui_mainwindow.d qrc_editabletreemodel.d)
\ No newline at end of file
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/build.bat
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/build.bat Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,3 @@
+../../../tools/drcc/drcc editabletreemodel.qrc -o qrc_editabletreemodel.d
+../../../tools/duic/duic mainwindow.ui -o ui_mainwindow.d
+dmd main.d mainwindow.d treeitem.d treemodel.d ui_mainwindow.d qrc_editabletreemodel.d libqtdcore.lib libqtdgui.lib -I../../../
\ No newline at end of file
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/build.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/build.sh Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+../../../tools/drcc/drcc editabletreemodel.qrc -o qrc_editabletreemodel.d
+../../../tools/duic/duic mainwindow.ui -o ui_mainwindow.d
+ldc main.d mainwindow.d treeitem.d treemodel.d ui_mainwindow.d qrc_editabletreemodel.d -I../../../ -I../../../qt/d1 -L-L../../../lib -L-lqtdgui -L-lqtdcore -L-lQtCore -L-lQtGui -ofeditabletreemodel
\ No newline at end of file
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/default.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/default.txt Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,40 @@
+Getting Started How to familiarize yourself with Qt Designer
+ Launching Designer Running the Qt Designer application
+ The User Interface How to interact with Qt Designer
+
+Designing a Component Creating a GUI for your application
+ Creating a Dialog How to create a dialog
+ Composing the Dialog Putting widgets into the dialog example
+ Creating a Layout Arranging widgets on a form
+ Signal and Slot Connections Making widget communicate with each other
+
+Using a Component in Your Application Generating code from forms
+ The Direct Approach Using a form without any adjustments
+ The Single Inheritance Approach Subclassing a form's base class
+ The Multiple Inheritance Approach Subclassing the form itself
+ Automatic Connections Connecting widgets using a naming scheme
+ A Dialog Without Auto-Connect How to connect widgets without a naming scheme
+ A Dialog With Auto-Connect Using automatic connections
+
+Form Editing Mode How to edit a form in Qt Designer
+ Managing Forms Loading and saving forms
+ Editing a Form Basic editing techniques
+ The Property Editor Changing widget properties
+ The Object Inspector Examining the hierarchy of objects on a form
+ Layouts Objects that arrange widgets on a form
+ Applying and Breaking Layouts Managing widgets in layouts
+ Horizontal and Vertical Layouts Standard row and column layouts
+ The Grid Layout Arranging widgets in a matrix
+ Previewing Forms Checking that the design works
+
+Using Containers How to group widgets together
+ General Features Common container features
+ Frames QFrame
+ Group Boxes QGroupBox
+ Stacked Widgets QStackedWidget
+ Tab Widgets QTabWidget
+ Toolbox Widgets QToolBox
+
+Connection Editing Mode Connecting widgets together with signals and slots
+ Connecting Objects Making connections in Qt Designer
+ Editing Connections Changing existing connections
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/editabletreemodel.qrc
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/editabletreemodel.qrc Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,5 @@
+
+
+ default.txt
+
+
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/main.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/main.d Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+module main;
+
+
+import qt.gui.QApplication;
+
+import mainwindow;
+
+
+int main(string[] args)
+{
+ scope app = new QApplication(args);
+ scope window = new MainWindow;
+ window.show();
+ return app.exec();
+}
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/mainwindow.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/mainwindow.d Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,202 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+module mainwindow;
+
+
+import qt.core.QModelIndex;
+import qt.core.QFile;
+import qt.gui.QMainWindow;
+import qt.gui.QAction;
+import qt.gui.QTreeView;
+import qt.gui.QWidget;
+
+import tango.text.convert.Format;
+
+import ui_mainwindow;
+import mainwindow;
+import treemodel;
+
+
+class MainWindow : public QMainWindow
+{
+
+mixin Ui_MainWindow;
+
+public:
+
+ this(QWidget parent = null)
+ {
+ super(parent);
+ setupUi(this);
+
+ string[] headers;
+ headers ~= tr("Title");
+ headers ~= tr("Description");
+
+ auto file = new QFile(":/default.txt");
+ file.open(QIODevice.ReadOnly);
+ TreeModel model = new TreeModel(headers, file.readAll().data()[0..file.size()]);
+ file.close();
+
+ view.setModel(model);
+ for (int column = 0; column < model.columnCount(); ++column)
+ view.resizeColumnToContents(column);
+
+ exitAction.triggered.connect(&QApplication.quit);
+
+ view.selectionModel().selectionChanged.connect(&this.updateActions);
+
+ actionsMenu.aboutToShow.connect(&this.updateActions);
+ insertRowAction.triggered.connect(&this.insertRow);
+ insertColumnAction.triggered.connect(&this.insertColumn);
+ removeRowAction.triggered.connect(&this.removeRow);
+ removeColumnAction.triggered.connect(&this.removeColumn);
+ insertChildAction.triggered.connect(&this.insertChild);
+
+ updateActions();
+ }
+
+public:
+
+ void updateActions()
+ {
+ bool hasSelection = !view.selectionModel().selection().isEmpty();
+ removeRowAction.setEnabled(hasSelection);
+ removeColumnAction.setEnabled(hasSelection);
+
+ bool hasCurrent = view.selectionModel().currentIndex().isValid();
+ insertRowAction.setEnabled(hasCurrent);
+ insertColumnAction.setEnabled(hasCurrent);
+
+ if (hasCurrent) {
+ view.closePersistentEditor(view.selectionModel().currentIndex());
+
+ int row = view.selectionModel().currentIndex().row();
+ int column = view.selectionModel().currentIndex().column();
+ if (view.selectionModel().currentIndex().parent().isValid())
+ statusBar().showMessage(Format(tr("Position: ({},{})"), row, column));
+ else
+ statusBar().showMessage(Format(tr("Position: ({},{}) in top level"), row, column));
+ }
+ }
+
+private:
+
+ void insertChild()
+ {
+ QModelIndex index = view.selectionModel().currentIndex();
+ QAbstractItemModel model = view.model();
+
+ if (model.columnCount(index) == 0) {
+ if (!model.insertColumn(0, index))
+ return;
+ }
+
+ if (!model.insertRow(0, index))
+ return;
+
+ for (int column = 0; column < model.columnCount(index); ++column) {
+ QModelIndex child = model.index(0, column, index);
+ model.setData(child, QVariant("[No data]"), Qt.EditRole);
+ if (!model.headerData(column, Qt.Horizontal).isValid())
+ model.setHeaderData(column, Qt.Horizontal, QVariant("[No header]"), Qt.EditRole);
+ }
+
+ view.selectionModel().setCurrentIndex(model.index(0, 0, index), QItemSelectionModel.ClearAndSelect);
+ updateActions();
+ }
+
+ bool insertColumn()
+ {
+ QModelIndex parent = QModelIndex(); //moved from method head
+ QAbstractItemModel model = view.model();
+ int column = view.selectionModel().currentIndex().column();
+
+ // Insert a column in the parent item.
+ bool changed = model.insertColumn(column + 1, parent);
+ if (changed)
+ model.setHeaderData(column + 1, Qt.Horizontal, QVariant("[No header]"), Qt.EditRole);
+
+ updateActions();
+
+ return changed;
+ }
+
+ void insertRow()
+ {
+ QModelIndex index = view.selectionModel().currentIndex();
+ QAbstractItemModel model = view.model();
+
+ if (!model.insertRow(index.row()+1, index.parent()))
+ return;
+
+ updateActions();
+
+ for (int column = 0; column < model.columnCount(index.parent()); ++column) {
+ QModelIndex child = model.index(index.row()+1, column, index.parent());
+ model.setData(child, QVariant("[No data]"), Qt.EditRole);
+ }
+ }
+
+ bool removeColumn()
+ {
+ QModelIndex parent = QModelIndex(); //moved from method head
+ QAbstractItemModel model = view.model();
+ int column = view.selectionModel().currentIndex().column();
+
+ // Insert columns in each child of the parent item.
+ bool changed = model.removeColumn(column, parent);
+
+ if (!parent.isValid() && changed)
+ updateActions();
+
+ return changed;
+ }
+
+ void removeRow()
+ {
+ QModelIndex index = view.selectionModel().currentIndex();
+ QAbstractItemModel model = view.model();
+ if (model.removeRow(index.row(), index.parent()))
+ updateActions();
+ }
+
+}
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/mainwindow.ui
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/mainwindow.ui Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,128 @@
+
+ MainWindow
+
+
+
+ 0
+ 0
+ 573
+ 468
+
+
+
+ Editable Tree Model
+
+
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ true
+
+
+ QAbstractItemView::SelectItems
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ false
+
+
+ true
+
+
+
+
+
+
+
+
+
+ E&xit
+
+
+ Ctrl+Q
+
+
+
+
+ Insert Row
+
+
+ Ctrl+I, R
+
+
+
+
+ Remove Row
+
+
+ Ctrl+R, R
+
+
+
+
+ Insert Column
+
+
+ Ctrl+I, C
+
+
+
+
+ Remove Column
+
+
+ Ctrl+R, C
+
+
+
+
+ Insert Child
+
+
+ Ctrl+N
+
+
+
+
+
+
+
+
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/treeitem.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/treeitem.d Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+module treeitem;
+
+
+import qt.core.QVariant;
+
+import tango.core.Array;
+
+
+//substitute for QList methods
+void insert(T)(ref T[] items, int pos, T item)
+{
+ items = items[0..pos] ~ [item] ~ items[pos..$];
+}
+
+T takeAt(T)(ref T[] items, int pos)
+{
+ T item = items[pos];
+ items = items[0..pos] ~ items[pos+1..$];
+ return item;
+}
+
+int indexOf(T)(T[] items, T item, int from = -1)
+{
+ assert(from < cast(int) items.length);
+ auto beg = (from < 0) ? 0 : from;
+ auto pos = beg + find(items[beg..$], item);
+ return (pos == items.length) ? -1 : pos;
+}
+
+void remove(T)(ref T[] items, uint pos)
+{
+ items = items[0..pos] ~ items[pos+1..$];
+}
+
+
+class TreeItem
+{
+public:
+
+ this(QVariant[] data, TreeItem parent = null)
+ {
+ parentItem = parent;
+ itemData = data;
+ }
+
+ ~this()
+ {
+ delete childItems;
+ }
+
+ TreeItem child(int number)
+ {
+ if(number < 0 || number >= childItems.length)
+ return null;
+ return childItems[number];
+ }
+
+ int childCount()
+ {
+ return childItems.length;
+ }
+
+ int columnCount()
+ {
+ return itemData.length;
+ }
+
+ QVariant data(int column)
+ {
+ if(column < 0 || column >= itemData.length)
+ return null;
+ return itemData[column];
+ }
+
+ bool insertChildren(int position, int count, int columns)
+ {
+ if (position < 0 || position > childItems.length)
+ return false;
+
+ for (int row = 0; row < count; ++row) {
+ auto data = new QVariant[](columns);
+ TreeItem item = new TreeItem(data, this);
+ insert(childItems, position, item);
+ }
+
+ return true;
+ }
+
+ bool insertColumns(int position, int columns)
+ {
+ if (position < 0 || position > itemData.length)
+ return false;
+
+ for (int column = 0; column < columns; ++column)
+ insert(itemData, position, new QVariant());
+
+ foreach (TreeItem child; childItems)
+ child.insertColumns(position, columns);
+
+ return true;
+ }
+
+ TreeItem parent()
+ {
+ return parentItem;
+ }
+
+ bool removeChildren(int position, int count)
+ {
+ if (position < 0 || position + count > childItems.length)
+ return false;
+
+ for (int row = 0; row < count; ++row)
+ {
+ auto tmp = takeAt(childItems, position);
+ delete tmp;
+ }
+ return true;
+ }
+
+ bool removeColumns(int position, int columns)
+ {
+ if (position < 0 || position + columns > itemData.length)
+ return false;
+
+ for (int column = 0; column < columns; ++column)
+ remove(itemData, position);
+
+ foreach (TreeItem child; childItems)
+ child.removeColumns(position, columns);
+
+ return true;
+ }
+
+ int childNumber()
+ {
+ if (parentItem)
+ return indexOf(parentItem.childItems, cast(TreeItem) this);
+
+ return 0;
+ }
+
+ bool setData(int column, QVariant value)
+ {
+ if (column < 0 || column >= itemData.length)
+ return false;
+
+ itemData[column] = value;
+ return true;
+ }
+
+private:
+
+ TreeItem[] childItems;
+ QVariant[] itemData;
+ TreeItem parentItem;
+}
diff -r 4d1c5d1d1bbf -r ea0861a37bf6 examples/itemviews/editabletreemodel/treemodel.d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/itemviews/editabletreemodel/treemodel.d Tue Jun 16 00:51:38 2009 +0000
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial Usage
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+module treemodel;
+
+
+import qt.core.QAbstractItemModel;
+import qt.core.QModelIndex;
+import qt.core.QVariant;
+
+import treeitem;
+
+import tango.core.Array : find;
+import tango.text.Util : trim;
+
+
+//replacement for QString.split
+T[][] split(T)(T[] str, T[] match, bool keep_empty = true)
+{
+ uint pos, start = 0;
+
+ T[][] values;
+ if(str.length == 0)
+ return values;
+
+ while(true)
+ {
+ pos = start + find(str[start..$], match);
+ if(keep_empty)
+ {
+ if((pos - start) >= 0)
+ values ~= str[start..pos];
+ }
+ else
+ {
+ if((pos - start) != 0)
+ values ~= str[start..pos];
+ }
+
+ if(pos == str.length)
+ break;
+
+ start = pos + 1;
+ }
+
+ return values;
+}
+
+
+class TreeModel : public QAbstractItemModel
+{
+public:
+
+ this(string[] headers, string data, QObject parent = null)
+ {
+ super(parent);
+ QVariant[] rootData;
+ foreach(string header; headers)
+ rootData ~= new QVariant(header);
+
+ rootItem = new TreeItem(rootData);
+ setupModelData(split(data, "\n"), rootItem);
+ }
+
+ ~this()
+ {
+ delete rootItem;
+ }
+
+ QVariant data(QModelIndex index, int role)
+ {
+ if (!index.isValid())
+ return new QVariant();
+
+ if (role != Qt.DisplayRole && role != Qt.EditRole)
+ return new QVariant();
+
+ TreeItem item = getItem(index);
+ return item.data(index.column());
+ }
+
+ QVariant headerData(int section, Qt.Orientation orientation, int role = Qt.DisplayRole)
+ {
+ if (orientation == Qt.Horizontal && role == Qt.DisplayRole)
+ return rootItem.data(section);
+
+ return new QVariant();
+ }
+
+ QModelIndex index(int row, int column, QModelIndex parent = QModelIndex())
+ {
+ if (parent.isValid() && parent.column() != 0)
+ return QModelIndex();
+
+ TreeItem parentItem = getItem(parent);
+
+ TreeItem childItem = parentItem.child(row);
+ if (childItem)
+ return createIndex(row, column, cast(void*) childItem);
+ else
+ return QModelIndex();
+ }
+
+ QModelIndex parent(QModelIndex index)
+ {
+ if (!index.isValid())
+ return QModelIndex();
+
+ TreeItem childItem = getItem(index);
+ TreeItem parentItem = childItem.parent();
+
+ if (parentItem == rootItem)
+ return QModelIndex();
+
+ return createIndex(parentItem.childNumber(), 0, cast(void*) parentItem);
+ }
+
+ int rowCount(QModelIndex parent = QModelIndex())
+ {
+ TreeItem parentItem = getItem(parent);
+ return parentItem.childCount();
+ }
+
+ int columnCount(QModelIndex parent = QModelIndex())
+ {
+ return rootItem.columnCount();
+ }
+
+ int flags(QModelIndex index)
+ {
+ if (!index.isValid())
+ return 0;
+
+ return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable;
+ }
+
+
+ bool setData(QModelIndex index, QVariant value, int role = Qt.EditRole)
+ {
+ if (role != Qt.EditRole)
+ return false;
+
+ TreeItem item = getItem(index);
+ bool result = item.setData(index.column(), value);
+
+ if (result)
+ dataChanged.emit(index, index);
+
+ return result;
+ }
+
+ bool setHeaderData(int section, Qt.Orientation orientation, QVariant value, int role = Qt.EditRole)
+ {
+ if (role != Qt.EditRole || orientation != Qt.Horizontal)
+ return false;
+
+ bool result = rootItem.setData(section, value);
+
+ if (result)
+ headerDataChanged.emit(orientation, section, section);
+
+ return result;
+ }
+
+ bool insertColumns(int position, int columns, QModelIndex parent = QModelIndex())
+ {
+ bool success;
+
+ beginInsertColumns(parent, position, position + columns - 1);
+ success = rootItem.insertColumns(position, columns);
+ endInsertColumns();
+
+ return success;
+ }
+
+
+ bool removeColumns(int position, int columns, QModelIndex parent = QModelIndex())
+ {
+ bool success;
+
+ beginRemoveColumns(parent, position, position + columns - 1);
+ success = rootItem.removeColumns(position, columns);
+ endRemoveColumns();
+
+ if (rootItem.columnCount() == 0)
+ removeRows(0, rowCount());
+
+ return success;
+ }
+
+
+ bool insertRows(int position, int rows, QModelIndex parent = QModelIndex())
+ {
+ TreeItem parentItem = getItem(parent);
+ bool success;
+
+ beginInsertRows(parent, position, position + rows - 1);
+ success = parentItem.insertChildren(position, rows, rootItem.columnCount());
+ endInsertRows();
+
+ return success;
+ }
+
+ bool removeRows(int position, int rows, QModelIndex parent = QModelIndex())
+ {
+ TreeItem parentItem = getItem(parent);
+ bool success = true;
+
+ beginRemoveRows(parent, position, position + rows - 1);
+ success = parentItem.removeChildren(position, rows);
+ endRemoveRows();
+
+ return success;
+ }
+
+private:
+
+ void setupModelData(string[] lines, TreeItem parent)
+ {
+ TreeItem[] parents;
+ int[] indentations;
+ parents ~= parent;
+ indentations ~= 0;
+
+ int number = 0;
+
+ while (number < lines.length) {
+ int position = 0;
+ while (position < lines[number].length) {
+ if (lines[number][position] != ' ')
+ break;
+ position++;
+ }
+
+ string lineData = trim(lines[number][position..$]);
+
+ if (lineData.length) {
+ // Read the column data from the rest of the line.
+ string[] columnStrings = split(lineData, "\t", false);
+ QVariant[] columnData;
+ for (int column = 0; column < columnStrings.length; ++column)
+ columnData ~= new QVariant(columnStrings[column]);
+
+ if (position > indentations[$-1]) {
+ // The last child of the current parent is now the new parent
+ // unless the current parent has no children.
+
+ if (parents[$-1].childCount() > 0) {
+ parents ~= parents[$-1].child(parents[$-1].childCount()-1);
+ indentations ~= position;
+ }
+ } else {
+ while (position < indentations[$-1] && parents.length > 0) {
+ parents = parents[0..$-1];
+ indentations = indentations[0..$-1];
+ }
+ }
+
+ // Append a new item to the current parent's list of children.
+ parent = parents[$-1];
+ parent.insertChildren(parent.childCount(), 1, rootItem.columnCount());
+ for (int column = 0; column < columnData.length; ++column)
+ parent.child(parent.childCount() - 1).setData(column, columnData[column]);
+ }
+
+ number++;
+ }
+ }
+
+ TreeItem getItem(QModelIndex index)
+ {
+ if (index.isValid()) {
+ TreeItem item = cast(TreeItem) index.internalPointer();
+ if (item) return item;
+ }
+ return rootItem;
+ }
+
+ TreeItem rootItem;
+}