diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 94575d82..2a906480 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -21,6 +21,7 @@ #include "FindDialog.h" #include "SQLiteSyntaxHighlighter.h" #include "sqltextedit.h" +#include "sqlitetablemodel.h" MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), @@ -51,6 +52,8 @@ void MainWindow::init() // Init the SQL log dock db.mainWindow = this; + m_browseTableModel = new SqliteTableModel(this, &db); + // Set up the db tree widget ui->dbTreeWidget->setColumnHidden(1, true); ui->dbTreeWidget->setColumnWidth(0, 300); @@ -63,7 +66,8 @@ void MainWindow::init() createSyntaxHighlighters(); // Set up DB models - ui->dataTable->setModel(browseTableModel); + //ui->dataTable->setModel(browseTableModel); + ui->dataTable->setModel(m_browseTableModel); queryResultListModel = new QStandardItemModel(this); ui->queryResultTableView->setModel(queryResultListModel); @@ -270,43 +274,45 @@ void MainWindow::populateStructure() void MainWindow::populateTable( const QString & tablename, bool keepColumnWidths) { - bool mustreset = false; QApplication::setOverrideCursor( Qt::WaitCursor ); - if (tablename.compare(db.curBrowseTableName)!=0) - { - mustreset = true; - curBrowseOrderByIndex = 1; - curBrowseOrderByMode = ORDERMODE_ASC; - } + if(!tablename.isEmpty()) + m_browseTableModel->setQuery(QString("SELECT * FROM `%1`").arg(tablename)); +// bool mustreset = false; +// if (tablename.compare(db.curBrowseTableName)!=0) +// { +// mustreset = true; +// curBrowseOrderByIndex = 1; +// curBrowseOrderByMode = ORDERMODE_ASC; +// } - QString orderby = QString::number(curBrowseOrderByIndex) + " " + (curBrowseOrderByMode == ORDERMODE_ASC ? "ASC" : "DESC"); - if(!db.browseTable(tablename, orderby)) - { - browseTableModel->setRowCount(0); - browseTableModel->setColumnCount(0); - QApplication::restoreOverrideCursor(); - if(findWin) - findWin->resetFields(db.getTableFields("")); - return; - } +// QString orderby = QString::number(curBrowseOrderByIndex) + " " + (curBrowseOrderByMode == ORDERMODE_ASC ? "ASC" : "DESC"); +// if(!db.browseTable(tablename, orderby)) +// { +// browseTableModel->setRowCount(0); +// browseTableModel->setColumnCount(0); +// QApplication::restoreOverrideCursor(); +// if(findWin) +// findWin->resetFields(db.getTableFields("")); +// return; +// } - // Activate the add and delete record buttons and editing only if a table has been selected - bool is_table = db.getObjectByName(tablename).gettype() == "table"; - ui->buttonNewRecord->setEnabled(is_table); - ui->buttonDeleteRecord->setEnabled(is_table); - ui->dataTable->setEditTriggers(is_table ? QAbstractItemView::DoubleClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed : QAbstractItemView::NoEditTriggers); +// // Activate the add and delete record buttons and editing only if a table has been selected +// bool is_table = db.getObjectByName(tablename).gettype() == "table"; +// ui->buttonNewRecord->setEnabled(is_table); +// ui->buttonDeleteRecord->setEnabled(is_table); +// ui->dataTable->setEditTriggers(is_table ? QAbstractItemView::DoubleClicked | QAbstractItemView::AnyKeyPressed | QAbstractItemView::EditKeyPressed : QAbstractItemView::NoEditTriggers); - if (mustreset){ - updateTableView(0, keepColumnWidths); - if (findWin) findWin->resetFields(db.getTableFields(db.curBrowseTableName)); - } else { - updateTableView(-1, keepColumnWidths); - } - //got to keep findWin in synch - if(findWin) - findWin->resetFields(); - if(editWin) - editWin->reset(); +// if (mustreset){ +// updateTableView(0, keepColumnWidths); +// if (findWin) findWin->resetFields(db.getTableFields(db.curBrowseTableName)); +// } else { +// updateTableView(-1, keepColumnWidths); +// } +// //got to keep findWin in synch +// if(findWin) +// findWin->resetFields(); +// if(editWin) +// editWin->reset(); QApplication::restoreOverrideCursor(); } @@ -423,52 +429,52 @@ void MainWindow::updateTableView(int lineToSelect, bool keepColumnWidths) { QApplication::setOverrideCursor( Qt::WaitCursor ); - browseTableModel->setRowCount(db.getRecordCount()); - browseTableModel->setColumnCount(db.browseFields.count()); - browseTableModel->setHorizontalHeaderLabels(db.browseFields); +// browseTableModel->setRowCount(db.getRecordCount()); +// browseTableModel->setColumnCount(db.browseFields.count()); +// browseTableModel->setHorizontalHeaderLabels(db.browseFields); - rowList tab = db.browseRecs; - int maxRecs = db.getRecordCount(); - gotoValidator->setRange(0, maxRecs); +// rowList tab = db.browseRecs; +// int maxRecs = db.getRecordCount(); +// gotoValidator->setRange(0, maxRecs); - if ( maxRecs > 0 ) { +// if ( maxRecs > 0 ) { - int rowNum = 0; - int colNum = 0; - QString rowLabel; - for (int i = 0; i < tab.size(); ++i) - { - rowLabel.setNum(rowNum+1); - browseTableModel->setVerticalHeaderItem(rowNum, new QStandardItem(rowLabel)); - colNum = 0; - QList rt = tab[i]; - for (int e = 1; e < rt.size(); ++e) - { - QString content = rt[e]; +// int rowNum = 0; +// int colNum = 0; +// QString rowLabel; +// for (int i = 0; i < tab.size(); ++i) +// { +// rowLabel.setNum(rowNum+1); +// browseTableModel->setVerticalHeaderItem(rowNum, new QStandardItem(rowLabel)); +// colNum = 0; +// QList rt = tab[i]; +// for (int e = 1; e < rt.size(); ++e) +// { +// QString content = rt[e]; - QStandardItem* item = new QStandardItem(content); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - item->setToolTip(wrapText(content)); - browseTableModel->setItem( rowNum, colNum, item); - colNum++; - } - rowNum++; - if (rowNum==maxRecs) break; - } - } +// QStandardItem* item = new QStandardItem(content); +// item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); +// item->setToolTip(wrapText(content)); +// browseTableModel->setItem( rowNum, colNum, item); +// colNum++; +// } +// rowNum++; +// if (rowNum==maxRecs) break; +// } +// } - if(!keepColumnWidths) { - for(int i=0;icolumnCount();++i) - { - ui->dataTable->resizeColumnToContents(i); - if( ui->dataTable->columnWidth(i) > 400 ) - ui->dataTable->setColumnWidth(i, 400); - } - } - if (lineToSelect!=-1){ - selectTableLine(lineToSelect); - } - setRecordsetLabel(); +// if(!keepColumnWidths) { +// for(int i=0;icolumnCount();++i) +// { +// ui->dataTable->resizeColumnToContents(i); +// if( ui->dataTable->columnWidth(i) > 400 ) +// ui->dataTable->setColumnWidth(i, 400); +// } +// } +// if (lineToSelect!=-1){ +// selectTableLine(lineToSelect); +// } +// setRecordsetLabel(); QApplication::restoreOverrideCursor(); } diff --git a/src/MainWindow.h b/src/MainWindow.h index 2a9c38f1..a95674b7 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -15,6 +15,7 @@ class QStandardItemModel; class QIntValidator; class QLabel; class QModelIndex; +class SqliteTableModel; namespace Ui { class MainWindow; @@ -53,6 +54,7 @@ private: Ui::MainWindow* ui; QStandardItemModel *browseTableModel; + SqliteTableModel* m_browseTableModel; QStandardItemModel *queryResultListModel; QMenu *popupTableMenu; QMenu *recentFilesMenu; diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp new file mode 100644 index 00000000..a5c79a7d --- /dev/null +++ b/src/sqlitetablemodel.cpp @@ -0,0 +1,152 @@ +#include "sqlitetablemodel.h" + +#include "sqlitedb.h" + +#include + +SqliteTableModel::SqliteTableModel(QObject* parent, DBBrowserDB* db) + : QAbstractTableModel(parent) + , m_db(db) + , m_rowCount(0) + , m_columnCount(0) + , m_chunkSize(1000) +{ +} + +void SqliteTableModel::setChunkSize(size_t chunksize) +{ + m_chunkSize = chunksize; +} + +void SqliteTableModel::setQuery(const QString& sQuery) +{ + if(!m_db->isOpen()) + return; + + sqlite3_stmt *stmt; + m_rowCount = 0; + m_sQuery = sQuery; + + // do a count query to get the full row count in a fast manner + QString sCountQuery = QString("SELECT COUNT(*) FROM (%1);").arg(sQuery); + QByteArray utf8Query = sCountQuery.toUtf8(); + int status = sqlite3_prepare_v2(m_db->_db, utf8Query, utf8Query.size(), &stmt, NULL); + + if(SQLITE_OK == status) + { + status = sqlite3_step(stmt); + if(SQLITE_ROW == status) + { + m_columnCount = sqlite3_data_count(stmt); + QString sCount = QString::fromUtf8((const char *) sqlite3_column_text(stmt, 0)); + m_rowCount = sCount.toInt(); + } + } + sqlite3_finalize(stmt); + + // now fetch the first 100 entries and get headers + m_headers.clear(); + m_columnCount = 0; + QString sLimitQuery = QString("%1 LIMIT 0, %2;").arg(sQuery).arg(m_chunkSize); + utf8Query = sLimitQuery.toUtf8(); + status = sqlite3_prepare_v2(m_db->_db, utf8Query, utf8Query.size(), &stmt, NULL); + + if(SQLITE_OK == status) + { + status = sqlite3_step(stmt); + + if(SQLITE_ROW == status) + { + m_columnCount = sqlite3_data_count(stmt); + for (int i = 0; i < m_columnCount; ++i) + m_headers.append(QString::fromUtf8((const char *)sqlite3_column_name(stmt, i))); + + int row = 0; + // row data starts here + do + { + QStringList rowdata; + for (int i = 0; i < m_columnCount; ++i) + rowdata.append(QString::fromUtf8((const char *)sqlite3_column_text(stmt, i))); + m_data.insert(row++, rowdata); + } while(sqlite3_step(stmt) == SQLITE_ROW); + } + } + sqlite3_finalize(stmt); + + emit layoutChanged(); +} + +int SqliteTableModel::rowCount(const QModelIndex &parent) const +{ + (void)parent; + return m_data.size(); // current fetched row count +} + +int SqliteTableModel::columnCount(const QModelIndex &parent) const +{ + (void)parent; + return m_columnCount; +} + +QVariant SqliteTableModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + return m_headers.at(section); + else + return QString("Row %1").arg(section); +} + +QVariant SqliteTableModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= m_rowCount) + return QVariant(); + + if (role == Qt::DisplayRole) + { + return m_data[index.row()].at(index.column()); + } + else + return QVariant(); +} + +bool SqliteTableModel::canFetchMore(const QModelIndex &parent) const +{ + return m_data.size() < m_rowCount; +} + +void SqliteTableModel::fetchMore(const QModelIndex& parent) +{ + int currentsize = m_data.size(); + int row = m_data.size(); + QString sLimitQuery = QString("%1 LIMIT %2, %3;").arg(m_sQuery).arg(row).arg(row + m_chunkSize); + QByteArray utf8Query = sLimitQuery.toUtf8(); + sqlite3_stmt *stmt; + int status = sqlite3_prepare_v2(m_db->_db, utf8Query, utf8Query.size(), &stmt, NULL); + + if(SQLITE_OK == status) + { + status = sqlite3_step(stmt); + + if(SQLITE_ROW == status) + { + do + { + QStringList rowdata; + for (int i = 0; i < m_columnCount; ++i) + rowdata.append(QString::fromUtf8((const char *)sqlite3_column_text(stmt, i))); + Q_ASSERT(m_headers.size() == rowdata.size()); + m_data.insert(row++, rowdata); + } while(sqlite3_step(stmt) == SQLITE_ROW); + } + } + sqlite3_finalize(stmt); + beginInsertRows(parent, currentsize, m_data.size()); + endInsertRows(); +} diff --git a/src/sqlitetablemodel.h b/src/sqlitetablemodel.h new file mode 100644 index 00000000..e0accf8d --- /dev/null +++ b/src/sqlitetablemodel.h @@ -0,0 +1,42 @@ +#ifndef SQLITETABLEMODEL_H +#define SQLITETABLEMODEL_H + +#include +#include + +class DBBrowserDB; + +class SqliteTableModel : public QAbstractTableModel +{ + Q_OBJECT +public: + explicit SqliteTableModel(QObject *parent = 0, DBBrowserDB* db = 0); + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QVariant data(const QModelIndex &index, int role) const; + bool canFetchMore(const QModelIndex &parent) const; + void fetchMore(const QModelIndex &parent); + size_t queryMore(size_t offset); + + void setQuery(const QString& sQuery); + void setChunkSize(size_t chunksize); + +signals: + +public slots: + + +private: + DBBrowserDB* m_db; + int m_rowCount; + int m_columnCount; + QStringList m_headers; + QMap m_data; + QString m_sQuery; + + size_t m_chunkSize; +}; + +#endif // SQLITETABLEMODEL_H diff --git a/src/src.pro b/src/src.pro index 9433049d..2787f12e 100644 --- a/src/src.pro +++ b/src/src.pro @@ -25,7 +25,8 @@ HEADERS += \ ExtendedTableWidget.h \ grammar/Sqlite3Lexer.hpp \ grammar/Sqlite3Parser.hpp \ - grammar/sqlite3TokenTypes.hpp + grammar/sqlite3TokenTypes.hpp \ + sqlitetablemodel.h SOURCES += \ sqlitedb.cpp \ @@ -43,7 +44,8 @@ SOURCES += \ sqlitetypes.cpp \ ExtendedTableWidget.cpp \ grammar/Sqlite3Lexer.cpp \ - grammar/Sqlite3Parser.cpp + grammar/Sqlite3Parser.cpp \ + sqlitetablemodel.cpp # create a unittest option CONFIG(unittest) {