#include "sql_table_widget.h" #include "qad_types.h" #include "ui_sql_table_widget.h" #include #include #include #include #include QString SQLTableWidget::_dir; ColumnProperties::ColumnProperties(const QString & table_, const QString & type_, const QString & name_, const QString & def_, bool auto_, bool prim_, bool option_) { visible = true; table = table_; name = name_; def = def_; auto_increment = auto_; primary = prim_; optional = option_; int bs = type_.indexOf("("), bf = type_.indexOf(")"); size = type_.mid(bs + 1, bf - bs - 1).toInt(); key_column = 0; type = typeFromString(type_.toLower()); is_text = (type == ColumnProperties::Chars || type == ColumnProperties::Text); } ColumnProperties::DataType ColumnProperties::typeFromString(const QString & n) { if (n.indexOf("datetime") >= 0 || n.indexOf("timestamp") >= 0) return ColumnProperties::DateTime; if (n.indexOf("date") >= 0) return ColumnProperties::Date; if (n.indexOf("time") >= 0) return ColumnProperties::Time; if (n.indexOf("int") >= 0) return ColumnProperties::Int; if (n.indexOf("char") >= 0) return ColumnProperties::Chars; if (n.indexOf("dec") >= 0 || n.indexOf("numeric") >= 0 || n.indexOf("real") >= 0 || n.indexOf("float") >= 0 || n.indexOf("double") >= 0) return ColumnProperties::Float; if (n.indexOf("text") >= 0) return ColumnProperties::Text; if (n.indexOf("blob") >= 0) return ColumnProperties::Binary; return ColumnProperties::Unknown; } QVariant SQLQueryModel::data(const QModelIndex & item, int role) const { QVariant var = QSqlQueryModel::data(item, role); // QVariant::Type t = var.type(); /*if (t == QVariant::Date) return var.toDate().toString("dd.MM.yyyy"); if (t == QVariant::Time) return var.toTime().toString("hh:mm:ss"); if (t == QVariant::DateTime) return var.toDateTime().toString("dd.MM.yyyy hh:mm:ss");*/ return var; } bool SQLQueryModel::setData(const QModelIndex & index, const QVariant & value, int role) { if (value.isValid() && role == Qt::EditRole) { QSqlQuery q(QSqlDatabase::database(conn_name)); int col = mapColumn(index.column()); ColumnProperties::DataType t = column_props[col].type; bool quotes = (t == ColumnProperties::Chars || t == ColumnProperties::Text || t == ColumnProperties::Date || t == ColumnProperties::Time || t == ColumnProperties::ColumnProperties::DateTime); QString val = value.toString(); if (t == ColumnProperties::Date) val = value.toDate().toString("yyyy-MM-dd"); if (t == ColumnProperties::Time) val = value.toTime().toString("hh:mm:ss"); if (t == ColumnProperties::DateTime) val = value.toDateTime().toString("yyyy-MM-dd hh:mm:ss"); if (!q.exec("UPDATE " + table_ + " SET " + column_props[col].name + "=" + (quotes ? "'" : "") + val + (quotes ? "'" : "") + " WHERE " + column_props[0].name + "=" + record(index.row()).value(0).toString() + ";")) { qDebug() << "[UPDATE]" << q.lastQuery() << "Error:" << q.lastError(); return false; } // qDebug() << "[UPDATE]" << q.lastQuery(); dataChanged(index, index); updateTable(true); emit tableChanged(); return true; } return false; } SQLUniEdit::SQLUniEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent) : QWidget(parent) , prop_(prop) , connection_name(conn_name) { wtext = 0; wint = 0; wfloat = 0; wdate = 0; wtime = 0; wdatetime = 0; wrelation = 0; setProp(prop_); w_ << (QWidget **)&wtext << (QWidget **)&wint << (QWidget **)&wfloat << (QWidget **)&wdate << (QWidget **)&wtime << (QWidget **)&wdatetime << (QWidget **)&wrelation; } void SQLUniEdit::setProp(const ColumnProperties & p) { for (int i = 0; i < w_.size(); ++i) deleteW(*w_[i]); wtext = 0; wint = 0; wfloat = 0; wdate = 0; wtime = 0; wdatetime = 0; wrelation = 0; prop_ = p; if (prop_.isRelation()) { wrelation = new QComboBox(this); wrelation->installEventFilter(this); for (int i = 0; i < prop_.relation_list.size(); ++i) wrelation->addItem(prop_.relation_list[i].second, prop_.relation_list[i].first); connect(wrelation, SIGNAL(currentIndexChanged(int)), this, SLOT(value_int(int))); } else { ColumnProperties::DataType t = prop_.getType(); switch (t) { case ColumnProperties::Int: wint = new QSpinBox(this); wint->setRange(-0x7FFFFFFF, 0x7FFFFFFF); connect(wint, SIGNAL(valueChanged(int)), this, SLOT(value_int(int))); break; case ColumnProperties::Float: wfloat = new QDoubleSpinBox(this); wfloat->setRange(-1E+300, 1E+300); wfloat->setDecimals(2); connect(wfloat, SIGNAL(valueChanged(double)), this, SLOT(value_float(double))); break; case ColumnProperties::Date: wdate = new QDateEdit(this); wdate->setDisplayFormat("dd.MM.yyyy"); wdate->setCalendarPopup(true); wdate->setDate(QDate::currentDate()); connect(wdate, SIGNAL(dateChanged(QDate)), this, SLOT(value_date(QDate))); break; case ColumnProperties::Time: wtime = new QTimeEdit(this); wtime->setDisplayFormat("hh:mm:ss"); wtime->setTime(QTime::currentTime()); connect(wtime, SIGNAL(timeChanged(QTime)), this, SLOT(value_time(QTime))); break; case ColumnProperties::DateTime: wdatetime = new QDateTimeEdit(this); wdatetime->setDisplayFormat("dd.MM.yyyy hh:mm:ss"); wdatetime->setCalendarPopup(true); wdatetime->setDateTime(QDateTime::currentDateTime()); connect(wdatetime, SIGNAL(dateTimeChanged(QDateTime)), this, SLOT(value_datetime(QDateTime))); break; case ColumnProperties::Chars: case ColumnProperties::Text: case ColumnProperties::Unknown: default: wtext = new QLineEdit(this); connect(wtext, SIGNAL(textChanged(QString)), this, SLOT(value_text(QString))); break; } } for (int i = 0; i < w_.size(); ++i) if (*w_[i]) (*w_[i])->setHidden(false); resizeEvent(0); } QString SQLUniEdit::value(bool for_insert) { QString ret; ColumnProperties::DataType t = (for_insert ? prop_.type : prop_.getType()); bool quotes = (t == ColumnProperties::Chars || t == ColumnProperties::Text || t == ColumnProperties::Date || t == ColumnProperties::Time || t == ColumnProperties::ColumnProperties::DateTime); if (quotes) ret = "'"; if (prop_.isRelation()) if (for_insert) ret += wrelation->itemData(wrelation->currentIndex()).toString(); else ret += wrelation->currentText(); else { if (wint != 0) ret += QString::number(wint->value()); else { if (wfloat != 0) ret += QString::number(wfloat->value()); else { if (wdate != 0) ret += wdate->date().toString("yyyy-MM-dd"); else { if (wtime != 0) ret += wtime->time().toString("hh:mm:ss"); else { if (wdatetime != 0) ret += wdatetime->dateTime().toString("yyyy-MM-dd hh:mm:ss"); else { ret += wtext->text(); } } } } } } if (quotes) ret += "'"; if (ret == "''") ret.clear(); return ret; } bool SQLUniEdit::eventFilter(QObject * o, QEvent * e) { if (e->type() == QEvent::MouseButtonPress) updateRelation(); return QWidget::eventFilter(o, e); } void SQLUniEdit::setValue(const QVariant & value) { if (prop_.isRelation()) return; if (wint != 0) wint->setValue(value.toInt()); else { if (wfloat != 0) wfloat->setValue(value.toDouble()); else { if (wdate != 0) wdate->setDate(value.toDate()); else { if (wtime != 0) wtime->setTime(value.toTime()); else { if (wdatetime != 0) wdatetime->setDateTime(value.toDateTime()); else { wtext->setText(value.toString()); } } } } } } void SQLUniEdit::updateRelation() { prop_.relation_list = SQLTableWidget::getColumnValues(prop_.relation_table, prop_.relation_key, prop_.relation_column, connection_name); int pi = wrelation->currentIndex(); wrelation->blockSignals(true); wrelation->clear(); for (int i = 0; i < prop_.relation_list.size(); ++i) wrelation->addItem(prop_.relation_list[i].second, prop_.relation_list[i].first); wrelation->setCurrentIndex(pi); wrelation->blockSignals(false); } SQLNewEdit::SQLNewEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent): QWidget(parent), prop_(prop) { line = new SQLUniEdit(prop, conn_name); line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); check = new QCheckBox(); check->setChecked(true); check->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); connect(check, SIGNAL(toggled(bool)), line, SLOT(setEnabled(bool))); QLayout * lay = new QHBoxLayout(); lay->addWidget(check); lay->addWidget(line); lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(0); setLayout(lay); setProp(prop); check->setChecked(!prop.primary); } void SQLNewEdit::setProp(const ColumnProperties & p) { prop_ = p; line->setProp(p); check->setEnabled(p.optional); if (!check->isEnabled()) check->setChecked(true); } SQLFilterEdit::SQLFilterEdit(const ColumnProperties & prop, const QString & conn_name, QWidget * parent): QWidget(parent), prop_(prop) { line = new SQLUniEdit(prop, conn_name); line->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); combo = new QComboBox(); combo->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); QStringList sl; sl << " " << "=" << QString::fromUtf8("≈") << QString::fromUtf8("≠") << ">" << QString::fromUtf8("≥") << "<" << QString::fromUtf8("≤"); combo->addItems(sl); combo->setCurrentIndex(0); connect(line, SIGNAL(valueChanged(QVariant)), this, SIGNAL(filterChanged())); connect(line, SIGNAL(valueChanged(QVariant)), this, SLOT(value_changed())); connect(combo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(filterChanged())); QLayout * lay = new QHBoxLayout(); lay->addWidget(combo); lay->addWidget(line); lay->setContentsMargins(0, 0, 0, 0); lay->setSpacing(2); setLayout(lay); setProp(prop); } QString SQLFilterEdit::filter() const { QString ret; if (combo->currentIndex() == 0) return ret; ret = prop_.fullName(); switch (combo->currentIndex()) { case 1: ret.append("="); break; case 2: ret.append("="); break; case 3: ret.append("!="); break; case 4: ret.append(">"); break; case 5: ret.append(">="); break; case 6: ret.append("<"); break; case 7: ret.append("<="); break; }; QString val = line->value(); if (prop_.is_text && combo->currentIndex() == 2) { ret.chop(1); ret.append(" LIKE '%"); ret.append(val.mid(1, val.length() - 2)); ret.append("%'"); } else ret.append(val); return ret; } void SQLFilterEdit::clear() { line->setValue(QVariant()); combo->setCurrentIndex(0); } SQLItemDelegate::SQLItemDelegate(QList & cp, QVector & ci, bool & ro, const QString & conn_name, QObject * parent) : QStyledItemDelegate(parent) , column_props(cp) , column_indexes(ci) , read_only(ro) , connection_name(conn_name) { ; } QWidget * SQLItemDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { if (read_only) return 0; ColumnProperties & cp(column_props[mapColumn(index.column())]); if (cp.isRelation()) { cp.relation_list = SQLTableWidget::getColumnValues(cp.relation_table, cp.relation_key, cp.relation_column, connection_name); QComboBox * w = new QComboBox(parent); w->setGeometry(option.rect); for (int i = 0; i < cp.relation_list.size(); ++i) { w->addItem(cp.relation_list[i].second, cp.relation_list[i].first); if (index.data().toString() == cp.relation_list[i].second) w->setCurrentIndex(i); } return w; } else { QWidget * w = QStyledItemDelegate::createEditor(parent, option, index); if (qobject_cast(w)) { qobject_cast(w)->setDisplayFormat("hh:mm:ss"); } else if (qobject_cast(w)) { qobject_cast(w)->setCalendarPopup(true); qobject_cast(w)->setDisplayFormat("dd.MM.yyyy"); } else if (qobject_cast(w)) { qobject_cast(w)->setCalendarPopup(true); qobject_cast(w)->setDisplayFormat("dd.MM.yyyy hh:mm:ss"); } return w; } return 0; } QString SQLItemDelegate::displayText(const QVariant & value, const QLocale & locale) const { QVariant::Type t = value.type(); if (t == QVariant::Date) return value.toDate().toString("dd.MM.yyyy"); if (t == QVariant::Time) return value.toTime().toString("hh:mm:ss"); if (t == QVariant::DateTime) return value.toDateTime().toString("dd.MM.yyyy hh:mm:ss"); return QStyledItemDelegate::displayText(value, locale); } void SQLItemDelegate::setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const { if (qobject_cast(editor)) { model->setData(index, qobject_cast(editor)->itemData(qobject_cast(editor)->currentIndex())); return; } QStyledItemDelegate::setModelData(editor, model, index); } SQLTableWidget::SQLTableWidget(QWidget * parent): QWidget(parent), filters_group(this) { ui = new Ui::SQLTableWidget(); ui->setupUi(this); model = 0; timer = 0; connection_name = QSqlDatabase::defaultConnection; filters_active = first_update = debug = true; table_opened = read_only = false; ui->labelNew->setFixedSize(preferredIconSize(1.2, this)); ui->labelFilter->setFixedSize(preferredIconSize(1.2, this)); ui->view->installEventFilter(this); ui->view->viewport()->installEventFilter(this); ui->view->horizontalHeader()->setSortIndicator(0, Qt::AscendingOrder); ui->view->horizontalHeader()->viewport()->installEventFilter(this); ui->view->setItemDelegate(new SQLItemDelegate(column_props, column_indexes, read_only, connection_name)); ui->view->horizontalHeader()->setItemDelegate(new QItemDelegate()); ui->view->verticalHeader()->setDefaultSectionSize(fontHeight(this) * 1.5); // qDebug() << view->horizontalHeader()->itemDelegate(); // qDebug() << fontMetrics().elidedText(, Qt::ElideNone, 30, Qt::TextWordWrap); setTableVisible(false); connect(ui->view->horizontalHeader(), SIGNAL(sectionResized(int, int, int)), this, SLOT(header_sectionResized(int, int, int))); connect(ui->view->horizontalHeader(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(header_sortIndicatorChanged(int, Qt::SortOrder))); connect(ui->view->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(scrolled(int))); // act_add.setText(tr("Add ...")); // act_del.setText(tr("Remove selected")); action_del = new QAction(QIcon(":/icons/edit-delete.png"), tr("Remove selected"), this); connect(action_del, SIGNAL(triggered(bool)), this, SLOT(del_triggered())); popup_menu.addAction(action_del); ui->actionFilter_AND->setChecked(true); filters_group.addAction(ui->actionFilter_AND); filters_group.addAction(ui->actionFilter_OR); connect(&filters_group, SIGNAL(triggered(QAction *)), this, SLOT(updateTable())); popup_filter.addAction(ui->actionFiltersClear); popup_filter.addSeparator(); popup_filter.addAction(ui->actionFilter_AND); popup_filter.addAction(ui->actionFilter_OR); ui->buttonFilterConfig->setMenu(&popup_filter); // connect(&act_add, SIGNAL(triggered(bool)), this, SLOT(add_triggered())); // connect(&act_del, SIGNAL(triggered(bool)), this, SLOT(del_triggered())); } SQLTableWidget::~SQLTableWidget() { stopTimer(); if (model != 0) delete model; } bool SQLTableWidget::eventFilter(QObject * o, QEvent * e) { if (o == ui->view) { if (e->type() == QEvent::KeyPress) { QKeyEvent * ke = (QKeyEvent *)e; if (ke->key() == Qt::Key_Home) { ui->view->selectRow(0); return true; } if (ke->key() == Qt::Key_End) { ui->view->selectRow(ui->view->verticalHeader()->count() - 1); return true; } } } if (o == ui->view->viewport()) { if (e->type() == QEvent::MouseButtonPress) { QMouseEvent * me = (QMouseEvent *)e; if (me->button() == Qt::RightButton) { action_del->setVisible(!read_only); popup_menu.popup(me->globalPos()); } } } if (o == ui->view->horizontalHeader()->viewport()) { QMouseEvent * me = (QMouseEvent *)e; if (e->type() == QEvent::MouseButtonPress) pp = me->pos(); if (e->type() == QEvent::MouseButtonRelease) { if ((me->pos() - pp).manhattanLength() < QApplication::startDragDistance()) { if (me->button() == Qt::LeftButton) { int ci = ui->view->horizontalHeader()->logicalIndexAt(me->pos()), ri = ui->view->horizontalHeader()->logicalIndexAt(me->pos() + QPoint(3, 0)), li = ui->view->horizontalHeader()->logicalIndexAt(me->pos() - QPoint(3, 0)); // qDebug() << ci << ri << li; if ((ci < 0) || (ci >= ui->view->horizontalHeader()->count()) || (ci != ri) || (ci != li) || (tm.elapsed() <= QApplication::doubleClickInterval())) { tm.restart(); return QObject::eventFilter(o, e); } tm.restart(); Qt::SortOrder o = Qt::AscendingOrder; if (ui->view->horizontalHeader()->sortIndicatorSection() == ci && ui->view->horizontalHeader()->sortIndicatorOrder() == Qt::AscendingOrder) o = Qt::DescendingOrder; ui->view->horizontalHeader()->setSortIndicator(ci, o); return true; } if (me->button() == Qt::RightButton) { popup_col.clear(); for (int i = 0; i < column_props.size(); ++i) { QPair ctr = trColumn(column_props[i].name); QAction * a = popup_col.addAction(ctr.first, this, SLOT(column_triggered(bool))); a->setToolTip(ctr.second); a->setCheckable(true); a->setChecked(column_props[i].visible); a->setData(i); } popup_col.popup(me->globalPos()); return true; } } else return true; } } return QWidget::eventFilter(o, e); } void SQLTableWidget::timerEvent(QTimerEvent *) { setTableName(table_); } void SQLTableWidget::changeEvent(QEvent * e) { QWidget::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: ui->retranslateUi(this); action_del->setText(tr("Remove selected")); break; default: break; } } void SQLTableWidget::setTableName(const QString & t) { ui->labelEmpty->setText(tr("Table \"%1\" doesn`t exists!").arg(t)); stopTimer(); table_opened = false; first_update = true; table_ = t; if (!QSqlDatabase::database(connection_name).isOpen()) { if (debug) qDebug() << "[setTableName] Database in not opened!"; setTableVisible(false); timer = startTimer(1000); return; } model = new SQLQueryModel(table_, connection_name, column_props, column_indexes, this); connect(model, SIGNAL(updateTable(bool)), this, SLOT(updateTable(bool))); connect(model, SIGNAL(tableChanged()), this, SIGNAL(tableChanged())); // model->setTable(table_); cquery = "SELECT * FROM " + table_ + ";"; model->setQuery(cquery, QSqlDatabase::database(connection_name)); ui->view->setModel(model); connect(ui->view->selectionModel(), SIGNAL(currentRowChanged(QModelIndex, QModelIndex)), this, SIGNAL(selectionChanged()), Qt::UniqueConnection); //((QSqlQueryModel * )model)->setQuery(QSqlQuery("SELECT id FROM " + table_ + ";")); setTableVisible(checkTable()); updateTable(); foreach(const QString & wr, wait_rels) { QStringList wrl = wr.split(";"); addRelation(wrl[0], wrl[1], wrl[2], wrl[3]); } QMapIterator cnit(col_vis); while (cnit.hasNext()) { cnit.next(); setColumnVisible(cnit.key(), cnit.value()); } } bool SQLTableWidget::checkTable() { table_opened = false; QSqlDatabase db = QSqlDatabase::database(connection_name); if (db.driver() == 0) return false; bool te = db.tables(QSql::Tables).contains(table_, Qt::CaseInsensitive); // qDebug() << "tables:" << db.tables(QSql::Tables) << table_ << table_opened; if (!te) { timer = startTimer(1000); return false; } /*if (!q.exec("SHOW TABLES")) { qDebug() << "[SHOW TABLES]" << q.lastError(); timer = startTimer(1000); return false; } while (q.next()) { //qDebug() << q.value(0); if (q.value(0) == table_) {table_opened = true; break;} } if (!table_opened) { timer = startTimer(1000); return false; }*/ QSqlRecord header = db.record(table_); QString pin = db.primaryIndex(table_).fieldName(0); table_opened = true; column_props.clear(); for (int i = 0; i < header.count(); ++i) { QSqlField f = header.field(i); column_props << ColumnProperties(table_, f.type() == QVariant::String ? "text" : QVariant::typeToName(f.type()), f.name(), f.defaultValue().toString(), f.isAutoValue(), f.name() == pin, f.requiredStatus() == QSqlField::Optional); } /*if (!q.exec("DESCRIBE " + table_ + ";")) { qDebug() << "[DESCRIBE " + table_ + "]" << q.lastError(); timer = startTimer(1000); return false; } while (q.next()) { column_props << ColumnProperties(table_, q.value(1).toString().toLower(), q.value(0).toString().toLower(), q.value(4).toString().toLower(), q.value(5).toString().toLower().indexOf("auto_increment") >= 0, q.value(3).toString().toLower().indexOf("pri") >= 0); }*/ // ui->labelNew->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); // ui->labelFilter->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); ui->scrollAreaNew->setFixedHeight(QLineEdit().sizeHint().height() + 2); ui->scrollAreaFilter->setFixedHeight(QLineEdit().sizeHint().height() + 2); qDeleteAll(column_news); qDeleteAll(column_filters); column_news.clear(); column_filters.clear(); SQLNewEdit * le = 0; for (int i = 0; i < column_props.size(); ++i) { le = new SQLNewEdit(column_props[i], connection_name); le->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); column_news.push_back(le); ui->layoutNew->insertWidget(i, le); } for (int i = 0; i < column_props.size(); ++i) { SQLFilterEdit * fe = new SQLFilterEdit(column_props[i], connection_name); fe->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); column_filters.push_back(fe); ui->layoutFilter->insertWidget(i, fe); connect(fe, SIGNAL(filterChanged()), this, SLOT(updateTable())); } return true; } QStringList SQLTableWidget::getTableColumns(const QString & t) { QStringList ret; QSqlDatabase db = QSqlDatabase::database(connection_name); QSqlRecord header = db.record(t); for (int i = 0; i < header.count(); ++i) ret << header.field(i).name(); return ret; } QString SQLTableWidget::getColumnType(const QString & t, const QString & c) { QSqlDatabase db = QSqlDatabase::database(connection_name); QSqlRecord header = db.record(t); for (int i = 0; i < header.count(); ++i) { QSqlField f = header.field(i); if (f.name() != c) continue; return (f.type() == QVariant::String ? "text" : QVariant::typeToName(f.type())); } return QString(); } QList> SQLTableWidget::getColumnValues(const QString & t, const QString & k, const QString & c, const QString & conn_name) { QList> ret; QSqlQuery q(QSqlDatabase::database(conn_name)); if (!q.exec("SELECT " + t + "." + k + "," + t + "." + c + " FROM " + t + ";")) return ret; while (q.next()) ret << QPair(q.value(0).toString(), q.value(1).toString()); return ret; } QPair SQLTableWidget::trColumn(const QString & n) { QPair ftr = fixed_translates.value(n); if (!ftr.first.isEmpty()) return ftr; QPair trn = translates.value(n); if (trn.first.isEmpty()) return QPair(n, ""); return trn; } void SQLTableWidget::updateTable(bool save_selection) { if (!filters_active || !table_opened) return; int vp = ui->view->verticalScrollBar()->value(); int hp = ui->view->horizontalScrollBar()->value(); // bool focus = view->hasFocus(); QModelIndex csi; QModelIndexList sl; if (save_selection) { csi = ui->view->selectionModel()->currentIndex(); sl = ui->view->selectionModel()->selectedRows(); } if (custom_query.isEmpty()) { QString cr = columnRelations(), cf = columnFilters(); bool where = !cr.isEmpty() || !cf.isEmpty(), and_ = !cr.isEmpty() && !cf.isEmpty(); cquery = "SELECT " + columnNames() + " FROM " + tableNames() + (where ? " WHERE " : "") + cr + (and_ ? " AND " : "") + cf + " ORDER BY " + column_props[ui->view->horizontalHeader()->sortIndicatorSection()].fullName() + (ui->view->horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder ? " DESC" : " ASC") + ";"; } else cquery = custom_query; // qDebug() << cquery; model->setQuery(cquery, QSqlDatabase::database(connection_name)); if (model->lastError().isValid()) qDebug() << model->lastError(); if (first_update) { ui->view->resizeColumnsToContents(); for (int i = 0; i < ui->view->horizontalHeader()->count(); ++i) if (ui->view->horizontalHeader()->sectionSize(i) < 100) ui->view->horizontalHeader()->resizeSection(i, 100); first_update = false; } // ui->labelNew->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); // ui->labelFilter->setFixedWidth(qMax(ui->view->verticalHeader()->sizeHint().width() + 2, 16)); ui->layoutNew->invalidate(); if (save_selection) { QItemSelectionModel * sm = ui->view->selectionModel(); foreach(const QModelIndex & i, sl) sm->select(i, QItemSelectionModel::Select | QItemSelectionModel::Rows); sm->setCurrentIndex(csi, QItemSelectionModel::Select); // ui->view->setFocus(); } if (custom_query.isEmpty()) { for (int i = 0; i < model->columnCount(); ++i) { QPair ctr = trColumn(column_props[mapColumn(i)].name); model->setHeaderData(i, Qt::Horizontal, ctr.first, Qt::DisplayRole); model->setHeaderData(i, Qt::Horizontal, ctr.second, Qt::ToolTipRole); } } else { if (custom_col_names.isEmpty()) { QSqlRecord header = model->record(); for (int i = 0; i < header.count(); ++i) { QSqlField f = header.field(i); QPair ctr = trColumn(f.name()); model->setHeaderData(i, Qt::Horizontal, ctr.first, Qt::DisplayRole); model->setHeaderData(i, Qt::Horizontal, ctr.second, Qt::ToolTipRole); } } else { for (int i = 0; i < qMin(custom_col_names.size(), model->columnCount()); ++i) { QPair ctr = trColumn(custom_col_names[i]); model->setHeaderData(i, Qt::Horizontal, ctr.first, Qt::DisplayRole); model->setHeaderData(i, Qt::Horizontal, ctr.second, Qt::ToolTipRole); } } } ui->view->verticalScrollBar()->setValue(vp); ui->view->horizontalScrollBar()->setValue(hp); // if (focus) view->setFocus(); } void SQLTableWidget::setConnectionName(const QString & conn_name) { connection_name = conn_name; ui->view->setItemDelegate(new SQLItemDelegate(column_props, column_indexes, read_only, connection_name)); } QString SQLTableWidget::tableNames() { QString ret = table_; QSet rtables; for (int i = 0; i < column_props.size(); ++i) { ColumnProperties & cp(column_props[i]); if (!cp.visible || cp.relation_key.isEmpty() || cp.relation_column.isEmpty()) continue; if (rtables.contains(cp.relation_table)) continue; rtables << cp.relation_table; ret.append("," + cp.relation_table); } return ret; } QString SQLTableWidget::columnNames() { QString ret; bool first = true; column_indexes.clear(); for (int i = 0; i < column_props.size(); ++i) { ColumnProperties & cp(column_props[i]); column_news[i]->setVisible(cp.visible); column_filters[i]->setVisible(cp.visible); if (!cp.visible && !cp.primary) continue; if (!first) ret.append(","); first = false; ret.append(cp.fullName()); if (i > 0) column_indexes.push_back(i); } // qDebug() << column_indexes; return ret; } QString SQLTableWidget::columnFilters() { QString ret; bool and_ = ui->actionFilter_AND->isChecked(); for (int i = 0; i < column_props.size(); ++i) { if (!column_filters[i]->isVisible() || column_filters[i]->isEmpty()) continue; if (!ret.isEmpty()) ret.append(and_ ? " AND " : " OR "); ret.append(column_filters[i]->filter()); } if (!ret.isEmpty()) { ret.prepend("("); ret.append(")"); } return ret; } QString SQLTableWidget::columnRelations() { QString ret; for (int i = 0; i < column_props.size(); ++i) { ColumnProperties & cp(column_props[i]); if (!cp.visible || cp.relation_key.isEmpty() || cp.relation_column.isEmpty()) continue; if (!ret.isEmpty()) ret.append(" AND "); ret.append(table_ + "." + cp.name + "="); ret.append(cp.relation_table + "." + cp.relation_key); } if (!ret.isEmpty()) { ret.prepend("("); ret.append(")"); } return ret; } void SQLTableWidget::on_buttonAdd_clicked() { QStringList values; bool at_least = false; for (int i = 0; i < column_props.size(); ++i) { values.append(column_news[i]->value()); if (!values.back().isEmpty()) at_least = true; } if (!at_least) return; QString qs("INSERT INTO " + table_ + " ("); bool first = true; for (int i = 0; i < column_props.size(); ++i) { if (values[i].isEmpty() || !column_news[i]->isEnabled()) continue; if (!first) qs.append(","); qs.append(column_props[i].name); first = false; } qs.append(") VALUES("); first = true; for (int i = 0; i < column_props.size(); ++i) { if (values[i].isEmpty() || !column_news[i]->isEnabled()) continue; if (!first) qs.append(","); qs.append(values[i]); first = false; } qs.append(");"); QSqlQuery q(QSqlDatabase::database(connection_name)); if (q.exec(qs)) { updateTable(); emit tableChanged(); } else qDebug() << q.lastError(); // qDebug() << q.lastQuery(); } void SQLTableWidget::on_actionFiltersClear_triggered() { filters_active = false; foreach(SQLFilterEdit * l, column_filters) l->clear(); filters_active = true; updateTable(); } void SQLTableWidget::on_view_clicked(const QModelIndex & index) { emit rowClicked(index.row()); emit recordClicked(model->record(index.row())); } void SQLTableWidget::del_triggered() { QModelIndexList si = ui->view->selectionModel()->selectedIndexes(); QSet ids; foreach(const QModelIndex & i, si) ids << model->index(i.row(), 0).data().toInt(); if (ids.isEmpty()) return; QString qs("DELETE FROM " + table_ + " WHERE " + column_props[0].name + " IN ("); bool first = true; foreach(int i, ids) { if (!first) qs.append(","); qs.append(QString::number(i)); first = false; } qs.append(");"); // qDebug() << qs; return; QSqlQuery q(QSqlDatabase::database(connection_name)); if (q.exec(qs)) { updateTable(); emit tableChanged(); } else qDebug() << q.lastError(); } void SQLTableWidget::setColumnVisible(int ind, bool visible) { if (!columnExists(ind)) return; column_props[ind].visible = visible; if (ind == 0) { ui->view->setColumnHidden(0, !visible); if (visible) ui->view->horizontalHeader()->resizeSection(0, ui->view->horizontalHeader()->defaultSectionSize()); } // qDebug() << ind << on; updateTable(); for (int i = 0; i < ui->view->horizontalHeader()->count(); ++i) { column_news[mapColumn(i)]->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); column_filters[mapColumn(i)]->setFixedWidth(ui->view->horizontalHeader()->sectionSize(i)); } } bool SQLTableWidget::addRelation(const QString & this_column, const QString & other_table, const QString & other_key, const QString & other_column) { QString wr = this_column + ";" + other_table + ";" + other_key + ";" + other_column; if (!wait_rels.contains(wr)) wait_rels << wr; ColumnProperties * cp = const_cast(columnProperty(this_column)); if (cp == 0) return false; cp->relation_table = other_table; cp->relation_key = other_key; cp->relation_column = other_column; cp->relation_type = ColumnProperties::typeFromString(getColumnType(other_table, other_column)); cp->relation_list = getColumnValues(other_table, other_key, other_column, connection_name); for (int i = 0; i < column_props.size(); ++i) column_news[i]->setProp(column_props[i]); for (int i = 0; i < column_props.size(); ++i) column_filters[i]->setProp(column_props[i]); updateTable(); return true; } void SQLTableWidget::addTranslation(const QString & file) { QPIConfig conf(file, QIODevice::ReadOnly, QPIConfig::Config); QPIConfig::Branch ae = conf.allLeaves(); foreach(QPIConfig::Entry * e, ae) translates[e->name()] = QPair(e->value(), e->comment()); } void SQLTableWidget::addFixedColumnTranslation(const QString & col_name, const QString & col_tr, const QString & col_tt) { fixed_translates[col_name] = QPair(col_tr, col_tt); updateTable(); } void SQLTableWidget::selectId(int id) { if (!model) return; for (int i = 0; i < model->rowCount(); ++i) if (model->data(model->index(i, 0)).toInt() == id) { ui->view->selectRow(i); break; } } void SQLTableWidget::setAdditionalActions(QList a) { foreach(QAction * i, add_actions) popup_menu.removeAction(i); add_actions = a; popup_menu.addActions(a); } void SQLTableWidget::setCustomQuery(const QString & q) { custom_query = q; updateTable(); } QString SQLTableWidget::preprocessScript(QString text) { QTextStream s(&text, QIODevice::ReadOnly); QString out; int ce = 0; while (!s.atEnd()) { QString line = s.readLine(); ce = line.indexOf("--"); if (ce >= 0) line.chop(line.length() - ce); out.append(line).append("\n"); } int cs = out.indexOf("/*"); while (cs >= 0) { ce = out.indexOf("*/", cs); if (ce > cs) out.remove(cs, ce - cs + 2); cs = out.indexOf("/*"); } // qDebug() << out; return out; } bool SQLTableWidget::executeScript(const QString & text_, QSqlDatabase db, bool skip_errors, bool sqlite) { QString text = preprocessScript(text_); int ls = 0, le = text.indexOf(';'); QSqlQuery q(db); db.transaction(); while (le > 0) { QString line = text.mid(ls, le - ls + 1).trimmed(), fword; if (sqlite) line.replace("auto_increment", "autoincrement"); QTextStream(&line, QIODevice::ReadOnly) >> fword; fword = fword.trimmed().toLower(); if (fword == "exec" || fword == "execute") { line = line.right(line.length() - fword.length()).trimmed(); if (line.endsWith(";")) line.chop(1); line = line.trimmed(); if (line.endsWith("'") || line.endsWith("\"")) line.chop(1); if (line.startsWith("'") || line.startsWith("\"")) line.remove(0, 1); executeScriptFile(line, db, skip_errors, sqlite); } else { if (!q.exec(line)) { qDebug() << q.lastError(); if (!skip_errors) return false; } } ls = le + 1; le = text.indexOf(';', ls); } db.commit(); return true; } bool SQLTableWidget::executeScriptFile(const QString & file, QSqlDatabase db, bool skip_errors, bool sqlite) { QFile f(_dir + file); if (!f.open(QIODevice::ReadOnly)) { qDebug() << "Can`t open file" << file << "!"; return false; } QString pd = _dir; _dir = QFileInfo(f).absolutePath() + "/"; QByteArray ba = f.readAll(); bool ok = executeScript(QString::fromUtf8(ba.data(), ba.size()), db, skip_errors, sqlite); f.close(); _dir = pd; return ok; } void SQLTableWidget::column_triggered(bool on) { setColumnVisible(((QAction *)sender())->data().toInt(), on); } void SQLTableWidget::header_sectionResized(int logicalIndex, int oldSize, int newSize) { column_news[mapColumn(logicalIndex)]->setFixedWidth(newSize); column_filters[mapColumn(logicalIndex)]->setFixedWidth(newSize); } void SQLTableWidget::header_sortIndicatorChanged(int logicalIndex, Qt::SortOrder order) { updateTable(); } bool SQLTableWidget::connectToDatabase(const QString & config, const QString & conn_name) { bool ok = true; { QPIConfig conf(config, QIODevice::ReadOnly, QPIConfig::Config); if (!conf.isOpen()) ok = false; else { QSqlDatabase base = QSqlDatabase::addDatabase(conf.getValue("driver", "QMYSQL").toString(), conn_name); if (!base.isValid()) { qDebug() << "[QSqlDatabase::addDatabase] Error:" << base.lastError(); ok = false; } else { base.setHostName(conf.getValue("host").toString()); base.setPort(conf.getValue("port", -1).toInt()); base.setDatabaseName(conf.getValue("database").toString()); if (!base.open(conf.getValue("login").toString(), conf.getValue("password").toString())) { qDebug() << "[QSqlDatabase::open] Error:" << base.lastError(); ok = false; } } } } if (!ok) QSqlDatabase::removeDatabase(conn_name); /*QSqlQuery q; QString dbname = conf.getValue("database", "").stringValue(); bool dbex = false; if (!q.exec("SHOW DATABASES;")) { qDebug() << "[SHOW DATABASES]" << q.lastError(); return false; } while (q.next()) if (q.value(0) == dbname) {dbex = true; break;} if (!dbex) { if (!q.exec("CREATE DATABASE " + dbname + ";")) { qDebug() << "[CREATE DATABASE]" << q.lastError(); return false; } } if (!q.exec("USE " + dbname + ";")) { qDebug() << "[USE]" << q.lastError(); return false; }*/ return ok; } QTableView * SQLTableWidget::tableView() { return ui->view; } bool SQLTableWidget::lineNewVisible() const { return ui->widgetNew->isVisibleTo(ui->pageTable); } bool SQLTableWidget::lineFilterVisible() const { return ui->widgetFilter->isVisibleTo(ui->pageTable); } QSqlRecord SQLTableWidget::currentRecord() const { if (model) return model->record(ui->view->currentIndex().row()); return QSqlRecord(); } void SQLTableWidget::setTableVisible(bool on) { ui->stackedWidget->setCurrentIndex(on ? 1 : 0); } void SQLTableWidget::setLineNewVisible(bool on) { ui->widgetNew->setVisible(on); ui->buttonAdd->setVisible(on); } void SQLTableWidget::setLineFilterVisible(bool on) { ui->widgetFilter->setVisible(on); ui->buttonFilterConfig->setVisible(on); } void SQLTableWidget::setReadOnly(bool yes) { read_only = yes; ui->scrollAreaNew->setDisabled(yes); ui->buttonAdd->setDisabled(yes); } void SQLTableWidget::scrolled(int value) { ui->scrollAreaNew->horizontalScrollBar()->setValue(value); ui->scrollAreaFilter->horizontalScrollBar()->setValue(value); }