diff --git a/CMakeLists.txt b/CMakeLists.txt index 87df0293..a6ad84fc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,6 +87,7 @@ set(SQLB_MOC_HDR src/ExportSqlDialog.h src/SqlUiLexer.h src/FileDialog.h + src/ColumnDisplayFormatDialog.h ) set(SQLB_SRC @@ -116,6 +117,7 @@ set(SQLB_SRC src/ExportSqlDialog.cpp src/SqlUiLexer.cpp src/FileDialog.cpp + src/ColumnDisplayFormatDialog.cpp ) set(SQLB_FORMS @@ -131,6 +133,7 @@ set(SQLB_FORMS src/VacuumDialog.ui src/CipherDialog.ui src/ExportSqlDialog.ui + src/ColumnDisplayFormatDialog.ui ) set(SQLB_RESOURCES diff --git a/src/ColumnDisplayFormatDialog.cpp b/src/ColumnDisplayFormatDialog.cpp new file mode 100644 index 00000000..69bb3d5e --- /dev/null +++ b/src/ColumnDisplayFormatDialog.cpp @@ -0,0 +1,59 @@ +#include "ColumnDisplayFormatDialog.h" +#include "ui_ColumnDisplayFormatDialog.h" + +ColumnDisplayFormatDialog::ColumnDisplayFormatDialog(const QString& colname, QString current_format, QWidget* parent) + : QDialog(parent), + ui(new Ui::ColumnDisplayFormatDialog), + column_name(colname) +{ + // Create UI + ui->setupUi(this); + ui->comboDisplayFormat->addItem(tr("Default"), "default"); + ui->comboDisplayFormat->addItem(tr("Lower case"), "lower"); + ui->comboDisplayFormat->addItem(tr("Upper case"), "upper"); + ui->comboDisplayFormat->addItem(tr("Unix epoch to date"), "epoch"); + ui->comboDisplayFormat->addItem(tr("Julian day to date"), "julian"); + ui->comboDisplayFormat->addItem(tr("Round number"), "round"); + ui->labelDisplayFormat->setText(ui->labelDisplayFormat->text().arg(column_name)); + + // Set the current format, if it's empty set the default format + if(current_format.isEmpty()) + { + ui->comboDisplayFormat->setCurrentIndex(0); + updateSqlCode(); + } else { + ui->comboDisplayFormat->addItem(tr("Custom"), "custom"); + ui->comboDisplayFormat->setCurrentIndex(ui->comboDisplayFormat->findData("custom")); + ui->editDisplayFormat->setText(current_format); + } +} + +ColumnDisplayFormatDialog::~ColumnDisplayFormatDialog() +{ + delete ui; +} + +QString ColumnDisplayFormatDialog::selectedDisplayFormat() const +{ + if(ui->comboDisplayFormat->currentData().toString() == "default") + return QString(); + else + return ui->editDisplayFormat->text(); +} + +void ColumnDisplayFormatDialog::updateSqlCode() +{ + QString format = ui->comboDisplayFormat->currentData().toString(); + if(format == "default") + ui->editDisplayFormat->setText("`" + column_name + "`"); + else if(format == "lower") + ui->editDisplayFormat->setText("lower(`" + column_name + "`)"); + else if(format == "upper") + ui->editDisplayFormat->setText("upper(`" + column_name + "`)"); + else if(format == "epoch") + ui->editDisplayFormat->setText("datetime(`" + column_name + "`, 'unixepoch')"); + else if(format == "julian") + ui->editDisplayFormat->setText("datetime(`" + column_name + "`)"); + else if(format == "round") + ui->editDisplayFormat->setText("round(`" + column_name + "`)"); +} diff --git a/src/ColumnDisplayFormatDialog.h b/src/ColumnDisplayFormatDialog.h new file mode 100644 index 00000000..066e348a --- /dev/null +++ b/src/ColumnDisplayFormatDialog.h @@ -0,0 +1,28 @@ +#ifndef COLUMNDISPLAYFORMATDIALOG_H +#define COLUMNDISPLAYFORMATDIALOG_H + +#include + +namespace Ui { +class ColumnDisplayFormatDialog; +} + +class ColumnDisplayFormatDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ColumnDisplayFormatDialog(const QString& colname, QString current_format, QWidget* parent = 0); + ~ColumnDisplayFormatDialog(); + + QString selectedDisplayFormat() const; + +private slots: + void updateSqlCode(); + +private: + Ui::ColumnDisplayFormatDialog* ui; + QString column_name; +}; + +#endif diff --git a/src/ColumnDisplayFormatDialog.ui b/src/ColumnDisplayFormatDialog.ui new file mode 100644 index 00000000..20844213 --- /dev/null +++ b/src/ColumnDisplayFormatDialog.ui @@ -0,0 +1,121 @@ + + + ColumnDisplayFormatDialog + + + + 0 + 0 + 624 + 205 + + + + Choose display format + + + + + + Display format + + + + + + Choose a display format for the column '%1' which is applied to each value prior to showing it. + + + + + + + + + + true + + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + SqlTextEdit + QTextEdit +
sqltextedit.h
+ 1 +
+
+ + comboDisplayFormat + editDisplayFormat + + + + + buttonBox + accepted() + ColumnDisplayFormatDialog + accept() + + + 227 + 188 + + + 157 + 204 + + + + + buttonBox + rejected() + ColumnDisplayFormatDialog + reject() + + + 295 + 194 + + + 286 + 204 + + + + + comboDisplayFormat + currentIndexChanged(int) + ColumnDisplayFormatDialog + updateSqlCode() + + + 125 + 69 + + + 244 + 4 + + + + + + updateSqlCode() + +
diff --git a/src/FilterTableHeader.cpp b/src/FilterTableHeader.cpp index 658e4589..b7957adc 100644 --- a/src/FilterTableHeader.cpp +++ b/src/FilterTableHeader.cpp @@ -58,6 +58,9 @@ FilterTableHeader::FilterTableHeader(QTableView* parent) : connect(this, SIGNAL(sectionResized(int,int,int)), this, SLOT(adjustPositions())); connect(parent->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustPositions())); connect(parent->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustPositions())); + + // Set custom context menu handling + setContextMenuPolicy(Qt::CustomContextMenu); } void FilterTableHeader::generateFilters(int number) diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 61fd22c9..1e340806 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -18,6 +18,7 @@ #include "ExportSqlDialog.h" #include "SqlUiLexer.h" #include "FileDialog.h" +#include "ColumnDisplayFormatDialog.h" #include #include @@ -116,6 +117,9 @@ void MainWindow::init() popupSaveSqlFileMenu->addAction(ui->actionSqlSaveFileAs); ui->actionSqlSaveFilePopup->setMenu(popupSaveSqlFileMenu); + popupBrowseDataHeaderMenu = new QMenu(this); + popupBrowseDataHeaderMenu->addAction(ui->actionBrowseTableEditDisplayFormat); + // Add menu item for log dock ui->viewMenu->insertAction(ui->viewDBToolbarAction, ui->dockLog->toggleViewAction()); ui->viewMenu->actions().at(0)->setShortcut(QKeySequence(tr("Ctrl+L"))); @@ -155,6 +159,7 @@ void MainWindow::init() connect(editWin, SIGNAL(goingAway()), this, SLOT(editWinAway())); connect(editWin, SIGNAL(updateRecordText(int, int, QByteArray)), this, SLOT(updateRecordText(int, int, QByteArray))); connect(ui->dbTreeWidget->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(changeTreeSelection())); + connect(ui->dataTable->horizontalHeader(), SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDataColumnPopupMenu(QPoint))); // Load window settings tabifyDockWidget(ui->dockLog, ui->dockPlot); @@ -319,16 +324,41 @@ void MainWindow::populateTable(const QString& tablename) // Set model ui->dataTable->setModel(m_browseTableModel); + // Search stored table settings for this table + QMap::ConstIterator tableIt; + tableIt = browseTableSettings.constFind(tablename); + bool storedDataFound = tableIt != browseTableSettings.constEnd(); + // Set new table - m_browseTableModel->setTable(tablename); + if(!storedDataFound) + { + m_browseTableModel->setTable(tablename); + } else { + QVector v; + bool only_defaults = true; + for(int i=0;iname() + "`"); + } + } + if(only_defaults) + m_browseTableModel->setTable(tablename); + else + m_browseTableModel->setTable(tablename, v); + } ui->dataTable->setColumnHidden(0, true); // Update the filter row qobject_cast(ui->dataTable->horizontalHeader())->generateFilters(m_browseTableModel->columnCount()); // Restore table settings - QMap::ConstIterator tableIt; - if((tableIt = browseTableSettings.constFind(tablename)) != browseTableSettings.constEnd()) + if(storedDataFound) { // There is information stored for this table, so extract it and apply it @@ -2176,3 +2206,41 @@ void MainWindow::jumpToRow(const QString& table, QString column, const QByteArra // Set filter ui->dataTable->filterHeader()->setFilter(column_index+1, value); } + +void MainWindow::showDataColumnPopupMenu(const QPoint& pos) +{ + // Get the index of the column which the user has clicked on and store it in the action. This is sort of hack-ish and it might be the heat in my room + // but I haven't come up with a better solution so far + ui->actionBrowseTableEditDisplayFormat->setProperty("clicked_column", ui->dataTable->horizontalHeader()->logicalIndexAt(pos)); + + // Calculate the proper position for the context menu and display it + popupBrowseDataHeaderMenu->exec(ui->dataTable->horizontalHeader()->mapToGlobal(pos)); +} + +void MainWindow::editDataColumnDisplayFormat() +{ + // Get the current table name and fetch its table object, then retrieve the fields of that table and look up the index of the clicked table header + // section using it as the table field array index. Subtract one from the header index to get the column index because in the the first (though hidden) + // column is always the rowid column. Ultimately, get the column name from the column object + QString current_table = ui->comboBrowseTable->currentText(); + int field_number = sender()->property("clicked_column").toInt(); + QString field_name = db.getObjectByName(current_table).table.fields().at(field_number-1)->name(); + + // Get the current display format of the field + QString current_displayformat = browseTableSettings[current_table].displayFormats[field_number]; + + // Open the dialog + ColumnDisplayFormatDialog dialog(field_name, current_displayformat, this); + if(dialog.exec()) + { + // Set the newly selected display format + QString new_format = dialog.selectedDisplayFormat(); + if(new_format.size()) + browseTableSettings[current_table].displayFormats[field_number] = new_format; + else + browseTableSettings[current_table].displayFormats.remove(field_number); + + // Refresh view + populateTable(current_table); + } +} diff --git a/src/MainWindow.h b/src/MainWindow.h index 20699d64..d2bab34c 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -38,6 +38,7 @@ public: Qt::SortOrder sortOrderMode; QMap columnWidths; QMap filterValues; + QMap displayFormats; friend QDataStream& operator<<(QDataStream& stream, const MainWindow::BrowseDataTableSettings& object) { @@ -45,6 +46,7 @@ public: stream << static_cast(object.sortOrderMode); stream << object.columnWidths; stream << object.filterValues; + stream << object.displayFormats; return stream; } @@ -56,6 +58,7 @@ public: object.sortOrderMode = static_cast(sortordermode); stream >> object.columnWidths; stream >> object.filterValues; + stream >> object.displayFormats; return stream; } @@ -98,6 +101,7 @@ private: QMenu *popupTableMenu; QMenu *recentFilesMenu; QMenu *popupSaveSqlFileMenu; + QMenu* popupBrowseDataHeaderMenu; QLabel* statusEncodingLabel; QLabel* statusEncryptionLabel; @@ -207,6 +211,8 @@ private slots: void copyCurrentCreateStatement(); void on_comboLineType_currentIndexChanged(int index); void on_comboPointShape_currentIndexChanged(int index); + void showDataColumnPopupMenu(const QPoint& pos); + void editDataColumnDisplayFormat(); }; #endif diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 5a9c3ecb..6e4fbc6f 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -1760,6 +1760,14 @@ Copy the CREATE statement of the item to the clipboard + + + Edit display format + + + Edit the display format of the data in this column + + @@ -2683,6 +2691,22 @@ + + actionBrowseTableEditDisplayFormat + triggered() + MainWindow + editDataColumnDisplayFormat() + + + -1 + -1 + + + 518 + 314 + + + fileOpen() @@ -2739,5 +2763,6 @@ switchToBrowseDataTab() copyCurrentCreateStatement() jumpToRow(QString,QString,QByteArray) + editDataColumnDisplayFormat() diff --git a/src/sqlitetablemodel.cpp b/src/sqlitetablemodel.cpp index 071c9fbb..9b8d8b5c 100644 --- a/src/sqlitetablemodel.cpp +++ b/src/sqlitetablemodel.cpp @@ -24,6 +24,7 @@ void SqliteTableModel::reset() m_headers.clear(); m_mWhere.clear(); m_vDataTypes.clear(); + m_vDisplayFormat.clear(); } void SqliteTableModel::setChunkSize(size_t chunksize) @@ -31,11 +32,12 @@ void SqliteTableModel::setChunkSize(size_t chunksize) m_chunkSize = chunksize; } -void SqliteTableModel::setTable(const QString& table) +void SqliteTableModel::setTable(const QString& table, const QVector& display_format) { reset(); m_sTable = table; + m_vDisplayFormat = display_format; m_vDataTypes.push_back(SQLITE_INTEGER); @@ -333,7 +335,17 @@ Qt::ItemFlags SqliteTableModel::flags(const QModelIndex& index) const return Qt::ItemIsEnabled; Qt::ItemFlags ret = QAbstractTableModel::flags(index); - if(!isBinary(index)) + + // Custom display format set? + bool custom_display_format = false; + if(m_vDisplayFormat.size()) + { + // NOTE: This assumes that custom display formats never start and end with a backtick + if(index.column() > 0) + custom_display_format = !(m_vDisplayFormat.at(index.column()-1).startsWith("`") && m_vDisplayFormat.at(index.column()-1).endsWith("`")); + } + + if(!isBinary(index) && !custom_display_format) ret |= Qt::ItemIsEditable; return ret; } @@ -469,7 +481,17 @@ void SqliteTableModel::buildQuery() where.append(QString(" AND `%1` %2").arg(m_headers.at(i.key())).arg(i.value())); } - QString sql = QString("SELECT `%1`,* FROM `%2` %3 ORDER BY `%4` %5").arg(m_headers.at(0)).arg(m_sTable).arg(where).arg(m_headers.at(m_iSortColumn)).arg(m_sSortOrder); + QString selector; + if(m_vDisplayFormat.empty()) + { + selector = "*"; + } else { + for(int i=0;i &display_format = QVector()); void setChunkSize(size_t chunksize); void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); @@ -68,6 +68,7 @@ private: int m_iSortColumn; QString m_sSortOrder; QMap m_mWhere; + QVector m_vDisplayFormat; QVector m_vDataTypes; /** diff --git a/src/src.pro b/src/src.pro index 755861ce..376577ef 100644 --- a/src/src.pro +++ b/src/src.pro @@ -51,7 +51,8 @@ HEADERS += \ CipherDialog.h \ ExportSqlDialog.h \ SqlUiLexer.h \ - FileDialog.h + FileDialog.h \ + ColumnDisplayFormatDialog.h SOURCES += \ sqlitedb.cpp \ @@ -78,7 +79,8 @@ SOURCES += \ CipherDialog.cpp \ ExportSqlDialog.cpp \ SqlUiLexer.cpp \ - FileDialog.cpp + FileDialog.cpp \ + ColumnDisplayFormatDialog.cpp RESOURCES += icons/icons.qrc \ translations/flags/flags.qrc \ @@ -96,7 +98,8 @@ FORMS += \ SqlExecutionArea.ui \ VacuumDialog.ui \ CipherDialog.ui \ - ExportSqlDialog.ui + ExportSqlDialog.ui \ + ColumnDisplayFormatDialog.ui TRANSLATIONS += \ translations/sqlb_zh.ts \