Skip to content

Commit 9d654a1

Browse files
committed
Support modifying the column list of a constraint in Edit Table dialog
This adds support for modifying the columns a constraint is applied on in the Constraints tab of the Edit Table dialog. This is a major step towards full constraint editing capabilities (adding new constraints, modifying constraint type, and editing constraint type-dependent parameters are the other missing pieces). The reasoning behind the popup dialog is to not introduce another full dialog on top of the Edit Table dialog. After opening the Edit Table dialog, then switching to the Constraints tab, then opening another modal dialog, I felt like losing track of what I am currently editing. The popup dialog is certainly not great but feels a bit less intrusive. Any suggestions regarding this are appreciated.
1 parent 3f60142 commit 9d654a1

6 files changed

Lines changed: 560 additions & 3 deletions

File tree

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ set(SQLB_MOC_HDR
175175
src/CondFormat.h
176176
src/RunSql.h
177177
src/ProxyDialog.h
178+
src/SelectItemsPopup.h
178179
)
179180

180181
set(SQLB_SRC
@@ -230,6 +231,7 @@ set(SQLB_SRC
230231
src/RunSql.cpp
231232
src/ProxyDialog.cpp
232233
src/IconCache.cpp
234+
src/SelectItemsPopup.cpp
233235
)
234236

235237
set(SQLB_FORMS
@@ -254,6 +256,7 @@ set(SQLB_FORMS
254256
src/FileExtensionManager.ui
255257
src/CondFormatManager.ui
256258
src/ProxyDialog.ui
259+
src/SelectItemsPopup.ui
257260
)
258261

259262
set(SQLB_RESOURCES

src/EditTableDialog.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include "ui_EditTableDialog.h"
55
#include "sqlitetablemodel.h"
66
#include "sqlitedb.h"
7+
#include "SelectItemsPopup.h"
78

89
#include <QMessageBox>
910
#include <QPushButton>
@@ -81,6 +82,45 @@ EditTableDialog::EditTableDialog(DBBrowserDB& db, const sqlb::ObjectIdentifier&
8182
ui->editTableName->setText(QString::fromStdString(curTable.name()));
8283
updateColumnWidth();
8384

85+
// Allow editing of constraint columns by double clicking the columns column of the constraints table
86+
connect(ui->tableConstraints, &QTableWidget::itemDoubleClicked, [this](QTableWidgetItem* item) {
87+
// Check whether the double clicked item is in the columns column
88+
if(item->column() == kConstraintColumns)
89+
{
90+
sqlb::ConstraintPtr constraint = ui->tableConstraints->item(item->row(), kConstraintName)->data(Qt::UserRole).value<sqlb::ConstraintPtr>();
91+
92+
// Do not allow editing the columns list of a CHECK constraint because CHECK constraints are independent of column lists
93+
if(constraint->type() == sqlb::Constraint::CheckConstraintType)
94+
return;
95+
96+
// Show the select items popup dialog
97+
SelectItemsPopup* dialog = new SelectItemsPopup(m_table.fieldNames(), item->data(Qt::UserRole).value<sqlb::StringVector>(), this);
98+
QRect item_rect = ui->tableConstraints->visualItemRect(item);
99+
dialog->move(ui->tableConstraints->mapToGlobal(QPoint(ui->tableConstraints->x() + item_rect.x(),
100+
ui->tableConstraints->y() + item_rect.y() + item_rect.height() / 2)));
101+
dialog->show();
102+
103+
// When clicking the Apply button in the popup dialog, save the new columns list
104+
connect(dialog, &SelectItemsPopup::accepted, [this, dialog, item, constraint]() {
105+
// Check if column selection changed at all
106+
sqlb::StringVector columns_before = ui->tableConstraints->item(item->row(), kConstraintColumns)->data(Qt::UserRole).value<sqlb::StringVector>();
107+
sqlb::StringVector columns_after = dialog->selectedItems();
108+
if(columns_before != columns_after)
109+
{
110+
// Remove the constraint with the old columns and add a new one with the new columns
111+
m_table.removeConstraint(columns_before, constraint);
112+
m_table.addConstraint(columns_after, constraint);
113+
114+
// Update the UI
115+
populateFields();
116+
populateConstraints();
117+
updateSqlText();
118+
}
119+
});
120+
}
121+
});
122+
123+
// (De-)activate fields
84124
checkInput();
85125
}
86126

src/SelectItemsPopup.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include "SelectItemsPopup.h"
2+
#include "ui_SelectItemsPopup.h"
3+
4+
#include <QPushButton>
5+
6+
SelectItemsPopup::SelectItemsPopup(const std::vector<std::string>& available, const std::vector<std::string>& selected, QWidget* parent) :
7+
QDialog(parent),
8+
ui(new Ui::SelectItemsPopup)
9+
{
10+
ui->setupUi(this);
11+
setWindowFlags(Qt::Popup);
12+
13+
// Load initial items
14+
for(const auto& s : available)
15+
{
16+
if(std::find(selected.begin(), selected.end(), s) == selected.end())
17+
new QListWidgetItem(QString::fromStdString(s), ui->listAvailable);
18+
}
19+
for(const auto& s : selected)
20+
new QListWidgetItem(QString::fromStdString(s), ui->listSelected);
21+
}
22+
23+
SelectItemsPopup::~SelectItemsPopup()
24+
{
25+
delete ui;
26+
}
27+
28+
std::vector<std::string> SelectItemsPopup::selectedItems() const
29+
{
30+
std::vector<std::string> result;
31+
for(int i=0;i<ui->listSelected->count();i++)
32+
result.push_back(ui->listSelected->item(i)->text().toStdString());
33+
return result;
34+
}
35+
36+
void SelectItemsPopup::selectItem(const QModelIndex& idx)
37+
{
38+
// Get currently selected iitem if none was provided
39+
QListWidgetItem* item;
40+
if(idx.isValid())
41+
item = ui->listAvailable->item(idx.row());
42+
else
43+
item = ui->listAvailable->currentItem();
44+
45+
if(!item)
46+
return;
47+
48+
// Add it to the selected items list
49+
new QListWidgetItem(item->text(), ui->listSelected);
50+
51+
// Remove it from available items list
52+
delete item;
53+
}
54+
55+
void SelectItemsPopup::unselectItem(const QModelIndex& idx)
56+
{
57+
// Get currently selected iitem if none was provided
58+
QListWidgetItem* item;
59+
if(idx.isValid())
60+
item = ui->listSelected->item(idx.row());
61+
else
62+
item = ui->listSelected->currentItem();
63+
64+
if(!item)
65+
return;
66+
67+
// Add it to the available items list
68+
new QListWidgetItem(item->text(), ui->listAvailable);
69+
70+
// Remove it from selected items list
71+
delete item;
72+
}
73+
74+
void SelectItemsPopup::resizeEvent(QResizeEvent*)
75+
{
76+
// We modify the shape of the dialog to add an arrow shaped edge. See the ascii art image below for details. The edges
77+
// are numbered, their order is the same as in the polygon definition.
78+
79+
/*
80+
/3\
81+
/ \
82+
1---2 4--------5
83+
| |
84+
| |
85+
7------------------6
86+
*/
87+
88+
const int arrow_height = ui->spacer->geometry().height();
89+
const int arrow_width = arrow_height * 3;
90+
const int arrow_position_div = 5;
91+
92+
QPolygon poly;
93+
poly << QPoint(rect().x(), rect().y() + arrow_height)
94+
<< QPoint(rect().x() + rect().width() / arrow_position_div - arrow_width / 2, rect().y() + arrow_height)
95+
<< QPoint(rect().x() + rect().width() / arrow_position_div, rect().y())
96+
<< QPoint(rect().x() + rect().width() / arrow_position_div + arrow_width / 2, rect().y() + arrow_height)
97+
<< QPoint(rect().x() + rect().width(), rect().y() + arrow_height)
98+
<< QPoint(rect().x() + rect().width(), rect().y() + rect().height())
99+
<< QPoint(rect().x(), rect().y() + rect().height());
100+
setMask(QRegion(poly));
101+
}
102+
103+
void SelectItemsPopup::buttonBoxClicked(QAbstractButton* button)
104+
{
105+
if(button == ui->buttonBox->button(QDialogButtonBox::Apply))
106+
accept();
107+
}
108+
109+
void SelectItemsPopup::moveItemUp()
110+
{
111+
moveCurrentItem(false);
112+
}
113+
114+
void SelectItemsPopup::moveItemDown()
115+
{
116+
moveCurrentItem(true);
117+
}
118+
119+
void SelectItemsPopup::moveCurrentItem(bool down)
120+
{
121+
// Get current row number and calculate row number after the movement. Check the values
122+
int currentRow = ui->listSelected->currentRow();
123+
if(currentRow == -1)
124+
return;
125+
int newRow = currentRow + (down ? 1 : -1);
126+
if(newRow < 0)
127+
return;
128+
if(newRow >= ui->listSelected->count())
129+
return;
130+
131+
// Swap items
132+
ui->listSelected->insertItem(newRow, ui->listSelected->takeItem(currentRow));
133+
134+
// Select old item at new position
135+
ui->listSelected->setCurrentRow(newRow);
136+
}

src/SelectItemsPopup.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifndef SELECTITEMS_H
2+
#define SELECTITEMS_H
3+
4+
#include <QDialog>
5+
#include <QModelIndex>
6+
7+
#include <string>
8+
#include <vector>
9+
10+
class QAbstractButton;
11+
12+
namespace Ui {
13+
class SelectItemsPopup;
14+
}
15+
16+
class SelectItemsPopup : public QDialog
17+
{
18+
Q_OBJECT
19+
20+
public:
21+
explicit SelectItemsPopup(const std::vector<std::string>& available, const std::vector<std::string>& selected = {}, QWidget* parent = nullptr);
22+
~SelectItemsPopup();
23+
24+
std::vector<std::string> selectedItems() const;
25+
26+
private slots:
27+
void buttonBoxClicked(QAbstractButton* button);
28+
29+
void selectItem(const QModelIndex& idx = QModelIndex());
30+
void unselectItem(const QModelIndex& idx = QModelIndex());
31+
32+
void moveItemUp();
33+
void moveItemDown();
34+
35+
protected:
36+
void resizeEvent(QResizeEvent* ev);
37+
38+
private:
39+
Ui::SelectItemsPopup* ui;
40+
41+
void moveCurrentItem(bool down);
42+
};
43+
44+
#endif

0 commit comments

Comments
 (0)