QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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] { mTableWidget->setSelectionTextFormat( mFormattingWidget->textFormat() ); } );
95
96 connect( mFormattingWidget, &QgsTableEditorFormattingWidget::numberFormatChanged, this, [this] { mTableWidget->setSelectionNumericFormat( mFormattingWidget->numericFormat() ); } );
99
100 connect( mTableWidget, &QgsTableEditorWidget::activeCellChanged, this, [this] {
101 mFormattingWidget->setBackgroundColor( mTableWidget->selectionBackgroundColor() );
102 mFormattingWidget->setNumericFormat( mTableWidget->selectionNumericFormat(), mTableWidget->hasMixedSelectionNumericFormat() );
103 mFormattingWidget->setRowHeight( mTableWidget->selectionRowHeight() );
104 mFormattingWidget->setColumnWidth( mTableWidget->selectionColumnWidth() );
105 mFormattingWidget->setTextFormat( mTableWidget->selectionTextFormat() );
106 mFormattingWidget->setHorizontalAlignment( mTableWidget->selectionHorizontalAlignment() );
107 mFormattingWidget->setVerticalAlignment( mTableWidget->selectionVerticalAlignment() );
108 mFormattingWidget->setCellProperty( mTableWidget->selectionCellProperty() );
109
110 updateActionsFromSelection();
111
112 mFormattingWidget->setEnabled( !mTableWidget->isHeaderCellSelected() );
113 } );
114 updateActionsFromSelection();
115
116 addDockWidget( Qt::RightDockWidgetArea, mPropertiesDock );
117
118 mActionImportFromClipboard->setEnabled( !QApplication::clipboard()->text().isEmpty() );
119 connect( QApplication::clipboard(), &QClipboard::dataChanged, this, [this]() { mActionImportFromClipboard->setEnabled( !QApplication::clipboard()->text().isEmpty() ); } );
120
121 connect( mActionImportFromClipboard, &QAction::triggered, this, &QgsTableEditorDialog::setTableContentsFromClipboard );
122 connect( mActionClose, &QAction::triggered, this, &QMainWindow::close );
123 connect( mActionInsertRowsAbove, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertRowsAbove );
124 connect( mActionInsertRowsBelow, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertRowsBelow );
125 connect( mActionInsertColumnsBefore, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertColumnsBefore );
126 connect( mActionInsertColumnsAfter, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::insertColumnsAfter );
127 connect( mActionMergeSelected, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::mergeSelectedCells );
128 connect( mActionSplitSelected, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::splitSelectedCells );
129 connect( mActionDeleteRows, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::deleteRows );
130 connect( mActionDeleteColumns, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::deleteColumns );
131 connect( mActionSelectRow, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::expandRowSelection );
132 connect( mActionSelectColumn, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::expandColumnSelection );
133 connect( mActionSelectAll, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::selectAll );
134 connect( mActionClear, &QAction::triggered, mTableWidget, &QgsTableEditorWidget::clearSelectedCells );
135 connect( mActionIncludeHeader, &QAction::toggled, this, [this]( bool checked ) {
136 mTableWidget->setIncludeTableHeader( checked );
137 emit includeHeaderChanged( checked );
138 } );
139
140 // restore the toolbar and dock widgets positions using Qt settings API
141 const QgsSettings settings;
142
143 const QByteArray state = settings.value( u"LayoutDesigner/tableEditorState"_s, QByteArray(), QgsSettings::App ).toByteArray();
144 if ( !state.isEmpty() && !restoreState( state ) )
145 {
146 QgsDebugError( u"restore of table editor dialog UI state failed"_s );
147 }
148}
149
151{
152 QgsSettings settings;
153 // store the toolbar/dock widget settings using Qt settings API
154 settings.setValue( u"LayoutDesigner/tableEditorState"_s, saveState(), QgsSettings::App );
155}
156
158{
159 return mLayer.data();
160}
161
163{
164 if ( layer != mLayer )
165 {
166 mLayer = layer;
167 mFormattingWidget->setLayer( layer );
168 }
169}
170
172{
173 return mTable;
174}
175
177{
178 if ( mTable == table )
179 return;
180
181 mTable = table;
182
183 if ( QgsLayout *layout = table->layout() )
184 {
185 setLayer( layout->reportContext().layer() );
186 }
188
189 setIncludeTableHeader( table->includeTableHeader() );
190 setTableContents( table->tableContents() );
191
192 int row = 0;
193 const QList<double> rowHeights = table->rowHeights();
194 for ( const double height : rowHeights )
195 {
196 setTableRowHeight( row, height );
197 row++;
198 }
199 int col = 0;
200 const QList<double> columnWidths = table->columnWidths();
201 QVariantList headers;
202 headers.reserve( columnWidths.size() );
203 for ( const double width : columnWidths )
204 {
205 setTableColumnWidth( col, width );
206 headers << ( col < table->headers().count() ? table->headers().value( col ).heading() : QVariant() );
207 col++;
208 }
209 setTableHeaders( headers );
210}
211
212
214{
215 if ( QApplication::clipboard()->text().isEmpty() )
216 return false;
217
218 if ( QMessageBox::question( this, tr( "Import Content From Clipboard" ), tr( "Importing content from clipboard will overwrite current table content. Are you sure?" ) ) != QMessageBox::Yes )
219 return false;
220
221 QgsTableContents contents;
222 const QStringList lines = QApplication::clipboard()->text().split( '\n' );
223 for ( const QString &line : lines )
224 {
225 if ( !line.isEmpty() )
226 {
227 QgsTableRow row;
228 const QStringList cells = line.split( '\t' );
229 for ( const QString &text : cells )
230 {
231 const QgsTableCell cell( text );
232 row << cell;
233 }
234 contents << row;
235 }
236 }
237
238 if ( !contents.isEmpty() )
239 {
240 setTableContents( contents );
241 emit tableChanged();
242 return true;
243 }
244
245 return false;
246}
247
249{
250 mBlockSignals = true;
251 mTableWidget->setTableContents( contents );
252 mTableWidget->resizeRowsToContents();
253 mTableWidget->resizeColumnsToContents();
254 mBlockSignals = false;
255}
256
258{
259 return mTableWidget->tableContents();
260}
261
263{
264 return mTableWidget->tableRowHeight( row );
265}
266
268{
269 return mTableWidget->tableColumnWidth( column );
270}
271
272void QgsTableEditorDialog::setTableRowHeight( int row, double height )
273{
274 mTableWidget->setTableRowHeight( row, height );
275}
276
277void QgsTableEditorDialog::setTableColumnWidth( int column, double width )
278{
279 mTableWidget->setTableColumnWidth( column, width );
280}
281
283{
284 return mActionIncludeHeader->isChecked();
285}
286
288{
289 mActionIncludeHeader->setChecked( included );
290}
291
293{
294 return mTableWidget->tableHeaders();
295}
296
297void QgsTableEditorDialog::setTableHeaders( const QVariantList &headers )
298{
299 mTableWidget->setTableHeaders( headers );
300}
301
303{
304 mFormattingWidget->registerExpressionContextGenerator( generator );
305}
306
307void QgsTableEditorDialog::updateActionsFromSelection()
308{
309 const int rowCount = mTableWidget->rowsAssociatedWithSelection().size();
310 const int columnCount = mTableWidget->columnsAssociatedWithSelection().size();
311
312 mActionInsertRowsAbove->setEnabled( rowCount > 0 );
313 mActionInsertRowsBelow->setEnabled( rowCount > 0 );
314 mActionDeleteRows->setEnabled( rowCount > 0 );
315 mActionSelectRow->setEnabled( rowCount > 0 );
316 if ( rowCount == 0 )
317 {
318 mActionInsertRowsAbove->setText( tr( "Rows Above" ) );
319 mActionInsertRowsBelow->setText( tr( "Rows Below" ) );
320 mActionDeleteRows->setText( tr( "Delete Rows" ) );
321 mActionSelectRow->setText( tr( "Select Rows" ) );
322 }
323 else if ( rowCount == 1 )
324 {
325 mActionInsertRowsAbove->setText( tr( "Row Above" ) );
326 mActionInsertRowsBelow->setText( tr( "Row Below" ) );
327 mActionDeleteRows->setText( tr( "Delete Row" ) );
328 mActionSelectRow->setText( tr( "Select Row" ) );
329 }
330 else
331 {
332 mActionInsertRowsAbove->setText( tr( "%n Row(s) Above", nullptr, rowCount ) );
333 mActionInsertRowsBelow->setText( tr( "%n Row(s) Below", nullptr, rowCount ) );
334 mActionDeleteRows->setText( tr( "Delete %n Row(s)", nullptr, rowCount ) );
335 mActionSelectRow->setText( tr( "Select %n Row(s)", nullptr, rowCount ) );
336 }
337
338 mActionInsertColumnsBefore->setEnabled( columnCount > 0 );
339 mActionInsertColumnsAfter->setEnabled( columnCount > 0 );
340 mActionDeleteColumns->setEnabled( columnCount > 0 );
341 mActionSelectColumn->setEnabled( columnCount > 0 );
342 if ( columnCount == 0 )
343 {
344 mActionInsertColumnsBefore->setText( tr( "Columns Before" ) );
345 mActionInsertColumnsAfter->setText( tr( "Columns After" ) );
346 mActionDeleteColumns->setText( tr( "Delete Columns" ) );
347 mActionSelectColumn->setText( tr( "Select Columns" ) );
348 }
349 else if ( columnCount == 1 )
350 {
351 mActionInsertColumnsBefore->setText( tr( "Column Before" ) );
352 mActionInsertColumnsAfter->setText( tr( "Column After" ) );
353 mActionDeleteColumns->setText( tr( "Delete Column" ) );
354 mActionSelectColumn->setText( tr( "Select Column" ) );
355 }
356 else
357 {
358 mActionInsertColumnsBefore->setText( tr( "%n Column(s) Before", nullptr, columnCount ) );
359 mActionInsertColumnsAfter->setText( tr( "%n Column(s) After", nullptr, columnCount ) );
360 mActionDeleteColumns->setText( tr( "Delete %n Column(s)", nullptr, columnCount ) );
361 mActionSelectColumn->setText( tr( "Select %n Column(s)", nullptr, columnCount ) );
362 }
363
364 mActionMergeSelected->setEnabled( mTableWidget->canMergeSelection() );
365 mActionSplitSelected->setEnabled( mTableWidget->canSplitSelection() );
366}
367
368#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.