From d9cd62ba4993c04cae213cc8e5b5150d0163d41a Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sat, 16 Mar 2013 18:31:12 +0100 Subject: [PATCH 1/4] Implement an extended table widget to add proper copy to clipboard support Extend the standard table widget class to make it possible to copy multiple cells to the clipboard. --- src/ExtendedTableWidget.cpp | 61 +++++++++++++++++++++++++++++++++++++ src/ExtendedTableWidget.h | 21 +++++++++++++ src/MainWindow.ui | 14 ++++++--- src/src.pro | 6 ++-- 4 files changed, 96 insertions(+), 6 deletions(-) create mode 100644 src/ExtendedTableWidget.cpp create mode 100644 src/ExtendedTableWidget.h diff --git a/src/ExtendedTableWidget.cpp b/src/ExtendedTableWidget.cpp new file mode 100644 index 00000000..c4939758 --- /dev/null +++ b/src/ExtendedTableWidget.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include "ExtendedTableWidget.h" + +ExtendedTableWidget::ExtendedTableWidget(int rows, int columns, QWidget* parent) : + QTableWidget(rows, columns, parent) +{ +} + + +ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) : + QTableWidget(parent) +{ +} + +void ExtendedTableWidget::copy() +{ + // Get list of selected items + QItemSelectionModel* selection = selectionModel(); + QModelIndexList indices = selection->selectedIndexes(); + + // Abort if there's nothing to copy + if(indices.size() == 0) + return; + + // Sort the items by row, then by column + qSort(indices); + + // Go through all the items... + QString result; + QModelIndex prev = indices.front(); + indices.removeFirst(); + foreach(QModelIndex index, indices) + { + // Add the content of this cell to the clipboard string + result.append(QString("\"%1\"").arg(prev.data().toString())); + + // If this is a new row add a line break, if not add a tab for cell separation + if(index.row() != prev.row()) + result.append("\r\n"); + else + result.append("\t"); + + prev = index; + } + result.append(QString("\"%1\"\r\n").arg(indices.last().data().toString())); // And the last cell + + // And finally add it to the clipboard + qApp->clipboard()->setText(result); +} + +void ExtendedTableWidget::keyPressEvent(QKeyEvent* event) +{ + // Call a custom copy method when Ctrl-C is pressed + if(event->matches(QKeySequence::Copy)) + copy(); + else + QTableWidget::keyPressEvent(event); +} diff --git a/src/ExtendedTableWidget.h b/src/ExtendedTableWidget.h new file mode 100644 index 00000000..e5a780e2 --- /dev/null +++ b/src/ExtendedTableWidget.h @@ -0,0 +1,21 @@ +#ifndef __EXTENDEDTABLEWIDGET_H__ +#define __EXTENDEDTABLEWIDGET_H__ + +#include + +class ExtendedTableWidget : public QTableWidget +{ + Q_OBJECT + +public: + explicit ExtendedTableWidget(int rows, int columns, QWidget* parent = 0); + explicit ExtendedTableWidget(QWidget* parent = 0); + +private: + void copy(); + +protected: + virtual void keyPressEvent(QKeyEvent* event); +}; + +#endif diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 9f637c6a..b15587da 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -205,12 +205,12 @@ - + This is the database view. You can double-click any record to edit its contents in the cell editor window. - QAbstractItemView::SingleSelection + QAbstractItemView::ExtendedSelection QAbstractItemView::ScrollPerPixel @@ -316,8 +316,8 @@ 0 0 - 763 - 494 + 278 + 444 @@ -1399,6 +1399,11 @@ QTextEdit
sqltextedit.h
+ + ExtendedTableWidget + QTableWidget +
ExtendedTableWidget.h
+
dbTreeWidget @@ -2169,5 +2174,6 @@ deleteField() loadPragmas() savePragmas() + copy() diff --git a/src/src.pro b/src/src.pro index a3bdffe9..8eb6ec88 100644 --- a/src/src.pro +++ b/src/src.pro @@ -24,7 +24,8 @@ HEADERS += \ ExportCsvDialog.h \ ImportCsvDialog.h \ sqltextedit.h \ - sqlitetypes.h + sqlitetypes.h \ + ExtendedTableWidget.h SOURCES += \ sqlitedb.cpp \ @@ -41,7 +42,8 @@ SOURCES += \ ExportCsvDialog.cpp \ ImportCsvDialog.cpp \ sqltextedit.cpp \ - sqlitetypes.cpp + sqlitetypes.cpp \ + ExtendedTableWidget.cpp # create a unittest option CONFIG(unittest) { From 5e8c14e942603a1182cfda6a64c4e0b34f9dc844 Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sat, 16 Mar 2013 19:10:03 +0100 Subject: [PATCH 2/4] Make the QTableWidget a QTableView Rewrite some code to use a QTableView widget instead of a QTableWidget in the browse tab of the main window, or more presicely in the new extended table widget class. This way the widget and the data model are separated which on the one hand means a bit more work on our side but on the other hand also gives us a bit more flexibility. And more importantly at the moment: This means both, the browse tab and the sql tab, use a table view now - that's going to be helpful for the next commit... --- src/ExtendedTableWidget.cpp | 10 ++---- src/ExtendedTableWidget.h | 5 ++- src/MainWindow.cpp | 64 ++++++++++++++++++++----------------- src/MainWindow.h | 4 ++- src/MainWindow.ui | 36 ++++++++++----------- 5 files changed, 59 insertions(+), 60 deletions(-) diff --git a/src/ExtendedTableWidget.cpp b/src/ExtendedTableWidget.cpp index c4939758..cb0f64f2 100644 --- a/src/ExtendedTableWidget.cpp +++ b/src/ExtendedTableWidget.cpp @@ -4,14 +4,8 @@ #include #include "ExtendedTableWidget.h" -ExtendedTableWidget::ExtendedTableWidget(int rows, int columns, QWidget* parent) : - QTableWidget(rows, columns, parent) -{ -} - - ExtendedTableWidget::ExtendedTableWidget(QWidget* parent) : - QTableWidget(parent) + QTableView(parent) { } @@ -57,5 +51,5 @@ void ExtendedTableWidget::keyPressEvent(QKeyEvent* event) if(event->matches(QKeySequence::Copy)) copy(); else - QTableWidget::keyPressEvent(event); + QTableView::keyPressEvent(event); } diff --git a/src/ExtendedTableWidget.h b/src/ExtendedTableWidget.h index e5a780e2..7e8adbbf 100644 --- a/src/ExtendedTableWidget.h +++ b/src/ExtendedTableWidget.h @@ -1,14 +1,13 @@ #ifndef __EXTENDEDTABLEWIDGET_H__ #define __EXTENDEDTABLEWIDGET_H__ -#include +#include -class ExtendedTableWidget : public QTableWidget +class ExtendedTableWidget : public QTableView { Q_OBJECT public: - explicit ExtendedTableWidget(int rows, int columns, QWidget* parent = 0); explicit ExtendedTableWidget(QWidget* parent = 0); private: diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 4a05abe6..c137f0de 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -27,6 +27,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), + browseTableModel(new QStandardItemModel(this)), editWin(new EditDialog(this)), findWin(0) { @@ -63,7 +64,9 @@ void MainWindow::init() // Create the SQL sytax highlighter sqliteHighlighterTabSql = new SQLiteSyntaxHighlighter(ui->sqlTextEdit->document()); - // Set up DB model + // Set up DB models + ui->dataTable->setModel(browseTableModel); + queryResultListModel = new QStandardItemModel(this); ui->queryResultTableView->setModel(queryResultListModel); @@ -114,7 +117,6 @@ void MainWindow::init() setAcceptDrops(true); setWindowTitle(QApplication::applicationName()); - // Fonts for edit fields QFont font("Monospace"); font.setStyleHint(QFont::TypeWriter); @@ -285,9 +287,10 @@ void MainWindow::populateTable( const QString & tablename, bool keepColumnWidths } QString orderby = QString::number(curBrowseOrderByIndex) + " " + (curBrowseOrderByMode == ORDERMODE_ASC ? "ASC" : "DESC"); - if (!db.browseTable(tablename, orderby)){ - ui->dataTable->setRowCount( 0 ); - ui->dataTable->setColumnCount( 0 ); + if(!db.browseTable(tablename, orderby)) + { + browseTableModel->setRowCount(0); + browseTableModel->setColumnCount(0); QApplication::restoreOverrideCursor(); if(findWin) findWin->resetFields(db.getTableFields("")); @@ -389,9 +392,10 @@ void MainWindow::addRecord() void MainWindow::deleteRecord() { - if (ui->dataTable->currentRow()!=-1){ - int lastselected = ui->dataTable->currentRow(); - db.deleteRecord(ui->dataTable->currentRow()); + if(ui->dataTable->currentIndex().row() != -1) + { + int lastselected = ui->dataTable->currentIndex().row(); + db.deleteRecord(lastselected); populateTable(db.curBrowseTableName); int nextselected = lastselected ; if (nextselected > db.getRecordCount()){ @@ -427,9 +431,9 @@ void MainWindow::updateTableView(int lineToSelect, bool keepColumnWidths) { QApplication::setOverrideCursor( Qt::WaitCursor ); - ui->dataTable->setRowCount(db.getRecordCount()); - ui->dataTable->setColumnCount( db.browseFields.count() ); - ui->dataTable->setHorizontalHeaderLabels(db.browseFields); + browseTableModel->setRowCount(db.getRecordCount()); + browseTableModel->setColumnCount(db.browseFields.count()); + browseTableModel->setHorizontalHeaderLabels(db.browseFields); rowList tab = db.browseRecs; int maxRecs = db.getRecordCount(); @@ -443,17 +447,17 @@ void MainWindow::updateTableView(int lineToSelect, bool keepColumnWidths) for (int i = 0; i < tab.size(); ++i) { rowLabel.setNum(rowNum+1); - ui->dataTable->setVerticalHeaderItem(rowNum, new QTableWidgetItem( rowLabel )); + browseTableModel->setVerticalHeaderItem(rowNum, new QStandardItem(rowLabel)); colNum = 0; QStringList& rt = tab[i]; for (int e = 1; e < rt.size(); ++e) { QString& content = rt[e]; - QTableWidgetItem* item = new QTableWidgetItem(content); + QStandardItem* item = new QStandardItem(content); item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); item->setToolTip(wrapText(content)); - ui->dataTable->setItem( rowNum, colNum, item); + browseTableModel->setItem( rowNum, colNum, item); colNum++; } rowNum++; @@ -462,7 +466,7 @@ void MainWindow::updateTableView(int lineToSelect, bool keepColumnWidths) } if(!keepColumnWidths) { - for(int i = 0; i < ui->dataTable->columnCount(); ++i) + for(int i=0;icolumnCount();++i) { ui->dataTable->resizeColumnToContents(i); if( ui->dataTable->columnWidth(i) > 400 ) @@ -480,13 +484,13 @@ void MainWindow::selectTableLine(int lineToSelect) { ui->dataTable->clearSelection(); ui->dataTable->selectRow(lineToSelect); - ui->dataTable->setCurrentCell(lineToSelect, 0); - ui->dataTable->scrollToItem(ui->dataTable->itemAt(lineToSelect, 0)); + ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(lineToSelect, 0)); + ui->dataTable->scrollTo(ui->dataTable->currentIndex().sibling(lineToSelect, 0)); } void MainWindow::navigatePrevious() { - int curRow = ui->dataTable->currentRow(); + int curRow = ui->dataTable->currentIndex().row(); curRow -= 100; if(curRow < 0) curRow = 0; updateTableView(curRow); @@ -495,9 +499,10 @@ void MainWindow::navigatePrevious() void MainWindow::navigateNext() { - int curRow = ui->dataTable->currentRow(); + int curRow = ui->dataTable->currentIndex().row(); curRow += 100; - if(curRow >= ui->dataTable->rowCount()) curRow = ui->dataTable->rowCount()-1; + if(curRow >= browseTableModel->rowCount()) + curRow = browseTableModel->rowCount()-1; updateTableView(curRow); } @@ -518,7 +523,7 @@ void MainWindow::setRecordsetLabel() { int from = ui->dataTable->verticalHeader()->visualIndexAt(0) + 1; int to = ui->dataTable->verticalHeader()->visualIndexAt(ui->dataTable->height()) - 1; - int total = ui->dataTable->rowCount(); + int total = browseTableModel->rowCount(); if(to == -2) to = total; @@ -709,9 +714,9 @@ void MainWindow::updateRecordText(int row, int col, const QString& newtext) QStringList& rt = tab[row]; QString& cv = rt[col+1];//must account for rowid - QTableWidgetItem* item = new QTableWidgetItem(cv); + QStandardItem* item = new QStandardItem(cv); item->setToolTip( wrapText(cv) ); - ui->dataTable->setItem(row, col, item); + browseTableModel->setItem(row, col, item); } @@ -719,7 +724,7 @@ void MainWindow::editWinAway() { editWin->hide(); activateWindow(); - ui->dataTable->setRangeSelected(QTableWidgetSelectionRange(editWin->getCurrentRow(), editWin->getCurrentCol(), editWin->getCurrentRow(), editWin->getCurrentCol()), true); + ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(editWin->getCurrentRow(), editWin->getCurrentCol())); } void MainWindow::editText(int row, int col) @@ -732,9 +737,10 @@ void MainWindow::editText(int row, int col) editWin->show(); } -void MainWindow::doubleClickTable( int row, int col ) +void MainWindow::doubleClickTable(const QModelIndex& index) { - if ((row==-1) || (col==-1)){ + if(!index.isValid()) + { qDebug("no cell selected"); return; } @@ -743,9 +749,7 @@ void MainWindow::doubleClickTable( int row, int col ) if(db.getObjectByName(ui->comboBrowseTable->currentText()).gettype() != "table") return; - int realRow = row; - - editText(realRow , col); + editText(index.row(), index.column()); } void MainWindow::executeQuery() @@ -1132,7 +1136,7 @@ void MainWindow::browseTableHeaderClicked(int logicalindex) // select the first item in the column so the header is bold // we might try to select the last selected item - ui->dataTable->setCurrentCell(0, logicalindex); + ui->dataTable->setCurrentIndex(ui->dataTable->currentIndex().sibling(0, logicalindex)); } void MainWindow::resizeEvent(QResizeEvent*) diff --git a/src/MainWindow.h b/src/MainWindow.h index 8625252c..d8ed23a0 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -14,6 +14,7 @@ class SQLiteSyntaxHighlighter; class QStandardItemModel; class QIntValidator; class QLabel; +class QModelIndex; namespace Ui { class MainWindow; @@ -51,6 +52,7 @@ private: Ui::MainWindow* ui; + QStandardItemModel *browseTableModel; QStandardItemModel *queryResultListModel; QMenu *popupTableMenu; QMenu *popupFieldMenu; @@ -128,7 +130,7 @@ private slots: virtual void updateRecordText( int row, int col, const QString& newtext ); virtual void editWinAway(); virtual void editText( int row, int col ); - virtual void doubleClickTable( int row, int col ); + virtual void doubleClickTable(const QModelIndex& index); virtual void executeQuery(); virtual void importTableFromCSV(); virtual void exportTableToCSV(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index b15587da..9880b1d5 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -316,7 +316,7 @@ 0 0 - 278 + 763 444 @@ -1702,22 +1702,6 @@ - - dataTable - cellDoubleClicked(int,int) - MainWindow - doubleClickTable(int,int) - - - 99 - 113 - - - 399 - 299 - - - mainTab currentChanged(int) @@ -2134,6 +2118,22 @@ + + dataTable + doubleClicked(QModelIndex) + MainWindow + doubleClickTable(QModelIndex) + + + 399 + 211 + + + 399 + 299 + + + fileOpen() @@ -2148,7 +2148,7 @@ browseRefresh() compact() helpWhatsThis() - doubleClickTable(int,int) + doubleClickTable(QModelIndex) browseTableHeaderClicked(int) mainTabSelected(int) executeQuery() From e548224bd942989a72915b89fd9eda2503e62fac Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sat, 16 Mar 2013 19:24:08 +0100 Subject: [PATCH 3/4] Add proper copy support to the SQL tab table view widget Allow copying data from the result table view widget in the SQL tab of the main window. --- src/MainWindow.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 9880b1d5..de2be14d 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -843,7 +843,7 @@
- + Query generated data @@ -854,7 +854,7 @@ QAbstractItemView::NoEditTriggers - QAbstractItemView::NoSelection + QAbstractItemView::ExtendedSelection QAbstractItemView::ScrollPerPixel @@ -1401,7 +1401,7 @@ ExtendedTableWidget - QTableWidget + QTableView
ExtendedTableWidget.h
From 80e4708fc21b3c606cc7c46be81cdda28b44f12c Mon Sep 17 00:00:00 2001 From: Martin Kleusberg Date: Sat, 16 Mar 2013 19:35:27 +0100 Subject: [PATCH 4/4] Fix selection of entire columns in browse tab Fix the selection of entire columns in the browse tab table view. Even when selecting multiple columns the data would be re-sorted instead of selected; this is changed now. --- src/MainWindow.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index c137f0de..766bada8 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1129,6 +1129,10 @@ void MainWindow::activateFields(bool enable) void MainWindow::browseTableHeaderClicked(int logicalindex) { + // Abort if there is more than one column selected because this tells us that the user pretty sure wants to do a range selection instead of sorting data + if(ui->dataTable->selectionModel()->selectedColumns().count() > 1) + return; + // instead of the column name we just use the column index, +2 because 'rowid, *' is the projection curBrowseOrderByIndex = logicalindex + 2; curBrowseOrderByMode = curBrowseOrderByMode == ORDERMODE_ASC ? ORDERMODE_DESC : ORDERMODE_ASC;