]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
ADD: add basic use cases of TreeData (can be used as "manual" unit tests)
authorboulant <boulant>
Wed, 2 Nov 2011 13:59:48 +0000 (13:59 +0000)
committerboulant <boulant>
Wed, 2 Nov 2011 13:59:48 +0000 (13:59 +0000)
14 files changed:
configure.ac
src/GuiHelpers/Makefile.am
src/Makefile.am
src/TreeData/Test/Makefile.am [new file with mode: 0644]
src/TreeData/Test/MyDataModel.cxx [new file with mode: 0644]
src/TreeData/Test/MyDataModel.hxx [new file with mode: 0644]
src/TreeData/Test/data.txt [new file with mode: 0755]
src/TreeData/Test/guitester.cxx [new file with mode: 0644]
src/TreeData/Test/mainwindow.cxx [new file with mode: 0644]
src/TreeData/Test/mainwindow.hxx [new file with mode: 0644]
src/TreeData/Test/mainwindow.ui [new file with mode: 0644]
src/TreeData/Test/tester.cxx [new file with mode: 0644]
src/TreeData/Test/testhelper.cxx [new file with mode: 0644]
src/TreeData/Test/testhelper.hxx [new file with mode: 0644]

index c2ad5d5e1ddafdbe704d17236da9da080dd5aac4..bd062e60dd1b966c7334d32ac5644cce46c84c11 100644 (file)
@@ -662,6 +662,7 @@ AC_OUTPUT([ \
   src/SalomeApp/Test/Makefile \
   src/GuiHelpers/Makefile \
   src/TreeData/Makefile \
+  src/TreeData/Test/Makefile \
   src/SALOME_SWIG/Makefile \
   src/SALOME_SWIG/supervisionexample.py \
   src/SALOME_SWIG/supervisiongeomexample.py \
index 931d1a4d8b9669d894088a1db7c809b1f463b909..1da8a1a8f52b453f58d2abac3e4fa58e4a9ec2d6 100644 (file)
@@ -78,4 +78,4 @@ MOC_FILES = \
 
 nodist_libSalomeGuiHelpers_la_SOURCES = $(MOC_FILES)
 
-EXTRA_DIST=$(MOC_FILES:%_moc.cxx=%.hxx)
+EXTRA_DIST+=$(MOC_FILES:%_moc.cxx=%.hxx)
index de80e714ffa66454cc37cc34242e333a9d2d4aa7..0769f85c75ad9ce6ef47ea58d16d7a9503df5a5b 100755 (executable)
@@ -107,8 +107,10 @@ SUBDIRS_LIGHT = LightApp ResExporter
 ##
 if GUI_ENABLE_CORBA
   SUBDIRS_CORBA = TOOLSGUI Session SalomeApp GuiHelpers TreeData
+  SUBDIRS_CORBA += TreeData/Test
 endif
 
+
 ##
 # Extra Python packages
 ##
diff --git a/src/TreeData/Test/Makefile.am b/src/TreeData/Test/Makefile.am
new file mode 100644 (file)
index 0000000..a1e9caf
--- /dev/null
@@ -0,0 +1,97 @@
+#  Copyright (C) 2010  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+# See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+# -* Makefile *- 
+#
+# Author : Guillaume Boulant (EDF) 
+#
+
+include $(top_srcdir)/adm_local/unix/make_common_starter.am
+
+# moc-files generation
+%_moc.cxx: %.hxx
+       $(MOC) $< -o $@
+
+mostlyclean-local:
+       rm -f @builddir@/*_moc.cxx
+       rm -f @builddir@/*.qm
+
+# qt forms files generation (uic)
+ui_%.h: %.ui
+       $(UIC) -o $@ $<
+
+
+CORBA_CXXFLAGS=@OMNIORB_CXXFLAGS@ @OMNIORB_INCLUDES@
+CORBA_LIBS=@OMNIORB_LIBS@
+QT_CXXFLAGS=@QT_INCLUDES@ @QT_MT_INCLUDES@
+
+TEST_CPPFLAGS = \
+       $(QT_CXXFLAGS) \
+       $(CORBA_CXXFLAGS) \
+       $(KERNEL_CXXFLAGS) \
+       -I$(top_srcdir)/src/GuiHelpers \
+       -I$(top_srcdir)/src/TreeData
+
+TEST_LDFLAGS  = \
+       $(CORBA_LIBS) $(QT_LIBS) \
+       $(top_builddir)/src/TreeData/libSalomeTreeData.la \
+       $(top_builddir)/src/GuiHelpers/libSalomeGuiHelpers.la \
+       $(KERNEL_LDFLAGS) -lSalomeLifeCycleCORBA -lSalomeKernelHelpers
+
+# Program targets
+bin_PROGRAMS = TreeData_guitester TreeData_tester
+
+MOC_FILES = \
+       mainwindow_moc.cxx
+
+UIC_FILES = \
+       ui_mainwindow.h
+
+BUILT_SOURCES = $(UIC_FILES)
+
+nodist_TreeData_guitester_SOURCES = $(MOC_FILES) $(UIC_FILES)
+
+TreeData_guitester_SOURCES = \
+       testhelper.cxx \
+       guitester.cxx \
+       mainwindow.cxx \
+       MyDataModel.cxx
+
+TreeData_guitester_CPPFLAGS = \
+       $(TEST_CPPFLAGS)
+
+TreeData_guitester_LDFLAGS = \
+       $(TEST_LDFLAGS)
+
+TreeData_tester_SOURCES = \
+       tester.cxx \
+       MyDataModel.cxx
+
+TreeData_tester_CPPFLAGS = \
+       $(TEST_CPPFLAGS)
+
+TreeData_tester_LDFLAGS = \
+       $(TEST_LDFLAGS)
+
+# test data files
+testdir = $(salomeresdir)/testdata
+test_DATA = \
+       data.txt
+
+EXTRA_DIST+=$(test_DATA)
+
diff --git a/src/TreeData/Test/MyDataModel.cxx b/src/TreeData/Test/MyDataModel.cxx
new file mode 100644 (file)
index 0000000..0517147
--- /dev/null
@@ -0,0 +1,48 @@
+#include "MyDataModel.hxx"
+
+//
+// =================================================================
+// MyDataObject implementation
+// =================================================================
+//
+
+const string MyDataObject::PROPERTY_KEY_TYPE    = "type";
+const string MyDataObject::PROPERTY_KEY_CIRCUIT ="circuit";
+const string MyDataObject::PROPERTY_KEY_REPFONC ="rf";
+
+MyDataObject::MyDataObject() : DataObject() {
+  this->setProperty(PROPERTY_KEY_TYPE, "Tuyauterie");
+  this->setProperty(PROPERTY_KEY_CIRCUIT,"RRA");
+  this->setProperty(PROPERTY_KEY_REPFONC,"RF_01");
+}
+
+/*! This function specified the localization of the object in the
+ * hierarchical organization
+ */
+string MyDataObject::getPath() {
+  // We choose here a convention for organizing the path for this
+  // class of object.
+  /*
+  string path = getProperty(PROPERTY_KEY_CIRCUIT) + pathsep
+    + getProperty(PROPERTY_KEY_REPFONC) + pathsep
+    + getProperty(PROPERTY_KEY_TYPE);
+  */
+  string path = getProperty(PROPERTY_KEY_TYPE) + pathsep
+    + getProperty(PROPERTY_KEY_CIRCUIT) + pathsep
+    + getProperty(PROPERTY_KEY_REPFONC);
+    
+  return path;
+}
+
+//
+// =================================================================
+// MyDataModel implementation
+// =================================================================
+//
+MyDataModel::MyDataModel() : DataModel() {
+}
+
+DataObject * MyDataModel::newDataObject() {
+  MyDataObject * dataObject = new MyDataObject();
+  return dataObject;
+}
diff --git a/src/TreeData/Test/MyDataModel.hxx b/src/TreeData/Test/MyDataModel.hxx
new file mode 100644 (file)
index 0000000..4354ba5
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _MYDATAMODEL_H_
+#define _MYDATAMODEL_H_
+
+//
+// =================================================================
+// Definition of an atom in the data model as an implementation of
+// the virtual class DataObject
+// =================================================================
+//
+
+#include "DataObject.hxx"
+class MyDataObject: public DataObject {
+public:
+  MyDataObject();
+  virtual string getPath();
+  static const string PROPERTY_KEY_TYPE;
+  static const string PROPERTY_KEY_CIRCUIT;
+  static const string PROPERTY_KEY_REPFONC;
+};
+
+
+//
+// =================================================================
+// Definition of the data model as an implementation of the virtual
+// class DataModel. It implements the DataObject factory.
+// =================================================================
+//
+#include "DataModel.hxx"
+class MyDataModel: public DataModel {
+public:
+  MyDataModel();
+  virtual DataObject * newDataObject();
+};
+
+#endif // _MYDATAMODEL_H_
diff --git a/src/TreeData/Test/data.txt b/src/TreeData/Test/data.txt
new file mode 100755 (executable)
index 0000000..d28285b
--- /dev/null
@@ -0,0 +1,15 @@
+Tuyauterie;RF1;T1\r
+Tuyauterie;RF1;T2\r
+Tuyauterie;RF1;T3\r
+Tuyauterie;RF2;T1\r
+Tuyauterie;RF3;T1\r
+Tuyauterie;RF3;T2\r
+Composansts;RF1;T1\r
+Composansts;RF1;T2\r
+Composansts;RF3;T2\r
+Genie Civil;RF1;T1\r
+Genie Civil;RF1;T2\r
+Genie Civil;RF1;T3\r
+Genie Civil;RF2;T1\r
+Genie Civil;RF3;T1\r
+Genie Civil;RF3;T2\r
diff --git a/src/TreeData/Test/guitester.cxx b/src/TreeData/Test/guitester.cxx
new file mode 100644 (file)
index 0000000..5b36e7b
--- /dev/null
@@ -0,0 +1,202 @@
+#include <QApplication>
+#include <QMainWindow>
+#include <QDockWidget>
+#include <QTreeView>
+
+#include <Basics_Utils.hxx>
+
+//
+// =================================================================
+// Generic helper functions
+// =================================================================
+//
+/*!
+ * This functions displays a main window that embeds the specified
+ * widget. A dockwidget is used to create a context similar to as the
+ * SALOME target context.
+ */
+void showWidget(QWidget * widget) {
+
+  QMainWindow * window = new QMainWindow();
+
+  // Prepare a gui framework for testing the widget. We use a
+  // dockwidget, just to be in a context similar to as the SALOME
+  // target context.
+  QDockWidget * dwDataPanel = new QDockWidget(window);
+  dwDataPanel->setVisible(true);
+  dwDataPanel->setWindowTitle("XCAD data model");
+  window->addDockWidget(Qt::LeftDockWidgetArea, dwDataPanel);
+
+  // Then plug the widget in the dock widget framework:
+  widget->setParent(dwDataPanel);
+  widget->setMinimumHeight(300);
+  dwDataPanel->setWidget(widget);
+
+  window->show();
+}
+
+//
+// =================================================================
+// Tests functions for TreeModel
+// =================================================================
+//
+#include "TreeModel.hxx"
+#include "MyDataModel.hxx"
+#include "testhelper.hxx"
+
+
+/*!
+ * This function fills the specified tree with data that show
+ * different levels of path in the tree.
+ */
+void _TEST_treemodel_addData_01(TreeModel * dataTreeModel) {
+  // We can first add categories (for example to set categories
+  // properties)
+  QStringList path;
+  DataObject * folder;
+
+  path << "folder_1";
+  folder = TESTHELPER_dummyObject("folder_1.1");
+  dataTreeModel->addData(folder, path);
+  folder = TESTHELPER_dummyObject("folder_1.2");
+  dataTreeModel->addData(folder, path);
+
+  path.clear();
+  path << "folder_2";
+  folder = TESTHELPER_dummyObject("folder_2.1");
+  dataTreeModel->addData(folder, path);
+  
+  // Then we can add data
+  DataObject * data;
+  path.clear();
+  path << "folder_1" << "folder_1.1";
+  data = TESTHELPER_dummyObject("data_1.1.1");
+  dataTreeModel->addData(data, path);
+  data = TESTHELPER_dummyObject("data_1.1.2");
+  dataTreeModel->addData(data, path);
+  // You can notice that there is no conceptual difference between a
+  // folder and an item, as in the QTreeModel.
+  
+  // No limit to the depth
+  path.clear();
+  path << "xcad" << "data1" << "x" << "y";
+  data = TESTHELPER_dummyObject("z");
+  dataTreeModel->addData(data,path);
+}
+
+#define LOOPSIZE 15
+/*!
+ * This function fills the specified tree with a huge amount of data
+ */
+void _TEST_treemodel_addData_02(TreeModel * dataTreeModel) {
+  QStringList path;
+  DataObject * data;
+  
+  START_TIMING(treemodel);
+  for (int i=0; i<LOOPSIZE; i++) {
+    END_TIMING(treemodel,1);
+    for (int j=0; j<LOOPSIZE; j++) {
+      for (int k=0; k<LOOPSIZE; k++) {
+        // The data list corresponds to the path of the item in the tree
+        path << QString("folder_%0").arg(i)
+             << QString("subfolder_%0_%1").arg(i).arg(j);
+        data = TESTHELPER_dummyObject(QString("item_%0_%1_%2").arg(i).arg(j).arg(k));
+        dataTreeModel->addData(data,path);
+        path.clear();
+      } 
+    }
+  }
+  END_TIMING(treemodel,1);
+}
+
+void _TEST_treemodel_addData_03(TreeModel * dataTreeModel) {
+  MyDataObject * dataObject = new MyDataObject();
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_TYPE,    "Tuyauterie");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_CIRCUIT, "RCP");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_REPFONC, "RF1");
+  dataTreeModel->addData(dataObject);
+
+  dataObject = new MyDataObject();
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_TYPE,    "Tuyauterie");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_CIRCUIT, "RCP");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_REPFONC, "RF1");
+  dataTreeModel->addData(dataObject);
+
+  dataObject = new MyDataObject();
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_TYPE,    "Tuyauterie");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_CIRCUIT, "RCP");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_REPFONC, "RF2");
+  dataTreeModel->addData(dataObject);
+
+  dataObject = new MyDataObject();
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_TYPE,    "Tuyauterie");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_CIRCUIT, "RRA");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_REPFONC, "RF1");
+  dataTreeModel->addData(dataObject);
+
+  dataObject = new MyDataObject();
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_TYPE,    "Génie civil");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_CIRCUIT, "RRA");
+  dataObject->setProperty(MyDataObject::PROPERTY_KEY_REPFONC, "RF1");
+  dataTreeModel->addData(dataObject);
+}
+
+/*!
+ * This test function shows how it's possible to load data from a file
+ * to populate the tree model.
+ */
+void _TEST_treemodel_loadDataFromFile(TreeModel * dataTreeModel, const QString &filename) {
+  TESTHELPER_loadDataFromFile(dataTreeModel, filename);
+}
+
+/*!
+ * Main test function for the tree model demo.
+ */
+#include "TreeModel.hxx"
+#include "TreeView.hxx"
+void TEST_treemodel() {
+
+  START_TIMING(treemodel);
+
+  // We first prepare a data view embedding a tree model
+  TreeView * dataView = new TreeView();
+  QStringList headers;
+  headers << QObject::tr("Name") << QObject::tr("Value");
+  TreeModel * dataTreeModel = new TreeModel(headers);
+  dataView->setModel(dataTreeModel);
+  END_TIMING(treemodel,1);
+
+  // Then we can fill the tree model with data. Can proceed with
+  // different ways (comment/uncomment which you want to test):
+  _TEST_treemodel_loadDataFromFile(dataTreeModel, TESTHELPER_testfilename(DATAFILENAME));
+  //_TEST_treemodel_addData_01(dataTreeModel);
+  //_TEST_treemodel_addData_02(dataTreeModel);
+  //_TEST_treemodel_addData_03(dataTreeModel);
+  // Finally, show the widget in a main window
+  END_TIMING(treemodel,1);
+
+  showWidget(dataView);
+  END_TIMING(treemodel,1);
+}
+
+//
+// =================================================================
+// Tests functions for TreeModel with interactive changes
+// =================================================================
+//
+#include "mainwindow.hxx"
+void TEST_treemodel_interactif() {
+  MainWindow * window = new MainWindow();
+  window->show();
+}
+
+//
+// =================================================================
+//
+int main(int argc, char * argv[ ])
+{
+  QApplication app(argc, argv);
+  TEST_treemodel();
+  //TST_treemodel_interactif();
+  return app.exec();
+}
diff --git a/src/TreeData/Test/mainwindow.cxx b/src/TreeData/Test/mainwindow.cxx
new file mode 100644 (file)
index 0000000..3dcf758
--- /dev/null
@@ -0,0 +1,169 @@
+#include <QtGui>
+
+#include "mainwindow.hxx"
+#include "TreeModel.hxx"
+
+#include <Basics_Utils.hxx>
+#include "testhelper.hxx"
+
+MainWindow::MainWindow(QWidget *parent)
+    : QMainWindow(parent)
+{
+    setupUi(this);
+
+    QStringList headers;
+    headers << tr("Title") << tr("Description");
+
+    TreeModel *model = new TreeModel(headers);
+    TESTHELPER_loadDataFromFile(model, TESTHELPER_testfilename(DATAFILENAME));
+
+    view->setModel(model);
+    for (int column = 0; column < model->columnCount(); ++column)
+        view->resizeColumnToContents(column);
+
+    connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+
+    connect(view->selectionModel(),
+            SIGNAL(selectionChanged(const QItemSelection &,
+                                    const QItemSelection &)),
+            this, SLOT(updateActions()));
+
+    connect(actionsMenu, SIGNAL(aboutToShow()), this, SLOT(updateActions()));
+    connect(insertRowAction, SIGNAL(triggered()), this, SLOT(insertRow()));
+    connect(insertColumnAction, SIGNAL(triggered()), this, SLOT(insertColumn()));
+    connect(removeRowAction, SIGNAL(triggered()), this, SLOT(removeRow()));
+    connect(removeColumnAction, SIGNAL(triggered()), this, SLOT(removeColumn()));
+    connect(insertChildAction, SIGNAL(triggered()), this, SLOT(insertChild()));
+    connect(newDataAction, SIGNAL(triggered()), this, SLOT(newData()));
+
+    updateActions();
+}
+
+void MainWindow::newData() {
+  LOG("MainWindow::newData(): START");
+
+  bool ok;
+  QString text = QInputDialog::getText(this, tr("QInputDialog::getText()"),
+                                       tr("Data path:"), QLineEdit::Normal,
+                                       "folder/subfolder/item", &ok);
+  if (!ok || text.trimmed().isEmpty())
+    return;
+
+  QStringList path = text.trimmed().split("/");
+  TreeModel *model = (TreeModel *)view->model();
+
+  QString label = path.last();
+  path.removeLast();
+  DataObject * data = TESTHELPER_dummyObject(label);
+  model->addData(data,path);
+
+  LOG("MainWindow::newData(): END");
+}
+
+void MainWindow::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 MainWindow::insertColumn(const QModelIndex &parent)
+{
+    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 MainWindow::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 MainWindow::removeColumn(const QModelIndex &parent)
+{
+    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 MainWindow::removeRow()
+{
+    QModelIndex index = view->selectionModel()->currentIndex();
+    QAbstractItemModel *model = view->model();
+    if (model->removeRow(index.row(), index.parent()))
+        updateActions();
+}
+
+void MainWindow::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(tr("Position: (%1,%2)").arg(row).arg(column));
+        else
+            statusBar()->showMessage(tr("Position: (%1,%2) in top level").arg(row).arg(column));
+    }
+}
+
+void MainWindow::contextMenuEvent(QContextMenuEvent *event) {
+  QMenu menu(this);
+  menu.addAction(newDataAction);
+  menu.exec(event->globalPos());
+}
diff --git a/src/TreeData/Test/mainwindow.hxx b/src/TreeData/Test/mainwindow.hxx
new file mode 100644 (file)
index 0000000..323121a
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QMainWindow>
+#include <QModelIndex>
+
+#include "ui_mainwindow.h"
+
+class QAction;
+class QTreeView;
+class QWidget;
+
+class MainWindow : public QMainWindow, private Ui::MainWindow
+{
+    Q_OBJECT
+
+public:
+    MainWindow(QWidget *parent = 0);
+
+protected:
+  void contextMenuEvent(QContextMenuEvent *event);
+
+public slots:
+    void updateActions();
+
+private slots:
+    void insertChild();
+    bool insertColumn(const QModelIndex &parent = QModelIndex());
+    void insertRow();
+    bool removeColumn(const QModelIndex &parent = QModelIndex());
+    void removeRow();
+    void newData();
+};
+
+#endif
diff --git a/src/TreeData/Test/mainwindow.ui b/src/TreeData/Test/mainwindow.ui
new file mode 100644 (file)
index 0000000..a7cfe6b
--- /dev/null
@@ -0,0 +1,140 @@
+<ui version="4.0" >
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>573</width>
+    <height>468</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Editable Tree Model</string>
+  </property>
+  <widget class="QWidget" name="centralwidget" >
+   <layout class="QVBoxLayout" >
+    <property name="margin" >
+     <number>0</number>
+    </property>
+    <property name="spacing" >
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="QTreeView" name="view" >
+      <property name="alternatingRowColors" >
+       <bool>true</bool>
+      </property>
+      <property name="selectionBehavior" >
+       <enum>QAbstractItemView::SelectItems</enum>
+      </property>
+      <property name="horizontalScrollMode" >
+       <enum>QAbstractItemView::ScrollPerPixel</enum>
+      </property>
+      <property name="animated" >
+       <bool>false</bool>
+      </property>
+      <property name="allColumnsShowFocus" >
+       <bool>true</bool>
+      </property>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar" >
+   <property name="geometry" >
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>573</width>
+     <height>29</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="actionsMenu" >
+    <property name="title" >
+     <string>&amp;Actions</string>
+    </property>
+    <addaction name="insertRowAction" />
+    <addaction name="insertColumnAction" />
+    <addaction name="separator" />
+    <addaction name="removeRowAction" />
+    <addaction name="removeColumnAction" />
+    <addaction name="separator" />
+    <addaction name="insertChildAction" />
+   </widget>
+   <widget class="QMenu" name="fileMenu" >
+    <property name="title" >
+     <string>&amp;File</string>
+    </property>
+    <addaction name="exitAction" />
+   </widget>
+   <widget class="QMenu" name="menuData" >
+    <property name="title" >
+     <string>Data</string>
+    </property>
+    <addaction name="newDataAction" />
+   </widget>
+   <addaction name="fileMenu" />
+   <addaction name="actionsMenu" />
+   <addaction name="menuData" />
+  </widget>
+  <widget class="QStatusBar" name="statusbar" />
+  <action name="exitAction" >
+   <property name="text" >
+    <string>E&amp;xit</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+Q</string>
+   </property>
+  </action>
+  <action name="insertRowAction" >
+   <property name="text" >
+    <string>Insert Row</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+I, R</string>
+   </property>
+  </action>
+  <action name="removeRowAction" >
+   <property name="text" >
+    <string>Remove Row</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+R, R</string>
+   </property>
+  </action>
+  <action name="insertColumnAction" >
+   <property name="text" >
+    <string>Insert Column</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+I, C</string>
+   </property>
+  </action>
+  <action name="removeColumnAction" >
+   <property name="text" >
+    <string>Remove Column</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+R, C</string>
+   </property>
+  </action>
+  <action name="insertChildAction" >
+   <property name="text" >
+    <string>Insert Child</string>
+   </property>
+   <property name="shortcut" >
+    <string>Ctrl+N</string>
+   </property>
+  </action>
+  <action name="newDataAction" >
+   <property name="text" >
+    <string>new</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="editabletreemodel.qrc" />
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/TreeData/Test/tester.cxx b/src/TreeData/Test/tester.cxx
new file mode 100644 (file)
index 0000000..413c672
--- /dev/null
@@ -0,0 +1,60 @@
+#include "QtHelper.hxx"
+
+//
+// =================================================================
+// Helper functions for DataObject and DataModel classes
+// =================================================================
+//
+
+// ----
+// A DataObject can't be used as is but must be specialized to
+// specify the behavior in the hierarchic model.
+#include "MyDataModel.hxx"
+
+void TEST_DataObject() {
+  // In this test, the object id should increase at each instance
+  DataObject * dataObject;
+  for (int i=0; i<100; i++) {
+    dataObject = new MyDataObject();
+    QLOG("object nameId = " << dataObject->getNameId().c_str());
+  }
+  QLOG("path     = " << dataObject->getPath().c_str());
+  QLOG("pathname = " << dataObject->getPathName().c_str());
+
+  QLOG("serialize= " << dataObject->toString().c_str());
+
+}
+
+void TEST_DataModel() {
+  MyDataModel * dataModel = new MyDataModel();
+
+  int refIter = 53;
+  string refNameId;
+
+  DataObject * dataObject;
+  for (int i=0; i<100; i++) {
+    // We can either create the data object using its constructor or
+    // using the factory of the model (the prefered way):
+    // dataObject = new MyDataObject();
+    dataObject = dataModel->newDataObject();
+    dataObject->setLabel("myobject"+ToString(i));
+    if ( i == refIter ) {
+      refNameId = dataObject->getNameId();
+    }
+    dataModel->addDataObject(dataObject);
+  }
+
+  dataObject = dataModel->getDataObject(refNameId);
+  QLOG("object nameId = " << dataObject->getNameId().c_str());
+  QLOG("path     = " << dataObject->getPath().c_str());
+  QLOG("pathname = " << dataObject->getPathName().c_str());
+}
+
+//
+// =================================================================
+//
+int main(int argc, char * argv[ ])
+{
+  TEST_DataObject();
+  //TEST_DataModel();
+}
diff --git a/src/TreeData/Test/testhelper.cxx b/src/TreeData/Test/testhelper.cxx
new file mode 100644 (file)
index 0000000..1b37c02
--- /dev/null
@@ -0,0 +1,76 @@
+
+
+#include "testhelper.hxx"
+
+#include <QFile>
+#include <QString>
+
+#include "QtHelper.hxx"
+#include "MyDataModel.hxx"
+
+// Standard C include (for getenv)
+#include <stdlib.h>
+
+QString TESTHELPER_testfilename(const char * basefilename) {
+  QString aFile;
+  char * GUI_ROOT_DIR = getenv("GUI_ROOT_DIR");
+  QString * root;
+  if ( GUI_ROOT_DIR != NULL ) {
+    root = new QString(GUI_ROOT_DIR);
+  }
+  else {
+    root = new QString("/home/gboulant/development/projets/salome/devel/XSALOME/install");
+  }
+  QString relativePathName = "/share/salome/resources/gui/testdata/";
+  aFile.append(*root + relativePathName + basefilename);
+
+  QLOG("The test file is : "<<aFile);
+  return aFile;
+}
+
+/*!
+ * This creates a dummy data object for the needs of the test
+ * functions. The label is the basename of the spécified pathname.
+ */
+DataObject * TESTHELPER_dummyObject(QString label) {
+  MyDataObject * dataObject = new MyDataObject();
+  dataObject->setLabel(QCHARSTAR(label));
+  return dataObject;
+}
+
+
+#define SEP ";"
+/*!
+ * This test function shows how it's possible to load data from a file
+ * to populate the tree model.
+ */
+void TESTHELPER_loadDataFromFile(TreeModel * dataTreeModel, const QString &filename) {
+  QFile file ( filename );
+  file.open ( QIODevice::ReadOnly );
+  
+  MyDataObject * dataObject;
+  while ( 1 ) {
+    QByteArray byteArray = file.readLine();
+
+    if ( byteArray.isEmpty() )
+      break;
+    
+    QString data = (QString ( byteArray.mid(0, byteArray.size()-1))).trimmed();
+    QStringList dataList = data.split ( SEP );
+    // The data list is used here to set properties (and then the path
+    // of location in the tree model).
+
+    dataObject = new MyDataObject();
+    // The label is autogenerated, but we may specify here a custom
+    // one. We just fill the properties with data values read in the
+    // file.
+    dataObject->setProperty(MyDataObject::PROPERTY_KEY_TYPE,    QCHARSTAR(dataList[0]));
+    dataObject->setProperty(MyDataObject::PROPERTY_KEY_REPFONC, QCHARSTAR(dataList[1]));
+    dataObject->setProperty(MyDataObject::PROPERTY_KEY_CIRCUIT, QCHARSTAR(dataList[2]));
+    if ( ! dataTreeModel->addData(dataObject) ) {
+      QLOG("ERR: data not added");
+    }
+  }
+
+  file.close();
+}
diff --git a/src/TreeData/Test/testhelper.hxx b/src/TreeData/Test/testhelper.hxx
new file mode 100644 (file)
index 0000000..53faa46
--- /dev/null
@@ -0,0 +1,15 @@
+
+#ifndef _TESTHELPER_HXX_
+#define _TESTHELPER_HXX_
+
+#include <QString>
+#include "TreeModel.hxx"
+#include "DataObject.hxx"
+
+#define DATAFILENAME "data.txt"
+
+QString      TESTHELPER_testfilename(const char * basefilename);
+DataObject * TESTHELPER_dummyObject(QString label);
+void         TESTHELPER_loadDataFromFile(TreeModel * dataTreeModel, const QString &filename);
+
+#endif // _TESTHELPER_HXX_