Actions Open Puzzle, Create Manual Layout, Update Manual Layout in Valentina.

This commit is contained in:
Roman Telezhynskyi 2020-04-21 19:02:21 +03:00
parent a9de60f515
commit 3b37d22a0b
12 changed files with 592 additions and 59 deletions

View File

@ -62,6 +62,28 @@ QT_WARNING_POP
Q_DECL_CONSTEXPR auto DAYS_TO_KEEP_LOGS = 3; Q_DECL_CONSTEXPR auto DAYS_TO_KEEP_LOGS = 3;
namespace
{
QString AppFilePath(const QString &appName)
{
QString appNameExe = appName;
#ifdef Q_OS_WIN
appNameExe += ".exe";
#endif
QFileInfo canonicalFile(QString("%1/%2").arg(QCoreApplication::applicationDirPath(), appNameExe));
if (canonicalFile.exists())
{
return canonicalFile.absoluteFilePath();
}
else
{
QFileInfo debugFile(QString("%1/../../%2/bin/%3")
.arg(QCoreApplication::applicationDirPath(), appName, appNameExe));
return debugFile.exists() ? debugFile.absoluteFilePath() : appNameExe;
}
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg) inline void noisyFailureMsgHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{ {
@ -447,54 +469,13 @@ void VApplication::ActivateDarkMode()
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
QString VApplication::TapeFilePath() const QString VApplication::TapeFilePath() const
{ {
const QString tape = QStringLiteral("tape"); return AppFilePath(QStringLiteral("tape"));
#ifdef Q_OS_WIN }
QFileInfo tapeFile(QCoreApplication::applicationDirPath() + "/" + tape + ".exe");
if (tapeFile.exists()) //---------------------------------------------------------------------------------------------------------------------
{ QString VApplication::PuzzleFilePath() const
return tapeFile.absoluteFilePath(); {
} return AppFilePath(QStringLiteral("puzzle"));
else
{
return QCoreApplication::applicationDirPath() + "/../../tape/bin/" + tape + ".exe";
}
#elif defined(Q_OS_MAC)
QFileInfo tapeFile(QCoreApplication::applicationDirPath() + "/" + tape);
if (tapeFile.exists())
{
return tapeFile.absoluteFilePath();
}
else
{
QFileInfo file(QCoreApplication::applicationDirPath() + "/../../tape/bin/" + tape);
if (file.exists())
{
return file.absoluteFilePath();
}
else
{
return tape;
}
}
#else // Unix
QFileInfo file(QCoreApplication::applicationDirPath() + "/../../tape/bin/" + tape);
if (file.exists())
{
return file.absoluteFilePath();
}
else
{
QFileInfo tapeFile(QCoreApplication::applicationDirPath() + "/" + tape);
if (tapeFile.exists())
{
return tapeFile.absoluteFilePath();
}
else
{
return tape;
}
}
#endif
} }
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View File

@ -58,6 +58,7 @@ public:
void InitOptions(); void InitOptions();
QString TapeFilePath() const; QString TapeFilePath() const;
QString PuzzleFilePath() const;
QTimer *getAutoSaveTimer() const; QTimer *getAutoSaveTimer() const;
void setAutoSaveTimer(QTimer *value); void setAutoSaveTimer(QTimer *value);

View File

@ -110,6 +110,7 @@ DialogSaveLayout::DialogSaveLayout(int count, Draw mode, const QString &fileName
} }
else else
{ {
RemoveFormatFromList(LayoutExportFormats::RLD);
ui->checkBoxTextAsPaths->setVisible(false); ui->checkBoxTextAsPaths->setVisible(false);
} }
@ -238,6 +239,7 @@ void DialogSaveLayout::SetBinaryDXFFormat(bool binary)
case LayoutExportFormats::PS: case LayoutExportFormats::PS:
case LayoutExportFormats::EPS: case LayoutExportFormats::EPS:
case LayoutExportFormats::NC: case LayoutExportFormats::NC:
case LayoutExportFormats::RLD:
default: default:
ui->checkBoxBinaryDXF->setChecked(false); ui->checkBoxBinaryDXF->setChecked(false);
break; break;
@ -285,6 +287,7 @@ bool DialogSaveLayout::IsBinaryDXFFormat() const
case LayoutExportFormats::PS: case LayoutExportFormats::PS:
case LayoutExportFormats::EPS: case LayoutExportFormats::EPS:
case LayoutExportFormats::NC: case LayoutExportFormats::NC:
case LayoutExportFormats::RLD:
default: default:
return false; return false;
} }
@ -424,6 +427,8 @@ QString DialogSaveLayout::ExportFormatDescription(LayoutExportFormats format)
return QStringLiteral("PDF %1 %2 (*.pdf)").arg(tr("tiled"), filesStr); return QStringLiteral("PDF %1 %2 (*.pdf)").arg(tr("tiled"), filesStr);
case LayoutExportFormats::NC: case LayoutExportFormats::NC:
return QStringLiteral("%1 %2 (*.nc)").arg(tr("Numerical control"), filesStr); return QStringLiteral("%1 %2 (*.nc)").arg(tr("Numerical control"), filesStr);
case LayoutExportFormats::RLD:
return QStringLiteral("%1 %2 (*.rld)").arg(tr("Raw Layout Data"), filesStr);
default: default:
return QString(); return QString();
} }
@ -477,6 +482,8 @@ QString DialogSaveLayout::ExportFormatSuffix(LayoutExportFormats format)
return QStringLiteral(".dxf"); return QStringLiteral(".dxf");
case LayoutExportFormats::NC: case LayoutExportFormats::NC:
return QStringLiteral(".nc"); return QStringLiteral(".nc");
case LayoutExportFormats::RLD:
return QStringLiteral(".rld");
default: default:
return QString(); return QString();
} }
@ -566,6 +573,7 @@ void DialogSaveLayout::ShowExample()
ui->checkBoxBinaryDXF->setEnabled(false); ui->checkBoxBinaryDXF->setEnabled(false);
ui->groupBoxPaperFormat->setEnabled(false); ui->groupBoxPaperFormat->setEnabled(false);
ui->groupBoxMargins->setEnabled(false); ui->groupBoxMargins->setEnabled(false);
ui->checkBoxTextAsPaths->setEnabled(true);
switch(currentFormat) switch(currentFormat)
{ {
@ -602,6 +610,9 @@ void DialogSaveLayout::ShowExample()
ui->groupBoxPaperFormat->setEnabled(true); ui->groupBoxPaperFormat->setEnabled(true);
ui->groupBoxMargins->setEnabled(true); ui->groupBoxMargins->setEnabled(true);
break; break;
case LayoutExportFormats::RLD:
ui->checkBoxTextAsPaths->setEnabled(false);
break;
case LayoutExportFormats::SVG: case LayoutExportFormats::SVG:
case LayoutExportFormats::PDF: case LayoutExportFormats::PDF:
case LayoutExportFormats::PNG: case LayoutExportFormats::PNG:
@ -869,6 +880,7 @@ QVector<std::pair<QString, LayoutExportFormats> > DialogSaveLayout::InitFormats(
InitFormat(LayoutExportFormats::DXF_AC1027_ASTM); InitFormat(LayoutExportFormats::DXF_AC1027_ASTM);
InitFormat(LayoutExportFormats::PDFTiled); InitFormat(LayoutExportFormats::PDFTiled);
// InitFormat(LayoutExportFormats::NC); // InitFormat(LayoutExportFormats::NC);
InitFormat(LayoutExportFormats::RLD);
return list; return list;
} }

View File

@ -3149,6 +3149,148 @@ void MainWindow::on_actionOpen_triggered()
LoadPattern(filePath); LoadPattern(filePath);
} }
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::on_actionOpenPuzzle_triggered()
{
const QString puzzle = qApp->PuzzleFilePath();
const QString workingDirectory = QFileInfo(puzzle).absoluteDir().absolutePath();
QStringList arguments;
if (isNoScaling)
{
arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
}
QProcess::startDetached(puzzle, arguments, workingDirectory);
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::on_actionCreateManualLayout_triggered()
{
QTemporaryFile rldFile(QDir::tempPath()+"/puzzle.rld.XXXXXX");
if (rldFile.open())
{
QVector<DetailForLayout> detailsInLayout = SortDetailsForLayout(pattern->DataPieces());
if (detailsInLayout.count() == 0)
{
QMessageBox::information(this, tr("Layout mode"), tr("You don't have enough details to export. Please, "
"include at least one detail in layout."),
QMessageBox::Ok, QMessageBox::Ok);
return;
}
QVector<VLayoutPiece> listDetails;
try
{
listDetails = PrepareDetailsForLayout(detailsInLayout);
}
catch (VException &e)
{
QMessageBox::warning(this, tr("Export details"),
tr("Can't export details.") + QLatin1String(" \n") + e.ErrorMessage(),
QMessageBox::Ok, QMessageBox::Ok);
return;
}
RLDFile(rldFile.fileName(), listDetails);
QStringList arguments {"-r", rldFile.fileName()};
if (isNoScaling)
{
arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
}
rldFile.setAutoRemove(false);
const QString puzzle = qApp->PuzzleFilePath();
const QString workingDirectory = QFileInfo(puzzle).absoluteDir().absolutePath();
QProcess::startDetached(puzzle, arguments, workingDirectory);
}
else
{
qCCritical(vMainWindow) << tr("Unable to prepare raw layout data.");
}
}
//---------------------------------------------------------------------------------------------------------------------
void MainWindow::on_actionUpdateManualLayout_triggered()
{
const QString filter(tr("Manual layout files") + QLatin1String(" (*.vlt)"));
//Use standard path to manual layouts
const QString path = qApp->ValentinaSettings()->GetPathManualLayouts();
bool usedNotExistedDir = false;
QDir directory(path);
if (not directory.exists())
{
usedNotExistedDir = directory.mkpath(QChar('.'));
}
auto RemoveUnsuded = qScopeGuard([usedNotExistedDir, path]()
{
if (usedNotExistedDir)
{
QDir directory(path);
directory.rmpath(QChar('.'));
}
});
const QString filePath = QFileDialog::getOpenFileName(this, tr("Select manual layout"), path, filter, nullptr);
if (filePath.isEmpty())
{
return;
}
QTemporaryFile rldFile(QDir::tempPath()+"/puzzle.rld.XXXXXX");
rldFile.setAutoRemove(false);
if (rldFile.open())
{
QVector<DetailForLayout> detailsInLayout = SortDetailsForLayout(pattern->DataPieces());
if (detailsInLayout.count() == 0)
{
QMessageBox::information(this, tr("Layout mode"), tr("You don't have enough details to export. Please, "
"include at least one detail in layout."),
QMessageBox::Ok, QMessageBox::Ok);
return;
}
QVector<VLayoutPiece> listDetails;
try
{
listDetails = PrepareDetailsForLayout(detailsInLayout);
}
catch (VException &e)
{
QMessageBox::warning(this, tr("Export details"),
tr("Can't export details.") + QLatin1String(" \n") + e.ErrorMessage(),
QMessageBox::Ok, QMessageBox::Ok);
return;
}
RLDFile(rldFile.fileName(), listDetails);
QStringList arguments {filePath, "-r", rldFile.fileName()};
if (isNoScaling)
{
arguments.append(QLatin1String("--") + LONG_OPTION_NO_HDPI_SCALING);
}
rldFile.setAutoRemove(false);
const QString puzzle = qApp->PuzzleFilePath();
const QString workingDirectory = QFileInfo(puzzle).absoluteDir().absolutePath();
QProcess::startDetached(puzzle, arguments, workingDirectory);
}
else
{
qCCritical(vMainWindow) << tr("Unable to prepare raw layout data.");
}
}
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------
/** /**
* @brief Clear reset to default window. * @brief Clear reset to default window.
@ -3554,7 +3696,9 @@ void MainWindow::SetEnableWidgets(bool enable)
{ {
const bool drawStage = (qApp->GetDrawMode() == Draw::Calculation); const bool drawStage = (qApp->GetDrawMode() == Draw::Calculation);
const bool detailsStage = (qApp->GetDrawMode() == Draw::Modeling); const bool detailsStage = (qApp->GetDrawMode() == Draw::Modeling);
const bool layoutStage = (qApp->GetDrawMode() == Draw::Layout);
const bool designStage = (drawStage || detailsStage); const bool designStage = (drawStage || detailsStage);
const bool piecesStage = (detailsStage || layoutStage);
comboBoxDraws->setEnabled(enable && drawStage); comboBoxDraws->setEnabled(enable && drawStage);
ui->actionOptionDraw->setEnabled(enable && drawStage); ui->actionOptionDraw->setEnabled(enable && drawStage);
@ -3588,6 +3732,8 @@ void MainWindow::SetEnableWidgets(bool enable)
ui->actionDecreaseLabelFont->setEnabled(enable); ui->actionDecreaseLabelFont->setEnabled(enable);
ui->actionOriginalLabelFont->setEnabled(enable); ui->actionOriginalLabelFont->setEnabled(enable);
ui->actionHideLabels->setEnabled(enable); ui->actionHideLabels->setEnabled(enable);
ui->actionCreateManualLayout->setEnabled(enable && piecesStage);
ui->actionUpdateManualLayout->setEnabled(enable && piecesStage);
ui->actionLoadWatermark->setEnabled(enable); ui->actionLoadWatermark->setEnabled(enable);
ui->actionRemoveWatermark->setEnabled(enable && not doc->GetWatermarkPath().isEmpty()); ui->actionRemoveWatermark->setEnabled(enable && not doc->GetWatermarkPath().isEmpty());

View File

@ -184,6 +184,10 @@ private slots:
bool on_actionSave_triggered(); bool on_actionSave_triggered();
void on_actionOpen_triggered(); void on_actionOpen_triggered();
void on_actionOpenPuzzle_triggered();
void on_actionCreateManualLayout_triggered();
void on_actionUpdateManualLayout_triggered();
void ClosedDialogUnionDetails(int result); void ClosedDialogUnionDetails(int result);
void ClosedDialogDuplicateDetail(int result); void ClosedDialogDuplicateDetail(int result);
void ClosedDialogGroup(int result); void ClosedDialogGroup(int result);

View File

@ -372,7 +372,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>104</width> <width>140</width>
<height>108</height> <height>108</height>
</rect> </rect>
</property> </property>
@ -481,7 +481,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>104</width> <width>126</width>
<height>243</height> <height>243</height>
</rect> </rect>
</property> </property>
@ -746,7 +746,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>104</width> <width>126</width>
<height>282</height> <height>282</height>
</rect> </rect>
</property> </property>
@ -1037,7 +1037,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>98</width> <width>140</width>
<height>102</height> <height>102</height>
</rect> </rect>
</property> </property>
@ -1120,7 +1120,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>104</width> <width>126</width>
<height>192</height> <height>192</height>
</rect> </rect>
</property> </property>
@ -1324,7 +1324,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>104</width> <width>126</width>
<height>237</height> <height>237</height>
</rect> </rect>
</property> </property>
@ -1589,8 +1589,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>104</width> <width>140</width>
<height>57</height> <height>170</height>
</rect> </rect>
</property> </property>
<attribute name="icon"> <attribute name="icon">
@ -1690,7 +1690,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>1100</width> <width>1100</width>
<height>22</height> <height>21</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">
@ -1804,12 +1804,21 @@
<addaction name="actionLoadWatermark"/> <addaction name="actionLoadWatermark"/>
<addaction name="actionRemoveWatermark"/> <addaction name="actionRemoveWatermark"/>
</widget> </widget>
<widget class="QMenu" name="menuManual_Layout">
<property name="title">
<string>Manual Layout</string>
</property>
<addaction name="actionOpenPuzzle"/>
<addaction name="actionCreateManualLayout"/>
<addaction name="actionUpdateManualLayout"/>
</widget>
<addaction name="menuFile"/> <addaction name="menuFile"/>
<addaction name="menuPatternPiece"/> <addaction name="menuPatternPiece"/>
<addaction name="menuMode"/> <addaction name="menuMode"/>
<addaction name="menuMeasurements"/> <addaction name="menuMeasurements"/>
<addaction name="menuHistory"/> <addaction name="menuHistory"/>
<addaction name="menuWatermark"/> <addaction name="menuWatermark"/>
<addaction name="menuManual_Layout"/>
<addaction name="menuWindow"/> <addaction name="menuWindow"/>
<addaction name="menuHelp"/> <addaction name="menuHelp"/>
</widget> </widget>
@ -3026,6 +3035,36 @@
<string>Create or edit a watermark</string> <string>Create or edit a watermark</string>
</property> </property>
</action> </action>
<action name="actionOpenPuzzle">
<property name="text">
<string>Open Puzzle</string>
</property>
<property name="toolTip">
<string>Open the Puzzle app</string>
</property>
</action>
<action name="actionCreateManualLayout">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Create</string>
</property>
<property name="toolTip">
<string>Create manual layout</string>
</property>
</action>
<action name="actionUpdateManualLayout">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Update</string>
</property>
<property name="toolTip">
<string>Update manual layout</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<customwidgets> <customwidgets>

View File

@ -53,6 +53,7 @@
#include "../ifc/xml/vvstconverter.h" #include "../ifc/xml/vvstconverter.h"
#include "../ifc/xml/vvitconverter.h" #include "../ifc/xml/vvitconverter.h"
#include "../ifc/xml/vwatermarkconverter.h" #include "../ifc/xml/vwatermarkconverter.h"
#include "../vlayout/vrawlayout.h"
#include <QFileDialog> #include <QFileDialog>
#include <QFileInfo> #include <QFileInfo>
@ -523,7 +524,8 @@ void MainWindowsNoGUI::ExportData(const QVector<VLayoutPiece> &listDetails)
format == LayoutExportFormats::DXF_AC1018_ASTM || format == LayoutExportFormats::DXF_AC1018_ASTM ||
format == LayoutExportFormats::DXF_AC1021_ASTM || format == LayoutExportFormats::DXF_AC1021_ASTM ||
format == LayoutExportFormats::DXF_AC1024_ASTM || format == LayoutExportFormats::DXF_AC1024_ASTM ||
format == LayoutExportFormats::DXF_AC1027_ASTM) format == LayoutExportFormats::DXF_AC1027_ASTM ||
format == LayoutExportFormats::RLD)
{ {
if (m_dialogSaveLayout->Mode() == Draw::Layout) if (m_dialogSaveLayout->Mode() == Draw::Layout)
{ {
@ -731,6 +733,9 @@ void MainWindowsNoGUI::ExportApparelLayout(const QVector<VLayoutPiece> &details,
case LayoutExportFormats::DXF_AC1027_AAMA: case LayoutExportFormats::DXF_AC1027_AAMA:
AAMADxfFile(name, DRW::AC1027, m_dialogSaveLayout->IsBinaryDXFFormat(), size, details); AAMADxfFile(name, DRW::AC1027, m_dialogSaveLayout->IsBinaryDXFFormat(), size, details);
break; break;
case LayoutExportFormats::RLD:
RLDFile(name, details, m_dialogSaveLayout->GetXScale(), m_dialogSaveLayout->GetYScale());
break;
default: default:
qDebug() << "Can't recognize file type." << Q_FUNC_INFO; qDebug() << "Can't recognize file type." << Q_FUNC_INFO;
break; break;
@ -1488,6 +1493,25 @@ void MainWindowsNoGUI::ASTMDxfFile(const QString &name, int version, bool binary
generator.ExportToASTM(details); generator.ExportToASTM(details);
} }
//---------------------------------------------------------------------------------------------------------------------
void MainWindowsNoGUI::RLDFile(const QString &name, QVector<VLayoutPiece> details, qreal xScale, qreal yScale) const
{
for(auto detail : details)
{
detail.Scale(xScale, yScale);
}
VRawLayoutData layoutDate;
layoutDate.pieces = details;
VRawLayout generator;
if (not generator.WriteFile(name, layoutDate))
{
const QString errorMsg = tr("Export raw layout data failed. %1.").arg(generator.ErrorString());
qApp->IsPedantic() ? throw VException(errorMsg) : qCritical() << errorMsg;
}
}
QT_WARNING_POP QT_WARNING_POP
//--------------------------------------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------------------------------------

View File

@ -150,6 +150,8 @@ protected:
QSharedPointer<VMeasurements> OpenMeasurementFile(const QString &path) const; QSharedPointer<VMeasurements> OpenMeasurementFile(const QString &path) const;
void CheckRequiredMeasurements(const VMeasurements *m) const; void CheckRequiredMeasurements(const VMeasurements *m) const;
void RLDFile(const QString &name, QVector<VLayoutPiece> details, qreal xScale=1, qreal yScale=1) const;
private slots: private slots:
void PrintPages (QPrinter *printer); void PrintPages (QPrinter *printer);
private: private:

View File

@ -13,6 +13,7 @@ HEADERS += \
$$PWD/vcontour_p.h \ $$PWD/vcontour_p.h \
$$PWD/vbestsquare.h \ $$PWD/vbestsquare.h \
$$PWD/vposition.h \ $$PWD/vposition.h \
$$PWD/vrawlayout.h \
$$PWD/vsapoint.h \ $$PWD/vsapoint.h \
$$PWD/vtextmanager.h \ $$PWD/vtextmanager.h \
$$PWD/vposter.h \ $$PWD/vposter.h \
@ -34,6 +35,7 @@ SOURCES += \
$$PWD/vcontour.cpp \ $$PWD/vcontour.cpp \
$$PWD/vbestsquare.cpp \ $$PWD/vbestsquare.cpp \
$$PWD/vposition.cpp \ $$PWD/vposition.cpp \
$$PWD/vrawlayout.cpp \
$$PWD/vtextmanager.cpp \ $$PWD/vtextmanager.cpp \
$$PWD/vposter.cpp \ $$PWD/vposter.cpp \
$$PWD/vgraphicsfillitem.cpp \ $$PWD/vgraphicsfillitem.cpp \

View File

@ -72,6 +72,7 @@ enum class LayoutExportFormats : qint8
DXF_AC1027_ASTM = 32, /* ACAD 2013. */ DXF_AC1027_ASTM = 32, /* ACAD 2013. */
PDFTiled = 33, PDFTiled = 33,
NC = 34, /*G-code. Reserved for future*/ NC = 34, /*G-code. Reserved for future*/
RLD = 35, /*Raw Layout Data*/
COUNT /*Use only for validation*/ COUNT /*Use only for validation*/
}; };

View File

@ -0,0 +1,248 @@
/************************************************************************
**
** @file vrawlayout.cpp
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 21 4, 2020
**
** @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) 2020 Valentina project
** <https://gitlab.com/smart-pattern/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#include "vrawlayout.h"
#include <QDataStream>
#include <QIODevice>
#include <QDebug>
#include <QFile>
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
#include "../vmisc/backport/qscopeguard.h"
#else
#include <QScopeGuard>
#endif
#include "../vmisc/def.h"
#include "../vmisc/vdatastreamenum.h"
#include "../ifc/exception/vexception.h"
const QByteArray VRawLayout::fileHeaderByteArray = QByteArray("RLD!...");
const quint16 VRawLayout::fileVersion = 1;
const quint32 VRawLayoutData::streamHeader = 0x8B0E8A27; // CRC-32Q string "VRawLayoutData"
const quint16 VRawLayoutData::classVersion = 1;
//---------------------------------------------------------------------------------------------------------------------
QDataStream &operator<<(QDataStream &dataStream, const VRawLayoutData &data)
{
dataStream << VRawLayoutData::streamHeader << VRawLayoutData::classVersion;
// Added in classVersion = 1
dataStream << data.pieces;
// Added in classVersion = 2
return dataStream;
}
//---------------------------------------------------------------------------------------------------------------------
QDataStream &operator>>(QDataStream &dataStream, VRawLayoutData &data)
{
quint32 actualStreamHeader = 0;
dataStream >> actualStreamHeader;
if (actualStreamHeader != VRawLayoutData::streamHeader)
{
QString message = QCoreApplication::tr("VRawLayoutData prefix mismatch error: actualStreamHeader = 0x%1 and "
"streamHeader = 0x%2")
.arg(actualStreamHeader, 8, 0x10, QChar('0'))
.arg(VRawLayoutData::streamHeader, 8, 0x10, QChar('0'));
throw VException(message);
}
quint16 actualClassVersion = 0;
dataStream >> actualClassVersion;
if (actualClassVersion > VRawLayoutData::classVersion)
{
QString message = QCoreApplication::tr("VRawLayoutData compatibility error: actualClassVersion = %1 and "
"classVersion = %2")
.arg( actualClassVersion ).arg(VRawLayoutData::classVersion);
throw VException(message);
}
dataStream >> data.pieces;
// if (actualClassVersion >= 2)
// {
// // read value in version 2
// }
return dataStream;
}
//---------------------------------------------------------------------------------------------------------------------
VRawLayout::VRawLayout()
{}
//---------------------------------------------------------------------------------------------------------------------
bool VRawLayout::WriteFile(QIODevice *ioDevice, const VRawLayoutData &data)
{
SCASSERT(ioDevice != nullptr)
m_errorString.clear();
const bool wasOpen = ioDevice->isOpen();
if (wasOpen || ioDevice->open(QIODevice::WriteOnly))
{
QDataStream dataStream(ioDevice);
dataStream.setVersion(QDataStream::Qt_5_4);
// Don't use the << operator for QByteArray. See the note in ReadFile() below.
dataStream.writeRawData(fileHeaderByteArray.constData(), fileHeaderByteArray.size());
dataStream << fileVersion;
dataStream << data;
if (not wasOpen)
{
ioDevice->close(); // Only close this if it was opened by this function.
}
return true;
}
else
{
m_errorString = ioDevice->errorString();
return false;
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
bool VRawLayout::ReadFile(QIODevice *ioDevice, VRawLayoutData &data)
{
SCASSERT(ioDevice != nullptr)
m_errorString.clear();
const bool wasOpen = ioDevice->isOpen();
if (wasOpen || ioDevice->open(QIODevice::ReadOnly))
{
auto CloseFile = qScopeGuard([wasOpen, ioDevice]()
{
if (not wasOpen) // Only close this if it was opened by this function.
{
ioDevice->close();
}
});
QDataStream dataStream(ioDevice);
dataStream.setVersion(QDataStream::Qt_5_4);
// Note: we could have used the QDataStream << and >> operators on QByteArray but since the first
// bytes of the stream will be the size of the array, we might end up attempting to allocate
// a large amount of memory if the wrong file type was read. Instead, we'll just read the
// same number of bytes that are in the array we are comparing it to. No size was written.
const int len = fileHeaderByteArray.size();
QByteArray actualFileHeaderByteArray( len, '\0' );
dataStream.readRawData( actualFileHeaderByteArray.data(), len );
if (actualFileHeaderByteArray != fileHeaderByteArray)
{
// prefixes don't match
m_errorString = tr("VRawLayout::ReadFile() failed. Raw layout format prefix mismatch error.");
return false;
}
quint16 actualFileVersion = 0;
dataStream >> actualFileVersion;
if (actualFileVersion > fileVersion)
{
// file is from a future version that we don't know how to load
m_errorString = tr("VRawLayout::ReadFile() failed.\n"
"Raw layout format compatibility error: actualFileVersion = %1 and fileVersion = %2" )
.arg(actualFileVersion).arg(fileVersion);
return false;
}
try
{
// This may throw an exception if one of the VRawLayoutData objects is corrupt or unsupported.
// For example, if this file is from a future version of this code.
dataStream >> data;
}
catch (const VException& e)
{
qCritical() << e.ErrorMessage();
m_errorString = e.ErrorMessage();
return false;
}
return true;
}
else
{
m_errorString = ioDevice->errorString();
return false;
}
return true;
}
//---------------------------------------------------------------------------------------------------------------------
bool VRawLayout::WriteFile(const QString &filePath, const VRawLayoutData &data)
{
QFile file(filePath);
if (file.open(QIODevice::WriteOnly | QIODevice::Truncate))
{
auto CloseFile = qScopeGuard([&file]()
{
file.flush();
file.close();
});
return WriteFile(&file, data);
}
else
{
m_errorString = file.errorString();
return false;
}
}
//---------------------------------------------------------------------------------------------------------------------
bool VRawLayout::ReadFile(const QString &filePath, VRawLayoutData &data)
{
QFile file(filePath);
if (file.open(QIODevice::ReadOnly))
{
auto CloseFile = qScopeGuard([&file]()
{
file.flush();
file.close();
});
return ReadFile(&file, data);
}
else
{
m_errorString = file.errorString();
return false;
}
}

View File

@ -0,0 +1,73 @@
/************************************************************************
**
** @file vrawlayout.h
** @author Roman Telezhynskyi <dismine(at)gmail.com>
** @date 21 4, 2020
**
** @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) 2020 Valentina project
** <https://gitlab.com/smart-pattern/valentina> 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 <http://www.gnu.org/licenses/>.
**
*************************************************************************/
#ifndef VRAWLAYOUT_H
#define VRAWLAYOUT_H
#include "vlayoutpiece.h"
struct VRawLayoutData
{
QVector<VLayoutPiece> pieces{};
friend QDataStream& operator<< (QDataStream& dataStream, const VRawLayoutData& date);
friend QDataStream& operator>> (QDataStream& dataStream, VRawLayoutData& date);
private:
static const quint32 streamHeader;
static const quint16 classVersion;
};
class VRawLayout
{
Q_DECLARE_TR_FUNCTIONS(VRawLayout)
public:
VRawLayout();
bool WriteFile(QIODevice* ioDevice, const VRawLayoutData& data);
bool ReadFile(QIODevice* ioDevice, VRawLayoutData& data);
bool WriteFile(const QString& filePath, const VRawLayoutData& data);
bool ReadFile(const QString& filePath, VRawLayoutData& data);
QString ErrorString() const;
private:
QString m_errorString{};
static const QByteArray fileHeaderByteArray;
static const quint16 fileVersion;
};
//---------------------------------------------------------------------------------------------------------------------
inline QString VRawLayout::ErrorString() const
{
return m_errorString;
}
#endif // VRAWLAYOUT_H