diff --git a/pcbnew/pcb_plotter.cpp b/pcbnew/pcb_plotter.cpp index 847dcf27eb..0a7d9eedcb 100644 --- a/pcbnew/pcb_plotter.cpp +++ b/pcbnew/pcb_plotter.cpp @@ -101,7 +101,10 @@ bool PCB_PLOTTER::Plot( const wxString& aOutputPath, const LSEQ& aLayersToPlot, LSEQ layersToPlot; LSEQ commonLayers; - if( aOutputPathIsSingle && !m_plotOpts.GetDXFMultiLayeredExportOption() ) + const bool isPdfMultiPage = + ( m_plotOpts.GetFormat() == PLOT_FORMAT::PDF && m_plotOpts.m_PDFSingle ); + + if( aOutputPathIsSingle && !m_plotOpts.GetDXFMultiLayeredExportOption() && !isPdfMultiPage ) { layersToPlot.push_back( aLayersToPlot[0] ); diff --git a/pcbnew/pcbnew_jobs_handler.cpp b/pcbnew/pcbnew_jobs_handler.cpp index 7fd980b715..8c069d136f 100644 --- a/pcbnew/pcbnew_jobs_handler.cpp +++ b/pcbnew/pcbnew_jobs_handler.cpp @@ -1100,7 +1100,9 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob ) return CLI::EXIT_CODES::ERR_ARGS; } - if( plotAllLayersOneFile && pdfJob->GetConfiguredOutputPath().IsEmpty() ) + const bool outputIsSingle = plotAllLayersOneFile || pdfJob->m_pdfSingle; + + if( outputIsSingle && pdfJob->GetConfiguredOutputPath().IsEmpty() ) { wxFileName fn = brd->GetFileName(); fn.SetName( fn.GetName() ); @@ -1114,13 +1116,9 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob ) PCB_PLOT_PARAMS plotOpts; PCB_PLOTTER::PlotJobToPlotOpts( plotOpts, pdfJob, *m_reporter ); - // ensure this is set for this one gen mode - if( plotAllLayersOneFile ) - plotOpts.m_PDFSingle = true; - PCB_PLOTTER pcbPlotter( brd, m_reporter, plotOpts ); - if( !PATHS::EnsurePathExists( outPath, plotAllLayersOneFile ) ) + if( !PATHS::EnsurePathExists( outPath, outputIsSingle ) ) { m_reporter->Report( _( "Failed to create output directory\n" ), RPT_SEVERITY_ERROR ); return CLI::EXIT_CODES::ERR_INVALID_OUTPUT_CONFLICT; @@ -1143,7 +1141,7 @@ int PCBNEW_JOBS_HANDLER::JobExportPdf( JOB* aJob ) } if( !pcbPlotter.Plot( outPath, pdfJob->m_plotLayerSequence, - pdfJob->m_plotOnAllLayersSequence, false, plotAllLayersOneFile, + pdfJob->m_plotOnAllLayersSequence, false, outputIsSingle, layerName, sheetName, sheetPath ) ) { return CLI::EXIT_CODES::ERR_UNKNOWN; diff --git a/qa/tests/pcbnew/CMakeLists.txt b/qa/tests/pcbnew/CMakeLists.txt index 1ff51efc96..8f55a9e390 100644 --- a/qa/tests/pcbnew/CMakeLists.txt +++ b/qa/tests/pcbnew/CMakeLists.txt @@ -51,6 +51,7 @@ set( QA_PCBNEW_SRCS test_prettifier.cpp test_libeval_compiler.cpp test_reference_image_load.cpp + test_pdf_output_path.cpp test_shape_corner_radius.cpp test_pcb_grid_helper.cpp test_save_load.cpp diff --git a/qa/tests/pcbnew/test_pdf_output_path.cpp b/qa/tests/pcbnew/test_pdf_output_path.cpp new file mode 100644 index 0000000000..22eb6f24aa --- /dev/null +++ b/qa/tests/pcbnew/test_pdf_output_path.cpp @@ -0,0 +1,73 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright The KiCad Developers, see AUTHORS.txt for contributors. + * + * This program 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 2 + * of the License, or (at your option) any later version. + * + * This program 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 this program; if not, you may find one here: + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html + * or you may search the http://www.gnu.org website for the version 2 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include +#include + +#include +#include +#include +#include + +#include + + +BOOST_AUTO_TEST_CASE( ExportPdfSingleDocumentOutputPath ) +{ + PCBNEW_JOBS_HANDLER handler( nullptr ); + + const std::filesystem::path boardPath = + std::filesystem::path( KI_TEST::GetPcbnewTestDataDir() ) / "api_kitchen_sink.kicad_pcb"; + + BOOST_REQUIRE( std::filesystem::exists( boardPath ) ); + + const std::filesystem::path outputRoot = + std::filesystem::temp_directory_path() / "kicad_pdf_single_doc_test"; + const std::filesystem::path outputPath = + outputRoot / "Assembly" / "Assembly_output.pdf"; + + if( std::filesystem::exists( outputRoot ) ) + std::filesystem::remove_all( outputRoot ); + + auto pdfJob = std::make_unique(); + pdfJob->m_filename = wxString::FromUTF8( boardPath.string().c_str() ); + pdfJob->SetConfiguredOutputPath( wxString::FromUTF8( outputPath.string().c_str() ) ); + pdfJob->m_plotDrawingSheet = false; + pdfJob->m_pdfSingle = true; + pdfJob->m_pdfGenMode = JOB_EXPORT_PCB_PDF::GEN_MODE::ONE_PAGE_PER_LAYER_ONE_FILE; + pdfJob->m_plotLayerSequence = LSEQ( { F_Cu } ); + + int result = handler.JobExportPdf( pdfJob.get() ); + BOOST_CHECK_EQUAL( result, CLI::EXIT_CODES::OK ); + + BOOST_CHECK( std::filesystem::exists( outputPath ) ); + BOOST_CHECK( std::filesystem::is_regular_file( outputPath ) ); + + const std::filesystem::path nestedPdf = + outputPath / ( boardPath.stem().string() + ".pdf" ); + BOOST_CHECK( !std::filesystem::exists( nestedPdf ) ); + + std::filesystem::remove_all( outputRoot ); +}