diff --git a/common/plotters/PDF_plotter.cpp b/common/plotters/PDF_plotter.cpp index b18025b478..7ff3d8f5f6 100644 --- a/common/plotters/PDF_plotter.cpp +++ b/common/plotters/PDF_plotter.cpp @@ -29,6 +29,7 @@ #include #include // snprintf +#include #include #include @@ -658,13 +659,19 @@ void PDF_PLOTTER::closePdfStream() } -void PDF_PLOTTER::StartPage( const wxString& aPageNumber, const wxString& aPageName ) +void PDF_PLOTTER::StartPage( const wxString& aPageNumber, const wxString& aPageName, + const wxString& aParentPageNumber, const wxString& aParentPageName ) { wxASSERT( m_outputFile ); wxASSERT( !m_workFile ); m_pageNumbers.push_back( aPageNumber ); - m_pageName = aPageName; + m_pageName = aPageName.IsEmpty() + ? wxString::Format( _( "Page %s" ), aPageNumber ) + : wxString::Format( _( "%s (Page %s)" ), aPageName, aPageNumber ); + m_parentPageName = aParentPageName.IsEmpty() + ? wxString::Format( _( "Page %s" ), aParentPageNumber ) + : wxString::Format( _( "%s (Page %s)" ), aParentPageName, aParentPageNumber ); // Compute the paper size in IUs m_paperSize = m_pageInfo.GetSizeMils(); @@ -889,20 +896,34 @@ void PDF_PLOTTER::ClosePage() // Mark the page stream as idle m_pageStreamHandle = 0; - wxString pageOutlineName = wxEmptyString; + int actionHandle = emitGoToAction( pageHandle ); + PDF_PLOTTER::OUTLINE_NODE* parent_node = m_outlineRoot.get(); - if( m_pageName.IsEmpty() ) + if( !m_parentPageName.IsEmpty() ) { - pageOutlineName = wxString::Format( _( "Page %s" ), m_pageNumbers.back() ); - } - else - { - pageOutlineName = wxString::Format( _( "%s (Page %s)" ), m_pageName, m_pageNumbers.back() ); + // Search for the parent node iteratively through the entire tree + std::stack nodes; + nodes.push( m_outlineRoot.get() ); + + while( !nodes.empty() ) + { + OUTLINE_NODE* node = nodes.top(); + nodes.pop(); + + // Check if this node matches + if( node->title == m_parentPageName ) + { + parent_node = node; + break; + } + + // Add all children to the stack + for( OUTLINE_NODE* child : node->children ) + nodes.push( child ); + } } - int actionHandle = emitGoToAction( pageHandle ); - OUTLINE_NODE* pageOutlineNode = - addOutlineNode( m_outlineRoot.get(), actionHandle, pageOutlineName ); + OUTLINE_NODE* pageOutlineNode = addOutlineNode( parent_node, actionHandle, m_pageName ); // let's reorg the symbol bookmarks under a page handle // let's reorg the symbol bookmarks under a page handle diff --git a/eeschema/sch_plotter.cpp b/eeschema/sch_plotter.cpp index 326e88d6f2..de743a5f96 100644 --- a/eeschema/sch_plotter.cpp +++ b/eeschema/sch_plotter.cpp @@ -122,7 +122,7 @@ void SCH_PLOTTER::createPDFFile( const SCH_PLOT_OPTS& aPlotOpts, if( aPlotOpts.m_plotAll || aPlotOpts.m_plotPages.size() > 0 ) { sheetList.BuildSheetList( &m_schematic->Root(), true ); - sheetList.SortByPageNumbers(); + sheetList.SortByHierarchicalPageNumbers(); // remove the non-selected pages if we are in plot pages mode if( aPlotOpts.m_plotPages.size() > 0 ) @@ -226,7 +226,20 @@ void SCH_PLOTTER::createPDFFile( const SCH_PLOT_OPTS& aPlotOpts, * reconfigure, and then start a new one */ plotter->ClosePage(); setupPlotPagePDF( plotter, screen, aPlotOpts ); - plotter->StartPage( sheetList[i].GetPageNumber(), sheetName ); + SCH_SHEET_PATH parentSheet = sheetList[i]; + + if( parentSheet.size() > 1 ) + { + // The sheet path is the full path to the sheet, so we need to remove the last + // sheet name to get the parent sheet path + parentSheet.pop_back(); + } + + wxString parentSheetName = + parentSheet.Last()->GetName(); + + plotter->StartPage( sheetList[i].GetPageNumber(), sheetName, + parentSheet.GetPageNumber(), parentSheetName ); } plotOneSheetPDF( plotter, screen, aPlotOpts ); diff --git a/eeschema/sch_sheet_path.cpp b/eeschema/sch_sheet_path.cpp index acf935ac23..5b358ad8d4 100644 --- a/eeschema/sch_sheet_path.cpp +++ b/eeschema/sch_sheet_path.cpp @@ -816,6 +816,44 @@ void SCH_SHEET_LIST::BuildSheetList( SCH_SHEET* aSheet, bool aCheckIntegrity ) } +void SCH_SHEET_LIST::SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums ) +{ + for( const SCH_SHEET_PATH& path : *this ) + path.CachePageNumber(); + + std::sort( begin(), end(), + []( const SCH_SHEET_PATH& a, const SCH_SHEET_PATH& b ) -> bool + { + if( a.size() != b.size() ) + return a.size() < b.size(); + + int retval = SCH_SHEET::ComparePageNum( a.GetCachedPageNumber(), + b.GetCachedPageNumber() ); + + if( retval < 0 ) + return true; + else if( retval > 0 ) + return false; + + if( a.GetVirtualPageNumber() < b.GetVirtualPageNumber() ) + return true; + else if( a.GetVirtualPageNumber() > b.GetVirtualPageNumber() ) + return false; + + // Enforce strict ordering. If the page numbers are the same, use UUIDs + return a.GetCurrentHash() < b.GetCurrentHash(); + } ); + + if( aUpdateVirtualPageNums ) + { + int virtualPageNum = 1; + + for( SCH_SHEET_PATH& sheet : *this ) + sheet.SetVirtualPageNumber( virtualPageNum++ ); + } +} + + void SCH_SHEET_LIST::SortByPageNumbers( bool aUpdateVirtualPageNums ) { for( const SCH_SHEET_PATH& path : *this ) diff --git a/eeschema/sch_sheet_path.h b/eeschema/sch_sheet_path.h index 9905e71536..568727ffd9 100644 --- a/eeschema/sch_sheet_path.h +++ b/eeschema/sch_sheet_path.h @@ -617,6 +617,13 @@ public: */ void SortByPageNumbers( bool aUpdateVirtualPageNums = true ); + /** + * This works like #SortByPageNumbers, but it sorts the sheets first by their hierarchical + * depth and then by their page numbers. This ensures that printouts follow the + * hierarchical structure of the schematic. + */ + void SortByHierarchicalPageNumbers( bool aUpdateVirtualPageNums = true ); + bool NameExists( const wxString& aSheetName ) const; bool PageNumberExists( const wxString& aPageNumber ) const; diff --git a/include/plotters/plotters_pslike.h b/include/plotters/plotters_pslike.h index 499b7d9219..eb6737fe88 100644 --- a/include/plotters/plotters_pslike.h +++ b/include/plotters/plotters_pslike.h @@ -289,7 +289,9 @@ public: * Start a new page in the PDF document. */ virtual void StartPage( const wxString& aPageNumber, - const wxString& aPageName = wxEmptyString ); + const wxString& aPageName = wxEmptyString, + const wxString& aParentPageNumber = wxEmptyString, + const wxString& aParentPageName = wxEmptyString ); /** * Close the current page in the PDF document (and emit its compressed stream). @@ -498,8 +500,11 @@ protected: std::vector m_pageHandles; ///< Handles to the page objects. int m_pageStreamHandle; ///< Handle of the page content object. int m_streamLengthHandle; ///< Handle to the deferred stream length. + wxString m_workFilename; wxString m_pageName; + wxString m_parentPageName; + FILE* m_workFile; ///< Temporary file to construct the stream before zipping. std::vector m_xrefTable; ///< The PDF xref offset table.