/************************************************************************ ** ** @file vcmdexport.cpp ** @author Alex Zaharov ** @date 25 8, 2015 ** ** @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) 2015 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 "vcmdexport.h" #include "../dialogs/dialoglayoutsettings.h" #include "../dialogs/dialogsavelayout.h" #include "../ifc/xml/vdomdocument.h" #include "../vformat/vmeasurements.h" #include "../vmisc/commandoptions.h" #include "../vmisc/vsettings.h" #include "../vmisc/dialogs/dialogexporttocsv.h" #include "../vlayout/vlayoutgenerator.h" #include "../vpatterndb/variables/vmeasurement.h" #include #include VCommandLinePtr VCommandLine::instance = nullptr; #define translate(context, source) QCoreApplication::translate((context), (source)) namespace { //--------------------------------------------------------------------------------------------------------------------- qreal Lo2Px(const QString &src, const DialogLayoutSettings &converter) { return converter.LayoutToPixels(src.toDouble()); } //--------------------------------------------------------------------------------------------------------------------- qreal Pg2Px(const QString& src, const DialogLayoutSettings& converter) { return converter.PageToPixels(src.toDouble()); } } // anonymous namespace //--------------------------------------------------------------------------------------------------------------------- VCommandLine::VCommandLine() : parser(), isGuiEnabled(false) { parser.setApplicationDescription(translate("VCommandLine", "Pattern making program.")); parser.addHelpOption(); parser.addVersionOption(); parser.addPositionalArgument(QStringLiteral("filename"), translate("VCommandLine", "Pattern file.")); InitCommandLineOptions(); } //--------------------------------------------------------------------------------------------------------------------- VAbstractLayoutDialog::PaperSizeTemplate VCommandLine::FormatSize(const QString &key) const { int ppsize = 0; if (IsOptionSet(key)) { ppsize = OptionValue(key).toInt(); } return static_cast(ppsize); } //--------------------------------------------------------------------------------------------------------------------- VLayoutGeneratorPtr VCommandLine::DefaultGenerator() const { //this functions covers all options found into layout setup dialog, nothing to add here, unless dialog extended VLayoutGeneratorPtr res(new VLayoutGenerator()); DialogLayoutSettings diag(res.get(), nullptr, true); { //just anonymous namespace ...don' like to have a,b,c,d everywhere defined bool x = IsOptionSet(LONG_OPTION_PAGETEMPLATE); bool a = IsOptionSet(LONG_OPTION_PAGEH); bool b = IsOptionSet(LONG_OPTION_PAGEW); bool c = IsOptionSet(LONG_OPTION_PAGEUNITS); if ((a || b) && x) { qCritical() << translate("VCommandLine", "Cannot use pageformat and page explicit size together.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } if ((a || b || c) && !(a && b && c)) { qCritical() << translate("VCommandLine", "Page height, width, units must be used all 3 at once.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } } { //just anonymous namespace ...don' like to have a,b,c,d everywhere defined bool a = IsOptionSet(LONG_OPTION_GAPWIDTH); bool b = IsOptionSet(LONG_OPTION_SHIFTUNITS); if ((a || b) && !(a && b)) { qCritical() << translate("VCommandLine", "Gap width must be used together with shift units.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } } auto CheckKey = [this](const QString &key, const QString &message) { bool a = IsOptionSet(key); bool b = IsOptionSet(LONG_OPTION_PAGEUNITS); if ((a || b) && !(a && b)) { qCritical() << message << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } }; if (not IsOptionSet(LONG_OPTION_IGNORE_MARGINS)) { CheckKey(LONG_OPTION_LEFT_MARGIN, translate("VCommandLine", "Left margin must be used together with page units.")); CheckKey(LONG_OPTION_RIGHT_MARGIN, translate("VCommandLine", "Right margin must be used together with page units.")); CheckKey(LONG_OPTION_TOP_MARGIN, translate("VCommandLine", "Top margin must be used together with page units.")); CheckKey(LONG_OPTION_BOTTOM_MARGIN, translate("VCommandLine", "Bottom margin must be used together with page units.")); } if (static_cast(OptExportType()) == LayoutExportFormats::PDFTiled) { CheckKey(LONG_OPTION_TILED_PDF_LEFT_MARGIN, translate("VCommandLine", "Tiled left margin must be used together with page units.")); CheckKey(LONG_OPTION_TILED_PDF_RIGHT_MARGIN, translate("VCommandLine", "Tiled right margin must be used together with page units.")); CheckKey(LONG_OPTION_TILED_PDF_TOP_MARGIN, translate("VCommandLine", "Tiled top margin must be used together with page units.")); CheckKey(LONG_OPTION_TILED_PDF_BOTTOM_MARGIN, translate("VCommandLine", "Tiled bottom margin must be used together with page units.")); } // if present units MUST be set before any other to keep conversions correct if (!diag.SelectTemplate(OptPaperSize())) { qCritical() << translate("VCommandLine", "Unknown page templated selected.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } if (IsOptionSet(LONG_OPTION_PAGEH)) { //at this point we already sure 3 are set or none if (!diag.SelectPaperUnit(OptionValue(LONG_OPTION_PAGEUNITS))) { qCritical() << translate("VCommandLine", "Unsupported paper units.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } diag.SetPaperHeight (Pg2Px(OptionValue(LONG_OPTION_PAGEH), diag)); diag.SetPaperWidth (Pg2Px(OptionValue(LONG_OPTION_PAGEW), diag)); } else { // Not explicit page size if (IsOptionSet(LONG_OPTION_LANDSCAPE_ORIENTATION)) { diag.EnableLandscapeOrientation(); } } if (IsOptionSet(LONG_OPTION_SHIFTUNITS)) { if (!diag.SelectLayoutUnit(OptionValue(LONG_OPTION_SHIFTUNITS))) { qCritical() << translate("VCommandLine", "Unsupported layout units.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } } if (IsOptionSet(LONG_OPTION_GAPWIDTH)) { diag.SetLayoutWidth(Lo2Px(OptionValue(LONG_OPTION_GAPWIDTH), diag)); } diag.SetAutoCropLength(IsOptionSet(LONG_OPTION_CROP_LENGTH)); diag.SetAutoCropWidth(IsOptionSet(LONG_OPTION_CROP_WIDTH)); diag.SetUnitePages(IsOptionSet(LONG_OPTION_UNITE)); diag.SetSaveLength(IsOptionSet(LONG_OPTION_SAVELENGTH)); diag.SetGroup(OptGroup()); if (IsOptionSet(LONG_OPTION_IGNORE_MARGINS)) { diag.SetIgnoreAllFields(true); } QMarginsF margins = diag.GetFields(); if (IsOptionSet(LONG_OPTION_LEFT_MARGIN)) { margins.setLeft(Pg2Px(OptionValue(LONG_OPTION_LEFT_MARGIN), diag)); } if (IsOptionSet(LONG_OPTION_RIGHT_MARGIN)) { margins.setRight(Pg2Px(OptionValue(LONG_OPTION_RIGHT_MARGIN), diag)); } if (IsOptionSet(LONG_OPTION_TOP_MARGIN)) { margins.setTop(Pg2Px(OptionValue(LONG_OPTION_TOP_MARGIN), diag)); } if (IsOptionSet(LONG_OPTION_BOTTOM_MARGIN)) { margins.setBottom(Pg2Px(OptionValue(LONG_OPTION_BOTTOM_MARGIN), diag)); } diag.SetFields(margins); diag.SetFollowGrainline(IsOptionSet(LONG_OPTION_FOLLOW_GRAINLINE)); diag.SetManualPriority(IsOptionSet(LONG_OPTION_MANUAL_PRIORITY)); diag.SetNestQuantity(IsOptionSet(LONG_OPTION_NEST_QUANTITY)); diag.SetNestingTime(OptNestingTime()); diag.SetEfficiencyCoefficient(OptEfficiencyCoefficient()); diag.DialogAccepted(); // filling VLayoutGenerator return res; } //------------------------------------------------------------------------------------------------------ VCommandLinePtr VCommandLine::Get(const QCoreApplication& app) { if (instance == nullptr) { instance.reset(new VCommandLine()); } instance->parser.process(app); //fixme: in case of additional options/modes which will need to disable GUI - add it here too instance->isGuiEnabled = not (instance->IsExportEnabled() || instance->IsTestModeEnabled() || instance->IsExportFMEnabled()); return instance; } //------------------------------------------------------------------------------------------------------ void VCommandLine::Reset() { instance.reset(); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsTestModeEnabled() const { const bool r = IsOptionSet(LONG_OPTION_TEST); if (r && parser.positionalArguments().size() != 1) { qCritical() << translate("VCommandLine", "Test option can be used with single input file only.") << "/n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } return r; } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsPedantic() const { // Pedantic doesn't work in GUI mode return IsGuiEnabled() ? false : IsOptionSet(LONG_OPTION_PENDANTIC); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsNoScalingEnabled() const { return IsOptionSet(LONG_OPTION_NO_HDPI_SCALING); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsExportEnabled() const { const bool r = IsOptionSet(LONG_OPTION_BASENAME); if (r && parser.positionalArguments().size() != 1) { qCritical() << translate("VCommandLine", "Export options can be used with single input file only.") << "/n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } return r; } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsExportFMEnabled() const { const bool r = IsOptionSet(LONG_OPTION_CSVEXPORTFM); if (r && parser.positionalArguments().size() != 1) { qCritical() << translate("VCommandLine", "Export options can be used with single input file only.") << "/n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } return r; } //------------------------------------------------------------------------------------------------------ VAbstractLayoutDialog::PaperSizeTemplate VCommandLine::OptPaperSize() const { return FormatSize(LONG_OPTION_PAGETEMPLATE); } //------------------------------------------------------------------------------------------------------ Cases VCommandLine::OptGroup() const { int r = OptionValue(LONG_OPTION_GROUPPING).toInt(); if ( r < 0 || r >= static_cast(Cases::UnknownCase)) { r = 0; } return static_cast(r); } //------------------------------------------------------------------------------------------------------ QString VCommandLine::OptMeasurePath() const { QString measure; if (IsOptionSet(LONG_OPTION_MEASUREFILE) && (IsExportEnabled() || IsTestModeEnabled())) //todo: don't want yet to allow user set measure file for general loading, //because need to fix multiply opened windows as well { measure = OptionValue(LONG_OPTION_MEASUREFILE); } return measure; } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptBaseName() const { QString path; if (IsExportEnabled()) { path = OptionValue(LONG_OPTION_BASENAME); } return path; } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptDestinationPath() const { QString path; if (IsExportEnabled()) { path = OptionValue(LONG_OPTION_DESTINATION); } return path; } //--------------------------------------------------------------------------------------------------------------------- int VCommandLine::OptExportType() const { int r = 0; if (IsOptionSet(LONG_OPTION_EXP2FORMAT)) { r = OptionValue(LONG_OPTION_EXP2FORMAT).toInt(); } return r; } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsBinaryDXF() const { return IsOptionSet(LONG_OPTION_BINARYDXF); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsTextAsPaths() const { return IsOptionSet(LONG_OPTION_TEXT2PATHS); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsExportOnlyDetails() const { return IsOptionSet(LONG_OPTION_EXPORTONLYDETAILS); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsCSVWithHeader() const { return IsOptionSet(LONG_OPTION_CSVWITHHEADER); } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptExportSuchDetails() const { QString path; if (IsExportEnabled()) { path = OptionValue(LONG_OPTION_EXPORTSUCHDETAILS); } return path; } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptCSVCodecName() const { return OptionValue(LONG_OPTION_CSVCODEC); } //--------------------------------------------------------------------------------------------------------------------- QChar VCommandLine::OptCSVSeparator() const { const QString value = OptionValue(LONG_OPTION_CSVSEPARATOR); return not value.isEmpty() ? value.at(0) : QChar(); } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptExportFMTo() const { return OptionValue(LONG_OPTION_CSVEXPORTFM); } //--------------------------------------------------------------------------------------------------------------------- QMap VCommandLine::OptUserMaterials() const { QMap userMaterials; const QStringList values = OptionValues(LONG_OPTION_USER_MATERIAL); for(auto &value : values) { const QStringList parts = value.split('@'); if (parts.size() != 2) { qCritical() << translate("VCommandLine", "Invalid user material '%1'. Separator is missing.").arg(value) << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } bool ok = false; const int number = parts.first().toInt(&ok); if (not ok or number < 1 or number > userMaterialPlaceholdersQuantity) { qCritical() << translate("VCommandLine", "Invalid user material '%1'. Wrong material number.").arg(value) << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } userMaterials.insert(number, parts.last()); } return userMaterials; } //--------------------------------------------------------------------------------------------------------------------- QStringList VCommandLine::OptInputFileNames() const { return parser.positionalArguments(); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsGuiEnabled() const { return isGuiEnabled; } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsSetGradationSize() const { return IsOptionSet(LONG_OPTION_GRADATIONSIZE); } //--------------------------------------------------------------------------------------------------------------------- bool VCommandLine::IsSetGradationHeight() const { return IsOptionSet(LONG_OPTION_GRADATIONHEIGHT); } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptGradationSize() const { const QString size = OptionValue(LONG_OPTION_GRADATIONSIZE); if (VMeasurement::IsGradationSizeValid(size)) { return size; } qCritical() << translate("VCommandLine", "Invalid gradation size value.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } //--------------------------------------------------------------------------------------------------------------------- QString VCommandLine::OptGradationHeight() const { const QString height = OptionValue(LONG_OPTION_GRADATIONHEIGHT); if (VMeasurement::IsGradationHeightValid(height)) { return height; } qCritical() << translate("VCommandLine", "Invalid gradation height value.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } //--------------------------------------------------------------------------------------------------------------------- QMarginsF VCommandLine::TiledPageMargins() const { QMarginsF margins(10, 10, 10, 10); // mm if (not IsOptionSet(LONG_OPTION_LEFT_MARGIN)) { return margins; } const QString value = OptionValue(LONG_OPTION_LEFT_MARGIN); const QStringList supportedUnits = QStringList() << unitMM << unitCM << unitINCH; if (not supportedUnits.contains(value)) { qCritical() << translate("VCommandLine", "Unsupported paper units.") << "\n"; const_cast(this)->parser.showHelp(V_EX_USAGE); } const Unit unit = StrToUnits(value); if (IsOptionSet(LONG_OPTION_LEFT_MARGIN)) { margins.setLeft(UnitConvertor(OptionValue(LONG_OPTION_LEFT_MARGIN).toDouble(), unit, Unit::Mm)); } if (IsOptionSet(LONG_OPTION_RIGHT_MARGIN)) { margins.setRight(UnitConvertor(OptionValue(LONG_OPTION_RIGHT_MARGIN).toDouble(), unit, Unit::Mm)); } if (IsOptionSet(LONG_OPTION_TOP_MARGIN)) { margins.setTop(UnitConvertor(OptionValue(LONG_OPTION_TOP_MARGIN).toDouble(), unit, Unit::Mm)); } if (IsOptionSet(LONG_OPTION_BOTTOM_MARGIN)) { margins.setBottom(UnitConvertor(OptionValue(LONG_OPTION_BOTTOM_MARGIN).toDouble(), unit, Unit::Mm)); } return margins; } //--------------------------------------------------------------------------------------------------------------------- VAbstractLayoutDialog::PaperSizeTemplate VCommandLine::OptTiledPaperSize() const { return FormatSize(LONG_OPTION_TILED_PDF_PAGE_TEMPLATE); } //--------------------------------------------------------------------------------------------------------------------- PageOrientation VCommandLine::OptTiledPageOrientation() const { return static_cast(not IsOptionSet(LONG_OPTION_TILED_PDF_LANDSCAPE)); } //--------------------------------------------------------------------------------------------------------------------- void VCommandLine::InitCommandLineOptions() { //keep in mind order here - that is how user will see it, so group-up for usability //================================================================================================================= parser.addOptions({ {{SINGLE_OPTION_BASENAME, LONG_OPTION_BASENAME}, translate("VCommandLine", "The base filename of exported layout files. Use it to enable console export mode."), translate("VCommandLine", "The base filename of layout files")}, {{SINGLE_OPTION_DESTINATION, LONG_OPTION_DESTINATION}, translate("VCommandLine", "The path to output destination folder. By default the directory at which the " "application was started."), translate("VCommandLine", "The destination folder")}, {{SINGLE_OPTION_MEASUREFILE, LONG_OPTION_MEASUREFILE}, translate("VCommandLine", "Path to custom measure file (export mode)."), translate("VCommandLine", "The measure file")}, {{SINGLE_OPTION_NESTING_TIME, LONG_OPTION_NESTING_TIME}, translate("VCommandLine", "