diff --git a/ChangeLog.txt b/ChangeLog.txt index 1757f2ada..d45a7a8ae 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -35,6 +35,7 @@ - New feature Pattern Messages. - [#984] Special variable "CurrentLength" for tools Cut Arc, Cut Spline and Cut Spline Path. - Added a ruler at the bottom of a tiled PDF document. +- Export tiled PDF with watermark. # Version 0.6.2 (unreleased) - [#903] Bug in tool Cut Spline path. diff --git a/src/app/valentina/dialogs/dialogpatternproperties.ui b/src/app/valentina/dialogs/dialogpatternproperties.ui index 90117708f..4f5631aa7 100644 --- a/src/app/valentina/dialogs/dialogpatternproperties.ui +++ b/src/app/valentina/dialogs/dialogpatternproperties.ui @@ -14,7 +14,7 @@ Pattern properties - + :/icon/64x64/icon64x64.png:/icon/64x64/icon64x64.png @@ -1220,13 +1220,26 @@ Security - + Open only for read + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -1421,20 +1434,18 @@ - - VPlainTextEdit - QPlainTextEdit -
vplaintextedit.h
-
VLineEdit QLineEdit
vlineedit.h
+ + VPlainTextEdit + QPlainTextEdit +
vplaintextedit.h
+
- - - + buttonBox diff --git a/src/app/valentina/mainwindow.cpp b/src/app/valentina/mainwindow.cpp index 0f5cf844f..f4e542ab8 100644 --- a/src/app/valentina/mainwindow.cpp +++ b/src/app/valentina/mainwindow.cpp @@ -64,6 +64,7 @@ #include "../qmuparser/qmuparsererror.h" #include "../vtools/dialogs/support/dialogeditlabel.h" #include "../vformat/vpatternrecipe.h" +#include "watermarkwindow.h" #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) #include "../vmisc/backport/qscopeguard.h" @@ -1933,6 +1934,69 @@ void MainWindow::SyncMeasurements() } } +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::CreateWatermark() +{ + CleanWaterkmarkEditors(); + OpenWatermark(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::EditCurrentWatermark() +{ + CleanWaterkmarkEditors(); + + QString watermarkFile = doc->GetWatermarkPath(); + if (not watermarkFile.isEmpty()) + { + OpenWatermark(watermarkFile); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::LoadWatermark() +{ + 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; + } + + if (doc->SetWatermarkPath(filePath)) + { + ui->actionRemoveWatermark->setEnabled(true); + ui->actionEditCurrentWatermark->setEnabled(true); + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::RemoveWatermark() +{ + if (doc->SetWatermarkPath(QString())) + { + ui->actionRemoveWatermark->setEnabled(false); + ui->actionEditCurrentWatermark->setEnabled(false); + } +} + + +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::CleanWaterkmarkEditors() +{ + QMutableListIterator> i(m_watermarkEditors); + while (i.hasNext()) + { + QPointer watermarkEditor = i.next(); + if (watermarkEditor.isNull()) + { + i.remove(); + } + } +} + //--------------------------------------------------------------------------------------------------------------------- #if defined(Q_OS_MAC) void MainWindow::OpenAt(QAction *where) @@ -3153,6 +3217,9 @@ void MainWindow::Clear() ui->actionOriginalLabelFont->setEnabled(false); ui->actionHideLabels->setEnabled(false); ui->plainTextEditPatternMessages->clear(); + ui->actionLoadWatermark->setEnabled(false); + ui->actionRemoveWatermark->setEnabled(false); + ui->actionEditCurrentWatermark->setEnabled(false); } //--------------------------------------------------------------------------------------------------------------------- @@ -3513,6 +3580,10 @@ void MainWindow::SetEnableWidgets(bool enable) ui->actionOriginalLabelFont->setEnabled(enable); ui->actionHideLabels->setEnabled(enable); + ui->actionLoadWatermark->setEnabled(enable); + ui->actionRemoveWatermark->setEnabled(enable && not doc->GetWatermarkPath().isEmpty()); + ui->actionEditCurrentWatermark->setEnabled(enable && not doc->GetWatermarkPath().isEmpty()); + actionDockWidgetToolOptions->setEnabled(enable && designStage); actionDockWidgetGroups->setEnabled(enable && designStage); @@ -4630,6 +4701,11 @@ void MainWindow::CreateActions() DialogEditLabel editor(doc); editor.exec(); }); + + connect(ui->actionWatermarkEditor, &QAction::triggered, this, &MainWindow::CreateWatermark); + connect(ui->actionEditCurrentWatermark, &QAction::triggered, this, &MainWindow::EditCurrentWatermark); + connect(ui->actionLoadWatermark, &QAction::triggered, this, &MainWindow::LoadWatermark); + connect(ui->actionRemoveWatermark, &QAction::triggered, this, &MainWindow::RemoveWatermark); } //--------------------------------------------------------------------------------------------------------------------- @@ -6161,3 +6237,25 @@ void MainWindow::PrintPatternMessage(QEvent *event) m_unreadPatternMessage->setText(DialogWarningIcon() + tr("Pattern messages")); } } + +//--------------------------------------------------------------------------------------------------------------------- +void MainWindow::OpenWatermark(const QString &path) +{ + QList>::const_iterator i; + for (i = m_watermarkEditors.begin(); i != m_watermarkEditors.end(); ++i) + { + if (not (*i).isNull() && not (*i)->CurrentFile().isEmpty() + && (*i)->CurrentFile() == AbsoluteMPath(qApp->GetPatternPath(), path)) + { + (*i)->show(); + return; + } + } + + auto *watermark = new WatermarkWindow(qApp->GetPatternPath(), this); + connect(watermark, &WatermarkWindow::New, this, [this](){OpenWatermark();}); + connect(watermark, &WatermarkWindow::OpenAnother, this, [this](const QString &path){OpenWatermark(path);}); + m_watermarkEditors.append(watermark); + watermark->show(); + watermark->Open(path); +} diff --git a/src/app/valentina/mainwindow.h b/src/app/valentina/mainwindow.h index ea85cdd67..ae4db1910 100644 --- a/src/app/valentina/mainwindow.h +++ b/src/app/valentina/mainwindow.h @@ -53,6 +53,7 @@ class VWidgetDetails; class QToolButton; class QDoubleSpinBox; class QProgressBar; +class WatermarkWindow; /** * @brief The MainWindow class main windows. @@ -197,6 +198,11 @@ private slots: void ShowMeasurements(); void MeasurementsChanged(const QString &path); void SyncMeasurements(); + + void CreateWatermark(); + void EditCurrentWatermark(); + void LoadWatermark(); + void RemoveWatermark(); #if defined(Q_OS_MAC) void OpenAt(QAction *where); #endif //defined(Q_OS_MAC) @@ -276,6 +282,8 @@ private: QProgressBar *m_progressBar; QLabel *m_statusLabel; + QList> m_watermarkEditors{}; + void SetDefaultHeight(); void SetDefaultSize(); @@ -381,6 +389,9 @@ private: void ToolSelectDetail(); void PrintPatternMessage(QEvent *event); + + void OpenWatermark(const QString &path = QString()); + void CleanWaterkmarkEditors(); }; #endif // MAINWINDOW_H diff --git a/src/app/valentina/mainwindow.ui b/src/app/valentina/mainwindow.ui index 3a6cd41c5..45663747b 100644 --- a/src/app/valentina/mainwindow.ui +++ b/src/app/valentina/mainwindow.ui @@ -1795,11 +1795,22 @@ + + + Watermark + + + + + + + + @@ -2980,6 +2991,50 @@ Globally show pieces main path + + + false + + + + .. + + + Load + + + + + false + + + + .. + + + Remove + + + + + false + + + Edit current + + + + + + .. + + + Editor + + + Create or edit a watermark + + diff --git a/src/app/valentina/mainwindowsnogui.cpp b/src/app/valentina/mainwindowsnogui.cpp index be9ac961c..281de0200 100644 --- a/src/app/valentina/mainwindowsnogui.cpp +++ b/src/app/valentina/mainwindowsnogui.cpp @@ -36,6 +36,7 @@ #include "../vmisc/dialogs/dialogexporttocsv.h" #include "../vmisc/qxtcsvmodel.h" #include "../vformat/vmeasurements.h" +#include "../vformat/vwatermark.h" #include "../vlayout/vlayoutgenerator.h" #include "dialogs/dialoglayoutprogress.h" #include "dialogs/dialogsavelayout.h" @@ -49,6 +50,7 @@ #include "../vtools/tools/vtoolseamallowance.h" #include "../ifc/xml/vvstconverter.h" #include "../ifc/xml/vvitconverter.h" +#include "../ifc/xml/vwatermarkconverter.h" #include #include @@ -876,6 +878,31 @@ void MainWindowsNoGUI::PrintPages(QPrinter *printer) copyCount = printer->copyCount(); } + VWatermarkData data; + const QString watermarkPath = AbsoluteMPath(qApp->GetPatternPath(), doc->GetWatermarkPath()); + if (not watermarkPath.isEmpty()) + { + try + { + VWatermarkConverter converter(watermarkPath); + VWatermark watermark; + watermark.setXMLContent(converter.Convert()); + data = watermark.GetWatermark(); + + if (not data.path.isEmpty()) + { + // Clean previous cache + QPixmapCache::remove(AbsoluteMPath(watermarkPath, data.path)); + } + } + catch (VException &e) + { + const QString errorMsg = tr("File error.\n\n%1\n\n%2").arg(e.ErrorMessage(), e.DetailedInformation()); + qApp->IsPedantic() ? throw VException(errorMsg) : + qWarning() << VAbstractApplication::patternMessageSignature + errorMsg; + } + } + for (int i = 0; i < copyCount; ++i) { for (int j = 0; j < numPages; ++j) @@ -905,10 +932,11 @@ void MainWindowsNoGUI::PrintPages(QPrinter *printer) if (paper) { QVector posterData; + if (isTiled) { - // Draw borders - posterData = posterazor->Borders(paper, poster->at(index), scenes.size()); + // Draw tile + posterData = posterazor->Tile(paper, poster->at(index), scenes.size(), data, watermarkPath); } PreparePaper(paperIndex); @@ -1408,7 +1436,6 @@ void MainWindowsNoGUI::PreparePaper(int index) const shadows.at(index)->setVisible(false); paper->setPen(QPen(Qt::white, 0.1, Qt::NoPen));// border } - } //--------------------------------------------------------------------------------------------------------------------- @@ -1718,43 +1745,6 @@ void MainWindowsNoGUI::SetPrinterSettings(QPrinter *printer, const PrintType &pr } printer->setDocName(FileName()); - - IsLayoutGrayscale() ? printer->setColorMode(QPrinter::GrayScale) : printer->setColorMode(QPrinter::Color); -} - -//--------------------------------------------------------------------------------------------------------------------- -bool MainWindowsNoGUI::IsLayoutGrayscale() const -{ - const QRect target = QRect(0, 0, 100, 100);//Small image less memory need - - for (int i=0; i < scenes.size(); ++i) - { - if (auto *paper = qgraphicsitem_cast(papers.at(i))) - { - // Hide shadow and paper border - PreparePaper(i); - - // Render png - QImage image(target.size(), QImage::Format_RGB32); - image.fill(Qt::white); - QPainter painter(&image); - painter.setPen(QPen(Qt::black, qApp->Settings()->WidthMainLine(), Qt::SolidLine, Qt::RoundCap, - Qt::RoundJoin)); - painter.setBrush ( QBrush ( Qt::NoBrush ) ); - scenes.at(i)->render(&painter, target, paper->rect(), Qt::KeepAspectRatio); - painter.end(); - - // Restore - RestorePaper(i); - - if (not image.isGrayscale()) - { - return false; - } - } - } - - return true; } //--------------------------------------------------------------------------------------------------------------------- diff --git a/src/app/valentina/mainwindowsnogui.h b/src/app/valentina/mainwindowsnogui.h index 30e7a0479..0db57b567 100644 --- a/src/app/valentina/mainwindowsnogui.h +++ b/src/app/valentina/mainwindowsnogui.h @@ -39,6 +39,7 @@ #include "dialogs/dialogsavelayout.h" #include "../vlayout/vlayoutgenerator.h" #include "../vwidgets/vabstractmainwindow.h" +#include "../vlayout/vtextmanager.h" class QGraphicsScene; struct PosterData; @@ -194,7 +195,6 @@ private: enum class PrintType : char {PrintPDF, PrintPreview, PrintNative}; void SetPrinterSettings(QPrinter *printer, const PrintType &printType); - bool IsLayoutGrayscale() const; QPageSize::PageSizeId FindPageSizeId(const QSizeF &size) const; bool isPagesUniform() const; diff --git a/src/app/valentina/valentina.pri b/src/app/valentina/valentina.pri index 772b54f49..32fa0d9dd 100644 --- a/src/app/valentina/valentina.pri +++ b/src/app/valentina/valentina.pri @@ -10,7 +10,8 @@ include(core/core.pri) SOURCES += \ $$PWD/main.cpp \ $$PWD/mainwindow.cpp \ - $$PWD/mainwindowsnogui.cpp + $$PWD/mainwindowsnogui.cpp \ + $$PWD/watermarkwindow.cpp *msvc*:SOURCES += $$PWD/stable.cpp @@ -19,7 +20,10 @@ HEADERS += \ $$PWD/mainwindow.h \ $$PWD/stable.h \ $$PWD/version.h \ - $$PWD/mainwindowsnogui.h + $$PWD/mainwindowsnogui.h \ + $$PWD/watermarkwindow.h + # Main forms FORMS += \ - $$PWD/mainwindow.ui + $$PWD/mainwindow.ui \ + $$PWD/watermarkwindow.ui diff --git a/src/app/valentina/watermarkwindow.cpp b/src/app/valentina/watermarkwindow.cpp new file mode 100644 index 000000000..f801ade79 --- /dev/null +++ b/src/app/valentina/watermarkwindow.cpp @@ -0,0 +1,728 @@ +/************************************************************************ + ** + ** @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);}); +} + +//--------------------------------------------------------------------------------------------------------------------- +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 messageBox(this); + messageBox.setIcon(QMessageBox::Warning); + messageBox.setText(tr("Cannot set permissions for %1 to writable.").arg(m_curFile)); + messageBox.setInformativeText(tr("Could not save the file.")); + messageBox.setDefaultButton(QMessageBox::Ok); + messageBox.setStandardButtons(QMessageBox::Ok); + messageBox.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.text = ui->lineEditText->text(); + m_data.textRotation = ui->spinBoxTextRotation->value(); + 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->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->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); + } +} diff --git a/src/app/valentina/watermarkwindow.h b/src/app/valentina/watermarkwindow.h new file mode 100644 index 000000000..d0be5f303 --- /dev/null +++ b/src/app/valentina/watermarkwindow.h @@ -0,0 +1,103 @@ +/************************************************************************ + ** + ** @file watermarkwindow.h + ** @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 . + ** + *************************************************************************/ +#ifndef WATERMARKWINDOW_H +#define WATERMARKWINDOW_H + +#include + +#include "../ifc/ifcdef.h" +#include "../vformat/vwatermark.h" +#include "../vmisc/vlockguard.h" + +namespace Ui +{ +class WatermarkWindow; +} + +class WatermarkWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit WatermarkWindow(const QString &patternPath, QWidget *parent = nullptr); + ~WatermarkWindow(); + + QString CurrentFile() const; + + bool Open(QString path); + +signals: + void New(); + void OpenAnother(const QString &fileName) const; + +protected: + virtual void closeEvent(QCloseEvent *event) override; + virtual void changeEvent(QEvent* event) override; + virtual void showEvent(QShowEvent *event) override; + virtual void resizeEvent(QResizeEvent *event) override; + +private slots: + void on_actionNew_triggered(); + bool on_actionSaveAs_triggered(); + bool on_actionSave_triggered(); + void on_actionOpen_triggered(); + void on_actionExit_triggered(); + + void WatermarkChangesWereSaved(bool saved); + +private: + Q_DISABLE_COPY(WatermarkWindow) + Ui::WatermarkWindow *ui; + QString m_patternPath; + QString m_curFile{}; + VWatermarkData m_data{}; + QColor m_okPathColor; + bool m_isInitialized{false}; + + int m_curFileFormatVersion{0x0}; + QString m_curFileFormatVersionStr{QLatin1String("0.0.0")}; + + QSharedPointer> lock{}; + + bool MaybeSave(); + void UpdateWindowTitle(); + + QString GetWatermarkFileName(); + + bool ContinueFormatRewrite(const QString ¤tFormatVersion, const QString &maxFormatVersion); + bool SaveWatermark(const QString &fileName, QString &error); + void SetCurrentFile(const QString &fileName); + bool OpenNewEditor(const QString &fileName = QString()) const; + void Clear(); + bool IgnoreLocking(int error, const QString &path); + void ShowWatermark(); + void ValidatePath(); + void ToolBarStyle(QToolBar *bar); +}; + +#endif // WATERMARKWINDOW_H diff --git a/src/app/valentina/watermarkwindow.ui b/src/app/valentina/watermarkwindow.ui new file mode 100644 index 000000000..98504975b --- /dev/null +++ b/src/app/valentina/watermarkwindow.ui @@ -0,0 +1,363 @@ + + + WatermarkWindow + + + + 0 + 0 + 532 + 468 + + + + Watermark + + + + :/icon/64x64/icon64x64.png:/icon/64x64/icon64x64.png + + + Qt::ToolButtonTextUnderIcon + + + + + + + true + + + + + 0 + 0 + 512 + 344 + + + + + + + QFormLayout::ExpandingFieldsGrow + + + + + + 0 + 0 + + + + Opacity: + + + + + + + + 0 + 0 + + + + % + + + 100 + + + 20 + + + + + + + + + + 0 + 0 + + + + Text + + + + QFormLayout::ExpandingFieldsGrow + + + + + Text: + + + + + + + + + + 32767 + + + watermark text + + + true + + + + + + + Rotation: + + + + + + + ° + + + 360 + + + + + + + + 0 + 0 + + + + Font: + + + + + + + + + The quick brown fox jumps over the lazy dog + + + true + + + + + + + Edit font + + + ... + + + + :/icon/24x24/font_preferences.png:/icon/24x24/font_preferences.png + + + + 24 + 24 + + + + + + + + + + + + + + 0 + 0 + + + + Image + + + + QFormLayout::ExpandingFieldsGrow + + + + + Path: + + + + + + + + + path to image + + + true + + + + + + + Browse… + + + + + + + + + Rotation: + + + + + + + ° + + + 100 + + + + + + + Gray color + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + 0 + 0 + 532 + 22 + + + + + &File + + + + + + + + + + + + + + Operations + + + false + + + TopToolBarArea + + + false + + + + + + + + + .. + + + Save + + + + + + .. + + + Save &As… + + + + + + .. + + + E&xit + + + + + + .. + + + Open + + + + + + .. + + + New + + + + + + + + diff --git a/src/libs/ifc/ifcdef.h b/src/libs/ifc/ifcdef.h index b4c7542ec..58fcb55d4 100644 --- a/src/libs/ifc/ifcdef.h +++ b/src/libs/ifc/ifcdef.h @@ -35,6 +35,7 @@ # include #endif /*Q_OS_WIN*/ +#include #include #include @@ -237,6 +238,17 @@ struct VLabelTemplateLine int fontSizeIncrement; }; +struct VWatermarkData +{ + int opacity{20}; + QString text{}; + int textRotation{0}; + QFont font{}; + QString path{}; + int imageRotation{0}; + bool grayscale{false}; +}; + QT_WARNING_POP #endif // IFCDEF_H diff --git a/src/libs/ifc/schema.qrc b/src/libs/ifc/schema.qrc index bef07eb83..bf0597e5d 100644 --- a/src/libs/ifc/schema.qrc +++ b/src/libs/ifc/schema.qrc @@ -57,6 +57,7 @@ schema/pattern/v0.8.3.xsd schema/pattern/v0.8.4.xsd schema/pattern/v0.8.5.xsd + schema/pattern/v0.8.6.xsd schema/standard_measurements/v0.3.0.xsd schema/standard_measurements/v0.4.0.xsd schema/standard_measurements/v0.4.1.xsd @@ -71,5 +72,6 @@ schema/individual_measurements/v0.4.0.xsd schema/individual_measurements/v0.5.0.xsd schema/label_template/v1.0.0.xsd + schema/watermark/v1.0.0.xsd diff --git a/src/libs/ifc/schema/pattern/v0.8.6.xsd b/src/libs/ifc/schema/pattern/v0.8.6.xsd new file mode 100644 index 000000000..7f860f2ac --- /dev/null +++ b/src/libs/ifc/schema/pattern/v0.8.6.xsd @@ -0,0 +1,1252 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/schema/watermark/v1.0.0.xsd b/src/libs/ifc/schema/watermark/v1.0.0.xsd new file mode 100644 index 000000000..1b9c44e31 --- /dev/null +++ b/src/libs/ifc/schema/watermark/v1.0.0.xsd @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/ifc/xml/vabstractpattern.cpp b/src/libs/ifc/xml/vabstractpattern.cpp index b89b5b041..297e9c6d0 100644 --- a/src/libs/ifc/xml/vabstractpattern.cpp +++ b/src/libs/ifc/xml/vabstractpattern.cpp @@ -55,6 +55,7 @@ #include "vdomdocument.h" #include "vtoolrecord.h" #include "../vmisc/vabstractapplication.h" +#include "../vlayout/vtextmanager.h" class QDomElement; @@ -90,6 +91,7 @@ const QString VAbstractPattern::TagPatternNum = QStringLiteral("patternNum const QString VAbstractPattern::TagCustomerName = QStringLiteral("customer"); const QString VAbstractPattern::TagCompanyName = QStringLiteral("company"); const QString VAbstractPattern::TagPatternLabel = QStringLiteral("patternLabel"); +const QString VAbstractPattern::TagWatermark = QStringLiteral("watermark"); const QString VAbstractPattern::TagPatternMaterials = QStringLiteral("patternMaterials"); const QString VAbstractPattern::TagFinalMeasurements= QStringLiteral("finalMeasurements"); const QString VAbstractPattern::TagMaterial = QStringLiteral("material"); @@ -132,6 +134,7 @@ const QString VAbstractPattern::AttrNumber = QStringLiteral("number") const QString VAbstractPattern::AttrCheckUniqueness = QStringLiteral("checkUniqueness"); const QString VAbstractPattern::AttrManualPassmarkLength = QStringLiteral("manualPassmarkLength"); const QString VAbstractPattern::AttrPassmarkLength = QStringLiteral("passmarkLength"); +const QString VAbstractPattern::AttrOpacity = QStringLiteral("opacity"); const QString VAbstractPattern::AttrAll = QStringLiteral("all"); @@ -215,6 +218,7 @@ Q_GLOBAL_STATIC_WITH_ARGS(QString, patternNumberCached, (unknownCharacter)) Q_GLOBAL_STATIC_WITH_ARGS(QString, labelDateFormatCached, (unknownCharacter)) Q_GLOBAL_STATIC_WITH_ARGS(QString, patternNameCached, (unknownCharacter)) Q_GLOBAL_STATIC_WITH_ARGS(QString, MPathCached, (unknownCharacter)) +Q_GLOBAL_STATIC_WITH_ARGS(QString, WatermarkPathCached, (unknownCharacter)) Q_GLOBAL_STATIC_WITH_ARGS(QString, companyNameCached, (unknownCharacter)) void ReadExpressionAttribute(QVector &expressions, const QDomElement &element, const QString &attribute) @@ -1525,6 +1529,48 @@ QVector VAbstractPattern::GetPatternLabelTemplate() const return patternLabelLines; } +//--------------------------------------------------------------------------------------------------------------------- +bool VAbstractPattern::SetWatermarkPath(const QString &path) +{ + QDomElement tag = CheckTagExists(TagWatermark); + + if (path.isEmpty()) + { + QDomNode parent = tag.parentNode(); + parent.removeChild(tag); + + emit patternChanged(false); + patternLabelWasChanged = true; + *WatermarkPathCached = path; + return true; + } + else + { + if (setTagText(tag, path)) + { + emit patternChanged(false); + patternLabelWasChanged = true; + *WatermarkPathCached = path; + return true; + } + else + { + qDebug() << "Can't save path to watermark" << Q_FUNC_INFO; + return false; + } + } +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VAbstractPattern::GetWatermarkPath() const +{ + if (*WatermarkPathCached == unknownCharacter) + { + *WatermarkPathCached = UniqueTagText(TagWatermark); + } + return *WatermarkPathCached; +} + //--------------------------------------------------------------------------------------------------------------------- void VAbstractPattern::SetPatternMaterials(const QMap &materials) { @@ -1728,10 +1774,23 @@ QDomElement VAbstractPattern::CheckTagExists(const QString &tag) QDomElement element; if (list.isEmpty()) { - const QStringList tags = QStringList() << TagUnit << TagImage << TagDescription << TagNotes - << TagGradation << TagPatternName << TagPatternNum << TagCompanyName - << TagCustomerName << TagPatternLabel << TagPatternMaterials - << TagFinalMeasurements; + const QStringList tags + { + TagUnit, // 0 + TagImage, // 1 + TagDescription, // 2 + TagNotes, // 3 + TagGradation, // 4 + TagPatternName, // 5 + TagPatternNum, // 6 + TagCompanyName, // 7 + TagCustomerName, // 8 + TagPatternLabel, // 9 + TagWatermark, // 10 + TagPatternMaterials, // 11 + TagFinalMeasurements // 12 + }; + switch (tags.indexOf(tag)) { case 1: //TagImage @@ -1771,10 +1830,13 @@ QDomElement VAbstractPattern::CheckTagExists(const QString &tag) case 9: // TagPatternLabel element = createElement(TagPatternLabel); break; - case 10: // TagPatternMaterials + case 10: // TagWatermark + element = createElement(TagWatermark); + break; + case 11: // TagPatternMaterials element = createElement(TagPatternMaterials); break; - case 11: // TagFinalMeasurements + case 12: // TagFinalMeasurements element = createElement(TagFinalMeasurements); break; case 0: //TagUnit (Mandatory tag) diff --git a/src/libs/ifc/xml/vabstractpattern.h b/src/libs/ifc/xml/vabstractpattern.h index baaf2fff1..1da118d76 100644 --- a/src/libs/ifc/xml/vabstractpattern.h +++ b/src/libs/ifc/xml/vabstractpattern.h @@ -43,6 +43,7 @@ #include "../vmisc/def.h" #include "vdomdocument.h" #include "vtoolrecord.h" +#include "../vlayout/vtextmanager.h" class QDomElement; class VPiecePath; @@ -172,6 +173,9 @@ public: void SetPatternLabelTemplate(const QVector &lines); QVector GetPatternLabelTemplate() const; + bool SetWatermarkPath(const QString &path); + QString GetWatermarkPath() const; + void SetPatternMaterials(const QMap &materials); QMap GetPatternMaterials() const; @@ -240,6 +244,7 @@ public: static const QString TagCompanyName; static const QString TagCustomerName; static const QString TagPatternLabel; + static const QString TagWatermark; static const QString TagPatternMaterials; static const QString TagFinalMeasurements; static const QString TagMaterial; @@ -282,6 +287,7 @@ public: static const QString AttrCheckUniqueness; static const QString AttrManualPassmarkLength; static const QString AttrPassmarkLength; + static const QString AttrOpacity; static const QString AttrAll; diff --git a/src/libs/ifc/xml/vpatternconverter.cpp b/src/libs/ifc/xml/vpatternconverter.cpp index aba3b81be..abf862c57 100644 --- a/src/libs/ifc/xml/vpatternconverter.cpp +++ b/src/libs/ifc/xml/vpatternconverter.cpp @@ -59,8 +59,8 @@ class QDomElement; */ const QString VPatternConverter::PatternMinVerStr = QStringLiteral("0.1.4"); -const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.8.5"); -const QString VPatternConverter::CurrentSchema = QStringLiteral("://schema/pattern/v0.8.5.xsd"); +const QString VPatternConverter::PatternMaxVerStr = QStringLiteral("0.8.6"); +const QString VPatternConverter::CurrentSchema = QStringLiteral("://schema/pattern/v0.8.6.xsd"); //VPatternConverter::PatternMinVer; // <== DON'T FORGET TO UPDATE TOO!!!! //VPatternConverter::PatternMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!! @@ -235,7 +235,8 @@ QString VPatternConverter::XSDSchema(int ver) const std::make_pair(FORMAT_VERSION(0, 8, 2), QStringLiteral("://schema/pattern/v0.8.2.xsd")), std::make_pair(FORMAT_VERSION(0, 8, 3), QStringLiteral("://schema/pattern/v0.8.3.xsd")), std::make_pair(FORMAT_VERSION(0, 8, 4), QStringLiteral("://schema/pattern/v0.8.4.xsd")), - std::make_pair(FORMAT_VERSION(0, 8, 5), CurrentSchema) + std::make_pair(FORMAT_VERSION(0, 8, 5), QStringLiteral("://schema/pattern/v0.8.5.xsd")), + std::make_pair(FORMAT_VERSION(0, 8, 6), CurrentSchema) }; if (schemas.contains(ver)) @@ -476,6 +477,10 @@ void VPatternConverter::ApplyPatches() ValidateXML(XSDSchema(FORMAT_VERSION(0, 8, 5)), m_convertedFileName); Q_FALLTHROUGH(); case (FORMAT_VERSION(0, 8, 5)): + ToV0_8_6(); + ValidateXML(XSDSchema(FORMAT_VERSION(0, 8, 6)), m_convertedFileName); + Q_FALLTHROUGH(); + case (FORMAT_VERSION(0, 8, 6)): break; default: InvalidVersion(m_ver); @@ -493,7 +498,7 @@ void VPatternConverter::DowngradeToCurrentMaxVersion() bool VPatternConverter::IsReadOnly() const { // Check if attribute readOnly was not changed in file format - Q_STATIC_ASSERT_X(VPatternConverter::PatternMaxVer == FORMAT_VERSION(0, 8, 5), + Q_STATIC_ASSERT_X(VPatternConverter::PatternMaxVer == FORMAT_VERSION(0, 8, 6), "Check attribute readOnly."); // Possibly in future attribute readOnly will change position etc. @@ -1113,6 +1118,16 @@ void VPatternConverter::ToV0_8_5() Save(); } +//--------------------------------------------------------------------------------------------------------------------- +void VPatternConverter::ToV0_8_6() +{ + // TODO. Delete if minimal supported version is 0.8.6 + Q_STATIC_ASSERT_X(VPatternConverter::PatternMinVer < FORMAT_VERSION(0, 8, 6), + "Time to refactor the code."); + SetVersion(QStringLiteral("0.8.6")); + Save(); +} + //--------------------------------------------------------------------------------------------------------------------- void VPatternConverter::TagUnitToV0_2_0() { diff --git a/src/libs/ifc/xml/vpatternconverter.h b/src/libs/ifc/xml/vpatternconverter.h index 553675d52..40c0595d7 100644 --- a/src/libs/ifc/xml/vpatternconverter.h +++ b/src/libs/ifc/xml/vpatternconverter.h @@ -53,7 +53,7 @@ public: static const QString PatternMaxVerStr; static const QString CurrentSchema; static Q_DECL_CONSTEXPR const int PatternMinVer = FORMAT_VERSION(0, 1, 4); - static Q_DECL_CONSTEXPR const int PatternMaxVer = FORMAT_VERSION(0, 8, 5); + static Q_DECL_CONSTEXPR const int PatternMaxVer = FORMAT_VERSION(0, 8, 6); protected: virtual int MinVer() const override; @@ -128,6 +128,7 @@ private: void ToV0_8_3(); void ToV0_8_4(); void ToV0_8_5(); + void ToV0_8_6(); void TagUnitToV0_2_0(); void TagIncrementToV0_2_0(); diff --git a/src/libs/ifc/xml/vwatermarkconverter.cpp b/src/libs/ifc/xml/vwatermarkconverter.cpp new file mode 100644 index 000000000..037f8a53a --- /dev/null +++ b/src/libs/ifc/xml/vwatermarkconverter.cpp @@ -0,0 +1,108 @@ +/************************************************************************ + ** + ** @file vwatermarkconverter.cpp + ** @author Roman Telezhynskyi + ** @date 26 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 "vwatermarkconverter.h" + +/* + * Version rules: + * 1. Version have three parts "major.minor.patch"; + * 2. major part only for stable releases; + * 3. minor - 10 or more patch changes, or one big change; + * 4. patch - little change. + */ + +const QString VWatermarkConverter::WatermarkMinVerStr = QStringLiteral("1.0.0"); +const QString VWatermarkConverter::WatermarkMaxVerStr = QStringLiteral("1.0.0"); +const QString VWatermarkConverter::CurrentSchema = QStringLiteral("://schema/watermark/v1.0.0.xsd"); + +//VWatermarkConverter::WatermarkMinVer; // <== DON'T FORGET TO UPDATE TOO!!!! +//VWatermarkConverter::WatermarkMaxVer; // <== DON'T FORGET TO UPDATE TOO!!!! + +//--------------------------------------------------------------------------------------------------------------------- +VWatermarkConverter::VWatermarkConverter(const QString &fileName) + : VAbstractConverter(fileName) +{ + ValidateInputFile(CurrentSchema); +} + +//--------------------------------------------------------------------------------------------------------------------- +int VWatermarkConverter::MinVer() const +{ + return WatermarkMinVer; +} + +//--------------------------------------------------------------------------------------------------------------------- +int VWatermarkConverter::MaxVer() const +{ + return WatermarkMaxVer; +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VWatermarkConverter::MinVerStr() const +{ + return WatermarkMinVerStr; +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VWatermarkConverter::MaxVerStr() const +{ + return WatermarkMaxVerStr; +} + +//--------------------------------------------------------------------------------------------------------------------- +QString VWatermarkConverter::XSDSchema(int ver) const +{ + switch (ver) + { + case (0x010000): + return CurrentSchema; + default: + InvalidVersion(ver); + break; + } + return QString();//unreachable code +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWatermarkConverter::ApplyPatches() +{ + switch (m_ver) + { + case (0x010000): + break; + default: + InvalidVersion(m_ver); + break; + } +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWatermarkConverter::DowngradeToCurrentMaxVersion() +{ + SetVersion(WatermarkMaxVerStr); + Save(); +} diff --git a/src/libs/ifc/xml/vwatermarkconverter.h b/src/libs/ifc/xml/vwatermarkconverter.h new file mode 100644 index 000000000..6f626f868 --- /dev/null +++ b/src/libs/ifc/xml/vwatermarkconverter.h @@ -0,0 +1,62 @@ +/************************************************************************ + ** + ** @file vwatermarkconverter.h + ** @author Roman Telezhynskyi + ** @date 26 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 . + ** + *************************************************************************/ +#ifndef VWATERMARKCONVERTER_H +#define VWATERMARKCONVERTER_H + +#include "vabstractconverter.h" + +class VWatermarkConverter : public VAbstractConverter +{ +public: + explicit VWatermarkConverter(const QString &fileName); + virtual ~VWatermarkConverter() Q_DECL_EQ_DEFAULT; + + static const QString WatermarkMaxVerStr; + static const QString CurrentSchema; + static Q_DECL_CONSTEXPR const int WatermarkMinVer = FORMAT_VERSION(1, 0, 0); + static Q_DECL_CONSTEXPR const int WatermarkMaxVer = FORMAT_VERSION(1, 0, 0); + +protected: + virtual int MinVer() const override; + virtual int MaxVer() const override; + + virtual QString MinVerStr() const override; + virtual QString MaxVerStr() const override; + + virtual QString XSDSchema(int ver) const override; + virtual void ApplyPatches() override; + virtual void DowngradeToCurrentMaxVersion() override; + + virtual bool IsReadOnly() const override {return false;} + +private: + Q_DISABLE_COPY(VWatermarkConverter) + static const QString WatermarkMinVerStr; +}; + +#endif // VWATERMARKCONVERTER_H diff --git a/src/libs/ifc/xml/xml.pri b/src/libs/ifc/xml/xml.pri index d5d333e23..1c558ea04 100644 --- a/src/libs/ifc/xml/xml.pri +++ b/src/libs/ifc/xml/xml.pri @@ -10,7 +10,8 @@ HEADERS += \ $$PWD/vvstconverter.h \ $$PWD//vvitconverter.h \ $$PWD//vabstractmconverter.h \ - $$PWD/vlabeltemplateconverter.h + $$PWD/vlabeltemplateconverter.h \ + $$PWD/vwatermarkconverter.h SOURCES += \ $$PWD/vabstractconverter.cpp \ @@ -21,4 +22,5 @@ SOURCES += \ $$PWD/vvstconverter.cpp \ $$PWD//vvitconverter.cpp \ $$PWD//vabstractmconverter.cpp \ - $$PWD/vlabeltemplateconverter.cpp + $$PWD/vlabeltemplateconverter.cpp \ + $$PWD/vwatermarkconverter.cpp diff --git a/src/libs/vformat/vformat.pri b/src/libs/vformat/vformat.pri index f3b883b34..77773b0b9 100644 --- a/src/libs/vformat/vformat.pri +++ b/src/libs/vformat/vformat.pri @@ -4,7 +4,8 @@ SOURCES += \ $$PWD/vmeasurements.cpp \ $$PWD/vlabeltemplate.cpp \ - $$PWD/vpatternrecipe.cpp + $$PWD/vpatternrecipe.cpp \ + $$PWD/vwatermark.cpp *msvc*:SOURCES += $$PWD/stable.cpp @@ -12,4 +13,5 @@ HEADERS += \ $$PWD/vmeasurements.h \ $$PWD/stable.h \ $$PWD/vlabeltemplate.h \ - $$PWD/vpatternrecipe.h + $$PWD/vpatternrecipe.h \ + $$PWD/vwatermark.h diff --git a/src/libs/vformat/vwatermark.cpp b/src/libs/vformat/vwatermark.cpp new file mode 100644 index 000000000..04cdd5bb3 --- /dev/null +++ b/src/libs/vformat/vwatermark.cpp @@ -0,0 +1,144 @@ +/************************************************************************ + ** + ** @file vwatermark.cpp + ** @author Roman Telezhynskyi + ** @date 25 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 "vwatermark.h" + +#include "../vmisc/projectversion.h" + +const QString VWatermark::TagWatermark = QStringLiteral("watermark"); +const QString VWatermark::TagText = QStringLiteral("text"); +const QString VWatermark::TagImage = QStringLiteral("image"); + +const QString VWatermark::AttrOpacity = QStringLiteral("opacity"); +const QString VWatermark::AttrText = QStringLiteral("text"); +const QString VWatermark::AttrRotation = QStringLiteral("rotation"); +const QString VWatermark::AttrFont = QStringLiteral("font"); +const QString VWatermark::AttrPath = QStringLiteral("path"); +const QString VWatermark::AttrGrayscale = QStringLiteral("grayscale"); + +namespace +{ +//--------------------------------------------------------------------------------------------------------------------- +QString FileComment() +{ + return QString("Watermark created with Valentina v%1 (https://valentinaproject.bitbucket.io/).") + .arg(APP_VERSION_STR); +} +} + +//--------------------------------------------------------------------------------------------------------------------- +VWatermark::VWatermark() +{} + +//--------------------------------------------------------------------------------------------------------------------- +void VWatermark::CreateEmptyWatermark() +{ + this->clear(); + QDomElement wElement = this->createElement(TagWatermark); + + wElement.appendChild(createComment(FileComment())); + wElement.appendChild(CreateElementWithText(TagVersion, "1.0.0" /*VWatermarkConverter::WatermarkMaxVerStr*/)); + wElement.appendChild(createElement(TagText)); + wElement.appendChild(createElement(TagImage)); + + appendChild(wElement); + insertBefore(createProcessingInstruction(QStringLiteral("xml"), + QStringLiteral("version=\"1.0\" encoding=\"UTF-8\"")), this->firstChild()); +} + +//--------------------------------------------------------------------------------------------------------------------- +bool VWatermark::SaveDocument(const QString &fileName, QString &error) +{ + // Update comment with Valentina version + QDomNode commentNode = documentElement().firstChild(); + if (commentNode.isComment()) + { + QDomComment comment = commentNode.toComment(); + comment.setData(FileComment()); + } + + return VDomDocument::SaveDocument(fileName, error); +} + +//--------------------------------------------------------------------------------------------------------------------- +VWatermarkData VWatermark::GetWatermark() const +{ + VWatermarkData data; + + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + const QDomElement rootElement = root.toElement(); + data.opacity = GetParametrUInt(rootElement, AttrOpacity, QChar('2')); + + QDomElement text = rootElement.firstChildElement(TagText); + if (not text.isNull()) + { + data.text = GetParametrEmptyString(text, AttrText); + data.textRotation = GetParametrUInt(text, AttrRotation, QChar('0')); + data.font.fromString(GetParametrEmptyString(text, AttrFont)); + } + + QDomElement image = rootElement.firstChildElement(TagImage); + if (not image.isNull()) + { + data.path = GetParametrEmptyString(image, AttrPath); + data.imageRotation = GetParametrUInt(image, AttrRotation, QChar('0')); + data.grayscale = GetParametrBool(image, AttrGrayscale, falseStr); + } + } + + return data; +} + +//--------------------------------------------------------------------------------------------------------------------- +void VWatermark::SetWatermark(const VWatermarkData &data) +{ + QDomNode root = documentElement(); + if (not root.isNull() && root.isElement()) + { + QDomElement rootElement = root.toElement(); + SetAttribute(rootElement, AttrOpacity, data.opacity); + + QDomElement text = rootElement.firstChildElement(TagText); + if (not text.isNull()) + { + SetAttributeOrRemoveIf(text, AttrText, data.text, data.text.isEmpty()); + SetAttributeOrRemoveIf(text, AttrRotation, data.textRotation, data.textRotation == 0); + const QString fontString = data.font.toString(); + SetAttributeOrRemoveIf(text, AttrFont, fontString, fontString.isEmpty()); + } + + QDomElement image = rootElement.firstChildElement(TagImage); + if (not image.isNull()) + { + SetAttributeOrRemoveIf(image, AttrPath, data.path, data.path.isEmpty()); + SetAttributeOrRemoveIf(image, AttrRotation, data.imageRotation, data.imageRotation == 0); + SetAttributeOrRemoveIf(image, AttrGrayscale, data.grayscale, data.grayscale == false); + } + } +} diff --git a/src/libs/vformat/vwatermark.h b/src/libs/vformat/vwatermark.h new file mode 100644 index 000000000..37cb48c7d --- /dev/null +++ b/src/libs/vformat/vwatermark.h @@ -0,0 +1,63 @@ +/************************************************************************ + ** + ** @file vwatermark.h + ** @author Roman Telezhynskyi + ** @date 25 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 . + ** + *************************************************************************/ +#ifndef VWATERMARK_H +#define VWATERMARK_H + +#include "../ifc/xml/vdomdocument.h" + + +class VWatermark : public VDomDocument +{ + Q_DECLARE_TR_FUNCTIONS(VWatermark) +public: + VWatermark(); + virtual ~VWatermark() Q_DECL_EQ_DEFAULT; + + void CreateEmptyWatermark(); + + virtual bool SaveDocument(const QString &fileName, QString &error) override; + + VWatermarkData GetWatermark() const; + void SetWatermark(const VWatermarkData &data); + + static const QString TagWatermark; + static const QString TagText; + static const QString TagImage; + + static const QString AttrOpacity; + static const QString AttrText; + static const QString AttrRotation; + static const QString AttrFont; + static const QString AttrPath; + static const QString AttrGrayscale; + +private: + Q_DISABLE_COPY(VWatermark) +}; + +#endif // VWATERMARK_H diff --git a/src/libs/vlayout/vposter.cpp b/src/libs/vlayout/vposter.cpp index 6a925ce56..7a640c0ef 100644 --- a/src/libs/vlayout/vposter.cpp +++ b/src/libs/vlayout/vposter.cpp @@ -29,7 +29,6 @@ #include "vposter.h" #include -#include #include #include #include @@ -41,10 +40,14 @@ #include #include #include +#include +#include +#include #include "../vmisc/vmath.h" #include "../vmisc/def.h" #include "../vmisc/vabstractapplication.h" +#include "../ifc/exception/vexception.h" namespace { @@ -53,6 +56,65 @@ qreal ToPixel(qreal val) { return val / 25.4 * PrintDPI; // Mm to pixels with current dpi. } + +//--------------------------------------------------------------------------------------------------------------------- +QImage Grayscale(QImage image) +{ + for (int ii = 0; ii < image.height(); ii++) + { + uchar* scan = image.scanLine(ii); + int depth = 4; + for (int jj = 0; jj < image.width(); jj++) + { + QRgb* rgbpixel = reinterpret_cast(scan + jj * depth); + int gray = qGray(*rgbpixel); + *rgbpixel = QColor(gray, gray, gray, qAlpha(*rgbpixel)).rgba(); + } + } + + return image; +} + +//--------------------------------------------------------------------------------------------------------------------- +QPixmap WatermarkImageFromCache(const VWatermarkData &watermarkData, const QString &watermarkPath, QString &error) +{ + QPixmap pixmap; + QString imagePath = AbsoluteMPath(watermarkPath, watermarkData.path); + + if (not QPixmapCache::find(imagePath, pixmap)) + { + QImageReader imageReader(imagePath); + QImage watermark = imageReader.read(); + if (watermark.isNull()) + { + error = imageReader.errorString(); + return pixmap; + } + + if (watermarkData.grayscale) + { + watermark = Grayscale(watermark); + watermark.save("/home/dismine/grayscale.png", "PNG"); + } + + // Workaround for QGraphicsPixmapItem opacity problem. + // Opacity applied only if use a cached pixmap and only after first draw. First image always has opacity 1. + // Preparing an image manually allows to avoid the problem. + QImage tmp(watermark.width(), watermark.height(), watermark.format()); + tmp = tmp.convertToFormat(QImage::Format_ARGB32); + tmp.fill(Qt::transparent); + QPainter p; + p.begin(&tmp); + p.setOpacity(watermarkData.opacity/100.); + p.drawImage(QPointF(), watermark); + p.end(); + + pixmap = QPixmap::fromImage(tmp); + + QPixmapCache::insert(imagePath, pixmap); + } + return pixmap; +} } //--------------------------------------------------------------------------------------------------------------------- @@ -89,6 +151,31 @@ QVector VPoster::Calc(const QRect &imageRect, int page, PageOrientat return poster; } +//--------------------------------------------------------------------------------------------------------------------- +QVector VPoster::Tile(QGraphicsItem *parent, + const PosterData &img, + int sheets, + const VWatermarkData &watermarkData, const QString &watermarkPath) const +{ + QVector data; + data.append(Borders(parent, img, sheets)); + + if (watermarkData.opacity > 0) + { + if (not watermarkData.path.isEmpty()) + { + data += ImageWatermark(parent, img, watermarkData, watermarkPath); + } + + if (not watermarkData.text.isEmpty()) + { + data += TextWatermark(parent, img, watermarkData); + } + } + + return data; +} + //--------------------------------------------------------------------------------------------------------------------- QVector VPoster::Borders(QGraphicsItem *parent, const PosterData &img, int sheets) const { @@ -176,6 +263,84 @@ QVector VPoster::Borders(QGraphicsItem *parent, const PosterDat return data; } +//--------------------------------------------------------------------------------------------------------------------- +QVector VPoster::TextWatermark(QGraphicsItem *parent, const PosterData &img, + const VWatermarkData &watermarkData) const +{ + SCASSERT(parent != nullptr) + + QVector data; + + QGraphicsSimpleTextItem *text = new QGraphicsSimpleTextItem(watermarkData.text, parent); + text->setFont(watermarkData.font); + text->setOpacity(watermarkData.opacity/100.); + text->setTransformOriginPoint(text->boundingRect().center()); + text->setRotation(-watermarkData.textRotation); + + const QRect boundingRect = text->boundingRect().toRect(); + int x = img.rect.x() + (img.rect.width() - boundingRect.width()) / 2; + int y = img.rect.y() + (img.rect.height() - boundingRect.height()) / 2; + + text->setX(x); + text->setY(y); + text->setZValue(-1); + + data.append(text); + + return data; +} + +//--------------------------------------------------------------------------------------------------------------------- +QVector VPoster::ImageWatermark(QGraphicsItem *parent, const PosterData &img, + const VWatermarkData &watermarkData, + const QString &watermarkPath) const +{ + SCASSERT(parent != nullptr) + + QVector data; + + QGraphicsItem *image = nullptr; + + QFileInfo f(watermarkData.path); + if (f.suffix() == "png" || f.suffix() == "jpg" || f.suffix() == "jpeg" || f.suffix() == "bmp") + { + QString error; + QPixmap watermark = WatermarkImageFromCache(watermarkData, watermarkPath, error); + + if (watermark.isNull()) + { + const QString errorMsg = tr("Cannot open the watermark image. %1").arg(error); + qApp->IsPedantic() ? throw VException(errorMsg) : + qWarning() << VAbstractApplication::patternMessageSignature + errorMsg; + return data; + } + + image = new QGraphicsPixmapItem(watermark, parent); + } + else + { + const QString errorMsg = tr("Not supported file suffix '%1'").arg(f.suffix()); + qApp->IsPedantic() ? throw VException(errorMsg) : + qWarning() << VAbstractApplication::patternMessageSignature + errorMsg; + return data; + } + + image->setZValue(-1); + image->setTransformOriginPoint(image->boundingRect().center()); + image->setRotation(-watermarkData.imageRotation); + + const QRect boundingRect = image->boundingRect().toRect(); + int x = img.rect.x() + (img.rect.width() - boundingRect.width()) / 2; + int y = img.rect.y() + (img.rect.height() - boundingRect.height()) / 2; + + image->setX(x); + image->setY(y); + + data.append(image); + + return data; +} + //--------------------------------------------------------------------------------------------------------------------- int VPoster::CountRows(int height, PageOrientation orientation) const { diff --git a/src/libs/vlayout/vposter.h b/src/libs/vlayout/vposter.h index 79b985a83..d242658b5 100644 --- a/src/libs/vlayout/vposter.h +++ b/src/libs/vlayout/vposter.h @@ -34,10 +34,12 @@ #include #include "../vmisc/def.h" +#include "../vlayout/vtextmanager.h" class QGraphicsItem; class QPrinter; template class QVector; +class VWatermarkData; struct PosterData { @@ -68,7 +70,9 @@ public: QVector Calc(const QRect &imageRect, int page, PageOrientation orientation) const; - QVector Borders(QGraphicsItem *parent, const PosterData &img, int sheets) const; + QVector Tile(QGraphicsItem *parent, const PosterData &img, int sheets, + const VWatermarkData &watermarkData, const QString &watermarkPath) const; + private: const QPrinter *printer; /** @@ -85,6 +89,13 @@ private: QRect PageRect() const; void Ruler(QVector &data, QGraphicsItem *parent, QRect rec) const; + + QVector Borders(QGraphicsItem *parent, const PosterData &img, int sheets) const; + + QVector TextWatermark(QGraphicsItem *parent, const PosterData &img, + const VWatermarkData &watermarkData) const; + QVector ImageWatermark(QGraphicsItem *parent, const PosterData &img, + const VWatermarkData &watermarkData, const QString &watermarkPath) const; }; #endif // VPOSTER_H diff --git a/src/libs/vmisc/share/resources/icon.qrc b/src/libs/vmisc/share/resources/icon.qrc index 1e346727e..ebd7ae48f 100644 --- a/src/libs/vmisc/share/resources/icon.qrc +++ b/src/libs/vmisc/share/resources/icon.qrc @@ -79,5 +79,11 @@ icon/32x32/button@2x.png icon/16x16/broom.png icon/16x16/broom@2x.png + icon/16x16/font_preferences@2x.png + icon/16x16/font_preferences.png + icon/32x32/font_preferences@2x.png + icon/32x32/font_preferences.png + icon/24x24/font_preferences@2x.png + icon/24x24/font_preferences.png diff --git a/src/libs/vmisc/share/resources/icon/16x16/font_preferences.png b/src/libs/vmisc/share/resources/icon/16x16/font_preferences.png new file mode 100644 index 000000000..8fd032e65 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/16x16/font_preferences.png differ diff --git a/src/libs/vmisc/share/resources/icon/16x16/font_preferences@2x.png b/src/libs/vmisc/share/resources/icon/16x16/font_preferences@2x.png new file mode 100644 index 000000000..a6041a898 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/16x16/font_preferences@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/24x24/font_preferences.png b/src/libs/vmisc/share/resources/icon/24x24/font_preferences.png new file mode 100644 index 000000000..93d71b5ac Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/24x24/font_preferences.png differ diff --git a/src/libs/vmisc/share/resources/icon/24x24/font_preferences@2x.png b/src/libs/vmisc/share/resources/icon/24x24/font_preferences@2x.png new file mode 100644 index 000000000..2cb6e7fd8 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/24x24/font_preferences@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/font_preferences.png b/src/libs/vmisc/share/resources/icon/32x32/font_preferences.png new file mode 100644 index 000000000..a6041a898 Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/font_preferences.png differ diff --git a/src/libs/vmisc/share/resources/icon/32x32/font_preferences@2x.png b/src/libs/vmisc/share/resources/icon/32x32/font_preferences@2x.png new file mode 100644 index 000000000..82c247c2d Binary files /dev/null and b/src/libs/vmisc/share/resources/icon/32x32/font_preferences@2x.png differ diff --git a/src/libs/vmisc/share/resources/icon/svg/font_preferences.svg b/src/libs/vmisc/share/resources/icon/svg/font_preferences.svg new file mode 100644 index 000000000..8ea824632 --- /dev/null +++ b/src/libs/vmisc/share/resources/icon/svg/font_preferences.svg @@ -0,0 +1,245 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + Jakub Steiner + + + http://jimmac.musichall.cz + + Wi-Fi network + + + + + + + + + + + + + + + + + + + + + diff --git a/src/libs/vmisc/vsettings.cpp b/src/libs/vmisc/vsettings.cpp index 12792f72a..548b69fc9 100644 --- a/src/libs/vmisc/vsettings.cpp +++ b/src/libs/vmisc/vsettings.cpp @@ -119,6 +119,8 @@ Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingDockWidgetPatternMessagesActive, (QLatin1String("dockWidget/patternMessagesActive"))) Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingPatternMessagesFontSize, (QLatin1String("font/patternMessagesSize"))) +Q_GLOBAL_STATIC_WITH_ARGS(const QString, settingWatermarkEditorSize, (QLatin1String("watermarkEditorSize"))) + // Reading settings file is very expensive, cache values to speed up getting a value int scrollingDurationCached = -1; int scrollingUpdateIntervalCached = -1; @@ -781,6 +783,18 @@ void VSettings::SetAutoRefreshPatternMessage(bool value) setValue(*settingAutoRefreshPatternMessage, value); } +//--------------------------------------------------------------------------------------------------------------------- +QSize VSettings::GetWatermarkEditorSize() const +{ + return value(*settingWatermarkEditorSize, QSize(0, 0)).toSize(); +} + +//--------------------------------------------------------------------------------------------------------------------- +void VSettings::SetWatermarkEditorSize(const QSize &sz) +{ + setValue(*settingWatermarkEditorSize, sz); +} + //--------------------------------------------------------------------------------------------------------------------- template T VSettings::GetCachedValue(T &cache, const QString &setting, T defValue, T valueMin, T valueMax) const diff --git a/src/libs/vmisc/vsettings.h b/src/libs/vmisc/vsettings.h index 96e39c151..21c13cb80 100644 --- a/src/libs/vmisc/vsettings.h +++ b/src/libs/vmisc/vsettings.h @@ -198,6 +198,9 @@ public: bool GetAutoRefreshPatternMessage() const; void SetAutoRefreshPatternMessage(bool value); + QSize GetWatermarkEditorSize() const; + void SetWatermarkEditorSize(const QSize& sz); + private: Q_DISABLE_COPY(VSettings)