diff libgui/graphics/Table.cc @ 26112:36e0e5b428e7

Implement uitable (patch #9084) * libgui/graphics/Table.[cc/h]: Add QT toolkit Table object. * libgui/graphics/module.mk: Add new files. * libgui/graphics/Backend.cc (toolkitObjectProperty, Backend::initialize, Backend::update): Add uitable. * libgui/graphics/Canvas.cc (Canvas::select_object): Allow uitable to be selected like uicontrol or uipanel. * libgui/graphics/ObjectFactory.cc (ObjectFactory::createObject): Add uitable. * libgui/graphics/QtHandlesUtils.cc (computeFont<uibuttongroup>): Make computeFont template for uitable. * libinterp/corefcn/gl-render.cc (opengl_renderer::draw): Add uitable. * libinterp/corefcn/graphics.cc (default_table_position, default_table_backgroundcolor): Add new static default values. * libinterp/corefcn/graphics.cc (lookup_object_name, make_graphics_object_from_type, property_list::set, property_list::lookup): Add uipanel. * libinterp/corefcn/graphics.cc (uitable::properties::get_boundingbox, uitable::properties::set_columnformat, uitable::properties::set_columnwidth, uitable::properties::set_units, uitable::properties::update_units, uitable::properties::set_fontunits, uitable::properties::update_fontunits, uitable::properties::get___fontsize_points__, uitable::properties::get_fontsize_pixels, uitable::properties::get_backgroundcolor_rgb, uitable::properties::get_alternatebackgroundcolor_rgb, uitable::properties::get_extent_matrix, uitable::properties::get_extent, uitable::properties::set_selectedobject, F__go_uitable__): Add new functions. * libinterp/corefcn/graphics.in.h: Add uitable. * scripts/gui/uitable.m: Add new file. * scripts/gui/module.mk: Add new file to list. * scripts/help/__unimplemented__.m: Remove uitable from missing_functions. * doc/interpreter/genpropdoc.m, doc/interpreter/gui.txi, doc/interpreter/module.mk, doc/interpreter/plot.txi: Add documentation for uitable. * NEWS: Add to list of new functions.
author Andrew Thornton <art27@cantab.net>
date Tue, 20 Dec 2016 03:25:17 +0000
parents
children 4d1c6c60f6b3
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/graphics/Table.cc	Tue Dec 20 03:25:17 2016 +0000
@@ -0,0 +1,1692 @@
+/*
+
+Copyright (C) 2016 Andrew Thornton
+
+This file is part of Octave.
+
+Octave 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.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QEvent>
+#include <QFrame>
+#include <QLabel>
+#include <QMouseEvent>
+#include <QTimer>
+
+#include <QCheckBox>
+#include <QComboBox>
+#include <QHeaderView>
+#include <QLineEdit>
+#include <QModelIndexList>
+#include <QString>
+#include <QStringList>
+#include <QTableWidget>
+#include <QTableWidgetItem>
+#include <QHBoxLayout>
+
+#include "Container.h"
+#include "ContextMenu.h"
+#include "Table.h"
+#include "QtHandlesUtils.h"
+
+#include "oct-stream.h"
+#include "oct-string.h"
+#include "oct-strstrm.h"
+#include "ov-struct.h"
+
+namespace QtHandles
+{
+
+  static const int AUTO_WIDTH = 75;
+
+#define AUTO_HEIGHT \
+  tp.get_fontsize () * 2 - 1
+
+  static QSize realQSizeForTable(QTableWidget *t)
+  {
+    int w = t->verticalHeader ()->width () + 4;
+    for (int i = 0; i < t->columnCount (); i++)
+      w += t->columnWidth (i);
+    int h = t->horizontalHeader ()->height () + 4;
+    for (int i = 0; i < t->rowCount (); i++)
+      h += t->rowHeight (i);
+    return QSize(w, h);
+  }
+
+#define FORMATNUMBER(type)                                                    \
+  static QString formatNumber (type d,                                        \
+                               char format = 'f',                             \
+                               int precision = 4)                             \
+  {                                                                           \
+    if (format == 'n')                                                        \
+      {                                                                       \
+        if (d == floor (d))                                                   \
+          return QString::number(d, 'g', precision);                          \
+        else if (d <= pow (10, precision - 1) && d > pow (10, 1 - precision)) \
+          return QString::number(d, 'f', precision);                          \
+        else                                                                  \
+          return QString::number(d, 'e', precision);                          \
+      }                                                                       \
+    else if (format == 'F')                                                   \
+      {                                                                       \
+        int exponent = floor (log10 (d) / 3) * 3;                             \
+        d *=  pow (10, -exponent);                                            \
+        return QString::number(d, 'f', precision) + "e" +                     \
+          (exponent < 0 ? "-" : "+") +                                        \
+          QString("%1").arg(abs (exponent), 3, 10, QChar('0'));               \
+      }                                                                       \
+    else if (format == 'E')                                                   \
+      {                                                                       \
+        int exponent = floor (log10 (d) / 3) * 3;                             \
+        d *=  pow (10, -exponent);                                            \
+        return QString::number(d,                                             \
+                               'f',                                           \
+                               precision - floor (log10 (d)) - 1) +           \
+               "e" + (exponent < 0 ? "-" : "+") +                             \
+               QString("%1").arg(abs (exponent), 3, 10, QChar('0'));          \
+      }                                                                       \
+    else                                                                      \
+      return QString::number(d, format, precision);                           \
+  }
+
+  FORMATNUMBER(double)
+  FORMATNUMBER(float)
+
+#undef FORMATNUMBER
+
+  static QString formatComplex (Complex c, char format = 'f', int precision = 4)
+  {
+    return formatNumber(c.real(), format, precision) +
+      " + " + formatNumber(c.imag (), format, precision) + "i";
+  }
+
+#define FORMAT_VALUE_EXCEPT_RAT(f,l)                      \
+  if (format == "numeric" || format == "short")           \
+    text = formatNumber(value, 'n', f);                   \
+  else if (format == "short f" || format == "shortf")     \
+    text = formatNumber(value, 'f', f);                   \
+  else if (format == "short e" || format == "shorte")     \
+    text = formatNumber(value, 'e', f);                   \
+  else if (format == "short eng" || format == "shorteng") \
+    text = formatNumber(value, 'F', f);                   \
+  else if (format == "short g" || format == "shortg")     \
+    text = formatNumber(value, 'g', f + 1);               \
+  else if (format == "long")                              \
+    text = formatNumber(value, 'n', l);                   \
+  else if (format == "long f" || format == "longf")       \
+    text = formatNumber(value, 'f', l);                   \
+  else if (format == "long e" || format == "longe")       \
+    text = formatNumber(value, 'e', l);                   \
+  else if (format == "long eng" || format == "longeng")   \
+    text = formatNumber(value, 'E', l);                   \
+  else if (format == "long g" || format == "longg")       \
+    text = formatNumber(value, 'g', l + 1);               \
+  else if (format == "bank")                              \
+    text = QString::number(value, 'f', 2);                \
+  else if (format == "+")                                 \
+    if (value > 0)                                        \
+      text = Utils::fromStdString("+");                   \
+    else if (value < 0)                                   \
+      text = Utils::fromStdString("-");                   \
+    else                                                  \
+      text = Utils::fromStdString("");
+
+#define FORMAT_VALUE(f,l)                                            \
+  FORMAT_VALUE_EXCEPT_RAT(f,l)                                       \
+  else if (format == "rat")                                          \
+    text = Utils::fromStdString(rational_approx(double (value), 0)); \
+  else                                                               \
+    {                                                                \
+      text = formatNumber (value, 'n', f);                           \
+      flag = Qt::AlignLeft ;                                         \
+    }
+
+#define FORMAT_UINT_VALUE()                   \
+  text = QString::number(value);              \
+  if (format == "char"  || format == "popup") \
+    flag = Qt::AlignLeft;                     \
+  else if (format == "+")                     \
+    {                                         \
+      if (value > 0)                          \
+        text = Utils::fromStdString("+");     \
+      else                                    \
+        text = Utils::fromStdString("");      \
+    }
+
+#define FORMAT_INT_VALUE()                    \
+  text = QString::number(value);              \
+  if (format == "char" || format == "popup")  \
+    flag = Qt::AlignLeft ;                    \
+  else if (format == "+")                     \
+    {                                         \
+      if (value > 0)                          \
+        text = Utils::fromStdString("+");     \
+      else if (value < 0)                     \
+        text = Utils::fromStdString("-");     \
+      else                                    \
+        text = Utils::fromStdString("");      \
+    }
+
+  static std::pair <Qt::AlignmentFlag, QString> qStringValueFor (
+    octave_value val, std::string format = "")
+  {
+    Qt::AlignmentFlag flag = Qt::AlignRight;
+    QString text;
+    if (val.is_string ())
+      {
+        text = QtHandles::Utils::fromStdString (val.string_value ());
+        flag = Qt::AlignLeft ;
+      }
+    else if (val.iscomplex ())
+      {
+        // Matlab has mulitple complex types we only have double.
+        Complex c = val.complex_value ();
+        if (format == "short")
+          text = formatComplex(c, 'f', 4);
+        else if (format == "short e" || format == "shorte")
+          text = formatComplex(c, 'e', 4);
+        else if (format == "short eng" || format == "shorteng")
+          text = formatComplex(c, 'E', 4);
+        else if (format == "short g" || format == "shortg")
+          text = formatComplex(c, 'g', 5);
+        else if (format == "long")
+          text = formatComplex(c, 'f', 15);
+        else if (format == "long e" || format == "longe")
+          text = formatComplex(c, 'e', 15);
+        else if (format == "long eng" || format == "longeng")
+          text = formatComplex(c, 'E', 15);
+        else if (format == "long g" || format == "longg")
+          text = formatComplex(c, 'g', 16);
+        else if (format == "bank")
+          text = QString::number(c.real (), 'f', 2);
+        else if (format == "+")
+          {
+            if (c.real () > 0)
+              text = Utils::fromStdString("+");
+            else if (c.real () < 0)
+              text = Utils::fromStdString("-");
+            else
+              text = Utils::fromStdString("");
+          }
+        else if (format == "rat")
+          text = Utils::fromStdString(rational_approx(c.real (), 0)) + " + " +
+            Utils::fromStdString(rational_approx(c.imag (), 0)) + "i";
+        else if (format == "numeric")
+          text = QString::number (c.real (), 'g', 5) + " + "
+            + QString::number (c.imag (), 'g', 5) + "i";
+        else
+          {
+            text = QString::number (c.real (), 'g', 5) + " + "
+              + QString::number (c.imag (), 'g', 5) + "i";
+            flag = Qt::AlignLeft ;
+          }
+      }
+    else if (val.is_double_type () )
+      {
+        double value = val.double_value ();
+        FORMAT_VALUE(4, 15)
+      }
+    else if (val.is_single_type ())
+      {
+        float value = val.float_value ();
+        FORMAT_VALUE(4, 7)
+      }
+    else if (val.is_int8_type ())
+      {
+        short int value = val.short_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint8_type ())
+      {
+        unsigned short int value = val.ushort_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.is_int16_type ())
+      {
+        int value = val.int_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint16_type ())
+      {
+        unsigned int value = val.uint_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.is_int32_type ())
+      {
+        long int value = val.long_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint32_type ())
+      {
+        unsigned long int value = val.ulong_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.is_int64_type ())
+      {
+        int64_t value = val.int64_value ();
+        FORMAT_INT_VALUE()
+      }
+    else if (val.is_uint64_type ())
+      {
+        uint64_t value = val.uint64_value ();
+        FORMAT_UINT_VALUE()
+      }
+    else if (val.islogical ())
+      {
+        bool b = val.bool_value ();
+        if (format == "char" || format == "popup" || format == "")
+          {
+            text = Utils::fromStdString(b ? "true" : "false");
+            flag = Qt::AlignLeft ;
+          }
+        else if (format == "+")
+          {
+            text = Utils::fromStdString(b ? "+" : "");
+            flag = Qt::AlignLeft ;
+          }
+        else
+          text = Utils::fromStdString(b ? "1" : "0");
+      }
+    else
+      {
+        std::stringstream warn_string;
+        warn_string << "Unknown conversion for datatype " << val.class_name ()
+          << " to " << format << " for value " << val.string_value (true);
+        warning (warn_string.str().c_str());
+
+        text = Utils::fromStdString(val.string_value (true));
+      }
+
+    return std::make_pair(flag, text);
+  }
+
+#undef FORMAT_VALUE
+#undef FORMAT_VALUE_EXCEPT_RAT
+#undef FORMAT_UINT_VALUE
+#undef FORMAT_INT_VALUE
+
+  static QTableWidgetItem * itemFor(octave_value val, std::string format = "",
+                                    bool enabled = false)
+  {
+    QTableWidgetItem* retval  = new QTableWidgetItem ();
+    std::pair <Qt::AlignmentFlag, QString> flag_and_text = qStringValueFor(val, format);
+    retval->setTextAlignment (flag_and_text.first);
+    retval->setText (flag_and_text.second);
+
+    if (enabled)
+      retval->setFlags (retval->flags ()  | Qt::ItemIsEditable);
+    else
+      retval->setFlags (retval->flags ()  & ~Qt::ItemIsEditable);
+
+    return retval;
+  }
+
+  static octave_value
+  attempt_type_conversion (const octave_value& ov, const octave_value& old_value)
+  {
+    octave_value retval;
+
+    // Define a macro to help with the conversion of strings to integers
+    // FIXME: these will happily integer overflow in the (u)int64 case
+    // - this probably doesn't matter.
+#define SCANF_AND_CONVERT(name,ctype,format)           \
+  else if (old_value.is_ ## name ## _type ())          \
+    {                                                  \
+      ctype val;                                       \
+      int n;                                           \
+      const char* c_str = ov.string_value ().c_str (); \
+      int error = sscanf (c_str, format, &val, &n);    \
+      if (error != 1 || c_str[n])                      \
+        {                                              \
+          val = 0;                                     \
+        }                                              \
+      retval = octave_value ( octave_ ## name (val));  \
+    }
+
+    if (old_value.is_string ())
+      retval = ov;
+    SCANF_AND_CONVERT(int8, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint8, uint64_t, "%ju %n")
+    SCANF_AND_CONVERT(int16, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint16, uint64_t, "%ju %n")
+    SCANF_AND_CONVERT(int32, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint32, uint64_t, "%ju %n")
+    SCANF_AND_CONVERT(int64, int64_t, "%jd %n")
+    SCANF_AND_CONVERT(uint64, uint64_t, "%ju %n")
+
+  #undef SCANF_AND_CONVERT
+
+    else if (old_value.isnumeric () && !old_value.isinteger ())
+      {
+        // Basically need to do str2double
+        Complex complex = octave_str2double (ov.string_value ());
+        if (old_value.is_single_type ())
+          retval = octave_value (FloatComplex (complex));
+        else
+          retval = octave_value (complex);
+      }
+    else if (old_value.islogical ())
+      {
+        // Right: Matlab basically needs this to be true or false, we should
+        // accept 1 too.
+        if (ov.string_value ()  == "true" || ov.string_value () == "1")
+          retval = octave_value (true);
+        else
+          retval = octave_value (false);
+      }
+    else
+      retval = octave_value (octave_str2double (ov.string_value ()));
+    return retval;
+  }
+
+  QWidget *
+  Table::checkBoxForLogical (octave_value val, bool enabled = false)
+  {
+    QWidget *retval = new QWidget(m_tableWidget);
+    QCheckBox *checkBox = new QCheckBox();
+    QHBoxLayout *layout = new QHBoxLayout(retval);
+    layout->addWidget (checkBox);
+    layout->setAlignment (Qt::AlignCenter);
+    layout->setContentsMargins (0, 0, 0, 0);
+    retval->setLayout (layout);
+
+    if ((val.islogical () || val.is_bool_scalar ()) && val.bool_value ())
+      checkBox->setCheckState (Qt::Checked);
+    else
+      checkBox->setCheckState (Qt::Unchecked);
+
+    checkBox->setAttribute (Qt::WA_TransparentForMouseEvents, true);
+    checkBox->setFocusPolicy (Qt::NoFocus);
+    checkBox->setProperty ("Enabled", QVariant (enabled));
+
+    return retval;
+  }
+
+  Table*
+  Table::create (const graphics_object& go)
+  {
+    Object* parent = Object::parentObject (go);
+
+    if (parent)
+      {
+        Container* container = parent->innerContainer ();
+
+        if (container)
+          return new Table (go, new QTableWidget (container));
+      }
+
+      return 0;
+  }
+
+  Table::Table (const graphics_object& go, QTableWidget* tableWidget)
+    : Object (go, tableWidget), m_tableWidget(tableWidget), m_curData(),
+      m_blockUpdates(false)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    m_curData = octave_value(tp.get_data ());
+    Matrix bb = tp.get_boundingbox (false);
+    m_tableWidget->setObjectName ("UITable");
+    m_tableWidget->setAutoFillBackground (true);
+    m_tableWidget->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
+                    octave::math::round (bb(2)), octave::math::round (bb(3)));
+    m_tableWidget->setFont (Utils::computeFont<uitable> (tp)) ;
+    m_tableWidget->setSelectionBehavior (QAbstractItemView::SelectItems);
+    updatePalette ();
+    m_keyPressHandlerDefined = ! tp.get_keypressfcn ().isempty ();
+    m_keyReleaseHandlerDefined = ! tp.get_keyreleasefcn ().isempty ();
+    updateData ();
+    updateRowname ();
+    updateColumnname ();
+    updateColumnwidth();
+    updateEnable(); // Also does rearrangeableColumns
+    m_tableWidget->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
+    m_tableWidget->setVisible (tp.is_visible ());
+    updateExtent ();
+    m_tableWidget->installEventFilter (this);
+
+
+    connect (m_tableWidget, SIGNAL (itemChanged (QTableWidgetItem*)),
+             SLOT (itemChanged (QTableWidgetItem*)));
+    connect (m_tableWidget, SIGNAL (cellClicked (int, int)),
+             SLOT (cellClicked (int, int)));
+    connect (m_tableWidget, SIGNAL (itemSelectionChanged (void)),
+             SLOT (itemSelectionChanged (void)));
+  }
+
+  Table::~Table (void)
+  {
+  }
+
+  void
+  Table::itemSelectionChanged ()
+  {
+    if (!(properties<uitable> ().get_cellselectioncallback ().isempty ()))
+      {
+        QModelIndexList modelIndexList = m_tableWidget->selectionModel()->selectedIndexes ();
+        int length = modelIndexList.size();
+        Matrix indices = Matrix (length, 2);
+        for (int i = 0; i < length; i++)
+          {
+            indices (i, 0) = modelIndexList.value (i).row () + 1;
+            indices (i, 1) = modelIndexList.value (i).column () + 1;
+          }
+        octave_scalar_map eventData;
+        eventData.setfield ("Indices", indices);
+        octave_value cellSelectionCallbackEventObject =
+          octave_value (new octave_struct (eventData));
+        gh_manager::post_callback(m_handle,
+                                  "cellselectioncallback",
+                                  cellSelectionCallbackEventObject);
+      }
+  }
+
+  void
+  Table::cellClicked (int row, int col)
+  {
+    QCheckBox* checkBox = NULL;
+    QWidget* widget = qobject_cast<QWidget*> (
+      m_tableWidget->cellWidget (row, col));
+    if (widget && !widget->children ().isEmpty ())
+      {
+        QHBoxLayout* layout = qobject_cast<QHBoxLayout*> (
+          widget->children ().first ());
+        if (layout && layout->count () > 0)
+          {
+            checkBox = qobject_cast<QCheckBox*> (
+              layout->itemAt (0)-> widget ());
+          }
+      }
+    if (checkBox && checkBox->property ("Enabled").toBool())
+      checkBoxClicked(row, col, checkBox);
+  }
+
+  void
+  Table::sendCellEditCallback (int row,
+    int col,
+    octave_value old_value,
+    octave_value new_value,
+    octave_value edit_data,
+    octave_value error)
+  {
+
+    if (!(properties<uitable> ().get_celleditcallback ().isempty ()))
+      {
+        Matrix indices = Matrix (1, 2);
+        indices (0, 0) = row + 1;
+        indices (0, 1) = col + 1;
+
+        octave_scalar_map eventData;
+        eventData.setfield ("Indices", indices);
+        eventData.setfield ("PreviousData", old_value);
+        eventData.setfield ("NewData", new_value);
+        eventData.setfield ("EditData", edit_data);
+        eventData.setfield ("Error", error);
+
+        octave_value cellEditCallbackEventObject =
+          octave_value (new octave_struct (eventData));
+
+        gh_manager::post_callback (m_handle,
+                                   "celleditcallback",
+                                   cellEditCallbackEventObject);
+      }
+    else if (error.string_value ().length () > 0)
+      warning (error.string_value ().c_str ());
+  }
+
+  void
+  Table::comboBoxCurrentIndexChanged (const QString& value)
+  {
+    if (m_blockUpdates)
+      return;
+    m_blockUpdates = true;
+    gh_manager::auto_lock lock;
+    octave_value data = octave_value(m_curData);
+    bool ok = false;
+
+    QComboBox* comboBox = qobject_cast<QComboBox*> (sender());
+    int row = comboBox->property ("row").toInt ();
+    int col = comboBox->property ("col").toInt ();
+
+    octave_value edit_data = octave_value(Utils::toStdString(value));
+
+    if (row < data.rows () && col < data.columns ())
+      {
+        if (data.iscell ())
+          {
+            Cell cell = data.cell_value ();
+            octave_value old_data = cell (row, col);
+            if (cell (row, col).is_string ())
+              {
+                cell (row, col) = edit_data;
+                if (edit_data.string_value () != old_data.string_value ())
+                  {
+                    m_curData = octave_value(cell);
+                    gh_manager::post_set (m_handle,
+                                          "data",
+                                          octave_value (cell),
+                                          false);
+                  }
+
+                octave_value error = octave_value("");
+                sendCellEditCallback(row,
+                  col,
+                  old_data,
+                  edit_data,
+                  edit_data,
+                  error);
+                ok = true;
+              }
+            else
+              {
+                cell (row, col) = attempt_type_conversion(edit_data, old_data);
+
+                // Inform the QTableWidget of our change
+                updateData(row, col, cell (row, col), columnformat (col), columneditable (col));
+
+                m_curData = octave_value(cell);
+                gh_manager::post_set (m_handle, "data", octave_value (cell), false);
+
+                octave_value error = octave_value("");
+                sendCellEditCallback(row,
+                  col,
+                  old_data,
+                  cell (row, col),
+                  edit_data,
+                  error);
+                ok = true;
+              }
+          }
+        else
+          {
+            octave_value old_data = data.is_matrix_type ()
+              ? data.fast_elem_extract(row + col * data.rows())
+              : octave_value ();
+            data.fast_elem_insert (row + col * data.rows(),
+                                   attempt_type_conversion(edit_data, old_data));
+
+            // Inform the QTableWidget of our change
+            updateData(row,
+                       col,
+                       data.fast_elem_extract (row + col * data.rows ()),
+                       columnformat (col),
+                       columneditable (col));
+
+            m_curData = octave_value(data);
+            gh_manager::post_set (m_handle, "data", data, false);
+
+            octave_value error = octave_value("");
+            sendCellEditCallback(row,
+              col,
+              old_data,
+              data.fast_elem_extract(row + col * data.rows()),
+              edit_data,
+              error);
+            ok = true;
+          }
+      }
+    else
+      {
+        // Reset the QTableWidgetItem
+        updateData(row, col, octave_value (""), columnformat (col), columneditable (col));
+
+        octave_value error = octave_value("Table data is not editable at this location.");
+        sendCellEditCallback(row,
+          col,
+          octave_value(),
+          octave_value(),
+          edit_data,
+          error);
+      }
+
+    if (!ok)
+      {
+        comboBox->setCurrentIndex (-1);
+        comboBox->setEditable (true);
+        comboBox->setEditText (comboBox->property ("original_value").toString ());
+        comboBox->lineEdit ()->setReadOnly (true);
+      }
+      m_blockUpdates = false;
+  }
+
+  void
+  Table::checkBoxClicked (int row, int col, QCheckBox* checkBox)
+  {
+    if (m_blockUpdates)
+      return;
+    m_blockUpdates = true;
+    gh_manager::auto_lock lock;
+
+    bool new_value = !checkBox->isChecked ();
+
+    octave_value data = octave_value(m_curData);
+    if (data.islogical ())
+      {
+        // EASY WE JUST CONVERT
+        boolMatrix matrix = data.bool_matrix_value ();
+        if (row < matrix.rows () && col < matrix.columns ())
+          {
+            bool old_value = matrix (row, col);
+            matrix (row, col) = new_value;
+            checkBox->setChecked(new_value);
+            if (new_value != old_value)
+              {
+                m_curData = octave_value(matrix);
+                gh_manager::post_set (m_handle, "data", octave_value(matrix), false);
+              }
+
+            sendCellEditCallback(row,
+              col,
+              octave_value(old_value),
+              octave_value(new_value),
+              octave_value(new_value),
+              octave_value(""));
+
+          }
+        else
+          {
+            sendCellEditCallback(row,
+              col,
+              octave_value(),
+              octave_value(),
+              octave_value(new_value),
+              octave_value("Table data is not editable at this location."));
+          }
+      }
+    else if (data.iscell ())
+      {
+        Cell cell = data.cell_value ();
+        if (row < cell.rows () && col < cell.columns ())
+          {
+              if (cell (row, col).islogical ())
+                {
+                  bool old_value = cell (row, col).bool_value ();
+                  cell (row, col) = octave_value(new_value);
+                  checkBox->setChecked(new_value);
+                  if (new_value != old_value)
+                    {
+                      m_curData = octave_value(cell);
+                      gh_manager::post_set (m_handle, "data", octave_value (cell), false);
+                    }
+
+                  sendCellEditCallback(row,
+                    col,
+                    octave_value(old_value),
+                    octave_value(new_value),
+                    octave_value(new_value),
+                    octave_value(""));
+                }
+              else
+                {
+                  sendCellEditCallback(row,
+                    col,
+                    cell (row, col),
+                    octave_value(),
+                    octave_value(new_value),
+                    octave_value("Cannot convert logical edit to other type."));
+                }
+          }
+        else
+          {
+            sendCellEditCallback(row,
+              col,
+              cell (row, col),
+              octave_value(),
+              octave_value(new_value),
+              octave_value("Table data is not editable at this location."));
+          }
+      }
+    else if (data.is_matrix_type ())
+      {
+        if (row < data.rows () && col < data.columns ())
+          {
+            sendCellEditCallback(row,
+              col,
+              data.fast_elem_extract (row + col * data.rows()),
+              octave_value(),
+              octave_value(new_value),
+              octave_value("Cannot convert logical edit to other type."));
+          }
+        else
+          {
+            sendCellEditCallback(row,
+              col,
+              data.fast_elem_extract (row + col * data.rows()),
+              octave_value(),
+              octave_value(new_value),
+              octave_value("Table data is not editable at this location."));
+          }
+      }
+      m_blockUpdates = false;
+  }
+
+
+  void
+  Table::itemChanged (QTableWidgetItem* item)
+  {
+    if (m_blockUpdates)
+      return;
+    m_blockUpdates = true;
+    gh_manager::auto_lock lock;
+    octave_value data = octave_value(m_curData);
+
+    int row = item->row ();
+    int col = item->column ();
+    octave_value edit_data = octave_value (Utils::toStdString(item->text ()));
+    octave_value new_value;
+    octave_value old_value;
+    octave_value new_data;
+
+    if (row < data.rows () && col < data.columns ())
+      {
+        if (data.iscell ())
+          {
+            old_value = data.cell_value () (row, col);
+          }
+        else if (data.is_matrix_type ())
+          {
+            old_value = data.fast_elem_extract (row + col * data.rows ());
+          }
+
+        // Now we need to coerce the new_value in to the type of the old_value
+        if (old_value.is_string ())
+          new_value = edit_data;
+        else
+          {
+            new_value = attempt_type_conversion(edit_data, old_value);
+            std::pair <Qt::AlignmentFlag, QString> flag_and_text =
+              qStringValueFor(new_value, columnformat (col));
+            item->setTextAlignment (flag_and_text.first);
+            item->setText (flag_and_text.second);
+          }
+
+        if (data.iscell ())
+          {
+            Cell cell = data.cell_value();
+            cell (row, col) = new_value;
+            new_data = octave_value (cell);
+          }
+        else
+          {
+            data.fast_elem_insert (row + col * data.rows (), new_value);
+            new_data = data;
+          }
+          m_curData = octave_value(new_data);
+          gh_manager::post_set (m_handle, "data", new_data, false);
+
+          sendCellEditCallback(row,
+            col,
+            octave_value(old_value),
+            octave_value(new_value),
+            octave_value(new_value),
+            octave_value(""));
+      }
+    else
+      {
+        item->setText ("");
+
+        octave_value error = octave_value("Table data is not editable at this location.");
+        sendCellEditCallback(row,
+          col,
+          octave_value(),
+          octave_value(),
+          edit_data,
+          error);
+      }
+
+      m_blockUpdates = false;
+  }
+
+  void
+  Table::update (int pId)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    switch (pId)
+      {
+      case uitable::properties::ID_BACKGROUNDCOLOR:
+      case uitable::properties::ID_FOREGROUNDCOLOR:
+        updatePalette ();
+        break;
+
+      case uitable::properties::ID_COLUMNNAME:
+        updateColumnname ();
+        updateColumnwidth ();
+        break;
+
+      case uitable::properties::ID_COLUMNWIDTH:
+        updateColumnwidth ();
+        break;
+
+      case uitable::properties::ID_COLUMNEDITABLE:
+      case uitable::properties::ID_COLUMNFORMAT:
+      case uitable::properties::ID_DATA:
+        m_blockUpdates = true;
+        m_curData = octave_value(tp.get_data ());
+        updateData ();
+        updateRowname ();
+        updateColumnname ();
+        updateColumnwidth ();
+        updateEnable();
+        m_blockUpdates = false;
+        break;
+
+      case uitable::properties::ID_ENABLE:
+        updateEnable();
+        break;
+
+      case uitable::properties::ID_KEYPRESSFCN:
+        m_keyPressHandlerDefined = ! tp.get_keypressfcn ().isempty ();
+        break;
+
+      case uitable::properties::ID_KEYRELEASEFCN:
+        m_keyReleaseHandlerDefined = ! tp.get_keyreleasefcn ().isempty ();
+        break;
+
+        case uitable::properties::ID_FONTNAME:
+        case uitable::properties::ID_FONTSIZE:
+        case uitable::properties::ID_FONTWEIGHT:
+        case uitable::properties::ID_FONTANGLE:
+          if (m_tableWidget)
+            {
+              m_tableWidget->setFont (Utils::computeFont<uitable> (tp));
+              for (int row = 0; row < m_tableWidget->rowCount (); row++)
+                {
+                  m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
+                }
+            }
+          break;
+
+      case uitable::properties::ID_POSITION:
+          {
+            Matrix bb = tp.get_boundingbox (false);
+            m_tableWidget->setGeometry (octave::math::round (bb(0)), octave::math::round (bb(1)),
+                                        octave::math::round (bb(2)), octave::math::round (bb(3)));
+            updateExtent();
+          }
+        break;
+
+      case uitable::properties::ID_REARRANGEABLECOLUMNS:
+        updateRearrangeableColumns ();
+        break;
+
+      case uitable::properties::ID_ROWNAME:
+        updateRowname ();
+        break;
+
+      case uitable::properties::ID_ROWSTRIPING:
+        updatePalette();
+        break;
+
+      case uitable::properties::ID_TOOLTIPSTRING:
+        m_tableWidget->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
+        break;
+
+      case base_properties::ID_VISIBLE:
+        m_tableWidget->setVisible (tp.is_visible ());
+        break;
+
+      default:
+        break;
+
+      }
+  }
+
+  void
+  Table::updateColumnname (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    // Reset the Column Count
+    m_tableWidget->setColumnCount (tp.get_data ().columns ());
+
+    octave_value columnname = tp.get_columnname ();
+    QStringList l;
+    bool visible = true;
+
+    if (columnname.is_string () && columnname.string_value (false) == "numbered")
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << QString::number(i + 1);
+    else if (columnname.is_string ())
+      {
+        if (m_tableWidget->columnCount () > 0)
+          l << Utils::fromStdString(columnname.string_value ());
+        for (int i = 1; i < m_tableWidget->columnCount (); i++)
+          l << "";
+      }
+    else if (columnname.isempty ())
+      {
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << "";
+
+        visible = false;
+      }
+    else if (columnname.iscell ())
+      {
+        octave_idx_type n = columnname.numel();
+        Cell cell_value = columnname.cell_value();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          {
+            octave_value v = cell_value (i);
+            if (v.is_string ())
+              l << Utils::fromStdString(v.string_value (true));
+            else if (v.is_matrix_type ())
+              {
+                Matrix data = v.matrix_value ();
+
+                /* Now Matlab does something very strange here:
+                 * If data is a row or column matrix, then each datapoint is added
+                 * Otherwise nothing is set.
+                 */
+                if (data.rows () > 1 && data.cols () > 1)
+                  l << "";
+                else
+                  for (octave_idx_type j = 0; j < data.numel (); j++)
+                    l << QString::number(data (j));
+              }
+            else if (v.isnumeric ())
+              l << QString::number(v.double_value ());
+            else
+              l << QString::number(v.double_value ());
+          }
+      }
+    else if (columnname.is_matrix_type ())
+      {
+        octave_idx_type n = columnname.numel ();
+        Matrix matrix_value = columnname.matrix_value ();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          l << QString::number(matrix_value (i));
+      }
+    else
+      {
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << "";
+        visible = false;
+      }
+
+    l.replaceInStrings("|", "\n");
+
+    // Now add the columns as required
+    if (m_tableWidget->columnCount () < l.length())
+      {
+        int oldColumnCount = m_tableWidget->columnCount ();
+        m_tableWidget->setColumnCount (l.length());
+        for (int col = oldColumnCount; col < l.length (); col++)
+          {
+            std::string format = columnformat (col);
+            bool enabled = columneditable (col);
+
+            for (int row = 0; row < m_tableWidget->rowCount (); row++)
+              updateData (row, col, octave_value (""), format, enabled);
+          }
+      }
+
+      m_tableWidget->setHorizontalHeaderLabels (l);
+      m_tableWidget->horizontalHeader ()->setVisible (visible);
+  }
+
+  void
+  Table::updateColumnwidth (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    octave_value columnwidth = tp.get_columnwidth ();
+    if (columnwidth.isempty () ||
+      (columnwidth.is_string () && columnwidth.string_value (false) == "auto"))
+      for (int i = 0; i < m_tableWidget->columnCount (); i++)
+        m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
+    else if (columnwidth.is_string () && columnwidth.string_value (false) == "preferred")
+      for (int i = 0; i < m_tableWidget->columnCount (); i++)
+        {
+          int column_size =
+            (qobject_cast<QAbstractItemView*> (m_tableWidget))->sizeHintForColumn (i);
+          int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
+
+          if (column_size > header_size)
+            header_size = column_size;
+          m_tableWidget->setColumnWidth (i, header_size);
+        }
+    else if (columnwidth.iscell ())
+      {
+        Cell cell_value = columnwidth.cell_value ();
+        int i = 0;
+        for (; i < m_tableWidget->columnCount () && i < cell_value.numel (); i++)
+          {
+            octave_value v = cell_value (i);
+            if (v.is_string ()  && v.string_value (false) == "auto")
+              m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
+            else if (v.is_string () && v.string_value (false) == "preferred")
+              {
+                int column_size =
+                  (qobject_cast<QAbstractItemView*> (m_tableWidget))->sizeHintForColumn (i);
+                int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
+
+                if (column_size > header_size)
+                  header_size = column_size;
+                m_tableWidget->setColumnWidth (i, header_size);
+              }
+            else
+              {
+                int w = int (v.double_value());
+                m_tableWidget->setColumnWidth (i, w);
+              }
+          }
+        for (;i < m_tableWidget->columnCount (); i++)
+          {
+            int column_size =
+              (qobject_cast<QAbstractItemView*> (m_tableWidget))->sizeHintForColumn (i);
+            int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
+
+            if (column_size > header_size)
+              header_size = column_size;
+            m_tableWidget->setColumnWidth (i, header_size);
+          }
+      }
+    else if (columnwidth.is_matrix_type ())
+      {
+        Matrix matrix_value = columnwidth.matrix_value ();
+        int i = 0;
+        for (; i < m_tableWidget->columnCount () && i < matrix_value.numel (); i++)
+          {
+            octave_value v = matrix_value (i);
+            int w = int (v.double_value());
+            m_tableWidget->setColumnWidth (i, w);
+          }
+        for (;i < m_tableWidget->columnCount (); i++)
+          m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
+      }
+  }
+
+  bool inline
+  Table::columneditable (int col)
+  {
+    uitable::properties& tp = properties<uitable> ();
+    boolNDArray columneditable = tp.get_columneditable ().bool_array_value ();
+    bool editable = false;
+
+    if (!columneditable.isempty () && col < columneditable.numel ())
+      editable = columneditable.xelem (col);
+    else if (!columneditable.isempty () && columneditable.numel () == 1)
+      editable = columneditable.xelem (0);
+
+    return editable;
+  }
+
+  std::string inline
+  Table::columnformat (int col)
+  {
+    uitable::properties& tp = properties<uitable> ();
+    std::string format = "";
+    octave_value ov_columnformat = tp.get_columnformat ();
+
+    if (ov_columnformat.iscell ())
+      {
+        Cell columnformat = ov_columnformat.cell_value ();
+        if (!columnformat.isempty () && col < columnformat.numel ())
+          {
+            octave_value format_value = columnformat.xelem (col);
+
+            if (!format_value.isempty () && format_value.is_string())
+              format = format_value.string_value ();
+            else if (!format_value.isempty () && format_value.iscell ())
+              format = "popup";
+          }
+      }
+    else if (ov_columnformat.is_string ())
+      {
+        format = ov_columnformat.string_value ();
+      }
+    return format;
+  }
+
+  void inline
+  Table::updateDataColumn (int col)
+  {
+    octave_value data = properties<uitable> ().get_data ();
+
+    std::string format = columnformat (col);
+    bool is_editable = columneditable (col);
+
+    for (octave_idx_type row = 0; row < data.rows (); row++)
+      updateData(row,
+        col,
+        data.iscell ()
+          ? data.cell_value () (row, col)
+          : data.fast_elem_extract (row + col * data.rows ()),
+        format,
+        is_editable);
+  }
+
+  void inline
+  Table::updateData (int row, int col)
+  {
+    octave_value data = properties<uitable> ().get_data ();
+    updateData (row,
+      col,
+      data.iscell ()
+        ? data.cell_value () (row, col)
+        : data.fast_elem_extract (row + col * data.rows ()),
+      columnformat (col),
+      columneditable (col));
+  }
+
+  void inline
+  Table::updateData (int row, int col, octave_value value,
+                     std::string format = "", bool enabled = false)
+  {
+    if (format == "logical" || (format == "" && value.islogical ()))
+      {
+        if (m_tableWidget->item (row, col))
+          delete m_tableWidget->item (row, col);
+
+        m_tableWidget->setCellWidget (row, col, checkBoxForLogical(value, enabled));
+        m_tableWidget->cellWidget (row, col)->setProperty ("row", QVariant(row));
+        m_tableWidget->cellWidget (row, col)->setProperty ("col", QVariant(col));
+      }
+    else if (format == "popup" && enabled)
+      {
+        if (m_tableWidget->item (row, col))
+          delete m_tableWidget->item (row, col);
+
+        QString string_value = qStringValueFor(value, format).second;
+        uitable::properties& tp = properties<uitable> ();
+        octave_value format_value = tp.get_columnformat ().cell_value ().xelem (col);
+
+        QComboBox* comboBox = new QComboBox ();
+        comboBox->setProperty("row", QVariant (row));
+        comboBox->setProperty("col", QVariant (col));
+
+        int index = -1;
+        for (int k = 0; k < format_value.numel (); k++)
+          {
+            QString popup_item = Utils::fromStdString(
+              format_value.fast_elem_extract (k).string_value ());
+
+            comboBox->addItem (popup_item);
+
+            if (popup_item == string_value)
+              index = k;
+          }
+        comboBox->setCurrentIndex (index);
+
+        if (index < 0)
+          {
+            comboBox->setEditable (true);
+            comboBox->setEditText (string_value);
+            comboBox->lineEdit ()->setReadOnly (true);
+          }
+
+        comboBox->setProperty ("original_value", QVariant (string_value));
+
+        comboBox->installEventFilter (this);
+        m_tableWidget->setCellWidget(row, col, comboBox);
+        connect(comboBox, SIGNAL(currentIndexChanged(const QString&)),
+                this, SLOT(comboBoxCurrentIndexChanged(const QString&)));
+      }
+    else
+      {
+        if (m_tableWidget->cellWidget (row, col))
+          delete m_tableWidget->cellWidget (row, col);
+        m_tableWidget->setItem (row, col, itemFor(value, format, enabled));
+      }
+  }
+
+  void
+  Table::updateData ()
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    octave_value data = tp.get_data();
+
+    if (data.iscell () || data.is_matrix_type ())
+      {
+        m_tableWidget->setRowCount (data.rows ());
+        m_tableWidget->setColumnCount (data.columns ());
+
+        for (octave_idx_type col = 0; col < data.columns (); col++)
+          updateDataColumn (col);
+      }
+
+    for (octave_idx_type row = 0; row < m_tableWidget->rowCount (); row++)
+      m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
+  }
+
+  void
+  Table::updateEnable (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+    m_tableWidget->setEnabled (!tp.enable_is ("off"));
+
+    bool enabled = tp.enable_is ("on");
+    bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
+
+    // Set selection mode
+    m_tableWidget->setSelectionMode (enabled
+      ? QAbstractItemView::ExtendedSelection
+      : QAbstractItemView::NoSelection);
+
+    // Set rearrangeablecolumns
+    #if defined (HAVE_QT4)
+      m_tableWidget->horizontalHeader ()->setMovable (enabled && rearrangeableColumns);
+    #elif defined (HAVE_QT5)
+      m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
+    #endif
+    m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
+    m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
+
+    // Turn off column editable
+    for (int col = 0; col < m_tableWidget->columnCount (); col++)
+      {
+        bool editable = columneditable (col);
+
+        for (int row = 0; row < m_tableWidget->rowCount (); row++)
+          if (QTableWidgetItem* item = m_tableWidget->item (row, col))
+            {
+              Qt::ItemFlags flags = item->flags ();
+              if (enabled && editable)
+                item->setFlags (flags | Qt::ItemIsEditable);
+              else
+                item->setFlags (flags & ~Qt::ItemIsEditable);
+            }
+          else if (QWidget* widget = m_tableWidget->cellWidget (row, col))
+            {
+              QCheckBox* checkBox = NULL;
+              if (widget && !widget->children ().isEmpty ())
+                {
+                  QHBoxLayout* layout = qobject_cast<QHBoxLayout*> (
+                    widget->children ().first ());
+                  if (layout && layout->count () > 0)
+                    {
+                      checkBox = qobject_cast<QCheckBox*> (
+                        layout->itemAt (0)-> widget ());
+                    }
+                }
+              if (checkBox)
+                {
+                  widget->setProperty ("Enabled", QVariant (enabled & editable));
+                }
+              else
+                {
+                  widget->setAttribute(Qt::WA_TransparentForMouseEvents, !(editable & enabled));
+                  widget->setFocusPolicy(Qt::NoFocus);
+                }
+            }
+      }
+  }
+
+  void
+  Table::updateExtent (void)
+  {
+    QSize s = realQSizeForTable (m_tableWidget);
+    Matrix extent = Matrix (1, 4);
+    extent(0, 0) = 0;
+    extent(0, 1) = 0;
+    extent(0, 2) = s.width ();
+    extent(0, 3) = s.height () ;
+    graphics_object go = object ();
+    gh_manager::post_set (go.get_handle (), "extent", extent, false);
+  }
+
+  void
+  Table::updatePalette (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    QPalette p = m_tableWidget->palette ();
+    p.setColor (QPalette::Text,
+                Utils::fromRgb (tp.get_foregroundcolor_rgb ()));
+    p.setColor (QPalette::Base,
+              Utils::fromRgb (tp.get_backgroundcolor_rgb ()));
+    p.setColor (QPalette::AlternateBase,
+              Utils::fromRgb (tp.get_alternatebackgroundcolor_rgb ()));
+    m_tableWidget->setPalette (p);
+    m_tableWidget->setAlternatingRowColors (tp.is_rowstriping ());
+    // FIXME: Handle multiple alternating background colors
+  }
+
+  void
+  Table::updateRowname (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    // Reset the row count
+    m_tableWidget->setRowCount (tp.get_data ().rows ());
+
+    octave_value rowname = tp.get_rowname ();
+    QStringList l;
+    bool visible = true;
+
+    if (rowname.is_string () && rowname.string_value (false) == "numbered")
+      for (int i = 0; i < m_tableWidget->rowCount (); i++)
+        l << QString::number(i + 1);
+    else if (rowname.is_string ())
+      {
+        if (m_tableWidget->rowCount () > 0)
+          l << Utils::fromStdString(rowname.string_value ());
+        for (int i = 1; i < m_tableWidget->rowCount (); i++)
+          l << "";
+      }
+    else if (rowname.isempty ())
+      {
+        for (int i = 0; i < m_tableWidget->rowCount (); i++)
+          l << "";
+        visible = false;
+      }
+    else if (rowname.iscell ())
+      {
+        octave_idx_type n = rowname.numel();
+        Cell cell_value = rowname.cell_value();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          {
+            octave_value v = cell_value (i);
+            if (v.is_string ())
+              l << Utils::fromStdString(v.string_value (true));
+            else if (v.is_matrix_type ())
+              {
+                Matrix data = v.matrix_value ();
+
+                /* Now Matlab does something very strange here:
+                 * If data is a row or column matrix, then each datapoint is added
+                 * Otherwise nothing is set.
+                 */
+                if (data.rows () > 1 && data.cols () > 1)
+                  l << "";
+                else
+                  for (octave_idx_type j = 0; j < data.numel (); j++)
+                    l << QString::number(data (j));
+              }
+            else if (v.isnumeric ())
+              l << QString::number(v.double_value (true));
+            else
+              l << QString::number(v.double_value (true));
+          }
+      }
+    else if (rowname.is_matrix_type ())
+      {
+        octave_idx_type n = rowname.numel();
+        Matrix matrix_value = rowname.matrix_value();
+
+        for (octave_idx_type i = 0; i < n; i++)
+          l << QString::number(matrix_value (i));
+      }
+    else
+      {
+        for (int i = 0; i < m_tableWidget->columnCount (); i++)
+          l << "";
+        visible = false;
+      }
+
+    // Add dummy rows as required
+    if (m_tableWidget->rowCount () < l.length())
+      {
+        int oldRowCount = m_tableWidget->rowCount ();
+        m_tableWidget->setRowCount (l.length());
+
+        for (int col = 0; col < m_tableWidget->columnCount (); col++)
+          {
+            std::string format = columnformat (col);
+            bool enabled = columneditable (col);
+
+            for (int row = oldRowCount; row < l.length (); row++)
+              {
+                m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
+
+                updateData (row, col, octave_value (""), format, enabled);
+              }
+          }
+      }
+
+    m_tableWidget->setVerticalHeaderLabels (l);
+    m_tableWidget->verticalHeader ()->setVisible (visible);
+  }
+
+  void
+  Table::updateRearrangeableColumns (void)
+  {
+    uitable::properties& tp = properties<uitable> ();
+
+    bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
+    bool enabled = tp.enable_is ("on");
+
+  #if defined (HAVE_QT4)
+    m_tableWidget->horizontalHeader ()->setMovable (enabled && rearrangeableColumns);
+  #elif defined (HAVE_QT5)
+    m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
+  #endif
+    m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
+    m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
+  }
+
+  bool
+  Table::eventFilter (QObject* watched, QEvent* xevent)
+  {
+    //uitable::properties& tp = properties<uitable> ();
+    if (qobject_cast<QTableWidget*> (watched))
+      {
+        switch (xevent->type ())
+          {
+          case QEvent::Resize:
+            {
+              gh_manager::auto_lock lock;
+              graphics_object go = object ();
+              if (go.valid_object ())
+                {
+                  const uitable::properties& tp =
+                    Utils::properties<uitable> (go);
+                  if (tp.fontunits_is ("normalized"))
+                    m_tableWidget->setFont (Utils::computeFont<uitable> (tp));
+                }
+            }
+            break;
+
+          case QEvent::MouseButtonPress:
+            {
+              gh_manager::auto_lock lock;
+              QMouseEvent* m = dynamic_cast<QMouseEvent*> (xevent);
+              graphics_object go = object ();
+              const uitable::properties& tp =
+                Utils::properties<uitable> (go);
+              graphics_object fig = go.get_ancestor ("figure");
+
+              if (m->button () != Qt::LeftButton || !tp.enable_is ("on"))
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        Utils::figureSelectionType (m), false);
+                  gh_manager::post_set (fig.get_handle (), "currentpoint",
+                                        Utils::figureCurrentPoint (fig, m),
+                                        false);
+                  gh_manager::post_callback (fig.get_handle (),
+                                             "windowbuttondownfcn");
+                  gh_manager::post_callback (m_handle, "buttondownfcn");
+
+                  if (m->button () == Qt::RightButton)
+                    ContextMenu::executeAt (properties (), m->globalPos ());
+                }
+              else
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                       octave_value ("normal"), false);
+                }
+            }
+            break;
+
+          case QEvent::KeyPress:
+            {
+              QKeyEvent* k = dynamic_cast<QKeyEvent*> (xevent);
+              if (m_keyPressHandlerDefined)
+                {
+                  gh_manager::auto_lock lock;
+
+                  octave_scalar_map keyData = Utils::makeKeyEventStruct (k);
+                  graphics_object fig = object ().get_ancestor ("figure");
+
+                  gh_manager::post_set (fig.get_handle (), "currentcharacter",
+                                        keyData.getfield ("Character"), false);
+                  gh_manager::post_callback (m_handle, "keypressfcn", keyData);
+                }
+              int row = m_tableWidget->currentRow ();
+              int col = m_tableWidget->currentColumn ();
+              switch (k->key())
+                {
+                case Qt::Key_Space:
+                  {
+                    QCheckBox* checkBox = NULL;
+                    QWidget* widget = qobject_cast<QWidget*> (
+                      m_tableWidget->cellWidget (row, col));
+                    if (widget && !widget->children ().isEmpty ())
+                      {
+                        QHBoxLayout* layout = qobject_cast<QHBoxLayout*> (
+                          widget->children ().first ());
+                        if (layout && layout->count () > 0)
+                          {
+                            checkBox = qobject_cast<QCheckBox*> (
+                              layout->itemAt (0)-> widget ());
+                          }
+                      }
+                    if (checkBox && checkBox->property ("Enabled").toBool())
+                      checkBoxClicked(row, col, checkBox);
+  
+                    QComboBox* comboBox = qobject_cast<QComboBox*> (
+                      m_tableWidget->cellWidget (row, col));
+                    if (comboBox)
+                      comboBox->showPopup ();
+                  }
+                  break;
+
+                case Qt::Key_Return:
+                case Qt::Key_Enter:
+                  {
+                    if (k->modifiers() == Qt::NoModifier)
+                      {
+                        if (row + 1 < m_tableWidget->rowCount())
+                          m_tableWidget->setCurrentCell (row + 1, col);
+                        else
+                          {
+                            if (col + 1 < m_tableWidget->columnCount())
+                              m_tableWidget->setCurrentCell (0, col + 1);
+                            else
+                              m_tableWidget->setCurrentCell (0, 0);
+                          }
+                      }
+                    else if (k->modifiers() == Qt::ShiftModifier)
+                      {
+                        if (row - 1 >= 0)
+                          m_tableWidget->setCurrentCell (row - 1, col);
+                        else
+                          {
+                            if (col - 1 >= 0)
+                              m_tableWidget->setCurrentCell
+                                  (m_tableWidget->rowCount() - 1,
+                                   col - 1);
+                            else
+                              m_tableWidget->setCurrentCell
+                                  (m_tableWidget->rowCount() - 1,
+                                   m_tableWidget->columnCount() - 1);
+                          }
+                      }
+                  }
+                  break;
+
+                default:
+                  break;
+                }
+            }
+            break;
+
+          case QEvent::KeyRelease:
+            {
+              if (m_keyReleaseHandlerDefined)
+                {
+                  gh_manager::auto_lock lock;
+                  QKeyEvent* k = dynamic_cast<QKeyEvent*> (xevent);
+
+                  octave_scalar_map keyData = Utils::makeKeyEventStruct (k);
+                  graphics_object fig = object ().get_ancestor ("figure");
+
+                  gh_manager::post_set (fig.get_handle (), "currentcharacter",
+                                        keyData.getfield ("Character"), false);
+                  gh_manager::post_callback (m_handle, "keyreleasefcn", keyData);
+                }
+            }
+            break;
+
+          default:
+            break;
+          }
+      }
+    else if (qobject_cast<QComboBox*> (watched))
+      {
+        switch (xevent->type ())
+          {
+          case QEvent::MouseButtonPress:
+            {
+              gh_manager::auto_lock lock;
+              QMouseEvent* m = dynamic_cast<QMouseEvent*> (xevent);
+              graphics_object go = object ();
+              const uitable::properties& tp =
+                Utils::properties<uitable> (go);
+              graphics_object fig = go.get_ancestor ("figure");
+
+              if (m->button () != Qt::LeftButton || !tp.enable_is ("on"))
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                        Utils::figureSelectionType (m), false);
+                  gh_manager::post_set (fig.get_handle (), "currentpoint",
+                                        Utils::figureCurrentPoint (fig, m),
+                                        false);
+                  gh_manager::post_callback (fig.get_handle (),
+                                             "windowbuttondownfcn");
+                  gh_manager::post_callback (m_handle, "buttondownfcn");
+
+                  if (m->button () == Qt::RightButton)
+                    ContextMenu::executeAt (tp, m->globalPos ());
+                }
+              else
+                {
+                  gh_manager::post_set (fig.get_handle (), "selectiontype",
+                                       Utils::figureSelectionType (m), false);
+
+                  QComboBox* comboBox_0 = qobject_cast<QComboBox*> (watched);
+                  for (int row = 0; row < m_tableWidget->rowCount (); row++)
+                    {
+                      for (int col = 0; col < m_tableWidget->columnCount (); col++)
+                        {
+                          QComboBox* comboBox_1 = qobject_cast<QComboBox*> (
+                            m_tableWidget->cellWidget (row, col));
+                          if (comboBox_0 == comboBox_1)
+                            m_tableWidget->setCurrentCell (row, col);
+                        }
+                    }
+                }
+            }
+            break;
+
+          default:
+            break;
+          }
+      }
+    return false;
+  }
+
+#undef AUTO_HEIGHT
+}