Skip to content

Commit f51ee6f

Browse files
committed
Merge branch 'dbConnection' into dev
2 parents 26e2660 + 3479cb4 commit f51ee6f

16 files changed

+740
-96
lines changed

src/CMakeLists.txt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
set(SOURCE_FILES main.cpp
22
QBrowserApp.cpp
33
QConnectionDialog.cpp
4-
QSqlCtrl.cpp
5-
QSqlQueryPanel.cpp)
4+
QSqlQueryPanel.cpp
5+
QConnectionCtrl.cpp
6+
QDbTableView.cpp
7+
QQueryHighlighter.cpp)
68

79
set(HEADERS QBrowserApp.h
810
QConnectionDialog.h
9-
QSqlCtrl.h
10-
QSqlQueryPanel.h)
11-
11+
QSqlQueryPanel.h
12+
QConnectionCtrl.h
13+
QDbTableView.h
14+
QQueryHighlighter.h)
15+
1216
if(WIN32)
1317
set(RESOURCES res/app_icon.rc)
1418
source_group("Resource files" FILES ${RESOURCES})

src/QBrowserApp.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,37 @@ QBrowserApp::QBrowserApp(QWidget* parent, Qt::WindowFlags flags) : QMainWindow(p
44
setCentralWidget(m_mainWidget);
55
setWindowTitle(QObject::tr("QSqlBrowser"));
66

7-
QSplitter* splitter = new QSplitter(Qt::Vertical, m_mainWidget);
8-
QSqlCtrl* sqlctrl = new QSqlCtrl(splitter);
9-
QSqlQueryPanel* querypanel = new QSqlQueryPanel(splitter);
7+
QSplitter* vSplitter = new QSplitter(Qt::Vertical, m_mainWidget);
8+
QSplitter* hSplitter = new QSplitter(vSplitter);
109

11-
splitter->setChildrenCollapsible(false);
12-
splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
13-
splitter->addWidget(sqlctrl);
14-
splitter->addWidget(querypanel);
15-
splitter->setStretchFactor(0, 1);
16-
splitter->setStretchFactor(1, 0);
10+
hSplitter->setChildrenCollapsible(false);
11+
m_tree = new QConnectionCtrl(hSplitter);
12+
m_table = new QDbTableView(hSplitter);
13+
14+
hSplitter->addWidget(m_tree);
15+
hSplitter->addWidget(m_table);
16+
hSplitter->setStretchFactor(0, 0);
17+
hSplitter->setStretchFactor(1, 1);
18+
hSplitter->setSizes({ 250, 550 });
19+
hSplitter->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));
20+
21+
QSqlQueryPanel* querypanel = new QSqlQueryPanel(vSplitter);
22+
23+
vSplitter->setChildrenCollapsible(false);
24+
vSplitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
25+
vSplitter->addWidget(hSplitter);
26+
vSplitter->addWidget(querypanel);
27+
vSplitter->setStretchFactor(0, 1);
28+
vSplitter->setStretchFactor(1, 0);
1729

1830
QVBoxLayout* mainLayout = new QVBoxLayout;
19-
mainLayout->addWidget(splitter);
31+
mainLayout->addWidget(vSplitter);
2032
m_mainWidget->setLayout(mainLayout);
2133
m_mainWidget->setMinimumSize(820, 625);
34+
35+
QObject::connect(m_tree, &QConnectionCtrl::tableModelChanged, m_table, &QDbTableView::setTableModel);
36+
QObject::connect(querypanel, &QSqlQueryPanel::tableModelChanged, m_table, &QDbTableView::setTableModel);
37+
QObject::connect(m_tree, &QConnectionCtrl::dbSelected, querypanel, &QSqlQueryPanel::dbChange);
38+
QObject::connect(m_tree, &QConnectionCtrl::statusMessage, [&](const QString& text) { statusBar()->showMessage(text); });
39+
QObject::connect(querypanel, &QSqlQueryPanel::statusMessage, [&](const QString& text) { statusBar()->showMessage(text); });
2240
}

src/QBrowserApp.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,22 @@
44
#define BROWSER_H
55

66
#include <QMainWindow>
7+
#include <QStatusBar>
8+
#include <QSplitter>
9+
#include <QFrame>
710

8-
#include "QSqlCtrl.h"
11+
#include "QConnectionCtrl.h"
12+
#include "QDbTableView.h"
913
#include "QSqlQueryPanel.h"
1014

1115
class QBrowserApp : public QMainWindow
1216
{
1317
Q_OBJECT
1418
protected:
1519
QWidget* m_mainWidget;
20+
21+
QConnectionCtrl* m_tree;
22+
QDbTableView* m_table;
1623
public:
1724
explicit QBrowserApp(QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::WindowFlags());
1825
};

src/QConnectionCtrl.cpp

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
#include "QConnectionCtrl.h"
2+
3+
QConnectionCtrl::QConnectionCtrl(QWidget* parent) {
4+
QTreeWidgetItem* rootItem = new QTreeWidgetItem();
5+
rootItem->setIcon(0, QApplication::style()->standardIcon(QStyle::SP_ComputerIcon));
6+
rootItem->setText(0, tr("Databases"));
7+
setHeaderItem(rootItem);
8+
9+
setMinimumSize(250, 252);
10+
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
11+
setFrameStyle(QFrame::Panel | QFrame::Sunken);
12+
setLineWidth(2);
13+
14+
QAction* refreshAction = new QAction(tr("Refresh"), this);
15+
QAction* shemaAction = new QAction(tr("Show shema"), this);
16+
shemaAction->setEnabled(false);
17+
shemaAction->setObjectName("shemaAction");
18+
QAction* separator = new QAction;
19+
separator->setSeparator(true);
20+
QAction* addConnectionAction = new QAction(tr("Add Connection..."), this);
21+
22+
connect(refreshAction, &QAction::triggered, this, [=]() { refresh(); });
23+
connect(shemaAction, &QAction::triggered, this, &QConnectionCtrl::showMetaData);
24+
connect(addConnectionAction, &QAction::triggered, this, &QConnectionCtrl::showConnectionDialog);
25+
26+
addAction(refreshAction);
27+
addAction(shemaAction);
28+
addAction(separator);
29+
addAction(addConnectionAction);
30+
setContextMenuPolicy(Qt::ActionsContextMenu);
31+
32+
connect(this, &QTreeWidget::itemActivated, [=](QTreeWidgetItem* item, int column) {setActiveItem(item, column); });
33+
connect(this, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem* current, QTreeWidgetItem* previous) {
34+
findChild<QAction*>("shemaAction")->setEnabled(current && current->parent());
35+
});
36+
37+
setObjectName("connectionCtrl");
38+
39+
emit statusMessage(tr("Ready."));
40+
}
41+
42+
QSqlError QConnectionCtrl::createConnection(const QString& driver, const QString& dbName, const QString& host, const QString& user, const QString& passwd, const int port) {
43+
static int cCount = 0;
44+
QSqlDatabase db = QSqlDatabase::addDatabase(driver, QString("dbConnection%1").arg(++cCount));
45+
db.setDatabaseName(dbName);
46+
db.setHostName(host);
47+
db.setPort(port);
48+
49+
QSqlError err;
50+
if (!db.open(user, passwd)) {
51+
err = db.lastError();
52+
db = QSqlDatabase();
53+
QSqlDatabase::removeDatabase(QString("dbConnection%1").arg(cCount));
54+
}
55+
56+
return err;
57+
}
58+
59+
void QConnectionCtrl::addConnection(const QString& driver, const QString& dbName, const QString& host, const QString& user, const QString& passwd, const int port) {
60+
QSqlError err = createConnection(driver, dbName, host, user, passwd, port);
61+
if (err.type() != QSqlError::NoError)
62+
QMessageBox::warning(this, tr("Unable to open database"), tr("An error occurred while "
63+
"opening the connection: ") + err.text());
64+
else refresh();
65+
}
66+
67+
void QConnectionCtrl::showConnectionDialog() {
68+
QConnectionDialog dialog(this);
69+
connect(&dialog, &QConnectionDialog::connectionAdded, this, &QConnectionCtrl::addConnection);
70+
dialog.exec();
71+
}
72+
73+
void QConnectionCtrl::showMetaData() {
74+
QTreeWidgetItem* cItem = currentItem();
75+
if (!cItem || !cItem->parent())
76+
return;
77+
setActiveDb(cItem->parent());
78+
79+
QString t = cItem->text(0);
80+
81+
QSqlRecord rec = QSqlDatabase::database(m_activeDb).record(t);
82+
QStandardItemModel* model = new QStandardItemModel(nullptr);
83+
84+
model->insertRows(0, rec.count());
85+
model->insertColumns(0, 7);
86+
87+
model->setHeaderData(0, Qt::Horizontal, "Fieldname");
88+
model->setHeaderData(1, Qt::Horizontal, "Type");
89+
model->setHeaderData(2, Qt::Horizontal, "Length");
90+
model->setHeaderData(3, Qt::Horizontal, "Precision");
91+
model->setHeaderData(4, Qt::Horizontal, "Required");
92+
model->setHeaderData(5, Qt::Horizontal, "AutoValue");
93+
model->setHeaderData(6, Qt::Horizontal, "DefaultValue");
94+
95+
for (int i = 0; i < rec.count(); ++i) {
96+
QSqlField fld = rec.field(i);
97+
model->setData(model->index(i, 0), fld.name());
98+
model->setData(model->index(i, 1), fld.typeID() == -1
99+
? QString(fld.metaType().name())
100+
: QString("%1 (%2)").arg(fld.metaType().name()).arg(fld.typeID()));
101+
model->setData(model->index(i, 2), fld.length());
102+
model->setData(model->index(i, 3), fld.precision());
103+
model->setData(model->index(i, 4), fld.requiredStatus() == -1 ? QVariant("?")
104+
: QVariant(bool(fld.requiredStatus())));
105+
model->setData(model->index(i, 5), fld.isAutoValue());
106+
model->setData(model->index(i, 6), fld.defaultValue());
107+
}
108+
109+
emit tableModelChanged(model, QAbstractItemView::NoEditTriggers);
110+
}
111+
112+
void QConnectionCtrl::setActiveItem(QTreeWidgetItem* item, int column) {
113+
if (!item)
114+
return;
115+
116+
if (item->parent()) {
117+
setActiveDb(item->parent());
118+
119+
const QString t = item->text(0);
120+
QSqlDatabase db = QSqlDatabase::database(m_activeDb);
121+
122+
QSqlTableModel* model = new CustomModel(nullptr, db);
123+
model->setEditStrategy(QSqlTableModel::OnRowChange);
124+
model->setTable(db.driver()->escapeIdentifier(t, QSqlDriver::TableName));
125+
model->select();
126+
if (model->lastError().type() != QSqlError::NoError)
127+
emit statusMessage(model->lastError().text());
128+
129+
emit tableModelChanged(model, QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
130+
}
131+
else setActiveDb(item);
132+
}
133+
134+
void QConnectionCtrl::refresh() {
135+
clear();
136+
QStringList connectionNames = QSqlDatabase::connectionNames();
137+
138+
bool gotActiveDb = false;
139+
for (int i = 0; i < connectionNames.count(); ++i) {
140+
QTreeWidgetItem* rootItem = new QTreeWidgetItem(this);
141+
QSqlDatabase db = QSqlDatabase::database(connectionNames.at(i), false);
142+
143+
QString dbCaption = db.driverName();
144+
dbCaption.append(QLatin1Char(':'));
145+
if (!db.userName().isEmpty())
146+
dbCaption.append(db.userName()).append(QLatin1Char('@'));
147+
dbCaption.append(db.databaseName());
148+
149+
rootItem->setText(0, dbCaption);
150+
rootItem->setIcon(0, QApplication::style()->standardIcon(QStyle::SP_DriveNetIcon));
151+
if (connectionNames.at(i) == QSqlDatabase::database(m_activeDb).connectionName()) {
152+
gotActiveDb = true;
153+
setActiveDb(rootItem);
154+
}
155+
if (db.isOpen()) {
156+
QStringList tableList = db.tables();
157+
for (int t = 0; t < tableList.count(); ++t) {
158+
QTreeWidgetItem* table = new QTreeWidgetItem(rootItem);
159+
table->setText(0, tableList.at(t));
160+
table->setIcon(0, QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon));
161+
}
162+
}
163+
}
164+
if (!gotActiveDb) {
165+
m_activeDb = connectionNames.value(0);
166+
setActiveDb(topLevelItem(0));
167+
}
168+
169+
doItemsLayout();
170+
}
171+
172+
void QConnectionCtrl::setActiveDb(QTreeWidgetItem* item) {
173+
auto f_setBold = [=](QTreeWidgetItem* item, bool bold) {
174+
QFont font = item->font(0);
175+
font.setBold(bold);
176+
item->setFont(0, font);
177+
};
178+
179+
for (int i = 0; i < topLevelItemCount(); ++i) {
180+
if (topLevelItem(i)->font(0).bold())
181+
f_setBold(topLevelItem(i), false);
182+
}
183+
184+
if (!item)
185+
return;
186+
187+
f_setBold(item, true);
188+
m_activeDb = QSqlDatabase::connectionNames().value(indexOfTopLevelItem(item));
189+
emit dbSelected(m_activeDb);
190+
}

src/QConnectionCtrl.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#pragma once
2+
3+
#ifndef CONNECTIONCTRL_H
4+
#define CONNECTIONCTRL_H
5+
6+
#include <QObject>
7+
#include <QTreeWidget>
8+
#include <QSqlDatabase>
9+
#include <QSqlTableModel>
10+
#include <QSqlDriver>
11+
#include <QSqlRecord>
12+
#include <QSqlError>
13+
#include <QSqlField>
14+
#include <QStandardItemModel>
15+
#include <QCursor>
16+
#include <QBrush>
17+
18+
#include "QConnectionDialog.h"
19+
20+
class QConnectionCtrl : public QTreeWidget
21+
{
22+
Q_OBJECT;
23+
public:
24+
explicit QConnectionCtrl(QWidget* parent = nullptr);
25+
static QSqlError createConnection(const QString& driver, const QString& dbName, const QString& host, const QString& user, const QString& passwd, const int port = -1);
26+
public slots:
27+
void addConnection(const QString& driver, const QString& dbName, const QString& host, const QString& user, const QString& passwd, const int port = -1);
28+
void showConnectionDialog();
29+
void showMetaData();
30+
void setActiveItem(QTreeWidgetItem* item, int column);
31+
signals:
32+
void tableModelChanged(QAbstractItemModel* model, QAbstractItemView::EditTriggers triggers);
33+
void statusMessage(const QString& message);
34+
void dbSelected(const QString& db);
35+
protected:
36+
QString m_activeDb;
37+
38+
void refresh();
39+
void setActiveDb(QTreeWidgetItem* item);
40+
};
41+
42+
class CustomModel : public QSqlTableModel
43+
{
44+
Q_OBJECT
45+
public:
46+
explicit CustomModel(QObject* parent = nullptr, QSqlDatabase db = QSqlDatabase())
47+
: QSqlTableModel(parent, db) {}
48+
49+
QVariant data(const QModelIndex& idx, int role) const override
50+
{
51+
if (role == Qt::BackgroundRole && isDirty(idx))
52+
return QBrush(QColor(255, 0, 0, 127));
53+
return QSqlTableModel::data(idx, role);
54+
}
55+
};
56+
57+
#endif

0 commit comments

Comments
 (0)