1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "tablewidgeteditor.h"
30#include <abstractformbuilder.h>
31#include <iconloader_p.h>
32#include <qdesigner_command_p.h>
33#include "formwindowbase_p.h"
34#include "qdesigner_utils_p.h"
35#include <designerpropertymanager.h>
36#include <qttreepropertybrowser.h>
37
38#include <QtDesigner/abstractformwindow.h>
39#include <QtDesigner/abstractformeditor.h>
40
41#include <QtCore/qdir.h>
42#include <QtCore/qqueue.h>
43#include <QtCore/qtextstream.h>
44
45QT_BEGIN_NAMESPACE
46
47namespace qdesigner_internal {
48
49TableWidgetEditor::TableWidgetEditor(QDesignerFormWindowInterface *form, QDialog *dialog)
50 : AbstractItemEditor(form, nullptr), m_updatingBrowser(false)
51{
52 m_columnEditor = new ItemListEditor(form, this);
53 m_columnEditor->setObjectName(QStringLiteral("columnEditor"));
54 m_columnEditor->setAlignDefault(Qt::AlignCenter);
55 m_columnEditor->setNewItemText(tr(s: "New Column"));
56 m_rowEditor = new ItemListEditor(form, this);
57 m_rowEditor->setObjectName(QStringLiteral("rowEditor"));
58 m_rowEditor->setNewItemText(tr(s: "New Row"));
59 ui.setupUi(dialog);
60
61 injectPropertyBrowser(parent: ui.itemsTab, widget: ui.widget);
62 connect(sender: ui.showPropertiesButton, signal: &QAbstractButton::clicked,
63 receiver: this, slot: &TableWidgetEditor::togglePropertyBrowser);
64 setPropertyBrowserVisible(false);
65
66 ui.tabWidget->insertTab(index: 0, widget: m_columnEditor, tr(s: "&Columns"));
67 ui.tabWidget->insertTab(index: 1, widget: m_rowEditor, tr(s: "&Rows"));
68 ui.tabWidget->setCurrentIndex(0);
69 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
70
71 ui.tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
72
73 connect(sender: iconCache(), signal: &DesignerIconCache::reloaded, receiver: this, slot: &TableWidgetEditor::cacheReloaded);
74
75 connect(sender: ui.tableWidget, signal: &QTableWidget::currentCellChanged,
76 receiver: this, slot: &TableWidgetEditor::on_tableWidget_currentCellChanged);
77 connect(sender: ui.tableWidget, signal: &QTableWidget::itemChanged,
78 receiver: this, slot: &TableWidgetEditor::on_tableWidget_itemChanged);
79 connect(sender: m_columnEditor, signal: &ItemListEditor::indexChanged,
80 receiver: this, slot: &TableWidgetEditor::on_columnEditor_indexChanged);
81 connect(sender: m_columnEditor, signal: &ItemListEditor::itemChanged,
82 receiver: this, slot: &TableWidgetEditor::on_columnEditor_itemChanged);
83 connect(sender: m_columnEditor, signal: &ItemListEditor::itemInserted,
84 receiver: this, slot: &TableWidgetEditor::on_columnEditor_itemInserted);
85 connect(sender: m_columnEditor, signal: &ItemListEditor::itemDeleted,
86 receiver: this, slot: &TableWidgetEditor::on_columnEditor_itemDeleted);
87 connect(sender: m_columnEditor, signal: &ItemListEditor::itemMovedUp,
88 receiver: this, slot: &TableWidgetEditor::on_columnEditor_itemMovedUp);
89 connect(sender: m_columnEditor, signal: &ItemListEditor::itemMovedDown,
90 receiver: this, slot: &TableWidgetEditor::on_columnEditor_itemMovedDown);
91
92 connect(sender: m_rowEditor, signal: &ItemListEditor::indexChanged,
93 receiver: this, slot: &TableWidgetEditor::on_rowEditor_indexChanged);
94 connect(sender: m_rowEditor, signal: &ItemListEditor::itemChanged,
95 receiver: this, slot: &TableWidgetEditor::on_rowEditor_itemChanged);
96 connect(sender: m_rowEditor, signal: &ItemListEditor::itemInserted,
97 receiver: this, slot: &TableWidgetEditor::on_rowEditor_itemInserted);
98 connect(sender: m_rowEditor, signal: &ItemListEditor::itemDeleted,
99 receiver: this, slot: &TableWidgetEditor::on_rowEditor_itemDeleted);
100 connect(sender: m_rowEditor, signal: &ItemListEditor::itemMovedUp,
101 receiver: this, slot: &TableWidgetEditor::on_rowEditor_itemMovedUp);
102 connect(sender: m_rowEditor, signal: &ItemListEditor::itemMovedDown,
103 receiver: this, slot: &TableWidgetEditor::on_rowEditor_itemMovedDown);
104}
105
106static AbstractItemEditor::PropertyDefinition tableHeaderPropList[] = {
107 { .role: Qt::DisplayPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerStringTypeId, .name: "text" },
108 { .role: Qt::DecorationPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerIconTypeId, .name: "icon" },
109 { .role: Qt::ToolTipPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerStringTypeId, .name: "toolTip" },
110// { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" },
111 { .role: Qt::WhatsThisPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerStringTypeId, .name: "whatsThis" },
112 { .role: Qt::FontRole, .type: QVariant::Font, .typeFunc: nullptr, .name: "font" },
113 { .role: Qt::TextAlignmentRole, .type: 0, .typeFunc: DesignerPropertyManager::designerAlignmentTypeId, .name: "textAlignment" },
114 { .role: Qt::BackgroundRole, .type: QVariant::Color, .typeFunc: nullptr, .name: "background" },
115 { .role: Qt::ForegroundRole, .type: QVariant::Brush, .typeFunc: nullptr, .name: "foreground" },
116 { .role: 0, .type: 0, .typeFunc: nullptr, .name: nullptr }
117};
118
119static AbstractItemEditor::PropertyDefinition tableItemPropList[] = {
120 { .role: Qt::DisplayPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerStringTypeId, .name: "text" },
121 { .role: Qt::DecorationPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerIconTypeId, .name: "icon" },
122 { .role: Qt::ToolTipPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerStringTypeId, .name: "toolTip" },
123// { Qt::StatusTipPropertyRole, 0, DesignerPropertyManager::designerStringTypeId, "statusTip" },
124 { .role: Qt::WhatsThisPropertyRole, .type: 0, .typeFunc: DesignerPropertyManager::designerStringTypeId, .name: "whatsThis" },
125 { .role: Qt::FontRole, .type: QVariant::Font, .typeFunc: nullptr, .name: "font" },
126 { .role: Qt::TextAlignmentRole, .type: 0, .typeFunc: DesignerPropertyManager::designerAlignmentTypeId, .name: "textAlignment" },
127 { .role: Qt::BackgroundRole, .type: QVariant::Brush, .typeFunc: nullptr, .name: "background" },
128 { .role: Qt::ForegroundRole, .type: QVariant::Brush, .typeFunc: nullptr, .name: "foreground" },
129 { .role: ItemFlagsShadowRole, .type: 0, .typeFunc: QtVariantPropertyManager::flagTypeId, .name: "flags" },
130 { .role: Qt::CheckStateRole, .type: 0, .typeFunc: QtVariantPropertyManager::enumTypeId, .name: "checkState" },
131 { .role: 0, .type: 0, .typeFunc: nullptr, .name: nullptr }
132};
133
134TableWidgetContents TableWidgetEditor::fillContentsFromTableWidget(QTableWidget *tableWidget)
135{
136 TableWidgetContents tblCont;
137 tblCont.fromTableWidget(tableWidget, editor: false);
138 tblCont.applyToTableWidget(tableWidget: ui.tableWidget, iconCache: iconCache(), editor: true);
139
140 auto *header = tableWidget->verticalHeader();
141 auto headerAlignment = header != nullptr
142 ? header->defaultAlignment() : Qt::Alignment(Qt::AlignLeading | Qt::AlignVCenter);
143 tblCont.m_verticalHeader.applyToListWidget(listWidget: m_rowEditor->listWidget(), iconCache: iconCache(),
144 editor: true, alignmentDefault: headerAlignment);
145 m_rowEditor->setupEditor(object: tableWidget, propDefs: tableHeaderPropList, alignDefault: headerAlignment);
146
147 header = tableWidget->horizontalHeader();
148 headerAlignment = header != nullptr
149 ? header->defaultAlignment() : Qt::Alignment(Qt::AlignCenter);
150 tblCont.m_horizontalHeader.applyToListWidget(listWidget: m_columnEditor->listWidget(), iconCache: iconCache(),
151 editor: true, alignmentDefault: headerAlignment);
152 m_columnEditor->setupEditor(object: tableWidget, propDefs: tableHeaderPropList, alignDefault: headerAlignment);
153
154 setupEditor(object: tableWidget, propDefs: tableItemPropList);
155 if (ui.tableWidget->columnCount() > 0 && ui.tableWidget->rowCount() > 0)
156 ui.tableWidget->setCurrentCell(row: 0, column: 0);
157
158 updateEditor();
159
160 return tblCont;
161}
162
163TableWidgetContents TableWidgetEditor::contents() const
164{
165 TableWidgetContents retVal;
166 retVal.fromTableWidget(tableWidget: ui.tableWidget, editor: true);
167 return retVal;
168}
169
170void TableWidgetEditor::setItemData(int role, const QVariant &v)
171{
172 QTableWidgetItem *item = ui.tableWidget->currentItem();
173 BoolBlocker block(m_updatingBrowser);
174 if (!item) {
175 item = new QTableWidgetItem;
176 ui.tableWidget->setItem(row: ui.tableWidget->currentRow(), column: ui.tableWidget->currentColumn(), item);
177 }
178 QVariant newValue = v;
179 if (role == Qt::FontRole && newValue.type() == QVariant::Font) {
180 QFont oldFont = ui.tableWidget->font();
181 QFont newFont = qvariant_cast<QFont>(v: newValue).resolve(oldFont);
182 newValue = QVariant::fromValue(value: newFont);
183 item->setData(role, value: QVariant()); // force the right font with the current resolve mask is set (item view bug)
184 }
185 item->setData(role, value: newValue);
186}
187
188QVariant TableWidgetEditor::getItemData(int role) const
189{
190 QTableWidgetItem *item = ui.tableWidget->currentItem();
191 if (!item)
192 return QVariant();
193 return item->data(role);
194}
195
196int TableWidgetEditor::defaultItemFlags() const
197{
198 static const int flags = QTableWidgetItem().flags();
199 return flags;
200}
201
202void TableWidgetEditor::on_tableWidget_currentCellChanged(int currentRow, int currentCol, int, int /* XXX remove me */)
203{
204 m_rowEditor->setCurrentIndex(currentRow);
205 m_columnEditor->setCurrentIndex(currentCol);
206 updateBrowser();
207}
208
209void TableWidgetEditor::on_tableWidget_itemChanged(QTableWidgetItem *item)
210{
211 if (m_updatingBrowser)
212 return;
213
214 PropertySheetStringValue val = qvariant_cast<PropertySheetStringValue>(v: item->data(role: Qt::DisplayPropertyRole));
215 val.setValue(item->text());
216 BoolBlocker block(m_updatingBrowser);
217 item->setData(role: Qt::DisplayPropertyRole, value: QVariant::fromValue(value: val));
218
219 updateBrowser();
220}
221
222void TableWidgetEditor::on_columnEditor_indexChanged(int col)
223{
224 ui.tableWidget->setCurrentCell(row: ui.tableWidget->currentRow(), column: col);
225}
226
227void TableWidgetEditor::on_columnEditor_itemChanged(int idx, int role, const QVariant &v)
228{
229 ui.tableWidget->horizontalHeaderItem(column: idx)->setData(role, value: v);
230}
231
232void TableWidgetEditor::on_rowEditor_indexChanged(int col)
233{
234 ui.tableWidget->setCurrentCell(row: col, column: ui.tableWidget->currentColumn());
235}
236
237void TableWidgetEditor::on_rowEditor_itemChanged(int idx, int role, const QVariant &v)
238{
239 ui.tableWidget->verticalHeaderItem(row: idx)->setData(role, value: v);
240}
241
242void TableWidgetEditor::setPropertyBrowserVisible(bool v)
243{
244 ui.showPropertiesButton->setText(v ? tr(s: "Properties &>>") : tr(s: "Properties &<<"));
245 m_propertyBrowser->setVisible(v);
246}
247
248void TableWidgetEditor::togglePropertyBrowser()
249{
250 setPropertyBrowserVisible(!m_propertyBrowser->isVisible());
251}
252
253void TableWidgetEditor::updateEditor()
254{
255 const bool wasEnabled = ui.tabWidget->isTabEnabled(index: 2);
256 const bool isEnabled = ui.tableWidget->columnCount() && ui.tableWidget->rowCount();
257 ui.tabWidget->setTabEnabled(index: 2, enabled: isEnabled);
258 if (!wasEnabled && isEnabled)
259 ui.tableWidget->setCurrentCell(row: 0, column: 0);
260
261 QMetaObject::invokeMethod(obj: ui.tableWidget, member: "updateGeometries");
262 ui.tableWidget->viewport()->update();
263}
264
265void TableWidgetEditor::moveColumnsLeft(int fromColumn, int toColumn)
266{
267 if (fromColumn >= toColumn)
268 return;
269
270 QTableWidgetItem *lastItem = ui.tableWidget->takeHorizontalHeaderItem(column: toColumn);
271 for (int i = toColumn; i > fromColumn; i--) {
272 ui.tableWidget->setHorizontalHeaderItem(column: i,
273 item: ui.tableWidget->takeHorizontalHeaderItem(column: i - 1));
274 }
275 ui.tableWidget->setHorizontalHeaderItem(column: fromColumn, item: lastItem);
276
277 for (int i = 0; i < ui.tableWidget->rowCount(); i++) {
278 QTableWidgetItem *lastItem = ui.tableWidget->takeItem(row: i, column: toColumn);
279 for (int j = toColumn; j > fromColumn; j--)
280 ui.tableWidget->setItem(row: i, column: j, item: ui.tableWidget->takeItem(row: i, column: j - 1));
281 ui.tableWidget->setItem(row: i, column: fromColumn, item: lastItem);
282 }
283}
284
285void TableWidgetEditor::moveColumnsRight(int fromColumn, int toColumn)
286{
287 if (fromColumn >= toColumn)
288 return;
289
290 QTableWidgetItem *lastItem = ui.tableWidget->takeHorizontalHeaderItem(column: fromColumn);
291 for (int i = fromColumn; i < toColumn; i++) {
292 ui.tableWidget->setHorizontalHeaderItem(column: i,
293 item: ui.tableWidget->takeHorizontalHeaderItem(column: i + 1));
294 }
295 ui.tableWidget->setHorizontalHeaderItem(column: toColumn, item: lastItem);
296
297 for (int i = 0; i < ui.tableWidget->rowCount(); i++) {
298 QTableWidgetItem *lastItem = ui.tableWidget->takeItem(row: i, column: fromColumn);
299 for (int j = fromColumn; j < toColumn; j++)
300 ui.tableWidget->setItem(row: i, column: j, item: ui.tableWidget->takeItem(row: i, column: j + 1));
301 ui.tableWidget->setItem(row: i, column: toColumn, item: lastItem);
302 }
303}
304
305void TableWidgetEditor::moveRowsDown(int fromRow, int toRow)
306{
307 if (fromRow >= toRow)
308 return;
309
310 QTableWidgetItem *lastItem = ui.tableWidget->takeVerticalHeaderItem(row: toRow);
311 for (int i = toRow; i > fromRow; i--) {
312 ui.tableWidget->setVerticalHeaderItem(row: i,
313 item: ui.tableWidget->takeVerticalHeaderItem(row: i - 1));
314 }
315 ui.tableWidget->setVerticalHeaderItem(row: fromRow, item: lastItem);
316
317 for (int i = 0; i < ui.tableWidget->columnCount(); i++) {
318 QTableWidgetItem *lastItem = ui.tableWidget->takeItem(row: toRow, column: i);
319 for (int j = toRow; j > fromRow; j--)
320 ui.tableWidget->setItem(row: j, column: i, item: ui.tableWidget->takeItem(row: j - 1, column: i));
321 ui.tableWidget->setItem(row: fromRow, column: i, item: lastItem);
322 }
323}
324
325void TableWidgetEditor::moveRowsUp(int fromRow, int toRow)
326{
327 if (fromRow >= toRow)
328 return;
329
330 QTableWidgetItem *lastItem = ui.tableWidget->takeVerticalHeaderItem(row: fromRow);
331 for (int i = fromRow; i < toRow; i++) {
332 ui.tableWidget->setVerticalHeaderItem(row: i,
333 item: ui.tableWidget->takeVerticalHeaderItem(row: i + 1));
334 }
335 ui.tableWidget->setVerticalHeaderItem(row: toRow, item: lastItem);
336
337 for (int i = 0; i < ui.tableWidget->columnCount(); i++) {
338 QTableWidgetItem *lastItem = ui.tableWidget->takeItem(row: fromRow, column: i);
339 for (int j = fromRow; j < toRow; j++)
340 ui.tableWidget->setItem(row: j, column: i, item: ui.tableWidget->takeItem(row: j + 1, column: i));
341 ui.tableWidget->setItem(row: toRow, column: i, item: lastItem);
342 }
343}
344
345void TableWidgetEditor::on_columnEditor_itemInserted(int idx)
346{
347 const int columnCount = ui.tableWidget->columnCount();
348 ui.tableWidget->setColumnCount(columnCount + 1);
349
350 QTableWidgetItem *newItem = new QTableWidgetItem(m_columnEditor->newItemText());
351 newItem->setData(role: Qt::DisplayPropertyRole, value: QVariant::fromValue(value: PropertySheetStringValue(m_columnEditor->newItemText())));
352 ui.tableWidget->setHorizontalHeaderItem(column: columnCount, item: newItem);
353
354 moveColumnsLeft(fromColumn: idx, toColumn: columnCount);
355
356 int row = ui.tableWidget->currentRow();
357 if (row >= 0)
358 ui.tableWidget->setCurrentCell(row, column: idx);
359
360 updateEditor();
361}
362
363void TableWidgetEditor::on_columnEditor_itemDeleted(int idx)
364{
365 const int columnCount = ui.tableWidget->columnCount();
366
367 moveColumnsRight(fromColumn: idx, toColumn: columnCount - 1);
368 ui.tableWidget->setColumnCount(columnCount - 1);
369
370 updateEditor();
371}
372
373void TableWidgetEditor::on_columnEditor_itemMovedUp(int idx)
374{
375 moveColumnsRight(fromColumn: idx - 1, toColumn: idx);
376
377 ui.tableWidget->setCurrentCell(row: ui.tableWidget->currentRow(), column: idx - 1);
378}
379
380void TableWidgetEditor::on_columnEditor_itemMovedDown(int idx)
381{
382 moveColumnsLeft(fromColumn: idx, toColumn: idx + 1);
383
384 ui.tableWidget->setCurrentCell(row: ui.tableWidget->currentRow(), column: idx + 1);
385}
386
387void TableWidgetEditor::on_rowEditor_itemInserted(int idx)
388{
389 const int rowCount = ui.tableWidget->rowCount();
390 ui.tableWidget->setRowCount(rowCount + 1);
391
392 QTableWidgetItem *newItem = new QTableWidgetItem(m_rowEditor->newItemText());
393 newItem->setData(role: Qt::DisplayPropertyRole, value: QVariant::fromValue(value: PropertySheetStringValue(m_rowEditor->newItemText())));
394 ui.tableWidget->setVerticalHeaderItem(row: rowCount, item: newItem);
395
396 moveRowsDown(fromRow: idx, toRow: rowCount);
397
398 int col = ui.tableWidget->currentColumn();
399 if (col >= 0)
400 ui.tableWidget->setCurrentCell(row: idx, column: col);
401
402 updateEditor();
403}
404
405void TableWidgetEditor::on_rowEditor_itemDeleted(int idx)
406{
407 const int rowCount = ui.tableWidget->rowCount();
408
409 moveRowsUp(fromRow: idx, toRow: rowCount - 1);
410 ui.tableWidget->setRowCount(rowCount - 1);
411
412 updateEditor();
413}
414
415void TableWidgetEditor::on_rowEditor_itemMovedUp(int idx)
416{
417 moveRowsUp(fromRow: idx - 1, toRow: idx);
418
419 ui.tableWidget->setCurrentCell(row: idx - 1, column: ui.tableWidget->currentColumn());
420}
421
422void TableWidgetEditor::on_rowEditor_itemMovedDown(int idx)
423{
424 moveRowsDown(fromRow: idx, toRow: idx + 1);
425
426 ui.tableWidget->setCurrentCell(row: idx + 1, column: ui.tableWidget->currentColumn());
427}
428
429void TableWidgetEditor::cacheReloaded()
430{
431 reloadIconResources(iconCache: iconCache(), object: ui.tableWidget);
432}
433
434TableWidgetEditorDialog::TableWidgetEditorDialog(QDesignerFormWindowInterface *form, QWidget *parent) :
435 QDialog(parent), m_editor(form, this)
436{
437 setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
438}
439
440TableWidgetContents TableWidgetEditorDialog::fillContentsFromTableWidget(QTableWidget *tableWidget)
441{
442 return m_editor.fillContentsFromTableWidget(tableWidget);
443}
444
445TableWidgetContents TableWidgetEditorDialog::contents() const
446{
447 return m_editor.contents();
448}
449
450} // namespace qdesigner_internal
451
452QT_END_NAMESPACE
453

source code of qttools/src/designer/src/components/taskmenu/tablewidgeteditor.cpp