Double clicking a table now opens a CRUD page for that table however data cannot be changed yet thought it will display an editbox.

This commit is contained in:
eelke 2018-01-09 20:39:43 +01:00
parent abd4020ddf
commit 2ba27178a2
13 changed files with 288 additions and 33 deletions

View file

@ -1,14 +1,25 @@
#include "CrudModel.h"
#include "ASyncWindow.h"
#include "OpenDatabase.h"
#include "PgDatabaseCatalog.h"
#include "PgAttributeContainer.h"
#include "PgConstraintContainer.h"
#include "GlobalIoService.h"
#include "SqlFormattingUtils.h"
#include "WorkManager.h"
#include <QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>
#include "Pgsql_oids.h"
#include <string>
CrudModel::CrudModel()
: m_dbConn(*getGlobalAsioIoService())
{}
CrudModel::CrudModel(ASyncWindow *async_window)
: m_asyncWindow(async_window)
, m_dbConn(*getGlobalAsioIoService())
{
connect(&m_dbConn, &ASyncDBConnection::onStateChanged, this, &CrudModel::connectionStateChanged);
}
CrudModel::~CrudModel()
{
@ -21,11 +32,150 @@ CrudModel::~CrudModel()
* when ordered by primary key, offset and limit work very quickly so we can get away with not loading
* everything.
*/
void CrudModel::setData(std::shared_ptr<OpenDatabase> db, const PgClass &table)
void CrudModel::setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table)
{
m_database = db;
m_table = table;
m_primaryKey = db->catalogue()->constraints()->getPrimaryForRelation(table.oid);
//cat->attributes()->getColumnsForRelation()
m_dbConn.setupConnection(m_database.config());
callLoadData = true;
m_dbConn.setupConnection(m_database->config());
}
QVariant CrudModel::headerData(int section, Qt::Orientation orientation, int role) const
{
QVariant r;
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
QString s(m_roData->getColName(section));
s += "\n";
s += getTypeDisplayString(*m_database->catalogue(), getType(section));
r = s;
}
else {
r = QString::number(section + 1);
}
}
return r;
}
// Basic functionality:
int CrudModel::rowCount(const QModelIndex &parent) const
{
return m_roData ? m_roData->rows() : 0;
}
int CrudModel::columnCount(const QModelIndex &parent) const
{
return m_roData ? m_roData->cols() : 0;
}
Oid CrudModel::getType(int column) const
{
return m_roData ? m_roData->type(column) : InvalidOid;
}
QVariant CrudModel::getData(const QModelIndex &index) const
{
QVariant r;
if (m_roData) {
int rij = index.row();
int col = index.column();
if (m_roData->null(col, rij)) {
r = "null";
}
else {
Oid o = m_roData->type(col);
auto value = m_roData->get(col, rij);
switch (o) {
case Pgsql::bool_oid:
r = bool(value); //s = (s == "t") ? "TRUE" : "FALSE";
break;
default: {
QString s = value;
if (s.length() > 256) {
s.truncate(256);
}
r = s;
}
}
}
}
return r;
}
QVariant CrudModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::ForegroundRole) {
int rij = index.row();
int col = index.column();
if (m_roData->null(col, rij)) {
return QBrush(Qt::gray);
}
}
else if (role == Qt::EditRole) {
return getData(index);
}
return BaseTableModel::data(index, role);
}
void CrudModel::loadData()
{
QString table_name = genFQTableName(*m_database->catalogue(), m_table);
std::string q = "SELECT * FROM ";
q += table_name.toUtf8();
m_dbConn.send(q, [this] (Expected<std::shared_ptr<Pgsql::Result>> res, qint64) {
if (res.valid()) {
auto dbres = res.get();
if (dbres && *dbres) {
// WorkManager::getWorkManager()->addWork(
// [dbres, this] () -> void {
// std::shared_ptr<RowList> rl = resultToRowList(dbres);
// m_asyncWindow->QueueTask([this, rl]() { loadIntoModel(rl); });
// });
m_asyncWindow->QueueTask([this, dbres]() { loadIntoModel(dbres); });
}
}
else {
// emit onQueryError();
}
});
}
void CrudModel::loadIntoModel(std::shared_ptr<Pgsql::Result> data)
{
beginResetModel();
m_roData = data;
endResetModel();
}
void CrudModel::connectionStateChanged(ASyncDBConnection::State state)
{
switch (state) {
case ASyncDBConnection::State::NotConnected:
break;
case ASyncDBConnection::State::Connecting:
break;
case ASyncDBConnection::State::Connected:
if (callLoadData) {
callLoadData = false;
loadData();
}
break;
case ASyncDBConnection::State::QuerySend:
break;
case ASyncDBConnection::State::CancelSend:
break;
case ASyncDBConnection::State::Terminating:
break;
}
}
Qt::ItemFlags CrudModel::flags(const QModelIndex &) const
{
return Qt::ItemIsSelectable + Qt::ItemIsEditable + Qt::ItemIsEnabled;
}

View file

@ -4,13 +4,15 @@
#include "BaseTableModel.h"
#include "ASyncDBConnection.h"
#include "PgClass.h"
#include "PgConstraint.h"
#include "Pgsql_Connection.h"
#include <memory>
#include <vector>
#include <boost/optional.hpp>
class PgConstraint;
class OpenDatase;
class OpenDatabase;
class ASyncWindow;
/**
* @brief The CrudModel class
@ -33,35 +35,55 @@ class OpenDatase;
class CrudModel: public BaseTableModel {
Q_OBJECT
public:
CrudModel();
explicit CrudModel(ASyncWindow *async_win);
~CrudModel();
void setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table);
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void setData(std::shared_ptr<OpenDatabase> db, const PgClass &table);
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
virtual QVariant data(const QModelIndex &index, int role) const override;
virtual Qt::ItemFlags flags(const QModelIndex &) const override;
protected:
virtual Oid getType(int column) const override;
virtual QVariant getData(const QModelIndex &index) const override;
private:
ASyncWindow * m_asyncWindow;
std::shared_ptr<OpenDatabase> m_database;
PgClass m_table;
boost::optional<PgConstraint> m_primaryKey;
ASyncDBConnection m_dbConn;
bool callLoadData = false;
using RowData = std::vector<std::string>;
using RowDataPtr = std::unique_ptr<RowData>;
/** Choosen for a vector of pointers while vector is relatively slow with insertion and removal in the middle
* I hope the small size of the elements will make this not much of an issue while the simple linear and sequential
* nature of a vector will keep memory allocation fairly efficient.
using RowList = std::vector<RowDataPtr>;
// using RowData = std::vector<std::string>;
// using RowDataPtr = std::unique_ptr<RowData>;
// /** Choosen for a vector of pointers while vector is relatively slow with insertion and removal in the middle
// * I hope the small size of the elements will make this not much of an issue while the simple linear and sequential
// * nature of a vector will keep memory allocation fairly efficient.
// */
// using RowList = std::vector<RowDataPtr>;
std::shared_ptr<Pgsql::Result> m_roData;
void loadData();
void loadIntoModel(std::shared_ptr<Pgsql::Result> data);
// std::shared_ptr<RowList> resultToRowList(std::shared_ptr<Pgsql::Result> result);
private slots:
void connectionStateChanged(ASyncDBConnection::State state);
// void queryResult(std::shared_ptr<Pgsql::Result> result);
// void queryError();
// void dataProcessingFutureFinished();
};
#endif // CRUDMODEL_H

View file

@ -1,14 +1,38 @@
#include "CrudTab.h"
#include "CrudTab.h"
#include "ui_CrudTab.h"
#include "CrudModel.h"
#include "MainWindow.h"
#include "ResultTableModelUtil.h"
CrudTab::CrudTab(QWidget *parent) :
QWidget(parent),
ui(new Ui::CrudTab)
CrudTab::CrudTab(MainWindow *parent)
: QWidget(parent)
, ui(new Ui::CrudTab)
, m_window(parent)
{
ui->setupUi(this);
SetTableViewDefault(ui->tableView);
m_crudModel = new CrudModel(parent);
ui->tableView->setModel(m_crudModel);
}
CrudTab::~CrudTab()
{
delete ui;
}
void CrudTab::setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table)
{
m_db = db;
m_table = table;
// m_catalog = cat;
// m_tablesModel->setCatalog(cat);
// ui->tableListTable->resizeColumnsToContents();
// m_namespaceFilterWidget->init(cat->namespaces());
// auto highlighter = new SqlSyntaxHighlighter(ui->constraintSqlEdit->document());
// highlighter->setTypes(*cat->types());
m_crudModel->setConfig(db, table);
}

View file

@ -1,22 +1,37 @@
#ifndef CRUDTAB_H
#ifndef CRUDTAB_H
#define CRUDTAB_H
#include "PgClass.h"
#include <QWidget>
#include <memory>
namespace Ui {
class CrudTab;
}
class OpenDatabase;
class CrudModel;
class MainWindow;
class CrudTab : public QWidget
{
Q_OBJECT
public:
explicit CrudTab(QWidget *parent = 0);
explicit CrudTab(MainWindow *parent = 0);
~CrudTab();
void setConfig(std::shared_ptr<OpenDatabase> db, const PgClass &table);
private:
Ui::CrudTab *ui;
MainWindow *m_window;
std::shared_ptr<OpenDatabase> m_db;
PgClass m_table;
CrudModel *m_crudModel = nullptr;
};
#endif // CRUDTAB_H

View file

@ -14,6 +14,7 @@
#include "QueryTab.h"
#include "util.h"
#include "MasterController.h"
#include "CrudTab.h"
#include "WorkManager.h"
#include "ScopeGuard.h"
@ -45,7 +46,13 @@ QueryTab* MainWindow::newSqlPage()
return qt;
}
void MainWindow::newCrudPage(const PgClass &table)
{
CrudTab *ct = new CrudTab(this);
ct->setConfig(m_database, table);
ui->tabWidget->addTab(ct, "CRUD");
ui->tabWidget->setCurrentWidget(ct);
}
QueryTab *MainWindow::GetActiveQueryTab()
{
@ -85,6 +92,7 @@ void MainWindow::catalogLoaded()
ui->tabWidget->addTab(tt, "Tables");
ui->tabWidget->setCurrentWidget(tt);
newSqlPage();
} catch (std::runtime_error &ex) {
QMessageBox::critical(this, "Error reading database",

View file

@ -32,6 +32,7 @@ class QueryTab;
class MasterController;
class QCloseEvent;
class OpenDatabase;
class PgClass;
class MainWindow : public ASyncWindow {
Q_OBJECT
@ -42,6 +43,8 @@ public:
void setConfig(const ConnectionConfig &config);
std::shared_ptr<OpenDatabase> getDatabase() { return m_database; }
void newCrudPage(const PgClass &table);
private:
Ui::MainWindow *ui;

View file

@ -14,10 +14,12 @@
#include "SqlSyntaxHighlighter.h"
#include <QStringBuilder>
#include <boost/container/flat_set.hpp>
#include "MainWindow.h"
TablesPage::TablesPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::TablesPage)
TablesPage::TablesPage(MainWindow *parent)
: QWidget(parent)
, ui(new Ui::TablesPage)
, m_window(parent)
{
ui->setupUi(this);
@ -121,3 +123,12 @@ void TablesPage::constraintsTable_selectionChanged(const QItemSelection &selecte
}
ui->constraintSqlEdit->setPlainText(drops % "\n" % creates);
}
void TablesPage::on_tableListTable_doubleClicked(const QModelIndex &index)
{
PgClass table = m_tablesModel->getTable(index.row());
if (table.oid != InvalidOid) {
m_window->newCrudPage(table);
}
}

View file

@ -15,18 +15,20 @@ class ConstraintModel;
class PgDatabaseCatalog;
class NamespaceFilterWidget;
class IndexModel;
class MainWindow;
class TablesPage : public QWidget
{
Q_OBJECT
public:
explicit TablesPage(QWidget *parent = 0);
explicit TablesPage(MainWindow *parent = 0);
~TablesPage();
void setCatalog(std::shared_ptr<PgDatabaseCatalog> cat);
private:
Ui::TablesPage *ui;
MainWindow *m_window;
std::shared_ptr<PgDatabaseCatalog> m_catalog;
TablesTableModel* m_tablesModel = nullptr;
ColumnTableModel* m_columnsModel = nullptr;
@ -39,6 +41,7 @@ private slots:
void tableListTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void constraintsTable_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
void constraintsTable_selectionChanged(const QItemSelection &selected, const QItemSelection &deselected);
void on_tableListTable_doubleClicked(const QModelIndex &index);
};
#endif // TABLESPAGE_H

View file

@ -5,7 +5,7 @@
#-------------------------------------------------
CONFIG += c++17
QT += core gui
QT += core gui concurrent
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets sql
@ -20,11 +20,11 @@ DEFINES += WIN32_LEAN_AND_MEAN NOMINMAX _WIN32_WINNT=0x0501
LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
#debug {
LIBS += c:/prog/lib/botand_imp.lib
LIBS += c:/prog/lib/botan_imp.lib
#}
#release {
#LIBS += c:\prog\lib\botan.lib
#LIBS += c:/prog/lib/botan_imp.lib
#}
win32:RC_ICONS += pglab.ico

View file

@ -12,6 +12,7 @@ namespace {
{
qRegisterMetaType<ASyncDBConnection::State>();
qRegisterMetaType<Pgsql::ErrorDetails>();
qRegisterMetaType<std::shared_ptr<Pgsql::Result>>();
}
} registerMetaTypes_instance;

View file

@ -48,11 +48,28 @@ public:
bool send(const std::string &command, on_result_callback on_result);
bool send(const std::string &command, Pgsql::Params params, on_result_callback on_result);
/** This version of send uses the signal onQueryResult and onQueryError to report back
* the completion of the query.
*/
bool send(const std::string &command, Pgsql::Params params = Pgsql::Params())
{
return send(command, params, [this] (Expected<std::shared_ptr<Pgsql::Result>> res, qint64) {
if (res.valid()) {
emit onQueryResult(res.get());
}
else {
emit onQueryError();
}
});
}
bool cancel();
signals:
void onStateChanged(ASyncDBConnection::State state);
void onNotice(Pgsql::ErrorDetails notice);
void onQueryResult(std::shared_ptr<Pgsql::Result> result);
void onQueryError();
private:
Pgsql::Connection m_connection;
@ -71,6 +88,7 @@ private:
Q_DECLARE_METATYPE(ASyncDBConnection::State);
Q_DECLARE_METATYPE(Pgsql::ErrorDetails);
Q_DECLARE_METATYPE(std::shared_ptr<Pgsql::Result>);
#endif // ASYNCDBCONNECTION_H

View file

@ -7,7 +7,6 @@ ParamListModel::ParamListModel(QObject *parent)
QVariant ParamListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
// FIXME: Implement me!
QVariant result;
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) {
@ -56,7 +55,7 @@ QVariant ParamListModel::data(const QModelIndex &index, int role) const
if (index.isValid()) {
int row = index.row();
int col = index.column();
if (role == Qt::DisplayRole) {
if (role == Qt::DisplayRole || role == Qt::EditRole) {
const auto& record = m_paramList[row];
switch (col) {
case ColValue: // value column

View file

@ -3,12 +3,13 @@
#include <QString>
class PgClass;
class PgConstraint;
class PgDatabaseCatalog;
bool identNeedsQuotes(QString ident);
QString genFQTableName(const PgDatabaseCatalog &catalog, const PgClass &cls);
QString getDropConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint);
QString getConstraintDefinition(const PgDatabaseCatalog &catalog, const PgConstraint &constraint);