QGIS API Documentation 3.99.0-Master (d270888f95f)
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
18#include "qgsdockwidget.h"
19#include "qgsgui.h"
20#include "qgslayout.h"
24#include "qgsmessagebar.h"
25#include "qgspanelwidgetstack.h"
26#include "qgssettings.h"
29#include "qgsvectorlayer.h"
30
31#include <QClipboard>
32#include <QMessageBox>
33#include <QString>
34
35#include "moc_qgstableeditordialog.cpp"
36
37using namespace Qt::StringLiterals;
38
40 : QMainWindow( parent )
41{
42 setupUi( this );
43 setWindowTitle( tr( "Table Designer" ) );
44
45 setAttribute( Qt::WA_DeleteOnClose );
46 setDockOptions( dockOptions() | QMainWindow::GroupedDragging );
47
49
50 QGridLayout *viewLayout = new QGridLayout();
51 viewLayout->setSpacing( 0 );
52 viewLayout->setContentsMargins( 0, 0, 0, 0 );
53 centralWidget()->layout()->setSpacing( 0 );
54 centralWidget()->layout()->setContentsMargins( 0, 0, 0, 0 );
55
56 mMessageBar = new QgsMessageBar( centralWidget() );
57 mMessageBar->setSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed );
58 static_cast<QGridLayout *>( centralWidget()->layout() )->addWidget( mMessageBar, 0, 0, 1, 1, Qt::AlignTop );
59
60 mTableWidget = new QgsTableEditorWidget();
61 mTableWidget->setContentsMargins( 0, 0, 0, 0 );
62 viewLayout->addWidget( mTableWidget, 0, 0 );
63 mViewFrame->setLayout( viewLayout );
64 mViewFrame->setContentsMargins( 0, 0, 0, 0 );
65
66 mTableWidget->setFocus();
67 mTableWidget->setTableContents( QgsTableContents() << ( QgsTableRow() << QgsTableCell() ) );
68
69 connect( mTableWidget, &QgsTableEditorWidget::tableChanged, this, [this] {
70 if ( !mBlockSignals )
71 emit tableChanged();
72 } );
73
74 const int minDockWidth( fontMetrics().boundingRect( u"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"_s ).width() );
75
76 mPropertiesDock = new QgsDockWidget( tr( "Cell Contents" ), this );
77 mPropertiesDock->setObjectName( u"FormattingDock"_s );
78 mPropertiesStack = new QgsPanelWidgetStack();
79 mPropertiesDock->setWidget( mPropertiesStack );
80 mPropertiesDock->setMinimumWidth( minDockWidth );
81
82 mFormattingWidget = new QgsTableEditorFormattingWidget();
83 mFormattingWidget->setDockMode( true );
84 mPropertiesStack->setMainPanel( mFormattingWidget );
85
86 mPropertiesDock->setFeatures( QDockWidget::NoDockWidgetFeatures );
87
89
93
94 connect( mFormattingWidget, &QgsTableEditorFormattingWidget::textFormatChanged, this, [this] {
95 mTableWidget->setSelectionTextFormat( mFormattingWidget->textFormat() );
96 } );
97
98 connect( mFormattingWidget, &QgsTableEditorFormattingWidget::numberFormatChanged, this, [this] {
99 mTableWidget->setSelectionNumericFormat( mFormattingWidget->numericFormat() );
100 } );
103
104 connect( mTableWidget, &QgsTableEditorWidget::activeCellChanged, this, [this] {
105 mFormattingWidget->setBackgroundColor( mTableWidget->selectionBackgroundColor() );
106 mFormattingWidget->setNumericFormat( mTableWidget->selectionNumericFormat(), mTableWidget->hasMixedSelectionNumericFormat() );
107 mFormattingWidget->setRowHeight( mTableWidget->selectionRowHeight() );
108 mFormattingWidget->setColumnWidth( mTableWidget->selectionColumnWidth() );
109 mFormattingWidget->setTextFormat( mTableWidget->selectionTextFormat() );
110 mFormattingWidget->setHorizontalAlignment( mTableWidget->selectionHorizontalAlignment() );
111 mFormattingWidget->setVerticalAlignment( mTableWidget->selectionVerticalAlignment() );
112 mFormattingWidget->setCellProperty( mTableWidget->selectionCellProperty() );
113
114 updateActionsFromSelection();
115
116 mFormattingWidget->setEnabled( !mTableWidget->isHeaderCellSelected() );
117 } );
118 updateActionsFromSelection();
119
120 addDockWidget( Qt::RightDockWidgetArea, mPropertiesDock );
121
122 mActionImportFromClipboard->setEnabled( !QApplication::clipboard()->text().isEmpty() );
123 connect( QApplication::clipboard(), &QClipboard::dataChanged, this, [this]() { mActionImportFromClipboard->setEnabled( !QApplication::clipboard()->text().isEmpty() ); } );
124
125 connect( mActionImportFromClipboard, &QAction::triggered, this, &QgsTableEditorDialog::setTableContentsFromClipboard );
126 connect( mActionClose, &QAction::triggered, this, &QMainWindow::close );
127 connect( mActionInsertRowsAbove, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertRowsAbove );
128 connect( mActionInsertRowsBelow, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertRowsBelow );
129 connect( mActionInsertColumnsBefore, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertColumnsBefore );
130 connect( mActionInsertColumnsAfter, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertColumnsAfter );
131 connect( mActionMergeSelected, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::mergeSelectedCells );
132 connect( mActionSplitSelected, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::splitSelectedCells );
133 connect( mActionDeleteRows, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::deleteRows );
134 connect( mActionDeleteColumns, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::deleteColumns );
135 connect( mActionSelectRow, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::expandRowSelection );
136 connect( mActionSelectColumn, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::expandColumnSelection );
137 connect( mActionSelectAll, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::selectAll );
138 connect( mActionClear, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::clearSelectedCells );
139 connect( mActionIncludeHeader, &QAction::toggled, this, [this]( bool checked ) {
140 mTableWidget->setIncludeTableHeader( checked );
141 emit includeHeaderChanged( checked );
142 } );
143
144 // restore the toolbar and dock widgets positions using Qt settings API
145 const QgsSettings settings;
146
147 const QByteArray state = settings.value( u"LayoutDesigner/tableEditorState"_s, QByteArray(), QgsSettings::App ).toByteArray();
148 if ( !state.isEmpty() && !restoreState( state ) )
149 {
150 QgsDebugError( u"restore of table editor dialog UI state failed"_s );
151 }
152}
153
155{
156 QgsSettings settings;
157 // store the toolbar/dock widget settings using Qt settings API
158 settings.setValue( u"LayoutDesigner/tableEditorState"_s, saveState(), QgsSettings::App );
159}
160
162{
163 return mLayer.data();
164}
165
167{
168 if ( layer != mLayer )
169 {
170 mLayer = layer;
171 mFormattingWidget->setLayer( layer );
172 }
173}
174
176{
177 return mTable;
178}
179
181{
182 if ( mTable == table )
183 return;
184
185 mTable = table;
186
187 if ( QgsLayout *layout = table->layout() )
188 {
189 setLayer( layout->reportContext().layer() );
190 }
192
193 setIncludeTableHeader( table->includeTableHeader() );
194 setTableContents( table->tableContents() );
195
196 int row = 0;
197 const QList<double> rowHeights = table->rowHeights();
198 for ( const double height : rowHeights )
199 {
200 setTableRowHeight( row, height );
201 row++;
202 }
203 int col = 0;
204 const QList<double> columnWidths = table->columnWidths();
205 QVariantList headers;
206 headers.reserve( columnWidths.size() );
207 for ( const double width : columnWidths )
208 {
209 setTableColumnWidth( col, width );
210 headers << ( col < table->headers().count() ? table->headers().value( col ).heading() : QVariant() );
211 col++;
212 }
213 setTableHeaders( headers );
214}
215
216
218{
219 if ( QApplication::clipboard()->text().isEmpty() )
220 return false;
221
222 if ( QMessageBox::question( this, tr( "Import Content From Clipboard" ), tr( "Importing content from clipboard will overwrite current table content. Are you sure?" ) ) != QMessageBox::Yes )
223 return false;
224
225 QgsTableContents contents;
226 const QStringList lines = QApplication::clipboard()->text().split( '\n' );
227 for ( const QString &line : lines )
228 {
229 if ( !line.isEmpty() )
230 {
231 QgsTableRow row;
232 const QStringList cells = line.split( '\t' );
233 for ( const QString &text : cells )
234 {
235 const QgsTableCell cell( text );
236 row << cell;
237 }
238 contents << row;
239 }
240 }
241
242 if ( !contents.isEmpty() )
243 {
244 setTableContents( contents );
245 emit tableChanged();
246 return true;
247 }
248
249 return false;
250}
251
253{
254 mBlockSignals = true;
255 mTableWidget->setTableContents( contents );
256 mTableWidget->resizeRowsToContents();
257 mTableWidget->resizeColumnsToContents();
258 mBlockSignals = false;
259}
260
262{
263 return mTableWidget->tableContents();
264}
265
267{
268 return mTableWidget->tableRowHeight( row );
269}
270
272{
273 return mTableWidget->tableColumnWidth( column );
274}
275
276void QgsTableEditorDialog::setTableRowHeight( int row, double height )
277{
278 mTableWidget->setTableRowHeight( row, height );
279}
280
281void QgsTableEditorDialog::setTableColumnWidth( int column, double width )
282{
283 mTableWidget->setTableColumnWidth( column, width );
284}
285
287{
288 return mActionIncludeHeader->isChecked();
289}
290
292{
293 mActionIncludeHeader->setChecked( included );
294}
295
297{
298 return mTableWidget->tableHeaders();
299}
300
301void QgsTableEditorDialog::setTableHeaders( const QVariantList &headers )
302{
303 mTableWidget->setTableHeaders( headers );
304}
305
307{
308 mFormattingWidget->registerExpressionContextGenerator( generator );
309}
310
311void QgsTableEditorDialog::updateActionsFromSelection()
312{
313 const int rowCount = mTableWidget->rowsAssociatedWithSelection().size();
314 const int columnCount = mTableWidget->columnsAssociatedWithSelection().size();
315
316 mActionInsertRowsAbove->setEnabled( rowCount > 0 );
317 mActionInsertRowsBelow->setEnabled( rowCount > 0 );
318 mActionDeleteRows->setEnabled( rowCount > 0 );
319 mActionSelectRow->setEnabled( rowCount > 0 );
320 if ( rowCount == 0 )
321 {
322 mActionInsertRowsAbove->setText( tr( "Rows Above" ) );
323 mActionInsertRowsBelow->setText( tr( "Rows Below" ) );
324 mActionDeleteRows->setText( tr( "Delete Rows" ) );
325 mActionSelectRow->setText( tr( "Select Rows" ) );
326 }
327 else if ( rowCount == 1 )
328 {
329 mActionInsertRowsAbove->setText( tr( "Row Above" ) );
330 mActionInsertRowsBelow->setText( tr( "Row Below" ) );
331 mActionDeleteRows->setText( tr( "Delete Row" ) );
332 mActionSelectRow->setText( tr( "Select Row" ) );
333 }
334 else
335 {
336 mActionInsertRowsAbove->setText( tr( "%n Row(s) Above", nullptr, rowCount ) );
337 mActionInsertRowsBelow->setText( tr( "%n Row(s) Below", nullptr, rowCount ) );
338 mActionDeleteRows->setText( tr( "Delete %n Row(s)", nullptr, rowCount ) );
339 mActionSelectRow->setText( tr( "Select %n Row(s)", nullptr, rowCount ) );
340 }
341
342 mActionInsertColumnsBefore->setEnabled( columnCount > 0 );
343 mActionInsertColumnsAfter->setEnabled( columnCount > 0 );
344 mActionDeleteColumns->setEnabled( columnCount > 0 );
345 mActionSelectColumn->setEnabled( columnCount > 0 );
346 if ( columnCount == 0 )
347 {
348 mActionInsertColumnsBefore->setText( tr( "Columns Before" ) );
349 mActionInsertColumnsAfter->setText( tr( "Columns After" ) );
350 mActionDeleteColumns->setText( tr( "Delete Columns" ) );
351 mActionSelectColumn->setText( tr( "Select Columns" ) );
352 }
353 else if ( columnCount == 1 )
354 {
355 mActionInsertColumnsBefore->setText( tr( "Column Before" ) );
356 mActionInsertColumnsAfter->setText( tr( "Column After" ) );
357 mActionDeleteColumns->setText( tr( "Delete Column" ) );
358 mActionSelectColumn->setText( tr( "Select Column" ) );
359 }
360 else
361 {
362 mActionInsertColumnsBefore->setText( tr( "%n Column(s) Before", nullptr, columnCount ) );
363 mActionInsertColumnsAfter->setText( tr( "%n Column(s) After", nullptr, columnCount ) );
364 mActionDeleteColumns->setText( tr( "Delete %n Column(s)", nullptr, columnCount ) );
365 mActionSelectColumn->setText( tr( "Select %n Column(s)", nullptr, columnCount ) );
366 }
367
368 mActionMergeSelected->setEnabled( mTableWidget->canMergeSelection() );
369 mActionSplitSelected->setEnabled( mTableWidget->canSplitSelection() );
370}
371
372#include "qgstableeditordialog.h"
A QDockWidget 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:224
A layout table subclass that displays manually entered (and formatted) content.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition qgslayout.h:50
Base class for all map layer types.
Definition qgsmaplayer.h:83
A bar for displaying non-blocking messages to the user.
A stack widget to manage multiple overlapping stacked panels.
Stores settings for use within QGIS.
Definition qgssettings.h:68
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.
void backgroundColorChanged(const QColor &color)
Emitted whenever the cell background color is changed in the widget.
void numberFormatChanged()
Emitted whenever the numeric format shown in the widget is changed.
void horizontalAlignmentChanged(Qt::Alignment alignment)
Emitted when the horizontal alignment shown in the widget is changed.
void columnWidthChanged(double width)
Emitted whenever the column width shown in the widget is changed.
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.
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.
void insertColumnsAfter()
Inserts new columns after the current selection.
void clearSelectedCells()
Clears the contents of the currently selected cells.
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.
void insertRowsAbove()
Inserts new rows above the current selection.
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 ...
void expandRowSelection()
Expands out the selection to include whole rows associated with the current selected cells.
void deleteColumns()
Deletes all columns associated with the current selected cells.
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 expandColumnSelection()
Expands out the selection to include whole columns associated with the current selected cells.
#define QgsDebugError(str)
Definition qgslogger.h:59
QVector< QgsTableRow > QgsTableContents
A set of table rows.
QVector< QgsTableCell > QgsTableRow
A row of table cells.