19#include "moc_qgstableeditorwidget.cpp"
25#include <QPlainTextEdit>
28 : QTableWidget( parent )
30 mHeaderMenu =
new QMenu(
this );
31 mCellMenu =
new QMenu(
this );
34 connect(
this, &QgsTableEditorWidget::cellChanged,
this, [ = ]
40 setContextMenuPolicy( Qt::CustomContextMenu );
41 connect(
this, &QWidget::customContextMenuRequested,
this, [ = ](
const QPoint & point )
47 QAction *mergeCells = mCellMenu->addAction( tr(
"Merge Selected Cells" ) );
52 QAction *splitCells = mCellMenu->addAction( tr(
"Split Selected Cells" ) );
55 if ( !mCellMenu->isEmpty() )
56 mCellMenu->popup( mapToGlobal( point ) );
60 horizontalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
61 connect( horizontalHeader(), &QWidget::customContextMenuRequested,
this, [ = ](
const QPoint & point )
63 const int column = horizontalHeader()->logicalIndexAt( point.x() );
65 QSet< int > selectedColumns;
66 for (
const QModelIndex &index : selectedIndexes() )
68 selectedColumns.insert( index.column() );
72 bool isConsecutive = collectConsecutiveColumnRange( selectedIndexes(), minCol, maxCol );
75 if ( selectedIndexes().count() == 1 )
78 selectColumn( column );
81 else if ( !selectedColumns.contains( column ) )
84 selectColumn( column );
91 QAction *insertBefore = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr(
"Insert %n Column(s) Before",
nullptr, selectedColumns.size() ) : tr(
"Insert Column Before" ) );
93 QAction *insertAfter = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr(
"Insert %n Column(s) After",
nullptr, selectedColumns.size() ) : tr(
"Insert Column After" ) );
96 QAction *deleteSelected = mHeaderMenu->addAction( selectedColumns.size() > 1 ? tr(
"Delete %n Column(s)",
nullptr, selectedColumns.size() ) : tr(
"Delete Column" ) );
99 mHeaderMenu->popup( horizontalHeader()->mapToGlobal( point ) );
102 verticalHeader()->setContextMenuPolicy( Qt::CustomContextMenu );
103 connect( verticalHeader(), &QWidget::customContextMenuRequested,
this, [ = ](
const QPoint & point )
105 const int row = verticalHeader()->logicalIndexAt( point.y() );
107 QSet< int > selectedRows;
108 for (
const QModelIndex &index : selectedIndexes() )
110 selectedRows.insert( index.row() );
114 bool isConsecutive = collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow );
117 if ( selectedIndexes().count() == 1 )
121 isConsecutive =
true;
123 else if ( !selectedRows.contains( row ) )
127 isConsecutive =
true;
130 mHeaderMenu->clear();
133 QAction *insertBefore = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr(
"Insert %n Row(s) Above",
nullptr, selectedRows.size() ) : tr(
"Insert Row Above" ) );
135 QAction *insertAfter = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr(
"Insert %n Row(s) Below",
nullptr, selectedRows.size() ) : tr(
"Insert Row Below" ) );
138 QAction *deleteSelected = mHeaderMenu->addAction( selectedRows.size() > 1 ? tr(
"Delete %n Row(s)",
nullptr, selectedRows.size() ) : tr(
"Delete Row" ) );
141 mHeaderMenu->popup( verticalHeader()->mapToGlobal( point ) );
146 connect( delegate, &QgsTableEditorDelegate::updateNumericFormatForIndex,
this, &QgsTableEditorWidget::updateNumericFormatForIndex );
147 setItemDelegate( delegate );
150 connect(
this, &QTableWidget::cellDoubleClicked,
this, [ = ]
154 d->setWeakEditorMode(
false );
163 qDeleteAll( mNumericFormats );
166void QgsTableEditorWidget::updateNumericFormatForIndex(
const QModelIndex &index )
168 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
172 i->setData( Qt::DisplayRole, format->formatDouble( index.data( CellContent ).toDouble(),
QgsNumericFormatContext() ) );
177void QgsTableEditorWidget::updateHeaders()
185 for (
char c =
'A';
c <=
'Z';
c++ )
187 letters.push_back( QString(
c ) );
190 int len = letters.length();
194 for (
int i = 0; i < 1000; i++ )
200 first = letters.at( fIndex );
210 current += letters.at( index );
211 headers.push_back( current );
217 setHorizontalHeaderLabels( headers );
220 if ( mIncludeHeader )
221 headers << tr(
"Header" );
222 for (
int i = 1; i <= 1000; i++ )
224 headers << QString::number( i );
227 setVerticalHeaderLabels( headers );
230bool QgsTableEditorWidget::collectConsecutiveRowRange(
const QModelIndexList &list,
int &minRow,
int &maxRow )
const
232 QSet< int > includedRows;
233 minRow = std::numeric_limits< int >::max();
235 for (
const QModelIndex &index : list )
237 includedRows.insert( index.row() );
238 minRow = std::min( minRow, index.row() );
239 maxRow = std::max( maxRow, index.row() );
243 for (
int r = minRow + 1; r < maxRow; r++ )
245 if ( !includedRows.contains( r ) )
251bool QgsTableEditorWidget::collectConsecutiveColumnRange(
const QModelIndexList &list,
int &minColumn,
int &maxColumn )
const
253 QSet< int > includedColumns;
254 minColumn = std::numeric_limits< int >::max();
256 for (
const QModelIndex &index : list )
258 includedColumns.insert( index.column() );
259 minColumn = std::min( minColumn, index.column() );
260 maxColumn = std::max( maxColumn, index.column() );
264 for (
int r = minColumn + 1; r < maxColumn; r++ )
266 if ( !includedColumns.contains( r ) )
272QList<int> QgsTableEditorWidget::collectUniqueRows(
const QModelIndexList &list )
const
275 for (
const QModelIndex &index : list )
277 if ( !res.contains( index.row() ) )
280 std::sort( res.begin(), res.end() );
284QList<int> QgsTableEditorWidget::collectUniqueColumns(
const QModelIndexList &list )
const
287 for (
const QModelIndex &index : list )
289 if ( !res.contains( index.column() ) )
290 res << index.column();
292 std::sort( res.begin(), res.end() );
296bool QgsTableEditorWidget::isRectangularSelection(
const QModelIndexList &list )
const
305 QSet< QPair< int, int > > selectedSet;
306 for (
const QModelIndex &index : list )
308 if ( minRow == -1 || index.row() < minRow )
309 minRow = index.row();
310 if ( maxRow == -1 || index.row() > maxRow )
311 maxRow = index.row();
312 if ( minCol == -1 || index.column() < minCol )
313 minCol = index.column();
314 if ( maxCol == -1 || index.column() > maxCol )
315 maxCol = index.column();
316 selectedSet.insert( qMakePair( index.row(), index.column() ) );
320 if ( list.size() != ( maxRow - minRow + 1 ) * ( maxCol - minCol + 1 ) )
324 QSet< QPair< int, int > > expectedSet;
325 for (
int row = minRow; row <= maxRow; ++row )
327 for (
int col = minCol; col <= maxCol; ++col )
329 expectedSet.insert( qMakePair( row, col ) );
332 return selectedSet == expectedSet;
335bool QgsTableEditorWidget::hasMergedCells(
const QModelIndexList &list )
const
337 for (
const QModelIndex &index : list )
339 if ( rowSpan( index.row(), index.column() ) > 1
340 || columnSpan( index.row(), index.column() ) > 1 )
348 switch ( event->key() )
354 QTableWidget::keyPressEvent( event );
355 setCurrentCell( currentRow() + 1, currentColumn() );
366 QTableWidget::keyPressEvent( event );
370 d->setWeakEditorMode(
true );
377 qDeleteAll( mNumericFormats );
378 mNumericFormats.clear();
381 int rowNumber = mIncludeHeader ? 1 : 0;
383 setRowCount( contents.size() + rowNumber );
388 setColumnCount( row.size() );
396 item->setData( CellContent, col.content() );
397 item->setData( Qt::BackgroundRole, col.backgroundColor().isValid() ? col.backgroundColor() : QColor( 255, 255, 255 ) );
398 item->setData( PresetBackgroundColorRole, col.backgroundColor().isValid() ? col.backgroundColor() : QVariant() );
399 item->setData( Qt::ForegroundRole, col.textFormat().isValid() ? col.textFormat().color() : QVariant() );
400 item->setData( TextFormat, QVariant::fromValue( col.textFormat() ) );
401 item->setData( HorizontalAlignment,
static_cast< int >( col.horizontalAlignment() ) );
402 item->setData( VerticalAlignment,
static_cast< int >( col.verticalAlignment() ) );
403 item->setData( CellProperty, QVariant::fromValue( col.content().value<
QgsProperty >() ) );
405 if ( col.content().value<
QgsProperty >().isActive() )
406 item->setFlags( item->flags() & ( ~Qt::ItemIsEditable ) );
408 if (
auto *lNumericFormat = col.numericFormat() )
410 mNumericFormats.insert( item, lNumericFormat->clone() );
411 item->setData( Qt::DisplayRole, mNumericFormats.value( item )->formatDouble( col.content().toDouble(), numericContext ) );
413 setItem( rowNumber, colNumber, item );
415 if ( col.rowSpan() > 1 || col.columnSpan() > 1 )
416 setSpan( rowNumber, colNumber, col.rowSpan(), col.columnSpan() );
428 resizeColumnsToContents();
429 resizeRowsToContents();
438 items.reserve( rowCount() );
440 QSet< QPair< int, int > > spannedCells;
441 for (
int r = mIncludeHeader ? 1 : 0; r < rowCount(); r++ )
444 row.reserve( columnCount() );
445 for (
int c = 0;
c < columnCount();
c++ )
448 if ( QTableWidgetItem *i = item( r,
c ) )
450 cell.
setContent( i->data( CellProperty ).value<
QgsProperty >().isActive() ? i->data( CellProperty ) : i->data( CellContent ) );
454 cell.
setVerticalAlignment(
static_cast< Qt::Alignment
>( i->data( VerticalAlignment ).toInt() ) );
457 if ( !spannedCells.contains( qMakePair( r,
c ) ) )
459 const int rowsSpan = rowSpan( r,
c );
460 const int colsSpan = columnSpan( r,
c );
461 for (
int spannedRow = r; spannedRow < r + rowsSpan; ++spannedRow )
463 for (
int spannedCol =
c; spannedCol <
c + colsSpan; ++spannedCol )
465 spannedCells.insert( qMakePair( spannedRow, spannedCol ) );
468 cell.
setSpan( rowSpan( r,
c ), columnSpan( r,
c ) );
475 if ( mNumericFormats.value( i ) )
480 row.push_back( cell );
482 items.push_back( row );
490 bool changed =
false;
492 std::unique_ptr< QgsNumericFormat > newFormat( format );
493 const QModelIndexList selection = selectedIndexes();
495 for (
const QModelIndex &index : selection )
497 if ( index.row() == 0 && mIncludeHeader )
500 QTableWidgetItem *i = item( index.row(), index.column() );
503 i =
new QTableWidgetItem();
504 setItem( index.row(), index.column(), i );
506 if ( !mNumericFormats.value( i ) && newFormat )
509 mNumericFormats.insert( i, newFormat->clone() );
511 else if ( mNumericFormats.value( i ) && !newFormat )
514 delete mNumericFormats.value( i );
515 mNumericFormats.remove( i );
517 else if ( newFormat && *newFormat != *mNumericFormats.value( i ) )
520 delete mNumericFormats.value( i );
521 mNumericFormats.insert( i, newFormat->clone() );
523 i->setData( Qt::DisplayRole, newFormat ? mNumericFormats.value( i )->formatDouble( i->data( CellContent ).toDouble(), numericContext ) : i->data( CellContent ) );
526 if ( changed && !mBlockSignals )
534 const QModelIndexList selection = selectedIndexes();
535 for (
const QModelIndex &index : selection )
537 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
541 f = mNumericFormats.value( i );
544 else if ( ( !f && !mNumericFormats.value( i ) )
545 || ( f && mNumericFormats.value( i ) && *f == *mNumericFormats.value( i ) ) )
564 const QModelIndexList selection = selectedIndexes();
565 for (
const QModelIndex &index : selection )
567 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
571 f = mNumericFormats.value( i );
574 else if ( ( !f && !mNumericFormats.value( i ) )
575 || ( f && mNumericFormats.value( i ) && *f == *mNumericFormats.value( i ) ) )
600 const QModelIndexList selection = selectedIndexes();
601 for (
const QModelIndex &index : selection )
603 QColor indexColor = model()->data( index, PresetBackgroundColorRole ).isValid() ? model()->data( index, PresetBackgroundColorRole ).value< QColor >() : QColor();
609 else if ( indexColor ==
c )
621 Qt::Alignment alignment = Qt::AlignLeft;
623 const QModelIndexList selection = selectedIndexes();
624 for (
const QModelIndex &index : selection )
626 Qt::Alignment cellAlign =
static_cast< Qt::Alignment
>( model()->data( index, HorizontalAlignment ).toInt() );
629 alignment = cellAlign;
632 else if ( cellAlign == alignment )
636 return Qt::AlignLeft | Qt::AlignTop;
644 Qt::Alignment alignment = Qt::AlignVCenter;
646 const QModelIndexList selection = selectedIndexes();
647 for (
const QModelIndex &index : selection )
649 Qt::Alignment cellAlign =
static_cast< Qt::Alignment
>( model()->data( index, VerticalAlignment ).toInt() );
652 alignment = cellAlign;
655 else if ( cellAlign == alignment )
659 return Qt::AlignLeft | Qt::AlignTop;
669 const QModelIndexList selection = selectedIndexes();
670 for (
const QModelIndex &index : selection )
675 property = cellProperty;
678 else if ( cellProperty == property )
692 const QModelIndexList selection = selectedIndexes();
693 for (
const QModelIndex &index : selection )
695 if ( !model()->data( index, TextFormat ).isValid() )
704 else if ( cellFormat == format )
716 const QModelIndexList selection = selectedIndexes();
717 for (
const QModelIndex &index : selection )
722 else if ( thisHeight != height )
735 const QModelIndexList selection = selectedIndexes();
736 for (
const QModelIndex &index : selection )
741 else if ( thisWidth != width )
753 for (
int col = 0; col < columnCount(); ++col )
755 double thisHeight = model()->data( model()->index( row + ( mIncludeHeader ? 1 : 0 ), col ), RowHeight ).toDouble();
756 height = std::max( thisHeight, height );
764 for (
int row = 0; row < rowCount(); ++row )
766 double thisWidth = model()->data( model()->index( row, column ), ColumnWidth ).toDouble();
767 width = std::max( thisWidth, width );
774 if ( row == 0 && mIncludeHeader )
777 bool changed =
false;
780 for (
int col = 0; col < columnCount(); ++col )
782 if ( QTableWidgetItem *i = item( row + ( mIncludeHeader ? 1 : 0 ), col ) )
784 if ( i->data( RowHeight ).toDouble() != height )
786 i->setData( RowHeight, height );
792 QTableWidgetItem *newItem =
new QTableWidgetItem();
793 newItem->setData( RowHeight, height );
794 setItem( row + ( mIncludeHeader ? 1 : 0 ), col, newItem );
800 if ( changed && !mBlockSignals )
806 bool changed =
false;
808 for (
int row = 0; row < rowCount(); ++row )
810 if ( QTableWidgetItem *i = item( row, col ) )
812 if ( i->data( ColumnWidth ).toDouble() != width )
814 i->setData( ColumnWidth, width );
820 QTableWidgetItem *newItem =
new QTableWidgetItem();
821 newItem->setData( ColumnWidth, width );
822 setItem( row, col, newItem );
827 if ( changed && !mBlockSignals )
833 return collectUniqueRows( selectedIndexes() );
838 return collectUniqueColumns( selectedIndexes() );
843 if ( !mIncludeHeader )
844 return QVariantList();
847 res.reserve( columnCount() );
848 for (
int col = 0; col < columnCount(); ++col )
850 if ( QTableWidgetItem *i = item( 0, col ) )
852 res << i->data( CellContent );
864 if ( !mIncludeHeader )
867 return collectUniqueRows( selectedIndexes() ).contains( 0 );
872 return selectedIndexes().size() > 1
874 && isRectangularSelection( selectedIndexes() );
879 return !selectedIndexes().empty()
881 && hasMergedCells( selectedIndexes() );
886 if ( rowCount() == 0 )
894 if ( !collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow ) )
897 const int rowsToInsert = maxRow - minRow + 1;
898 for (
int i = 0; i < rowsToInsert; ++i )
899 insertRow( maxRow + 1 );
902 if ( !mBlockSignals )
908 if ( rowCount() == 0 )
916 if ( !collectConsecutiveRowRange( selectedIndexes(), minRow, maxRow ) )
919 const int rowsToInsert = maxRow - minRow + 1;
920 for (
int i = 0; i < rowsToInsert; ++i )
924 if ( !mBlockSignals )
930 if ( columnCount() == 0 )
938 if ( !collectConsecutiveColumnRange( selectedIndexes(), minColumn, maxColumn ) )
941 const int columnsToInsert = maxColumn - minColumn + 1;
942 for (
int i = 0; i < columnsToInsert; ++i )
943 insertColumn( minColumn );
946 if ( !mBlockSignals )
952 if ( columnCount() == 0 )
960 if ( !collectConsecutiveColumnRange( selectedIndexes(), minColumn, maxColumn ) )
963 const int columnsToInsert = maxColumn - minColumn + 1;
964 for (
int i = 0; i < columnsToInsert; ++i )
965 insertColumn( maxColumn + 1 );
968 if ( !mBlockSignals )
978 bool changed =
false;
979 for (
int i = rows.size() - 1; i >= 0 && rowCount() > 1; i-- )
981 removeRow( rows.at( i ) );
985 if ( changed && !mBlockSignals )
992 if ( columns.empty() )
995 bool changed =
false;
996 for (
int i = columns.size() - 1; i >= 0 && columnCount() > 1; i-- )
998 removeColumn( columns.at( i ) );
1002 if ( !mBlockSignals && changed )
1008 const QModelIndexList s = selectedIndexes();
1009 for (
const QModelIndex &index : s )
1011 selectionModel()->select( index, QItemSelectionModel::Rows | QItemSelectionModel::Select );
1017 const QModelIndexList s = selectedIndexes();
1018 for (
const QModelIndex &index : s )
1020 selectionModel()->select( index, QItemSelectionModel::Columns | QItemSelectionModel::Select );
1026 const QModelIndexList selection = selectedIndexes();
1027 bool changed =
false;
1029 for (
const QModelIndex &index : selection )
1031 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1033 i->setText( QString() );
1034 i->setData( CellContent, QVariant() );
1039 if ( changed && !mBlockSignals )
1045 const QModelIndexList selection = selectedIndexes();
1046 bool changed =
false;
1048 for (
const QModelIndex &index : selection )
1050 if ( index.row() == 0 && mIncludeHeader )
1053 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1055 if ( i->data( Qt::ForegroundRole ).value< QColor >() != color )
1057 i->setData( Qt::ForegroundRole, color.isValid() ? color : QVariant() );
1060 i->setData( TextFormat, QVariant::fromValue( f ) );
1066 QTableWidgetItem *newItem =
new QTableWidgetItem();
1067 newItem->setData( Qt::ForegroundRole, color.isValid() ? color : QVariant() );
1070 newItem->setData( TextFormat, QVariant::fromValue( f ) );
1071 setItem( index.row(), index.column(), newItem );
1076 if ( changed && !mBlockSignals )
1082 const QModelIndexList selection = selectedIndexes();
1083 bool changed =
false;
1085 for (
const QModelIndex &index : selection )
1087 if ( index.row() == 0 && mIncludeHeader )
1090 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1092 if ( i->data( PresetBackgroundColorRole ).value< QColor >() != color )
1094 i->setData( Qt::BackgroundRole, color.isValid() ? color : QVariant() );
1095 i->setData( PresetBackgroundColorRole, color.isValid() ? color : QVariant() );
1101 QTableWidgetItem *newItem =
new QTableWidgetItem();
1102 newItem->setData( Qt::BackgroundRole, color.isValid() ? color : QVariant() );
1103 newItem->setData( PresetBackgroundColorRole, color.isValid() ? color : QVariant() );
1104 setItem( index.row(), index.column(), newItem );
1109 if ( changed && !mBlockSignals )
1115 const QModelIndexList selection = selectedIndexes();
1116 bool changed =
false;
1118 for (
const QModelIndex &index : selection )
1120 if ( index.row() == 0 && mIncludeHeader )
1123 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1125 if (
static_cast< Qt::Alignment
>( i->data( HorizontalAlignment ).toInt() ) != alignment )
1127 i->setData( HorizontalAlignment,
static_cast< int >( alignment ) );
1133 QTableWidgetItem *newItem =
new QTableWidgetItem();
1134 newItem->setData( HorizontalAlignment,
static_cast< int >( alignment ) );
1135 setItem( index.row(), index.column(), newItem );
1140 if ( changed && !mBlockSignals )
1146 const QModelIndexList selection = selectedIndexes();
1147 bool changed =
false;
1149 for (
const QModelIndex &index : selection )
1151 if ( index.row() == 0 && mIncludeHeader )
1154 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1156 if (
static_cast< Qt::Alignment
>( i->data( HorizontalAlignment ).toInt() ) != alignment )
1158 i->setData( VerticalAlignment,
static_cast< int >( alignment ) );
1164 QTableWidgetItem *newItem =
new QTableWidgetItem();
1165 newItem->setData( VerticalAlignment,
static_cast< int >( alignment ) );
1166 setItem( index.row(), index.column(), newItem );
1171 if ( changed && !mBlockSignals )
1177 const QModelIndexList selection = selectedIndexes();
1178 bool changed =
false;
1180 for (
const QModelIndex &index : selection )
1182 if ( index.row() == 0 && mIncludeHeader )
1185 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1187 if ( i->data( CellProperty ).value<
QgsProperty >() != property )
1191 i->setData( CellProperty, QVariant::fromValue( property ) );
1193 i->setFlags( i->flags() & ( ~Qt::ItemIsEditable ) );
1197 i->setData( CellProperty, QVariant() );
1198 i->setText( QString() );
1199 i->setFlags( i->flags() | Qt::ItemIsEditable );
1206 QTableWidgetItem *newItem =
new QTableWidgetItem( property.
asExpression() );
1209 newItem->setData( CellProperty, QVariant::fromValue( property ) );
1210 newItem->setFlags( newItem->flags() & ( ~Qt::ItemIsEditable ) );
1214 newItem->setData( CellProperty, QVariant() );
1215 newItem->setFlags( newItem->flags() | Qt::ItemIsEditable );
1217 setItem( index.row(), index.column(), newItem );
1222 if ( changed && !mBlockSignals )
1228 const QModelIndexList selection = selectedIndexes();
1229 bool changed =
false;
1231 for (
const QModelIndex &index : selection )
1233 if ( index.row() == 0 && mIncludeHeader )
1236 if ( QTableWidgetItem *i = item( index.row(), index.column() ) )
1238 i->setData( TextFormat, QVariant::fromValue( format ) );
1239 i->setData( Qt::ForegroundRole, format.
color() );
1244 QTableWidgetItem *newItem =
new QTableWidgetItem();
1245 newItem->setData( TextFormat, QVariant::fromValue( format ) );
1246 newItem->setData( Qt::ForegroundRole, format.
color() );
1247 setItem( index.row(), index.column(), newItem );
1252 if ( changed && !mBlockSignals )
1258 bool changed =
false;
1261 for (
int row : rows )
1263 if ( row == 0 && mIncludeHeader )
1266 for (
int col = 0; col < columnCount(); ++col )
1268 if ( QTableWidgetItem *i = item( row, col ) )
1270 if ( i->data( RowHeight ).toDouble() != height )
1272 i->setData( RowHeight, height );
1278 QTableWidgetItem *newItem =
new QTableWidgetItem();
1279 newItem->setData( RowHeight, height );
1280 setItem( row, col, newItem );
1286 if ( changed && !mBlockSignals )
1292 bool changed =
false;
1295 for (
int col : cols )
1297 for (
int row = 0; row < rowCount(); ++row )
1299 if ( QTableWidgetItem *i = item( row, col ) )
1301 if ( i->data( ColumnWidth ).toDouble() != width )
1303 i->setData( ColumnWidth, width );
1309 QTableWidgetItem *newItem =
new QTableWidgetItem();
1310 newItem->setData( ColumnWidth, width );
1311 setItem( row, col, newItem );
1317 if ( changed && !mBlockSignals )
1323 if ( included == mIncludeHeader )
1326 mIncludeHeader = included;
1328 if ( mIncludeHeader )
1337 if ( !mIncludeHeader )
1342 for (
int col = 0; col < columnCount(); ++col )
1344 if ( QTableWidgetItem *i = item( 0, col ) )
1346 i->setText( headers.value( col ).toString() );
1347 i->setData( CellContent, headers.value( col ) );
1351 QTableWidgetItem *item =
new QTableWidgetItem( headers.value( col ).toString() );
1352 item->setData( CellContent, headers.value( col ) );
1353 setItem( 0, col, item );
1361 const QModelIndexList selection = selectedIndexes();
1362 if ( selection.size() < 2 )
1369 for (
const QModelIndex &index : selection )
1371 if ( minRow == -1 || index.row() < minRow )
1372 minRow = index.row();
1373 if ( maxRow == -1 || index.row() > maxRow )
1374 maxRow = index.row();
1375 if ( minCol == -1 || index.column() < minCol )
1376 minCol = index.column();
1377 if ( maxCol == -1 || index.column() > maxCol )
1378 maxCol = index.column();
1381 setSpan( minRow, minCol, maxRow - minRow + 1, maxCol - minCol + 1 );
1383 if ( !mBlockSignals )
1389 const QModelIndexList selection = selectedIndexes();
1390 for (
const QModelIndex &index : selection )
1392 if ( rowSpan( index.row(), index.column() ) > 1 ||
1393 columnSpan( index.row(), index.column() ) > 1 )
1394 setSpan( index.row(), index.column(), 1, 1 );
1397 if ( !mBlockSignals )
1403QgsTableEditorTextEdit::QgsTableEditorTextEdit( QWidget *parent )
1404 : QPlainTextEdit( parent )
1407 document()->setDocumentMargin( document()->documentMargin() / 2 );
1409 connect(
this, &QPlainTextEdit::textChanged,
this, &QgsTableEditorTextEdit::resizeToContents );
1410 updateMinimumSize();
1413void QgsTableEditorTextEdit::keyPressEvent( QKeyEvent *event )
1415 switch ( event->key() )
1418 case Qt::Key_Return:
1420 if ( event->modifiers() & Qt::ControlModifier )
1423 insertPlainText( QString(
'\n' ) );
1439 if ( mWeakEditorMode )
1446 QPlainTextEdit::keyPressEvent( event );
1453 if ( event->modifiers() & Qt::ControlModifier )
1457 insertPlainText( QString(
'\t' ) );
1468 QPlainTextEdit::keyPressEvent( event );
1472void QgsTableEditorTextEdit::updateMinimumSize()
1474 const double tm = document()->documentMargin();
1475 const QMargins cm = contentsMargins();
1476 const int width = tm * 2 + cm.left() + cm.right() + 30;
1477 const int height = tm * 2 + cm.top() + cm.bottom() + 4;
1478 QStyleOptionFrame opt;
1479 initStyleOption( &opt );
1480 const QSize sizeFromContent = style()->sizeFromContents( QStyle::CT_LineEdit, &opt, QSize( width, height ),
this );
1481 setMinimumWidth( sizeFromContent.width() );
1482 setMinimumHeight( sizeFromContent.height() );
1485void QgsTableEditorTextEdit::setWeakEditorMode(
bool weakEditorMode )
1487 mWeakEditorMode = weakEditorMode;
1490void QgsTableEditorTextEdit::resizeToContents()
1492 int oldWidth = width();
1493 int oldHeight = height();
1494 if ( mOriginalWidth == -1 )
1495 mOriginalWidth = oldWidth;
1496 if ( mOriginalHeight == -1 )
1497 mOriginalHeight = oldHeight;
1499 if ( QWidget *parent = parentWidget() )
1501 QPoint position = pos();
1502 QFontMetrics fm( font() );
1504 const QStringList lines = toPlainText().split(
'\n' );
1505 int maxTextLineWidth = 0;
1506 int totalTextHeight = 0;
1507 for (
const QString &line : lines )
1509 const QRect bounds = fontMetrics().boundingRect( line );
1510 maxTextLineWidth = std::max( maxTextLineWidth, bounds.width() );
1511 totalTextHeight += fm.height();
1514 int hintWidth = minimumWidth() + maxTextLineWidth;
1515 int hintHeight = minimumHeight() + totalTextHeight;
1516 int parentWidth = parent->width();
1517 int maxWidth = isRightToLeft() ? position.x() + oldWidth : parentWidth - position.x();
1518 int maxHeight = parent->height() - position.y();
1519 int newWidth = std::clamp( hintWidth, mOriginalWidth, maxWidth );
1520 int newHeight = std::clamp( hintHeight, mOriginalHeight, maxHeight );
1522 if ( mWidgetOwnsGeometry )
1524 setMaximumWidth( newWidth );
1525 setMaximumHeight( newHeight );
1527 if ( isRightToLeft() )
1528 move( position.x() - newWidth + oldWidth, position.y() );
1529 resize( newWidth, newHeight );
1533void QgsTableEditorTextEdit::changeEvent( QEvent *e )
1535 switch ( e->type() )
1537 case QEvent::FontChange:
1538 case QEvent::StyleChange:
1539 case QEvent::ContentsRectChange:
1540 updateMinimumSize();
1545 QPlainTextEdit::changeEvent( e );
1548QgsTableEditorDelegate::QgsTableEditorDelegate( QObject *parent )
1549 : QStyledItemDelegate( parent )
1554void QgsTableEditorDelegate::setWeakEditorMode(
bool weakEditorMode )
1556 mWeakEditorMode = weakEditorMode;
1559QWidget *QgsTableEditorDelegate::createEditor( QWidget *parent,
const QStyleOptionViewItem &,
const QModelIndex & )
const
1561 QgsTableEditorTextEdit *w =
new QgsTableEditorTextEdit( parent );
1562 w->setWeakEditorMode( mWeakEditorMode );
1564 if ( !w->style()->styleHint( QStyle::SH_ItemView_DrawDelegateFrame, 0, w ) )
1565 w->setFrameShape( QFrame::NoFrame );
1566 if ( !w->style()->styleHint( QStyle::SH_ItemView_ShowDecorationSelected, 0, w ) )
1567 w->setWidgetOwnsGeometry(
true );
1572void QgsTableEditorDelegate::setEditorData( QWidget *editor,
const QModelIndex &index )
const
1574 QVariant value = index.model()->data( index, QgsTableEditorWidget::CellContent );
1575 if ( QgsTableEditorTextEdit *lineEdit = qobject_cast<QgsTableEditorTextEdit * >( editor ) )
1577 if ( index != mLastIndex || lineEdit->toPlainText() != value.toString() )
1579 lineEdit->setPlainText( value.toString() );
1580 lineEdit->selectAll();
1586void QgsTableEditorDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index )
const
1588 if ( QgsTableEditorTextEdit *lineEdit = qobject_cast<QgsTableEditorTextEdit * >( editor ) )
1590 const QString text = lineEdit->toPlainText();
1591 if ( text != model->data( index, QgsTableEditorWidget::CellContent ).toString() && !model->data( index, QgsTableEditorWidget::CellProperty ).value<
QgsProperty >().
isActive() )
1593 model->setData( index, text, QgsTableEditorWidget::CellContent );
1594 model->setData( index, text, Qt::DisplayRole );
1595 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 setSpan(int rowSpan, int columnSpan)
Sets the row and column span for 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.