This repository has been archived on 2020-09-07. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
libs/qad/sql_table/sql_table_widget.h
2020-05-25 16:59:19 +03:00

354 lines
13 KiB
C++

/*
QAD - Qt ADvanced
Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef MYSQLTABLE_H
#define MYSQLTABLE_H
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlQueryModel>
#include <QSqlRecord>
#include <QSqlField>
#include <QSqlTableModel>
#include <QSqlError>
#include <QSqlIndex>
#include <QBoxLayout>
#include <QTableView>
#include <QLabel>
#include <QToolButton>
#include <QAction>
#include <QMenu>
#include <QMouseEvent>
#include <QHeaderView>
#include <QLineEdit>
#include <QScrollBar>
#include <QDoubleSpinBox>
#include <QDateTimeEdit>
#include <QComboBox>
#include <QStyledItemDelegate>
#include <QCheckBox>
#include <QDebug>
#include "qpiconfig.h"
struct QAD_EXPORT ColumnProperties {
enum DataType {Unknown, Int, Float, Chars, Text, Binary, Date, Time, DateTime};
ColumnProperties(const QString & table_, const QString & type_, const QString & name_, const QString & def_, bool auto_, bool prim_, bool option_);
bool isRelation() const {return (!relation_key.isEmpty() && !relation_column.isEmpty());}
QString shortName() const {if (!isRelation()) return name; return relation_column;}
QString fullName() const {if (!isRelation()) return table + "." + name; return (relation_table.isEmpty() ? "" : relation_table + ".") + relation_column;}
DataType getType() const {if (!isRelation()) return type; return relation_type;}
static DataType typeFromString(const QString & n);
DataType type;
int size;
bool auto_increment;
bool primary;
bool optional;
bool visible;
bool is_text;
QString table;
QString name;
QString relation_table;
QString relation_key;
QString relation_column;
QList<QPair<QString, QString> > relation_list; // <id, relation_column>
DataType relation_type;
int key_column;
QString def;
};
struct QAD_EXPORT TableColumns {
int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];}
QVector<int> column_indexes;
QList<ColumnProperties> columns;
};
class QAD_EXPORT SQLQueryModel: public QSqlQueryModel {
Q_OBJECT
public:
explicit SQLQueryModel(QString & t, QString & conn, QList<ColumnProperties> & cp, QVector<int> & ci, QObject* parent = 0): QSqlQueryModel(parent), table_(t), column_props(cp), column_indexes(ci), conn_name(conn) {;}
virtual QVariant data(const QModelIndex & item, int role = Qt::DisplayRole) const;
protected:
virtual Qt::ItemFlags flags(const QModelIndex & ) const {return (Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);}
virtual bool setData(const QModelIndex & index, const QVariant& value, int role = Qt::EditRole);
int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];}
QString & table_;
QList<ColumnProperties> & column_props;
QVector<int> & column_indexes;
QString & conn_name;
signals:
void updateTable(bool save_selection);
void tableChanged();
};
class QAD_EXPORT SQLUniEdit: public QWidget {
Q_OBJECT
public:
explicit SQLUniEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent = 0);
~SQLUniEdit() {for (int i = 0; i < w_.size(); ++i) deleteW(*w_[i]);}
void setProp(const ColumnProperties & p);
QString value(bool for_insert = false);
void clear() {setValue(QVariant());}
private:
void deleteW(QWidget * w) {if (w != 0) delete w;}
void resizeW(QWidget * w) {if (w != 0) w->setGeometry(QRect(0, 0, width(), height()));}
void resizeEvent(QResizeEvent * ) {for (int i = 0; i < w_.size(); ++i) resizeW(*w_[i]);}
bool eventFilter(QObject * o, QEvent * e);
QLineEdit * wtext;
QSpinBox * wint;
QDoubleSpinBox * wfloat;
QDateEdit * wdate;
QTimeEdit * wtime;
QDateTimeEdit * wdatetime;
QComboBox * wrelation;
QList<QWidget ** > w_;
ColumnProperties prop_;
QString connection_name;
private slots:
void value_text(QString value) {valueChanged(value);}
void value_int(int value) {valueChanged(value);}
void value_float(double value) {valueChanged(value);}
void value_date(QDate value) {valueChanged(value);}
void value_time(QTime value) {valueChanged(value);}
void value_datetime(QDateTime value) {valueChanged(value);}
public slots:
void setValue(const QVariant & value);
void updateRelation();
signals:
void valueChanged(const QVariant & );
};
class QAD_EXPORT SQLNewEdit: public QWidget {
Q_OBJECT
friend class SQLTableWidget;
public:
explicit SQLNewEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent = 0);
~SQLNewEdit() {delete line; delete check;}
void setProp(const ColumnProperties & p);
bool isEnabled() const {return check->isChecked();}
QString value() const {return line->value(true);}
void clear() {line->clear();}
private:
ColumnProperties prop_;
SQLUniEdit * line;
QCheckBox * check;
};
class QAD_EXPORT SQLFilterEdit: public QWidget {
Q_OBJECT
friend class SQLTableWidget;
public:
explicit SQLFilterEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent = 0);
~SQLFilterEdit() {delete line; delete combo;}
void setProp(const ColumnProperties & p) {prop_ = p; line->setProp(p);}
QString filter() const;
bool isEmpty() const {return line->value().isEmpty() || combo->currentIndex() == 0;}
void clear();
private:
ColumnProperties prop_;
SQLUniEdit * line;
QComboBox * combo;
private slots:
void value_changed() {if (combo->currentIndex() == 0) combo->setCurrentIndex(prop_.is_text ? 2 : 1);}
public slots:
signals:
void filterChanged();
};
class QAD_EXPORT SQLItemDelegate: public QStyledItemDelegate {
Q_OBJECT
public:
explicit SQLItemDelegate(QList<ColumnProperties> & cp, QVector<int> & ci, bool & ro, const QString & conn_name, QObject * parent = 0);
~SQLItemDelegate() {;}
private:
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const;
QString displayText(const QVariant & value, const QLocale & locale) const;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];}
void setConnectionName(const QString & conn_name) {connection_name = conn_name;}
QList<ColumnProperties> & column_props;
QVector<int> & column_indexes;
bool & read_only;
QString connection_name;
private slots:
public slots:
signals:
};
namespace Ui {
class SQLTableWidget;
}
class QAD_EXPORT SQLTableWidget: public QWidget
{
Q_OBJECT
Q_PROPERTY(QString tableName READ tableName WRITE setTableName)
Q_PROPERTY(QString connectionName READ connectionName WRITE setConnectionName)
Q_PROPERTY(bool lineNewVisible READ lineNewVisible WRITE setLineNewVisible)
Q_PROPERTY(bool lineFilterVisible READ lineFilterVisible WRITE setLineFilterVisible)
Q_PROPERTY(bool readOnly READ readOnly WRITE setReadOnly)
friend class SQLItemDelegate;
friend class SQLUniEdit;
public:
SQLTableWidget(QWidget * parent = 0);
virtual ~SQLTableWidget();
bool isTableExists() const {return table_opened;}
const QString & tableName() const {return table_;}
QTableView * tableView();
bool readOnly() const {return read_only;}
const ColumnProperties * columnProperty(int index) const {if (index < 0 || index >= column_props.count()) return 0; return &(column_props[index]);}
const ColumnProperties * columnProperty(const QString & name) const {return columnProperty(columnByName(name));}
const QList<ColumnProperties> & columnProperties() const {return column_props;}
QStringList columnNames() const {QStringList sl; foreach (const ColumnProperties & i, column_props) sl << i.name; return sl;}
int columnsCount() const {return column_props.size();}
bool isColumnVisible(int ind) {if (!columnExists(ind)) return false; return column_props[ind].visible;}
bool isColumnVisible(const QString & name) {if (!columnExists(name)) return false; return column_props[columnByName(name)].visible;}
bool isColumnHidden(int ind) {if (!columnExists(ind)) return true; return !column_props[ind].visible;}
bool isColumnHidden(const QString & name) {if (!columnExists(name)) return true; return !column_props[columnByName(name)].visible;}
void setColumnVisible(int ind, bool visible);
void setColumnVisible(const QString & name, bool visible) {col_vis[name] = visible; setColumnVisible(columnByName(name), visible);}
void setColumnHidden(int ind, bool hidden) {setColumnVisible(ind, !hidden);}
void setColumnHidden(const QString & name, bool hidden) {col_vis[name] = !hidden; setColumnVisible(columnByName(name), !hidden);}
bool lineNewVisible() const;
bool lineFilterVisible() const;
bool addRelation(const QString & this_column, const QString & other_table, const QString & other_key, const QString & other_column);
void addTranslation(const QString & file);
void addFixedColumnTranslation(const QString & col_name, const QString & col_tr, const QString & col_tt = QString());
void fetchMore() {if (model) model->fetchMore();}
void fetchAll() {if (model) while (model->canFetchMore()) model->fetchMore();}
void selectId(int id);
void setAdditionalActions(QList<QAction * > a);
QSqlRecord headerRecord() const {if (model) return model->record(); return QSqlRecord();}
QSqlRecord currentRecord() const;
void setCustomQuery(const QString & q);
void setCustomColumnNames(const QStringList & cn) {custom_col_names = cn; updateTable();}
static bool isTableExists(const QString & table, const QString & conn_name = QLatin1String(QSqlDatabase::defaultConnection)) {return QSqlDatabase::database(conn_name).tables().contains(table, Qt::CaseInsensitive);}
static bool executeScript(const QString & text, QSqlDatabase db = QSqlDatabase::database(), bool skip_errors = false, bool sqlite = false);
static bool executeScriptFile(const QString & file, QSqlDatabase db = QSqlDatabase::database(), bool skip_errors = false, bool sqlite = false);
static bool isConnectedToDatabase(const QString & conn_name = QLatin1String(QSqlDatabase::defaultConnection)) {return QSqlDatabase::database(conn_name, false).isOpen();}
static bool connectToDatabase(const QString & config, const QString & conn_name = QLatin1String(QSqlDatabase::defaultConnection));
QString connectionName() const {return connection_name;}
private:
static QString preprocessScript(QString text);
bool eventFilter(QObject * o, QEvent * e);
void timerEvent(QTimerEvent * );
void changeEvent(QEvent * e);
void stopTimer() {if (timer != 0) killTimer(timer); timer = 0;}
bool checkTable();
QStringList getTableColumns(const QString & t);
QString getColumnType(const QString & t, const QString & c);
static QList<QPair<QString, QString> > getColumnValues(const QString & t, const QString & k, const QString & c, const QString & conn_name);
void setTableVisible(bool on);
int mapColumn(int abs_ind) const {if (abs_ind <= 0 || abs_ind >= column_indexes.size() + 1) return 0; return column_indexes[abs_ind - 1];}
int columnByName(const QString & name) const {for (int i = 0; i < column_props.size(); ++i) if (column_props[i].name == name) return i; return -1;}
bool columnExists(int index) const {return (index >= 0 && index < column_props.size());}
bool columnExists(const QString & name) const {for (int i = 0; i < column_props.size(); ++i) if (column_props[i].name == name) return true; return false;}
QPair<QString, QString> trColumn(const QString & n);
QString tableNames();
QString columnNames();
QString columnFilters();
QString columnRelations();
Ui::SQLTableWidget * ui;
QString table_, cquery, custom_query;
QStringList custom_col_names;
SQLQueryModel * model;
//QAction act_add, act_del;
QList<ColumnProperties> column_props;
QList<SQLNewEdit * > column_news;
QList<SQLFilterEdit * > column_filters;
QVector<int> column_indexes;
QStringList wait_rels;
QMenu popup_menu, popup_col, popup_filter;
QTime tm;
QActionGroup filters_group;
QAction * action_del;
QList<QAction*> add_actions;
QMap<QString, QPair<QString, QString> > translates, fixed_translates;
QMap<QString, bool> col_vis;
int timer;
bool filters_active, table_opened, read_only, first_update;
static QString _dir;
QPoint pp;
QString connection_name;
public slots:
void setTableName(const QString & t);
void setLineNewVisible(bool on);
void setLineFilterVisible(bool on);
void setReadOnly(bool yes);
void updateTable(bool save_selection = false);
void setConnectionName(const QString &conn_name);
private slots:
void on_buttonAdd_clicked();
void on_actionFiltersClear_triggered();
void on_view_clicked(const QModelIndex & index);
void header_sectionResized(int logicalIndex, int oldSize, int newSize);
void header_sortIndicatorChanged(int logicalIndex, Qt::SortOrder order);
void scrolled(int value);
void del_triggered();
void column_triggered(bool on);
signals:
void rowClicked(int row);
void recordClicked(QSqlRecord rec);
void selectionChanged();
void tableChanged();
};
#endif // MYSQLTABLE_H