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 demonstration applications of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
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 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include "browser.h" |
52 | #include "qsqlconnectiondialog.h" |
53 | |
54 | #include <QtWidgets> |
55 | #include <QtSql> |
56 | |
57 | Browser::Browser(QWidget *parent) |
58 | : QWidget(parent) |
59 | { |
60 | setupUi(this); |
61 | |
62 | table->addAction(action: insertRowAction); |
63 | table->addAction(action: deleteRowAction); |
64 | table->addAction(action: fieldStrategyAction); |
65 | table->addAction(action: rowStrategyAction); |
66 | table->addAction(action: manualStrategyAction); |
67 | table->addAction(action: submitAction); |
68 | table->addAction(action: revertAction); |
69 | table->addAction(action: selectAction); |
70 | |
71 | if (QSqlDatabase::drivers().isEmpty()) |
72 | QMessageBox::information(parent: this, title: tr(s: "No database drivers found" ), |
73 | text: tr(s: "This demo requires at least one Qt database driver. " |
74 | "Please check the documentation how to build the " |
75 | "Qt SQL plugins." )); |
76 | |
77 | emit statusMessage(message: tr(s: "Ready." )); |
78 | } |
79 | |
80 | Browser::~Browser() |
81 | { |
82 | } |
83 | |
84 | void Browser::exec() |
85 | { |
86 | QSqlQueryModel *model = new QSqlQueryModel(table); |
87 | model->setQuery(QSqlQuery(sqlEdit->toPlainText(), connectionWidget->currentDatabase())); |
88 | table->setModel(model); |
89 | |
90 | if (model->lastError().type() != QSqlError::NoError) |
91 | emit statusMessage(message: model->lastError().text()); |
92 | else if (model->query().isSelect()) |
93 | emit statusMessage(message: tr(s: "Query OK." )); |
94 | else |
95 | emit statusMessage(message: tr(s: "Query OK, number of affected rows: %1" ).arg( |
96 | a: model->query().numRowsAffected())); |
97 | |
98 | updateActions(); |
99 | } |
100 | |
101 | QSqlError Browser::addConnection(const QString &driver, const QString &dbName, const QString &host, |
102 | const QString &user, const QString &passwd, int port) |
103 | { |
104 | static int cCount = 0; |
105 | |
106 | QSqlError err; |
107 | QSqlDatabase db = QSqlDatabase::addDatabase(type: driver, connectionName: QString("Browser%1" ).arg(a: ++cCount)); |
108 | db.setDatabaseName(dbName); |
109 | db.setHostName(host); |
110 | db.setPort(port); |
111 | if (!db.open(user, password: passwd)) { |
112 | err = db.lastError(); |
113 | db = QSqlDatabase(); |
114 | QSqlDatabase::removeDatabase(connectionName: QString("Browser%1" ).arg(a: cCount)); |
115 | } |
116 | connectionWidget->refresh(); |
117 | |
118 | return err; |
119 | } |
120 | |
121 | void Browser::addConnection() |
122 | { |
123 | QSqlConnectionDialog dialog(this); |
124 | if (dialog.exec() != QDialog::Accepted) |
125 | return; |
126 | |
127 | if (dialog.useInMemoryDatabase()) { |
128 | QSqlDatabase::database(connectionName: "in_mem_db" , open: false).close(); |
129 | QSqlDatabase::removeDatabase(connectionName: "in_mem_db" ); |
130 | QSqlDatabase db = QSqlDatabase::addDatabase(type: "QSQLITE" , connectionName: "in_mem_db" ); |
131 | db.setDatabaseName(":memory:" ); |
132 | if (!db.open()) |
133 | QMessageBox::warning(parent: this, title: tr(s: "Unable to open database" ), text: tr(s: "An error occurred while " |
134 | "opening the connection: " ) + db.lastError().text()); |
135 | QSqlQuery q("" , db); |
136 | q.exec(query: "drop table Movies" ); |
137 | q.exec(query: "drop table Names" ); |
138 | q.exec(query: "create table Movies (id integer primary key, Title varchar, Director varchar, Rating number)" ); |
139 | q.exec(query: "insert into Movies values (0, 'Metropolis', 'Fritz Lang', '8.4')" ); |
140 | q.exec(query: "insert into Movies values (1, 'Nosferatu, eine Symphonie des Grauens', 'F.W. Murnau', '8.1')" ); |
141 | q.exec(query: "insert into Movies values (2, 'Bis ans Ende der Welt', 'Wim Wenders', '6.5')" ); |
142 | q.exec(query: "insert into Movies values (3, 'Hardware', 'Richard Stanley', '5.2')" ); |
143 | q.exec(query: "insert into Movies values (4, 'Mitchell', 'Andrew V. McLaglen', '2.1')" ); |
144 | q.exec(query: "create table Names (id integer primary key, Firstname varchar, Lastname varchar, City varchar)" ); |
145 | q.exec(query: "insert into Names values (0, 'Sala', 'Palmer', 'Morristown')" ); |
146 | q.exec(query: "insert into Names values (1, 'Christopher', 'Walker', 'Morristown')" ); |
147 | q.exec(query: "insert into Names values (2, 'Donald', 'Duck', 'Andeby')" ); |
148 | q.exec(query: "insert into Names values (3, 'Buck', 'Rogers', 'Paris')" ); |
149 | q.exec(query: "insert into Names values (4, 'Sherlock', 'Holmes', 'London')" ); |
150 | connectionWidget->refresh(); |
151 | } else { |
152 | QSqlError err = addConnection(driver: dialog.driverName(), dbName: dialog.databaseName(), host: dialog.hostName(), |
153 | user: dialog.userName(), passwd: dialog.password(), port: dialog.port()); |
154 | if (err.type() != QSqlError::NoError) |
155 | QMessageBox::warning(parent: this, title: tr(s: "Unable to open database" ), text: tr(s: "An error occurred while " |
156 | "opening the connection: " ) + err.text()); |
157 | } |
158 | } |
159 | |
160 | void Browser::showTable(const QString &t) |
161 | { |
162 | QSqlTableModel *model = new CustomModel(table, connectionWidget->currentDatabase()); |
163 | model->setEditStrategy(QSqlTableModel::OnRowChange); |
164 | model->setTable(connectionWidget->currentDatabase().driver()->escapeIdentifier(identifier: t, type: QSqlDriver::TableName)); |
165 | model->select(); |
166 | if (model->lastError().type() != QSqlError::NoError) |
167 | emit statusMessage(message: model->lastError().text()); |
168 | |
169 | table->setModel(model); |
170 | table->setEditTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed); |
171 | connect(sender: table->selectionModel(), signal: &QItemSelectionModel::currentRowChanged, |
172 | receiver: this, slot: &Browser::currentChanged); |
173 | |
174 | updateActions(); |
175 | } |
176 | |
177 | void Browser::showMetaData(const QString &t) |
178 | { |
179 | QSqlRecord rec = connectionWidget->currentDatabase().record(tablename: t); |
180 | QStandardItemModel *model = new QStandardItemModel(table); |
181 | |
182 | model->insertRows(row: 0, count: rec.count()); |
183 | model->insertColumns(column: 0, count: 7); |
184 | |
185 | model->setHeaderData(section: 0, orientation: Qt::Horizontal, value: "Fieldname" ); |
186 | model->setHeaderData(section: 1, orientation: Qt::Horizontal, value: "Type" ); |
187 | model->setHeaderData(section: 2, orientation: Qt::Horizontal, value: "Length" ); |
188 | model->setHeaderData(section: 3, orientation: Qt::Horizontal, value: "Precision" ); |
189 | model->setHeaderData(section: 4, orientation: Qt::Horizontal, value: "Required" ); |
190 | model->setHeaderData(section: 5, orientation: Qt::Horizontal, value: "AutoValue" ); |
191 | model->setHeaderData(section: 6, orientation: Qt::Horizontal, value: "DefaultValue" ); |
192 | |
193 | for (int i = 0; i < rec.count(); ++i) { |
194 | QSqlField fld = rec.field(i); |
195 | model->setData(index: model->index(row: i, column: 0), value: fld.name()); |
196 | model->setData(index: model->index(row: i, column: 1), value: fld.typeID() == -1 |
197 | ? QString(QMetaType::typeName(type: fld.type())) |
198 | : QString("%1 (%2)" ).arg(a: QMetaType::typeName(type: fld.type())).arg(a: fld.typeID())); |
199 | model->setData(index: model->index(row: i, column: 2), value: fld.length()); |
200 | model->setData(index: model->index(row: i, column: 3), value: fld.precision()); |
201 | model->setData(index: model->index(row: i, column: 4), value: fld.requiredStatus() == -1 ? QVariant("?" ) |
202 | : QVariant(bool(fld.requiredStatus()))); |
203 | model->setData(index: model->index(row: i, column: 5), value: fld.isAutoValue()); |
204 | model->setData(index: model->index(row: i, column: 6), value: fld.defaultValue()); |
205 | } |
206 | |
207 | table->setModel(model); |
208 | table->setEditTriggers(QAbstractItemView::NoEditTriggers); |
209 | |
210 | updateActions(); |
211 | } |
212 | |
213 | void Browser::insertRow() |
214 | { |
215 | QSqlTableModel *model = qobject_cast<QSqlTableModel *>(object: table->model()); |
216 | if (!model) |
217 | return; |
218 | |
219 | QModelIndex insertIndex = table->currentIndex(); |
220 | int row = insertIndex.row() == -1 ? 0 : insertIndex.row(); |
221 | model->insertRow(arow: row); |
222 | insertIndex = model->index(row, column: 0); |
223 | table->setCurrentIndex(insertIndex); |
224 | table->edit(index: insertIndex); |
225 | } |
226 | |
227 | void Browser::deleteRow() |
228 | { |
229 | QSqlTableModel *model = qobject_cast<QSqlTableModel *>(object: table->model()); |
230 | if (!model) |
231 | return; |
232 | |
233 | QModelIndexList currentSelection = table->selectionModel()->selectedIndexes(); |
234 | for (int i = 0; i < currentSelection.count(); ++i) { |
235 | if (currentSelection.at(i).column() != 0) |
236 | continue; |
237 | model->removeRow(arow: currentSelection.at(i).row()); |
238 | } |
239 | |
240 | updateActions(); |
241 | } |
242 | |
243 | void Browser::updateActions() |
244 | { |
245 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
246 | bool enableIns = tm; |
247 | bool enableDel = enableIns && table->currentIndex().isValid(); |
248 | |
249 | insertRowAction->setEnabled(enableIns); |
250 | deleteRowAction->setEnabled(enableDel); |
251 | |
252 | fieldStrategyAction->setEnabled(tm); |
253 | rowStrategyAction->setEnabled(tm); |
254 | manualStrategyAction->setEnabled(tm); |
255 | submitAction->setEnabled(tm); |
256 | revertAction->setEnabled(tm); |
257 | selectAction->setEnabled(tm); |
258 | |
259 | if (tm) { |
260 | QSqlTableModel::EditStrategy es = tm->editStrategy(); |
261 | fieldStrategyAction->setChecked(es == QSqlTableModel::OnFieldChange); |
262 | rowStrategyAction->setChecked(es == QSqlTableModel::OnRowChange); |
263 | manualStrategyAction->setChecked(es == QSqlTableModel::OnManualSubmit); |
264 | } |
265 | } |
266 | |
267 | void Browser::about() |
268 | { |
269 | QMessageBox::about(parent: this, title: tr(s: "About" ), text: tr(s: "The SQL Browser demonstration " |
270 | "shows how a data browser can be used to visualize the results of SQL" |
271 | "statements on a live database" )); |
272 | } |
273 | |
274 | void Browser::on_fieldStrategyAction_triggered() |
275 | { |
276 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
277 | if (tm) |
278 | tm->setEditStrategy(QSqlTableModel::OnFieldChange); |
279 | } |
280 | |
281 | void Browser::on_rowStrategyAction_triggered() |
282 | { |
283 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
284 | if (tm) |
285 | tm->setEditStrategy(QSqlTableModel::OnRowChange); |
286 | } |
287 | |
288 | void Browser::on_manualStrategyAction_triggered() |
289 | { |
290 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
291 | if (tm) |
292 | tm->setEditStrategy(QSqlTableModel::OnManualSubmit); |
293 | } |
294 | |
295 | void Browser::on_submitAction_triggered() |
296 | { |
297 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
298 | if (tm) |
299 | tm->submitAll(); |
300 | } |
301 | |
302 | void Browser::on_revertAction_triggered() |
303 | { |
304 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
305 | if (tm) |
306 | tm->revertAll(); |
307 | } |
308 | |
309 | void Browser::on_selectAction_triggered() |
310 | { |
311 | QSqlTableModel * tm = qobject_cast<QSqlTableModel *>(object: table->model()); |
312 | if (tm) |
313 | tm->select(); |
314 | } |
315 | |
316 | |