24#include <QPlainTextEdit> 
   27  : QTableWidget( parent )
 
   29  mHeaderMenu = 
new QMenu( 
this );
 
   32  connect( 
this, &QgsTableEditorWidget::cellChanged, 
this, [ = ]
 
   38  horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
 
   39  connect( horizontalHeader(), &QWidget::customContextMenuRequested, 
this, [ = ]( 
const QPoint & point )
 
   41    const int column = horizontalHeader()->logicalIndexAt( point.x() );
 
   43    QSet< int > selectedColumns;
 
   44    for ( 
const QModelIndex &index : selectedIndexes() )
 
   46      selectedColumns.insert( index.column() );
 
   50    bool isConsecutive = collectConsecutiveColumnRange( selectedIndexes(), minCol, maxCol );
 
   53    if ( selectedIndexes().count() == 1 )
 
   56      selectColumn( column );
 
   59    else if ( !selectedColumns.contains( column ) )
 
   62      selectColumn( column );
 
   69      QAction *insertBefore = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr( 
"Insert %n Column(s) Before", 
nullptr, selectedColumns.size() ) : tr( 
"Insert Column Before" ) );
 
   71      QAction *insertAfter = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr( 
"Insert %n Column(s) After", 
nullptr, selectedColumns.size() ) : tr( 
"Insert Column After" ) );
 
   74    QAction *deleteSelected = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr( 
"Delete %n Column(s)", 
nullptr, selectedColumns.size() ) : tr( 
"Delete Column" ) );
 
   77    mHeaderMenu->popup( horizontalHeader()->mapToGlobal( point ) );
 
   80  verticalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
 
   81  connect( verticalHeader(), &QWidget::customContextMenuRequested, 
this, [ = ]( 
const QPoint & point )
 
   83    const int row = verticalHeader()->logicalIndexAt( point.y() );
 
   85    QSet< int > selectedRows;
 
   86    for ( 
const QModelIndex &index : selectedIndexes() )
 
   88      selectedRows.insert( index.row() );
 
   92    bool isConsecutive = collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow );
 
   95    if ( selectedIndexes().count() == 1 )
 
  101    else if ( !selectedRows.contains( row ) )
 
  105      isConsecutive = 
true;
 
  108    mHeaderMenu->clear();
 
  111      QAction *insertBefore = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr( 
"Insert %n Row(s) Above", 
nullptr, selectedRows.size() ) : tr( 
"Insert Row Above" ) );
 
  113      QAction *insertAfter = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr( 
"Insert %n Row(s) Below", 
nullptr, selectedRows.size() ) : tr( 
"Insert Row Below" ) );
 
  116    QAction *deleteSelected = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr( 
"Delete %n Row(s)", 
nullptr, selectedRows.size() ) : tr( 
"Delete Row" ) );
 
  119    mHeaderMenu->popup( verticalHeader()->mapToGlobal( point ) );
 
  124  connect( delegate, &QgsTableEditorDelegate::updateNumericFormatForIndex, 
this, &QgsTableEditorWidget::updateNumericFormatForIndex );
 
  125  setItemDelegate( delegate );
 
  128  connect( 
this, &QTableWidget::cellDoubleClicked, 
this, [ = ]
 
  132      d->setWeakEditorMode( 
false );
 
 
  141  qDeleteAll( mNumericFormats );
 
 
  144void QgsTableEditorWidget::updateNumericFormatForIndex( 
const QModelIndex &index )
 
  146  if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
  150      i->setData( Qt::DisplayRole, format->formatDouble( index.data( CellContent ).toDouble(), 
QgsNumericFormatContext() ) );
 
  155void QgsTableEditorWidget::updateHeaders()
 
  163  for ( 
char c = 
'A'; 
c <= 
'Z'; 
c++ )
 
  165    letters.push_back( QString( 
c ) );
 
  168  int len = letters.length();
 
  172  for ( 
int i = 0; i < 1000; i++ )
 
  178      first = letters.at( fIndex );
 
  188    current += letters.at( index );
 
  189    headers.push_back( current );
 
  195  setHorizontalHeaderLabels( headers );
 
  198  if ( mIncludeHeader )
 
  199    headers << tr( 
"Header" );
 
  200  for ( 
int i = 1; i <= 1000; i++ )
 
  202    headers << QString::number( i );
 
  205  setVerticalHeaderLabels( headers );
 
  208bool QgsTableEditorWidget::collectConsecutiveRowRange( 
const QModelIndexList &list, 
int &minRow, 
int &maxRow )
 const 
  210  QSet< int > includedRows;
 
  211  minRow = std::numeric_limits< int >::max();
 
  213  for ( 
const QModelIndex &index : list )
 
  215    includedRows.insert( index.row() );
 
  216    minRow = std::min( minRow, index.row() );
 
  217    maxRow = std::max( maxRow, index.row() );
 
  221  for ( 
int r = minRow + 1; r < maxRow; r++ )
 
  223    if ( !includedRows.contains( r ) )
 
  229bool QgsTableEditorWidget::collectConsecutiveColumnRange( 
const QModelIndexList &list, 
int &minColumn, 
int &maxColumn )
 const 
  231  QSet< int > includedColumns;
 
  232  minColumn = std::numeric_limits< int >::max();
 
  234  for ( 
const QModelIndex &index : list )
 
  236    includedColumns.insert( index.column() );
 
  237    minColumn = std::min( minColumn, index.column() );
 
  238    maxColumn = std::max( maxColumn, index.column() );
 
  242  for ( 
int r = minColumn + 1; r < maxColumn; r++ )
 
  244    if ( !includedColumns.contains( r ) )
 
  250QList<int> QgsTableEditorWidget::collectUniqueRows( 
const QModelIndexList &list )
 const 
  253  for ( 
const QModelIndex &index : list )
 
  255    if ( !res.contains( index.row() ) )
 
  258  std::sort( res.begin(), res.end() );
 
  262QList<int> QgsTableEditorWidget::collectUniqueColumns( 
const QModelIndexList &list )
 const 
  265  for ( 
const QModelIndex &index : list )
 
  267    if ( !res.contains( index.column() ) )
 
  268      res << index.column();
 
  270  std::sort( res.begin(), res.end() );
 
  276  switch ( event->key() )
 
  282      QTableWidget::keyPressEvent( event );
 
  283      setCurrentCell( currentRow() + 1, currentColumn() );
 
  294      QTableWidget::keyPressEvent( event );
 
  298    d->setWeakEditorMode( 
true );
 
 
  305  qDeleteAll( mNumericFormats );
 
  306  mNumericFormats.clear();
 
  309  int rowNumber = mIncludeHeader ? 1 : 0;
 
  311  setRowCount( contents.size() + rowNumber );
 
  316      setColumnCount( row.size() );
 
  324      item->setData( CellContent, col.content() ); 
 
  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 >() ) );
 
  333      if ( col.content().value< 
QgsProperty >().isActive() )
 
  334        item->setFlags( item->flags() & ( ~Qt::ItemIsEditable ) );
 
  336      if ( 
auto *lNumericFormat = col.numericFormat() )
 
  338        mNumericFormats.insert( item, lNumericFormat->clone() );
 
  339        item->setData( Qt::DisplayRole, mNumericFormats.value( item )->formatDouble( col.content().toDouble(), numericContext ) );
 
  341      setItem( rowNumber, colNumber, item );
 
  352    resizeColumnsToContents();
 
  353    resizeRowsToContents();
 
 
  362  items.reserve( rowCount() );
 
  364  for ( 
int r = mIncludeHeader ? 1 : 0; r < rowCount(); r++ )
 
  367    row.reserve( columnCount() );
 
  368    for ( 
int c = 0; 
c < columnCount(); 
c++ )
 
  371      if ( QTableWidgetItem *i = item( r, 
c ) )
 
  373        cell.
setContent( i->data( CellProperty ).value< 
QgsProperty >().isActive() ? i->data( CellProperty ) : i->data( CellContent ) );
 
  377        cell.
setVerticalAlignment( 
static_cast< Qt::Alignment 
>( i->data( VerticalAlignment ).toInt() ) );
 
  379        if ( mNumericFormats.value( i ) )
 
  384      row.push_back( cell );
 
  386    items.push_back( row );
 
 
  394  bool changed = 
false;
 
  396  std::unique_ptr< QgsNumericFormat > newFormat( format );
 
  397  const QModelIndexList selection = selectedIndexes();
 
  399  for ( 
const QModelIndex &index : selection )
 
  401    if ( index.row() == 0 && mIncludeHeader )
 
  404    QTableWidgetItem *i = item( index.row(), index.column() );
 
  407      i = 
new QTableWidgetItem();
 
  408      setItem( index.row(), index.column(), i );
 
  410    if ( !mNumericFormats.value( i ) && newFormat )
 
  413      mNumericFormats.insert( i, newFormat->clone() );
 
  415    else if ( mNumericFormats.value( i ) && !newFormat )
 
  418      delete mNumericFormats.value( i );
 
  419      mNumericFormats.remove( i );
 
  421    else if ( newFormat && *newFormat != *mNumericFormats.value( i ) )
 
  424      delete mNumericFormats.value( i );
 
  425      mNumericFormats.insert( i, newFormat->clone() );
 
  427    i->setData( Qt::DisplayRole, newFormat ? mNumericFormats.value( i )->formatDouble( i->data( CellContent ).toDouble(), numericContext ) : i->data( CellContent ) );
 
  430  if ( changed && !mBlockSignals )
 
 
  438  const QModelIndexList selection = selectedIndexes();
 
  439  for ( 
const QModelIndex &index : selection )
 
  441    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
  445        f = mNumericFormats.value( i );
 
  448      else if ( ( !f && !mNumericFormats.value( i ) )
 
  449                || ( f && mNumericFormats.value( i ) && *f == *mNumericFormats.value( i ) ) )
 
 
  468  const QModelIndexList selection = selectedIndexes();
 
  469  for ( 
const QModelIndex &index : selection )
 
  471    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
  475        f = mNumericFormats.value( i );
 
  478      else if ( ( !f && !mNumericFormats.value( i ) )
 
  479                || ( f && mNumericFormats.value( i ) && *f == *mNumericFormats.value( i ) ) )
 
 
  504  const QModelIndexList selection = selectedIndexes();
 
  505  for ( 
const QModelIndex &index : selection )
 
  507    QColor indexColor = model()->data( index, PresetBackgroundColorRole ).isValid() ? model()->data( index, PresetBackgroundColorRole ).value< QColor >() : QColor();
 
  513    else if ( indexColor == 
c )
 
 
  525  Qt::Alignment alignment = Qt::AlignLeft;
 
  527  const QModelIndexList selection = selectedIndexes();
 
  528  for ( 
const QModelIndex &index : selection )
 
  530    Qt::Alignment cellAlign = 
static_cast< Qt::Alignment 
>( model()->data( index, HorizontalAlignment ).toInt() );
 
  533      alignment = cellAlign;
 
  536    else if ( cellAlign == alignment )
 
  540      return Qt::AlignLeft | Qt::AlignTop;
 
 
  548  Qt::Alignment alignment = Qt::AlignVCenter;
 
  550  const QModelIndexList selection = selectedIndexes();
 
  551  for ( 
const QModelIndex &index : selection )
 
  553    Qt::Alignment cellAlign = 
static_cast< Qt::Alignment 
>( model()->data( index, VerticalAlignment ).toInt() );
 
  556      alignment = cellAlign;
 
  559    else if ( cellAlign == alignment )
 
  563      return Qt::AlignLeft | Qt::AlignTop;
 
 
  573  const QModelIndexList selection = selectedIndexes();
 
  574  for ( 
const QModelIndex &index : selection )
 
  579      property = cellProperty;
 
  582    else if ( cellProperty == property )
 
 
  596  const QModelIndexList selection = selectedIndexes();
 
  597  for ( 
const QModelIndex &index : selection )
 
  599    if ( !model()->data( index, TextFormat ).isValid() )
 
  608    else if ( cellFormat == format )
 
 
  620  const QModelIndexList selection = selectedIndexes();
 
  621  for ( 
const QModelIndex &index : selection )
 
  626    else if ( thisHeight != height )
 
 
  639  const QModelIndexList selection = selectedIndexes();
 
  640  for ( 
const QModelIndex &index : selection )
 
  645    else if ( thisWidth != width )
 
 
  657  for ( 
int col = 0; col < columnCount(); ++col )
 
  659    double thisHeight = model()->data( model()->index( row + ( mIncludeHeader ? 1 : 0 ), col ), RowHeight ).toDouble();
 
  660    height = std::max( thisHeight, height );
 
 
  668  for ( 
int row = 0; row < rowCount(); ++row )
 
  670    double thisWidth = model()->data( model()->index( row, column ), ColumnWidth ).toDouble();
 
  671    width = std::max( thisWidth, width );
 
 
  678  if ( row == 0 && mIncludeHeader )
 
  681  bool changed = 
false;
 
  684  for ( 
int col = 0; col < columnCount(); ++col )
 
  686    if ( QTableWidgetItem *i = item( row + ( mIncludeHeader ? 1 : 0 ), col ) )
 
  688      if ( i->data( RowHeight ).toDouble() != height )
 
  690        i->setData( RowHeight, height );
 
  696      QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
  697      newItem->setData( RowHeight, height );
 
  698      setItem( row + ( mIncludeHeader ? 1 : 0 ), col, newItem );
 
  704  if ( changed && !mBlockSignals )
 
 
  710  bool changed = 
false;
 
  712  for ( 
int row = 0; row < rowCount(); ++row )
 
  714    if ( QTableWidgetItem *i = item( row, col ) )
 
  716      if ( i->data( ColumnWidth ).toDouble() != width )
 
  718        i->setData( ColumnWidth, width );
 
  724      QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
  725      newItem->setData( ColumnWidth, width );
 
  726      setItem( row, col, newItem );
 
  731  if ( changed && !mBlockSignals )
 
 
  737  return collectUniqueRows( selectedIndexes() );
 
 
  742  return collectUniqueColumns( selectedIndexes() );
 
 
  747  if ( !mIncludeHeader )
 
  748    return QVariantList();
 
  751  res.reserve( columnCount() );
 
  752  for ( 
int col = 0; col < columnCount(); ++col )
 
  754    if ( QTableWidgetItem *i = item( 0, col ) )
 
  756      res << i->data( CellContent );
 
 
  768  if ( !mIncludeHeader )
 
  771  return collectUniqueRows( selectedIndexes() ).contains( 0 );
 
 
  776  if ( rowCount() == 0 )
 
  784  if ( !collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow ) )
 
  787  const int rowsToInsert = maxRow - minRow + 1;
 
  788  for ( 
int i = 0; i < rowsToInsert; ++i )
 
  789    insertRow( maxRow + 1 );
 
  792  if ( !mBlockSignals )
 
 
  798  if ( rowCount() == 0 )
 
  806  if ( !collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow ) )
 
  809  const int rowsToInsert = maxRow - minRow + 1;
 
  810  for ( 
int i = 0; i < rowsToInsert; ++i )
 
  814  if ( !mBlockSignals )
 
 
  820  if ( columnCount() == 0 )
 
  828  if ( !collectConsecutiveColumnRange( selectedIndexes(), minColumn, maxColumn ) )
 
  831  const int columnsToInsert = maxColumn - minColumn + 1;
 
  832  for ( 
int i = 0; i < columnsToInsert; ++i )
 
  833    insertColumn( minColumn );
 
  836  if ( !mBlockSignals )
 
 
  842  if ( columnCount() == 0 )
 
  850  if ( !collectConsecutiveColumnRange( selectedIndexes(), minColumn, maxColumn ) )
 
  853  const int columnsToInsert = maxColumn - minColumn + 1;
 
  854  for ( 
int i = 0; i < columnsToInsert; ++i )
 
  855    insertColumn( maxColumn + 1 );
 
  858  if ( !mBlockSignals )
 
 
  868  bool changed = 
false;
 
  869  for ( 
int i = rows.size() - 1; i >= 0 && rowCount() > 1; i-- )
 
  871    removeRow( rows.at( i ) );
 
  875  if ( changed &&  !mBlockSignals )
 
 
  882  if ( columns.empty() )
 
  885  bool changed = 
false;
 
  886  for ( 
int i = columns.size() - 1; i >= 0 && columnCount() > 1; i-- )
 
  888    removeColumn( columns.at( i ) );
 
  892  if ( !mBlockSignals && changed )
 
 
  898  const QModelIndexList s = selectedIndexes();
 
  899  for ( 
const QModelIndex &index : s )
 
  901    selectionModel()->select( index, QItemSelectionModel::Rows | QItemSelectionModel::Select );
 
 
  907  const QModelIndexList s = selectedIndexes();
 
  908  for ( 
const QModelIndex &index : s )
 
  910    selectionModel()->select( index, QItemSelectionModel::Columns | QItemSelectionModel::Select );
 
 
  916  const QModelIndexList selection = selectedIndexes();
 
  917  bool changed = 
false;
 
  919  for ( 
const QModelIndex &index : selection )
 
  921    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
  923      i->setText( QString() );
 
  924      i->setData( CellContent, QVariant() );
 
  929  if ( changed && !mBlockSignals )
 
 
  935  const QModelIndexList selection = selectedIndexes();
 
  936  bool changed = 
false;
 
  938  for ( 
const QModelIndex &index : selection )
 
  940    if ( index.row() == 0 && mIncludeHeader )
 
  943    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
  945      if ( i->data( Qt::ForegroundRole ).value< QColor >() != color )
 
  947        i->setData( Qt::ForegroundRole, color.isValid() ? color : QVariant() );
 
  950        i->setData( TextFormat, QVariant::fromValue( f ) );
 
  956      QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
  957      newItem->setData( Qt::ForegroundRole, color.isValid() ? color : QVariant() );
 
  960      newItem->setData( TextFormat, QVariant::fromValue( f ) );
 
  961      setItem( index.row(), index.column(), newItem );
 
  966  if ( changed && !mBlockSignals )
 
 
  972  const QModelIndexList selection = selectedIndexes();
 
  973  bool changed = 
false;
 
  975  for ( 
const QModelIndex &index : selection )
 
  977    if ( index.row() == 0 && mIncludeHeader )
 
  980    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
  982      if ( i->data( PresetBackgroundColorRole ).value< QColor >() != color )
 
  984        i->setData( Qt::BackgroundRole, color.isValid() ? color : QVariant() );
 
  985        i->setData( PresetBackgroundColorRole, color.isValid() ? color : QVariant() );
 
  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 );
 
  999  if ( changed && !mBlockSignals )
 
 
 1005  const QModelIndexList selection = selectedIndexes();
 
 1006  bool changed = 
false;
 
 1008  for ( 
const QModelIndex &index : selection )
 
 1010    if ( index.row() == 0 && mIncludeHeader )
 
 1013    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
 1015      if ( 
static_cast< Qt::Alignment 
>( i->data( HorizontalAlignment ).toInt() ) != alignment )
 
 1017        i->setData( HorizontalAlignment, 
static_cast< int >( alignment ) );
 
 1023      QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
 1024      newItem->setData( HorizontalAlignment, 
static_cast< int >( alignment ) );
 
 1025      setItem( index.row(), index.column(), newItem );
 
 1030  if ( changed && !mBlockSignals )
 
 
 1036  const QModelIndexList selection = selectedIndexes();
 
 1037  bool changed = 
false;
 
 1039  for ( 
const QModelIndex &index : selection )
 
 1041    if ( index.row() == 0 && mIncludeHeader )
 
 1044    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
 1046      if ( 
static_cast< Qt::Alignment 
>( i->data( HorizontalAlignment ).toInt() ) != alignment )
 
 1048        i->setData( VerticalAlignment, 
static_cast< int >( alignment ) );
 
 1054      QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
 1055      newItem->setData( VerticalAlignment, 
static_cast< int >( alignment ) );
 
 1056      setItem( index.row(), index.column(), newItem );
 
 1061  if ( changed && !mBlockSignals )
 
 
 1067  const QModelIndexList selection = selectedIndexes();
 
 1068  bool changed = 
false;
 
 1070  for ( 
const QModelIndex &index : selection )
 
 1072    if ( index.row() == 0 && mIncludeHeader )
 
 1075    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
 1077      if ( i->data( CellProperty ).value< 
QgsProperty >() != property )
 
 1081          i->setData( CellProperty, QVariant::fromValue( property ) );
 
 1083          i->setFlags( i->flags() & ( ~Qt::ItemIsEditable ) );
 
 1087          i->setData( CellProperty, QVariant() );
 
 1088          i->setText( QString() );
 
 1089          i->setFlags( i->flags() | Qt::ItemIsEditable );
 
 1096      QTableWidgetItem *newItem = 
new QTableWidgetItem( property.
asExpression() );
 
 1099        newItem->setData( CellProperty,  QVariant::fromValue( property ) );
 
 1100        newItem->setFlags( newItem->flags() & ( ~Qt::ItemIsEditable ) );
 
 1104        newItem->setData( CellProperty, QVariant() );
 
 1105        newItem->setFlags( newItem->flags() | Qt::ItemIsEditable );
 
 1107      setItem( index.row(), index.column(), newItem );
 
 1112  if ( changed && !mBlockSignals )
 
 
 1118  const QModelIndexList selection = selectedIndexes();
 
 1119  bool changed = 
false;
 
 1121  for ( 
const QModelIndex &index : selection )
 
 1123    if ( index.row() == 0 && mIncludeHeader )
 
 1126    if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
 
 1128      i->setData( TextFormat, QVariant::fromValue( format ) );
 
 1129      i->setData( Qt::ForegroundRole, format.
color() );
 
 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 );
 
 1142  if ( changed && !mBlockSignals )
 
 
 1148  bool changed = 
false;
 
 1151  for ( 
int row : rows )
 
 1153    if ( row == 0 && mIncludeHeader )
 
 1156    for ( 
int col = 0; col < columnCount(); ++col )
 
 1158      if ( QTableWidgetItem *i = item( row, col ) )
 
 1160        if ( i->data( RowHeight ).toDouble() != height )
 
 1162          i->setData( RowHeight, height );
 
 1168        QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
 1169        newItem->setData( RowHeight, height );
 
 1170        setItem( row, col, newItem );
 
 1176  if ( changed && !mBlockSignals )
 
 
 1182  bool changed = 
false;
 
 1185  for ( 
int col : cols )
 
 1187    for ( 
int row = 0; row < rowCount(); ++row )
 
 1189      if ( QTableWidgetItem *i = item( row, col ) )
 
 1191        if ( i->data( ColumnWidth ).toDouble() != width )
 
 1193          i->setData( ColumnWidth, width );
 
 1199        QTableWidgetItem *newItem = 
new QTableWidgetItem();
 
 1200        newItem->setData( ColumnWidth, width );
 
 1201        setItem( row, col, newItem );
 
 1207  if ( changed && !mBlockSignals )
 
 
 1213  if ( included == mIncludeHeader )
 
 1216  mIncludeHeader = included;
 
 1218  if ( mIncludeHeader )
 
 
 1227  if ( !mIncludeHeader )
 
 1232  for ( 
int col = 0; col < columnCount(); ++col )
 
 1234    if ( QTableWidgetItem *i = item( 0, col ) )
 
 1236      i->setText( headers.value( col ).toString() );
 
 1237      i->setData( CellContent, headers.value( col ) ); 
 
 1241      QTableWidgetItem *item = 
new QTableWidgetItem( headers.value( col ).toString() );
 
 1242      item->setData( CellContent, headers.value( col ) ); 
 
 1243      setItem( 0, col, item );
 
 
 1251QgsTableEditorTextEdit::QgsTableEditorTextEdit( QWidget *parent )
 
 1252  : QPlainTextEdit( parent )
 
 1255  document()->setDocumentMargin( document()->documentMargin() / 2 );
 
 1257  connect( 
this, &QPlainTextEdit::textChanged, 
this, &QgsTableEditorTextEdit::resizeToContents );
 
 1258  updateMinimumSize();
 
 1261void QgsTableEditorTextEdit::keyPressEvent( QKeyEvent *event )
 
 1263  switch ( event->key() )
 
 1266    case Qt::Key_Return:
 
 1268      if ( event->modifiers() & Qt::ControlModifier )
 
 1271        insertPlainText( QString( 
'\n' ) );
 
 1287      if ( mWeakEditorMode )
 
 1294        QPlainTextEdit::keyPressEvent( event );
 
 1301      if ( event->modifiers() & Qt::ControlModifier )
 
 1305        insertPlainText( QString( 
'\t' ) );
 
 1316      QPlainTextEdit::keyPressEvent( event );
 
 1320void QgsTableEditorTextEdit::updateMinimumSize()
 
 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() );
 
 1333void QgsTableEditorTextEdit::setWeakEditorMode( 
bool weakEditorMode )
 
 1335  mWeakEditorMode = weakEditorMode;
 
 1338void QgsTableEditorTextEdit::resizeToContents()
 
 1340  int oldWidth = width();
 
 1341  int oldHeight = height();
 
 1342  if ( mOriginalWidth == -1 )
 
 1343    mOriginalWidth = oldWidth;
 
 1344  if ( mOriginalHeight == -1 )
 
 1345    mOriginalHeight = oldHeight;
 
 1347  if ( QWidget *parent = parentWidget() )
 
 1349    QPoint position = pos();
 
 1350    QFontMetrics fm( font() );
 
 1352    const QStringList lines = toPlainText().split( 
'\n' );
 
 1353    int maxTextLineWidth = 0;
 
 1354    int totalTextHeight = 0;
 
 1355    for ( 
const QString &line : lines )
 
 1357      const QRect bounds = fontMetrics().boundingRect( line );
 
 1358      maxTextLineWidth = std::max( maxTextLineWidth, bounds.width() );
 
 1359      totalTextHeight += fm.height();
 
 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 );
 
 1370    if ( mWidgetOwnsGeometry )
 
 1372      setMaximumWidth( newWidth );
 
 1373      setMaximumHeight( newHeight );
 
 1375    if ( isRightToLeft() )
 
 1376      move( position.x() - newWidth + oldWidth, position.y() );
 
 1377    resize( newWidth, newHeight );
 
 1381void QgsTableEditorTextEdit::changeEvent( QEvent *e )
 
 1383  switch ( e->type() )
 
 1385    case QEvent::FontChange:
 
 1386    case QEvent::StyleChange:
 
 1387    case QEvent::ContentsRectChange:
 
 1388      updateMinimumSize();
 
 1393  QPlainTextEdit::changeEvent( e );
 
 1396QgsTableEditorDelegate::QgsTableEditorDelegate( QObject *parent )
 
 1397  : QStyledItemDelegate( parent )
 
 1402void QgsTableEditorDelegate::setWeakEditorMode( 
bool weakEditorMode )
 
 1404  mWeakEditorMode = weakEditorMode;
 
 1407QWidget *QgsTableEditorDelegate::createEditor( QWidget *parent, 
const QStyleOptionViewItem &, 
const QModelIndex & )
 const 
 1409  QgsTableEditorTextEdit *w = 
new QgsTableEditorTextEdit( parent );
 
 1410  w->setWeakEditorMode( mWeakEditorMode );
 
 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 );
 
 1420void QgsTableEditorDelegate::setEditorData( QWidget *editor, 
const QModelIndex &index )
 const 
 1422  QVariant value = index.model()->data( index, QgsTableEditorWidget::CellContent );
 
 1423  if ( QgsTableEditorTextEdit *lineEdit = qobject_cast<QgsTableEditorTextEdit * >( editor ) )
 
 1425    if ( index != mLastIndex || lineEdit->toPlainText() != value.toString() )
 
 1427      lineEdit->setPlainText( value.toString() );
 
 1428      lineEdit->selectAll();
 
 1434void QgsTableEditorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, 
const QModelIndex &index )
 const 
 1436  if ( QgsTableEditorTextEdit *lineEdit = qobject_cast<QgsTableEditorTextEdit * >( editor ) )
 
 1438    const QString text = lineEdit->toPlainText();
 
 1439    if ( text != model->data( index, QgsTableEditorWidget::CellContent ).toString() && !model->data( index, QgsTableEditorWidget::CellProperty ).value< 
QgsProperty >().
isActive() )
 
 1441      model->setData( index, text, QgsTableEditorWidget::CellContent );
 
 1442      model->setData( index, text, Qt::DisplayRole );
 
 1443      emit updateNumericFormatForIndex( index );
 
A context for numeric formats.
 
A store for object properties.
 
QString asExpression() const
Returns an expression string representing the state of the property, or an empty string if the proper...
 
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...
 
bool isActive() const
Returns whether the property is currently active.
 
Encapsulates the contents and formatting of a single table cell.
 
void setHorizontalAlignment(Qt::Alignment alignment)
Sets the horizontal alignment for text in the cell.
 
void setVerticalAlignment(Qt::Alignment alignment)
Sets the vertical alignment for text in the cell.
 
void setBackgroundColor(const QColor &color)
Sets the cell's background color.
 
void setTextFormat(const QgsTextFormat &format)
Sets the cell's text format.
 
void setContent(const QVariant &content)
Sets the cell's content.
 
void setNumericFormat(QgsNumericFormat *format)
Sets the numeric format used for numbers in the cell, or nullptr if no specific format is set.
 
Container for all settings relating to text rendering.
 
void setColor(const QColor &color)
Sets the color that text will be rendered in.
 
bool isValid() const
Returns true if the format is valid.
 
QColor color() const
Returns the color that text will be rendered in.
 
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
 
QVector< QgsTableRow > QgsTableContents
A set of table rows.
 
QVector< QgsTableCell > QgsTableRow
A row of table cells.