fix: comprehensive boot warnings and exceptions — fixable silenced, unfixable diagnosed

Build system (5 gaps hardened):
- COOKBOOK_OFFLINE defaults to true (fork-mode)
- normalize_patch handles diff -ruN format
- New 'repo validate-patches' command (25/25 relibc patches)
- 14 patched Qt/Wayland/display recipes added to protected list
- relibc archive regenerated with current patch chain

Boot fixes (fixable):
- Full ISO EFI partition: 16 MiB → 1 MiB (matches mini, BIOS hardcoded 2 MiB offset)
- D-Bus system bus: absolute /usr/bin/dbus-daemon path (was skipped)
- redbear-sessiond: absolute /usr/bin/redbear-sessiond path (was skipped)
- daemon framework: silenced spurious INIT_NOTIFY warnings for oneshot_async services (P0-daemon-silence-init-notify.patch)
- udev-shim: demoted INIT_NOTIFY warning to INFO (expected for oneshot_async)
- relibc: comprehensive named semaphores (sem_open/close/unlink) replacing upstream todo!() stubs
- greeterd: Wayland socket timeout 15s → 30s (compositor DRM wait)
- greeter-ui: built and linked (header guard unification, sem_compat stubs removed)
- mc: un-ignored in both configs, fixed glib/libiconv/pcre2 transitive deps
- greeter config: removed stale keymapd dependency from display/greeter services
- prefix toolchain: relibc headers synced, _RELIBC_STDLIB_H guard unified

Unfixable (diagnosed, upstream):
- i2c-hidd: abort on no-I2C-hardware (QEMU) — process::exit → relibc abort
- kded6/greeter-ui: page fault 0x8 — Qt library null deref
- Thread panics fd != -1 — Rust std library on Redox
- DHCP timeout / eth0 MAC — QEMU user-mode networking
- hwrngd/thermald — no hardware RNG/thermal in VM
- live preload allocation — BIOS memory fragmentation, continues on demand
This commit is contained in:
2026-05-05 20:20:37 +01:00
parent a5f97b6632
commit f31522130f
81834 changed files with 11051982 additions and 108 deletions
@@ -0,0 +1,44 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
cmake_minimum_required(VERSION 3.16)
project(sqlbrowser LANGUAGES CXX)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt6 REQUIRED COMPONENTS Core Gui Sql Widgets)
qt_standard_project_setup()
qt_add_executable(sqlbrowser
browser.cpp browser.h
browserwidget.ui
connectionwidget.cpp connectionwidget.h
main.cpp
qsqlconnectiondialog.cpp qsqlconnectiondialog.h qsqlconnectiondialog.ui
)
set_target_properties(sqlbrowser PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(sqlbrowser PRIVATE
Qt6::Core
Qt6::Gui
Qt6::Sql
Qt6::Widgets
)
install(TARGETS sqlbrowser
BUNDLE DESTINATION .
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
qt_generate_deploy_app_script(
TARGET sqlbrowser
OUTPUT_SCRIPT deploy_script
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${deploy_script})
@@ -0,0 +1,300 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "browser.h"
#include "qsqlconnectiondialog.h"
#include <ui_browserwidget.h>
#include <QAction>
#include <QMessageBox>
#include <QStandardItemModel>
#include <QSqlDriver>
#include <QSqlError>
#include <QSqlField>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QTextEdit>
#include <QTimer>
Browser::Browser(QWidget *parent)
: QWidget(parent)
, m_ui{std::make_unique<Ui::Browser>()}
{
m_ui->setupUi(this);
m_ui->table->addAction(m_ui->insertRowAction);
m_ui->table->addAction(m_ui->deleteRowAction);
m_ui->table->addAction(m_ui->fieldStrategyAction);
m_ui->table->addAction(m_ui->rowStrategyAction);
m_ui->table->addAction(m_ui->manualStrategyAction);
m_ui->table->addAction(m_ui->submitAction);
m_ui->table->addAction(m_ui->revertAction);
m_ui->table->addAction(m_ui->selectAction);
connect(m_ui->insertRowAction, &QAction::triggered, this, &Browser::insertRow);
connect(m_ui->deleteRowAction, &QAction::triggered, this, &Browser::deleteRow);
connect(m_ui->fieldStrategyAction, &QAction::triggered, this, &Browser::onFieldStrategyAction);
connect(m_ui->rowStrategyAction, &QAction::triggered, this, &Browser::onRowStrategyAction);
connect(m_ui->sqlEdit, &QTextEdit::textChanged, this, &Browser::updateActions);
connect(m_ui->connectionWidget, &ConnectionWidget::tableActivated,
this, &Browser::showTable);
connect(m_ui->connectionWidget, &ConnectionWidget::metaDataRequested,
this, &Browser::showMetaData);
connect(m_ui->submitButton, &QPushButton::clicked,
this, &Browser::onSubmitButton);
connect(m_ui->clearButton, &QPushButton::clicked,
this, &Browser::onClearButton);
if (QSqlDatabase::drivers().isEmpty())
QMessageBox::information(this, tr("No database drivers found"),
tr("This demo requires at least one Qt database driver. "
"Please check the documentation how to build the "
"Qt SQL plugins."));
QTimer::singleShot(0, this, [this]() {
updateActions();
emit statusMessage(tr("Ready."));
});
}
Browser::~Browser()
= default;
void Browser::exec()
{
QSqlQueryModel *model = new QSqlQueryModel(m_ui->table);
model->setQuery(QSqlQuery(m_ui->sqlEdit->toPlainText(), m_ui->connectionWidget->currentDatabase()));
m_ui->table->setModel(model);
if (model->lastError().type() != QSqlError::NoError)
emit statusMessage(model->lastError().text());
else if (model->query().isSelect())
emit statusMessage(tr("Query OK."));
else
emit statusMessage(tr("Query OK, number of affected rows: %1").arg(
model->query().numRowsAffected()));
updateActions();
}
QSqlError Browser::addConnection(const QString &driver, const QString &dbName, const QString &host,
const QString &user, const QString &passwd, int port)
{
static int cCount = 0;
QSqlError err;
QSqlDatabase db = QSqlDatabase::addDatabase(driver, QString("Browser%1").arg(++cCount));
db.setDatabaseName(dbName);
db.setHostName(host);
db.setPort(port);
if (!db.open(user, passwd)) {
err = db.lastError();
db = QSqlDatabase();
QSqlDatabase::removeDatabase(QString("Browser%1").arg(cCount));
}
m_ui->connectionWidget->refresh();
return err;
}
void Browser::openNewConnectionDialog()
{
QSqlConnectionDialog dialog(this);
if (dialog.exec() != QDialog::Accepted)
return;
if (dialog.useInMemoryDatabase()) {
QSqlDatabase::database("in_mem_db", false).close();
QSqlDatabase::removeDatabase("in_mem_db");
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "in_mem_db");
db.setDatabaseName(":memory:");
if (!db.open()) {
QMessageBox::warning(this, tr("Unable to open database"),
tr("An error occurred while "
"opening the connection: %1") .arg(db.lastError().text()));
return;
}
db.transaction();
QSqlQuery q(db);
q.exec("drop table Movies");
q.exec("drop table Names");
q.exec("create table Movies (id integer primary key, Title varchar, Director varchar, Rating number)");
q.exec("insert into Movies values (0, 'Metropolis', 'Fritz Lang', '8.4')");
q.exec("insert into Movies values (1, 'Nosferatu, eine Symphonie des Grauens', 'F.W. Murnau', '8.1')");
q.exec("insert into Movies values (2, 'Bis ans Ende der Welt', 'Wim Wenders', '6.5')");
q.exec("insert into Movies values (3, 'Hardware', 'Richard Stanley', '5.2')");
q.exec("insert into Movies values (4, 'Mitchell', 'Andrew V. McLaglen', '2.1')");
q.exec("create table Names (id integer primary key, FirstName varchar, LastName varchar, City varchar)");
q.exec("insert into Names values (0, 'Sala', 'Palmer', 'Morristown')");
q.exec("insert into Names values (1, 'Christopher', 'Walker', 'Morristown')");
q.exec("insert into Names values (2, 'Donald', 'Duck', 'Andeby')");
q.exec("insert into Names values (3, 'Buck', 'Rogers', 'Paris')");
q.exec("insert into Names values (4, 'Sherlock', 'Holmes', 'London')");
db.commit();
m_ui->connectionWidget->refresh();
} else {
QSqlError err = addConnection(dialog.driverName(), dialog.databaseName(), dialog.hostName(),
dialog.userName(), dialog.password(), dialog.port());
if (err.type() != QSqlError::NoError)
QMessageBox::warning(this, tr("Unable to open database"),
tr("An error occurred while "
"opening the connection: %1").arg(err.text()));
}
}
void Browser::showTable(const QString &t)
{
QSqlTableModel *model = new CustomModel(m_ui->table, m_ui->connectionWidget->currentDatabase());
model->setEditStrategy(QSqlTableModel::OnRowChange);
model->setTable(m_ui->connectionWidget->currentDatabase().driver()->escapeIdentifier(t, QSqlDriver::TableName));
model->select();
if (model->lastError().type() != QSqlError::NoError)
emit statusMessage(model->lastError().text());
m_ui->table->setModel(model);
m_ui->table->setEditTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed);
connect(m_ui->table->selectionModel(), &QItemSelectionModel::currentRowChanged,
this, &Browser::updateActions);
connect(m_ui->submitAction, &QAction::triggered, model, &QSqlTableModel::submitAll);
connect(m_ui->revertAction, &QAction::triggered, model, &QSqlTableModel::revertAll);
connect(m_ui->selectAction, &QAction::triggered, model, &QSqlTableModel::select);
updateActions();
}
void Browser::showMetaData(const QString &t)
{
QSqlRecord rec = m_ui->connectionWidget->currentDatabase().record(t);
QStandardItemModel *model = new QStandardItemModel(m_ui->table);
model->insertRows(0, rec.count());
model->insertColumns(0, 7);
model->setHeaderData(0, Qt::Horizontal, "Fieldname");
model->setHeaderData(1, Qt::Horizontal, "Type");
model->setHeaderData(2, Qt::Horizontal, "Length");
model->setHeaderData(3, Qt::Horizontal, "Precision");
model->setHeaderData(4, Qt::Horizontal, "Required");
model->setHeaderData(5, Qt::Horizontal, "AutoValue");
model->setHeaderData(6, Qt::Horizontal, "DefaultValue");
for (int i = 0; i < rec.count(); ++i) {
QSqlField fld = rec.field(i);
model->setData(model->index(i, 0), fld.name());
model->setData(model->index(i, 1), QString::fromUtf8(fld.metaType().name()));
model->setData(model->index(i, 2), fld.length());
model->setData(model->index(i, 3), fld.precision());
model->setData(model->index(i, 4), fld.requiredStatus() == -1 ? QVariant("?")
: QVariant(bool(fld.requiredStatus())));
model->setData(model->index(i, 5), fld.isAutoValue());
model->setData(model->index(i, 6), fld.defaultValue());
}
m_ui->table->setModel(model);
m_ui->table->setEditTriggers(QAbstractItemView::NoEditTriggers);
updateActions();
}
void Browser::insertRow()
{
QSqlTableModel *model = qobject_cast<QSqlTableModel *>(m_ui->table->model());
if (!model)
return;
QModelIndex insertIndex = m_ui->table->currentIndex();
int row = insertIndex.row() == -1 ? 0 : insertIndex.row();
model->insertRow(row);
insertIndex = model->index(row, 0);
m_ui->table->setCurrentIndex(insertIndex);
m_ui->table->edit(insertIndex);
}
void Browser::deleteRow()
{
QSqlTableModel *model = qobject_cast<QSqlTableModel *>(m_ui->table->model());
if (!model)
return;
const QModelIndexList currentSelection = m_ui->table->selectionModel()->selectedIndexes();
for (const auto &idx : currentSelection) {
if (idx.column() != 0)
continue;
model->removeRow(idx.row());
}
updateActions();
}
void Browser::updateActions()
{
QSqlTableModel *tm = qobject_cast<QSqlTableModel *>(m_ui->table->model());
bool enableIns = tm != nullptr;
bool enableDel = enableIns && m_ui->table->currentIndex().isValid();
m_ui->insertRowAction->setEnabled(enableIns);
m_ui->deleteRowAction->setEnabled(enableDel);
m_ui->submitAction->setEnabled(tm);
m_ui->revertAction->setEnabled(tm);
m_ui->selectAction->setEnabled(tm);
const bool isEmpty = m_ui->sqlEdit->toPlainText().isEmpty();
m_ui->submitButton->setEnabled(m_ui->connectionWidget->currentDatabase().isOpen() && !isEmpty);
m_ui->clearButton->setEnabled(!isEmpty);
if (tm) {
QSqlTableModel::EditStrategy es = tm->editStrategy();
m_ui->fieldStrategyAction->setChecked(es == QSqlTableModel::OnFieldChange);
m_ui->rowStrategyAction->setChecked(es == QSqlTableModel::OnRowChange);
m_ui->manualStrategyAction->setChecked(es == QSqlTableModel::OnManualSubmit);
} else {
m_ui->fieldStrategyAction->setEnabled(false);
m_ui->rowStrategyAction->setEnabled(false);
m_ui->manualStrategyAction->setEnabled(false);
}
}
void Browser::about()
{
QMessageBox::about(this, tr("About"),
tr("The SQL Browser demonstration shows how a data browser "
"can be used to visualize the results of SQL "
"statements on a live database"));
}
void Browser::onFieldStrategyAction()
{
QSqlTableModel *tm = qobject_cast<QSqlTableModel *>(m_ui->table->model());
if (tm)
tm->setEditStrategy(QSqlTableModel::OnFieldChange);
}
void Browser::onRowStrategyAction()
{
QSqlTableModel *tm = qobject_cast<QSqlTableModel *>(m_ui->table->model());
if (tm)
tm->setEditStrategy(QSqlTableModel::OnRowChange);
}
void Browser::onManualStrategyAction()
{
QSqlTableModel *tm = qobject_cast<QSqlTableModel *>(m_ui->table->model());
if (tm)
tm->setEditStrategy(QSqlTableModel::OnManualSubmit);
}
void Browser::onSubmitButton()
{
exec();
m_ui->sqlEdit->setFocus();
}
void Browser::onClearButton()
{
m_ui->sqlEdit->clear();
m_ui->sqlEdit->setFocus();
}
@@ -0,0 +1,71 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef BROWSER_H
#define BROWSER_H
#include <QWidget>
#include <QSqlTableModel>
#include <memory>
QT_FORWARD_DECLARE_CLASS(QSqlError)
QT_BEGIN_NAMESPACE
namespace Ui
{
class Browser;
}
QT_END_NAMESPACE
class Browser : public QWidget
{
Q_OBJECT
public:
explicit Browser(QWidget *parent = nullptr);
~Browser() override;
QSqlError addConnection(const QString &driver, const QString &dbName, const QString &host,
const QString &user, const QString &passwd, int port);
public slots:
void openNewConnectionDialog();
void about();
protected:
void insertRow();
void deleteRow();
void updateActions();
protected slots:
void exec();
void showTable(const QString &table);
void showMetaData(const QString &table);
void onFieldStrategyAction();
void onRowStrategyAction();
void onManualStrategyAction();
void onSubmitButton();
void onClearButton();
signals:
void statusMessage(const QString &message);
private:
const std::unique_ptr<Ui::Browser> m_ui;
};
class CustomModel : public QSqlTableModel
{
Q_OBJECT
public:
using QSqlTableModel::QSqlTableModel;
QVariant data(const QModelIndex &idx, int role) const override
{
if (role == Qt::BackgroundRole && isDirty(idx))
return QBrush(QColor(Qt::yellow));
return QSqlTableModel::data(idx, role);
}
};
#endif
@@ -0,0 +1,241 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Browser</class>
<widget class="QWidget" name="Browser">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>765</width>
<height>515</height>
</rect>
</property>
<property name="windowTitle">
<string>Qt SQL Browser</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>8</number>
</property>
<item>
<widget class="QSplitter" name="splitter_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="ConnectionWidget" name="connectionWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QTableView" name="table">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>2</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="contextMenuPolicy">
<enum>Qt::ActionsContextMenu</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>180</height>
</size>
</property>
<property name="title">
<string>SQL Query</string>
</property>
<layout class="QVBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>9</number>
</property>
<item>
<widget class="QTextEdit" name="sqlEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>18</height>
</size>
</property>
<property name="baseSize">
<size>
<width>0</width>
<height>120</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="margin">
<number>1</number>
</property>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="clearButton">
<property name="text">
<string>&amp;Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="submitButton">
<property name="text">
<string>&amp;Submit</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
</layout>
<action name="insertRowAction">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Insert Row</string>
</property>
<property name="statusTip">
<string>Inserts a new Row</string>
</property>
</action>
<action name="deleteRowAction">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>&amp;Delete Row</string>
</property>
<property name="statusTip">
<string>Deletes the current Row</string>
</property>
</action>
<action name="fieldStrategyAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Submit on &amp;Field Change</string>
</property>
<property name="toolTip">
<string>Commit on Field Change</string>
</property>
</action>
<action name="rowStrategyAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Submit on &amp;Row Change</string>
</property>
<property name="toolTip">
<string>Commit on Row Change</string>
</property>
</action>
<action name="manualStrategyAction">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Submit &amp;Manually</string>
</property>
<property name="toolTip">
<string>Commit Manually</string>
</property>
</action>
<action name="submitAction">
<property name="text">
<string>&amp;Submit All</string>
</property>
<property name="toolTip">
<string>Submit Changes</string>
</property>
</action>
<action name="revertAction">
<property name="text">
<string>&amp;Revert All</string>
</property>
<property name="toolTip">
<string>Revert</string>
</property>
</action>
<action name="selectAction">
<property name="text">
<string>S&amp;elect</string>
</property>
<property name="toolTip">
<string>Refresh Data from Database</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>ConnectionWidget</class>
<extends>QTreeView</extends>
<header>connectionwidget.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>sqlEdit</tabstop>
<tabstop>clearButton</tabstop>
<tabstop>submitButton</tabstop>
<tabstop>connectionWidget</tabstop>
<tabstop>table</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
@@ -0,0 +1,130 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "connectionwidget.h"
#include <QAction>
#include <QHeaderView>
#include <QSqlDatabase>
#include <QTreeWidget>
#include <QVBoxLayout>
ConnectionWidget::ConnectionWidget(QWidget *parent)
: QWidget(parent)
, tree(new QTreeWidget(this))
{
QVBoxLayout *layout = new QVBoxLayout(this);
layout->setContentsMargins({});
tree->setHeaderLabels(QStringList(tr("Database")));
tree->header()->setStretchLastSection(true);
QAction *refreshAction = new QAction(tr("Refresh"), tree);
metaDataAction = new QAction(tr("Show Schema"), tree);
connect(refreshAction, &QAction::triggered, this, &ConnectionWidget::refresh);
connect(metaDataAction, &QAction::triggered, this, &ConnectionWidget::showMetaData);
tree->addAction(refreshAction);
tree->addAction(metaDataAction);
tree->setContextMenuPolicy(Qt::ActionsContextMenu);
layout->addWidget(tree);
connect(tree, &QTreeWidget::itemActivated,
this, &ConnectionWidget::onItemActivated);
connect(tree, &QTreeWidget::currentItemChanged,
this, &ConnectionWidget::onCurrentItemChanged);
}
ConnectionWidget::~ConnectionWidget()
= default;
void ConnectionWidget::refresh()
{
const auto qDBCaption = [](const QSqlDatabase &db)
{
QString nm = db.driverName() + QLatin1Char(':');
if (!db.userName().isEmpty())
nm += db.userName() + QLatin1Char('@');
nm += db.databaseName();
return nm;
};
tree->clear();
const QStringList connectionNames = QSqlDatabase::connectionNames();
bool gotActiveDb = false;
for (const auto &connectionName : connectionNames) {
QTreeWidgetItem *root = new QTreeWidgetItem(tree);
QSqlDatabase db = QSqlDatabase::database(connectionName, false);
root->setText(0, qDBCaption(db));
if (connectionName == activeDb) {
gotActiveDb = true;
setActive(root);
}
if (db.isOpen()) {
QStringList tables = db.tables();
for (int t = 0; t < tables.count(); ++t) {
QTreeWidgetItem *table = new QTreeWidgetItem(root);
table->setText(0, tables.at(t));
}
}
}
if (!gotActiveDb) {
activeDb = connectionNames.value(0);
setActive(tree->topLevelItem(0));
}
tree->doItemsLayout(); // HACK
}
QSqlDatabase ConnectionWidget::currentDatabase() const
{
return QSqlDatabase::database(activeDb);
}
void ConnectionWidget::setActive(QTreeWidgetItem *item)
{
const auto qSetBold = [](QTreeWidgetItem *item, bool bold)
{
QFont font = item->font(0);
font.setBold(bold);
item->setFont(0, font);
};
for (int i = 0; i < tree->topLevelItemCount(); ++i) {
if (tree->topLevelItem(i)->font(0).bold())
qSetBold(tree->topLevelItem(i), false);
}
if (!item)
return;
qSetBold(item, true);
activeDb = QSqlDatabase::connectionNames().value(tree->indexOfTopLevelItem(item));
}
void ConnectionWidget::onItemActivated(QTreeWidgetItem *item)
{
if (!item)
return;
if (!item->parent()) {
setActive(item);
} else {
setActive(item->parent());
emit tableActivated(item->text(0));
}
}
void ConnectionWidget::showMetaData()
{
QTreeWidgetItem *cItem = tree->currentItem();
if (!cItem || !cItem->parent())
return;
setActive(cItem->parent());
emit metaDataRequested(cItem->text(0));
}
void ConnectionWidget::onCurrentItemChanged(QTreeWidgetItem *current)
{
metaDataAction->setEnabled(current && current->parent());
}
@@ -0,0 +1,40 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef CONNECTIONWIDGET_H
#define CONNECTIONWIDGET_H
#include <QWidget>
QT_FORWARD_DECLARE_CLASS(QTreeWidget)
QT_FORWARD_DECLARE_CLASS(QTreeWidgetItem)
QT_FORWARD_DECLARE_CLASS(QSqlDatabase)
class ConnectionWidget : public QWidget
{
Q_OBJECT
public:
explicit ConnectionWidget(QWidget *parent = nullptr);
~ConnectionWidget() override;
QSqlDatabase currentDatabase() const;
signals:
void tableActivated(const QString &table);
void metaDataRequested(const QString &tableName);
public slots:
void refresh();
void showMetaData();
void onItemActivated(QTreeWidgetItem *item);
void onCurrentItemChanged(QTreeWidgetItem *current);
private:
void setActive(QTreeWidgetItem *);
QTreeWidget *tree;
QAction *metaDataAction;
QString activeDb;
};
#endif
@@ -0,0 +1,64 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "browser.h"
#include <QApplication>
#include <QDebug>
#include <QMainWindow>
#include <QMenu>
#include <QMenuBar>
#include <QSqlError>
#include <QStatusBar>
#include <QUrl>
void addConnectionsFromCommandline(const QStringList &args, Browser *browser)
{
for (qsizetype i = 1; i < args.count(); ++i) {
const auto &arg = args.at(i);
const QUrl url(arg, QUrl::TolerantMode);
if (!url.isValid()) {
qWarning("Invalid URL: %s", qPrintable(arg));
continue;
}
QSqlError err = browser->addConnection(url.scheme(), url.path().mid(1), url.host(),
url.userName(), url.password(), url.port(-1));
if (err.type() != QSqlError::NoError)
qDebug() << "Unable to open connection:" << err;
}
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow mainWin;
mainWin.setWindowTitle(QApplication::translate("MainWindow", "Qt SQL Browser"));
Browser browser(&mainWin);
mainWin.setCentralWidget(&browser);
QMenu *fileMenu = mainWin.menuBar()->addMenu(QObject::tr("&File"));
fileMenu->addAction(QApplication::translate("MainWindow", "Add &Connection..."),
&browser, &Browser::openNewConnectionDialog);
fileMenu->addSeparator();
fileMenu->addAction(QApplication::translate("MainWindow", "&Quit"),
qApp, &QApplication::quit);
QMenu *helpMenu = mainWin.menuBar()->addMenu(QObject::tr("&Help"));
helpMenu->addAction(QApplication::translate("MainWindow", "About"),
&browser, &Browser::about);
helpMenu->addAction(QApplication::translate("MainWindow", "About Qt"),
qApp, &QApplication::aboutQt);
QObject::connect(&browser, &Browser::statusMessage,
&mainWin, [&mainWin](const QString &text) { mainWin.statusBar()->showMessage(text); });
addConnectionsFromCommandline(app.arguments(), &browser);
mainWin.show();
if (QSqlDatabase::connectionNames().isEmpty())
QMetaObject::invokeMethod(&browser, &Browser::openNewConnectionDialog,
Qt::QueuedConnection);
return app.exec();
}
@@ -0,0 +1,73 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "qsqlconnectiondialog.h"
#include <ui_qsqlconnectiondialog.h>
#include <QCheckBox>
#include <QMessageBox>
#include <QPushButton>
#include <QSqlDatabase>
QSqlConnectionDialog::QSqlConnectionDialog(QWidget *parent)
: QDialog(parent)
, m_ui{std::make_unique<Ui::QSqlConnectionDialogUi>()}
{
m_ui->setupUi(this);
QStringList drivers = QSqlDatabase::drivers();
if (!drivers.contains("QSQLITE"))
m_ui->dbCheckBox->setEnabled(false);
m_ui->comboDriver->addItems(drivers);
}
QSqlConnectionDialog::~QSqlConnectionDialog()
= default;
QString QSqlConnectionDialog::driverName() const
{
return m_ui->comboDriver->currentText();
}
QString QSqlConnectionDialog::databaseName() const
{
return m_ui->editDatabase->text();
}
QString QSqlConnectionDialog::userName() const
{
return m_ui->editUsername->text();
}
QString QSqlConnectionDialog::password() const
{
return m_ui->editPassword->text();
}
QString QSqlConnectionDialog::hostName() const
{
return m_ui->editHostname->text();
}
int QSqlConnectionDialog::port() const
{
return m_ui->portSpinBox->value();
}
bool QSqlConnectionDialog::useInMemoryDatabase() const
{
return m_ui->dbCheckBox->isChecked();
}
void QSqlConnectionDialog::accept()
{
if (m_ui->comboDriver->currentText().isEmpty()) {
QMessageBox::information(this, tr("No database driver selected"),
tr("Please select a database driver"));
m_ui->comboDriver->setFocus();
} else {
QDialog::accept();
}
}
@@ -0,0 +1,39 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#ifndef QSQLCONNECTIONDIALOG_H
#define QSQLCONNECTIONDIALOG_H
#include <QDialog>
#include <memory>
QT_BEGIN_NAMESPACE
namespace Ui
{
class QSqlConnectionDialogUi;
}
QT_END_NAMESPACE
class QSqlConnectionDialog : public QDialog
{
Q_OBJECT
public:
explicit QSqlConnectionDialog(QWidget *parent = nullptr);
~QSqlConnectionDialog() override;
QString driverName() const;
QString databaseName() const;
QString userName() const;
QString password() const;
QString hostName() const;
int port() const;
bool useInMemoryDatabase() const;
void accept() override;
private:
const std::unique_ptr<Ui::QSqlConnectionDialogUi> m_ui;
};
#endif
@@ -0,0 +1,229 @@
<ui version="4.0" >
<author></author>
<comment></comment>
<exportmacro></exportmacro>
<class>QSqlConnectionDialogUi</class>
<widget class="QDialog" name="QSqlConnectionDialogUi" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>315</width>
<height>302</height>
</rect>
</property>
<property name="windowTitle" >
<string>Connect...</string>
</property>
<layout class="QVBoxLayout" >
<property name="margin" >
<number>8</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<widget class="QGroupBox" name="connGroupBox" >
<property name="title" >
<string>Connection settings</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="1" >
<widget class="QComboBox" name="comboDriver" />
</item>
<item row="2" column="0" >
<widget class="QLabel" name="textLabel4" >
<property name="text" >
<string>&amp;Username:</string>
</property>
<property name="buddy" >
<cstring>editUsername</cstring>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="textLabel2" >
<property name="text" >
<string>D&amp;river</string>
</property>
<property name="buddy" >
<cstring>comboDriver</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="editDatabase" />
</item>
<item row="5" column="1" >
<widget class="QSpinBox" name="portSpinBox" >
<property name="specialValueText" >
<string>Default</string>
</property>
<property name="maximum" >
<number>65535</number>
</property>
<property name="minimum" >
<number>-1</number>
</property>
<property name="value" >
<number>-1</number>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="textLabel3" >
<property name="text" >
<string>Database Name:</string>
</property>
<property name="buddy" >
<cstring>editDatabase</cstring>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLineEdit" name="editPassword" >
<property name="echoMode" >
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLineEdit" name="editUsername" />
</item>
<item row="4" column="1" >
<widget class="QLineEdit" name="editHostname" />
</item>
<item row="4" column="0" >
<widget class="QLabel" name="textLabel5" >
<property name="text" >
<string>&amp;Hostname:</string>
</property>
<property name="buddy" >
<cstring>editHostname</cstring>
</property>
</widget>
</item>
<item row="5" column="0" >
<widget class="QLabel" name="textLabel5_2" >
<property name="text" >
<string>P&amp;ort:</string>
</property>
<property name="buddy" >
<cstring>portSpinBox</cstring>
</property>
</widget>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="textLabel4_2" >
<property name="text" >
<string>&amp;Password:</string>
</property>
<property name="buddy" >
<cstring>editPassword</cstring>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" >
<property name="margin" >
<number>0</number>
</property>
<property name="spacing" >
<number>6</number>
</property>
<item>
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="dbCheckBox" >
<property name="text" >
<string>Us&amp;e predefined in-memory database</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<pixmapfunction></pixmapfunction>
<tabstops>
<tabstop>comboDriver</tabstop>
<tabstop>editDatabase</tabstop>
<tabstop>editUsername</tabstop>
<tabstop>editPassword</tabstop>
<tabstop>editHostname</tabstop>
<tabstop>portSpinBox</tabstop>
<tabstop>dbCheckBox</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>dbCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>connGroupBox</receiver>
<slot>setDisabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>165</x>
<y>248</y>
</hint>
<hint type="destinationlabel">
<x>107</x>
<y>221</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>QSqlConnectionDialogUi</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>19</x>
<y>278</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>244</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>QSqlConnectionDialogUi</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>58</x>
<y>276</y>
</hint>
<hint type="destinationlabel">
<x>58</x>
<y>258</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,18 @@
TEMPLATE = app
TARGET = sqlbrowser
QT += sql widgets
requires(qtConfig(tableview))
HEADERS = browser.h connectionwidget.h qsqlconnectiondialog.h
SOURCES = main.cpp browser.cpp connectionwidget.cpp qsqlconnectiondialog.cpp
FORMS = browserwidget.ui qsqlconnectiondialog.ui
build_all:!build_pass {
CONFIG -= build_all
CONFIG += release
}
# install
target.path = $$[QT_INSTALL_EXAMPLES]/sql/sqlbrowser
INSTALLS += target