From 64d86a0e9230b531fc447f617c19e295deea33a1 Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Mon, 12 Jul 2021 16:24:29 +0300 Subject: [PATCH 1/9] ColumnDisplayFormatDialog: Escape column_name only once --- src/ColumnDisplayFormatDialog.cpp | 56 ++++++++++++++++--------------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/src/ColumnDisplayFormatDialog.cpp b/src/ColumnDisplayFormatDialog.cpp index 66699a776..798b6c959 100644 --- a/src/ColumnDisplayFormatDialog.cpp +++ b/src/ColumnDisplayFormatDialog.cpp @@ -41,33 +41,35 @@ ColumnDisplayFormatDialog::ColumnDisplayFormatDialog(DBBrowserDB& db, const sqlb ui->labelDisplayFormat->setText(ui->labelDisplayFormat->text().arg(column_name)); - formatFunctions["decimal"] = "printf('%d', " + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["exponent"] = "printf('%e', " + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["hexblob"] = "hex(" + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["hex"] = "printf('0x%x', " + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["octal"] = "printf('%o', " + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["round"] = "round(" + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["appleDate"] = "datetime('2001-01-01', " + sqlb::escapeIdentifier(column_name) + " || ' seconds')"; - formatFunctions["javaEpoch"] = "strftime('%Y-%m-%d %H:%M:%S.', " + sqlb::escapeIdentifier(column_name) + - "/1000, 'unixepoch') || (" + sqlb::escapeIdentifier(column_name) + "%1000)"; - formatFunctions["dotNetTicks"] = "datetime(" + sqlb::escapeIdentifier(column_name) + " / 10000000 - 62135596800, 'unixepoch')"; - formatFunctions["julian"] = "datetime(" + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["epoch"] = "datetime(" + sqlb::escapeIdentifier(column_name) + ", 'unixepoch')"; - formatFunctions["epochLocalTime"] = "datetime(" + sqlb::escapeIdentifier(column_name) + ", 'unixepoch', 'localtime')"; - formatFunctions["winDate"] = "datetime('1899-12-30', " + sqlb::escapeIdentifier(column_name) + " || ' days')"; - formatFunctions["ddmmyyyyDate"] = "strftime('%d/%m/%Y', " + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["lower"] = "lower(" + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["upper"] = "upper(" + sqlb::escapeIdentifier(column_name) + ")"; - formatFunctions["guid"] = "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 7, 2) || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 5, 2) || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 3, 2) || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 1, 2) || '-' || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 11, 2) || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 9, 2) || '-' || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 15, 2) || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 13, 2) || '-' || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 17, 4) || '-' || " + - "substr(hex(" + sqlb::escapeIdentifier(column_name) + "), 21, 12)"; + const QString e_column_name = sqlb::escapeIdentifier(column_name); + + formatFunctions["decimal"] = "printf('%d', " + e_column_name + ")"; + formatFunctions["exponent"] = "printf('%e', " + e_column_name + ")"; + formatFunctions["hexblob"] = "hex(" + e_column_name + ")"; + formatFunctions["hex"] = "printf('0x%x', " + e_column_name + ")"; + formatFunctions["octal"] = "printf('%o', " + e_column_name + ")"; + formatFunctions["round"] = "round(" + e_column_name + ")"; + formatFunctions["appleDate"] = "datetime('2001-01-01', " + e_column_name + " || ' seconds')"; + formatFunctions["javaEpoch"] = "strftime('%Y-%m-%d %H:%M:%S.', " + e_column_name + + "/1000, 'unixepoch') || (" + e_column_name + "%1000)"; + formatFunctions["dotNetTicks"] = "datetime(" + e_column_name + " / 10000000 - 62135596800, 'unixepoch')"; + formatFunctions["julian"] = "datetime(" + e_column_name + ")"; + formatFunctions["epoch"] = "datetime(" + e_column_name + ", 'unixepoch')"; + formatFunctions["epochLocalTime"] = "datetime(" + e_column_name + ", 'unixepoch', 'localtime')"; + formatFunctions["winDate"] = "datetime('1899-12-30', " + e_column_name + " || ' days')"; + formatFunctions["ddmmyyyyDate"] = "strftime('%d/%m/%Y', " + e_column_name + ")"; + formatFunctions["lower"] = "lower(" + e_column_name + ")"; + formatFunctions["upper"] = "upper(" + e_column_name + ")"; + formatFunctions["guid"] = "substr(hex(" + e_column_name + "), 7, 2) || " + + "substr(hex(" + e_column_name + "), 5, 2) || " + + "substr(hex(" + e_column_name + "), 3, 2) || " + + "substr(hex(" + e_column_name + "), 1, 2) || '-' || " + + "substr(hex(" + e_column_name + "), 11, 2) || " + + "substr(hex(" + e_column_name + "), 9, 2) || '-' || " + + "substr(hex(" + e_column_name + "), 15, 2) || " + + "substr(hex(" + e_column_name + "), 13, 2) || '-' || " + + "substr(hex(" + e_column_name + "), 17, 4) || '-' || " + + "substr(hex(" + e_column_name + "), 21, 12)"; // Set the current format, if it's empty set the default format if(current_format.isEmpty()) From 4e5f117851faad03923c99767db1aad63e818439 Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Mon, 12 Jul 2021 16:38:09 +0300 Subject: [PATCH 2/9] ColumnDisplayFormatDialog: Added SpatiaLite geometry to SVG Display Format The new Display Format should convert SpatiaLite geometry (BLOB) into SVG. By default the geometry is scaled to 320 pixels (0..319) --- src/ColumnDisplayFormatDialog.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/ColumnDisplayFormatDialog.cpp b/src/ColumnDisplayFormatDialog.cpp index 798b6c959..b41a0af34 100644 --- a/src/ColumnDisplayFormatDialog.cpp +++ b/src/ColumnDisplayFormatDialog.cpp @@ -36,6 +36,7 @@ ColumnDisplayFormatDialog::ColumnDisplayFormatDialog(DBBrowserDB& db, const sqlb ui->comboDisplayFormat->addItem(tr("Upper case"), "upper"); ui->comboDisplayFormat->insertSeparator(ui->comboDisplayFormat->count()); ui->comboDisplayFormat->addItem(tr("Binary GUID to text"), "guid"); + ui->comboDisplayFormat->addItem(tr("SpatiaLite Geometry to SVG"), "geomToSVG"); ui->comboDisplayFormat->insertSeparator(ui->comboDisplayFormat->count()); ui->comboDisplayFormat->addItem(tr("Custom"), "custom"); @@ -70,6 +71,16 @@ ColumnDisplayFormatDialog::ColumnDisplayFormatDialog(DBBrowserDB& db, const sqlb "substr(hex(" + e_column_name + "), 13, 2) || '-' || " + "substr(hex(" + e_column_name + "), 17, 4) || '-' || " + "substr(hex(" + e_column_name + "), 21, 12)"; + formatFunctions["geomToSVG"] = QString( +R"('' +|| '' +|| '')").arg(e_column_name); // Set the current format, if it's empty set the default format if(current_format.isEmpty()) From 78a1209c3e7f4bbf2c80725d3ff69f4a917458c4 Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Tue, 13 Jul 2021 14:34:35 +0300 Subject: [PATCH 3/9] ImageViewer: initialize m_scale_factor with default value --- src/ImageViewer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index 97cb7db53..94f75abe3 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -8,7 +8,8 @@ ImageViewer::ImageViewer(QWidget* parent) : QWidget(parent), - ui(new Ui::ImageViewer) + ui(new Ui::ImageViewer), + m_scale_factor(1.0) { ui->setupUi(this); connect(ui->buttonOriginalSize, &QToolButton::clicked, this, [this]{ scaleImage(100); }); From daee6bcaf11bd8c27e2fd3fb69b13b8e6a33733e Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Tue, 13 Jul 2021 14:44:38 +0300 Subject: [PATCH 4/9] ImageViewer: Use scrollArea widget for boundaries check Check if the image is inside the scrollArea widget, not the "scrollable content". --- src/ImageViewer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index 94f75abe3..4ba27e205 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -31,9 +31,10 @@ void ImageViewer::setImage(const QImage& image) { ui->labelView->setPixmap(QPixmap::fromImage(image)); + auto widget_size = ui->scrollArea->size(); // If the image is larger than the viewport scale it to fit the viewport. // If the image is smaller than the viewport show it in its original size. - if(image.size().width() > ui->labelView->size().width() || image.size().height() > ui->labelView->size().height()) + if(image.size().width() > widget_size.width() || image.size().height() > widget_size.height()) ui->buttonFitToWindow->setChecked(true); else scaleImage(100); From d2e957cbdf0917646712c9f7523432590f6be233 Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Tue, 13 Jul 2021 17:27:09 +0300 Subject: [PATCH 5/9] ImageViewer: Keep aspect ratio for a scaled image --- src/ImageViewer.cpp | 22 ++++++++++++---------- src/ImageViewer.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index 4ba27e205..3286918ad 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -9,7 +9,7 @@ ImageViewer::ImageViewer(QWidget* parent) : QWidget(parent), ui(new Ui::ImageViewer), - m_scale_factor(1.0) + m_image_size(0, 0) { ui->setupUi(this); connect(ui->buttonOriginalSize, &QToolButton::clicked, this, [this]{ scaleImage(100); }); @@ -29,9 +29,12 @@ void ImageViewer::resetImage() void ImageViewer::setImage(const QImage& image) { + auto widget_size = ui->scrollArea->size(); + m_image_size = image.size(); + ui->labelView->setMaximumSize(m_image_size.scaled(widget_size, Qt::KeepAspectRatio)); + ui->labelView->setPixmap(QPixmap::fromImage(image)); - auto widget_size = ui->scrollArea->size(); // If the image is larger than the viewport scale it to fit the viewport. // If the image is smaller than the viewport show it in its original size. if(image.size().width() > widget_size.width() || image.size().height() > widget_size.height()) @@ -72,6 +75,8 @@ void ImageViewer::scaleToFitWindow(bool enabled) // When disabling the fit to window scaling, revert back to the original image size if(!enabled) scaleImage(100); + else + ui->labelView->setMaximumSize(m_image_size.scaled(ui->scrollArea->size(), Qt::KeepAspectRatio)); } void ImageViewer::scaleImage(int scale) @@ -80,16 +85,13 @@ void ImageViewer::scaleImage(int scale) ui->sliderScale->setValue(scale); // Update our scale factor - qreal factor_change = (scale / 100.0) / m_scale_factor; - m_scale_factor = scale / 100.0; + auto scale_factor = scale / 100.0; // Resize the image -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - QPixmap pixmap = *ui->labelView->pixmap(); -#else - QPixmap pixmap = ui->labelView->pixmap(Qt::ReturnByValue); -#endif - ui->labelView->resize(m_scale_factor * pixmap.size()); + auto max_size_old = ui->labelView->maximumSize(); + ui->labelView->setMaximumSize(m_image_size * scale_factor); + ui->labelView->resize(ui->labelView->maximumSize()); + auto factor_change = ui->labelView->maximumSize().width() / double(max_size_old.width()); // Uncheck the fit to window button ui->buttonFitToWindow->setChecked(false); diff --git a/src/ImageViewer.h b/src/ImageViewer.h index 720b4a394..3d3408dc9 100644 --- a/src/ImageViewer.h +++ b/src/ImageViewer.h @@ -28,7 +28,7 @@ private slots: private: Ui::ImageViewer* ui; - qreal m_scale_factor; + QSize m_image_size; }; #endif From f97d1013cdf5a03dd8af47844d511c5e1b0cc4ac Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Tue, 13 Jul 2021 17:39:38 +0300 Subject: [PATCH 6/9] ImageViewer: Change image alignment to center --- src/ImageViewer.ui | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ImageViewer.ui b/src/ImageViewer.ui index 177af8563..1a97a5dfe 100644 --- a/src/ImageViewer.ui +++ b/src/ImageViewer.ui @@ -31,6 +31,9 @@ + + Qt::AlignCenter + @@ -132,6 +135,7 @@ + From d62ccb1a6dd37382b0f92159c77823ba335b33db Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Tue, 13 Jul 2021 19:46:20 +0300 Subject: [PATCH 7/9] ImageViewer: Added mouse pan mode --- src/ImageViewer.cpp | 54 ++++++++++++++++++++++++++++++++++++++++----- src/ImageViewer.h | 6 ++++- 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index 3286918ad..a008a18e9 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -1,17 +1,22 @@ #include "ImageViewer.h" #include "ui_ImageViewer.h" +#include #include #include #include #include +#include +#include ImageViewer::ImageViewer(QWidget* parent) : QWidget(parent), ui(new Ui::ImageViewer), - m_image_size(0, 0) + m_image_size(0, 0), + m_pan_mode{false} { ui->setupUi(this); + ui->scrollArea->installEventFilter(this); connect(ui->buttonOriginalSize, &QToolButton::clicked, this, [this]{ scaleImage(100); }); ui->labelView->addAction(ui->actionPrintImage); @@ -37,12 +42,50 @@ void ImageViewer::setImage(const QImage& image) // If the image is larger than the viewport scale it to fit the viewport. // If the image is smaller than the viewport show it in its original size. - if(image.size().width() > widget_size.width() || image.size().height() > widget_size.height()) + if(!isQSizeCovered(m_image_size)) ui->buttonFitToWindow->setChecked(true); else scaleImage(100); } +bool ImageViewer::isQSizeCovered(QSize rect) +{ + auto widget_size = ui->scrollArea->size(); + return widget_size.width() >= rect.width() && widget_size.height() >= rect.height(); +} + +bool ImageViewer::eventFilter(QObject *obj, QEvent *e) { + auto e_type = e->type(); + if (ui->buttonFitToWindow->isChecked()) { + if (e_type == QEvent::Resize) + scaleToFitWindow(true); + } else if (e_type >= QEvent::MouseButtonPress && e_type <= QEvent::MouseMove) { + auto *mouse_event = static_cast(e); + if (e_type == QEvent::MouseButtonPress && mouse_event->button() == Qt::LeftButton && + !isQSizeCovered(ui->labelView->size())) { + m_mouse_down = mouse_event->globalPos(); + m_pan_mode = true; + ui->scrollArea->setCursor(Qt::ClosedHandCursor); + } else if (e_type == QEvent::MouseMove && m_pan_mode) { + auto dx = mouse_event->globalX() - m_mouse_down.x(); + auto dy = mouse_event->globalY() - m_mouse_down.y(); + if (dx != 0) { + ui->scrollArea->horizontalScrollBar()->setValue(ui->scrollArea->horizontalScrollBar()->value() - dx); + m_mouse_down.setX(mouse_event->globalX()); + } + + if (dy != 0) { + ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->value() - dy); + m_mouse_down.setY(mouse_event->globalY()); + } + } else if (e_type == QEvent::MouseButtonRelease && mouse_event->button() == Qt::LeftButton) { + m_pan_mode = false; + ui->scrollArea->setCursor(Qt::ArrowCursor); + } + } + return false; +} + void ImageViewer::openPrintImageDialog() { QPrinter printer; @@ -73,10 +116,11 @@ void ImageViewer::scaleToFitWindow(bool enabled) ui->scrollArea->setWidgetResizable(enabled); // When disabling the fit to window scaling, revert back to the original image size - if(!enabled) + if(!enabled) { scaleImage(100); - else + } else { ui->labelView->setMaximumSize(m_image_size.scaled(ui->scrollArea->size(), Qt::KeepAspectRatio)); + } } void ImageViewer::scaleImage(int scale) @@ -91,7 +135,7 @@ void ImageViewer::scaleImage(int scale) auto max_size_old = ui->labelView->maximumSize(); ui->labelView->setMaximumSize(m_image_size * scale_factor); ui->labelView->resize(ui->labelView->maximumSize()); - auto factor_change = ui->labelView->maximumSize().width() / double(max_size_old.width()); + auto factor_change = ui->labelView->maximumSize().width() / static_cast(max_size_old.width()); // Uncheck the fit to window button ui->buttonFitToWindow->setChecked(false); diff --git a/src/ImageViewer.h b/src/ImageViewer.h index 3d3408dc9..748919208 100644 --- a/src/ImageViewer.h +++ b/src/ImageViewer.h @@ -27,8 +27,12 @@ private slots: private: Ui::ImageViewer* ui; - QSize m_image_size; + bool m_pan_mode; + QPoint m_mouse_down; + + bool eventFilter(QObject *obj, QEvent *e) override; + bool isQSizeCovered(QSize rect); }; #endif From c4dd27e03459273e381e6a4003ba5c55af515d84 Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Wed, 14 Jul 2021 09:34:24 +0300 Subject: [PATCH 8/9] ImageViewer: Code cleanup --- src/ImageViewer.cpp | 9 ++++----- src/ImageViewer.ui | 1 - 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/ImageViewer.cpp b/src/ImageViewer.cpp index a008a18e9..5c78c66a7 100644 --- a/src/ImageViewer.cpp +++ b/src/ImageViewer.cpp @@ -1,13 +1,12 @@ #include "ImageViewer.h" #include "ui_ImageViewer.h" -#include -#include -#include +#include #include -#include +#include +#include #include -#include +#include ImageViewer::ImageViewer(QWidget* parent) : QWidget(parent), diff --git a/src/ImageViewer.ui b/src/ImageViewer.ui index 1a97a5dfe..64535c6ed 100644 --- a/src/ImageViewer.ui +++ b/src/ImageViewer.ui @@ -135,7 +135,6 @@ - From 4a0ba0d51afc518fca7492c0eaf666c60e90614b Mon Sep 17 00:00:00 2001 From: Nikolay Zlatev Date: Wed, 14 Jul 2021 09:48:46 +0300 Subject: [PATCH 9/9] ColumnDisplayFormatDialog: geomToSVG change default resolution to 640 --- src/ColumnDisplayFormatDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ColumnDisplayFormatDialog.cpp b/src/ColumnDisplayFormatDialog.cpp index b41a0af34..2c4b18372 100644 --- a/src/ColumnDisplayFormatDialog.cpp +++ b/src/ColumnDisplayFormatDialog.cpp @@ -77,7 +77,7 @@ R"('' || AsSVG( ScaleCoords( ST_Translate(%1, -St_MinX(%1), -St_MaxY(%1), 0) - , 319 / (MAX(St_MaxX(%1) - St_MinX(%1), St_MaxY(%1) - St_MinY(%1)))) + , 639 / (MAX(St_MaxX(%1) - St_MinX(%1), St_MaxY(%1) - St_MinY(%1)))) , 1, 5) || '" stroke="darkblue" fill="#b5cfed" stroke-width="1"/>' || '')").arg(e_column_name);