Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+80
View File
@@ -0,0 +1,80 @@
#include "AddLine.h"
#include "ui_AddLinesUi.h"
#include <QDebug>
AddLines::AddLines(QWidget* parent)
: QDialog(parent)
, m_ui(new Ui::AddLines)
{
qRegisterMetaType<AddModel*>("AddModel*");
m_ui->setupUi(this);
m_ui->dataView->setModel(&addModel);
connect(m_ui->pbDone, &QPushButton::clicked,
this, &AddLines::slotAddLines);
connect(m_ui->pbAbort, &QPushButton::clicked,
this, &AddLines::close);
connect(m_ui->pbDelete, &QPushButton::clicked,
this, &AddLines::slotDeleteLines);
connect(m_ui->pbClear, &QPushButton::clicked,
this, &AddLines::slotClear);
}
AddLines::~AddLines()
{
delete m_ui;
}
void AddLines::slotDeleteLines()
{
//qWarning() << "slotDeleteLines";
while (m_ui->dataView->selectionModel()->selectedRows().count())
{
const QModelIndexList selectedRows = m_ui->dataView->selectionModel()->selectedRows();
if (selectedRows.at(0).row() == addModel.rowCount()-1) // do not delete empty row!
{
return; // In hope that the selectedRows list is sorted.....
}
addModel.removeRow(selectedRows.at(0).row());
}
}
void AddLines::slotClear()
{
//qWarning() << "slotClear";
addModel.clear();
}
void AddLines::reject()
{
emit signalAddLines(nullptr);
}
void AddLines::copyDataFromModel(DataModel* dataModel)
{
addModel.setHeaderList(dataModel->getHeaderList());
addModel.setTablename(dataModel->getTableName());
}
void AddLines::slotAddLines()
{
this->hide(); // hide until in work..
emit signalAddLines(&addModel);
}
+37
View File
@@ -0,0 +1,37 @@
#pragma once
#include "AddModel.h"
#include <QDialog>
namespace Ui
{
class AddLines;
}
class AddLines : public QDialog
{
Q_OBJECT
public:
explicit AddLines(QWidget *parent = nullptr);
~AddLines();
void copyDataFromModel(DataModel* dataModel);
protected:
void reject();
private:
Ui::AddLines* m_ui;
AddModel addModel;
private slots:
void slotAddLines();
void slotDeleteLines();
void slotClear();
signals:
void signalAddLines(AddModel*);
};
+152
View File
@@ -0,0 +1,152 @@
#include "AddModel.h"
#include <QDebug>
void AddModel::setHeaderList(const HeaderList& headerList)
{
m_headerList = headerList;
beginResetModel();
endResetModel();
}
const HeaderList& AddModel::getHeaderList() const
{
return m_headerList;
}
bool AddModel::removeRow(int row, const QModelIndex &parent)
{
//qWarning() << "removeRow";
(void)parent;
if (row >= m_dataList.count())
{
//qWarning() << "removeRows false";
return false;
}
beginRemoveRows(parent, row, row);
m_dataList.removeAt(row);
endRemoveRows();
return true;
}
void AddModel::clear()
{
beginResetModel();
m_dataList.clear();
endResetModel();
}
QVariant AddModel::data(const QModelIndex &index, int role) const
{
switch (role)
{
case Qt::EditRole:
case Qt::DisplayRole:
{
if (index.row() >= m_dataList.count())
{
return QVariant(); // probably the new line was not added yet (use setData the first time to create it)
}
return m_dataList.at(index.row()).at(index.column());
}
}
return QVariant();
}
bool AddModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::EditRole)
{
return false;
}
if (index.row() >= m_dataList.count()) // no row in dataList?
{
Data newData; // create new row
int headerListCount = m_headerList.count();
newData.reserve(headerListCount);
for (int i = 0; i < headerListCount; i++) // preadd empty columns
{
newData.append(QString());
}
m_dataList.append(newData); // finally add new line to dataList
}
Data data = m_dataList.at(index.row()); // get old row
data.replace(index.column(), value.toString()); // replace column in row
m_dataList.replace(index.row(), data); // finally replace row in dataList
beginResetModel();
endResetModel(); // tell the model to show the new empty line
return true;
}
QVariant::Type AddModel::getColumnType(const int column) const
{
if (column < 0 || column >= m_headerList.size())
return QVariant::Invalid;
return m_headerList.at(column).second;
}
QVariant AddModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation != Qt::Horizontal)
return QVariant();
switch (role)
{
case Qt::DisplayRole:
{
return m_headerList.at(section).first;
}
}
return QVariant();
}
int AddModel::rowCount(const QModelIndex &) const
{
return m_dataList.count() + 1 /* empty row for new data */; // yes, if the user wants to add more than 1 line!
}
int AddModel::columnCount(const QModelIndex &) const
{
return m_headerList.count();
}
Qt::ItemFlags AddModel::flags(const QModelIndex &) const
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable;
}
void AddModel::setTablename(const QString& tableName)
{
m_tableName = tableName;
}
const QString& AddModel::getTableName() const
{
return m_tableName;
}
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <QAbstractTableModel>
#include "DataModel.h"
class AddModel : public QAbstractTableModel
{
Q_OBJECT
public:
using QAbstractTableModel::QAbstractTableModel;
void setHeaderList(const HeaderList& headerList);
void setTablename(const QString& tableName);
const QString& getTableName() const;
QVariant::Type getColumnType(const int column) const;
const HeaderList& getHeaderList() const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool removeRow(int row, const QModelIndex &parent = QModelIndex());
void clear();
private:
HeaderList m_headerList;
DataList m_dataList;
QString m_tableName;
};
+251
View File
@@ -0,0 +1,251 @@
#include "ui_BrowserWndUi.h"
#include "BrowserWnd.h"
#include "LoginWnd.h"
#include "Query.h"
#include "DataModel.h"
#include "QueryThread.h"
#include <QDebug>
#include <QGraphicsDropShadowEffect>
#include <QListWidgetItem>
#include <QMessageBox>
#include <QRegExp>
#include <QShortcut>
#include <QThread>
BrowserWnd::BrowserWnd()
: QWidget(nullptr)
, m_loginWnd(new LoginWnd(this))
, m_waitWnd(new WaitWnd(this))
, m_ui(new Ui::BrowserWnd)
, m_queryWorker(new QueryWorker())
, m_queryThread(new QThread())
{
//setVersionView();
qRegisterMetaType<LoginData>("LoginData");
if (!test())
exit(1);
new QShortcut(QKeySequence(QStringLiteral("Ctrl+Q")), this, SLOT(close()));
connect(this, &BrowserWnd::signalConnect, m_queryWorker, &QueryWorker::slotConnectIt);
connect(m_queryWorker, &QueryWorker::signalConnectResult, this, &BrowserWnd::slotConnectResult);
connect(this, &BrowserWnd::signalGetTableList, m_queryWorker, &QueryWorker::slotGetTableList);
connect(m_queryWorker, &QueryWorker::signalNewTableList, this, &BrowserWnd::slotNewTableList);
m_queryWorker->moveToThread(m_queryThread);
m_queryThread->start();
}
BrowserWnd::~BrowserWnd()
{
endThread();
delete m_ui;
delete m_waitWnd;
delete m_loginWnd;
}
void BrowserWnd::slotAddNewQuery()
{
addNewQuery();
}
void BrowserWnd::slotConnectResult(const QString &result)
{
if (result.isEmpty()) // connection success!
{
// everything okay, logged in, go!
m_ui->setupUi(this);
// showing Host / DB name in window title
this->setWindowTitle(QStringLiteral("RDE SQL Browser on Database: ") + m_loginWnd->getLoginData().database);
m_ui->splitter->setStretchFactor(0, 0); // not stretch for table list
m_ui->splitter->setStretchFactor(1, 1); // stretch the query widget
this->show();
addNewQuery();
refreshTableList();
connect(m_ui->leFilter, &QLineEdit::textChanged, this, &BrowserWnd::slotFilterTableList);
connect(m_ui->lwTables, &QListWidget::itemDoubleClicked, this, &BrowserWnd::slotFilterTableItemChanged);
connect(m_ui->twQueries, &QTabWidget::tabCloseRequested, this, &BrowserWnd::slotTabCloseRequested);
connect(m_ui->pbNewQuery, &QPushButton::clicked, this, &BrowserWnd::slotAddNewQuery);
connect(m_ui->pushButton, &QPushButton::clicked, qApp, &QApplication::quit);
connect(m_ui->pushButton_2, &QPushButton::clicked, this, &BrowserWnd::slotHeart);
}
else // failed with message
{
QMessageBox::critical(this,
tr("Connection Error"),
tr("Cannot connect to specified server."
"\nError:"
"\n'%1'").arg(result));
}
m_waitWnd->hide();
}
void BrowserWnd::slotFilterTableList(const QString &)
{
refreshTableList();
}
void BrowserWnd::addNewQuery(const QString &tableName) // tableName only set when query from double clicking table list
{
Query *query = new Query(m_queryWorker);
connect(query, &Query::signalShowWait, this, &BrowserWnd::slotShowWait);
connect(query, &Query::signalHideWait, this, &BrowserWnd::slotHideWait);
int tabIndex = -1;
if (tableName.length()) // there is a tablename
{
query->setTable(tableName);
tabIndex = m_ui->twQueries->addTab(query, tableName);
}
else // no tablename
tabIndex = m_ui->twQueries->addTab(query, QStringLiteral("Query %1").arg(m_newQueryCounter++));
m_ui->twQueries->setCurrentIndex(tabIndex);
}
//#warning TODO: reimpl
//void BrowserWnd::slotSelectQueryStatus(int percent)
//{
// m_waitWnd->setStatus(percent);
//}
void BrowserWnd::endThread()
{
if (!m_queryThread)
return;
m_queryWorker->dy();
m_queryThread->quit();
m_queryThread->wait();
delete m_queryThread;
m_queryThread = nullptr;
delete m_queryWorker;
m_queryWorker = nullptr;
}
void BrowserWnd::refreshTableList()
{
m_ui->lwTables->clear();
m_waitWnd->wait(QStringLiteral("Refreshing Table List .."));
emit signalGetTableList();
}
void BrowserWnd::slotNewTableList(QStringList tables)
{
if (!m_ui->leFilter->text().isEmpty()) // filter when there is a filter
{
QRegExp regExp(m_ui->leFilter->text(), Qt::CaseInsensitive, QRegExp::Wildcard);
tables = tables.filter(regExp);
}
m_ui->lwTables->addItems(tables);
m_waitWnd->hide();
}
void BrowserWnd::startConnect()
{
//m_loginWnd->setDefaultLoginData(presetManager. defaultLoginData);
if (!m_loginWnd->exec()) // false = user reject
{
QCoreApplication::quit();
return;
}
m_waitWnd->wait(tr("Connecting .."));
emit signalConnect(m_loginWnd->getLoginData());
}
bool BrowserWnd::test()
{
if (QSqlDatabase::drivers().isEmpty() ||
QSqlDatabase::drivers().indexOf(QLatin1String("QSQLITE")) == -1)
{
QMessageBox::critical(this,
tr("Missing Qt PostgreSQL driver"),
tr("There is no QPSQL driver."
"\nDid you install the package 'libQt5Sql5-postgresql'?"));
return false;
}
return true;
}
void BrowserWnd::slotFilterTableItemChanged(QListWidgetItem *item)
{
QString tableName = item->text();
addNewQuery(tableName);
}
void BrowserWnd::slotTabCloseRequested(int index)
{
Query *q = qobject_cast<Query *>(m_ui->twQueries->widget(index));
m_ui->twQueries->removeTab(index);
if (!q)
QMessageBox::critical(this, QStringLiteral("Query Failed"), QStringLiteral("Woops..?!!"));
delete q; // It´s safe to delete nullptr;
}
void BrowserWnd::slotShowWait(const QString &msg)
{
m_waitWnd->wait(msg);
}
void BrowserWnd::slotHideWait()
{
m_waitWnd->hide();
}
void BrowserWnd::slotHeart()
{
QWidget *w = new QWidget;
w->setAttribute(Qt::WA_DeleteOnClose); // delete when closed
QVBoxLayout *b = new QVBoxLayout;
QLabel *l = new QLabel(QStringLiteral("<html><body>Geschmiedet mit %1 , ohne Kostenträger, für das Team.<br>Diese Software wurde in meiner Freizeit entwickelt, bitte habt Verständnis für Bugs und Geduld für Fixes. Danke! - Euer Mike Wille, SLSE 2016, 17</body></html>").arg(QChar(0x2764)));
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
shadow->setOffset(0, 0);
shadow->setBlurRadius(22);
shadow->setColor(QColor("blue"));
l->setGraphicsEffect(shadow);
b->addWidget(l);
w->setLayout(b);
w->show();
}
+68
View File
@@ -0,0 +1,68 @@
#pragma once
#include "LoginWnd.h"
#include "WaitWnd.h"
#include "QueryThread.h"
#include <QWidget>
class QListWidgetItem;
class Query;
namespace Ui
{
class BrowserWnd;
}
class BrowserWnd: public QWidget
{
Q_OBJECT
public:
BrowserWnd();
~BrowserWnd();
/** Must be called *after* the event loop was started, i.e. use QTimer::singleShot(). */
void startConnect();
private:
bool test();
void endThread();
void refreshTableList();
void selectQuery(QString queryString, Query *query, QString tableName);
void addNewQuery(const QString &tableName = QString());
LoginWnd *m_loginWnd{nullptr};
WaitWnd *m_waitWnd{nullptr};
Ui::BrowserWnd *m_ui{nullptr};
QueryWorker *m_queryWorker{nullptr};
QThread *m_queryThread{nullptr};
Query *m_waitingQueryWidget{nullptr};
int m_newQueryCounter{0};
private slots:
void slotFilterTableList(const QString &filter);
void slotFilterTableItemChanged(QListWidgetItem *item);
void slotConnectResult(const QString &);
void slotNewTableList(QStringList);
void slotHeart();
/*void slotSelectQueryResult(QString errorMsg, DataModel* dataModel);
void slotSelectQueryStatus(int percent);
void slotQueryQuery(QString); // when the query widget starts a query....*/
void slotTabCloseRequested(int);
/*void slotExecute(QString, QVariant, QModelIndex);
void slotExecuteQueryResult(bool success, QString msg, QVariant val, QModelIndex onThisPosition);*/
void slotAddNewQuery();
void slotShowWait(const QString &msg);
void slotHideWait();
signals:
void signalConnect(const LoginData &data);
void signalGetTableList();
};
+50
View File
@@ -0,0 +1,50 @@
#
# CMakeLists.txt for New SQL Browser
#
# $Id$
# $HeadURL$
# $Author$
# Created by Mike Wille, SLSE, 2016-02-10
#
SET(my_SRCS
main.cpp
LoginWnd.cpp
LoginWnd.h
BrowserWnd.cpp
BrowserWnd.h
WaitWnd.cpp
WaitWnd.h
Query.cpp
Query.h
QueryThread.cpp
QueryThread.h
DataModel.cpp
DataModel.h
PresetManager.cpp
PresetManager.h
AddModel.cpp
AddModel.h
AddLine.cpp
AddLine.h
)
SET(my_UICS
ui/LoginUi.ui
ui/BrowserWndUi.ui
ui/WaitWndUi.ui
ui/QueryUi.ui
ui/AddLinesUi.ui
)
NGL_ADD_TOOL_ICON(my_SRCS "sql")
NGL_WRAP_UI(my_SRCS ${my_UICS})
NGL_ADD_EXECUTABLE(AAR SV WS NO_TRANSLATION sqlbrowser ${my_SRCS} ${my_UICS})
NGL_TARGET_LINK_LIBRARIES(sqlbrowser
PUBLIC
nglapplication
Qt5::Core
Qt5::Widgets
Qt5::Sql
)
NGL_INSTALL_TARGET(sqlbrowser)
+217
View File
@@ -0,0 +1,217 @@
#include "DataModel.h"
#include <QDebug>
#include <QColor>
#include <QDateTime>
#include <QMetaEnum>
#include <QMetaObject>
#include <QMetaType>
//#define WAIT_FOR_IDLE while (!m_idle) { QThread::msleep(50); } (void)m_idle
DataModel::DataModel(QObject *parent) // [M]VC
: QAbstractTableModel(parent)
, m_idle(true)
{
resetFlags();
}
//void DataModel::fillModel(const HeaderList &headerList, const DataList &dataList)
//{
// beginResetModel();
// m_headerList = headerList;
// m_dataList = dataList;
// endResetModel();
//}
void DataModel::dataListReserve(const int size)
{
m_newDataList.reserve(size);
}
void DataModel::addLine(const Data& data)
{
m_newDataList.append(data);
}
void DataModel::addColumn(const QString& columnName, QVariant::Type type)
{
// QPair<QString,QVariant::Type> pair;
// pair.first = columnName;
// pair.second = type;
m_newHeaderList.append(QPair<QString,QVariant::Type>(columnName, type));
}
void DataModel::slotSwapLists() // for threading..
{
m_dataList = m_newDataList;
m_headerList = m_newHeaderList;
m_newDataList.clear();
m_newHeaderList.clear();
beginResetModel();
endResetModel();
}
void DataModel::setTableName(const QString &tableName)
{
m_tableName = tableName;
setEditable(!m_tableName.isEmpty()); // editable items depend on wether it's a custom query, or a table list query
}
QString DataModel::getTableName() const
{
return m_tableName;
}
int DataModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_dataList.count();
}
int DataModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : m_headerList.count();
}
QVariant DataModel::data(const QModelIndex &index, int role) const
{
if (index.row() >= m_dataList.count())
{
//qWarning() << "threading problems.. #1";
return QVariant();
}
const Data& row = m_dataList.at(index.row());
if (index.column() >= row.count())
{
//qWarning() << "threading problems.. #2";
return QVariant();
}
const QVariant& element = row.at(index.column());
switch (role)
{
case Qt::EditRole:
case Qt::DisplayRole:
return element;
case Qt::BackgroundRole:
if (element.isNull())
return QColor::fromRgb(255, 255, 215);
return QVariant();
case Qt::ToolTipRole:
if ((element.type() == QVariant::ULongLong || element.type() == QVariant::LongLong)
&& element.toLongLong() > 1000000000)
return QDateTime::fromMSecsSinceEpoch(element.toLongLong()).toString(QStringLiteral("dd.MM.yyyy hh:mm:ss.zzz"));
break;
}
return QVariant();
}
QVariant DataModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && section >= 0 && section < m_headerList.size())
{
switch (role)
{
case Qt::DisplayRole:
return m_headerList.at(section).first;
case Qt::ToolTipRole:
int type = m_headerList.at(section).second;
return QString::fromUtf8(QMetaType::typeName(type));
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
void DataModel::setEditable(bool editable)
{
resetFlags();
if (editable)
m_flags |= Qt::ItemIsEditable;
}
const HeaderList& DataModel::getHeaderList() const
{
return m_headerList;
}
void DataModel::resetFlags()
{
m_flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
Qt::ItemFlags DataModel::flags(const QModelIndex &index) const
{
Q_UNUSED(index);
return m_flags;
}
void DataModel::slotSetData(const QModelIndex &index, const QVariant &value)
{
Data row = m_dataList.at(index.row()); // get row from data list
row.replace(index.column(), value); // replace column in row
m_dataList.replace(index.row(), row); // replace row in data list
emit dataChanged(index, index); // tell the view that data has changed and redraw/reget data
}
bool DataModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::EditRole)
return true;
// DataModel* => model to write value to on success
// QModelIndex => row&col of value to write
// QVariant => value to write
emit signalSetData(this, index, value);
return false; // ALWAYS! as we need to wait for a result (which is async)
}
void DataModel::deleteLines(const QList<QModelIndex> &affectedRowsList)
{
if (affectedRowsList.isEmpty())
{
//qWarning() << "DataModel::deleteLines: !affectedRowsList->count()";
return;
}
for (int i = 0; i < affectedRowsList.count(); i++)
{
const QModelIndex &idx = affectedRowsList.at(i);
beginRemoveRows(QModelIndex() /* FIXME: ??? */, idx.row(), idx.row());
m_dataList.removeAt(idx.row() /* TODO: checks ?? */);
endRemoveRows();
}
}
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <QAbstractTableModel>
using Data = QVector<QVariant>;
using DataList = QVector<Data>;
using HeaderList = QVector<QPair<QString, QVariant::Type>>;
class DataModel: public QAbstractTableModel
{
Q_OBJECT
public:
explicit DataModel(QObject* parent = nullptr);
//void fillModel(const HeaderList &headerList, const DataList &dataList);
void dataListReserve(const int size);
void addLine(const Data& data);
void addColumn(const QString& columnName, QVariant::Type type);
const HeaderList& getHeaderList() const;
void setTableName(const QString& tableName);
QString getTableName() const;
void setEditable(bool editable);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
void deleteLines(const QList<QModelIndex> &affectedRowsList);
private:
HeaderList m_headerList;
DataList m_dataList;
// Threading...
HeaderList m_newHeaderList;
DataList m_newDataList;
QString m_tableName;
Qt::ItemFlags m_flags;
QAtomicInt m_idle;
void resetFlags();
public slots:
void slotSwapLists();
void slotSetData(const QModelIndex &index, const QVariant &value);
signals:
void signalSetData(DataModel*, const QModelIndex &, const QVariant &);
};
+161
View File
@@ -0,0 +1,161 @@
#include "LoginWnd.h"
#include "ui_LoginUi.h"
#include <QGraphicsDropShadowEffect>
#include <QFileDialog>
#include <QDebug>
#include <QSqlDatabase>
LoginWnd::LoginWnd(QWidget *parent)
: QDialog(parent)
, m_ui(new Ui::LoginWnd)
{
m_ui->setupUi(this);
connect(m_ui->pbHeart, &QPushButton::clicked,
this, &LoginWnd::slotHeart);
// SQLite:
connect(m_ui->pbLoadFile, &QPushButton::clicked, this, &LoginWnd::slotLoadFile);
connect(m_ui->tbChooseFile, &QToolButton::clicked, this, &LoginWnd::slotChooseFile);
connect(m_ui->pbExit_2, &QPushButton::clicked, this, &LoginWnd::reject);
// DBMS:
connect(m_ui->pbLogin, &QPushButton::clicked, this, &LoginWnd::accept);
connect(m_ui->pbExit, &QPushButton::clicked, this, &LoginWnd::reject);
// Common:
connect(m_ui->pbLoad, &QPushButton::clicked, this, &LoginWnd::slotLoadPreset);
connect(m_ui->pbSave, &QPushButton::clicked, this, &LoginWnd::slotSavePreset);
fillPresetComboBox();
// set typical values
m_ui->leDatabase->setText(QStringLiteral("lts_ets_pro"));
m_ui->leUsername->setText(QStringLiteral("ets_exm"));
m_ui->leHostname->setPlaceholderText(QStringLiteral("on-site: try 'EXCDBS01'"));
m_ui->cbDriver->addItems(QSqlDatabase::drivers());
const int idx = m_ui->cbDriver->findText(QStringLiteral("QPSQL"));
if (idx >= 0)
m_ui->cbDriver->setCurrentIndex(idx);
}
LoginWnd::~LoginWnd()
{
delete m_ui;
}
void LoginWnd::slotLoadFile()
{
if (m_ui->leFilename->text().isEmpty())
return;
accept(); // just to make clear that the user cannot login to a database, so he has to click explicitly on "Load File"
}
void LoginWnd::slotChooseFile()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Select File-based Database"),
QString(), // last wd
tr("All Files (*.*)"));
if (fileName.isEmpty())
return;
m_ui->leFilename->setText(fileName);
}
void LoginWnd::fillPresetComboBox()
{
m_ui->cbPresets->clear();
const PresetManager::PresetList &presetList = presetManager.getPresetList();
for (const Preset &preset : qAsConst(presetList))
m_ui->cbPresets->addItem(preset.name);
if (!presetList.isEmpty())
{
setDefaultLoginData(presetList.first().loginData);
m_ui->cbPresets->setCurrentIndex(0);
}
}
void LoginWnd::slotLoadPreset()
{
setDefaultLoginData(presetManager.getPresetList().at(m_ui->cbPresets->currentIndex()).loginData);
}
void LoginWnd::slotSavePreset()
{
presetManager.savePreset(getLoginData(), this);
fillPresetComboBox();
setDefaultLoginData(presetManager.getPresetList().at(m_ui->cbPresets->count()-1).loginData); // set default to last (new) preset
m_ui->cbPresets->setCurrentIndex(m_ui->cbPresets->count()-1); // set index to last (new) preset
}
void LoginWnd::setDefaultLoginData(const LoginData &defaultLoginData)
{
if (!defaultLoginData.filename.isEmpty()) // no username, etc needed if that's a file
{
m_ui->leFilename->setText(defaultLoginData.filename);
m_ui->leDatabase->setText(QString());
m_ui->leUsername->setText(QString());
m_ui->lePassword->setText(QString());
m_ui->leHostname->setText(QString());
m_ui->sbPort->setValue(-1);
}
else
{
m_ui->leFilename->setText(QString());
m_ui->leDatabase->setText(defaultLoginData.database);
m_ui->leUsername->setText(defaultLoginData.username);
m_ui->lePassword->setText(defaultLoginData.password);
m_ui->leHostname->setText(defaultLoginData.hostname);
m_ui->cbDriver->setCurrentIndex(m_ui->cbDriver->findText(defaultLoginData.driver));
m_ui->sbPort->setValue(defaultLoginData.port);
}
}
LoginData LoginWnd::getLoginData() const
{
LoginData ld;
ld.driver = m_ui->cbDriver->currentText();
ld.database = m_ui->leDatabase->text();
ld.username = m_ui->leUsername->text();
ld.password = m_ui->lePassword->text();
ld.hostname = m_ui->leHostname->text();
ld.port = m_ui->sbPort->value();
ld.filename = m_ui->leFilename->text();
return ld;
}
void LoginWnd::slotHeart()
{
QWidget* w = new QWidget;
w->setAttribute(Qt::WA_DeleteOnClose); // delete when closed
QVBoxLayout* b = new QVBoxLayout;
QLabel* l = new QLabel(QStringLiteral("<html><body>Geschmiedet mit %1 , ohne Kostenträger, für das Team.<br>Diese Software wurde in meiner Freizeit entwickelt, bitte habt Verständnis für Bugs und Geduld für Fixes. Danke! - Euer Mike Wille, SLSE 2016, 17</body></html>").arg(QChar(0x2764)));
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
shadow->setOffset(0,0);
shadow->setBlurRadius(22);
shadow->setColor(QColor("blue"));
l->setGraphicsEffect(shadow);
b->addWidget(l);
w->setLayout(b);
w->show();
}
+35
View File
@@ -0,0 +1,35 @@
#pragma once
#include "PresetManager.h"
#include <QDialog>
namespace Ui
{
class LoginWnd;
}
class LoginWnd : public QDialog
{
Q_OBJECT
public:
explicit LoginWnd(QWidget *parent);
~LoginWnd();
LoginData getLoginData() const;
void setDefaultLoginData(const LoginData &defaultLoginData);
private:
Ui::LoginWnd* m_ui;
PresetManager presetManager;
void fillPresetComboBox();
private slots:
void slotLoadFile();
void slotChooseFile();
void slotHeart();
void slotLoadPreset();
void slotSavePreset();
};
+187
View File
@@ -0,0 +1,187 @@
#include "PresetManager.h"
#include <QInputDialog>
#include <QApplication>
#include <QDebug>
#ifdef Q_OS_WIN
static QString newLine(QStringLiteral("\r\n"));
#else
static QString newLine(QStringLiteral("\n"));
#endif
PresetManager::PresetManager()
: QObject()
{
QString filename(QStringLiteral("%1.conf").arg(QApplication::arguments().at(0)));
file.setFileName(filename);
bool goCreateFile = false;
if (!file.exists())
{
goCreateFile = true;
}
if (!file.open(QIODevice::ReadWrite))
{
//qWarning() << "cannot read/write conf file! ("<<filename<<")";
return;
}
if (goCreateFile)
{
addDefaultPreset();
createFile();
savePresets(); // add default preset to new file
}
// read file...
QString presetString(QString::fromUtf8(file.readLine(32000)));
while (!presetString.isEmpty())
{
if (presetString.endsWith(newLine))
{
presetString.truncate(presetString.length() - newLine.length());
}
if (presetString.at(0) == QLatin1Char('#')) // allow comments
{
//qWarning() << "line is comment line! next line..";
presetString = QString::fromUtf8(file.readLine(32000));
continue;
}
QStringList presetStringList = presetString.split(QStringLiteral(":"));
if (presetStringList.count() != 2)
{
//qWarning() << "line ded! next line..";
presetString = QString::fromUtf8(file.readLine(32000));
continue;
}
Preset preset;
preset.name = presetStringList.at(0);
QStringList presetValueList = presetStringList.at(1).split(QStringLiteral(","));
if (presetValueList.count() < 5) // port is optional, as there is a default port !!
{
//qWarning() << "too few valz! next line..";
presetString = QString::fromUtf8(file.readLine(32000));
continue;
}
preset.loginData.database = presetValueList.at(0);
preset.loginData.username = presetValueList.at(1);
preset.loginData.password = presetValueList.at(2);
preset.loginData.hostname = presetValueList.at(3);
preset.loginData.driver = presetValueList.at(4);
if (presetValueList.count() > 5) // is there a port?
preset.loginData.port = presetValueList.at(5).toInt();
// keep compatibility
if (presetValueList.count() > 6) // is there a filename?
preset.loginData.filename = presetValueList.at(6);
presetList.append(preset);
presetString = QString::fromUtf8(file.readLine(32000));
}
}
const PresetManager::PresetList &PresetManager::getPresetList() const
{
return presetList;
}
void PresetManager::savePreset(const LoginData &loginData, QWidget* parent)
{
bool ok;
QString presetName = QInputDialog::getText(parent, tr("Save new Preset as.."),
tr("Preset name:"), QLineEdit::Normal,
QString(), &ok);
if (!ok || presetName.isEmpty())
{
//qWarning() << "doin nothin";
return;
}
for (int i = 0; i < presetList.size(); ++i)
{
if (presetList.at(i).name == presetName)
{
presetList.removeAt(i);
break;
}
}
Preset preset;
preset.name = presetName;
preset.loginData = loginData;
presetList.append(preset);
savePresets();
}
void PresetManager::savePresets()
{
createFile(); // recreate file
// save all presets to file
for (const Preset &preset : qAsConst(presetList))
{
QString presetString = QStringLiteral("%1:%2%3");
QStringList presetValueList;
presetValueList << preset.loginData.database;
presetValueList << preset.loginData.username;
presetValueList << preset.loginData.password;
presetValueList << preset.loginData.hostname;
presetValueList << preset.loginData.driver;
if (preset.loginData.port > -1)
presetValueList << QString::number(preset.loginData.port);
if (!preset.loginData.filename.isEmpty())
presetValueList << preset.loginData.filename;
presetString = presetString.arg(preset.name, presetValueList.join(QLatin1Char(',')), newLine);
file.write(presetString.toUtf8());
}
file.flush();
}
void PresetManager::addDefaultPreset()
{
Preset defaultPreset;
//defaultPreset.loginData.database = Settings::databaseName();
defaultPreset.loginData.driver = QStringLiteral("PQSQL");
defaultPreset.name = defaultPreset.loginData.database;
defaultPreset.loginData.username = QStringLiteral("ctc_ws");
defaultPreset.loginData.password = QStringLiteral("ctc11de");
//defaultPreset.loginData.hostname = Settings::databaseHostname();
defaultPreset.loginData.port = -1;
// no need to set filename
presetList.insert(0, defaultPreset); // first item!
}
void PresetManager::createFile()
{
file.resize(0); // clear file
file.flush();
file.write("#<PresetName>:<database><,username><,password><,hostname><,port(optional)><,filename(optional)>");
file.write(newLine.toUtf8());
file.flush();
}
+43
View File
@@ -0,0 +1,43 @@
#pragma once
#include <QFile>
#include <QVector>
struct LoginData
{
QString database;
QString username;
QString password;
QString hostname;
QString filename;
QString driver;
int port = - 1; // no unsigned short (must contain -1 as default port)
};
struct Preset
{
QString name;
LoginData loginData;
};
class PresetManager : public QObject
{
Q_OBJECT
public:
using PresetList = QVector<Preset>;
PresetManager();
const PresetList &getPresetList() const;
void savePreset(const LoginData &loginData, QWidget *parent);
private:
QFile file;
PresetList presetList;
void createFile();
void savePresets();
void addDefaultPreset();
};
+474
View File
@@ -0,0 +1,474 @@
#include "ui_QueryUi.h"
#include "Query.h"
#include "QueryThread.h"
#include "AddLine.h"
#include <QMessageBox>
#include <QFileDialog>
#include <QCheckBox>
#include <QRadioButton>
#include <QDebug>
#ifdef Q_OS_WIN
#define NEWLINE "\r\n"
#else
#define NEWLINE "\n"
#endif
Query::Query(//const QString &queryString,
QueryWorker *queryWorker,
QWidget* parent) // MV[C]
: QWidget(parent)
, m_ui(new Ui::Query)
, m_model(new DataModel())
, m_queryWorker(queryWorker)
, m_addLines(nullptr)
{
m_ui->setupUi(this);
setCustomQuery(); // for safety, disable table sensitive buttons, until table name is set
qRegisterMetaType<QList<QModelIndex>>("QList<QModelIndex>");
connect(m_ui->pbQueryDelete, &QPushButton::clicked, this, &Query::onQueryDelete);
connect(m_ui->pbQueryInsert, &QPushButton::clicked, this, &Query::onQueryInsert);
connect(m_ui->pbQueryUpdate, &QPushButton::clicked, this, &Query::onQueryUpdate);
// NEW ARCH
// Delete Lines
connect(this, &Query::signalDeleteLines,
queryWorker, &QueryWorker::slotDeleteLines); // request => QueryWorker
connect(queryWorker, &QueryWorker::signalDeleteLinesResult,
this, &Query::slotDeleteLinesResult); // reply => this
// Custom Query
connect(this, &Query::signalCustomQuery,
queryWorker, &QueryWorker::slotCustomQuery);
connect(queryWorker, &QueryWorker::signalCustomQueryResult,
this, &Query::slotCustomQueryResult);
// Table Query
connect(this, &Query::signalTableQuery,
queryWorker, &QueryWorker::slotTableQuery);
connect(queryWorker, &QueryWorker::signalTableQueryResult,
this, &Query::slotTableQueryResult);
// Add Lines
connect(this, &Query::signalAddLines,
queryWorker, &QueryWorker::slotAddLines);
connect(queryWorker, &QueryWorker::signalAddLinesResult,
this, &Query::slotAddLinesResult);
// Set Data
connect(m_model, &DataModel::signalSetData, // comes from the model ..
this, &Query::slotSetData);
connect(this, &Query::signalSetData,
queryWorker, &QueryWorker::slotSetData);
connect(queryWorker, &QueryWorker::signalSetDataResult, // .. and comes back to THIS ! (query)
this, &Query::slotSetDataResult);
connect(m_ui->pbQuery, &QPushButton::clicked, this, &Query::slotCustomQuery);
connect(m_ui->pbAddLine, &QPushButton::clicked, this, &Query::slotStartAddLines);
connect(m_ui->pbDeleteLine, &QPushButton::clicked, this, &Query::slotDeleteLine);
connect(m_ui->pbReload, &QPushButton::clicked, this, &Query::slotTableQuery);
connect(m_ui->pbExport, &QPushButton::clicked, this, &Query::slotExportCSV);
m_ui->dataTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); // TODO: qt4
setModel();
}
Query::~Query()
{
delete m_ui;
delete m_model;
}
void Query::slotExportCSV()
{
//qWarning() << "slotExportCSV";
QFileDialog dialog(this); // save dialog
//dialog.setFileMode(QFileDialog::ExistingFile); // single file selection
dialog.setNameFilter(tr("CSV File (*.csv)"));
dialog.setAcceptMode(QFileDialog::AcceptSave);
QStringList fileNames;
if (dialog.exec())
fileNames = dialog.selectedFiles();
if (!fileNames.count())
{
return;
}
QFile file;
file.setFileName(fileNames.at(0));
if (!file.open(QFile::ReadWrite))
{
QMessageBox::critical(this, tr("CSV Export Error"), tr("File '%1' is not accessible!").arg(fileNames.at(0)));
return;
}
// file is open, now save to csv file
int colCount = m_model->columnCount();
// get column names
QStringList columnNames;
columnNames.reserve(colCount);
for (int i = 0; i < colCount; i++)
{
columnNames.append(m_model->headerData(i, Qt::Horizontal).toString());
}
// get rows & row values
QStringList rows;
int rowsCount = m_sortModel.rowCount();
rows.reserve(rowsCount);
QStringList rowData;
for (int row = 0; row < rowsCount; row++)
{
// get row's values
rowData.clear();
for (int col = 0; col < colCount; col++)
{
rowData.append(m_sortModel.data(m_sortModel.index(row, col)).toString());
}
rows.append(rowData.join(QLatin1Char(',')));
}
file.write(columnNames.join(QLatin1Char(',')).toUtf8()); // write header
file.write(NEWLINE);
for (const QString &row : qAsConst(rows))
{
file.write(row.toUtf8());
file.write(NEWLINE);
}
file.close();
QMessageBox::information(this, tr("CSV Export Success"), tr("CSV Export was successful"));
}
void Query::onQueryDelete()
{
m_ui->queryText->setText(tr("DELETE FROM %1 WHERE %2").arg(m_model->getTableName(), m_idInWhere ? QStringLiteral("id = ") : QString()));
}
void Query::onQueryInsert()
{
m_ui->queryText->setText(tr("INSERT INTO %1 (%2) VALUES ()").arg(m_model->getTableName(), checkedColumnsNames().join(QStringLiteral(", "))));
}
void Query::onQueryUpdate()
{
const QStringList sl = checkedColumnsNames();
QStringList sl2;
sl2.reserve(sl.size());
for (const QString &s : sl)
sl2.append(tr("%1 = ").arg(s));
m_ui->queryText->setText(tr("UPDATE %1 SET %2 WHERE %3").arg(m_model->getTableName(), sl2.join(QStringLiteral(", ")), m_idInWhere ? QStringLiteral("id = ") : QString()));
}
void Query::handleError(const QString &errorText)
{
emit signalHideWait();
if (errorText.isEmpty())
return; // nothing to handle
QMessageBox::critical(this, tr("Error while executing query"),
tr("There was an error executing the query:\n%1").arg(errorText));
}
// Delete Lines
void Query::slotDeleteLine() // called from UI
{
int result = QMessageBox::question(this, tr("SqlBrowser"),
tr("Do you really want to delete selected data?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (result == QMessageBox::No)
return;
emit signalShowWait(QStringLiteral("Deleting line(s).."));
const QModelIndexList unmapped = m_ui->dataTable->selectionModel()->selectedRows();
QModelIndexList mapped;
mapped.reserve(unmapped.size());
for (const auto &idx : unmapped)
mapped.append(m_sortModel.mapToSource(idx));
emit signalDeleteLines(this, mapped, m_model); // => QueryWorker
}
void Query::slotDeleteLinesResult(Query* caller, int affectedRowsCount, QString errorText, const QList<QModelIndex> &affectedRowsList) // => from QueryWorker
{
if (caller != this)
return;
if (errorText.isEmpty() && !affectedRowsCount) // no error but no rows affected?
{
errorText = tr("The row to be deleted could not be found - This is probably a type-conversion error! Please report that to Mike");
}
handleError(errorText);
//qWarning() << "Query::slotDeleteLinesResult: errorText = " << errorText << "affectedRowsCount = " << affectedRowsCount;
if (affectedRowsCount == affectedRowsList.count())
{
m_model->deleteLines(affectedRowsList); // tell the model to delete that rows (and tell the view about it)
}
}
// Custom Query
void Query::slotCustomQuery()
{
emit signalShowWait(QStringLiteral("Executing query.."));
emit signalCustomQuery(this, m_ui->queryText->document()->toPlainText(), m_model);
}
void Query::slotCustomQueryResult(Query* caller, const QString &errorText)
{
if (caller != this)
return;
setCustomQuery();
handleError(errorText);
//qWarning() << "Query::slotCustomQueryResult: errorText = " << errorText;
}
// Table Query
void Query::slotTableQuery()
{
emit signalShowWait(QStringLiteral("Getting table data .."));
//qWarning() << "Query: model" << m_model;
emit signalTableQuery(this, m_model);
}
void Query::slotTableQueryResult(Query* caller, const QString &errorText)
{
if (caller != this)
return;
handleError(errorText);
// Don't put it in twice
if (!m_checkboxes.isEmpty())
return;
for(const auto &item : m_model->getHeaderList())
{
QCheckBox *cb = new QCheckBox(item.first, this);
m_ui->checkboxes->addWidget(cb);
m_checkboxes << cb;
if (item.first.compare(QStringLiteral("id"), Qt::CaseInsensitive) != 0)
continue;
// Only for ID:
QRadioButton *rbwhere = new QRadioButton(tr("in WHERE"), this);
m_ui->checkboxes->addWidget(rbwhere);
QRadioButton *rbnormal = new QRadioButton(tr("normal"), this);
m_ui->checkboxes->addWidget(rbnormal);
rbnormal->setEnabled(cb->isChecked());
rbwhere->setEnabled(cb->isChecked());
connect(cb, &QCheckBox::toggled, rbwhere, &QRadioButton::setEnabled);
connect(cb, &QCheckBox::toggled, rbnormal, &QRadioButton::setEnabled);
connect(rbwhere, &QRadioButton::toggled, this, [this, rbwhere, cb] { m_idInWhere = rbwhere->isChecked() && cb->isChecked(); });
connect(cb, &QRadioButton::toggled, this, [this, rbwhere, cb] { m_idInWhere = rbwhere->isChecked() && cb->isChecked(); });
rbwhere->setChecked(true);
}
m_ui->checkboxes->addItem(new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
//qWarning() << "Query::slotTableQueryResult: errorText = " << errorText;
}
QStringList Query::checkedColumnsNames() const
{
QStringList sl;
for(const auto &cb : m_checkboxes)
{
if (cb->isChecked())
{
if ((cb->text().compare(QStringLiteral("id"), Qt::CaseInsensitive) == 0) && m_idInWhere)
continue;
sl << cb->text();
}
}
return sl;
}
// Add Lines
void Query::slotStartAddLines()
{
if (!m_addLines)
{
m_addLines = new AddLines(this);
connect(m_addLines, &AddLines::signalAddLines,
this, &Query::slotAddLines);
m_addLines->copyDataFromModel(m_model);
}
m_addLines->show();
}
void Query::slotAddLines(AddModel *model)
{
emit signalShowWait(QStringLiteral("Adding line(s).."));
emit signalAddLines(this, model);
}
void Query::slotAddLinesResult(Query* caller, int , const QString &errorText)
{
if (caller != this)
return;
handleError(errorText);
//qWarning() << "Query::slotAddLinesResult: affectedRows = " << affectedRows << "errorText = " << errorText;
if (errorText.isEmpty()) // no error
{
// if (affectedRows) // only get new data when something changed
// {
// emit signalTableQuery(m_model); // re-get table!
// }
m_addLines->deleteLater(); // done, close add lines window and delete it..
m_addLines = nullptr;
emit signalTableQuery(this, m_model); // get fresh data from db
}
else // error
{
if (!m_addLines) // FIXME: needed! but not logically needed ;) what's going on here?
{
//qWarning() << "Query::slotAddLinesResult: !m_addLines";
}
else
m_addLines->show(); // show again, error!
}
}
// Set Data
void Query::slotSetData(DataModel* model, const QModelIndex &index, const QVariant &val)
{
int result = QMessageBox::question(this, tr("SqlBrowser"),
tr("Do you really want to change the data?"),
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if (result == QMessageBox::No)
return;
emit signalShowWait(QStringLiteral("Setting data.."));
emit signalSetData(this, model, index, val);
}
void Query::slotSetDataResult(Query* caller, const QString &errorText)
{
if (caller != this)
return;
handleError(errorText);
//qWarning() << "Query::slotSetDataResult: errorText =" << errorText;
}
void Query::setTable(const QString &tableName)
{
emit signalShowWait(QStringLiteral("Updating value.."));
if (tableName.isEmpty())
{
//qWarning() << "Query::setTable: tableName.isEmpty()";
return;
}
m_model->setTableName(tableName);
setTableQuery();
slotTableQuery();
}
void Query::setModel()
{
m_sortModel.setSourceModel(m_model);
m_ui->dataTable->setModel(/*(QAbstractTableModel*)*/&m_sortModel);
}
void Query::setCustomQuery() // cannot add/delete/reload
{
m_ui->pbAddLine->setEnabled(false);
m_ui->pbDeleteLine->setEnabled(false);
m_ui->pbReload->setEnabled(false);
}
void Query::setTableQuery() // cannot add/delete/reload
{
m_ui->pbAddLine->setEnabled(true);
m_ui->pbDeleteLine->setEnabled(true);
m_ui->pbReload->setEnabled(true);
}
+105
View File
@@ -0,0 +1,105 @@
#pragma once
#include "DataModel.h"
#include "AddModel.h"
#include "AddLine.h"
#include <QWidget>
#include <QSortFilterProxyModel>
#include <QList>
#include <QSet>
#include <QModelIndex>
class QueryWorker;
class QCheckBox;
namespace Ui
{
class Query;
}
class Query: public QWidget
{
Q_OBJECT
public:
explicit Query(QueryWorker* queryWorker, QWidget *parent = nullptr);
~Query();
void setTable(const QString& tableName); // get's data from specified table and shows it in the data view
void setModel();
void refreshData(QVariant val, QModelIndex onThisPosition);
void handleError(const QString &errorText);
private:
Ui::Query* m_ui;
DataModel* m_model;
QSortFilterProxyModel m_sortModel;
QueryWorker* m_queryWorker;
AddLines* m_addLines; // need access to add lines for show/hide/close.....
QSet<QCheckBox *> m_checkboxes;
bool m_idInWhere;
void setCustomQuery(); // cannot add/delete/reload
void setTableQuery(); // can add/delete/reload
QStringList checkedColumnsNames() const;
signals:
void signalShowWait(const QString &msg);
void signalHideWait();
private slots:
void slotExportCSV();
void onQueryDelete();
void onQueryInsert();
void onQueryUpdate();
// new architecture
// Delete Line(s)
signals:
void signalDeleteLines(Query* caller, const QList<QModelIndex> &, DataModel*);
private slots:
void slotDeleteLine();
void slotDeleteLinesResult(Query* caller, int affectedRowsCount, QString errorText, const QList<QModelIndex> &affectedRowsList);
// Custom Query
signals:
void signalCustomQuery(Query* caller, const QString &, DataModel*);
private slots:
void slotCustomQuery();
void slotCustomQueryResult(Query* caller, const QString &errorText);
// Table Query
signals:
void signalTableQuery(Query* caller, DataModel*);
private slots:
void slotTableQuery();
void slotTableQueryResult(Query* caller, const QString &errorText);
// Add Line
signals:
void signalAddLines(Query* caller, AddModel*);
private slots:
void slotStartAddLines();
void slotAddLines(AddModel*);
void slotAddLinesResult(Query* caller, int affectedRows, const QString &errorText);
// Set Data
signals:
void signalSetData(Query* caller, DataModel *model, const QModelIndex &index, const QVariant &val);
private slots:
void slotSetData(DataModel* model, const QModelIndex &index, const QVariant &val);
void slotSetDataResult(Query* caller, const QString &errorText);
};
+510
View File
@@ -0,0 +1,510 @@
#include "QueryThread.h"
#include "DataModel.h"
#include "AddModel.h"
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlField>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QDebug>
// uncomment next line to unarm the delete method - delete method does actually not delete content
//#define UNARMED
const char browserName[] = "SQLBrowser";
const char driverName[] = "QSQLITE";
QueryWorker::QueryWorker()
: m_dy(false)
, m_idle(true)
{
//qWarning() << "QueryWorker";
//test.dummy();
}
QueryWorker::~QueryWorker()
{
//qWarning() << "~QueryWorker";
m_idle = true;
m_sqlDB.close();
//QSqlDatabase::removeDatabase(BROWSER_NAME);
}
void QueryWorker::slotGetTableList()
{
m_idle = false;
if (m_sqlDB.isOpen())
{
QStringList tables = m_sqlDB.tables();
tables.append(m_sqlDB.tables(QSql::Views));
tables.sort();
emit signalNewTableList(tables);
}
else
{
//qWarning() << "mep...";
}
m_idle = true;
}
void QueryWorker::slotConnectIt(const LoginData &loginData)
{
m_idle = false;
// SQLite
if (!loginData.filename.isEmpty())
{
m_sqlDB = QSqlDatabase::addDatabase(QLatin1String(driverName), QLatin1String(browserName));
m_sqlDB.setDatabaseName(loginData.filename);
}
else // DBMS
{
// CONNECT & TEST
m_sqlDB = QSqlDatabase::addDatabase(loginData.driver, QLatin1String(browserName));
m_sqlDB.setDatabaseName(loginData.database);
m_sqlDB.setHostName(loginData.hostname);
m_sqlDB.setPort(loginData.port);
m_sqlDB.setUserName(loginData.username);
m_sqlDB.setPassword(loginData.password);
}
if (!m_sqlDB.open())
{
emit signalConnectResult(m_sqlDB.lastError().text());
}
else
{
emit signalConnectResult(QString()); // connected!
}
m_idle = true;
}
void QueryWorker::slotDeleteLines(Query* caller, const QList<QModelIndex> &selectedRows, DataModel* dataModel)
{
m_idle = false;
if (dataModel->getTableName().isEmpty())
{
emit signalDeleteLinesResult(caller, 0, QStringLiteral("This is a custom query"), QList<QModelIndex>());
m_idle = true;
return;
}
QString deleteStatement(QStringLiteral("DELETE FROM %1 WHERE %2"));
if (!selectedRows.count())
{
emit signalDeleteLinesResult(caller, 0, QStringLiteral("No line(s) selected to delete"), QList<QModelIndex>());
m_idle = true;
return;
}
// DELETE FROM table_name WHERE (x1=1 AND x2=2) OR (x1=2 AND x=3)
QStringList rows; // (x1=1 AND x2=2) (x1=2 AND x2=3) - join with "AND" !
rows.reserve(selectedRows.size());
for (int rowIterator = 0; rowIterator < selectedRows.count(); rowIterator++)
{
QStringList whereStatements;
int columnCount = dataModel->columnCount();
whereStatements.reserve(columnCount);
int row = selectedRows.at(rowIterator).row();
//qWarning() << "row" << row;
for (int column = 0; column < columnCount; column++)
{
//qWarning() << "col" << column;
QVariant var = dataModel->data(dataModel->index(row, column), Qt::DisplayRole);
QString value = valueToSqlString(var.toString(), dataModel->getHeaderList(), column);
QStringList whereStatement;
whereStatement.reserve(2);
whereStatement.append(dataModel->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString()); // column name
whereStatement.append(value);
if (value == QStringLiteral("NULL"))
whereStatements.append(whereStatement.join(QStringLiteral(" IS "))); // >>> column_name = %value% <<<
else
whereStatements.append(whereStatement.join(QStringLiteral("="))); // >>> column_name IS NULL <<<
}
QString rowText(QStringLiteral("(%1)").arg(whereStatements.join(QStringLiteral(" AND "))));
rows.append(rowText); // >>> column_name1 = 'value1' AND column_name2 = 'value2' <<<
}
deleteStatement = deleteStatement.arg(dataModel->getTableName(), rows.join(QStringLiteral(" OR ")));
qWarning() << "OKAY! my statement = >>>" << deleteStatement;
int rowsAffected = -1;
emit signalDeleteLinesResult(caller, rowsAffected,
#ifdef UNARMED
QString(),
#else
executeQuery(&rowsAffected, deleteStatement),
#endif
selectedRows);
m_idle = true;
}
QString QueryWorker::selectQuery(const QString &queryString, DataModel* dataModel)
{
m_idle = false;
QString result;
QSqlQuery q(m_sqlDB);
if (q.exec(queryString) && !m_dy) // execute query first..
{
// header
//HeaderList headerList;
const auto record = q.record();
int querySize = q.size(); // aka rows
int recordCount = record.count(); // aka columns
int statusStep = querySize / 100;
int statusCurrent = 0; // NOT in percent! (maximum = querySize)
int statusPercent = 0; // 0 - 100
// TODO: let's ignore the pk autoincrement first...
//qWarning() << "primaryIndex" << m_sqlDB.primaryIndex(dataModel->getTableName());
//q.record().field(i).setAutoValue(true);
for (int i = 0; i < recordCount; i++)
{
dataModel->addColumn(record.fieldName(i), record.field(i).type());
if (m_dy) break;
}
// data
//DataList dataList;
dataModel->dataListReserve(querySize); // speedup
Data data;
data.reserve(recordCount);
while (q.next() && !m_dy)
{
if (statusCurrent >= statusStep)
{
statusPercent++;
statusCurrent = 0;
emit signalSelectQueryStatus(statusPercent);
}
statusCurrent++;
data.clear();
for (int i = 0; i < recordCount; i++)
data.append(q.value(i));
dataModel->addLine(data);
}
// done reading, create model
//DataModel* dataModel = 0;
if (!m_dy)
{
// resultHeaderList = headerList;
// resultDataList = dataList;
connect(this, &QueryWorker::signalSwapModelData,
dataModel, &DataModel::slotSwapLists);
emit signalSwapModelData(); // single shot.... for threading
disconnect(this, &QueryWorker::signalSwapModelData,
dataModel, &DataModel::slotSwapLists);
//qWarning() << "QueryThread: headerList.count()" << headerList->count();
//qWarning() << "QueryThread: dataList.count()" << dataList->count();
}
}
else // query failed
{
if (!m_dy) // only an error when not dying
{
result = /*
emit signalSelectQueryResult(*/q.lastError().text()/*, 0)*/; // TODO: respect qt4 return invalid pointer
}
}
m_idle = true;
return result;
}
void QueryWorker::slotSetData(Query* caller, DataModel* model, const QModelIndex &index, const QVariant &value)
{
// TODO: use executeQuery here!
m_idle = false;
QString queryString(QStringLiteral("UPDATE %1 SET %2=%3 WHERE %4"));
int row = index.row();
/* %1 */ QString tableName = model->getTableName();
if (tableName.isEmpty())
{
emit signalSetDataResult(caller, QStringLiteral("This is a custom query"));
m_idle = true;
return;
}
/* %2 */ QString columnToChange = model->headerData(index.column(), Qt::Horizontal).toString();
const HeaderList &headerList = model->getHeaderList();
/* %3 */ const QString &valueForColumn = valueToSqlString(value, headerList, index.column()); // cannot get from model, as setData retured FALSE, which resets the change
/* %4 */ QString allColumnValuesInRow;
QStringList allColumnValuesInRowList;
allColumnValuesInRowList.reserve(model->columnCount());
QString condition;
for (int i = 0; i < model->columnCount(); i++)
{
QString columnName = model->headerData(i, Qt::Horizontal).toString();
QString columnValue = valueToSqlString(model->data(model->index(row, i)).toString(), headerList, i);
// nur für Spalte mit Namen 'id'
if (columnName.compare(QStringLiteral("id"), Qt::CaseInsensitive) == 0)
condition = QStringLiteral("%1=%2").arg(columnName, columnValue);
QString statement(QStringLiteral("%1=%2").arg(columnName, columnValue));
if (model->data(model->index(row, i)).isNull())
statement = QStringLiteral("%1 IS NULL").arg(columnName);
allColumnValuesInRowList.append(statement);
}
allColumnValuesInRow = allColumnValuesInRowList.join(QStringLiteral(" AND "));
if (condition.isEmpty())
condition = allColumnValuesInRow;
queryString = queryString.arg(tableName, columnToChange, valueForColumn, condition);
// qCritical() << "queryString =" << queryString;
QSqlQuery q(m_sqlDB);
if (q.exec(queryString) && !m_dy) // execute set data query
{
// worked? then change value in model
// signalSetDataResult(caller, QStringLiteral("Num affected rows: %1").arg(q.numRowsAffected()));
auto con = connect(this, &QueryWorker::signalSetDataInModel,
model, &DataModel::slotSetData);
if (value.toString().isEmpty())
emit signalSetDataInModel(index, QVariant()); // single shot.... for threading
else
emit signalSetDataInModel(index, value); // single shot.... for threading
disconnect(con);
emit signalSetDataResult(caller, QString()); // empty string = success
}
else
{
emit signalSetDataResult(caller, q.lastError().text()); // error
}
m_idle = true;
}
void QueryWorker::slotTableQuery(Query* caller, DataModel *model)
{
// no need to unidle here, as selectQuery does it!
//qWarning() << "QueryWorker: model" << model;
if (model->getTableName().isEmpty())
{
emit signalTableQueryResult(caller, QStringLiteral("This is a custom query"));
return;
}
QString queryString(QStringLiteral("SELECT * FROM %1").arg(model->getTableName()));
emit signalTableQueryResult(caller, selectQuery(queryString, model));
}
void QueryWorker::slotCustomQuery(Query* caller, const QString &queryString, DataModel *model)
{
// no need to unidle here, as selectQuery does it!
model->setTableName(QString()); // set empty table name, as this is not a table query anymore!
emit signalCustomQueryResult(caller, selectQuery(queryString, model));
}
void QueryWorker::slotAddLines(Query* caller, AddModel* addModel)
{
if (!addModel) // no lines to add
{
emit signalAddLinesResult(caller, 0, QString());
return;
}
// no need to unidle here, as executeQuery does it!
QString addQuery(QStringLiteral("INSERT INTO %1 VALUES %2"));
QStringList rows;
rows.reserve(addModel->rowCount());
for (int row = 0; row < addModel->rowCount() - 1 /* ignore empty add-line */; row++)
{
QStringList columns;
int columnCount = addModel->columnCount();
columns.reserve(columnCount);
for (int col = 0; col < columnCount; col++)
{
//qWarning() << "col" << col << "type" << addModel->getColumnType(col);
columns << valueToSqlString(addModel->data(addModel->index(row,col)), addModel->getHeaderList(), col);
////#warning implement IS NULL !
// if (addModel->getColumnType(col) == QVariant::Int) // get sql type
// {
// columns << addModel->data(addModel->index(row, col)).toString();
// }
// else // string
// {
// QString str = "'%1'";
// str = str.arg(addModel->data(addModel->index(row, col)).toString());
// columns << str;
// }
}
const QString rowString(QLatin1Char('(') + columns.join(QLatin1Char(',')) + QLatin1Char(')'));
rows << rowString;
}
addQuery = addQuery.arg(addModel->getTableName(), rows.join(QLatin1Char(',')));
int affectedRows = -1;
emit signalAddLinesResult(caller, affectedRows, executeQuery(&affectedRows, addQuery));
qWarning() << "OKAY! add query = " << addQuery;
}
//QString QueryWorker::valueFromSqlString(const QString& val, const HeaderList &headerList, const int col)
//{
// // value comes from sql database and must be made 'visual'
// QVariant::Type type = headerList.at(col).second; // get column type from model
// //qWarning() << "QueryWorker::variantToSqlString: type =" << type;
// if (val.isEmpty()) // if val is empty, return empty sql type "NULL"
// {
// return "NULL";
// }
// if (type == QVariant::String) // col is string type
// {
// return "'" + val + "'";
// }
// else // col is ANY int type
// {
// return val;
// }
//}
QString QueryWorker::valueToSqlString(const QVariant& val, const HeaderList &headerList, const int col)
{
// value must be converted to sql value
QVariant::Type type = headerList.at(col).second; // get column type from model
//qWarning() << "QueryWorker::valueToSqlString: val" << val << "type" << type << "("<<type<<")";
if (val.isNull() || val.toString().isEmpty()) // if val is empty, return empty sql type "NULL"
return QStringLiteral("NULL");
//if (type == QVariant::String) // col is string type
switch (type)
{
case QVariant::Int:
return QString::number(val.toInt());
case QVariant::UInt:
return QString::number(val.toUInt());
case QVariant::LongLong:
return QString::number(val.toLongLong());
case QVariant::ULongLong:
return QString::number(val.toULongLong());
case QVariant::Double:
return QString::number(val.toDouble());
default: // any other than numeric type
break;
}
return QStringLiteral("'%1'").arg(val.toString());
}
QString QueryWorker::executeQuery(int* affectedRows, const QString &queryString)
{
m_idle = false;
QString result;
QSqlQuery q(m_sqlDB);
if (q.exec(queryString))
{
qWarning() << "executeQuery: success: numRowsAffected" << q.numRowsAffected();
*affectedRows= q.numRowsAffected();
}
else // error
{
*affectedRows = 0;
result = q.lastError().text(); // error (no rows affected)
// if (result.isEmpty())
// {
// result = "UNKNOWN ERROR";
// }
}
m_idle = true;
return result;
}
+108
View File
@@ -0,0 +1,108 @@
#pragma once
#include "LoginWnd.h"
#include "DataModel.h"
#include "AddModel.h"
#include <QSqlDatabase>
#include <QList>
#include <QModelIndex>
class Query;
class QueryWorker: public QObject
{
Q_OBJECT
public:
explicit QueryWorker();
~QueryWorker();
void dy()
{
m_dy = true;
}
bool isIdle() const
{
return m_idle;
}
QAtomicInt m_dy;
QAtomicInt m_idle; // dunno how to solve this atm
private:
QSqlDatabase m_sqlDB;
QString selectQuery(const QString &queryString, DataModel *dataModel); //DataModel* model, )
QString executeQuery(int* affectedRows, const QString &queryString);
QString valueToSqlString(const QVariant &val, const HeaderList &headerList, const int col);
// NEW ARCH
// Delete Lines
public slots:
void slotDeleteLines(Query* caller, const QList<QModelIndex> &selectedRows, DataModel* dataModel);
signals:
void signalDeleteLinesResult(Query*,int, const QString &, const QList<QModelIndex> &);
// Custom Query
public slots:
void slotCustomQuery(Query* caller, const QString &queryString, DataModel* model);
signals:
void signalCustomQueryResult(Query*,const QString &);
// Table Query
public slots:
void slotTableQuery(Query* caller, DataModel* model);
signals:
void signalTableQueryResult(Query*,const QString &);
void signalSwapModelData();
// Add Lines
public slots:
void slotAddLines(Query* caller, AddModel* addModel);
signals:
void signalAddLinesResult(Query*,int, const QString &);
// Set Data
public slots:
void slotSetData(Query* caller, DataModel*, const QModelIndex &, const QVariant &);
signals:
void signalSetDataResult(Query*,const QString &);
void signalSetDataInModel(const QModelIndex &idx, const QVariant &data);
public slots:
void slotConnectIt(const LoginData &loginData);
void slotGetTableList();
signals:
void signalConnectResult(const QString &);
void signalNewTableList(const QStringList &);
//unused?void signalSelectQueryResult(QString errorMsg, DataModel* dataModel);
void signalSelectQueryStatus(int percent); // 0 - 100
//unsued?void signalExecuteQueryResult(bool success, QString errorMsg, QVariant actualValue, QModelIndex onThisPosition); // take actual value as the new value set!
void signalExecuteQueryStatus(int percent);
};
+33
View File
@@ -0,0 +1,33 @@
#include "WaitWnd.h"
#include "ui_WaitWndUi.h"
WaitWnd::WaitWnd(QWidget* parent)
: QDialog(parent)
, m_ui(new Ui::WaitWnd)
{
m_ui->setupUi(this);
}
WaitWnd::~WaitWnd()
{
delete m_ui;
}
void WaitWnd::wait(const QString &text)
{
m_ui->progressBar->setMinimum(0);
m_ui->progressBar->setMaximum(0);
m_ui->progressBar->setValue(-1);
m_ui->label->setText(text);
show();
}
void WaitWnd::setStatus(int status)
{
m_ui->progressBar->setMinimum(0);
m_ui->progressBar->setMaximum(100);
m_ui->progressBar->setValue(status);
}
+24
View File
@@ -0,0 +1,24 @@
#pragma once
#include <QDialog>
namespace Ui
{
class WaitWnd;
}
class WaitWnd: public QDialog
{
Q_OBJECT
public:
explicit WaitWnd(QWidget* parent = nullptr);
~WaitWnd();
void wait(const QString &text);
void setStatus(int status);
private:
Ui::WaitWnd* m_ui;
};
+56
View File
@@ -0,0 +1,56 @@
// needed: libQt5Sql5-postgresql
/* TODO:
*
* hint for custom queries and their 'editibility'
* autocompletion of tablenames (& columns?)
* csv export for iuliana
* to insert something, DataModel must use QVariant as data storage !
*
*/
#include "BrowserWnd.h"
#include <nglapplication/nglapplication.h>
#include <QDebug>
#include <QTimer>
int main(int argc, char** argv)
{
QStringList params;
params << QStringLiteral("--darkStyle");
int setDarkStyle = false;
for (int i = 0; i < argc; i++)
{
switch (params.indexOf(QString::fromUtf8(argv[i])))
{
case 0: // darkStyle
{
setDarkStyle = true;
break;
}
}
}
if (setDarkStyle)
{
qunsetenv("TDS_DEVEL"); // no dark style
}
else
{
qputenv("TDS_DEVEL", "1");
}
NGLApplication a(argc, argv);
a.createLogger("SQLBrowser", "log4cxx_sqlbrowser.props");
BrowserWnd browserWnd;
QTimer::singleShot(0, &browserWnd, &BrowserWnd::startConnect);
return a.exec();
}
+110
View File
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddLines</class>
<widget class="QWidget" name="AddLines">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>526</width>
<height>399</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Login</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTableView" name="dataView">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<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="pbDone">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Adds all lines to the database and hides this window.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add &amp;&amp; Hide</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbDelete">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Deletes all selected lines (one or more line) from this temporary table.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbClear">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Clears the temporary table by deleting all lines from this temporary table.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Clear</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbAbort">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Do not make any changes and hide this window.&lt;br/&gt;This window's data will be kept until the query is deleted.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Hide</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+219
View File
@@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BrowserWnd</class>
<widget class="QWidget" name="BrowserWnd">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>762</width>
<height>564</height>
</rect>
</property>
<property name="windowTitle">
<string>RDE SQL Browser</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_3">
<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="pushButton_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;3</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbNewQuery">
<property name="text">
<string>New Query</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Exit</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>5</number>
</property>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Filter: </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="leFilter"/>
</item>
</layout>
</item>
<item>
<widget class="QListWidget" name="lwTables">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<spacer name="horizontalSpacer">
<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="pbRefreshTableList">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Refresh List</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="widget_2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QTabWidget" name="twQueries">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="tabPosition">
<enum>QTabWidget::North</enum>
</property>
<property name="tabShape">
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex">
<number>-1</number>
</property>
<property name="tabsClosable">
<bool>true</bool>
</property>
<property name="movable">
<bool>true</bool>
</property>
<property name="tabBarAutoHide">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+299
View File
@@ -0,0 +1,299 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LoginWnd</class>
<widget class="QWidget" name="LoginWnd">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>407</width>
<height>448</height>
</rect>
</property>
<property name="windowTitle">
<string>Login</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Preset:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbPresets">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>150</width>
<height>0</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbLoad">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbSave">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>Load Database file:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="leFilename"/>
</item>
<item>
<widget class="QToolButton" name="tbChooseFile">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="horizontalSpacer_2">
<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="pbLoadFile">
<property name="text">
<string>Load File [F12]</string>
</property>
<property name="shortcut">
<string>F12</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbExit_2">
<property name="text">
<string>Exit [ESC]</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_8">
<property name="text">
<string>Connect to Database:</string>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_2">
<property name="leftMargin">
<number>7</number>
</property>
<property name="topMargin">
<number>7</number>
</property>
<property name="rightMargin">
<number>7</number>
</property>
<property name="bottomMargin">
<number>7</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Database</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="leDatabase"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Username</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="leUsername"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Password</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lePassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Hostname</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="leHostname"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Port</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QSpinBox" name="sbPort">
<property name="specialValueText">
<string>Default</string>
</property>
<property name="minimum">
<number>-1</number>
</property>
<property name="maximum">
<number>65535</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Driver</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="cbDriver"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetMinimumSize</enum>
</property>
<item>
<spacer name="horizontalSpacer">
<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="pbHeart">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&lt;3</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbLogin">
<property name="text">
<string>Login [ENTER]</string>
</property>
<property name="default">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbExit">
<property name="text">
<string>Exit [ESC]</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<tabstops>
<tabstop>cbPresets</tabstop>
<tabstop>pbLoad</tabstop>
<tabstop>pbSave</tabstop>
<tabstop>leFilename</tabstop>
<tabstop>tbChooseFile</tabstop>
<tabstop>pbLoadFile</tabstop>
<tabstop>pbExit_2</tabstop>
<tabstop>cbDriver</tabstop>
<tabstop>leDatabase</tabstop>
<tabstop>leUsername</tabstop>
<tabstop>lePassword</tabstop>
<tabstop>leHostname</tabstop>
<tabstop>sbPort</tabstop>
<tabstop>pbHeart</tabstop>
<tabstop>pbLogin</tabstop>
<tabstop>pbExit</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+321
View File
@@ -0,0 +1,321 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Query</class>
<widget class="QWidget" name="Query">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>643</width>
<height>527</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>Login</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QTableView" name="dataTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>1</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>10</pointsize>
</font>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
<attribute name="horizontalHeaderCascadingSectionResizes">
<bool>true</bool>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item row="1" column="0">
<widget class="QPushButton" name="pbQueryUpdate">
<property name="text">
<string>Update...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pbQueryDelete">
<property name="text">
<string>Delete...</string>
</property>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QTextEdit" name="queryText">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>10</pointsize>
</font>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pbQueryInsert">
<property name="text">
<string>Insert...</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QScrollArea" name="saCheckboxes">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="checkboxesContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>629</width>
<height>68</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="checkboxes">
<property name="topMargin">
<number>0</number>
</property>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="3">
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<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="pbAddLine">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Opens a new window, where one or more lines can be added to the database.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Add</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbDeleteLine">
<property name="enabled">
<bool>true</bool>
</property>
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Deletes all selected lines (one or more line) from the database.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Delete</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbReload">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Reloads the table data with current data from the database.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Shortcut: F5&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Reload</string>
</property>
<property name="shortcut">
<string>F5</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbQuery">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Execute a custom query from the text box below the table data.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;WARNING&lt;/span&gt;: You cannot use Add, Delete, Revert anymore, as a custom query revokes the query tab's functionality as table query.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Shortcut: Ctrl + Enter&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Query</string>
</property>
<property name="shortcut">
<string>Ctrl+Return</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbExport">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Saves the current data from the data table in a CSV file. &lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;Shortcut: Ctrl + S&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>CSV Export</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
+51
View File
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WaitWnd</class>
<widget class="QWidget" name="WaitWnd">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>119</width>
<height>79</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Minimum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="windowTitle">
<string>RDE SQL Browser - Wait ...</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QProgressBar" name="progressBar">
<property name="maximum">
<number>0</number>
</property>
<property name="value">
<number>-1</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>