/************************************************************************ ** ** @file watermarkwindow.cpp ** @author Roman Telezhynskyi ** @date 24 12, 2019 ** ** @brief ** @copyright ** This source code is part of the Valentina project, a pattern making ** program, whose allow create and modeling patterns of clothing. ** Copyright (C) 2019 Valentina project ** All Rights Reserved. ** ** Valentina is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Valentina is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Valentina. If not, see . ** *************************************************************************/ #include "watermarkwindow.h" #include "ui_watermarkwindow.h" #include #include #include #include #include #include #include #include "../vmisc/def.h" #include "core/vapplication.h" #include "../vpropertyexplorer/checkablemessagebox.h" #include "../ifc/exception/vexception.h" #include "../ifc/xml/vwatermarkconverter.h" //--------------------------------------------------------------------------------------------------------------------- WatermarkWindow::WatermarkWindow(const QString &patternPath, QWidget *parent) : QMainWindow(parent), ui(new Ui::WatermarkWindow), m_patternPath(patternPath), m_okPathColor() { ui->setupUi(this); m_okPathColor = ui->lineEditPath->palette().color(ui->lineEditPath->foregroundRole()); qApp->Settings()->GetOsSeparator() ? setLocale(QLocale()) : setLocale(QLocale::c()); UpdateWindowTitle(); m_curFileFormatVersion = VWatermarkConverter::WatermarkMaxVer; m_curFileFormatVersionStr = VWatermarkConverter::WatermarkMaxVerStr; ToolBarStyle(ui->toolBar); connect(ui->spinBoxOpacity, QOverload::of(&QSpinBox::valueChanged),this, [this](){WatermarkChangesWereSaved(false);}); connect(ui->lineEditText, &QLineEdit::textChanged, this, [this]() { WatermarkChangesWereSaved(false); }); connect(ui->spinBoxTextRotation, QOverload::of(&QSpinBox::valueChanged), this, [this](){WatermarkChangesWereSaved(false);}); connect(ui->toolButtonFont, &QToolButton::clicked, this, [this]() { bool ok; QFont font = QFontDialog::getFont(&ok, m_data.font, this); if (ok) { WatermarkChangesWereSaved(false); m_data.font = font; ui->lineEditFontSample->setFont(font); } }); connect(ui->lineEditPath, &QLineEdit::textChanged, this, [this]() { WatermarkChangesWereSaved(false); ValidatePath(); }); connect(ui->pushButtonBrowse, &QPushButton::clicked, this, [this]() { const QString filter = tr("Images") + QLatin1String(" (*.png *.jpg *.jpeg *.bmp)"); const QString fileName = QFileDialog::getOpenFileName(this, tr("Watermark image"), QString(), filter, nullptr); if (not fileName.isEmpty()) { ui->lineEditPath->setText(fileName); } }); connect(ui->spinBoxImageRotation, QOverload::of(&QSpinBox::valueChanged),this, [this](){WatermarkChangesWereSaved(false);}); connect(ui->checkBoxGrayColor, &QCheckBox::stateChanged, this, [this](){WatermarkChangesWereSaved(false);}); connect(ui->groupBoxWatermarkText, &QGroupBox::toggled, this, [this](){WatermarkChangesWereSaved(false);}); connect(ui->groupBoxWatermarkImage, &QGroupBox::toggled, this, [this](){WatermarkChangesWereSaved(false);}); } //--------------------------------------------------------------------------------------------------------------------- WatermarkWindow::~WatermarkWindow() { delete ui; } //--------------------------------------------------------------------------------------------------------------------- QString WatermarkWindow::CurrentFile() const { return m_curFile; } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::Open(QString path) { qDebug("Loading new watermark file %s.", qUtf8Printable(path)); if (path.isEmpty()) { qDebug("Path is empty"); Clear(); return false; } // Convert to absolute path if need path = AbsoluteMPath(m_patternPath, path); QFuture futureConverter = QtConcurrent::run([path]() { QScopedPointer converter(new VWatermarkConverter(path)); return converter.take(); }); //We have unsaved changes or load more then one file per time if (OpenNewEditor(path)) { return false; } qDebug("Loking watermark file"); VlpCreateLock(lock, path); if (lock->IsLocked()) { qDebug("Watermark file %s was locked.", qUtf8Printable(path)); } else { if (not IgnoreLocking(lock->GetLockError(), path)) { return false; } } VWatermark doc; try { QScopedPointer converter(futureConverter.result()); m_curFileFormatVersion = converter->GetCurrentFormatVersion(); m_curFileFormatVersionStr = converter->GetFormatVersionStr(); doc.setXMLContent(converter->Convert()); } catch (VException &e) { qCritical("%s\n\n%s\n\n%s", qUtf8Printable(tr("File error.")), qUtf8Printable(e.ErrorMessage()), qUtf8Printable(e.DetailedInformation())); Clear(); return false; } m_curFile = path; UpdateWindowTitle(); m_data = doc.GetWatermark(); ShowWatermark(); return true; } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::closeEvent(QCloseEvent *event) { #if defined(Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK(5, 11, 1) // Workaround for Qt bug https://bugreports.qt.io/browse/QTBUG-43344 static int numCalled = 0; if (numCalled++ >= 1) { return; } #endif if (MaybeSave()) { event->accept(); deleteLater(); } else { event->ignore(); } } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::changeEvent(QEvent *event) { if (event->type() == QEvent::LanguageChange) { // retranslate designer form (single inheritance approach) ui->retranslateUi(this); UpdateWindowTitle(); } // remember to call base class implementation QMainWindow::changeEvent(event); } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::showEvent(QShowEvent *event) { QMainWindow::showEvent( event ); if ( event->spontaneous() ) { return; } if (m_isInitialized) { return; } // do your init stuff here QSize sz = qApp->ValentinaSettings()->GetWatermarkEditorSize(); if (sz.isEmpty() == false) { resize(sz); } m_isInitialized = true;//first show windows are held } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::resizeEvent(QResizeEvent *event) { // remember the size for the next time this window is opened, but only // if the window was already initialized, which rules out the resize at // window creating, which would if (m_isInitialized) { qApp->ValentinaSettings()->SetWatermarkEditorSize(size()); } QMainWindow::resizeEvent(event); } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::on_actionNew_triggered() { emit New(); } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::on_actionSaveAs_triggered() { QString filters(tr("Watermark files") + QLatin1String("(*.vwm)")); QString dir; if (m_curFile.isEmpty()) { dir = QDir::homePath(); } else { dir = QFileInfo(m_curFile).absolutePath(); } QString fileName = QFileDialog::getSaveFileName(this, tr("Save as"), dir + QLatin1String("/") + tr("watermark") + QLatin1String(".vwm"), filters, nullptr); if (fileName.isEmpty()) { return false; } QFileInfo f( fileName ); if (f.suffix().isEmpty() && f.suffix() != QLatin1String("vwm")) { fileName += QLatin1String(".vwm"); } if (f.exists() && m_curFile != fileName) { // Temporary try to lock the file before saving VLockGuard tmp(fileName); if (not tmp.IsLocked()) { qCritical("%s", qUtf8Printable(tr("Failed to lock. This file already opened in another window."))); return false; } } QString error; const bool result = SaveWatermark(fileName, error); if (not result) { QMessageBox messageBox(this); messageBox.setIcon(QMessageBox::Warning); messageBox.setInformativeText(tr("Could not save file")); messageBox.setDefaultButton(QMessageBox::Ok); messageBox.setDetailedText(error); messageBox.setStandardButtons(QMessageBox::Ok); messageBox.exec(); return result; } if (m_curFile == fileName && not lock.isNull()) { lock->Unlock(); } VlpCreateLock(lock, fileName); if (lock->IsLocked()) { qDebug("Watermark file %s was locked.", qUtf8Printable(fileName)); } else { qDebug("Failed to lock %s", qUtf8Printable(fileName)); qDebug("Error type: %d", lock->GetLockError()); qCritical("%s", qUtf8Printable(tr("Failed to lock. This file already opened in another window. Expect " "collissions when run 2 copies of the program."))); } return result; } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::on_actionSave_triggered() { if (m_curFile.isEmpty()) { return on_actionSaveAs_triggered(); } else { if (m_curFileFormatVersion < VWatermarkConverter::WatermarkMaxVer && not ContinueFormatRewrite(m_curFileFormatVersionStr, VWatermarkConverter::WatermarkMaxVerStr)) { return false; } #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup++; // turn checking on #endif /*Q_OS_WIN32*/ const bool isFileWritable = QFileInfo(m_curFile).isWritable(); #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup--; // turn it off again #endif /*Q_OS_WIN32*/ if (not isFileWritable) { QMessageBox messageBox(this); messageBox.setIcon(QMessageBox::Question); messageBox.setText(tr("The document has no write permissions.")); messageBox.setInformativeText("Do you want to change the premissions?"); messageBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel); messageBox.setDefaultButton(QMessageBox::Yes); if (messageBox.exec() == QMessageBox::Yes) { #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup++; // turn checking on #endif /*Q_OS_WIN32*/ bool changed = QFile::setPermissions(m_curFile, QFileInfo(m_curFile).permissions() | QFileDevice::WriteUser); #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup--; // turn it off again #endif /*Q_OS_WIN32*/ if (not changed) { QMessageBox messageBoxWarning(this); messageBoxWarning.setIcon(QMessageBox::Warning); messageBoxWarning.setText(tr("Cannot set permissions for %1 to writable.").arg(m_curFile)); messageBoxWarning.setInformativeText(tr("Could not save the file.")); messageBoxWarning.setDefaultButton(QMessageBox::Ok); messageBoxWarning.setStandardButtons(QMessageBox::Ok); messageBoxWarning.exec(); return false; } } else { return false; } } QString error; bool result = SaveWatermark(m_curFile, error); if (result) { m_curFileFormatVersion = VWatermarkConverter::WatermarkMaxVer; m_curFileFormatVersionStr = VWatermarkConverter::WatermarkMaxVerStr; } else { QMessageBox messageBox(this); messageBox.setIcon(QMessageBox::Warning); messageBox.setText(tr("Could not save the file")); messageBox.setDefaultButton(QMessageBox::Ok); messageBox.setDetailedText(error); messageBox.setStandardButtons(QMessageBox::Ok); messageBox.exec(); } return result; } } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::on_actionOpen_triggered() { qDebug("Openning new watermark file."); const QString filter(tr("Watermark files") + QLatin1String(" (*.vwm)")); QString dir = QDir::homePath(); qDebug("Run QFileDialog::getOpenFileName: dir = %s.", qUtf8Printable(dir)); const QString filePath = QFileDialog::getOpenFileName(this, tr("Open file"), dir, filter, nullptr); if (filePath.isEmpty()) { return; } Open(filePath); } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::on_actionExit_triggered() { close(); } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::WatermarkChangesWereSaved(bool saved) { const bool state = /*doc->IsModified() ||*/ !saved; setWindowModified(state); } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::MaybeSave() { if (this->isWindowModified()) { QScopedPointer messageBox(new QMessageBox(tr("Unsaved changes"), tr("The watermark has been modified.\n" "Do you want to save your changes?"), QMessageBox::Warning, QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel, this, Qt::Sheet)); messageBox->setDefaultButton(QMessageBox::Yes); messageBox->setEscapeButton(QMessageBox::Cancel); messageBox->setButtonText(QMessageBox::Yes, m_curFile.isEmpty() ? tr("Save") : tr("Save as")); messageBox->setButtonText(QMessageBox::No, tr("Don't Save")); messageBox->setWindowModality(Qt::ApplicationModal); const auto ret = static_cast(messageBox->exec()); switch (ret) { case QMessageBox::Yes: return m_curFile.isEmpty() ? on_actionSaveAs_triggered() : on_actionSave_triggered(); case QMessageBox::No: return true; case QMessageBox::Cancel: return false; default: break; } } return true; } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::UpdateWindowTitle() { bool isFileWritable = true; if (not m_curFile.isEmpty()) { #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup++; // turn checking on #endif /*Q_OS_WIN32*/ isFileWritable = QFileInfo(m_curFile).isWritable(); #ifdef Q_OS_WIN32 qt_ntfs_permission_lookup--; // turn it off again #endif /*Q_OS_WIN32*/ } if (isFileWritable) { setWindowTitle(GetWatermarkFileName()); } else { setWindowTitle(GetWatermarkFileName() + QLatin1String(" (") + tr("read only") + QLatin1String(")")); } setWindowFilePath(m_curFile); #if defined(Q_OS_MAC) static QIcon fileIcon = QIcon(QCoreApplication::applicationDirPath() + QLatin1String("/../Resources/Valentina.icns")); QIcon icon; if (not m_curFile.isEmpty()) { if (not isWindowModified()) { icon = fileIcon; } else { static QIcon darkIcon; if (darkIcon.isNull()) { darkIcon = QIcon(darkenPixmap(fileIcon.pixmap(16, 16))); } icon = darkIcon; } } setWindowIcon(icon); #endif //defined(Q_OS_MAC) } //--------------------------------------------------------------------------------------------------------------------- QString WatermarkWindow::GetWatermarkFileName() { QString shownName = tr("untitled.vwm"); if(not m_curFile.isEmpty()) { shownName = StrippedName(m_curFile); } shownName += QLatin1String("[*]"); return shownName; } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::ContinueFormatRewrite(const QString ¤tFormatVersion, const QString &maxFormatVersion) { if (qApp->Settings()->GetConfirmFormatRewriting()) { Utils::CheckableMessageBox msgBox(this); msgBox.setWindowTitle(tr("Confirm format rewriting")); msgBox.setText(tr("This file is using previous format version v%1. The current is v%2. " "Saving the file with this app version will update the format version for this " "file. This may prevent you from be able to open the file with older app versions. " "Do you really want to continue?").arg(currentFormatVersion, maxFormatVersion)); msgBox.setStandardButtons(QDialogButtonBox::Yes | QDialogButtonBox::No); msgBox.setDefaultButton(QDialogButtonBox::No); msgBox.setIconPixmap(QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion).pixmap(32, 32)); int dialogResult = msgBox.exec(); if (dialogResult == QDialog::Accepted) { qApp->Settings()->SetConfirmFormatRewriting(not msgBox.isChecked()); return true; } else { return false; } } return true; } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::SaveWatermark(const QString &fileName, QString &error) { m_data.opacity = ui->spinBoxOpacity->value(); m_data.showText = ui->groupBoxWatermarkText->isChecked(); m_data.text = ui->lineEditText->text(); m_data.textRotation = ui->spinBoxTextRotation->value(); m_data.showImage = ui->groupBoxWatermarkImage->isChecked(); m_data.path = RelativeMPath(fileName, ui->lineEditPath->text()); m_data.imageRotation = ui->spinBoxImageRotation->value(); m_data.grayscale = ui->checkBoxGrayColor->isChecked(); VWatermark doc; doc.CreateEmptyWatermark(); doc.SetWatermark(m_data); const bool result = doc.SaveDocument(fileName, error); if (result) { SetCurrentFile(fileName); statusBar()->showMessage(tr("File saved"), 5000); WatermarkChangesWereSaved(result); } return result; } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::SetCurrentFile(const QString &fileName) { m_curFile = fileName; UpdateWindowTitle(); } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::OpenNewEditor(const QString &fileName) const { if (this->isWindowModified() || not m_curFile.isEmpty()) { emit OpenAnother(fileName); return true; } return false; } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::Clear() { m_curFile.clear(); UpdateWindowTitle(); setWindowModified(false); m_data = VWatermarkData(); ShowWatermark(); } //--------------------------------------------------------------------------------------------------------------------- bool WatermarkWindow::IgnoreLocking(int error, const QString &path) { QMessageBox::StandardButton answer = QMessageBox::Abort; switch(error) { case QLockFile::LockFailedError: answer = QMessageBox::warning(this, tr("Locking file"), tr("This file already opened in another window. Ignore if you want " "to continue (not recommended, can cause a data corruption)."), QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort); break; case QLockFile::PermissionError: answer = QMessageBox::question(this, tr("Locking file"), tr("The lock file could not be created, for lack of permissions. " "Ignore if you want to continue (not recommended, can cause " "a data corruption)."), QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort); break; case QLockFile::UnknownError: answer = QMessageBox::question(this, tr("Locking file"), tr("Unknown error happened, for instance a full partition prevented " "writing out the lock file. Ignore if you want to continue (not " "recommended, can cause a data corruption)."), QMessageBox::Abort|QMessageBox::Ignore, QMessageBox::Abort); break; default: answer = QMessageBox::Abort; break; } if (answer == QMessageBox::Abort) { qDebug("Failed to lock %s", qUtf8Printable(path)); qDebug("Error type: %d", error); Clear(); return false; } return true; } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::ShowWatermark() { ui->spinBoxOpacity->blockSignals(true); ui->spinBoxOpacity->setValue(m_data.opacity); ui->spinBoxOpacity->blockSignals(false); ui->groupBoxWatermarkText->blockSignals(true); ui->groupBoxWatermarkText->setChecked(m_data.showText); ui->groupBoxWatermarkText->blockSignals(false); ui->lineEditText->blockSignals(true); ui->lineEditText->setText(m_data.text); ui->lineEditText->blockSignals(false); ui->spinBoxTextRotation->blockSignals(true); ui->spinBoxTextRotation->setValue(m_data.textRotation); ui->spinBoxTextRotation->blockSignals(false); ui->lineEditFontSample->blockSignals(true); ui->lineEditFontSample->setFont(m_data.font); ui->lineEditFontSample->blockSignals(false); ui->groupBoxWatermarkImage->blockSignals(true); ui->groupBoxWatermarkImage->setChecked(m_data.showImage); ui->groupBoxWatermarkImage->blockSignals(false); ui->lineEditPath->blockSignals(true); ui->lineEditPath->setText(AbsoluteMPath(m_curFile, m_data.path)); ValidatePath(); ui->lineEditPath->blockSignals(false); ui->spinBoxImageRotation->blockSignals(true); ui->spinBoxImageRotation->setValue(m_data.imageRotation); ui->spinBoxImageRotation->blockSignals(false); ui->checkBoxGrayColor->blockSignals(true); ui->checkBoxGrayColor->setChecked(m_data.grayscale); ui->checkBoxGrayColor->blockSignals(false); } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::ValidatePath() { QPalette palette = ui->lineEditPath->palette(); const QString path = ui->lineEditPath->text(); palette.setColor(ui->lineEditPath->foregroundRole(), path.isEmpty() || QFileInfo::exists(path) ? m_okPathColor : Qt::red); ui->lineEditPath->setPalette(palette); } //--------------------------------------------------------------------------------------------------------------------- void WatermarkWindow::ToolBarStyle(QToolBar *bar) { SCASSERT(bar != nullptr) if (qApp->Settings()->GetToolBarStyle()) { bar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); } else { bar->setToolButtonStyle(Qt::ToolButtonIconOnly); } }