QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgstableeditorwidget.cpp
Go to the documentation of this file.
1 // This file is part of CppSheets.
2 //
3 // Copyright 2018 Patrick Flynn <[email protected]>
4 //
5 // CppSheets is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // CppSheets is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with CppSheets. If not, see <https://www.gnu.org/licenses/>.
17 
18 #include "qgstableeditorwidget.h"
19 #include "qgsnumericformat.h"
20 #include <QStringList>
21 #include <QKeyEvent>
22 #include <QHeaderView>
23 #include <QMenu>
24 #include <QPlainTextEdit>
25 
27  : QTableWidget( parent )
28 {
29  mHeaderMenu = new QMenu( this );
30  setColumnCount( 0 );
31  setRowCount( 0 );
32  connect( this, &QgsTableEditorWidget::cellChanged, this, [ = ]
33  {
34  if ( !mBlockSignals )
35  emit tableChanged();
36  } );
37 
38  horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
39  connect( horizontalHeader(), &QWidget::customContextMenuRequested, this, [ = ]( const QPoint & point )
40  {
41  const int column = horizontalHeader()->logicalIndexAt( point.x() );
42 
43  QSet< int > selectedColumns;
44  for ( const QModelIndex &index : selectedIndexes() )
45  {
46  selectedColumns.insert( index.column() );
47  }
48  int minCol = 0;
49  int maxCol = 0;
50  bool isConsecutive = collectConsecutiveColumnRange( selectedIndexes(), minCol, maxCol );
51 
52  // this is modeled off Libreoffice calc!
53  if ( selectedIndexes().count() == 1 )
54  {
55  // select whole column
56  selectColumn( column );
57  isConsecutive = true;
58  }
59  else if ( !selectedColumns.contains( column ) )
60  {
61  // select whole column
62  selectColumn( column );
63  isConsecutive = true;
64  }
65 
66  mHeaderMenu->clear();
67  if ( isConsecutive )
68  {
69  QAction *insertBefore = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr( "Insert %n Column(s) Before", nullptr, selectedColumns.size() ) : tr( "Insert Column Before" ) );
70  connect( insertBefore, &QAction::triggered, this, &QgsTableEditorWidget::insertColumnsBefore );
71  QAction *insertAfter = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr( "Insert %n Column(s) After", nullptr, selectedColumns.size() ) : tr( "Insert Column After" ) );
72  connect( insertAfter, &QAction::triggered, this, &QgsTableEditorWidget::insertColumnsAfter );
73  }
74  QAction *deleteSelected = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr( "Delete %n Column(s)", nullptr, selectedColumns.size() ) : tr( "Delete Column" ) );
75  connect( deleteSelected, &QAction::triggered, this, &QgsTableEditorWidget::deleteColumns );
76 
77  mHeaderMenu->popup( horizontalHeader()->mapToGlobal( point ) );
78  } );
79 
80  verticalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
81  connect( verticalHeader(), &QWidget::customContextMenuRequested, this, [ = ]( const QPoint & point )
82  {
83  const int row = verticalHeader()->logicalIndexAt( point.y() );
84 
85  QSet< int > selectedRows;
86  for ( const QModelIndex &index : selectedIndexes() )
87  {
88  selectedRows.insert( index.row() );
89  }
90  int minRow = 0;
91  int maxRow = 0;
92  bool isConsecutive = collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow );
93 
94  // this is modeled off Libreoffice calc!
95  if ( selectedIndexes().count() == 1 )
96  {
97  // select whole row
98  selectRow( row );
99  isConsecutive = true;
100  }
101  else if ( !selectedRows.contains( row ) )
102  {
103  // select whole row
104  selectRow( row );
105  isConsecutive = true;
106  }
107 
108  mHeaderMenu->clear();
109  if ( isConsecutive )
110  {
111  QAction *insertBefore = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr( "Insert %n Row(s) Above", nullptr, selectedRows.size() ) : tr( "Insert Row Above" ) );
112  connect( insertBefore, &QAction::triggered, this, &QgsTableEditorWidget::insertRowsAbove );
113  QAction *insertAfter = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr( "Insert %n Row(s) Below", nullptr, selectedRows.size() ) : tr( "Insert Row Below" ) );
114  connect( insertAfter, &QAction::triggered, this, &QgsTableEditorWidget::insertRowsBelow );
115  }
116  QAction *deleteSelected = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr( "Delete %n Row(s)", nullptr, selectedRows.size() ) : tr( "Delete Row" ) );
117  connect( deleteSelected, &QAction::triggered, this, &QgsTableEditorWidget::deleteRows );
118 
119  mHeaderMenu->popup( verticalHeader()->mapToGlobal( point ) );
120  } );
121 
122 
123  QgsTableEditorDelegate *delegate = new QgsTableEditorDelegate( this );
124  connect( delegate, &QgsTableEditorDelegate::updateNumericFormatForIndex, this, &QgsTableEditorWidget::updateNumericFormatForIndex );
125  setItemDelegate( delegate );
126 
127 
128  connect( this, &QTableWidget::cellDoubleClicked, this, [ = ]
129  {
130  if ( QgsTableEditorDelegate *d = qobject_cast< QgsTableEditorDelegate *>( itemDelegate( ) ) )
131  {
132  d->setWeakEditorMode( false );
133  }
134  } );
135 
136  connect( selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsTableEditorWidget::activeCellChanged );
137 }
138 
140 {
141  qDeleteAll( mNumericFormats );
142 }
143 
144 void QgsTableEditorWidget::updateNumericFormatForIndex( const QModelIndex &index )
145 {
146  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
147  {
148  if ( QgsNumericFormat *format = mNumericFormats.value( i ) )
149  {
150  i->setData( Qt::DisplayRole, format->formatDouble( index.data( CellContent ).toDouble(), QgsNumericFormatContext() ) );
151  }
152  }
153 }
154 
155 void QgsTableEditorWidget::updateHeaders()
156 {
157  QStringList headers;
158  QStringList letters;
159 
160  QString first;
161  QString current;
162 
163  for ( char c = 'A'; c <= 'Z'; c++ )
164  {
165  letters.push_back( QString( c ) );
166  }
167 
168  int len = letters.length();
169  int index = 0;
170  int fIndex = 0;
171 
172  for ( int i = 0; i < 1000; i++ )
173  {
174  if ( index == len )
175  {
176  index = 0;
177 
178  first = letters.at( fIndex );
179  fIndex++;
180 
181  if ( fIndex == len )
182  {
183  fIndex = 0;
184  }
185  }
186 
187  current = first;
188  current += letters.at( index );
189  headers.push_back( current );
190  current.clear();
191 
192  index++;
193  }
194 
195  setHorizontalHeaderLabels( headers );
196 
197  headers.clear();
198  if ( mIncludeHeader )
199  headers << tr( "Header" );
200  for ( int i = 1; i <= 1000; i++ )
201  {
202  headers << QString::number( i );
203  }
204 
205  setVerticalHeaderLabels( headers );
206 }
207 
208 bool QgsTableEditorWidget::collectConsecutiveRowRange( const QModelIndexList &list, int &minRow, int &maxRow ) const
209 {
210  QSet< int > includedRows;
211  minRow = std::numeric_limits< int >::max();
212  maxRow = -1;
213  for ( const QModelIndex &index : list )
214  {
215  includedRows.insert( index.row() );
216  minRow = std::min( minRow, index.row() );
217  maxRow = std::max( maxRow, index.row() );
218  }
219 
220  // test that selection is consecutive rows
221  for ( int r = minRow + 1; r < maxRow; r++ )
222  {
223  if ( !includedRows.contains( r ) )
224  return false;
225  }
226  return true;
227 }
228 
229 bool QgsTableEditorWidget::collectConsecutiveColumnRange( const QModelIndexList &list, int &minColumn, int &maxColumn ) const
230 {
231  QSet< int > includedColumns;
232  minColumn = std::numeric_limits< int >::max();
233  maxColumn = -1;
234  for ( const QModelIndex &index : list )
235  {
236  includedColumns.insert( index.column() );
237  minColumn = std::min( minColumn, index.column() );
238  maxColumn = std::max( maxColumn, index.column() );
239  }
240 
241  // test that selection is consecutive columns
242  for ( int r = minColumn + 1; r < maxColumn; r++ )
243  {
244  if ( !includedColumns.contains( r ) )
245  return false;
246  }
247  return true;
248 }
249 
250 QList<int> QgsTableEditorWidget::collectUniqueRows( const QModelIndexList &list ) const
251 {
252  QList<int > res;
253  for ( const QModelIndex &index : list )
254  {
255  if ( !res.contains( index.row() ) )
256  res << index.row();
257  }
258  std::sort( res.begin(), res.end() );
259  return res;
260 }
261 
262 QList<int> QgsTableEditorWidget::collectUniqueColumns( const QModelIndexList &list ) const
263 {
264  QList<int > res;
265  for ( const QModelIndex &index : list )
266  {
267  if ( !res.contains( index.column() ) )
268  res << index.column();
269  }
270  std::sort( res.begin(), res.end() );
271  return res;
272 }
273 
274 void QgsTableEditorWidget::keyPressEvent( QKeyEvent *event )
275 {
276  switch ( event->key() )
277  {
278  case Qt::Key_Enter:
279  case Qt::Key_Return:
280  {
281  //Enter or return keys moves to next row
282  QTableWidget::keyPressEvent( event );
283  setCurrentCell( currentRow() + 1, currentColumn() );
284  break;
285  }
286 
287  case Qt::Key_Delete:
288  {
290  break;
291  }
292 
293  default:
294  QTableWidget::keyPressEvent( event );
295  }
296  if ( QgsTableEditorDelegate *d = qobject_cast< QgsTableEditorDelegate *>( itemDelegate( ) ) )
297  {
298  d->setWeakEditorMode( true );
299  }
300 }
301 
303 {
304  mBlockSignals++;
305  qDeleteAll( mNumericFormats );
306  mNumericFormats.clear();
307 
308  QgsNumericFormatContext numericContext;
309  int rowNumber = mIncludeHeader ? 1 : 0;
310  bool first = true;
311  setRowCount( contents.size() + rowNumber );
312  for ( const QgsTableRow &row : contents )
313  {
314  if ( first )
315  {
316  setColumnCount( row.size() );
317  first = false;
318  }
319 
320  int colNumber = 0;
321  for ( const QgsTableCell &col : row )
322  {
323  QTableWidgetItem *item = new QTableWidgetItem( col.content().value< QgsProperty >().isActive() ? col.content().value< QgsProperty >().asExpression() : col.content().toString() );
324  item->setData( CellContent, col.content() ); // can't use EditRole, because Qt. (https://bugreports.qt.io/browse/QTBUG-11549)
325  item->setData( Qt::BackgroundRole, col.backgroundColor().isValid() ? col.backgroundColor() : QColor( 255, 255, 255 ) );
326  item->setData( PresetBackgroundColorRole, col.backgroundColor().isValid() ? col.backgroundColor() : QVariant() );
327  item->setData( Qt::ForegroundRole, col.textFormat().isValid() ? col.textFormat().color() : QVariant() );
328  item->setData( TextFormat, QVariant::fromValue( col.textFormat() ) );
329  item->setData( HorizontalAlignment, static_cast< int >( col.horizontalAlignment() ) );
330  item->setData( VerticalAlignment, static_cast< int >( col.verticalAlignment() ) );
331  item->setData( CellProperty, QVariant::fromValue( col.content().value< QgsProperty >() ) );
332 
333  if ( col.content().value< QgsProperty >().isActive() )
334  item->setFlags( item->flags() & ( ~Qt::ItemIsEditable ) );
335 
336  if ( auto *lNumericFormat = col.numericFormat() )
337  {
338  mNumericFormats.insert( item, lNumericFormat->clone() );
339  item->setData( Qt::DisplayRole, mNumericFormats.value( item )->formatDouble( col.content().toDouble(), numericContext ) );
340  }
341  setItem( rowNumber, colNumber, item );
342  colNumber++;
343  }
344  rowNumber++;
345  }
346 
347  mBlockSignals--;
348  updateHeaders();
349 
350  if ( mFirstSet )
351  {
352  resizeColumnsToContents();
353  resizeRowsToContents();
354  mFirstSet = false;
355  }
356  emit tableChanged();
357 }
358 
360 {
361  QgsTableContents items;
362  items.reserve( rowCount() );
363 
364  for ( int r = mIncludeHeader ? 1 : 0; r < rowCount(); r++ )
365  {
366  QgsTableRow row;
367  row.reserve( columnCount() );
368  for ( int c = 0; c < columnCount(); c++ )
369  {
370  QgsTableCell cell;
371  if ( QTableWidgetItem *i = item( r, c ) )
372  {
373  cell.setContent( i->data( CellProperty ).value< QgsProperty >().isActive() ? i->data( CellProperty ) : i->data( CellContent ) );
374  cell.setBackgroundColor( i->data( PresetBackgroundColorRole ).value< QColor >() );
375  cell.setTextFormat( i->data( TextFormat ).value< QgsTextFormat >() );
376  cell.setHorizontalAlignment( static_cast< Qt::Alignment >( i->data( HorizontalAlignment ).toInt() ) );
377  cell.setVerticalAlignment( static_cast< Qt::Alignment >( i->data( VerticalAlignment ).toInt() ) );
378 
379  if ( mNumericFormats.value( i ) )
380  {
381  cell.setNumericFormat( mNumericFormats.value( i )->clone() );
382  }
383  }
384  row.push_back( cell );
385  }
386  items.push_back( row );
387  }
388 
389  return items;
390 }
391 
393 {
394  bool changed = false;
395  mBlockSignals++;
396  std::unique_ptr< QgsNumericFormat > newFormat( format );
397  const QModelIndexList selection = selectedIndexes();
398  QgsNumericFormatContext numericContext;
399  for ( const QModelIndex &index : selection )
400  {
401  if ( index.row() == 0 && mIncludeHeader )
402  continue;
403 
404  QTableWidgetItem *i = item( index.row(), index.column() );
405  if ( !i )
406  {
407  i = new QTableWidgetItem();
408  setItem( index.row(), index.column(), i );
409  }
410  if ( !mNumericFormats.value( i ) && newFormat )
411  {
412  changed = true;
413  mNumericFormats.insert( i, newFormat->clone() );
414  }
415  else if ( mNumericFormats.value( i ) && !newFormat )
416  {
417  changed = true;
418  delete mNumericFormats.value( i );
419  mNumericFormats.remove( i );
420  }
421  else if ( newFormat && *newFormat != *mNumericFormats.value( i ) )
422  {
423  changed = true;
424  delete mNumericFormats.value( i );
425  mNumericFormats.insert( i, newFormat->clone() );
426  }
427  i->setData( Qt::DisplayRole, newFormat ? mNumericFormats.value( i )->formatDouble( i->data( CellContent ).toDouble(), numericContext ) : i->data( CellContent ) );
428  }
429  mBlockSignals--;
430  if ( changed && !mBlockSignals )
431  emit tableChanged();
432 }
433 
435 {
436  QgsNumericFormat *f = nullptr;
437  bool first = true;
438  const QModelIndexList selection = selectedIndexes();
439  for ( const QModelIndex &index : selection )
440  {
441  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
442  {
443  if ( first )
444  {
445  f = mNumericFormats.value( i );
446  first = false;
447  }
448  else if ( ( !f && !mNumericFormats.value( i ) )
449  || ( f && mNumericFormats.value( i ) && *f == *mNumericFormats.value( i ) ) )
450  continue;
451  else
452  {
453  return nullptr;
454  }
455  }
456  else
457  {
458  return nullptr;
459  }
460  }
461  return f;
462 }
463 
465 {
466  QgsNumericFormat *f = nullptr;
467  bool first = true;
468  const QModelIndexList selection = selectedIndexes();
469  for ( const QModelIndex &index : selection )
470  {
471  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
472  {
473  if ( first )
474  {
475  f = mNumericFormats.value( i );
476  first = false;
477  }
478  else if ( ( !f && !mNumericFormats.value( i ) )
479  || ( f && mNumericFormats.value( i ) && *f == *mNumericFormats.value( i ) ) )
480  continue;
481  else
482  {
483  return true;
484  }
485  }
486  else if ( f )
487  {
488  return true;
489  }
490  }
491  return false;
492 }
493 
495 {
497  return f.isValid() ? f.color() : QColor();
498 }
499 
501 {
502  QColor c;
503  bool first = true;
504  const QModelIndexList selection = selectedIndexes();
505  for ( const QModelIndex &index : selection )
506  {
507  QColor indexColor = model()->data( index, PresetBackgroundColorRole ).isValid() ? model()->data( index, PresetBackgroundColorRole ).value< QColor >() : QColor();
508  if ( first )
509  {
510  c = indexColor;
511  first = false;
512  }
513  else if ( indexColor == c )
514  continue;
515  else
516  {
517  return QColor();
518  }
519  }
520  return c;
521 }
522 
524 {
525  Qt::Alignment alignment = Qt::AlignLeft;
526  bool first = true;
527  const QModelIndexList selection = selectedIndexes();
528  for ( const QModelIndex &index : selection )
529  {
530  Qt::Alignment cellAlign = static_cast< Qt::Alignment >( model()->data( index, HorizontalAlignment ).toInt() );
531  if ( first )
532  {
533  alignment = cellAlign;
534  first = false;
535  }
536  else if ( cellAlign == alignment )
537  continue;
538  else
539  {
540  return Qt::AlignLeft | Qt::AlignTop;
541  }
542  }
543  return alignment;
544 }
545 
547 {
548  Qt::Alignment alignment = Qt::AlignVCenter;
549  bool first = true;
550  const QModelIndexList selection = selectedIndexes();
551  for ( const QModelIndex &index : selection )
552  {
553  Qt::Alignment cellAlign = static_cast< Qt::Alignment >( model()->data( index, VerticalAlignment ).toInt() );
554  if ( first )
555  {
556  alignment = cellAlign;
557  first = false;
558  }
559  else if ( cellAlign == alignment )
560  continue;
561  else
562  {
563  return Qt::AlignLeft | Qt::AlignTop;
564  }
565  }
566  return alignment;
567 }
568 
570 {
571  QgsProperty property;
572  bool first = true;
573  const QModelIndexList selection = selectedIndexes();
574  for ( const QModelIndex &index : selection )
575  {
576  const QgsProperty cellProperty = model()->data( index, CellProperty ).value< QgsProperty >();
577  if ( first )
578  {
579  property = cellProperty;
580  first = false;
581  }
582  else if ( cellProperty == property )
583  continue;
584  else
585  {
586  return QgsProperty();
587  }
588  }
589  return property;
590 }
591 
593 {
594  QgsTextFormat format;
595  bool first = true;
596  const QModelIndexList selection = selectedIndexes();
597  for ( const QModelIndex &index : selection )
598  {
599  if ( !model()->data( index, TextFormat ).isValid() )
600  return QgsTextFormat();
601 
602  QgsTextFormat cellFormat = model()->data( index, TextFormat ).value< QgsTextFormat >();
603  if ( first )
604  {
605  format = cellFormat;
606  first = false;
607  }
608  else if ( cellFormat == format )
609  continue;
610  else
611  return QgsTextFormat();
612  }
613  return format;
614 }
615 
617 {
618  double height = 0;
619  bool first = true;
620  const QModelIndexList selection = selectedIndexes();
621  for ( const QModelIndex &index : selection )
622  {
623  double thisHeight = tableRowHeight( index.row() );
624  if ( first )
625  height = thisHeight;
626  else if ( thisHeight != height )
627  {
628  return -1;
629  }
630  first = false;
631  }
632  return height;
633 }
634 
636 {
637  double width = 0;
638  bool first = true;
639  const QModelIndexList selection = selectedIndexes();
640  for ( const QModelIndex &index : selection )
641  {
642  double thisWidth = tableColumnWidth( index.column() );
643  if ( first )
644  width = thisWidth;
645  else if ( thisWidth != width )
646  {
647  return -1;
648  }
649  first = false;
650  }
651  return width;
652 }
653 
655 {
656  double height = 0;
657  for ( int col = 0; col < columnCount(); ++col )
658  {
659  double thisHeight = model()->data( model()->index( row + ( mIncludeHeader ? 1 : 0 ), col ), RowHeight ).toDouble();
660  height = std::max( thisHeight, height );
661  }
662  return height;
663 }
664 
666 {
667  double width = 0;
668  for ( int row = 0; row < rowCount(); ++row )
669  {
670  double thisWidth = model()->data( model()->index( row, column ), ColumnWidth ).toDouble();
671  width = std::max( thisWidth, width );
672  }
673  return width;
674 }
675 
676 void QgsTableEditorWidget::setTableRowHeight( int row, double height )
677 {
678  if ( row == 0 && mIncludeHeader )
679  return;
680 
681  bool changed = false;
682  mBlockSignals++;
683 
684  for ( int col = 0; col < columnCount(); ++col )
685  {
686  if ( QTableWidgetItem *i = item( row + ( mIncludeHeader ? 1 : 0 ), col ) )
687  {
688  if ( i->data( RowHeight ).toDouble() != height )
689  {
690  i->setData( RowHeight, height );
691  changed = true;
692  }
693  }
694  else
695  {
696  QTableWidgetItem *newItem = new QTableWidgetItem();
697  newItem->setData( RowHeight, height );
698  setItem( row + ( mIncludeHeader ? 1 : 0 ), col, newItem );
699  changed = true;
700  }
701  }
702 
703  mBlockSignals--;
704  if ( changed && !mBlockSignals )
705  emit tableChanged();
706 }
707 
708 void QgsTableEditorWidget::setTableColumnWidth( int col, double width )
709 {
710  bool changed = false;
711  mBlockSignals++;
712  for ( int row = 0; row < rowCount(); ++row )
713  {
714  if ( QTableWidgetItem *i = item( row, col ) )
715  {
716  if ( i->data( ColumnWidth ).toDouble() != width )
717  {
718  i->setData( ColumnWidth, width );
719  changed = true;
720  }
721  }
722  else
723  {
724  QTableWidgetItem *newItem = new QTableWidgetItem();
725  newItem->setData( ColumnWidth, width );
726  setItem( row, col, newItem );
727  changed = true;
728  }
729  }
730  mBlockSignals--;
731  if ( changed && !mBlockSignals )
732  emit tableChanged();
733 }
734 
736 {
737  return collectUniqueRows( selectedIndexes() );
738 }
739 
741 {
742  return collectUniqueColumns( selectedIndexes() );
743 }
744 
746 {
747  if ( !mIncludeHeader )
748  return QVariantList();
749 
750  QVariantList res;
751  res.reserve( columnCount() );
752  for ( int col = 0; col < columnCount(); ++col )
753  {
754  if ( QTableWidgetItem *i = item( 0, col ) )
755  {
756  res << i->data( CellContent );
757  }
758  else
759  {
760  res << QVariant();
761  }
762  }
763  return res;
764 }
765 
767 {
768  if ( !mIncludeHeader )
769  return false;
770 
771  return collectUniqueRows( selectedIndexes() ).contains( 0 );
772 }
773 
775 {
776  if ( rowCount() == 0 )
777  {
778  insertRow( 0 );
779  return;
780  }
781 
782  int minRow = 0;
783  int maxRow = 0;
784  if ( !collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow ) )
785  return;
786 
787  const int rowsToInsert = maxRow - minRow + 1;
788  for ( int i = 0; i < rowsToInsert; ++i )
789  insertRow( maxRow + 1 );
790 
791  updateHeaders();
792  if ( !mBlockSignals )
793  emit tableChanged();
794 }
795 
797 {
798  if ( rowCount() == 0 )
799  {
800  insertRow( 0 );
801  return;
802  }
803 
804  int minRow = 0;
805  int maxRow = 0;
806  if ( !collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow ) )
807  return;
808 
809  const int rowsToInsert = maxRow - minRow + 1;
810  for ( int i = 0; i < rowsToInsert; ++i )
811  insertRow( minRow );
812 
813  updateHeaders();
814  if ( !mBlockSignals )
815  emit tableChanged();
816 }
817 
819 {
820  if ( columnCount() == 0 )
821  {
822  insertColumn( 0 );
823  return;
824  }
825 
826  int minColumn = 0;
827  int maxColumn = 0;
828  if ( !collectConsecutiveColumnRange( selectedIndexes(), minColumn, maxColumn ) )
829  return;
830 
831  const int columnsToInsert = maxColumn - minColumn + 1;
832  for ( int i = 0; i < columnsToInsert; ++i )
833  insertColumn( minColumn );
834 
835  updateHeaders();
836  if ( !mBlockSignals )
837  emit tableChanged();
838 }
839 
841 {
842  if ( columnCount() == 0 )
843  {
844  insertColumn( 0 );
845  return;
846  }
847 
848  int minColumn = 0;
849  int maxColumn = 0;
850  if ( !collectConsecutiveColumnRange( selectedIndexes(), minColumn, maxColumn ) )
851  return;
852 
853  const int columnsToInsert = maxColumn - minColumn + 1;
854  for ( int i = 0; i < columnsToInsert; ++i )
855  insertColumn( maxColumn + 1 );
856 
857  updateHeaders();
858  if ( !mBlockSignals )
859  emit tableChanged();
860 }
861 
863 {
864  const QList< int > rows = rowsAssociatedWithSelection();
865  if ( rows.empty() )
866  return;
867 
868  bool changed = false;
869  for ( int i = rows.size() - 1; i >= 0 && rowCount() > 1; i-- )
870  {
871  removeRow( rows.at( i ) );
872  changed = true;
873  }
874  updateHeaders();
875  if ( changed && !mBlockSignals )
876  emit tableChanged();
877 }
878 
880 {
881  const QList< int > columns = columnsAssociatedWithSelection();
882  if ( columns.empty() )
883  return;
884 
885  bool changed = false;
886  for ( int i = columns.size() - 1; i >= 0 && columnCount() > 1; i-- )
887  {
888  removeColumn( columns.at( i ) );
889  changed = true;
890  }
891  updateHeaders();
892  if ( !mBlockSignals && changed )
893  emit tableChanged();
894 }
895 
897 {
898  const QModelIndexList s = selectedIndexes();
899  for ( const QModelIndex &index : s )
900  {
901  selectionModel()->select( index, QItemSelectionModel::Rows | QItemSelectionModel::Select );
902  }
903 }
904 
906 {
907  const QModelIndexList s = selectedIndexes();
908  for ( const QModelIndex &index : s )
909  {
910  selectionModel()->select( index, QItemSelectionModel::Columns | QItemSelectionModel::Select );
911  }
912 }
913 
915 {
916  const QModelIndexList selection = selectedIndexes();
917  bool changed = false;
918  mBlockSignals++;
919  for ( const QModelIndex &index : selection )
920  {
921  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
922  {
923  i->setText( QString() );
924  i->setData( CellContent, QVariant() );
925  changed = true;
926  }
927  }
928  mBlockSignals--;
929  if ( changed && !mBlockSignals )
930  emit tableChanged();
931 }
932 
934 {
935  const QModelIndexList selection = selectedIndexes();
936  bool changed = false;
937  mBlockSignals++;
938  for ( const QModelIndex &index : selection )
939  {
940  if ( index.row() == 0 && mIncludeHeader )
941  continue;
942 
943  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
944  {
945  if ( i->data( Qt::ForegroundRole ).value< QColor >() != color )
946  {
947  i->setData( Qt::ForegroundRole, color.isValid() ? color : QVariant() );
948  QgsTextFormat f = i->data( TextFormat ).value< QgsTextFormat >();
949  f.setColor( color );
950  i->setData( TextFormat, QVariant::fromValue( f ) );
951  changed = true;
952  }
953  }
954  else
955  {
956  QTableWidgetItem *newItem = new QTableWidgetItem();
957  newItem->setData( Qt::ForegroundRole, color.isValid() ? color : QVariant() );
958  QgsTextFormat f;
959  f.setColor( color );
960  newItem->setData( TextFormat, QVariant::fromValue( f ) );
961  setItem( index.row(), index.column(), newItem );
962  changed = true;
963  }
964  }
965  mBlockSignals--;
966  if ( changed && !mBlockSignals )
967  emit tableChanged();
968 }
969 
971 {
972  const QModelIndexList selection = selectedIndexes();
973  bool changed = false;
974  mBlockSignals++;
975  for ( const QModelIndex &index : selection )
976  {
977  if ( index.row() == 0 && mIncludeHeader )
978  continue;
979 
980  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
981  {
982  if ( i->data( PresetBackgroundColorRole ).value< QColor >() != color )
983  {
984  i->setData( Qt::BackgroundRole, color.isValid() ? color : QVariant() );
985  i->setData( PresetBackgroundColorRole, color.isValid() ? color : QVariant() );
986  changed = true;
987  }
988  }
989  else
990  {
991  QTableWidgetItem *newItem = new QTableWidgetItem();
992  newItem->setData( Qt::BackgroundRole, color.isValid() ? color : QVariant() );
993  newItem->setData( PresetBackgroundColorRole, color.isValid() ? color : QVariant() );
994  setItem( index.row(), index.column(), newItem );
995  changed = true;
996  }
997  }
998  mBlockSignals--;
999  if ( changed && !mBlockSignals )
1000  emit tableChanged();
1001 }
1002 
1004 {
1005  const QModelIndexList selection = selectedIndexes();
1006  bool changed = false;
1007  mBlockSignals++;
1008  for ( const QModelIndex &index : selection )
1009  {
1010  if ( index.row() == 0 && mIncludeHeader )
1011  continue;
1012 
1013  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1014  {
1015  if ( static_cast< Qt::Alignment >( i->data( HorizontalAlignment ).toInt() ) != alignment )
1016  {
1017  i->setData( HorizontalAlignment, static_cast< int >( alignment ) );
1018  changed = true;
1019  }
1020  }
1021  else
1022  {
1023  QTableWidgetItem *newItem = new QTableWidgetItem();
1024  newItem->setData( HorizontalAlignment, static_cast< int >( alignment ) );
1025  setItem( index.row(), index.column(), newItem );
1026  changed = true;
1027  }
1028  }
1029  mBlockSignals--;
1030  if ( changed && !mBlockSignals )
1031  emit tableChanged();
1032 }
1033 
1035 {
1036  const QModelIndexList selection = selectedIndexes();
1037  bool changed = false;
1038  mBlockSignals++;
1039  for ( const QModelIndex &index : selection )
1040  {
1041  if ( index.row() == 0 && mIncludeHeader )
1042  continue;
1043 
1044  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1045  {
1046  if ( static_cast< Qt::Alignment >( i->data( HorizontalAlignment ).toInt() ) != alignment )
1047  {
1048  i->setData( VerticalAlignment, static_cast< int >( alignment ) );
1049  changed = true;
1050  }
1051  }
1052  else
1053  {
1054  QTableWidgetItem *newItem = new QTableWidgetItem();
1055  newItem->setData( VerticalAlignment, static_cast< int >( alignment ) );
1056  setItem( index.row(), index.column(), newItem );
1057  changed = true;
1058  }
1059  }
1060  mBlockSignals--;
1061  if ( changed && !mBlockSignals )
1062  emit tableChanged();
1063 }
1064 
1066 {
1067  const QModelIndexList selection = selectedIndexes();
1068  bool changed = false;
1069  mBlockSignals++;
1070  for ( const QModelIndex &index : selection )
1071  {
1072  if ( index.row() == 0 && mIncludeHeader )
1073  continue;
1074 
1075  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1076  {
1077  if ( i->data( CellProperty ).value< QgsProperty >() != property )
1078  {
1079  if ( property.isActive() )
1080  {
1081  i->setData( CellProperty, QVariant::fromValue( property ) );
1082  i->setText( property.asExpression() );
1083  i->setFlags( i->flags() & ( ~Qt::ItemIsEditable ) );
1084  }
1085  else
1086  {
1087  i->setData( CellProperty, QVariant() );
1088  i->setText( QString() );
1089  i->setFlags( i->flags() | Qt::ItemIsEditable );
1090  }
1091  changed = true;
1092  }
1093  }
1094  else
1095  {
1096  QTableWidgetItem *newItem = new QTableWidgetItem( property.asExpression() );
1097  if ( property.isActive() )
1098  {
1099  newItem->setData( CellProperty, QVariant::fromValue( property ) );
1100  newItem->setFlags( newItem->flags() & ( ~Qt::ItemIsEditable ) );
1101  }
1102  else
1103  {
1104  newItem->setData( CellProperty, QVariant() );
1105  newItem->setFlags( newItem->flags() | Qt::ItemIsEditable );
1106  }
1107  setItem( index.row(), index.column(), newItem );
1108  changed = true;
1109  }
1110  }
1111  mBlockSignals--;
1112  if ( changed && !mBlockSignals )
1113  emit tableChanged();
1114 }
1115 
1117 {
1118  const QModelIndexList selection = selectedIndexes();
1119  bool changed = false;
1120  mBlockSignals++;
1121  for ( const QModelIndex &index : selection )
1122  {
1123  if ( index.row() == 0 && mIncludeHeader )
1124  continue;
1125 
1126  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1127  {
1128  i->setData( TextFormat, QVariant::fromValue( format ) );
1129  i->setData( Qt::ForegroundRole, format.color() );
1130  changed = true;
1131  }
1132  else
1133  {
1134  QTableWidgetItem *newItem = new QTableWidgetItem();
1135  newItem->setData( TextFormat, QVariant::fromValue( format ) );
1136  newItem->setData( Qt::ForegroundRole, format.color() );
1137  setItem( index.row(), index.column(), newItem );
1138  changed = true;
1139  }
1140  }
1141  mBlockSignals--;
1142  if ( changed && !mBlockSignals )
1143  emit tableChanged();
1144 }
1145 
1147 {
1148  bool changed = false;
1149  mBlockSignals++;
1150  const QList< int > rows = rowsAssociatedWithSelection();
1151  for ( int row : rows )
1152  {
1153  if ( row == 0 && mIncludeHeader )
1154  continue;
1155 
1156  for ( int col = 0; col < columnCount(); ++col )
1157  {
1158  if ( QTableWidgetItem *i = item( row, col ) )
1159  {
1160  if ( i->data( RowHeight ).toDouble() != height )
1161  {
1162  i->setData( RowHeight, height );
1163  changed = true;
1164  }
1165  }
1166  else
1167  {
1168  QTableWidgetItem *newItem = new QTableWidgetItem();
1169  newItem->setData( RowHeight, height );
1170  setItem( row, col, newItem );
1171  changed = true;
1172  }
1173  }
1174  }
1175  mBlockSignals--;
1176  if ( changed && !mBlockSignals )
1177  emit tableChanged();
1178 }
1179 
1181 {
1182  bool changed = false;
1183  mBlockSignals++;
1184  const QList< int > cols = columnsAssociatedWithSelection();
1185  for ( int col : cols )
1186  {
1187  for ( int row = 0; row < rowCount(); ++row )
1188  {
1189  if ( QTableWidgetItem *i = item( row, col ) )
1190  {
1191  if ( i->data( ColumnWidth ).toDouble() != width )
1192  {
1193  i->setData( ColumnWidth, width );
1194  changed = true;
1195  }
1196  }
1197  else
1198  {
1199  QTableWidgetItem *newItem = new QTableWidgetItem();
1200  newItem->setData( ColumnWidth, width );
1201  setItem( row, col, newItem );
1202  changed = true;
1203  }
1204  }
1205  }
1206  mBlockSignals--;
1207  if ( changed && !mBlockSignals )
1208  emit tableChanged();
1209 }
1210 
1212 {
1213  if ( included == mIncludeHeader )
1214  return;
1215 
1216  mIncludeHeader = included;
1217 
1218  if ( mIncludeHeader )
1219  insertRow( 0 );
1220  else
1221  removeRow( 0 );
1222  updateHeaders();
1223 }
1224 
1225 void QgsTableEditorWidget::setTableHeaders( const QVariantList &headers )
1226 {
1227  if ( !mIncludeHeader )
1228  return;
1229 
1230  mBlockSignals++;
1231 
1232  for ( int col = 0; col < columnCount(); ++col )
1233  {
1234  if ( QTableWidgetItem *i = item( 0, col ) )
1235  {
1236  i->setText( headers.value( col ).toString() );
1237  i->setData( CellContent, headers.value( col ) ); // can't use EditRole, because Qt. (https://bugreports.qt.io/browse/QTBUG-11549)
1238  }
1239  else
1240  {
1241  QTableWidgetItem *item = new QTableWidgetItem( headers.value( col ).toString() );
1242  item->setData( CellContent, headers.value( col ) ); // can't use EditRole, because Qt. (https://bugreports.qt.io/browse/QTBUG-11549)
1243  setItem( 0, col, item );
1244  }
1245  }
1246  mBlockSignals--;
1247 }
1248 
1250 
1251 QgsTableEditorTextEdit::QgsTableEditorTextEdit( QWidget *parent )
1252  : QPlainTextEdit( parent )
1253 {
1254  // narrower default margins
1255  document()->setDocumentMargin( document()->documentMargin() / 2 );
1256 
1257  connect( this, &QPlainTextEdit::textChanged, this, &QgsTableEditorTextEdit::resizeToContents );
1258  updateMinimumSize();
1259 }
1260 
1261 void QgsTableEditorTextEdit::keyPressEvent( QKeyEvent *event )
1262 {
1263  switch ( event->key() )
1264  {
1265  case Qt::Key_Enter:
1266  case Qt::Key_Return:
1267  {
1268  if ( event->modifiers() & Qt::ControlModifier )
1269  {
1270  // ctrl+enter inserts a line break
1271  insertPlainText( QString( '\n' ) );
1272  resizeToContents();
1273  }
1274  else
1275  {
1276  // closes editor
1277  event->ignore();
1278  }
1279  break;
1280  }
1281 
1282  case Qt::Key_Right:
1283  case Qt::Key_Left:
1284  case Qt::Key_Up:
1285  case Qt::Key_Down:
1286  {
1287  if ( mWeakEditorMode )
1288  {
1289  // close editor and defer to table
1290  event->ignore();
1291  }
1292  else
1293  {
1294  QPlainTextEdit::keyPressEvent( event );
1295  }
1296  break;
1297  }
1298 
1299  case Qt::Key_Tab:
1300  {
1301  if ( event->modifiers() & Qt::ControlModifier )
1302  {
1303  // if tab is pressed then defer to table, unless ctrl modifier is also held
1304  // (emulate spreadsheet behavior)
1305  insertPlainText( QString( '\t' ) );
1306  resizeToContents();
1307  }
1308  else
1309  {
1310  event->ignore();
1311  }
1312  break;
1313  }
1314 
1315  default:
1316  QPlainTextEdit::keyPressEvent( event );
1317  }
1318 }
1319 
1320 void QgsTableEditorTextEdit::updateMinimumSize()
1321 {
1322  const double tm = document()->documentMargin();
1323  const QMargins cm = contentsMargins();
1324  const int width = tm * 2 + cm.left() + cm.right() + 30;
1325  const int height = tm * 2 + cm.top() + cm.bottom() + 4;
1326  QStyleOptionFrame opt;
1327  initStyleOption( &opt );
1328  const QSize sizeFromContent = style()->sizeFromContents( QStyle::CT_LineEdit, &opt, QSize( width, height ), this );
1329  setMinimumWidth( sizeFromContent.width() );
1330  setMinimumHeight( sizeFromContent.height() );
1331 }
1332 
1333 void QgsTableEditorTextEdit::setWeakEditorMode( bool weakEditorMode )
1334 {
1335  mWeakEditorMode = weakEditorMode;
1336 }
1337 
1338 void QgsTableEditorTextEdit::resizeToContents()
1339 {
1340  int oldWidth = width();
1341  int oldHeight = height();
1342  if ( mOriginalWidth == -1 )
1343  mOriginalWidth = oldWidth;
1344  if ( mOriginalHeight == -1 )
1345  mOriginalHeight = oldHeight;
1346 
1347  if ( QWidget *parent = parentWidget() )
1348  {
1349  QPoint position = pos();
1350  QFontMetrics fm( font() );
1351 
1352  const QStringList lines = toPlainText().split( '\n' );
1353  int maxTextLineWidth = 0;
1354  int totalTextHeight = 0;
1355  for ( const QString &line : lines )
1356  {
1357  const QRect bounds = fontMetrics().boundingRect( line );
1358  maxTextLineWidth = std::max( maxTextLineWidth, bounds.width() );
1359  totalTextHeight += fm.height();
1360  }
1361 
1362  int hintWidth = minimumWidth() + maxTextLineWidth;
1363  int hintHeight = minimumHeight() + totalTextHeight;
1364  int parentWidth = parent->width();
1365  int maxWidth = isRightToLeft() ? position.x() + oldWidth : parentWidth - position.x();
1366  int maxHeight = parent->height() - position.y();
1367  int newWidth = std::clamp( hintWidth, mOriginalWidth, maxWidth );
1368  int newHeight = std::clamp( hintHeight, mOriginalHeight, maxHeight );
1369 
1370  if ( mWidgetOwnsGeometry )
1371  {
1372  setMaximumWidth( newWidth );
1373  setMaximumHeight( newHeight );
1374  }
1375  if ( isRightToLeft() )
1376  move( position.x() - newWidth + oldWidth, position.y() );
1377  resize( newWidth, newHeight );
1378  }
1379 }
1380 
1381 void QgsTableEditorTextEdit::changeEvent( QEvent *e )
1382 {
1383  switch ( e->type() )
1384  {
1385  case QEvent::FontChange:
1386  case QEvent::StyleChange:
1387  case QEvent::ContentsRectChange:
1388  updateMinimumSize();
1389  break;
1390  default:
1391  break;
1392  }
1393  QPlainTextEdit::changeEvent( e );
1394 }
1395 
1396 QgsTableEditorDelegate::QgsTableEditorDelegate( QObject *parent )
1397  : QStyledItemDelegate( parent )
1398 {
1399 
1400 }
1401 
1402 void QgsTableEditorDelegate::setWeakEditorMode( bool weakEditorMode )
1403 {
1404  mWeakEditorMode = weakEditorMode;
1405 }
1406 
1407 QWidget *QgsTableEditorDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &, const QModelIndex & ) const
1408 {
1409  QgsTableEditorTextEdit *w = new QgsTableEditorTextEdit( parent );
1410  w->setWeakEditorMode( mWeakEditorMode );
1411 
1412  if ( !w->style()->styleHint( QStyle::SH_ItemView_DrawDelegateFrame, 0, w ) )
1413  w->setFrameShape( QFrame::NoFrame );
1414  if ( !w->style()->styleHint( QStyle::SH_ItemView_ShowDecorationSelected, 0, w ) )
1415  w->setWidgetOwnsGeometry( true );
1416 
1417  return w;
1418 }
1419 
1420 void QgsTableEditorDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
1421 {
1422  QVariant value = index.model()->data( index, QgsTableEditorWidget::CellContent );
1423  if ( QgsTableEditorTextEdit *lineEdit = qobject_cast<QgsTableEditorTextEdit * >( editor ) )
1424  {
1425  if ( index != mLastIndex || lineEdit->toPlainText() != value.toString() )
1426  {
1427  lineEdit->setPlainText( value.toString() );
1428  lineEdit->selectAll();
1429  }
1430  }
1431  mLastIndex = index;
1432 }
1433 
1434 void QgsTableEditorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
1435 {
1436  if ( QgsTableEditorTextEdit *lineEdit = qobject_cast<QgsTableEditorTextEdit * >( editor ) )
1437  {
1438  const QString text = lineEdit->toPlainText();
1439  if ( text != model->data( index, QgsTableEditorWidget::CellContent ).toString() && !model->data( index, QgsTableEditorWidget::CellProperty ).value< QgsProperty >().isActive() )
1440  {
1441  model->setData( index, text, QgsTableEditorWidget::CellContent );
1442  model->setData( index, text, Qt::DisplayRole );
1443  emit updateNumericFormatForIndex( index );
1444  }
1445  }
1446 }
1447 
1448 
1450 
QgsTableEditorWidget::tableRowHeight
double tableRowHeight(int row)
Returns the configured row height for the specified row, or 0 if an automatic height should be used f...
Definition: qgstableeditorwidget.cpp:654
QgsProperty::isActive
bool isActive() const
Returns whether the property is currently active.
Definition: qgsproperty.cpp:291
QgsTableEditorWidget::selectionColumnWidth
double selectionColumnWidth()
Returns the width (in millimeters) of the columns associated with the current selection,...
Definition: qgstableeditorwidget.cpp:635
QgsTableCell::setTextFormat
void setTextFormat(const QgsTextFormat &format)
Sets the cell's text format.
Definition: qgstablecell.h:116
QgsTableEditorWidget::tableColumnWidth
double tableColumnWidth(int column)
Returns the configured column width for the specified column, or 0 if an automatic width should be us...
Definition: qgstableeditorwidget.cpp:665
QgsTableEditorWidget::setSelectionTextFormat
void setSelectionTextFormat(const QgsTextFormat &format)
Sets the text format for the selected cells.
Definition: qgstableeditorwidget.cpp:1116
qgstableeditorwidget.h
QgsTableEditorWidget::setSelectionColumnWidth
void setSelectionColumnWidth(double height)
Sets the column width (in millimeters) for the currently selected columns, or 0 for automatic column ...
Definition: qgstableeditorwidget.cpp:1180
QgsTableCell::setHorizontalAlignment
void setHorizontalAlignment(Qt::Alignment alignment)
Sets the horizontal alignment for text in the cell.
Definition: qgstablecell.cpp:127
QgsProperty
A store for object properties.
Definition: qgsproperty.h:230
QgsTableEditorWidget::setSelectionHorizontalAlignment
void setSelectionHorizontalAlignment(Qt::Alignment alignment)
Sets the horizontal alignment for the currently selected cells.
Definition: qgstableeditorwidget.cpp:1003
QgsTableEditorWidget::hasMixedSelectionNumericFormat
bool hasMixedSelectionNumericFormat()
Returns true if the current selection has a mix of numeric formats.
Definition: qgstableeditorwidget.cpp:464
QgsTableCell::setVerticalAlignment
void setVerticalAlignment(Qt::Alignment alignment)
Sets the vertical alignment for text in the cell.
Definition: qgstablecell.cpp:137
QgsProperty::asExpression
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
Definition: qgsproperty.cpp:398
QgsTableEditorWidget::insertColumnsAfter
void insertColumnsAfter()
Inserts new columns after the current selection.
Definition: qgstableeditorwidget.cpp:840
QgsTableEditorWidget::expandColumnSelection
void expandColumnSelection()
Expands out the selection to include whole columns associated with the current selected cells.
Definition: qgstableeditorwidget.cpp:905
QgsTableEditorWidget::tableContents
QgsTableContents tableContents() const
Returns the current contents of the editor widget table.
Definition: qgstableeditorwidget.cpp:359
QgsTableEditorWidget::setIncludeTableHeader
void setIncludeTableHeader(bool included)
Sets whether the table includes a header row.
Definition: qgstableeditorwidget.cpp:1211
QgsTableEditorWidget::deleteColumns
void deleteColumns()
Deletes all columns associated with the current selected cells.
Definition: qgstableeditorwidget.cpp:879
QgsTableEditorWidget::insertColumnsBefore
void insertColumnsBefore()
Inserts new columns before the current selection.
Definition: qgstableeditorwidget.cpp:818
QgsTableEditorWidget::selectionRowHeight
double selectionRowHeight()
Returns the height (in millimeters) of the rows associated with the current selection,...
Definition: qgstableeditorwidget.cpp:616
QgsNumericFormat
A numeric formatter allows for formatting a numeric value for display, using a variety of different f...
Definition: qgsnumericformat.h:259
QgsTableCell::setContent
void setContent(const QVariant &content)
Sets the cell's content.
Definition: qgstablecell.h:64
QgsTableEditorWidget::keyPressEvent
void keyPressEvent(QKeyEvent *event) override
Definition: qgstableeditorwidget.cpp:274
QgsTableEditorWidget::selectionVerticalAlignment
Qt::Alignment selectionVerticalAlignment()
Returns the horizontal alignment for the currently selected cells.
Definition: qgstableeditorwidget.cpp:546
QgsTableEditorWidget::setSelectionRowHeight
void setSelectionRowHeight(double height)
Sets the row height (in millimeters) for the currently selected rows, or 0 for automatic row height.
Definition: qgstableeditorwidget.cpp:1146
QgsProperty::value
QVariant value(const QgsExpressionContext &context, const QVariant &defaultValue=QVariant(), bool *ok=nullptr) const
Calculates the current value of the property, including any transforms which are set for the property...
Definition: qgsproperty.cpp:585
QgsTableEditorWidget::setTableColumnWidth
void setTableColumnWidth(int column, double width)
Sets the configured column width for the specified column.
Definition: qgstableeditorwidget.cpp:708
QgsTableContents
QVector< QgsTableRow > QgsTableContents
A set of table rows.
Definition: qgstablecell.h:220
QgsTextFormat::color
QColor color() const
Returns the color that text will be rendered in.
Definition: qgstextformat.cpp:297
QgsTextFormat
Container for all settings relating to text rendering.
Definition: qgstextformat.h:40
QgsTextFormat::setColor
void setColor(const QColor &color)
Sets the color that text will be rendered in.
Definition: qgstextformat.cpp:302
QgsTableEditorWidget::setSelectionNumericFormat
void setSelectionNumericFormat(QgsNumericFormat *format)
Sets the numeric format to use for the currently selected cells.
Definition: qgstableeditorwidget.cpp:392
QgsTableEditorWidget::insertRowsAbove
void insertRowsAbove()
Inserts new rows above the current selection.
Definition: qgstableeditorwidget.cpp:796
QgsTableEditorWidget::~QgsTableEditorWidget
~QgsTableEditorWidget() override
Definition: qgstableeditorwidget.cpp:139
QgsTableEditorWidget::setSelectionForegroundColor
Q_DECL_DEPRECATED void setSelectionForegroundColor(const QColor &color)
Sets the foreground color for the currently selected cells.
Definition: qgstableeditorwidget.cpp:933
QgsTableEditorWidget::setTableRowHeight
void setTableRowHeight(int row, double height)
Sets the configured row height for the specified row.
Definition: qgstableeditorwidget.cpp:676
QgsTableEditorWidget::setSelectionBackgroundColor
void setSelectionBackgroundColor(const QColor &color)
Sets the background color for the currently selected cells.
Definition: qgstableeditorwidget.cpp:970
QgsTableCell
Encapsulates the contents and formatting of a single table cell.
Definition: qgstablecell.h:35
QgsTableCell::setNumericFormat
void setNumericFormat(QgsNumericFormat *format)
Sets the numeric format used for numbers in the cell, or nullptr if no specific format is set.
Definition: qgstablecell.cpp:55
QgsTableEditorWidget::tableChanged
void tableChanged()
Emitted whenever the table contents are changed.
QgsTableEditorWidget::selectionBackgroundColor
QColor selectionBackgroundColor()
Returns the background color for the currently selected cells.
Definition: qgstableeditorwidget.cpp:500
QgsTableEditorWidget::selectionTextFormat
QgsTextFormat selectionTextFormat()
Returns the text format for the currently selected cells.
Definition: qgstableeditorwidget.cpp:592
QgsTableEditorWidget::setSelectionVerticalAlignment
void setSelectionVerticalAlignment(Qt::Alignment alignment)
Sets the vertical alignment for the currently selected cells.
Definition: qgstableeditorwidget.cpp:1034
QgsTableCell::setBackgroundColor
void setBackgroundColor(const QColor &color)
Sets the cell's background color.
Definition: qgstablecell.h:80
QgsTableEditorWidget::selectionHorizontalAlignment
Qt::Alignment selectionHorizontalAlignment()
Returns the horizontal alignment for the currently selected cells.
Definition: qgstableeditorwidget.cpp:523
QgsTableEditorWidget::isHeaderCellSelected
bool isHeaderCellSelected()
Returns true if any header cells are selected.
Definition: qgstableeditorwidget.cpp:766
QgsTableEditorWidget::QgsTableEditorWidget
QgsTableEditorWidget(QWidget *parent=nullptr)
Constructor for QgsTableEditorWidget with the specified parent widget.
Definition: qgstableeditorwidget.cpp:26
QgsTextFormat::isValid
bool isValid() const
Returns true if the format is valid.
Definition: qgstextformat.cpp:102
QgsTableEditorWidget::expandRowSelection
void expandRowSelection()
Expands out the selection to include whole rows associated with the current selected cells.
Definition: qgstableeditorwidget.cpp:896
QgsTableEditorWidget::selectionForegroundColor
Q_DECL_DEPRECATED QColor selectionForegroundColor()
Returns the foreground color for the currently selected cells.
Definition: qgstableeditorwidget.cpp:494
qgsnumericformat.h
QgsTableEditorWidget::tableHeaders
QVariantList tableHeaders() const
Returns the table header values.
Definition: qgstableeditorwidget.cpp:745
QgsTableEditorWidget::deleteRows
void deleteRows()
Deletes all rows associated with the current selected cells.
Definition: qgstableeditorwidget.cpp:862
QgsTableRow
QVector< QgsTableCell > QgsTableRow
A row of table cells.
Definition: qgstablecell.h:211
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsTableEditorWidget::setSelectionCellProperty
void setSelectionCellProperty(const QgsProperty &property)
Sets the cell contents QgsProperty for the currently selected cells.
Definition: qgstableeditorwidget.cpp:1065
QgsTableEditorWidget::insertRowsBelow
void insertRowsBelow()
Inserts new rows below the current selection.
Definition: qgstableeditorwidget.cpp:774
QgsTableEditorWidget::selectionNumericFormat
QgsNumericFormat * selectionNumericFormat()
Returns the numeric format used for the currently selected cells, or nullptr if the selection has no ...
Definition: qgstableeditorwidget.cpp:434
QgsTableEditorWidget::setTableContents
void setTableContents(const QgsTableContents &contents)
Sets the contents to show in the editor widget.
Definition: qgstableeditorwidget.cpp:302
QgsTableEditorWidget::QgsTableEditorDelegate
friend class QgsTableEditorDelegate
Definition: qgstableeditorwidget.h:489
QgsTableEditorWidget::clearSelectedCells
void clearSelectedCells()
Clears the contents of the currently selected cells.
Definition: qgstableeditorwidget.cpp:914
QgsTableEditorWidget::columnsAssociatedWithSelection
QList< int > columnsAssociatedWithSelection()
Returns a list of the columns associated with the current table selected cells.
Definition: qgstableeditorwidget.cpp:740
QgsTableEditorWidget::activeCellChanged
void activeCellChanged()
Emitted whenever the active (or selected) cell changes in the widget.
QgsTableEditorWidget::selectionCellProperty
QgsProperty selectionCellProperty()
Returns the QgsProperty used for the contents of the currently selected cells.
Definition: qgstableeditorwidget.cpp:569
QgsTableEditorWidget::rowsAssociatedWithSelection
QList< int > rowsAssociatedWithSelection()
Returns a list of the rows associated with the current table selected cells.
Definition: qgstableeditorwidget.cpp:735
QgsNumericFormatContext
A context for numeric formats.
Definition: qgsnumericformat.h:34
QgsTableEditorWidget::setTableHeaders
void setTableHeaders(const QVariantList &headers)
Sets the table headers.
Definition: qgstableeditorwidget.cpp:1225