view gui/src/WorkspaceModel.cpp @ 14664:664f54233c98 gui

Extracted model code from the WorkspaceView and rearranged it in a new model class. * WorkspaceModel.cpp/.h (new class): Model class for the workspace. * WorkspaceView.cpp/.h: Replaced QTreeWidget with QTreeView and removed model code. * OctaveLink.cpp/.h: Removed symbol table semaphore and methods to access the copy of the symbol table, removed copying the symbol table. * src.pro: Added new files to Qt project.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Sun, 20 May 2012 22:05:49 +0200
parents
children 6a6733a55982
line wrap: on
line source

/* OctaveGUI - A graphical user interface for Octave
 * Copyright (C) 2011 Jacob Dawid (jacob.dawid@googlemail.com)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#include "WorkspaceModel.h"
#include <QTreeWidget>

WorkspaceModel::WorkspaceModel(QObject *parent)
  : QAbstractItemModel(parent)
{
  QList<QVariant> rootData;
  rootData << tr ("Name") << tr ("Type") << tr ("Value");
  _rootItem = new TreeItem(rootData);
}

WorkspaceModel::~WorkspaceModel()
{
  delete _rootItem;
}

QModelIndex
WorkspaceModel::index(int row, int column, const QModelIndex &parent) const
{
  if (!hasIndex(row, column, parent))
    return QModelIndex();

  TreeItem *parentItem;

  if (!parent.isValid())
    parentItem = _rootItem;
  else
    parentItem = static_cast<TreeItem*>(parent.internalPointer());

  TreeItem *childItem = parentItem->child(row);
  if (childItem)
    return createIndex(row, column, childItem);
  else
    return QModelIndex();
}

QModelIndex
WorkspaceModel::parent(const QModelIndex &index) const
{
  if (!index.isValid())
    return QModelIndex();

  TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());
  TreeItem *parentItem = childItem->parent();

  if (parentItem == _rootItem)
    return QModelIndex();

  return createIndex(parentItem->row(), 0, parentItem);
}

int
WorkspaceModel::rowCount(const QModelIndex &parent) const
{
  TreeItem *parentItem;
  if (parent.column() > 0)
    return 0;

  if (!parent.isValid())
    parentItem = _rootItem;
  else
    parentItem = static_cast<TreeItem*>(parent.internalPointer());

  return parentItem->childCount();
}

int
WorkspaceModel::columnCount(const QModelIndex &parent) const
{
  if (parent.isValid())
    return static_cast<TreeItem*>(parent.internalPointer())->columnCount();
  else
    return _rootItem->columnCount();
}

void
WorkspaceModel::insertTopLevelItem(int at, TreeItem *treeItem)
{
  _rootItem->insertChildItem(at, treeItem);
}

TreeItem *
WorkspaceModel::topLevelItem (int at)
{
  return _rootItem->child(at);
}

Qt::ItemFlags
WorkspaceModel::flags(const QModelIndex &index) const
{
  if (!index.isValid())
    return 0;

  return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
}

QVariant
WorkspaceModel::headerData(int section, Qt::Orientation orientation, int role) const
{
  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
    return _rootItem->data(section);

  return QVariant();
}

QVariant
WorkspaceModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid())
    return QVariant();

  if (role != Qt::DisplayRole)
    return QVariant();

  TreeItem *item = static_cast<TreeItem*>(index.internalPointer());

  return item->data(index.column());
}

void
WorkspaceModel::updateTreeEntry (TreeItem * treeItem, symbol_table::symbol_record symbolRecord)
{
  treeItem->setData (0, QString (symbolRecord.name ().c_str ()));
  treeItem->setData (1, QString (symbolRecord.varval ().type_name ().c_str ()));
  treeItem->setData (2, octaveValueAsQString (symbolRecord.varval ()));
  emit dataChanged(index(treeItem->row(), 0), index(treeItem->row(), 2));
}

void
WorkspaceModel::updateFromSymbolTable ()
{
  std::list < symbol_table::symbol_record > allVariables = symbol_table::all_variables ();

  // Split the symbol table into its different categories.
  QList < symbol_table::symbol_record > localSymbolTable;
  QList < symbol_table::symbol_record > globalSymbolTable;
  QList < symbol_table::symbol_record > persistentSymbolTable;
  QList < symbol_table::symbol_record > hiddenSymbolTable;

  for (std::list < symbol_table::symbol_record > ::iterator iterator = allVariables.begin ();
       iterator != allVariables.end (); iterator++)
    {
      // It's true that being global or hidden includes it's can mean it's also locally visible,
      // but we want to distinguish that here.
      if (iterator->is_local () && !iterator->is_global () && !iterator->is_hidden ())
        {
          localSymbolTable.append (iterator->dup (symbol_table::global_scope ()));
        }

      if (iterator->is_global ())
        {
          globalSymbolTable.append (iterator->dup (symbol_table::global_scope ()));
        }

      if (iterator->is_persistent ())
        {
          persistentSymbolTable.append (iterator->dup (symbol_table::global_scope ()));
        }

      if (iterator->is_hidden ())
        {
          hiddenSymbolTable.append (iterator->dup (symbol_table::global_scope ()));
        }
    }

  updateCategory (0, localSymbolTable);
  updateCategory (1, globalSymbolTable);
  updateCategory (2, persistentSymbolTable);
  updateCategory (3, hiddenSymbolTable);
}

void
WorkspaceModel::updateCategory (int topLevelItemIndex, QList < symbol_table::symbol_record > symbolTable)
{
  // This method may be a little bit confusing; variablesList is a complete list of all
  // variables that are in the workspace currently.
  TreeItem *treeItem = topLevelItem (topLevelItemIndex);

  // First we check, if any variables that exist in the model tree have to be updated
  // or created. So we walk the variablesList check against the tree.
  foreach (symbol_table::symbol_record symbolRecord, symbolTable)
    {
      int childCount = treeItem->childCount ();
      bool alreadyExists = false;
      TreeItem *child;

      // Search for the corresponding item in the tree. If it has been found, child
      // will contain the appropriate QTreeWidgetItem* pointing at it.
      for (int i = 0; i < childCount; i++)
        {
          child = treeItem->child (i);
          if (child->data (0).toString () ==
              QString (symbolRecord.name ().c_str ()))
            {
              alreadyExists = true;
              break;
            }
        }

      // If it already exists, just update it.
      if (alreadyExists)
        {
          updateTreeEntry (child, symbolRecord);
        }
      else
        {
          // It does not exist, so create a new one and set the right values.
          child = new TreeItem ();
          updateTreeEntry (child, symbolRecord);
          treeItem->addChild (child);
        }
    }

  // Check the tree against the list for deleted variables.
  for (int i = 0; i < treeItem->childCount (); i++)
    {
      bool existsInVariableList = false;
      TreeItem *child = treeItem->child (i);
      foreach (symbol_table::symbol_record symbolRecord, symbolTable)
        {
          if (QString (symbolRecord.name ().c_str ()) ==
              child->data (0).toString ())
            {
              existsInVariableList = true;
            }
        }

      if (!existsInVariableList)
        {
          treeItem->removeChild (child);
          delete child;
          i--;
        }
    }
}

QString
WorkspaceModel::octaveValueAsQString (octave_value octaveValue)
{
  // Convert single qouted string.
  if (octaveValue.is_sq_string ())
    {
      return QString ("\'%1\'").arg (octaveValue.string_value ().c_str ());

      // Convert double qouted string.
    }
  else if (octaveValue.is_dq_string ())
    {
      return QString ("\"%1\"").arg (octaveValue.string_value ().c_str ());

      // Convert real scalar.
    }
  else if (octaveValue.is_real_scalar ())
    {
      return QString ("%1").arg (octaveValue.scalar_value ());

      // Convert complex scalar.
    }
  else if (octaveValue.is_complex_scalar ())
    {
      return QString ("%1 + %2i").arg (octaveValue.scalar_value ()).
          arg (octaveValue.complex_value ().imag ());

      // Convert range.
    }
  else if (octaveValue.is_range ())
    {
      return QString ("%1 : %2 : %3").arg (octaveValue.range_value ().
                                           base ()).arg (octaveValue.
                                                         range_value ().
                                                         inc ()).
          arg (octaveValue.range_value ().limit ());

      // Convert real matrix.
    }
  else if (octaveValue.is_real_matrix ())
    {
      return QString ("%1x%2 matrix")
          .arg (octaveValue.matrix_value ().rows ())
          .arg (octaveValue.matrix_value ().cols ());

      // Convert complex matrix.
    }
  else if (octaveValue.is_complex_matrix ())
    {
      return QString ("%1x%2 complex matrix")
          .arg (octaveValue.matrix_value ().rows ())
          .arg (octaveValue.matrix_value ().cols ());

      // If everything else does not fit, we could not recognize the type.
    }
  else
    {
      return QString ("<Type not recognized>");
    }
}