GNU Octave 7.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
Table.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2016-2022 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26#if defined (HAVE_CONFIG_H)
27# include "config.h"
28#endif
29
30#include <QCheckBox>
31#include <QComboBox>
32#include <QEvent>
33#include <QFrame>
34#include <QHBoxLayout>
35#include <QHeaderView>
36#include <QLabel>
37#include <QLineEdit>
38#include <QModelIndexList>
39#include <QMouseEvent>
40#include <QString>
41#include <QStringList>
42#include <QTableWidget>
43#include <QTableWidgetItem>
44#include <QTimer>
45
46#include "Container.h"
47#include "ContextMenu.h"
48#include "Table.h"
49#include "QtHandlesUtils.h"
50
51#include "octave-qobject.h"
52
53#include "graphics.h"
54#include "interpreter.h"
55#include "oct-map.h"
56#include "oct-stream.h"
57#include "oct-string.h"
58#include "oct-strstrm.h"
59
60namespace octave
61{
62
63 static const int AUTO_WIDTH = 75;
64
65#define AUTO_HEIGHT (tp.get_fontsize () * 2 - 1)
66
67 static QSize realQSizeForTable (QTableWidget *t)
68 {
69 int w = t->verticalHeader ()->width () + 4;
70 for (int i = 0; i < t->columnCount (); i++)
71 w += t->columnWidth (i);
72 int h = t->horizontalHeader ()->height () + 4;
73 for (int i = 0; i < t->rowCount (); i++)
74 h += t->rowHeight (i);
75 return QSize (w, h);
76 }
77
78#define FORMATNUMBER(type) \
79 static QString formatNumber (type d, \
80 char format = 'f', \
81 int precision = 4) \
82 { \
83 type ten = 10; \
84 if (format == 'n') \
85 { \
86 if (d == floor (d)) \
87 return QString::number (d, 'g', precision); \
88 else if (d <= pow (ten, precision - 1) \
89 && d > pow (ten, 1 - precision)) \
90 return QString::number (d, 'f', precision); \
91 else \
92 return QString::number (d, 'e', precision); \
93 } \
94 else if (format == 'F') \
95 { \
96 int exponent = floor (log10 (d) / 3) * 3; \
97 d *= pow (ten, -exponent); \
98 return QString::number (d, 'f', precision) + "e" + \
99 (exponent < 0 ? "-" : "+") + \
100 QString ("%1").arg (abs (exponent), 3, 10, QChar ('0')); \
101 } \
102 else if (format == 'E') \
103 { \
104 int exponent = floor (log10 (d) / 3) * 3; \
105 d *= pow (ten, -exponent); \
106 return QString::number (d, \
107 'f', \
108 precision - floor (log10 (d)) - 1) + \
109 "e" + (exponent < 0 ? "-" : "+") + \
110 QString ("%1").arg (abs (exponent), 3, 10, QChar ('0')); \
111 } \
112 else \
113 return QString::number (d, format, precision); \
114 }
115
118
119#undef FORMATNUMBER
120
121 static QString formatComplex (Complex c, char format = 'f', int precision = 4)
122 {
123 return formatNumber (c.real (), format, precision) + " + "
124 + formatNumber (c.imag (), format, precision) + "i";
125 }
126
127#define FORMAT_VALUE_EXCEPT_RAT(f,l) \
128 if (format == "numeric" || format == "short") \
129 text = formatNumber (value, 'n', f); \
130 else if (format == "short f" || format == "shortf") \
131 text = formatNumber (value, 'f', f); \
132 else if (format == "short e" || format == "shorte") \
133 text = formatNumber (value, 'e', f); \
134 else if (format == "short eng" || format == "shorteng") \
135 text = formatNumber (value, 'F', f); \
136 else if (format == "short g" || format == "shortg") \
137 text = formatNumber (value, 'g', f + 1); \
138 else if (format == "long") \
139 text = formatNumber (value, 'n', l); \
140 else if (format == "long f" || format == "longf") \
141 text = formatNumber (value, 'f', l); \
142 else if (format == "long e" || format == "longe") \
143 text = formatNumber (value, 'e', l); \
144 else if (format == "long eng" || format == "longeng") \
145 text = formatNumber (value, 'E', l); \
146 else if (format == "long g" || format == "longg") \
147 text = formatNumber (value, 'g', l + 1); \
148 else if (format == "bank") \
149 text = QString::number (value, 'f', 2); \
150 else if (format == "+") \
151 if (value > 0) \
152 text = Utils::fromStdString ("+"); \
153 else if (value < 0) \
154 text = Utils::fromStdString ("-"); \
155 else \
156 text = Utils::fromStdString ("");
157
158#define FORMAT_VALUE(f,l) \
159 FORMAT_VALUE_EXCEPT_RAT(f,l) \
160 else if (format == "rat") \
161 text = Utils::fromStdString (rational_approx (double (value), 0)); \
162 else \
163 { \
164 text = formatNumber (value, 'n', f); \
165 flag = Qt::AlignLeft ; \
166 }
167
168#define FORMAT_UINT_VALUE() \
169 text = QString::number (value); \
170 if (format == "char" || format == "popup") \
171 flag = Qt::AlignLeft; \
172 else if (format == "+") \
173 { \
174 if (value > 0) \
175 text = Utils::fromStdString ("+"); \
176 else \
177 text = Utils::fromStdString (""); \
178 }
179
180#define FORMAT_INT_VALUE() \
181 text = QString::number (value); \
182 if (format == "char" || format == "popup") \
183 flag = Qt::AlignLeft ; \
184 else if (format == "+") \
185 { \
186 if (value > 0) \
187 text = Utils::fromStdString ("+"); \
188 else if (value < 0) \
189 text = Utils::fromStdString ("-"); \
190 else \
191 text = Utils::fromStdString (""); \
192 }
193
194 static std::pair<Qt::AlignmentFlag, QString>
195 qStringValueFor (octave_value val, std::string format = "")
196 {
197 Qt::AlignmentFlag flag = Qt::AlignRight;
198 QString text;
199 if (val.isempty ())
200 {
201 text = "";
202 flag = Qt::AlignLeft;
203 }
204 else if (val.is_string ())
205 {
207 flag = Qt::AlignLeft;
208 }
209 else if (val.iscomplex ())
210 {
211 // Matlab has multiple complex types, we only have double.
212 Complex c = val.complex_value ();
213 if (format == "short")
214 text = formatComplex (c, 'f', 4);
215 else if (format == "short e" || format == "shorte")
216 text = formatComplex (c, 'e', 4);
217 else if (format == "short eng" || format == "shorteng")
218 text = formatComplex (c, 'E', 4);
219 else if (format == "short g" || format == "shortg")
220 text = formatComplex (c, 'g', 5);
221 else if (format == "long")
222 text = formatComplex (c, 'f', 15);
223 else if (format == "long e" || format == "longe")
224 text = formatComplex (c, 'e', 15);
225 else if (format == "long eng" || format == "longeng")
226 text = formatComplex (c, 'E', 15);
227 else if (format == "long g" || format == "longg")
228 text = formatComplex (c, 'g', 16);
229 else if (format == "bank")
230 text = QString::number (c.real (), 'f', 2);
231 else if (format == "+")
232 {
233 if (c.real () > 0)
234 text = Utils::fromStdString ("+");
235 else if (c.real () < 0)
236 text = Utils::fromStdString ("-");
237 else
238 text = Utils::fromStdString ("");
239 }
240 else if (format == "rat")
241 text = Utils::fromStdString (rational_approx (c.real (), 0)) + " + "
242 + Utils::fromStdString (rational_approx (c.imag (), 0)) + "i";
243 else if (format == "numeric")
244 text = QString::number (c.real (), 'g', 5) + " + "
245 + QString::number (c.imag (), 'g', 5) + "i";
246 else
247 {
248 text = QString::number (c.real (), 'g', 5) + " + "
249 + QString::number (c.imag (), 'g', 5) + "i";
250 flag = Qt::AlignLeft;
251 }
252 }
253 else if (val.is_double_type () )
254 {
255 double value = val.double_value ();
256 FORMAT_VALUE(4, 15)
257 }
258 else if (val.is_single_type ())
259 {
260 float value = val.float_value ();
261 FORMAT_VALUE(4, 7)
262 }
263 else if (val.is_int8_type ())
264 {
265 short int value = val.short_value ();
267 }
268 else if (val.is_uint8_type ())
269 {
270 unsigned short int value = val.ushort_value ();
272 }
273 else if (val.is_int16_type ())
274 {
275 int value = val.int_value ();
277 }
278 else if (val.is_uint16_type ())
279 {
280 unsigned int value = val.uint_value ();
282 }
283 else if (val.is_int32_type ())
284 {
285 long int value = val.long_value ();
287 }
288 else if (val.is_uint32_type ())
289 {
290 unsigned long int value = val.ulong_value ();
292 }
293 else if (val.is_int64_type ())
294 {
295 int64_t value = val.int64_value ();
297 }
298 else if (val.is_uint64_type ())
299 {
300 uint64_t value = val.uint64_value ();
302 }
303 else if (val.islogical ())
304 {
305 bool b = val.bool_value ();
306 if (format == "char" || format == "popup" || format == "")
307 {
308 text = Utils::fromStdString (b ? "true" : "false");
309 flag = Qt::AlignLeft;
310 }
311 else if (format == "+")
312 {
313 text = Utils::fromStdString (b ? "+" : "");
314 flag = Qt::AlignLeft;
315 }
316 else
317 text = Utils::fromStdString (b ? "1" : "0");
318 }
319 else
320 {
321 std::stringstream warn_string;
322 warn_string << "Unknown conversion for datatype " << val.class_name ()
323 << " to " << format
324 << " for value " << val.string_value (true);
325 warning ("%s", warn_string.str ().c_str ());
326
327 text = Utils::fromStdString (val.string_value (true));
328 }
329
330 return std::make_pair (flag, text);
331 }
332
333#undef FORMAT_VALUE
334#undef FORMAT_VALUE_EXCEPT_RAT
335#undef FORMAT_UINT_VALUE
336#undef FORMAT_INT_VALUE
337
338 static QTableWidgetItem * itemFor (octave_value val, std::string format = "",
339 bool enabled = false)
340 {
341 QTableWidgetItem *retval = new QTableWidgetItem ();
342 std::pair<Qt::AlignmentFlag, QString> flag_and_text =
343 qStringValueFor (val, format);
344 retval->setTextAlignment (flag_and_text.first);
345 retval->setText (flag_and_text.second);
346
347 if (enabled)
348 retval->setFlags (retval->flags () | Qt::ItemIsEditable);
349 else
350 retval->setFlags (retval->flags () & ~Qt::ItemIsEditable);
351
352 return retval;
353 }
354
355 static octave_value
357 const octave_value& old_value)
358 {
359 octave_value retval;
360
361 // Define a macro to help with the conversion of strings to integers
362 // FIXME: these will happily integer overflow in the (u)int64 case
363 // - this probably doesn't matter.
364#define SCANF_AND_CONVERT(name,ctype,format) \
365 else if (old_value.is_ ## name ## _type ()) \
366 { \
367 ctype val; \
368 int n; \
369 const std::string cxx_str = ov.string_value (); \
370 const char *c_str = cxx_str.c_str (); \
371 int error = sscanf (c_str, format, &val, &n); \
372 if (error != 1 || c_str[n]) \
373 { \
374 val = 0; \
375 } \
376 retval = octave_value ( octave_ ## name (val)); \
377 }
378
379 if (old_value.is_string ())
380 retval = ov;
381 SCANF_AND_CONVERT(int8, int64_t, "%" PRId64 " %n")
382 SCANF_AND_CONVERT(uint8, uint64_t, "%" PRIu64 " %n")
383 SCANF_AND_CONVERT(int16, int64_t, "%" PRId64 " %n")
384 SCANF_AND_CONVERT(uint16, uint64_t, "%" PRIu64 " %n")
385 SCANF_AND_CONVERT(int32, int64_t, "%" PRId64 " %n")
386 SCANF_AND_CONVERT(uint32, uint64_t, "%" PRIu64 " %n")
387 SCANF_AND_CONVERT(int64, int64_t, "%" PRId64 " %n")
388 SCANF_AND_CONVERT(uint64, uint64_t, "%" PRIu64 " %n")
389
390#undef SCANF_AND_CONVERT
391
392 else if (old_value.isnumeric () && ! old_value.isinteger ())
393 {
394 // Basically need to do str2double
396 if (old_value.is_single_type ())
397 retval = octave_value (FloatComplex (complex));
398 else
399 retval = octave_value (complex);
400 }
401 else if (old_value.islogical ())
402 {
403 // Right: Matlab basically needs this to be true or false, we should
404 // accept 1 too.
405 if (ov.string_value () == "true" || ov.string_value () == "1")
406 retval = octave_value (true);
407 else
408 retval = octave_value (false);
409 }
410 else
412 return retval;
413 }
414
415 QWidget *
416 Table::checkBoxForLogical (octave_value val, bool enabled = false)
417 {
418 QWidget *retval = new QWidget (m_tableWidget);
419 QCheckBox *checkBox = new QCheckBox ();
420 QHBoxLayout *layout = new QHBoxLayout (retval);
421 layout->addWidget (checkBox);
422 layout->setAlignment (Qt::AlignCenter);
423 layout->setContentsMargins (0, 0, 0, 0);
424 retval->setLayout (layout);
425
426 if ((val.islogical () || val.is_bool_scalar ()) && val.bool_value ())
427 checkBox->setCheckState (Qt::Checked);
428 else
429 checkBox->setCheckState (Qt::Unchecked);
430
431 checkBox->setAttribute (Qt::WA_TransparentForMouseEvents, true);
432 checkBox->setFocusPolicy (Qt::NoFocus);
433 checkBox->setProperty ("Enabled", QVariant (enabled));
434
435 return retval;
436 }
437
438 Table *
439 Table::create (octave::base_qobject& oct_qobj, octave::interpreter& interp,
440 const graphics_object& go)
441 {
442 Object *parent = parentObject (interp, go);
443
444 if (parent)
445 {
446 Container *container = parent->innerContainer ();
447
448 if (container)
449 return new Table (oct_qobj, interp, go, new QTableWidget (container));
450 }
451
452 return 0;
453 }
454
455 Table::Table (octave::base_qobject& oct_qobj, octave::interpreter& interp,
456 const graphics_object& go, QTableWidget *tableWidget)
457 : Object (oct_qobj, interp, go, tableWidget), m_tableWidget (tableWidget),
458 m_curData (), m_blockUpdates (false)
459 {
460 qObject ()->setObjectName ("UItable");
461 uitable::properties& tp = properties<uitable> ();
462
463 m_curData = octave_value (tp.get_data ());
464 Matrix bb = tp.get_boundingbox (false);
465 m_tableWidget->setObjectName ("UITable");
466 m_tableWidget->setAutoFillBackground (true);
467 m_tableWidget->setGeometry (octave::math::round (bb(0)),
468 octave::math::round (bb(1)),
469 octave::math::round (bb(2)),
470 octave::math::round (bb(3)));
472 m_tableWidget->setSelectionBehavior (QAbstractItemView::SelectItems);
473 updatePalette ();
474 m_keyPressHandlerDefined = ! tp.get_keypressfcn ().isempty ();
475 m_keyReleaseHandlerDefined = ! tp.get_keyreleasefcn ().isempty ();
476 updateData ();
477 updateRowname ();
480 updateEnable (); // Also does rearrangeableColumns
481 m_tableWidget->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
482 m_tableWidget->setVisible (tp.is_visible ());
483 updateExtent ();
484 m_tableWidget->installEventFilter (this);
485
486
487 connect (m_tableWidget, &QTableWidget::itemChanged,
488 this, &Table::itemChanged);
489 connect (m_tableWidget, &QTableWidget::cellClicked,
490 this, &Table::cellClicked);
491 connect (m_tableWidget, &QTableWidget::itemSelectionChanged,
493 }
494
495 Table::~Table (void) { }
496
497 void
499 {
500 if (! (properties<uitable> ().get_cellselectioncallback ().isempty ()))
501 {
502 QModelIndexList modelIndexList =
503 m_tableWidget->selectionModel ()->selectedIndexes ();
504 int length = modelIndexList.size ();
505 Matrix indices = Matrix (length, 2);
506 for (int i = 0; i < length; i++)
507 {
508 indices(i, 0) = modelIndexList.value (i).row () + 1;
509 indices(i, 1) = modelIndexList.value (i).column () + 1;
510 }
511 octave_scalar_map eventData;
512 eventData.setfield ("Indices", indices);
513 octave_value cellSelectionCallbackEventObject (eventData);
514 emit gh_callback_event (m_handle, "cellselectioncallback",
515 cellSelectionCallbackEventObject);
516 }
517 }
518
519 void
520 Table::cellClicked (int row, int col)
521 {
522 QCheckBox *checkBox = nullptr;
523 QWidget *widget
524 = qobject_cast<QWidget *> (m_tableWidget->cellWidget (row, col));
525 if (widget && ! widget->children ().isEmpty ())
526 {
527 QHBoxLayout *layout
528 = qobject_cast<QHBoxLayout *> (widget->children ().first ());
529
530 if (layout && layout->count () > 0)
531 checkBox = qobject_cast<QCheckBox *> (layout->itemAt (0)-> widget ());
532 }
533
534 if (checkBox && checkBox->property ("Enabled").toBool ())
535 checkBoxClicked (row, col, checkBox);
536 }
537
538 void
540 int col,
541 octave_value old_value,
542 octave_value new_value,
543 octave_value edit_data,
545 {
546
547 if (!(properties<uitable> ().get_celleditcallback ().isempty ()))
548 {
549 Matrix indices = Matrix (1, 2);
550 indices(0, 0) = row + 1;
551 indices(0, 1) = col + 1;
552
553 octave_scalar_map eventData;
554 eventData.setfield ("Indices", indices);
555 eventData.setfield ("PreviousData", old_value);
556 eventData.setfield ("NewData", new_value);
557 eventData.setfield ("EditData", edit_data);
558 eventData.setfield ("Error", error);
559
560 octave_value cellEditCallbackEventObject (eventData);
561
562 emit gh_callback_event (m_handle, "celleditcallback",
563 cellEditCallbackEventObject);
564 }
565 else if (error.string_value ().length () > 0)
566 warning ("%s", error.string_value ().c_str ());
567 }
568
569 void
571 {
572 if (m_blockUpdates)
573 return;
574
575 m_blockUpdates = true;
576
577 gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
578
579 octave::autolock guard (gh_mgr.graphics_lock ());
580
582 bool ok = false;
583
584 QComboBox *comboBox = qobject_cast<QComboBox *> (sender ());
585 int row = comboBox->property ("row").toInt ();
586 int col = comboBox->property ("col").toInt ();
587
588 octave_value edit_data = octave_value (Utils::toStdString (value));
589
590 if (row < data.rows () && col < data.columns ())
591 {
592 if (data.iscell ())
593 {
594 Cell cell = data.cell_value ();
595 octave_value old_data = cell(row, col);
596 if (cell(row, col).is_string ())
597 {
598 cell(row, col) = edit_data;
599 if (edit_data.string_value () != old_data.string_value ())
600 {
601 m_curData = octave_value (cell);
602 emit gh_set_event (m_handle, "data", octave_value (cell),
603 false);
604 }
605
607 sendCellEditCallback (row, col,
608 old_data,
609 edit_data,
610 edit_data,
611 error);
612 ok = true;
613 }
614 else
615 {
616 cell(row, col) = attempt_type_conversion (edit_data, old_data);
617
618 // Inform the QTableWidget of our change
619 updateData (row, col, cell(row, col),
620 columnformat (col), columneditable (col));
621
622 m_curData = octave_value (cell);
623 emit gh_set_event (m_handle, "data", octave_value (cell),
624 false);
625
628 col,
629 old_data,
630 cell(row, col),
631 edit_data,
632 error);
633 ok = true;
634 }
635 }
636 else
637 {
638 octave_value old_data = data.is_matrix_type ()
639 ? data.fast_elem_extract (row + col * data.rows ())
640 : octave_value ();
641 data.fast_elem_insert (row + col * data.rows (),
642 attempt_type_conversion (edit_data, old_data));
643
644 // Inform the QTableWidget of our change
645 updateData (row,
646 col,
647 data.fast_elem_extract (row + col * data.rows ()),
648 columnformat (col),
649 columneditable (col));
650
651 m_curData = octave_value (data);
652 emit gh_set_event (m_handle, "data", data, false);
653
656 col,
657 old_data,
658 data.fast_elem_extract (row + col * data.rows ()),
659 edit_data,
660 error);
661 ok = true;
662 }
663 }
664 else
665 {
666 // Reset the QTableWidgetItem
667 updateData (row, col, octave_value (""), columnformat (col),
668 columneditable (col));
669
671 octave_value ("Table data is not editable at this location.");
673 col,
674 octave_value (),
675 octave_value (),
676 edit_data,
677 error);
678 }
679
680 if (! ok)
681 {
682 comboBox->setCurrentIndex (-1);
683 comboBox->setEditable (true);
684 comboBox->setEditText (comboBox->property ("original_value").toString ());
685 comboBox->lineEdit ()->setReadOnly (true);
686 }
687 m_blockUpdates = false;
688 }
689
690 void
691 Table::checkBoxClicked (int row, int col, QCheckBox *checkBox)
692 {
693 if (m_blockUpdates)
694 return;
695 m_blockUpdates = true;
696
697 gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
698
699 octave::autolock guard (gh_mgr.graphics_lock ());
700
701 bool new_value = ! checkBox->isChecked ();
702
704 if (data.islogical ())
705 {
706 // EASY WE JUST CONVERT
707 boolMatrix matrix = data.bool_matrix_value ();
708 if (row < matrix.rows () && col < matrix.columns ())
709 {
710 bool old_value = matrix(row, col);
711 matrix(row, col) = new_value;
712 checkBox->setChecked (new_value);
713 if (new_value != old_value)
714 {
715 m_curData = octave_value (matrix);
716 emit gh_set_event (m_handle, "data", octave_value (matrix),
717 false);
718 }
719
720 sendCellEditCallback (row, col,
721 octave_value (old_value),
722 octave_value (new_value),
723 octave_value (new_value),
724 octave_value (""));
725
726 }
727 else
728 {
730 col,
731 octave_value (),
732 octave_value (),
733 octave_value (new_value),
734 octave_value ("Table data is not editable at this location."));
735 }
736 }
737 else if (data.iscell ())
738 {
739 Cell cell = data.cell_value ();
740 if (row < cell.rows () && col < cell.columns ())
741 {
742 if (cell(row, col).islogical ())
743 {
744 bool old_value = cell(row, col).bool_value ();
745 cell(row, col) = octave_value (new_value);
746 checkBox->setChecked (new_value);
747 if (new_value != old_value)
748 {
749 m_curData = octave_value (cell);
750 emit gh_set_event (m_handle, "data", octave_value (cell),
751 false);
752 }
753
755 col,
756 octave_value (old_value),
757 octave_value (new_value),
758 octave_value (new_value),
759 octave_value (""));
760 }
761 else
762 {
764 col,
765 cell(row, col),
766 octave_value (),
767 octave_value (new_value),
768 octave_value ("Cannot convert logical edit to other type."));
769 }
770 }
771 else
772 {
774 col,
775 cell(row, col),
776 octave_value (),
777 octave_value (new_value),
778 octave_value ("Table data is not editable at this location."));
779 }
780 }
781 else if (data.is_matrix_type ())
782 {
783 if (row < data.rows () && col < data.columns ())
784 {
786 col,
787 data.fast_elem_extract (row + col * data.rows ()),
788 octave_value (),
789 octave_value (new_value),
790 octave_value ("Cannot convert logical edit to other type."));
791 }
792 else
793 {
795 col,
796 data.fast_elem_extract (row + col * data.rows ()),
797 octave_value (),
798 octave_value (new_value),
799 octave_value ("Table data is not editable at this location."));
800 }
801 }
802 m_blockUpdates = false;
803 }
804
805
806 void
807 Table::itemChanged (QTableWidgetItem *item)
808 {
809 if (m_blockUpdates)
810 return;
811 m_blockUpdates = true;
812
813 gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
814
815 octave::autolock guard (gh_mgr.graphics_lock ());
816
818
819 int row = item->row ();
820 int col = item->column ();
821 octave_value edit_data = octave_value (Utils::toStdString (item->text ()));
822 octave_value new_value;
823 octave_value old_value;
824 octave_value new_data;
825
826 if (row < data.rows () && col < data.columns ())
827 {
828 if (data.iscell ())
829 {
830 old_value = data.cell_value () (row, col);
831 }
832 else if (data.is_matrix_type ())
833 {
834 old_value = data.fast_elem_extract (row + col * data.rows ());
835 }
836
837 // Now we need to coerce the new_value in to the type of the old_value
838 if (old_value.is_string ())
839 new_value = edit_data;
840 else
841 {
842 new_value = attempt_type_conversion (edit_data, old_value);
843 std::pair<Qt::AlignmentFlag, QString> flag_and_text =
844 qStringValueFor (new_value, columnformat (col));
845 item->setTextAlignment (flag_and_text.first);
846 item->setText (flag_and_text.second);
847 }
848
849 if (data.iscell ())
850 {
851 Cell cell = data.cell_value ();
852 cell(row, col) = new_value;
853 new_data = octave_value (cell);
854 }
855 else
856 {
857 data.fast_elem_insert (row + col * data.rows (), new_value);
858 new_data = data;
859 }
860 m_curData = octave_value (new_data);
861 emit gh_set_event (m_handle, "data", new_data, false);
862
864 col,
865 octave_value (old_value),
866 octave_value (new_value),
867 octave_value (new_value),
868 octave_value (""));
869 }
870 else
871 {
872 item->setText ("");
873
875 octave_value ("Table data is not editable at this location.");
877 col,
878 octave_value (),
879 octave_value (),
880 edit_data,
881 error);
882 }
883
884 m_blockUpdates = false;
885 }
886
887 void
889 {
890 update (uitable::properties::ID_POSITION);
891 }
892
893 void
895 {
896 uitable::properties& tp = properties<uitable> ();
897
898 switch (pId)
899 {
900 case uitable::properties::ID_BACKGROUNDCOLOR:
901 case uitable::properties::ID_FOREGROUNDCOLOR:
902 updatePalette ();
903 break;
904
905 case uitable::properties::ID_COLUMNNAME:
908 break;
909
910 case uitable::properties::ID_COLUMNWIDTH:
912 break;
913
914 case uitable::properties::ID_COLUMNEDITABLE:
915 case uitable::properties::ID_COLUMNFORMAT:
916 case uitable::properties::ID_DATA:
917 m_blockUpdates = true;
918 m_curData = octave_value (tp.get_data ());
919 updateData ();
920 updateRowname ();
923 updateEnable ();
924 m_blockUpdates = false;
925 break;
926
927 case uitable::properties::ID_ENABLE:
928 updateEnable ();
929 break;
930
931 case uitable::properties::ID_KEYPRESSFCN:
932 m_keyPressHandlerDefined = ! tp.get_keypressfcn ().isempty ();
933 break;
934
935 case uitable::properties::ID_KEYRELEASEFCN:
936 m_keyReleaseHandlerDefined = ! tp.get_keyreleasefcn ().isempty ();
937 break;
938
939 case uitable::properties::ID_FONTNAME:
940 case uitable::properties::ID_FONTSIZE:
941 case uitable::properties::ID_FONTWEIGHT:
942 case uitable::properties::ID_FONTANGLE:
943 if (m_tableWidget)
944 {
946 for (int row = 0; row < m_tableWidget->rowCount (); row++)
947 {
948 m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
949 }
950 }
951 break;
952
953 case uitable::properties::ID_POSITION:
954 {
955 Matrix bb = tp.get_boundingbox (false);
956 m_tableWidget->setGeometry (octave::math::round (bb(0)),
957 octave::math::round (bb(1)),
958 octave::math::round (bb(2)),
959 octave::math::round (bb(3)));
960 updateExtent ();
961 }
962 break;
963
964 case uitable::properties::ID_REARRANGEABLECOLUMNS:
966 break;
967
968 case uitable::properties::ID_ROWNAME:
969 updateRowname ();
970 break;
971
972 case uitable::properties::ID_ROWSTRIPING:
973 updatePalette ();
974 break;
975
976 case uitable::properties::ID_TOOLTIPSTRING:
977 m_tableWidget->setToolTip (Utils::fromStdString (tp.get_tooltipstring ()));
978 break;
979
980 case base_properties::ID_VISIBLE:
981 m_tableWidget->setVisible (tp.is_visible ());
982 break;
983
984 default:
985 break;
986
987 }
988 }
989
990 void
992 {
993 uitable::properties& tp = properties<uitable> ();
994
995 // Reset the Column Count
996 m_tableWidget->setColumnCount (tp.get_data ().columns ());
997
998 octave_value columnname = tp.get_columnname ();
999 QStringList l;
1000 bool visible = true;
1001
1002 if (columnname.is_string () && columnname.string_value (false) == "numbered")
1003 for (int i = 0; i < m_tableWidget->columnCount (); i++)
1004 l << QString::number (i + 1);
1005 else if (columnname.is_string ())
1006 {
1007 if (m_tableWidget->columnCount () > 0)
1008 l << Utils::fromStdString (columnname.string_value ());
1009 for (int i = 1; i < m_tableWidget->columnCount (); i++)
1010 l << "";
1011 }
1012 else if (columnname.isempty ())
1013 {
1014 for (int i = 0; i < m_tableWidget->columnCount (); i++)
1015 l << "";
1016
1017 visible = false;
1018 }
1019 else if (columnname.iscell ())
1020 {
1021 octave_idx_type n = columnname.numel ();
1022 Cell cell_value = columnname.cell_value ();
1023
1024 for (octave_idx_type i = 0; i < n; i++)
1025 {
1026 octave_value v = cell_value (i);
1027 if (v.is_string ())
1028 l << Utils::fromStdString (v.string_value (true));
1029 else if (v.is_matrix_type ())
1030 {
1031 Matrix data = v.matrix_value ();
1032
1033 /* Now Matlab does something very strange here:
1034 * If data is a row or column matrix,
1035 * then each datapoint is added.
1036 * Otherwise, nothing is set.
1037 */
1038 if (data.rows () > 1 && data.cols () > 1)
1039 l << "";
1040 else
1041 for (octave_idx_type j = 0; j < data.numel (); j++)
1042 l << QString::number (data(j));
1043 }
1044 else if (v.isnumeric ())
1045 l << QString::number (v.double_value ());
1046 else
1047 l << QString::number (v.double_value ());
1048 }
1049 }
1050 else if (columnname.is_matrix_type ())
1051 {
1052 octave_idx_type n = columnname.numel ();
1053 Matrix matrix_value = columnname.matrix_value ();
1054
1055 for (octave_idx_type i = 0; i < n; i++)
1056 l << QString::number (matrix_value(i));
1057 }
1058 else
1059 {
1060 for (int i = 0; i < m_tableWidget->columnCount (); i++)
1061 l << "";
1062 visible = false;
1063 }
1064
1065 l.replaceInStrings ("|", "\n");
1066
1067 // Now add the columns as required
1068 if (m_tableWidget->columnCount () < l.length ())
1069 {
1070 int oldColumnCount = m_tableWidget->columnCount ();
1071 m_tableWidget->setColumnCount (l.length ());
1072 for (int col = oldColumnCount; col < l.length (); col++)
1073 {
1074 std::string format = columnformat (col);
1075 bool enabled = columneditable (col);
1076
1077 for (int row = 0; row < m_tableWidget->rowCount (); row++)
1078 updateData (row, col, octave_value (""), format, enabled);
1079 }
1080 }
1081
1082 m_tableWidget->setHorizontalHeaderLabels (l);
1083 m_tableWidget->horizontalHeader ()->setVisible (visible);
1084 }
1085
1086 void
1088 {
1089 uitable::properties& tp = properties<uitable> ();
1090
1091 octave_value columnwidth = tp.get_columnwidth ();
1092 if (columnwidth.isempty ()
1093 || (columnwidth.is_string ()
1094 && columnwidth.string_value (false) == "auto"))
1095 for (int i = 0; i < m_tableWidget->columnCount (); i++)
1096 m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
1097 else if (columnwidth.is_string ()
1098 && columnwidth.string_value (false) == "preferred")
1099 for (int i = 0; i < m_tableWidget->columnCount (); i++)
1100 {
1101 int column_size =
1102 (qobject_cast<QAbstractItemView *> (m_tableWidget))->sizeHintForColumn (i);
1103 int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
1104
1105 if (column_size > header_size)
1106 header_size = column_size;
1107 m_tableWidget->setColumnWidth (i, header_size);
1108 }
1109 else if (columnwidth.iscell ())
1110 {
1111 Cell cell_value = columnwidth.cell_value ();
1112 int i = 0;
1113 for (; i < m_tableWidget->columnCount () && i < cell_value.numel (); i++)
1114 {
1115 octave_value v = cell_value (i);
1116 if (v.is_string () && v.string_value (false) == "auto")
1117 m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
1118 else if (v.is_string () && v.string_value (false) == "preferred")
1119 {
1120 int column_size =
1121 (qobject_cast<QAbstractItemView *> (m_tableWidget))->sizeHintForColumn (i);
1122 int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
1123
1124 if (column_size > header_size)
1125 header_size = column_size;
1126 m_tableWidget->setColumnWidth (i, header_size);
1127 }
1128 else
1129 {
1130 int w = int (v.double_value ());
1131 m_tableWidget->setColumnWidth (i, w);
1132 }
1133 }
1134 for (; i < m_tableWidget->columnCount (); i++)
1135 {
1136 int column_size =
1137 (qobject_cast<QAbstractItemView *> (m_tableWidget))->sizeHintForColumn (i);
1138 int header_size = m_tableWidget->horizontalHeader ()->sectionSizeHint (i);
1139
1140 if (column_size > header_size)
1141 header_size = column_size;
1142 m_tableWidget->setColumnWidth (i, header_size);
1143 }
1144 }
1145 else if (columnwidth.is_matrix_type ())
1146 {
1147 Matrix matrix_value = columnwidth.matrix_value ();
1148 int i = 0;
1149 for (; i < m_tableWidget->columnCount () && i < matrix_value.numel (); i++)
1150 {
1151 octave_value v = matrix_value(i);
1152 int w = int (v.double_value ());
1153 m_tableWidget->setColumnWidth (i, w);
1154 }
1155 for (; i < m_tableWidget->columnCount (); i++)
1156 m_tableWidget->setColumnWidth (i, AUTO_WIDTH);
1157 }
1158 }
1159
1160 bool inline
1162 {
1163 uitable::properties& tp = properties<uitable> ();
1164 boolNDArray columneditable = tp.get_columneditable ().bool_array_value ();
1165 bool editable = false;
1166
1167 if (! columneditable.isempty () && col < columneditable.numel ())
1168 editable = columneditable.xelem (col);
1169 else if (! columneditable.isempty () && columneditable.numel () == 1)
1170 editable = columneditable.xelem (0);
1171
1172 return editable;
1173 }
1174
1175 std::string inline
1177 {
1178 uitable::properties& tp = properties<uitable> ();
1179 std::string format = "";
1180 octave_value ov_columnformat = tp.get_columnformat ();
1181
1182 if (ov_columnformat.iscell ())
1183 {
1184 Cell columnformat = ov_columnformat.cell_value ();
1185 if (! columnformat.isempty () && col < columnformat.numel ())
1186 {
1187 octave_value format_value = columnformat.xelem (col);
1188
1189 if (! format_value.isempty () && format_value.is_string ())
1190 format = format_value.string_value ();
1191 else if (! format_value.isempty () && format_value.iscell ())
1192 format = "popup";
1193 }
1194 }
1195 else if (ov_columnformat.is_string ())
1196 {
1197 format = ov_columnformat.string_value ();
1198 }
1199 return format;
1200 }
1201
1202 void inline
1204 {
1205 octave_value data = properties<uitable> ().get_data ();
1206
1207 std::string format = columnformat (col);
1208 bool is_editable = columneditable (col);
1209
1210 for (octave_idx_type row = 0; row < data.rows (); row++)
1211 updateData (row,
1212 col,
1213 data.iscell ()
1214 ? data.cell_value () (row, col)
1215 : data.fast_elem_extract (row + col * data.rows ()),
1216 format,
1217 is_editable);
1218 }
1219
1220 void inline
1221 Table::updateData (int row, int col)
1222 {
1223 octave_value data = properties<uitable> ().get_data ();
1224 updateData (row,
1225 col,
1226 data.iscell ()
1227 ? data.cell_value () (row, col)
1228 : data.fast_elem_extract (row + col * data.rows ()),
1229 columnformat (col),
1230 columneditable (col));
1231 }
1232
1233 void inline
1234 Table::updateData (int row, int col, octave_value value,
1235 std::string format = "", bool enabled = false)
1236 {
1237 if (format == "logical" || (format == "" && value.islogical ()))
1238 {
1239 if (m_tableWidget->item (row, col))
1240 delete m_tableWidget->item (row, col);
1241
1242 m_tableWidget->setCellWidget (row, col, checkBoxForLogical (value, enabled));
1243 m_tableWidget->cellWidget (row, col)->setProperty ("row", QVariant (row));
1244 m_tableWidget->cellWidget (row, col)->setProperty ("col", QVariant (col));
1245 }
1246 else if (format == "popup" && enabled)
1247 {
1248 if (m_tableWidget->item (row, col))
1249 delete m_tableWidget->item (row, col);
1250
1251 QString string_value = qStringValueFor (value, format).second;
1252 uitable::properties& tp = properties<uitable> ();
1253 octave_value format_value = tp.get_columnformat ().cell_value ().xelem (col);
1254
1255 QComboBox *comboBox = new QComboBox ();
1256 comboBox->setProperty ("row", QVariant (row));
1257 comboBox->setProperty ("col", QVariant (col));
1258
1259 int index = -1;
1260 for (int k = 0; k < format_value.numel (); k++)
1261 {
1262 QString popup_item
1263 = Utils::fromStdString (format_value.fast_elem_extract (k).string_value ());
1264
1265 comboBox->addItem (popup_item);
1266
1267 if (popup_item == string_value)
1268 index = k;
1269 }
1270 comboBox->setCurrentIndex (index);
1271
1272 if (index < 0)
1273 {
1274 comboBox->setEditable (true);
1275 comboBox->setEditText (string_value);
1276 comboBox->lineEdit ()->setReadOnly (true);
1277 }
1278
1279 comboBox->setProperty ("original_value", QVariant (string_value));
1280
1281 comboBox->installEventFilter (this);
1282 m_tableWidget->setCellWidget (row, col, comboBox);
1283 connect (comboBox, SIGNAL(currentIndexChanged (const QString&)),
1284 this, SLOT(comboBoxCurrentIndexChanged (const QString&)));
1285 }
1286 else
1287 {
1288 if (m_tableWidget->cellWidget (row, col))
1289 delete m_tableWidget->cellWidget (row, col);
1290 m_tableWidget->setItem (row, col, itemFor (value, format, enabled));
1291 }
1292 }
1293
1294 void
1296 {
1297 uitable::properties& tp = properties<uitable> ();
1298
1299 octave_value data = tp.get_data ();
1300
1301 if (data.iscell () || data.is_matrix_type ())
1302 {
1303 m_tableWidget->setRowCount (data.rows ());
1304 m_tableWidget->setColumnCount (data.columns ());
1305
1306 for (octave_idx_type col = 0; col < data.columns (); col++)
1307 updateDataColumn (col);
1308 }
1309
1310 for (octave_idx_type row = 0; row < m_tableWidget->rowCount (); row++)
1311 m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
1312 }
1313
1314 void
1316 {
1317 uitable::properties& tp = properties<uitable> ();
1318 bool enabled = tp.is_enable ();
1319 m_tableWidget->setEnabled (enabled);
1320
1321 bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
1322
1323 // Set selection mode
1324 m_tableWidget->setSelectionMode (enabled
1325 ? QAbstractItemView::ExtendedSelection
1326 : QAbstractItemView::NoSelection);
1327
1328 // Set rearrangeablecolumns
1329 m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
1330 m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
1331 m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
1332
1333 // Turn off column editable
1334 for (int col = 0; col < m_tableWidget->columnCount (); col++)
1335 {
1336 bool editable = columneditable (col);
1337
1338 for (int row = 0; row < m_tableWidget->rowCount (); row++)
1339 if (QTableWidgetItem *item = m_tableWidget->item (row, col))
1340 {
1341 Qt::ItemFlags flags = item->flags ();
1342 if (enabled && editable)
1343 item->setFlags (flags | Qt::ItemIsEditable);
1344 else
1345 item->setFlags (flags & ~Qt::ItemIsEditable);
1346 }
1347 else if (QWidget *widget = m_tableWidget->cellWidget (row, col))
1348 {
1349 QCheckBox *checkBox = nullptr;
1350 if (widget && ! widget->children ().isEmpty ())
1351 {
1352 QHBoxLayout *layout
1353 = qobject_cast<QHBoxLayout *> (widget->children ().first ());
1354
1355 if (layout && layout->count () > 0)
1356 checkBox = qobject_cast<QCheckBox *> (layout->itemAt (0)-> widget ());
1357 }
1358
1359 if (checkBox)
1360 widget->setProperty ("Enabled", QVariant (enabled & editable));
1361 else
1362 {
1363 widget->setAttribute (Qt::WA_TransparentForMouseEvents,
1364 !(editable & enabled));
1365
1366 widget->setFocusPolicy (Qt::NoFocus);
1367 }
1368 }
1369 }
1370 }
1371
1372 void
1374 {
1375 QSize s = realQSizeForTable (m_tableWidget);
1376 Matrix extent = Matrix (1, 4);
1377 extent(0, 0) = 0;
1378 extent(0, 1) = 0;
1379 extent(0, 2) = s.width ();
1380 extent(0, 3) = s.height () ;
1381 graphics_object go = object ();
1382 emit gh_set_event (go.get_handle (), "extent", extent, false);
1383 }
1384
1385 void
1387 {
1388 uitable::properties& tp = properties<uitable> ();
1389
1390 QPalette p = m_tableWidget->palette ();
1391 p.setColor (QPalette::Text,
1392 Utils::fromRgb (tp.get_foregroundcolor_rgb ()));
1393 p.setColor (QPalette::Base,
1394 Utils::fromRgb (tp.get_backgroundcolor_rgb ()));
1395 p.setColor (QPalette::AlternateBase,
1396 Utils::fromRgb (tp.get_alternatebackgroundcolor_rgb ()));
1397 m_tableWidget->setPalette (p);
1398 m_tableWidget->setAlternatingRowColors (tp.is_rowstriping ());
1399 // FIXME: Handle multiple alternating background colors
1400 }
1401
1402 void
1404 {
1405 uitable::properties& tp = properties<uitable> ();
1406
1407 // Reset the row count
1408 m_tableWidget->setRowCount (tp.get_data ().rows ());
1409
1410 octave_value rowname = tp.get_rowname ();
1411 QStringList l;
1412 bool visible = true;
1413
1414 if (rowname.is_string () && rowname.string_value (false) == "numbered")
1415 for (int i = 0; i < m_tableWidget->rowCount (); i++)
1416 l << QString::number (i + 1);
1417 else if (rowname.is_string ())
1418 {
1419 if (m_tableWidget->rowCount () > 0)
1420 l << Utils::fromStdString (rowname.string_value ());
1421 for (int i = 1; i < m_tableWidget->rowCount (); i++)
1422 l << "";
1423 }
1424 else if (rowname.isempty ())
1425 {
1426 for (int i = 0; i < m_tableWidget->rowCount (); i++)
1427 l << "";
1428 visible = false;
1429 }
1430 else if (rowname.iscell ())
1431 {
1432 octave_idx_type n = rowname.numel ();
1433 Cell cell_value = rowname.cell_value ();
1434
1435 for (octave_idx_type i = 0; i < n; i++)
1436 {
1437 octave_value v = cell_value (i);
1438 if (v.is_string ())
1439 l << Utils::fromStdString (v.string_value (true));
1440 else if (v.is_matrix_type ())
1441 {
1442 Matrix data = v.matrix_value ();
1443
1444 /* Now Matlab does something very strange here:
1445 * If data is a row or column matrix,
1446 * then each datapoint is added.
1447 * Otherwise, nothing is set.
1448 */
1449 if (data.rows () > 1 && data.cols () > 1)
1450 l << "";
1451 else
1452 for (octave_idx_type j = 0; j < data.numel (); j++)
1453 l << QString::number (data(j));
1454 }
1455 else if (v.isnumeric ())
1456 l << QString::number (v.double_value (true));
1457 else
1458 l << QString::number (v.double_value (true));
1459 }
1460 }
1461 else if (rowname.is_matrix_type ())
1462 {
1463 octave_idx_type n = rowname.numel ();
1464 Matrix matrix_value = rowname.matrix_value ();
1465
1466 for (octave_idx_type i = 0; i < n; i++)
1467 l << QString::number (matrix_value(i));
1468 }
1469 else
1470 {
1471 for (int i = 0; i < m_tableWidget->columnCount (); i++)
1472 l << "";
1473 visible = false;
1474 }
1475
1476 // Add dummy rows as required
1477 if (m_tableWidget->rowCount () < l.length ())
1478 {
1479 int oldRowCount = m_tableWidget->rowCount ();
1480 m_tableWidget->setRowCount (l.length ());
1481
1482 for (int col = 0; col < m_tableWidget->columnCount (); col++)
1483 {
1484 std::string format = columnformat (col);
1485 bool enabled = columneditable (col);
1486
1487 for (int row = oldRowCount; row < l.length (); row++)
1488 {
1489 m_tableWidget->setRowHeight (row, AUTO_HEIGHT);
1490
1491 updateData (row, col, octave_value (""), format, enabled);
1492 }
1493 }
1494 }
1495
1496 m_tableWidget->setVerticalHeaderLabels (l);
1497 m_tableWidget->verticalHeader ()->setVisible (visible);
1498 }
1499
1500 void
1502 {
1503 uitable::properties& tp = properties<uitable> ();
1504
1505 bool rearrangeableColumns = tp.is_rearrangeablecolumns ();
1506 bool enabled = tp.is_enable ();
1507
1508 m_tableWidget->horizontalHeader ()->setSectionsMovable (enabled && rearrangeableColumns);
1509 m_tableWidget->horizontalHeader ()->setDragEnabled (enabled && rearrangeableColumns);
1510 m_tableWidget->horizontalHeader ()->setDragDropMode (QAbstractItemView::InternalMove);
1511 }
1512
1513 bool
1514 Table::eventFilter (QObject *watched, QEvent *xevent)
1515 {
1516 gh_manager& gh_mgr = m_interpreter.get_gh_manager ();
1517
1518 //uitable::properties& tp = properties<uitable> ();
1519 if (qobject_cast<QTableWidget *> (watched))
1520 {
1521 switch (xevent->type ())
1522 {
1523 case QEvent::Resize:
1524 {
1525 octave::autolock guard (gh_mgr.graphics_lock ());
1526
1527 graphics_object go = object ();
1528 if (go.valid_object ())
1529 {
1530 const uitable::properties& tp =
1531 Utils::properties<uitable> (go);
1532 if (tp.fontunits_is ("normalized"))
1534 }
1535 }
1536 break;
1537
1538 case QEvent::MouseButtonPress:
1539 {
1540 octave::autolock guard (gh_mgr.graphics_lock ());
1541
1542 QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
1543 graphics_object go = object ();
1544 const uitable::properties& tp =
1545 Utils::properties<uitable> (go);
1546 graphics_object fig = go.get_ancestor ("figure");
1547
1548 if (m->button () != Qt::LeftButton || ! tp.is_enable ())
1549 {
1550 emit gh_set_event (fig.get_handle (), "selectiontype",
1551 Utils::figureSelectionType (m), false);
1552 emit gh_set_event (fig.get_handle (), "currentpoint",
1554 false);
1555 emit gh_callback_event (fig.get_handle (),
1556 "windowbuttondownfcn");
1557 emit gh_callback_event (m_handle, "buttondownfcn");
1558
1559 if (m->button () == Qt::RightButton)
1561 m->globalPos ());
1562 }
1563 else
1564 {
1565 emit gh_set_event (fig.get_handle (), "selectiontype",
1566 octave_value ("normal"), false);
1567 }
1568 }
1569 break;
1570
1571 case QEvent::KeyPress:
1572 {
1573 QKeyEvent *k = dynamic_cast<QKeyEvent *> (xevent);
1575 {
1576 octave::autolock guard (gh_mgr.graphics_lock ());
1577
1579 graphics_object fig = object ().get_ancestor ("figure");
1580
1581 emit gh_set_event (fig.get_handle (), "currentcharacter",
1582 keyData.getfield ("Character"), false);
1583 emit gh_callback_event (m_handle, "keypressfcn", keyData);
1584 }
1585 int row = m_tableWidget->currentRow ();
1586 int col = m_tableWidget->currentColumn ();
1587 switch (k->key ())
1588 {
1589 case Qt::Key_Space:
1590 {
1591 QCheckBox *checkBox = nullptr;
1592
1593 QWidget *widget
1594 = qobject_cast<QWidget *> (m_tableWidget->cellWidget (row, col));
1595
1596 if (widget && ! widget->children ().isEmpty ())
1597 {
1598 QHBoxLayout *layout
1599 = qobject_cast<QHBoxLayout *> (widget->children ().first ());
1600
1601 if (layout && layout->count () > 0)
1602 checkBox = qobject_cast<QCheckBox *> (layout->itemAt (0)-> widget ());
1603 }
1604
1605 if (checkBox && checkBox->property ("Enabled").toBool ())
1606 checkBoxClicked (row, col, checkBox);
1607
1608 QComboBox *comboBox
1609 = qobject_cast<QComboBox *> (m_tableWidget->cellWidget (row, col));
1610
1611 if (comboBox)
1612 comboBox->showPopup ();
1613 }
1614 break;
1615
1616 case Qt::Key_Return:
1617 case Qt::Key_Enter:
1618 {
1619 if (k->modifiers () == Qt::NoModifier)
1620 {
1621 if (row + 1 < m_tableWidget->rowCount ())
1622 m_tableWidget->setCurrentCell (row + 1, col);
1623 else
1624 {
1625 if (col + 1 < m_tableWidget->columnCount ())
1626 m_tableWidget->setCurrentCell (0, col + 1);
1627 else
1628 m_tableWidget->setCurrentCell (0, 0);
1629 }
1630 }
1631 else if (k->modifiers () == Qt::ShiftModifier)
1632 {
1633 if (row - 1 >= 0)
1634 m_tableWidget->setCurrentCell (row - 1, col);
1635 else
1636 {
1637 if (col - 1 >= 0)
1638 m_tableWidget->setCurrentCell
1639 (m_tableWidget->rowCount () - 1,
1640 col - 1);
1641 else
1642 m_tableWidget->setCurrentCell
1643 (m_tableWidget->rowCount () - 1,
1644 m_tableWidget->columnCount () - 1);
1645 }
1646 }
1647 }
1648 break;
1649
1650 default:
1651 break;
1652 }
1653 }
1654 break;
1655
1656 case QEvent::KeyRelease:
1657 {
1659 {
1660 octave::autolock guard (gh_mgr.graphics_lock ());
1661
1662 QKeyEvent *k = dynamic_cast<QKeyEvent *> (xevent);
1663
1665 graphics_object fig = object ().get_ancestor ("figure");
1666
1667 emit gh_set_event (fig.get_handle (), "currentcharacter",
1668 keyData.getfield ("Character"), false);
1669 emit gh_callback_event (m_handle, "keyreleasefcn", keyData);
1670 }
1671 }
1672 break;
1673
1674 default:
1675 break;
1676 }
1677 }
1678 else if (qobject_cast<QComboBox *> (watched))
1679 {
1680 switch (xevent->type ())
1681 {
1682 case QEvent::MouseButtonPress:
1683 {
1684 octave::autolock guard (gh_mgr.graphics_lock ());
1685
1686 QMouseEvent *m = dynamic_cast<QMouseEvent *> (xevent);
1687 graphics_object go = object ();
1688 const uitable::properties& tp = Utils::properties<uitable> (go);
1689 graphics_object fig = go.get_ancestor ("figure");
1690
1691 if (m->button () != Qt::LeftButton || ! tp.is_enable ())
1692 {
1693 emit gh_set_event (fig.get_handle (), "selectiontype",
1694 Utils::figureSelectionType (m), false);
1695 emit gh_set_event (fig.get_handle (), "currentpoint",
1697 false);
1698 emit gh_callback_event (fig.get_handle (),
1699 "windowbuttondownfcn");
1700 emit gh_callback_event (m_handle, "buttondownfcn");
1701
1702 if (m->button () == Qt::RightButton)
1703 ContextMenu::executeAt (m_interpreter, tp, m->globalPos ());
1704 }
1705 else
1706 {
1707 emit gh_set_event (fig.get_handle (), "selectiontype",
1708 Utils::figureSelectionType (m), false);
1709
1710 QComboBox *comboBox_0 = qobject_cast<QComboBox *> (watched);
1711 for (int row = 0; row < m_tableWidget->rowCount (); row++)
1712 {
1713 for (int col = 0; col < m_tableWidget->columnCount (); col++)
1714 {
1715 QComboBox *comboBox_1
1716 = qobject_cast<QComboBox *> (m_tableWidget->cellWidget (row, col));
1717
1718 if (comboBox_0 == comboBox_1)
1719 m_tableWidget->setCurrentCell (row, col);
1720 }
1721 }
1722 }
1723 }
1724 break;
1725
1726 default:
1727 break;
1728 }
1729 }
1730 return false;
1731 }
1732
1733#undef AUTO_HEIGHT
1734}
#define FORMAT_INT_VALUE()
Definition: Table.cc:180
#define AUTO_HEIGHT
Definition: Table.cc:65
#define SCANF_AND_CONVERT(name, ctype, format)
#define FORMAT_VALUE(f, l)
Definition: Table.cc:158
#define FORMAT_UINT_VALUE()
Definition: Table.cc:168
#define FORMATNUMBER(type)
Definition: Table.cc:78
T & xelem(octave_idx_type n)
Size of the specified dimension.
Definition: Array.h:504
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:411
octave_idx_type cols(void) const
Definition: Array.h:457
octave_idx_type rows(void) const
Definition: Array.h:449
octave_idx_type columns(void) const
Definition: Array.h:458
Definition: Cell.h:43
Definition: dMatrix.h:42
OCTAVE_API RowVector row(octave_idx_type i) const
Definition: dMatrix.cc:416
OCTAVE_API ColumnVector column(octave_idx_type i) const
Definition: dMatrix.cc:422
static void executeAt(octave::interpreter &interp, const base_properties &props, const QPoint &pt)
Definition: ContextMenu.cc:123
virtual Container * innerContainer(void)=0
void gh_callback_event(const graphics_handle &h, const std::string &name)
octave::interpreter & m_interpreter
Definition: Object.h:140
void gh_set_event(const graphics_handle &h, const std::string &name, const octave_value &value)
graphics_handle m_handle
Definition: Object.h:157
virtual QObject * qObject(void)
Definition: Object.h:82
graphics_object object(void) const
Definition: Object.cc:83
static Object * parentObject(octave::interpreter &interp, const graphics_object &go)
Definition: Object.cc:201
base_properties & properties(void)
Definition: Object.h:60
void updateColumnwidth(void)
Definition: Table.cc:1087
~Table(void)
Definition: Table.cc:495
void updatePalette(void)
Definition: Table.cc:1386
void updateExtent(void)
Definition: Table.cc:1373
void updateData(void)
Definition: Table.cc:1295
void updateEnable(void)
Definition: Table.cc:1315
octave_value m_curData
Definition: Table.h:84
static Table * create(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go)
Definition: Table.cc:439
bool m_keyReleaseHandlerDefined
Definition: Table.h:87
void updateRowname(void)
Definition: Table.cc:1403
void updateDataColumn(int col)
Definition: Table.cc:1203
void checkBoxClicked(int row, int col, QCheckBox *checkBox)
Definition: Table.cc:691
Table(octave::base_qobject &oct_qobj, octave::interpreter &interp, const graphics_object &go, QTableWidget *tableWidget)
Definition: Table.cc:455
QWidget * checkBoxForLogical(octave_value cal, bool enabled)
Definition: Table.cc:416
void updateColumnname(void)
Definition: Table.cc:991
bool m_blockUpdates
Definition: Table.h:85
void itemSelectionChanged(void)
Definition: Table.cc:498
void sendCellEditCallback(int row, int col, octave_value old_value, octave_value new_value, octave_value edit_data, octave_value error)
Definition: Table.cc:539
void update(int pId)
Definition: Table.cc:894
bool columneditable(int column)
Definition: Table.cc:1161
void itemChanged(QTableWidgetItem *item)
Definition: Table.cc:807
void cellClicked(int row, int col)
Definition: Table.cc:520
std::string columnformat(int column)
Definition: Table.cc:1176
QTableWidget * m_tableWidget
Definition: Table.h:83
void updateRearrangeableColumns(void)
Definition: Table.cc:1501
void redraw(void)
Definition: Table.cc:888
bool eventFilter(QObject *watched, QEvent *event)
Definition: Table.cc:1514
bool m_keyPressHandlerDefined
Definition: Table.h:86
void comboBoxCurrentIndexChanged(const QString &value)
Definition: Table.cc:570
Base class for Octave interfaces that use Qt.
void setfield(const std::string &key, const octave_value &val)
Definition: oct-map.cc:190
octave_value getfield(const std::string &key) const
Definition: oct-map.cc:183
uint64_t uint64_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:880
bool iscell(void) const
Definition: ov.h:649
bool bool_value(bool warn=false) const
Definition: ov.h:930
bool fast_elem_insert(octave_idx_type n, const octave_value &x)
Assign the n-th element, aka 'val(n) = x'.
Definition: ov.h:1657
int int_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:857
bool is_uint16_type(void) const
Definition: ov.h:766
bool is_bool_scalar(void) const
Definition: ov.h:667
int64_t int64_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:876
short int short_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:850
Complex complex_value(bool frc_str_conv=false) const
Definition: ov.h:910
bool is_int8_type(void) const
Definition: ov.h:751
octave_idx_type rows(void) const
Definition: ov.h:590
bool isnumeric(void) const
Definition: ov.h:795
octave_idx_type numel(void) const
Definition: ov.h:604
unsigned short int ushort_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:854
bool is_string(void) const
Definition: ov.h:682
bool isinteger(void) const
Definition: ov.h:775
bool is_double_type(void) const
Definition: ov.h:740
Cell cell_value(void) const
std::string class_name(void) const
Definition: ov.h:1451
bool is_uint32_type(void) const
Definition: ov.h:769
octave_idx_type columns(void) const
Definition: ov.h:592
bool is_int64_type(void) const
Definition: ov.h:760
float float_value(bool frc_str_conv=false) const
Definition: ov.h:889
unsigned long int ulong_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:872
boolMatrix bool_matrix_value(bool warn=false) const
Definition: ov.h:933
octave_value fast_elem_extract(octave_idx_type n) const
Extract the n-th element, aka 'val(n)'.
Definition: ov.h:1645
std::string string_value(bool force=false) const
Definition: ov.h:1019
bool is_matrix_type(void) const
Definition: ov.h:792
bool is_int32_type(void) const
Definition: ov.h:757
bool is_uint64_type(void) const
Definition: ov.h:772
bool is_int16_type(void) const
Definition: ov.h:754
long int long_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:868
bool isempty(void) const
Definition: ov.h:646
bool is_single_type(void) const
Definition: ov.h:743
bool is_uint8_type(void) const
Definition: ov.h:763
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:898
bool iscomplex(void) const
Definition: ov.h:786
double double_value(bool frc_str_conv=false) const
Definition: ov.h:886
unsigned int uint_value(bool req_int=false, bool frc_str_conv=false) const
Definition: ov.h:861
bool islogical(void) const
Definition: ov.h:780
void warning(const char *fmt,...)
Definition: error.cc:1055
void error(const char *fmt,...)
Definition: error.cc:980
class OCTAVE_API Matrix
Definition: mx-fwd.h:31
std::complex< double > w(std::complex< double > z, double relerr=0)
QColor fromRgb(const Matrix &rgb)
QString fromStdString(const std::string &s)
template QFont computeFont< uitable >(const uitable::properties &props, int height)
std::string figureSelectionType(QMouseEvent *event, bool isDoubleClick)
T::properties & properties(graphics_object obj)
octave_scalar_map makeKeyEventStruct(QKeyEvent *event)
std::string toStdString(const QString &s)
Matrix figureCurrentPoint(const graphics_object &fig, QMouseEvent *event)
double round(double x)
Definition: lo-mappers.h:136
OCTAVE_API Complex str2double(const std::string &str_arg)
Definition: oct-string.cc:462
static QSize realQSizeForTable(QTableWidget *t)
Definition: Table.cc:67
static QString formatNumber(double d, char format='f', int precision=4)
Definition: Table.cc:116
static QString formatComplex(Complex c, char format='f', int precision=4)
Definition: Table.cc:121
static octave_value attempt_type_conversion(const octave_value &ov, const octave_value &old_value)
Definition: Table.cc:356
static QTableWidgetItem * itemFor(octave_value val, std::string format="", bool enabled=false)
Definition: Table.cc:338
static std::pair< Qt::AlignmentFlag, QString > qStringValueFor(octave_value val, std::string format="")
Definition: Table.cc:195
static const int AUTO_WIDTH
Definition: Table.cc:63
std::complex< double > Complex
Definition: oct-cmplx.h:33
std::complex< float > FloatComplex
Definition: oct-cmplx.h:34
std::string rational_approx(T val, int len)
Definition: oct-string.cc:612
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
std::size_t format(std::ostream &os, const char *fmt,...)
Definition: utils.cc:1471