QGIS API Documentation 3.41.0-Master (cea29feecf2)
Loading...
Searching...
No Matches
qgstableeditordialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgstableeditordialog.cpp
3 ------------------------
4 begin : January 2020
5 copyright : (C) 2020 by Nyall Dawson
6 email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "moc_qgstableeditordialog.cpp"
19#include "qgsmessagebar.h"
20#include "qgsgui.h"
21#include "qgsdockwidget.h"
22#include "qgspanelwidgetstack.h"
24#include "qgssettings.h"
25#include "qgsvectorlayer.h"
26#include "qgslayout.h"
30
31#include <QClipboard>
32#include <QMessageBox>
33
35 : QMainWindow( parent )
36{
37 setupUi( this );
38 setWindowTitle( tr( "Table Designer" ) );
39
40 setAttribute( Qt::WA_DeleteOnClose );
41 setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
42
44
45 QGridLayout *viewLayout = new QGridLayout();
46 viewLayout->setSpacing( 0 );
47 viewLayout->setContentsMargins( 0, 0, 0, 0 );
48 centralWidget()->layout()->setSpacing( 0 );
49 centralWidget()->layout()->setContentsMargins( 0, 0, 0, 0 );
50
51 mMessageBar = new QgsMessageBar( centralWidget() );
52 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
53 static_cast<QGridLayout *>( centralWidget()->layout() )->addWidget( mMessageBar, 0, 0, 1, 1, Qt::AlignTop );
54
55 mTableWidget = new QgsTableEditorWidget();
56 mTableWidget->setContentsMargins( 0, 0, 0, 0 );
57 viewLayout->addWidget( mTableWidget, 0, 0 );
58 mViewFrame->setLayout( viewLayout );
59 mViewFrame->setContentsMargins( 0, 0, 0, 0 );
60
61 mTableWidget->setFocus();
62 mTableWidget->setTableContents( QgsTableContents() << ( QgsTableRow() << QgsTableCell() ) );
63
64 connect( mTableWidget, &QgsTableEditorWidget::tableChanged, this, [=] {
65 if ( !mBlockSignals )
66 emit tableChanged();
67 } );
68
69 const int minDockWidth( fontMetrics().boundingRect( QStringLiteral( "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) ).width() );
70
71 mPropertiesDock = new QgsDockWidget( tr( "Cell Contents" ), this );
72 mPropertiesDock->setObjectName( QStringLiteral( "FormattingDock" ) );
73 mPropertiesStack = new QgsPanelWidgetStack();
74 mPropertiesDock->setWidget( mPropertiesStack );
75 mPropertiesDock->setMinimumWidth( minDockWidth );
76
77 mFormattingWidget = new QgsTableEditorFormattingWidget();
78 mFormattingWidget->setDockMode( true );
79 mPropertiesStack->setMainPanel( mFormattingWidget );
80
81 mPropertiesDock->setFeatures( QDockWidget::NoDockWidgetFeatures );
82
84
88
89 connect( mFormattingWidget, &QgsTableEditorFormattingWidget::textFormatChanged, this, [=] {
90 mTableWidget->setSelectionTextFormat( mFormattingWidget->textFormat() );
91 } );
92
93 connect( mFormattingWidget, &QgsTableEditorFormattingWidget::numberFormatChanged, this, [=] {
94 mTableWidget->setSelectionNumericFormat( mFormattingWidget->numericFormat() );
95 } );
98
99 connect( mTableWidget, &QgsTableEditorWidget::activeCellChanged, this, [=] {
100 mFormattingWidget->setBackgroundColor( mTableWidget->selectionBackgroundColor() );
101 mFormattingWidget->setNumericFormat( mTableWidget->selectionNumericFormat(), mTableWidget->hasMixedSelectionNumericFormat() );
102 mFormattingWidget->setRowHeight( mTableWidget->selectionRowHeight() );
103 mFormattingWidget->setColumnWidth( mTableWidget->selectionColumnWidth() );
104 mFormattingWidget->setTextFormat( mTableWidget->selectionTextFormat() );
105 mFormattingWidget->setHorizontalAlignment( mTableWidget->selectionHorizontalAlignment() );
106 mFormattingWidget->setVerticalAlignment( mTableWidget->selectionVerticalAlignment() );
107 mFormattingWidget->setCellProperty( mTableWidget->selectionCellProperty() );
108
109 updateActionsFromSelection();
110
111 mFormattingWidget->setEnabled( !mTableWidget->isHeaderCellSelected() );
112 } );
113 updateActionsFromSelection();
114
115 addDockWidget( Qt::RightDockWidgetArea, mPropertiesDock );
116
117 mActionImportFromClipboard->setEnabled( !QApplication::clipboard()->text().isEmpty() );
118 connect( QApplication::clipboard(), &QClipboard::dataChanged, this, [=]() { mActionImportFromClipboard->setEnabled( !QApplication::clipboard()->text().isEmpty() ); } );
119
120 connect( mActionImportFromClipboard, &QAction::triggered, this, &QgsTableEditorDialog::setTableContentsFromClipboard );
121 connect( mActionClose, &QAction::triggered, this, &QMainWindow::close );
122 connect( mActionInsertRowsAbove, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertRowsAbove );
123 connect( mActionInsertRowsBelow, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertRowsBelow );
124 connect( mActionInsertColumnsBefore, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertColumnsBefore );
125 connect( mActionInsertColumnsAfter, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertColumnsAfter );
126 connect( mActionMergeSelected, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::mergeSelectedCells );
127 connect( mActionSplitSelected, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::splitSelectedCells );
128 connect( mActionDeleteRows, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::deleteRows );
129 connect( mActionDeleteColumns, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::deleteColumns );
130 connect( mActionSelectRow, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::expandRowSelection );
131 connect( mActionSelectColumn, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::expandColumnSelection );
132 connect( mActionSelectAll, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::selectAll );
133 connect( mActionClear, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::clearSelectedCells );
134 connect( mActionIncludeHeader, &QAction::toggled, this, [=]( bool checked ) {
135 mTableWidget->setIncludeTableHeader( checked );
136 emit includeHeaderChanged( checked );
137 } );
138
139 // restore the toolbar and dock widgets positions using Qt settings API
140 const QgsSettings settings;
141
142 const QByteArray state = settings.value( QStringLiteral( "LayoutDesigner/tableEditorState" ), QByteArray(), QgsSettings::App ).toByteArray();
143 if ( !state.isEmpty() && !restoreState( state ) )
144 {
145 QgsDebugError( QStringLiteral( "restore of table editor dialog UI state failed" ) );
146 }
147}
148
150{
151 QgsSettings settings;
152 // store the toolbar/dock widget settings using Qt settings API
153 settings.setValue( QStringLiteral( "LayoutDesigner/tableEditorState" ), saveState(), QgsSettings::App );
154}
155
157{
158 return mLayer.data();
159}
160
162{
163 if ( layer != mLayer )
164 {
165 mLayer = layer;
166 mFormattingWidget->setLayer( layer );
167 }
168}
169
171{
172 return mTable;
173}
174
176{
177 if ( mTable == table )
178 return;
179
180 mTable = table;
181
182 if ( QgsLayout *layout = table->layout() )
183 {
184 setLayer( layout->reportContext().layer() );
185 }
187
190
191 int row = 0;
192 const QList<double> rowHeights = table->rowHeights();
193 for ( const double height : rowHeights )
194 {
195 setTableRowHeight( row, height );
196 row++;
197 }
198 int col = 0;
199 const QList<double> columnWidths = table->columnWidths();
200 QVariantList headers;
201 headers.reserve( columnWidths.size() );
202 for ( const double width : columnWidths )
203 {
204 setTableColumnWidth( col, width );
205 headers << ( col < table->headers().count() ? table->headers().value( col ).heading() : QVariant() );
206 col++;
207 }
208 setTableHeaders( headers );
209}
210
211
213{
214 if ( QApplication::clipboard()->text().isEmpty() )
215 return false;
216
217 if ( QMessageBox::question( this, tr( "Import Content From Clipboard" ), tr( "Importing content from clipboard will overwrite current table content. Are you sure?" ) ) != QMessageBox::Yes )
218 return false;
219
220 QgsTableContents contents;
221 const QStringList lines = QApplication::clipboard()->text().split( '\n' );
222 for ( const QString &line : lines )
223 {
224 if ( !line.isEmpty() )
225 {
226 QgsTableRow row;
227 const QStringList cells = line.split( '\t' );
228 for ( const QString &text : cells )
229 {
230 const QgsTableCell cell( text );
231 row << cell;
232 }
233 contents << row;
234 }
235 }
236
237 if ( !contents.isEmpty() )
238 {
239 setTableContents( contents );
240 emit tableChanged();
241 return true;
242 }
243
244 return false;
245}
246
248{
249 mBlockSignals = true;
250 mTableWidget->setTableContents( contents );
251 mTableWidget->resizeRowsToContents();
252 mTableWidget->resizeColumnsToContents();
253 mBlockSignals = false;
254}
255
257{
258 return mTableWidget->tableContents();
259}
260
262{
263 return mTableWidget->tableRowHeight( row );
264}
265
267{
268 return mTableWidget->tableColumnWidth( column );
269}
270
271void QgsTableEditorDialog::setTableRowHeight( int row, double height )
272{
273 mTableWidget->setTableRowHeight( row, height );
274}
275
276void QgsTableEditorDialog::setTableColumnWidth( int column, double width )
277{
278 mTableWidget->setTableColumnWidth( column, width );
279}
280
282{
283 return mActionIncludeHeader->isChecked();
284}
285
287{
288 mActionIncludeHeader->setChecked( included );
289}
290
292{
293 return mTableWidget->tableHeaders();
294}
295
296void QgsTableEditorDialog::setTableHeaders( const QVariantList &headers )
297{
298 mTableWidget->setTableHeaders( headers );
299}
300
305
306void QgsTableEditorDialog::updateActionsFromSelection()
307{
308 const int rowCount = mTableWidget->rowsAssociatedWithSelection().size();
309 const int columnCount = mTableWidget->columnsAssociatedWithSelection().size();
310
311 mActionInsertRowsAbove->setEnabled( rowCount > 0 );
312 mActionInsertRowsBelow->setEnabled( rowCount > 0 );
313 mActionDeleteRows->setEnabled( rowCount > 0 );
314 mActionSelectRow->setEnabled( rowCount > 0 );
315 if ( rowCount == 0 )
316 {
317 mActionInsertRowsAbove->setText( tr( "Rows Above" ) );
318 mActionInsertRowsBelow->setText( tr( "Rows Below" ) );
319 mActionDeleteRows->setText( tr( "Delete Rows" ) );
320 mActionSelectRow->setText( tr( "Select Rows" ) );
321 }
322 else if ( rowCount == 1 )
323 {
324 mActionInsertRowsAbove->setText( tr( "Row Above" ) );
325 mActionInsertRowsBelow->setText( tr( "Row Below" ) );
326 mActionDeleteRows->setText( tr( "Delete Row" ) );
327 mActionSelectRow->setText( tr( "Select Row" ) );
328 }
329 else
330 {
331 mActionInsertRowsAbove->setText( tr( "%n Row(s) Above", nullptr, rowCount ) );
332 mActionInsertRowsBelow->setText( tr( "%n Row(s) Below", nullptr, rowCount ) );
333 mActionDeleteRows->setText( tr( "Delete %n Row(s)", nullptr, rowCount ) );
334 mActionSelectRow->setText( tr( "Select %n Row(s)", nullptr, rowCount ) );
335 }
336
337 mActionInsertColumnsBefore->setEnabled( columnCount > 0 );
338 mActionInsertColumnsAfter->setEnabled( columnCount > 0 );
339 mActionDeleteColumns->setEnabled( columnCount > 0 );
340 mActionSelectColumn->setEnabled( columnCount > 0 );
341 if ( columnCount == 0 )
342 {
343 mActionInsertColumnsBefore->setText( tr( "Columns Before" ) );
344 mActionInsertColumnsAfter->setText( tr( "Columns After" ) );
345 mActionDeleteColumns->setText( tr( "Delete Columns" ) );
346 mActionSelectColumn->setText( tr( "Select Columns" ) );
347 }
348 else if ( columnCount == 1 )
349 {
350 mActionInsertColumnsBefore->setText( tr( "Column Before" ) );
351 mActionInsertColumnsAfter->setText( tr( "Column After" ) );
352 mActionDeleteColumns->setText( tr( "Delete Column" ) );
353 mActionSelectColumn->setText( tr( "Select Column" ) );
354 }
355 else
356 {
357 mActionInsertColumnsBefore->setText( tr( "%n Column(s) Before", nullptr, columnCount ) );
358 mActionInsertColumnsAfter->setText( tr( "%n Column(s) After", nullptr, columnCount ) );
359 mActionDeleteColumns->setText( tr( "Delete %n Column(s)", nullptr, columnCount ) );
360 mActionSelectColumn->setText( tr( "Select %n Column(s)", nullptr, columnCount ) );
361 }
362
363 mActionMergeSelected->setEnabled( mTableWidget->canMergeSelection() );
364 mActionSplitSelected->setEnabled( mTableWidget->canSplitSelection() );
365}
366
367#include "qgstableeditordialog.h"
QgsDockWidget subclass with more fine-grained control over how the widget is closed or opened.
Abstract interface for generating an expression context.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:210
A layout table subclass that displays manually entered (and formatted) content.
QList< double > rowHeights() const
Returns the list of row heights (in millimeters) to use when rendering the table.
bool includeTableHeader() const
Returns true if the table includes a header row.
QgsLayoutTableColumns & headers()
Returns a reference to the list of headers shown in the table.
QList< double > columnWidths() const
Returns the list of column widths (in millimeters) to use when rendering the table.
QgsTableContents tableContents() const
Returns the contents of the table.
const QgsLayout * layout() const
Returns the layout the object is attached to.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition qgslayout.h:49
Base class for all map layer types.
Definition qgsmaplayer.h:76
A bar for displaying non-blocking messages to the user.
A stack widget to manage panels in the interface.
void setMainPanel(QgsPanelWidget *panel SIP_TRANSFER)
Sets the main panel widget for the stack and selects it for the user.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Encapsulates the contents and formatting of a single table cell.
void setIncludeTableHeader(bool included)
Sets whether the table includes a header row.
void setTable(QgsLayoutItemManualTable *table)
Sets the table associated with the editor.
QgsTableContents tableContents() const
Returns the current contents of the editor widget table.
void setTableHeaders(const QVariantList &headers)
Sets the table headers.
bool includeTableHeader() const
Returns true if the table includes a header row.
QgsTableEditorDialog(QWidget *parent=nullptr)
Constructor for QgsTableEditorDialog with the specified parent widget.
void includeHeaderChanged(bool included)
Emitted whenever the "include table header" setting is changed.
void setTableColumnWidth(int column, double width)
Sets the configured column width for the specified column.
void tableChanged()
Emitted whenever the table contents are changed.
void setTableRowHeight(int row, double height)
Sets the configured row height for the specified row.
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
bool setTableContentsFromClipboard()
Parses the clipboard text into contents to show in the editor widget.
QVariantList tableHeaders() const
Returns the table header values.
void closeEvent(QCloseEvent *) override
QgsMapLayer * layer() const
Returns the (possibly nullptr) layer associated with the expression editor context.
double tableRowHeight(int row)
Returns the configured row height for the specified row, or 0 if an automatic height should be used f...
double tableColumnWidth(int column)
Returns the configured column width for the specified column, or 0 if an automatic width should be us...
QgsLayoutItemManualTable * table() const
Returns the manual table associated with the editor.
void setLayer(QgsMapLayer *layer)
Sets the layer to be used associated with the expression editor context.
void setTableContents(const QgsTableContents &contents)
Sets the contents to show in the editor widget.
A reusable widget for formatting the contents of a QgsTableCell.
void cellPropertyChanged(const QgsProperty &property)
Emitted when the cell contents property shown in the widget is changed.
void textFormatChanged()
Emitted whenever the text format shown in the widget is changed.
void verticalAlignmentChanged(Qt::Alignment alignment)
Emitted when the vertical alignment shown in the widget is changed.
void rowHeightChanged(double height)
Emitted whenever the row height shown in the widget is changed.
QgsTextFormat textFormat() const
Returns the current text format shown in the widget.
void setVerticalAlignment(Qt::Alignment alignment)
Sets the vertical alignment to show in the widget.
void setTextFormat(const QgsTextFormat &format)
Sets the text format to show in the widget.
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
void setBackgroundColor(const QColor &color)
Sets the cell background color to show in the widget.
void backgroundColorChanged(const QColor &color)
Emitted whenever the cell background color is changed in the widget.
QgsNumericFormat * numericFormat()
Returns the current numeric format shown in the widget, or a nullptr if no numeric format is set.
void setCellProperty(const QgsProperty &property)
Sets the cell content's property to show in the widget.
void numberFormatChanged()
Emitted whenever the numeric format shown in the widget is changed.
void setColumnWidth(double width)
Sets the column width to show in the widget, or 0 for automatic width.
void setHorizontalAlignment(Qt::Alignment alignment)
Sets the horizontal alignment to show in the widget.
void setNumericFormat(QgsNumericFormat *format, bool isMixedFormat)
Sets the numeric format to show in the widget, or nullptr if no numeric format is set.
void horizontalAlignmentChanged(Qt::Alignment alignment)
Emitted when the horizontal alignment shown in the widget is changed.
void setLayer(QgsMapLayer *layer)
Set the layer to be used for in the expression editor context.
void columnWidthChanged(double width)
Emitted whenever the column width shown in the widget is changed.
void setRowHeight(double height)
Sets the row height to show in the widget, or 0 for automatic height.
A reusable widget for editing simple spreadsheet-style tables.
void setSelectionVerticalAlignment(Qt::Alignment alignment)
Sets the vertical alignment for the currently selected cells.
void splitSelectedCells()
Splits (un-merges) selected table cells.
QgsProperty selectionCellProperty()
Returns the QgsProperty used for the contents of the currently selected cells.
QVariantList tableHeaders() const
Returns the table header values.
void setSelectionTextFormat(const QgsTextFormat &format)
Sets the text format for the selected cells.
void setTableHeaders(const QVariantList &headers)
Sets the table headers.
void setSelectionBackgroundColor(const QColor &color)
Sets the background color for the currently selected cells.
void activeCellChanged()
Emitted whenever the active (or selected) cell changes in the widget.
Qt::Alignment selectionHorizontalAlignment()
Returns the horizontal alignment for the currently selected cells.
QgsTextFormat selectionTextFormat()
Returns the text format for the currently selected cells.
void insertColumnsAfter()
Inserts new columns after the current selection.
double selectionRowHeight()
Returns the height (in millimeters) of the rows associated with the current selection,...
void clearSelectedCells()
Clears the contents of the currently selected cells.
bool hasMixedSelectionNumericFormat()
Returns true if the current selection has a mix of numeric formats.
QList< int > rowsAssociatedWithSelection()
Returns a list of the rows associated with the current table selected cells.
QList< int > columnsAssociatedWithSelection()
Returns a list of the columns associated with the current table selected cells.
void deleteRows()
Deletes all rows associated with the current selected cells.
void setSelectionHorizontalAlignment(Qt::Alignment alignment)
Sets the horizontal alignment for the currently selected cells.
void setSelectionRowHeight(double height)
Sets the row height (in millimeters) for the currently selected rows, or 0 for automatic row height.
void insertRowsBelow()
Inserts new rows below the current selection.
double tableRowHeight(int row)
Returns the configured row height for the specified row, or 0 if an automatic height should be used f...
QColor selectionBackgroundColor()
Returns the background color for the currently selected cells.
bool canMergeSelection() const
Returns true if a selection has been made which can be merged.
Qt::Alignment selectionVerticalAlignment()
Returns the horizontal alignment for the currently selected cells.
void insertRowsAbove()
Inserts new rows above the current selection.
void setTableColumnWidth(int column, double width)
Sets the configured column width for the specified column.
void setSelectionCellProperty(const QgsProperty &property)
Sets the cell contents QgsProperty for the currently selected cells.
void setSelectionColumnWidth(double height)
Sets the column width (in millimeters) for the currently selected columns, or 0 for automatic column ...
double selectionColumnWidth()
Returns the width (in millimeters) of the columns associated with the current selection,...
bool canSplitSelection() const
Returns true if a selection has been made which can be split.
void expandRowSelection()
Expands out the selection to include whole rows associated with the current selected cells.
double tableColumnWidth(int column)
Returns the configured column width for the specified column, or 0 if an automatic width should be us...
void setIncludeTableHeader(bool included)
Sets whether the table includes a header row.
QgsNumericFormat * selectionNumericFormat()
Returns the numeric format used for the currently selected cells, or nullptr if the selection has no ...
void setTableRowHeight(int row, double height)
Sets the configured row height for the specified row.
QgsTableContents tableContents() const
Returns the current contents of the editor widget table.
void deleteColumns()
Deletes all columns associated with the current selected cells.
bool isHeaderCellSelected() const
Returns true if any header cells are selected.
void setTableContents(const QgsTableContents &contents)
Sets the contents to show in the editor widget.
void tableChanged()
Emitted whenever the table contents are changed.
void insertColumnsBefore()
Inserts new columns before the current selection.
void mergeSelectedCells()
Merges selected table cells.
void setSelectionNumericFormat(QgsNumericFormat *format)
Sets the numeric format to use for the currently selected cells.
void expandColumnSelection()
Expands out the selection to include whole columns associated with the current selected cells.
#define QgsDebugError(str)
Definition qgslogger.h:38
QVector< QgsTableRow > QgsTableContents
A set of table rows.
QVector< QgsTableCell > QgsTableRow
A row of table cells.