| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- #include "imageinsertdialog.h"
- #include <QGridLayout>
- #include <QVBoxLayout>
- #include <QUrl>
- #include <QRegularExpression>
- #include <QLabel>
- #include <QPushButton>
- #include <QRegExpValidator>
- #include <QSpinBox>
- #include <QSlider>
- #include <QScrollArea>
- #include <QFileInfo>
- #include <QDir>
- #include <QFileDialog>
- #include <QTimer>
- #include <QTemporaryFile>
- #include <QCheckBox>
- #include <vtextedit/markdownutils.h>
- #include <vtextedit/networkutils.h>
- #include <widgets/widgetsfactory.h>
- #include <widgets/lineedit.h>
- #include <utils/fileutils.h>
- #include <utils/pathutils.h>
- #include <core/sessionconfig.h>
- #include <core/configmgr.h>
- using namespace vnotex;
- int ImageInsertDialog::s_lastScaleSliderValue = 10;
- int ImageInsertDialog::s_lastScaleWidth = -1;
- bool ImageInsertDialog::s_fixedScaleWidth = false;
- ImageInsertDialog::ImageInsertDialog(const QString &p_title,
- const QString &p_imageTitle,
- const QString &p_imageAlt,
- const QString &p_imagePath,
- bool p_browserEnabled,
- QWidget *p_parent)
- : Dialog(p_parent),
- m_browserEnabled(p_browserEnabled)
- {
- m_imagePathCheckTimer = new QTimer(this);
- m_imagePathCheckTimer->setSingleShot(true);
- m_imagePathCheckTimer->setInterval(500);
- connect(m_imagePathCheckTimer, &QTimer::timeout,
- this, &ImageInsertDialog::checkImagePathInput);
- setupUI(p_title, p_imageTitle, p_imageAlt, p_imagePath);
- checkInput();
- }
- void ImageInsertDialog::setupUI(const QString &p_title,
- const QString &p_imageTitle,
- const QString &p_imageAlt,
- const QString &p_imagePath)
- {
- auto mainWidget = new QWidget(this);
- setCentralWidget(mainWidget);
- auto mainLayout = new QVBoxLayout(mainWidget);
- auto gridLayout = new QGridLayout();
- mainLayout->addLayout(gridLayout);
- mainLayout->addStretch();
- // Image Path.
- m_imagePathEdit = WidgetsFactory::createLineEdit(p_imagePath, mainWidget);
- m_imagePathEdit->setReadOnly(!m_browserEnabled);
- gridLayout->addWidget(new QLabel(tr("From:"), mainWidget), 0, 0, 1, 1);
- gridLayout->addWidget(m_imagePathEdit, 0, 1, 1, 3);
- connect(m_imagePathEdit, &QLineEdit::textChanged,
- this, [this]() {
- m_imagePathCheckTimer->start();
- });
- m_browseBtn = new QPushButton(tr("&Browse"), mainWidget);
- m_browseBtn->setEnabled(m_browserEnabled);
- gridLayout->addWidget(m_browseBtn, 0, 4, 1, 1);
- connect(m_browseBtn, &QPushButton::clicked,
- this, &ImageInsertDialog::browseFile);
- // Image Title.
- m_imageTitleEdit = WidgetsFactory::createLineEdit(p_imageTitle, mainWidget);
- auto titleValidator = new QRegExpValidator(QRegExp(vte::MarkdownUtils::c_imageTitleRegExp), m_imageTitleEdit);
- m_imageTitleEdit->setValidator(titleValidator);
- gridLayout->addWidget(new QLabel(tr("Title:"), mainWidget), 1, 0, 1, 1);
- gridLayout->addWidget(m_imageTitleEdit, 1, 1, 1, 3);
- connect(m_imageTitleEdit, &QLineEdit::textChanged,
- this, &ImageInsertDialog::checkInput);
- // Image Alt.
- m_imageAltEdit = WidgetsFactory::createLineEdit(p_imageAlt, mainWidget);
- auto altValidator = new QRegExpValidator(QRegExp(vte::MarkdownUtils::c_imageAltRegExp), m_imageAltEdit);
- m_imageAltEdit->setValidator(altValidator);
- gridLayout->addWidget(new QLabel(tr("Alt text:"), mainWidget), 2, 0, 1, 1);
- gridLayout->addWidget(m_imageAltEdit, 2, 1, 1, 3);
- // Scale.
- m_widthSpin = WidgetsFactory::createSpinBox(mainWidget);
- m_widthSpin->setMinimum(1);
- m_widthSpin->setSingleStep(10);
- m_widthSpin->setSuffix(" px");
- connect(m_widthSpin, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
- this, [this](int p_val) {
- if (m_image.isNull()) {
- return;
- }
- int height = m_image.height() * (1.0 * p_val / m_image.width());
- m_imageLabel->resize(p_val, height);
- s_lastScaleWidth = p_val;
- });
- // 0.1 to 2.0 -> 1 to 20.
- m_scaleSlider = new QSlider(mainWidget);
- m_scaleSlider->setOrientation(Qt::Horizontal);
- m_scaleSlider->setMinimum(1);
- m_scaleSlider->setMaximum(50);
- m_scaleSlider->setValue(s_lastScaleSliderValue);
- m_scaleSlider->setSingleStep(1);
- m_scaleSlider->setPageStep(5);
- connect(m_scaleSlider, &QSlider::valueChanged,
- this, &ImageInsertDialog::handleScaleSliderValueChanged);
- m_sliderLabel = new QLabel("1x", mainWidget);
- gridLayout->addWidget(new QLabel(tr("Scaling width:"), mainWidget), 3, 0, 1, 1);
- gridLayout->addWidget(m_widthSpin, 3, 1, 1, 1);
- gridLayout->addWidget(m_scaleSlider, 3, 2, 1, 2);
- gridLayout->addWidget(m_sliderLabel, 3, 4, 1, 1);
- {
- auto fixedWidthCheckBox = WidgetsFactory::createCheckBox(tr("Fixed scaling width"), mainWidget);
- fixedWidthCheckBox->setChecked(s_fixedScaleWidth);
- connect(fixedWidthCheckBox, &QCheckBox::stateChanged,
- this, [](int p_state) {
- s_fixedScaleWidth = p_state == Qt::Checked;
- });
- gridLayout->addWidget(fixedWidthCheckBox, 4, 1, 1, 1);
- }
- // Preview area.
- m_imageLabel = new QLabel(mainWidget);
- m_imageLabel->setScaledContents(true);
- m_previewArea = new QScrollArea(mainWidget);
- m_previewArea->setBackgroundRole(QPalette::Dark);
- m_previewArea->setWidget(m_imageLabel);
- m_previewArea->setMinimumSize(256, 256);
- gridLayout->addWidget(m_previewArea, 5, 0, 1, 5);
- setImageControlsVisible(false);
- gridLayout->setColumnStretch(0, 0);
- gridLayout->setColumnStretch(1, 0);
- gridLayout->setColumnStretch(2, 1);
- gridLayout->setColumnStretch(3, 1);
- gridLayout->setColumnStretch(4, 0);
- setDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- setWindowTitle(p_title);
- }
- void ImageInsertDialog::setImageControlsVisible(bool p_visible)
- {
- m_widthSpin->setEnabled(p_visible);
- m_scaleSlider->setEnabled(p_visible);
- m_sliderLabel->setEnabled(p_visible);
- m_previewArea->setVisible(p_visible);
- }
- void ImageInsertDialog::showEvent(QShowEvent *p_event)
- {
- Dialog::showEvent(p_event);
- m_imageTitleEdit->selectAll();
- m_imageTitleEdit->setFocus();
- }
- void ImageInsertDialog::checkImagePathInput()
- {
- const QString text = m_imagePathEdit->text();
- QUrl url = QUrl::fromUserInput(text);
- if (text.isEmpty() || !url.isValid()) {
- setImage(QImage());
- return;
- }
- if (url.isLocalFile()) {
- const auto localFile = url.toLocalFile();
- if (QFileInfo::exists(localFile)) {
- setImage(FileUtils::imageFromFile(localFile));
- } else {
- setImage(QImage());
- }
- m_source = Source::LocalFile;
- } else {
- setImage(QImage());
- m_source = Source::ImageData;
- if (!m_downloader) {
- m_downloader = new vte::NetworkAccess(this);
- connect(m_downloader, &vte::NetworkAccess::requestFinished,
- this, &ImageInsertDialog::handleImageDownloaded);
- }
- m_downloader->requestAsync(url);
- }
- m_imageTitleEdit->setText(QFileInfo(text).baseName());
- checkInput();
- }
- void ImageInsertDialog::checkInput()
- {
- setButtonEnabled(QDialogButtonBox::Ok, !m_image.isNull());
- }
- void ImageInsertDialog::browseFile()
- {
- auto &sessionConfig = ConfigMgr::getInst().getSessionConfig();
- QString filePath = QFileDialog::getOpenFileName(this,
- tr("Select Image To Insert"),
- sessionConfig.getExternalMediaDefaultPath(),
- tr("Images (*.png *.xpm *.jpg *.bmp *.gif *.svg *.webp);;All (*.*)"));
- if (filePath.isEmpty()) {
- return;
- }
- sessionConfig.setExternalMediaDefaultPath(PathUtils::parentDirPath(filePath));
- m_source = Source::LocalFile;
- setImagePath(filePath);
- m_imageTitleEdit->selectAll();
- m_imageTitleEdit->setFocus();
- }
- QString ImageInsertDialog::getImageTitle() const
- {
- return m_imageTitleEdit->text();
- }
- QString ImageInsertDialog::getImageAltText() const
- {
- return m_imageAltEdit->text();
- }
- QString ImageInsertDialog::getImagePath() const
- {
- if (m_tempFile.isNull()) {
- return m_imagePathEdit->text();
- } else {
- return m_tempFile->fileName();
- }
- }
- ImageInsertDialog::Source ImageInsertDialog::getImageSource() const
- {
- return m_source;
- }
- void ImageInsertDialog::setImageSource(ImageInsertDialog::Source p_source)
- {
- m_source = p_source;
- }
- const QImage &ImageInsertDialog::getImage() const
- {
- return m_image;
- }
- void ImageInsertDialog::setImage(const QImage &p_image)
- {
- m_image = p_image;
- if (m_image.isNull()) {
- m_imageLabel->clear();
- setImageControlsVisible(false);
- } else {
- m_imageLabel->setPixmap(QPixmap::fromImage(m_image));
- m_imageLabel->adjustSize();
- m_widthSpin->setMaximum(m_image.width() * 5);
- if (s_fixedScaleWidth) {
- m_widthSpin->setValue(s_lastScaleWidth);
- } else {
- // Set the scaling widgets.
- if (m_scaleSlider->value() == s_lastScaleSliderValue) {
- // Trigger it manually.
- handleScaleSliderValueChanged(s_lastScaleSliderValue);
- } else {
- m_scaleSlider->setValue(s_lastScaleSliderValue);
- }
- }
- setImageControlsVisible(true);
- }
- checkInput();
- }
- void ImageInsertDialog::setImagePath(const QString &p_path)
- {
- m_tempFile.reset();
- m_imagePathEdit->setText(p_path);
- }
- int ImageInsertDialog::getScaledWidth() const
- {
- if (m_image.isNull()) {
- return 0;
- }
- int val = m_widthSpin->value();
- return val == m_image.width() ? 0 : val;
- }
- void ImageInsertDialog::handleImageDownloaded(const vte::NetworkReply &p_data, const QString &p_url)
- {
- setImage(QImage::fromData(p_data.m_data));
- // Save it to a temp file to avoid potential data loss via QImage.
- bool savedToFile = false;
- if (!p_data.m_data.isEmpty()) {
- auto format = QFileInfo(PathUtils::removeUrlParameters(p_url)).suffix();
- m_tempFile.reset(FileUtils::createTemporaryFile(format));
- if (m_tempFile->open()) {
- savedToFile = -1 != m_tempFile->write(p_data.m_data);
- m_tempFile->close();
- }
- }
- m_source = savedToFile ? Source::LocalFile : Source::ImageData;
- if (!savedToFile) {
- m_tempFile.reset();
- }
- }
- void ImageInsertDialog::handleScaleSliderValueChanged(int p_val)
- {
- if (m_image.isNull()) {
- return;
- }
- int width = m_image.width();
- qreal factor = 1.0;
- if (p_val != 10) {
- factor = p_val / 10.0;
- width = m_image.width() * factor;
- }
- m_widthSpin->setValue(width);
- m_sliderLabel->setText(QString::number(factor) + "x");
- s_lastScaleSliderValue = p_val;
- }
|