From 5fa5a73c6d11da5709a32c4adcf30664b2ab4241 Mon Sep 17 00:00:00 2001 From: Jeff Young Date: Wed, 23 Jun 2021 23:53:08 +0100 Subject: [PATCH] File open/import progress dialogs. Fixes https://gitlab.com/kicad/code/kicad/issues/6864 Fixes https://gitlab.com/kicad/code/kicad/issues/2166 --- common/richio.cpp | 20 ++- common/single_top.cpp | 8 -- eeschema/files-io.cpp | 19 +-- eeschema/sch_io_mgr.h | 6 + .../sch_plugins/eagle/sch_eagle_plugin.cpp | 121 ++++++++++++++-- eeschema/sch_plugins/eagle/sch_eagle_plugin.h | 33 +++-- .../sch_plugins/kicad/sch_sexpr_parser.cpp | 33 ++++- eeschema/sch_plugins/kicad/sch_sexpr_parser.h | 10 +- .../sch_plugins/kicad/sch_sexpr_plugin.cpp | 26 +++- eeschema/sch_plugins/kicad/sch_sexpr_plugin.h | 23 +-- .../sch_plugins/legacy/sch_legacy_plugin.cpp | 52 ++++++- .../sch_plugins/legacy/sch_legacy_plugin.h | 26 ++-- eeschema/symbol_async_loader.cpp | 2 +- include/richio.h | 3 + kicad/tools/kicad_manager_control.cpp | 9 +- pcbnew/dialogs/dialog_board_setup.cpp | 6 +- .../dialogs/panel_pcbnew_color_settings.cpp | 2 +- pcbnew/files.cpp | 6 +- pcbnew/io_mgr.cpp | 5 +- pcbnew/io_mgr.h | 9 +- pcbnew/kicad_clipboard.cpp | 3 +- pcbnew/kicad_clipboard.h | 3 +- pcbnew/pcb_painter.cpp | 3 +- pcbnew/plugin.cpp | 2 +- .../altium/altium_circuit_maker_plugin.cpp | 3 +- .../altium/altium_circuit_maker_plugin.h | 3 +- .../altium/altium_circuit_studio_plugin.cpp | 3 +- .../altium/altium_circuit_studio_plugin.h | 2 +- .../plugins/altium/altium_designer_plugin.cpp | 3 +- .../plugins/altium/altium_designer_plugin.h | 3 +- .../cadstar/cadstar_pcb_archive_plugin.cpp | 3 +- .../cadstar/cadstar_pcb_archive_plugin.h | 3 +- pcbnew/plugins/eagle/eagle_plugin.cpp | 135 ++++++++++++++---- pcbnew/plugins/eagle/eagle_plugin.h | 16 ++- pcbnew/plugins/fabmaster/fabmaster_plugin.cpp | 3 +- pcbnew/plugins/fabmaster/fabmaster_plugin.h | 8 +- pcbnew/plugins/kicad/kicad_plugin.cpp | 24 +++- pcbnew/plugins/kicad/kicad_plugin.h | 6 +- pcbnew/plugins/kicad/pcb_parser.cpp | 27 +++- pcbnew/plugins/kicad/pcb_parser.h | 23 ++- pcbnew/plugins/legacy/legacy_plugin.cpp | 52 ++++++- pcbnew/plugins/legacy/legacy_plugin.h | 37 +++-- pcbnew/plugins/pcad/pcad_plugin.cpp | 3 +- pcbnew/plugins/pcad/pcad_plugin.h | 9 +- pcbnew/tools/pcb_control.cpp | 5 +- 45 files changed, 643 insertions(+), 158 deletions(-) diff --git a/common/richio.cpp b/common/richio.cpp index d888aa0607..4780e2c040 100644 --- a/common/richio.cpp +++ b/common/richio.cpp @@ -167,8 +167,8 @@ FILE_LINE_READER::FILE_LINE_READER( const wxString& aFileName, if( !m_fp ) { - wxString msg = wxString::Format( - _( "Unable to open filename \"%s\" for reading" ), aFileName.GetData() ); + wxString msg = wxString::Format( _( "Unable to open %s for reading." ), + aFileName.GetData() ); THROW_IO_ERROR( msg ); } @@ -195,6 +195,22 @@ FILE_LINE_READER::~FILE_LINE_READER() } +long int FILE_LINE_READER::FileLength() +{ + fseek( m_fp, 0, SEEK_END ); + long int fileLength = ftell( m_fp ); + rewind( m_fp ); + + return fileLength; +} + + +long int FILE_LINE_READER::CurPos() +{ + return ftell( m_fp ); +} + + char* FILE_LINE_READER::ReadLine() { m_length = 0; diff --git a/common/single_top.cpp b/common/single_top.cpp index 30da289073..4cf00b8514 100644 --- a/common/single_top.cpp +++ b/common/single_top.cpp @@ -369,14 +369,6 @@ bool PGM_SINGLE_TOP::OnPgmInit() App().SetTopWindow( frame ); // wxApp gets a face. App().SetAppDisplayName( frame->GetAboutTitle() ); - // Allocate a slice of time to show the frame and update wxWidgets widgets - // (especially setting valid sizes) after creating frame and before calling - // OpenProjectFiles() that can update/use some widgets. - // The 2 calls to wxSafeYield are needed on wxGTK for best results. - wxSafeYield(); - frame->Show(); - wxSafeYield(); - // Individual frames may provide additional option/switch processing, but for compatibility, // any positional arguments are treated as a list of files to pass to OpenProjectFiles frame->ParseArgs( parser ); diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 81ebd3201e..e31e932854 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -61,6 +61,7 @@ #include #include #include // For ::ResolvePossibleSymlinks +#include bool SCH_EDIT_FRAME::SaveEEFile( SCH_SHEET* aSheet, bool aSaveUnderNewName ) { @@ -400,6 +401,9 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in SCH_PLUGIN* plugin = SCH_IO_MGR::FindPlugin( schFileType ); SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( plugin ); + WX_PROGRESS_REPORTER progressReporter( this, _( "Loading Schematic" ), 1 ); + pi->SetProgressReporter( &progressReporter ); + bool failedLoad = false; try { @@ -1117,20 +1121,19 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType ) try { SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( fileType ) ); - DIALOG_HTML_REPORTER* reporter = new DIALOG_HTML_REPORTER( this ); + DIALOG_HTML_REPORTER errorReporter( this ); + WX_PROGRESS_REPORTER progressReporter( this, _( "Importing Schematic" ), 1 ); - pi->SetReporter( reporter->m_Reporter ); + pi->SetReporter( errorReporter.m_Reporter ); + pi->SetProgressReporter( &progressReporter ); Schematic().SetRoot( pi->Load( aFileName, &Schematic() ) ); - if( reporter->m_Reporter->HasMessage() ) + if( errorReporter.m_Reporter->HasMessage() ) { - reporter->m_Reporter->Flush(); // Build HTML messages - reporter->ShowModal(); + errorReporter.m_Reporter->Flush(); // Build HTML messages + errorReporter.ShowModal(); } - pi->SetReporter( &WXLOG_REPORTER::GetInstance() ); - delete reporter; - // Non-KiCad schematics do not use a drawing-sheet (or if they do, it works differently // to KiCad), so set it to an empty one DS_DATA_MODEL& drawingSheet = DS_DATA_MODEL::GetTheInstance(); diff --git a/eeschema/sch_io_mgr.h b/eeschema/sch_io_mgr.h index 7748c83f85..ab0033ace1 100644 --- a/eeschema/sch_io_mgr.h +++ b/eeschema/sch_io_mgr.h @@ -38,6 +38,7 @@ class KIWAY; class LIB_SYMBOL; class SYMBOL_LIB; class PROPERTIES; +class PROGRESS_REPORTER; /** @@ -164,6 +165,11 @@ public: */ virtual void SetReporter( REPORTER* aReporter ) {} + /** + * Set an optional progress reporter. + */ + virtual void SetProgressReporter( PROGRESS_REPORTER* aReporter ) {} + /** * Return the file extension for the #SCH_PLUGIN. */ diff --git a/eeschema/sch_plugins/eagle/sch_eagle_plugin.cpp b/eeschema/sch_plugins/eagle/sch_eagle_plugin.cpp index f940f7faf2..bbebd4f372 100644 --- a/eeschema/sch_plugins/eagle/sch_eagle_plugin.cpp +++ b/eeschema/sch_plugins/eagle/sch_eagle_plugin.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -60,6 +61,7 @@ #include #include #include +#include // Eagle schematic axes are aligned with x increasing left to right and Y increasing bottom to top @@ -351,7 +353,11 @@ static void eagleToKicadAlignment( EDA_TEXT* aText, int aEagleAlignment, int aRe } -SCH_EAGLE_PLUGIN::SCH_EAGLE_PLUGIN() +SCH_EAGLE_PLUGIN::SCH_EAGLE_PLUGIN() : + m_progressReporter( nullptr ), + m_doneCount( 0 ), + m_lastProgressCount( 0 ), + m_totalCount( 0 ) { m_rootSheet = nullptr; m_currentSheet = nullptr; @@ -390,6 +396,25 @@ int SCH_EAGLE_PLUGIN::GetModifyHash() const } +void SCH_EAGLE_PLUGIN::checkpoint() +{ + const unsigned PROGRESS_DELTA = 5; + + if( m_progressReporter ) + { + if( ++m_doneCount > m_lastProgressCount + PROGRESS_DELTA ) + { + m_progressReporter->SetCurrentProgress(( (double) m_doneCount ) / m_totalCount ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lastProgressCount = m_doneCount; + } + } +} + + SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic, SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) { @@ -399,13 +424,21 @@ SCH_SHEET* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchema m_filename = aFileName; m_schematic = aSchematic; + if( m_progressReporter ) + { + m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + } + // Load the document wxXmlDocument xmlDocument; wxFFileInputStream stream( m_filename.GetFullPath() ); if( !stream.IsOk() || !xmlDocument.Load( stream ) ) { - THROW_IO_ERROR( wxString::Format( _( "Unable to read file \"%s\"" ), + THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'." ), m_filename.GetFullPath() ) ); } @@ -562,8 +595,68 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode ) if( !sheetNode ) return; + auto count_nodes = []( wxXmlNode* aNode ) -> unsigned + { + unsigned count = 0; + + while( aNode ) + { + count++; + aNode = aNode->GetNext(); + } + + return count; + }; + + if( m_progressReporter ) + { + m_totalCount = 0; + m_doneCount = 0; + + m_totalCount += count_nodes( partNode ); + + while( libraryNode ) + { + NODE_MAP libraryChildren = MapChildren( libraryNode ); + wxXmlNode* devicesetNode = getChildrenNodes( libraryChildren, "devicesets" ); + + while( devicesetNode ) + { + NODE_MAP deviceSetChildren = MapChildren( devicesetNode ); + wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, "devices" ); + wxXmlNode* gateNode = getChildrenNodes( deviceSetChildren, "gates" ); + + m_totalCount += count_nodes( deviceNode ) * count_nodes( gateNode ); + + devicesetNode = devicesetNode->GetNext(); + } + + libraryNode = libraryNode->GetNext(); + } + + // Rewind + libraryNode = getChildrenNodes( schematicChildren, "libraries" ); + + while( sheetNode ) + { + NODE_MAP sheetChildren = MapChildren( sheetNode ); + + m_totalCount += count_nodes( getChildrenNodes( sheetChildren, "instances" ) ); + m_totalCount += count_nodes( getChildrenNodes( sheetChildren, "busses" ) ); + m_totalCount += count_nodes( getChildrenNodes( sheetChildren, "nets" ) ); + m_totalCount += count_nodes( getChildrenNodes( sheetChildren, "plain" ) ); + + sheetNode = sheetNode->GetNext(); + } + + // Rewind + sheetNode = getChildrenNodes( schematicChildren, "sheets" ); + } + while( partNode ) { + checkpoint(); + std::unique_ptr epart = std::make_unique( partNode ); // N.B. Eagle parts are case-insensitive in matching but we keep the display case @@ -585,7 +678,6 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode ) libraryNode = libraryNode->GetNext(); } - m_pi->SaveLibrary( getLibFileName().GetFullPath() ); } @@ -734,6 +826,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex ) while( instanceNode ) { + checkpoint(); + loadInstance( instanceNode ); instanceNode = instanceNode->GetNext(); } @@ -746,6 +840,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex ) while( busNode ) { + checkpoint(); + // Get the bus name wxString busName = translateEagleBusName( busNode->GetAttribute( "name" ) ); @@ -762,6 +858,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex ) while( netNode ) { + checkpoint(); + // Get the net name and class wxString netName = netNode->GetAttribute( "name" ); wxString netClass = netNode->GetAttribute( "class" ); @@ -792,6 +890,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex ) while( plainNode ) { + checkpoint(); + wxString nodeName = plainNode->GetName(); if( nodeName == "text" ) @@ -1371,8 +1471,8 @@ void SCH_EAGLE_PLUGIN::loadInstance( wxXmlNode* aInstanceNode ) } -EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( - wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLibrary ) +EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode, + EAGLE_LIBRARY* aEagleLibrary ) { NODE_MAP libraryChildren = MapChildren( aLibraryNode ); @@ -1396,8 +1496,8 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : ""; - NODE_MAP aDeviceSetChildren = MapChildren( devicesetNode ); - wxXmlNode* deviceNode = getChildrenNodes( aDeviceSetChildren, "devices" ); + NODE_MAP deviceSetChildren = MapChildren( devicesetNode ); + wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, "devices" ); // For each device in the device set: while( deviceNode ) @@ -1418,8 +1518,8 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( unique_ptr kpart( new LIB_SYMBOL( symbolName ) ); // Process each gate in the deviceset for this device. - wxXmlNode* gateNode = getChildrenNodes( aDeviceSetChildren, "gates" ); - int gates_count = countChildren( aDeviceSetChildren["gates"], "gate" ); + wxXmlNode* gateNode = getChildrenNodes( deviceSetChildren, "gates" ); + int gates_count = countChildren( deviceSetChildren["gates"], "gate" ); kpart->SetUnitCount( gates_count ); kpart->LockUnits( true ); @@ -1437,10 +1537,11 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( while( gateNode ) { + checkpoint(); + EGATE egate = EGATE( gateNode ); aEagleLibrary->GateUnit[edeviceset.name + edevice.name + egate.name] = gateindex; - ispower = loadSymbol( aEagleLibrary->SymbolNodes[egate.symbol], kpart, &edevice, gateindex, egate.name ); diff --git a/eeschema/sch_plugins/eagle/sch_eagle_plugin.h b/eeschema/sch_plugins/eagle/sch_eagle_plugin.h index a56ece093e..5953d90065 100644 --- a/eeschema/sch_plugins/eagle/sch_eagle_plugin.h +++ b/eeschema/sch_plugins/eagle/sch_eagle_plugin.h @@ -87,6 +87,11 @@ public: void SetReporter( REPORTER* aReporter ) override { m_reporter = aReporter; } + void SetProgressReporter( PROGRESS_REPORTER* aReporter ) override + { + m_progressReporter = aReporter; + } + const wxString GetFileExtension() const override; const wxString GetLibraryFileExtension() const override; @@ -99,8 +104,9 @@ public: bool CheckHeader( const wxString& aFileName ) override; - private: + void checkpoint(); + void loadDrawing( wxXmlNode* aDrawingNode ); void loadLayerDefs( wxXmlNode* aLayers ); void loadSchematic( wxXmlNode* aSchematicNode ); @@ -120,15 +126,15 @@ private: SCH_LAYER_ID kiCadLayer( int aEagleLayer ); std::pair findNearestLinePoint( const wxPoint& aPoint, - const std::vector& aLines ) const; + const std::vector& aLines ) const; - void loadSegments( wxXmlNode* aSegmentsNode, const wxString& aNetName, - const wxString& aNetClass ); - SCH_LINE* loadWire( wxXmlNode* aWireNode ); - SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName ); - SCH_JUNCTION* loadJunction( wxXmlNode* aJunction ); - SCH_TEXT* loadPlainText( wxXmlNode* aSchText ); - void loadFrame( wxXmlNode* aFrameNode, std::vector& aLines ); + void loadSegments( wxXmlNode* aSegmentsNode, const wxString& aNetName, + const wxString& aNetClass ); + SCH_LINE* loadWire( wxXmlNode* aWireNode ); + SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName ); + SCH_JUNCTION* loadJunction( wxXmlNode* aJunction ); + SCH_TEXT* loadPlainText( wxXmlNode* aSchText ); + void loadFrame( wxXmlNode* aFrameNode, std::vector& aLines ); bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr& aSymbol, EDEVICE* aDevice, int aGateNumber, const wxString& aGateName ); @@ -228,8 +234,13 @@ private: EPART_MAP m_partlist; std::map m_eagleLibs; - SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi; ///< Plugin to create the KiCad symbol library. - std::unique_ptr< PROPERTIES > m_properties; ///< Library plugin properties. + SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi; ///< PI to create KiCad symbol library. + std::unique_ptr< PROPERTIES > m_properties; ///< Library plugin properties. + + PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr + unsigned m_doneCount; + unsigned m_lastProgressCount; + unsigned m_totalCount; ///< for progress reporting std::map m_netCounts; std::map m_layerMap; diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_parser.cpp b/eeschema/sch_plugins/kicad/sch_sexpr_parser.cpp index 36cb960048..e6dc47a714 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_parser.cpp +++ b/eeschema/sch_plugins/kicad/sch_sexpr_parser.cpp @@ -55,21 +55,48 @@ #include #include #include +#include using namespace TSCHEMATIC_T; -SCH_SEXPR_PARSER::SCH_SEXPR_PARSER( LINE_READER* aLineReader ) : +SCH_SEXPR_PARSER::SCH_SEXPR_PARSER( LINE_READER* aLineReader, PROGRESS_REPORTER* aProgressReporter, + unsigned aLineCount ) : SCHEMATIC_LEXER( aLineReader ), m_requiredVersion( 0 ), m_fieldId( 0 ), m_unit( 1 ), - m_convert( 1 ) + m_convert( 1 ), + m_progressReporter( aProgressReporter ), + m_lineReader( aLineReader ), + m_lastProgressLine( 0 ), + m_lineCount( aLineCount ) { } +void SCH_SEXPR_PARSER::checkpoint() +{ + const unsigned PROGRESS_DELTA = 250; + + if( m_progressReporter ) + { + unsigned curLine = m_lineReader->LineNumber(); + + if( curLine > m_lastProgressLine + PROGRESS_DELTA ) + { + m_progressReporter->SetCurrentProgress( ( (double) curLine ) / m_lineCount ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lastProgressLine = curLine; + } + } +} + + bool SCH_SEXPR_PARSER::parseBool() { T token = NextTok(); @@ -2090,6 +2117,8 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopyableOnly, token = NextTok(); + checkpoint(); + if( !aIsCopyableOnly && token == T_page && m_requiredVersion <= 20200506 ) token = T_paper; diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_parser.h b/eeschema/sch_plugins/kicad/sch_sexpr_parser.h index 048def9e64..dac41e65d4 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_parser.h +++ b/eeschema/sch_plugins/kicad/sch_sexpr_parser.h @@ -84,6 +84,13 @@ class SCH_SEXPR_PARSER : public SCHEMATIC_LEXER int m_convert; ///< The current body style being parsed. wxString m_symbolName; ///< The current symbol name. + PROGRESS_REPORTER* m_progressReporter; // optional; may be nullptr + const LINE_READER* m_lineReader; // for progress reporting + unsigned m_lastProgressLine; + unsigned m_lineCount; // for progress reporting + + void checkpoint(); + void parseHeader( TSCHEMATIC_T::T aHeaderType, int aFileVersion ); inline long parseHex() @@ -184,7 +191,8 @@ class SCH_SEXPR_PARSER : public SCHEMATIC_LEXER void parseBusAlias( SCH_SCREEN* aScreen ); public: - SCH_SEXPR_PARSER( LINE_READER* aLineReader = nullptr ); + SCH_SEXPR_PARSER( LINE_READER* aLineReader = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr, unsigned aLineCount = 0 ); void ParseLib( LIB_SYMBOL_MAP& aSymbolLibMap ); diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp index 0dbdc0236d..1d81059677 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp +++ b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.cpp @@ -61,6 +61,7 @@ #include #include #include // for ::ResolvePossibleSymlinks() +#include using namespace TSCHEMATIC_T; @@ -365,7 +366,8 @@ public: }; -SCH_SEXPR_PLUGIN::SCH_SEXPR_PLUGIN() +SCH_SEXPR_PLUGIN::SCH_SEXPR_PLUGIN() : + m_progressReporter( nullptr ) { init( NULL ); } @@ -387,6 +389,7 @@ void SCH_SEXPR_PLUGIN::init( SCHEMATIC* aSchematic, const PROPERTIES* aPropertie m_nextFreeFieldId = 100; // number arbitrarily > MANDATORY_FIELDS or SHEET_MANDATORY_FIELDS } + SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic, SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) { @@ -518,10 +521,10 @@ void SCH_SEXPR_PLUGIN::loadHierarchy( SCH_SHEET* aSheet ) // This was moved out of the try{} block so that any sheets definitionsthat // the plugin fully parsed before the exception was raised will be loaded. - for( auto aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) ) + for( SCH_ITEM* aItem : aSheet->GetScreen()->Items().OfType( SCH_SHEET_T ) ) { wxCHECK2( aItem->Type() == SCH_SHEET_T, /* do nothing */ ); - auto sheet = static_cast( aItem ); + SCH_SHEET* sheet = static_cast( aItem ); // Recursion starts here. loadHierarchy( sheet ); @@ -538,7 +541,22 @@ void SCH_SEXPR_PLUGIN::loadFile( const wxString& aFileName, SCH_SHEET* aSheet ) { FILE_LINE_READER reader( aFileName ); - SCH_SEXPR_PARSER parser( &reader ); + size_t lineCount = 0; + + if( m_progressReporter ) + { + m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + while( reader.ReadLine() ) + lineCount++; + + reader.Rewind(); + } + + SCH_SEXPR_PARSER parser( &reader, m_progressReporter, lineCount ); parser.ParseSchematic( aSheet ); } diff --git a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h index 90ee4714bc..3506d86724 100644 --- a/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h +++ b/eeschema/sch_plugins/kicad/sch_sexpr_plugin.h @@ -79,6 +79,11 @@ public: return wxT( "kicad_sym" ); } + void SetProgressReporter( PROGRESS_REPORTER* aReporter ) override + { + m_progressReporter = aReporter; + } + /** * The property used internally by the plugin to enable cache buffering which prevents * the library file from being written every time the cache is changed. This is useful @@ -152,16 +157,18 @@ private: bool isBuffering( const PROPERTIES* aProperties ); protected: - int m_version; ///< Version of file being loaded. - int m_nextFreeFieldId; + int m_version; ///< Version of file being loaded. + int m_nextFreeFieldId; - wxString m_error; ///< For throwing exceptions or errors on partial loads. + wxString m_error; ///< For throwing exceptions or errors on partial + ///< loads. + PROGRESS_REPORTER* m_progressReporter; - wxString m_path; ///< Root project path for loading child sheets. - std::stack m_currentPath;///< Stack to maintain nested sheet paths - SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.. - SCHEMATIC* m_schematic; ///< Passed to Load(), the schematic object being loaded - OUTPUTFORMATTER* m_out; ///< The output formatter for saving SCH_SCREEN objects. + wxString m_path; ///< Root project path for loading child sheets. + std::stack m_currentPath; ///< Stack to maintain nested sheet paths + SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded. + SCHEMATIC* m_schematic; + OUTPUTFORMATTER* m_out; ///< The formatter for saving SCH_SCREEN objects. SCH_SEXPR_PLUGIN_CACHE* m_cache; /// initialize PLUGIN like a constructor would. diff --git a/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp b/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp index 6315c0f164..198543210c 100644 --- a/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp +++ b/eeschema/sch_plugins/legacy/sch_legacy_plugin.cpp @@ -41,6 +41,9 @@ #include #include #include +#include +#include +#include // For ::ResolvePossibleSymlinks() #include #include @@ -70,10 +73,8 @@ #include #include // for MAX_UNIT_COUNT_PER_PACKAGE definition #include // for PropPowerSymsOnly definition. -#include #include #include // For some default values -#include // For ::ResolvePossibleSymlinks() #define Mils2Iu( x ) Mils2iu( x ) @@ -582,7 +583,11 @@ public: }; -SCH_LEGACY_PLUGIN::SCH_LEGACY_PLUGIN() +SCH_LEGACY_PLUGIN::SCH_LEGACY_PLUGIN() : + m_progressReporter( nullptr ), + m_lineReader( nullptr ), + m_lastProgressLine( 0 ), + m_lineCount( 0 ) { init( NULL ); } @@ -604,6 +609,27 @@ void SCH_LEGACY_PLUGIN::init( SCHEMATIC* aSchematic, const PROPERTIES* aProperti } +void SCH_LEGACY_PLUGIN::checkpoint() +{ + const unsigned PROGRESS_DELTA = 250; + + if( m_progressReporter ) + { + unsigned curLine = m_lineReader->LineNumber(); + + if( curLine > m_lastProgressLine + PROGRESS_DELTA ) + { + m_progressReporter->SetCurrentProgress( ( (double) curLine ) / m_lineCount ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lastProgressLine = curLine; + } + } +} + + SCH_SHEET* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic, SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) { @@ -753,6 +779,22 @@ void SCH_LEGACY_PLUGIN::loadFile( const wxString& aFileName, SCH_SCREEN* aScreen { FILE_LINE_READER reader( aFileName ); + if( m_progressReporter ) + { + m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lineReader = &reader; + m_lineCount = 0; + + while( reader.ReadLine() ) + m_lineCount++; + + reader.Rewind(); + } + loadHeader( reader, aScreen ); LoadContent( reader, aScreen, m_version ); @@ -782,6 +824,8 @@ void SCH_LEGACY_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen, while( aReader.ReadLine() ) { + checkpoint(); + char* line = aReader.Line(); while( *line == ' ' ) @@ -842,6 +886,8 @@ void SCH_LEGACY_PLUGIN::loadHeader( LINE_READER& aReader, SCH_SCREEN* aScreen ) // Skip all lines until the end of header "EELAYER END" is found while( aReader.ReadLine() ) { + checkpoint(); + line = aReader.Line(); while( *line == ' ' ) diff --git a/eeschema/sch_plugins/legacy/sch_legacy_plugin.h b/eeschema/sch_plugins/legacy/sch_legacy_plugin.h index d35c608419..8a4b2a62ef 100644 --- a/eeschema/sch_plugins/legacy/sch_legacy_plugin.h +++ b/eeschema/sch_plugins/legacy/sch_legacy_plugin.h @@ -82,6 +82,11 @@ public: return wxT( "lib" ); } + void SetProgressReporter( PROGRESS_REPORTER* aReporter ) override + { + m_progressReporter = aReporter; + } + /** * The property used internally by the plugin to enable cache buffering which prevents * the library file from being written every time the cache is changed. This is useful @@ -140,6 +145,7 @@ public: static void FormatPart( LIB_SYMBOL* aSymbol, OUTPUTFORMATTER& aFormatter ); private: + void checkpoint(); void loadHierarchy( SCH_SHEET* aSheet ); void loadHeader( LINE_READER& aReader, SCH_SCREEN* aScreen ); void loadPageSettings( LINE_READER& aReader, SCH_SCREEN* aScreen ); @@ -170,17 +176,21 @@ private: bool isBuffering( const PROPERTIES* aProperties ); protected: - int m_version; ///< Version of file being loaded. + int m_version; ///< Version of file being loaded. - /** For throwing exceptions or errors on partial schematic loads. */ - wxString m_error; + wxString m_error; ///< For throwing exceptions or errors on partial + ///< schematic loads. + PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr + LINE_READER* m_lineReader; ///< for progress reporting + unsigned m_lastProgressLine; + unsigned m_lineCount; ///< for progress reporting - wxString m_path; ///< Root project path for loading child sheets. - std::stack m_currentPath;///< Stack to maintain nested sheet paths - SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.. - OUTPUTFORMATTER* m_out; ///< The output formatter for saving SCH_SCREEN objects. + wxString m_path; ///< Root project path for loading child sheets. + std::stack m_currentPath; ///< Stack to maintain nested sheet paths + SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded. + OUTPUTFORMATTER* m_out; ///< The formatter for saving SCH_SCREEN objects. SCH_LEGACY_PLUGIN_CACHE* m_cache; - SCHEMATIC* m_schematic; ///< Passed to Load(), the schematic object being loaded + SCHEMATIC* m_schematic; /// initialize PLUGIN like a constructor would. void init( SCHEMATIC* aSchematic, const PROPERTIES* aProperties = nullptr ); diff --git a/eeschema/symbol_async_loader.cpp b/eeschema/symbol_async_loader.cpp index d0e4fa0347..f8c5360cbf 100644 --- a/eeschema/symbol_async_loader.cpp +++ b/eeschema/symbol_async_loader.cpp @@ -131,7 +131,7 @@ std::vector SYMBOL_ASYNC_LOADER::worker() } if( m_reporter ) - m_reporter->AdvancePhase( wxString::Format( _( "Loading library \"%s\"" ), nickname ) ); + m_reporter->AdvancePhase( wxString::Format( _( "Loading library %s..." ), nickname ) ); } return ret; diff --git a/include/richio.h b/include/richio.h index 0b207a2de2..cb1d0a7c36 100644 --- a/include/richio.h +++ b/include/richio.h @@ -225,6 +225,9 @@ public: m_lineNum = 0; } + long int FileLength(); + long int CurPos(); + protected: bool m_iOwn; ///< if I own the file, I'll promise to close it, else not. FILE* m_fp; ///< I may own this file, but might not. diff --git a/kicad/tools/kicad_manager_control.cpp b/kicad/tools/kicad_manager_control.cpp index bf8eb9f2c9..b58836a856 100644 --- a/kicad/tools/kicad_manager_control.cpp +++ b/kicad/tools/kicad_manager_control.cpp @@ -665,18 +665,13 @@ int KICAD_MANAGER_CONTROL::ShowPlayer( const TOOL_EVENT& aEvent ) filepath = legacy_board.GetFullPath(); } - // Show the frame (and update widgets to set valid sizes), - // after creating player and before calling OpenProjectFiles(). - // Useful because loading a complex board and building its internal data can be - // time consuming - player->Show( true ); - wxSafeYield(); - if( !filepath.IsEmpty() ) { if( !player->OpenProjectFiles( std::vector( 1, filepath ) ) ) return -1; } + + player->Show( true ); } // Needed on Windows, other platforms do not use it, but it creates no issue diff --git a/pcbnew/dialogs/dialog_board_setup.cpp b/pcbnew/dialogs/dialog_board_setup.cpp index 690cbebd67..0fb0a4eb96 100644 --- a/pcbnew/dialogs/dialog_board_setup.cpp +++ b/pcbnew/dialogs/dialog_board_setup.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "dialog_board_setup.h" @@ -192,7 +193,10 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event ) try { - otherBoard = pi->Load( boardFn.GetFullPath(), nullptr, nullptr ); + WX_PROGRESS_REPORTER progressReporter( this, _( "Loading PCB" ), 1 ); + + otherBoard = pi->Load( boardFn.GetFullPath(), nullptr, nullptr, nullptr, + &progressReporter ); if( importDlg.m_LayersOpt->GetValue() ) { diff --git a/pcbnew/dialogs/panel_pcbnew_color_settings.cpp b/pcbnew/dialogs/panel_pcbnew_color_settings.cpp index b297d8a254..de5a5ae34e 100644 --- a/pcbnew/dialogs/panel_pcbnew_color_settings.cpp +++ b/pcbnew/dialogs/panel_pcbnew_color_settings.cpp @@ -501,7 +501,7 @@ void PANEL_PCBNEW_COLOR_SETTINGS::createPreviewItems() try { - pi.DoLoad( reader, m_preview->GetBoard(), nullptr ); + pi.DoLoad( reader, m_preview->GetBoard(), nullptr, nullptr, 0 ); } catch( const IO_ERROR& ) { diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index ecf603f7e3..d08a80e24b 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -25,7 +25,6 @@ #include #include -#include #include #include #include @@ -48,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +56,6 @@ #include #include #include -#include #include #include "footprint_info_impl.h" #include // For ::ResolvePossibleSymlinks() @@ -691,12 +690,13 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector& aFileSet, in props["page_width"] = xbuf; props["page_height"] = ybuf; + WX_PROGRESS_REPORTER progressReporter( this, _( "Loading PCB" ), 1 ); #if USE_INSTRUMENTATION // measure the time to load a BOARD. unsigned startTime = GetRunningMicroSecs(); #endif - loadedBoard = pi->Load( fullFileName, NULL, &props, &Prj() ); + loadedBoard = pi->Load( fullFileName, NULL, &props, &Prj(), &progressReporter ); #if USE_INSTRUMENTATION unsigned stopTime = GetRunningMicroSecs(); diff --git a/pcbnew/io_mgr.cpp b/pcbnew/io_mgr.cpp index 611730b557..4519457f8f 100644 --- a/pcbnew/io_mgr.cpp +++ b/pcbnew/io_mgr.cpp @@ -156,14 +156,15 @@ IO_MGR::PCB_FILE_T IO_MGR::GuessPluginTypeFromLibPath( const wxString& aLibPath BOARD* IO_MGR::Load( PCB_FILE_T aFileType, const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { // release the PLUGIN even if an exception is thrown. PLUGIN::RELEASER pi( PluginFind( aFileType ) ); if( (PLUGIN*) pi ) // test pi->plugin { - return pi->Load( aFileName, aAppendToMe, aProperties, aProject ); // virtual + return pi->Load( aFileName, aAppendToMe, aProperties, aProject, aProgressReporter ); } THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) ); diff --git a/pcbnew/io_mgr.h b/pcbnew/io_mgr.h index bc1a20df58..bba94a19f6 100644 --- a/pcbnew/io_mgr.h +++ b/pcbnew/io_mgr.h @@ -37,6 +37,7 @@ class PLUGIN; class FOOTPRINT; class PROPERTIES; class PROJECT; +class PROGRESS_REPORTER; /** * A factory which returns an instance of a #PLUGIN. @@ -210,7 +211,8 @@ public: */ static BOARD* Load( PCB_FILE_T aFileType, const wxString& aFileName, BOARD* aAppendToMe = nullptr, const PROPERTIES* aProperties = nullptr, - PROJECT* aProject = nullptr ); + PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ); /** * Write either a full \a aBoard to a storage file in a format that this implementation @@ -296,6 +298,8 @@ public: * it to be optionally NULL. * @param aProject is the optional #PROJECT object primarily used by third party * importers. + * @param aProgressReporter an optional progress reporter + * @param aLineCount a line count (necessary if a progress reporter is supplied) * @return the successfully loaded board, or the same one as \a aAppendToMe if aAppendToMe * was not NULL, and caller owns it. * @@ -304,7 +308,8 @@ public: * possible. */ virtual BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ); + const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ); /** * Return a container with the cached library footprints generated in the last call to diff --git a/pcbnew/kicad_clipboard.cpp b/pcbnew/kicad_clipboard.cpp index efbfef00cc..f94a5fc477 100644 --- a/pcbnew/kicad_clipboard.cpp +++ b/pcbnew/kicad_clipboard.cpp @@ -352,7 +352,8 @@ void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard, BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { std::string result; diff --git a/pcbnew/kicad_clipboard.h b/pcbnew/kicad_clipboard.h index b3aba5ced4..140343258e 100644 --- a/pcbnew/kicad_clipboard.h +++ b/pcbnew/kicad_clipboard.h @@ -59,7 +59,8 @@ public: BOARD_ITEM* Parse(); BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ) override; + const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; void SetBoard( BOARD* aBoard ); diff --git a/pcbnew/pcb_painter.cpp b/pcbnew/pcb_painter.cpp index 950f117f53..222150d930 100644 --- a/pcbnew/pcb_painter.cpp +++ b/pcbnew/pcb_painter.cpp @@ -1164,9 +1164,10 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer ) m_gal->DrawPolygon( outline ); } - else + { m_gal->DrawPolygon( poly->Vertices() ); + } // Now add on a rounded margin (using segments) if the margin > 0 if( margin.x > 0 ) diff --git a/pcbnew/plugin.cpp b/pcbnew/plugin.cpp index e2564fbadb..c5a9b7eaad 100644 --- a/pcbnew/plugin.cpp +++ b/pcbnew/plugin.cpp @@ -44,7 +44,7 @@ static void not_implemented( PLUGIN* aPlugin, const char* aCaller ) BOARD* PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, - PROJECT* aProject ) + PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter ) { not_implemented( this, __FUNCTION__ ); return nullptr; diff --git a/pcbnew/plugins/altium/altium_circuit_maker_plugin.cpp b/pcbnew/plugins/altium/altium_circuit_maker_plugin.cpp index 4446ef4924..9c03d0a21a 100644 --- a/pcbnew/plugins/altium/altium_circuit_maker_plugin.cpp +++ b/pcbnew/plugins/altium/altium_circuit_maker_plugin.cpp @@ -64,7 +64,8 @@ const wxString ALTIUM_CIRCUIT_MAKER_PLUGIN::GetFileExtension() const BOARD* ALTIUM_CIRCUIT_MAKER_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { m_props = aProperties; diff --git a/pcbnew/plugins/altium/altium_circuit_maker_plugin.h b/pcbnew/plugins/altium/altium_circuit_maker_plugin.h index f7d356b2ef..938d678e9a 100644 --- a/pcbnew/plugins/altium/altium_circuit_maker_plugin.h +++ b/pcbnew/plugins/altium/altium_circuit_maker_plugin.h @@ -39,7 +39,8 @@ public: const wxString PluginName() const override; BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, - PROJECT* aProject = nullptr ) override; + PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; const wxString GetFileExtension() const override; diff --git a/pcbnew/plugins/altium/altium_circuit_studio_plugin.cpp b/pcbnew/plugins/altium/altium_circuit_studio_plugin.cpp index 1c23258f13..5be855d1d8 100644 --- a/pcbnew/plugins/altium/altium_circuit_studio_plugin.cpp +++ b/pcbnew/plugins/altium/altium_circuit_studio_plugin.cpp @@ -64,7 +64,8 @@ const wxString ALTIUM_CIRCUIT_STUDIO_PLUGIN::GetFileExtension() const BOARD* ALTIUM_CIRCUIT_STUDIO_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { m_props = aProperties; diff --git a/pcbnew/plugins/altium/altium_circuit_studio_plugin.h b/pcbnew/plugins/altium/altium_circuit_studio_plugin.h index 7996ddd07a..94998f0bd3 100644 --- a/pcbnew/plugins/altium/altium_circuit_studio_plugin.h +++ b/pcbnew/plugins/altium/altium_circuit_studio_plugin.h @@ -39,7 +39,7 @@ public: const wxString PluginName() const override; BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, - PROJECT* aProject ) override; + PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter = nullptr ) override; const wxString GetFileExtension() const override; diff --git a/pcbnew/plugins/altium/altium_designer_plugin.cpp b/pcbnew/plugins/altium/altium_designer_plugin.cpp index 8c8a3b6746..8796a9dcac 100644 --- a/pcbnew/plugins/altium/altium_designer_plugin.cpp +++ b/pcbnew/plugins/altium/altium_designer_plugin.cpp @@ -64,7 +64,8 @@ const wxString ALTIUM_DESIGNER_PLUGIN::GetFileExtension() const BOARD* ALTIUM_DESIGNER_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { m_props = aProperties; diff --git a/pcbnew/plugins/altium/altium_designer_plugin.h b/pcbnew/plugins/altium/altium_designer_plugin.h index 14b20bd335..27528977e9 100644 --- a/pcbnew/plugins/altium/altium_designer_plugin.h +++ b/pcbnew/plugins/altium/altium_designer_plugin.h @@ -41,7 +41,8 @@ public: const wxString PluginName() const override; BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, - PROJECT* aProject = nullptr) override; + PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; const wxString GetFileExtension() const override; diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp index 57f0b871df..e405c5cfb3 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.cpp @@ -106,7 +106,8 @@ std::vector CADSTAR_PCB_ARCHIVE_PLUGIN::GetImportedCachedLibraryFoot BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { m_props = aProperties; m_board = aAppendToMe ? aAppendToMe : new BOARD(); diff --git a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h index 7a908f1b87..3c689de2fa 100644 --- a/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h +++ b/pcbnew/plugins/cadstar/cadstar_pcb_archive_plugin.h @@ -39,7 +39,8 @@ public: const wxString PluginName() const override; BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ) override; + const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; const wxString GetFileExtension() const override; diff --git a/pcbnew/plugins/eagle/eagle_plugin.cpp b/pcbnew/plugins/eagle/eagle_plugin.cpp index e570e4feb5..1d49506dfc 100644 --- a/pcbnew/plugins/eagle/eagle_plugin.cpp +++ b/pcbnew/plugins/eagle/eagle_plugin.cpp @@ -67,6 +67,7 @@ Load() TODO's #include #include #include // for KiROUND +#include #include #include @@ -207,12 +208,14 @@ static void setKeepoutSettingsToZone( ZONE* aZone, LAYER_NUM aLayer ) } -void ERULES::parse( wxXmlNode* aRules ) +void ERULES::parse( wxXmlNode* aRules, std::function aCheckpoint ) { wxXmlNode* child = aRules->GetChildren(); while( child ) { + aCheckpoint(); + if( child->GetName() == "param" ) { const wxString& name = child->GetAttribute( "name" ); @@ -273,9 +276,13 @@ void ERULES::parse( wxXmlNode* aRules ) EAGLE_PLUGIN::EAGLE_PLUGIN() : - m_rules( new ERULES() ), - m_xpath( new XPATH() ), - m_mod_time( wxDateTime::Now() ) + m_rules( new ERULES() ), + m_xpath( new XPATH() ), + m_progressReporter( nullptr ), + m_doneCount( 0 ), + m_lastProgressCount( 0 ), + m_totalCount( 0 ), + m_mod_time( wxDateTime::Now() ) { using namespace std::placeholders; @@ -305,6 +312,26 @@ const wxString EAGLE_PLUGIN::GetFileExtension() const return wxT( "brd" ); } + +void EAGLE_PLUGIN::checkpoint() +{ + const unsigned PROGRESS_DELTA = 50; + + if( m_progressReporter ) + { + if( ++m_doneCount > m_lastProgressCount + PROGRESS_DELTA ) + { + m_progressReporter->SetCurrentProgress(( (double) m_doneCount ) / m_totalCount ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lastProgressCount = m_doneCount; + } + } +} + + wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d, int aTextThickness ) const { // Eagle includes stroke thickness in the text size, KiCAD does not @@ -314,7 +341,8 @@ wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d, int aTextThickness ) c BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { LOCALE_IO toggle; // toggles on, then off, the C locale. wxXmlNode* doc; @@ -322,6 +350,7 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, init( aProperties ); m_board = aAppendToMe ? aAppendToMe : new BOARD(); + m_progressReporter = aProgressReporter; // Give the filename to the board if it's new if( !aAppendToMe ) @@ -332,6 +361,14 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, try { + if( m_progressReporter ) + { + m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + } + wxFileName fn = aFileName; // Load the document wxFFileInputStream stream( fn.GetFullPath() ); @@ -339,7 +376,7 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, if( !stream.IsOk() || !xmlDocument.Load( stream ) ) { - THROW_IO_ERROR( wxString::Format( _( "Unable to read file \"%s\"" ), + THROW_IO_ERROR( wxString::Format( _( "Unable to read file '%s'" ), fn.GetFullPath() ) ); } @@ -414,9 +451,7 @@ std::vector EAGLE_PLUGIN::GetImportedCachedLibraryFootprints() std::vector retval; for( std::pair fp : m_templates ) - { retval.push_back( static_cast( fp.second->Clone() ) ); - } return retval; } @@ -458,12 +493,53 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc ) wxXmlNode* board = drawingChildren["board"]; NODE_MAP boardChildren = MapChildren( board ); + auto count_children = [this]( wxXmlNode* aNode ) + { + if( aNode ) + { + wxXmlNode* child = aNode->GetChildren(); + + while( child ) + { + m_totalCount++; + child = child->GetNext(); + } + } + }; + + wxXmlNode* designrules = boardChildren["designrules"]; + wxXmlNode* layers = drawingChildren["layers"]; + wxXmlNode* plain = boardChildren["plain"]; + wxXmlNode* signals = boardChildren["signals"]; + wxXmlNode* libs = boardChildren["libraries"]; + wxXmlNode* elems = boardChildren["elements"]; + + if( m_progressReporter ) + { + m_totalCount = 0; + m_doneCount = 0; + + count_children( designrules ); + count_children( layers ); + count_children( plain ); + count_children( signals ); + count_children( elems ); + + while( libs ) + { + count_children( MapChildren( libs )["packages"] ); + libs = libs->GetNext(); + } + + // Rewind + libs = boardChildren["libraries"]; + } + m_xpath->push( "eagle.drawing" ); { m_xpath->push( "board" ); - wxXmlNode* designrules = boardChildren["designrules"]; loadDesignRules( designrules ); m_xpath->pop(); @@ -472,7 +548,6 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc ) { m_xpath->push( "layers" ); - wxXmlNode* layers = drawingChildren["layers"]; loadLayerDefs( layers ); mapEagleLayersToKicad(); @@ -482,19 +557,12 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc ) { m_xpath->push( "board" ); - wxXmlNode* plain = boardChildren["plain"]; loadPlain( plain ); - - wxXmlNode* signals = boardChildren["signals"]; loadSignals( signals ); - - wxXmlNode* libs = boardChildren["libraries"]; loadLibraries( libs ); - - wxXmlNode* elems = boardChildren["elements"]; loadElements( elems ); - m_xpath->pop(); // "board" + m_xpath->pop(); } m_xpath->pop(); // "eagle.drawing" @@ -506,7 +574,7 @@ void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules ) if( aDesignRules ) { m_xpath->push( "designrules" ); - m_rules->parse( aDesignRules ); + m_rules->parse( aDesignRules, [this](){ checkpoint(); } ); m_xpath->pop(); // "designrules" } } @@ -533,9 +601,7 @@ void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers ) // find the subset of layers that are copper and active if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) ) - { cu.push_back( elayer ); - } layerNode = layerNode->GetNext(); } @@ -546,9 +612,13 @@ void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers ) for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count ) { if( ki_layer_count == 0 ) + { m_cu_map[it->number] = F_Cu; + } else if( ki_layer_count == int( cu.size()-1 ) ) + { m_cu_map[it->number] = B_Cu; + } else { // some eagle boards do not have contiguous layer number sequences. @@ -592,6 +662,8 @@ void EAGLE_PLUGIN::loadPlain( wxXmlNode* aGraphics ) // (polygon | wire | text | circle | rectangle | frame | hole)* while( gr ) { + checkpoint(); + wxString grName = gr->GetName(); if( grName == "wire" ) @@ -945,6 +1017,8 @@ void EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLib, const wxString* aLibName ) while( package ) { + checkpoint(); + m_xpath->push( "package", "name" ); wxString pack_ref = package->GetAttribute( "name" ); @@ -1018,6 +1092,8 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements ) while( element ) { + checkpoint(); + if( element->GetName() != "element" ) { // Get next item @@ -1039,7 +1115,7 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements ) if( it == m_templates.end() ) { - wxString emsg = wxString::Format( _( "No \"%s\" package in library \"%s\"" ), + wxString emsg = wxString::Format( _( "No '%s' package in library '%s'." ), FROM_UTF8( e.package.c_str() ), FROM_UTF8( e.library.c_str() ) ); THROW_IO_ERROR( emsg ); @@ -1742,7 +1818,7 @@ void EAGLE_PLUGIN::packagePad( FOOTPRINT* aFootprint, wxXmlNode* aTree ) // if shape is not present, our default is circle and that matches their default "round" } - if( e.diameter ) + if( e.diameter && e.diameter->value > 0 ) { int diameter = e.diameter->ToPcbUnits(); pad->SetSize( wxSize( diameter, diameter ) ); @@ -2148,6 +2224,9 @@ void EAGLE_PLUGIN::packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aC { EHOLE e( aTree ); + if( e.drill.value == 0 ) + return; + // we add a PAD_ATTRIB::NPTH pad to this footprint. PAD* pad = new PAD( aFootprint ); aFootprint->Add( pad ); @@ -2188,7 +2267,7 @@ void EAGLE_PLUGIN::packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const ESMD e( aTree ); PCB_LAYER_ID layer = kicad_layer( e.layer ); - if( !IsCopperLayer( layer ) ) + if( !IsCopperLayer( layer ) || e.dx.value == 0 || e.dy.value == 0 ) return; PAD* pad = new PAD( aFootprint ); @@ -2304,6 +2383,8 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals ) while( net ) { + checkpoint(); + bool sawPad = false; zones.clear(); @@ -2557,7 +2638,13 @@ void EAGLE_PLUGIN::mapEagleLayersToKicad() inputDescs.push_back( layerDesc ); } + if( m_progressReporter && dynamic_cast( m_progressReporter ) ) + dynamic_cast( m_progressReporter )->Hide(); + m_layer_map = m_layer_mapping_handler( inputDescs ); + + if( m_progressReporter && dynamic_cast( m_progressReporter )) + dynamic_cast( m_progressReporter )->Show(); } PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const diff --git a/pcbnew/plugins/eagle/eagle_plugin.h b/pcbnew/plugins/eagle/eagle_plugin.h index 733521ae09..f01cc267f4 100644 --- a/pcbnew/plugins/eagle/eagle_plugin.h +++ b/pcbnew/plugins/eagle/eagle_plugin.h @@ -78,7 +78,7 @@ struct ERULES mdWireWire ( 0 ) {} - void parse( wxXmlNode* aRules ); + void parse( wxXmlNode* aRules, std::function aCheckpoint ); ///< percent over 100%. 0-> not elongated, 100->twice as wide as is tall ///< Goes into making a scaling factor for "long" pads. @@ -131,7 +131,8 @@ public: const wxString PluginName() const override; BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ) override; + const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; std::vector GetImportedCachedLibraryFootprints() override; @@ -176,9 +177,11 @@ public: private: /// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed. - void init( const PROPERTIES* aProperties ); + void init( const PROPERTIES* aProperties ); - void clear_cu_map(); + void checkpoint(); + + void clear_cu_map(); /// Convert an Eagle distance to a KiCad distance. int kicad_y( const ECOORD& y ) const { return -y.ToPcbUnits(); } @@ -299,6 +302,11 @@ private: const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL. BOARD* m_board; ///< which BOARD is being worked on, no ownership here + PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr + unsigned m_doneCount; + unsigned m_lastProgressCount; + unsigned m_totalCount; ///< for progress reporting + int m_min_trace; ///< smallest trace we find on Load(), in BIU. int m_min_hole; ///< smallest diameter hole we find on Load(), in BIU. int m_min_via; ///< smallest via we find on Load(), in BIU. diff --git a/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp b/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp index 612d318fc9..09312909b0 100644 --- a/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp +++ b/pcbnew/plugins/fabmaster/fabmaster_plugin.cpp @@ -59,7 +59,8 @@ const wxString FABMASTER_PLUGIN::GetFileExtension() const BOARD* FABMASTER_PLUGIN::Load( const wxString &aFileName, BOARD *aAppendToMe, - const PROPERTIES *aProperties, PROJECT *aProject ) + const PROPERTIES *aProperties, PROJECT *aProject, + PROGRESS_REPORTER* aProgressReporter ) { m_props = aProperties; diff --git a/pcbnew/plugins/fabmaster/fabmaster_plugin.h b/pcbnew/plugins/fabmaster/fabmaster_plugin.h index 4b875ddd87..e5b326ef3a 100644 --- a/pcbnew/plugins/fabmaster/fabmaster_plugin.h +++ b/pcbnew/plugins/fabmaster/fabmaster_plugin.h @@ -41,9 +41,11 @@ public: const wxString PluginName() const override; - BOARD* Load( const wxString& aFileName, - BOARD* aAppendToMe, - const PROPERTIES* aProperties = NULL, PROJECT* aProject = nullptr ) override; + BOARD* Load( const wxString& aFileName, + BOARD* aAppendToMe, + const PROPERTIES* aProperties = NULL, + PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; const wxString GetFileExtension() const override; diff --git a/pcbnew/plugins/kicad/kicad_plugin.cpp b/pcbnew/plugins/kicad/kicad_plugin.cpp index b6680e20ac..f330e0a5c2 100644 --- a/pcbnew/plugins/kicad/kicad_plugin.cpp +++ b/pcbnew/plugins/kicad/kicad_plugin.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -2188,11 +2189,26 @@ PCB_IO::~PCB_IO() BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, - PROJECT* aProject ) + PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter ) { FILE_LINE_READER reader( aFileName ); - BOARD* board = DoLoad( reader, aAppendToMe, aProperties ); + unsigned lineCount = 0; + + if( aProgressReporter ) + { + aProgressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) ); + + if( !aProgressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + while( reader.ReadLine() ) + lineCount++; + + reader.Rewind(); + } + + BOARD* board = DoLoad( reader, aAppendToMe, aProperties, aProgressReporter, lineCount ); // Give the filename to the board if it's new if( !aAppendToMe ) @@ -2202,12 +2218,14 @@ BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPER } -BOARD* PCB_IO::DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPERTIES* aProperties ) +BOARD* PCB_IO::DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPERTIES* aProperties, + PROGRESS_REPORTER* aProgressReporter, unsigned aLineCount) { init( aProperties ); m_parser->SetLineReader( &aReader ); m_parser->SetBoard( aAppendToMe ); + m_parser->SetProgressReporter( aProgressReporter, &aReader, aLineCount ); BOARD* board; diff --git a/pcbnew/plugins/kicad/kicad_plugin.h b/pcbnew/plugins/kicad/kicad_plugin.h index 8095afbf56..330a6b2ac5 100644 --- a/pcbnew/plugins/kicad/kicad_plugin.h +++ b/pcbnew/plugins/kicad/kicad_plugin.h @@ -153,9 +153,11 @@ public: const PROPERTIES* aProperties = nullptr ) override; BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ) override; + const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; - BOARD* DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPERTIES* aProperties ); + BOARD* DoLoad( LINE_READER& aReader, BOARD* aAppendToMe, const PROPERTIES* aProperties, + PROGRESS_REPORTER* aProgressReporter, unsigned aLineCount ); void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath, bool aBestEfforts, const PROPERTIES* aProperties = nullptr ) override; diff --git a/pcbnew/plugins/kicad/pcb_parser.cpp b/pcbnew/plugins/kicad/pcb_parser.cpp index c2e68366a2..da89395b19 100644 --- a/pcbnew/plugins/kicad/pcb_parser.cpp +++ b/pcbnew/plugins/kicad/pcb_parser.cpp @@ -28,13 +28,11 @@ */ #include -#include #include #include #include #include -#include #include #include #include @@ -54,10 +52,10 @@ #include #include #include // for RECT_CHAMFER_POSITIONS definition -#include #include // KiROUND, Clamp #include #include +#include using namespace PCB_KEYS_T; @@ -107,6 +105,27 @@ void PCB_PARSER::init() } +void PCB_PARSER::checkpoint() +{ + const unsigned PROGRESS_DELTA = 250; + + if( m_progressReporter ) + { + unsigned curLine = m_lineReader->LineNumber(); + + if( curLine > m_lastProgressLine + PROGRESS_DELTA ) + { + m_progressReporter->SetCurrentProgress( ( (double) curLine ) / m_lineCount ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lastProgressLine = curLine; + } + } +} + + void PCB_PARSER::skipCurrent() { int curr_level = 0; @@ -588,6 +607,8 @@ BOARD* PCB_PARSER::parseBOARD_unchecked() for( token = NextTok(); token != T_RIGHT; token = NextTok() ) { + checkpoint(); + if( token != T_LEFT ) Expecting( T_LEFT ); diff --git a/pcbnew/plugins/kicad/pcb_parser.h b/pcbnew/plugins/kicad/pcb_parser.h index 23938765ee..9fa9527203 100644 --- a/pcbnew/plugins/kicad/pcb_parser.h +++ b/pcbnew/plugins/kicad/pcb_parser.h @@ -60,6 +60,7 @@ class PCB_VIA; class ZONE; class FP_3DMODEL; struct LAYER; +class PROGRESS_REPORTER; /** @@ -72,7 +73,11 @@ public: PCB_PARSER( LINE_READER* aReader = nullptr ) : PCB_LEXER( aReader ), m_board( nullptr ), - m_resetKIIDs( false ) + m_resetKIIDs( false ), + m_progressReporter( nullptr ), + m_lineReader( nullptr ), + m_lastProgressLine( 0 ), + m_lineCount( 0 ) { init(); } @@ -101,6 +106,15 @@ public: m_resetKIIDs = true; } + void SetProgressReporter( PROGRESS_REPORTER* aProgressReporter, const LINE_READER* aLineReader, + unsigned aLineCount ) + { + m_progressReporter = aProgressReporter; + m_lineReader = aLineReader; + m_lastProgressLine = 0; + m_lineCount = aLineCount; + } + BOARD_ITEM* Parse(); /** @@ -154,6 +168,8 @@ private: */ void init(); + void checkpoint(); + /** * Create a mapping from the (short-lived) bug where layer names were translated. * @@ -342,6 +358,11 @@ private: bool m_showLegacyZoneWarning; + PROGRESS_REPORTER* m_progressReporter; ///< optional; may be nullptr + const LINE_READER* m_lineReader; ///< for progress reporting + unsigned m_lastProgressLine; + unsigned m_lineCount; ///< for progress reporting + // Group membership info refers to other Uuids in the file. // We don't want to rely on group declarations being last in the file, so // we store info about the group declarations here during parsing and then resolve diff --git a/pcbnew/plugins/legacy/legacy_plugin.cpp b/pcbnew/plugins/legacy/legacy_plugin.cpp index a8ab8d2ae1..47a9bddb8c 100644 --- a/pcbnew/plugins/legacy/legacy_plugin.cpp +++ b/pcbnew/plugins/legacy/legacy_plugin.cpp @@ -88,6 +88,7 @@ #include #include #include // for KiROUND +#include typedef LEGACY_PLUGIN::BIU BIU; @@ -194,6 +195,28 @@ static bool inline isSpace( int c ) { return strchr( delims, c ) != nullptr; } #define MASK(x) (1<<(x)) + +void LEGACY_PLUGIN::checkpoint() +{ + const unsigned PROGRESS_DELTA = 250; + + if( m_progressReporter ) + { + unsigned curLine = m_reader->LineNumber(); + + if( curLine > m_lastProgressLine + PROGRESS_DELTA ) + { + m_progressReporter->SetCurrentProgress( ( (double) curLine ) / m_lineCount ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + m_lastProgressLine = curLine; + } + } +} + + //-------------------------------------------------------- /// C string compare test for a specific length of characters. @@ -378,7 +401,8 @@ static inline long hexParse( const char* next, const char** out = NULL ) BOARD* LEGACY_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { LOCALE_IO toggle; // toggles on, then off, the C locale. @@ -402,13 +426,30 @@ BOARD* LEGACY_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, FILE_LINE_READER reader( aFileName ); - m_reader = &reader; // member function accessibility + m_reader = &reader; + m_progressReporter = aProgressReporter; checkVersion(); + if( m_progressReporter ) + { + m_lineCount = 0; + + m_progressReporter->Report( wxString::Format( _( "Loading %s..." ), aFileName ) ); + + if( !m_progressReporter->KeepRefreshing() ) + THROW_IO_ERROR( ( "Open cancelled by user." ) ); + + while( reader.ReadLine() ) + m_lineCount++; + + reader.Rewind(); + } + loadAllSections( bool( aAppendToMe ) ); (void)boardDeleter.release(); // give it up so we dont delete it on exit + m_progressReporter = nullptr; return m_board; } @@ -426,6 +467,8 @@ void LEGACY_PLUGIN::loadAllSections( bool doAppend ) while( ( line = READLINE( m_reader ) ) != NULL ) { + checkpoint(); + // put the more frequent ones at the top, but realize TRACKs are loaded as a group if( TESTLINE( "$MODULE" ) ) @@ -2200,6 +2243,8 @@ void LEGACY_PLUGIN::loadTrackList( int aStructType ) while( ( line = READLINE( m_reader ) ) != NULL ) { + checkpoint(); + // read two lines per loop iteration, each loop is one TRACK or VIA // example first line: // e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track @@ -3386,6 +3431,9 @@ LEGACY_PLUGIN::LEGACY_PLUGIN() : m_cu_count( 16 ), // for FootprintLoad() m_board( nullptr ), m_props( nullptr ), + m_progressReporter( nullptr ), + m_lastProgressLine( 0 ), + m_lineCount( 0 ), m_reader( nullptr ), m_fp( nullptr ), m_cache( nullptr ) diff --git a/pcbnew/plugins/legacy/legacy_plugin.h b/pcbnew/plugins/legacy/legacy_plugin.h index 2a28b7b2e7..459e6f91ab 100644 --- a/pcbnew/plugins/legacy/legacy_plugin.h +++ b/pcbnew/plugins/legacy/legacy_plugin.h @@ -74,7 +74,8 @@ public: } BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr ) override; + const PROPERTIES* aProperties = nullptr, PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath, bool aBestEfforts, @@ -101,6 +102,11 @@ public: static LSET leg_mask2new( int cu_count, unsigned aMask ); protected: + /// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed. + void init( const PROPERTIES* aProperties ); + + void checkpoint(); + ///< Converts net code using the mapping table if available, ///< otherwise returns unchanged net code inline int getNetCode( int aNetCode ) @@ -174,24 +180,25 @@ protected: void cacheLib( const wxString& aLibraryPath ); protected: - int m_cu_count; + int m_cu_count; - wxString m_error; ///< for throwing exceptions - BOARD* m_board; ///< which BOARD, no ownership here - const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL. + wxString m_error; ///< for throwing exceptions + BOARD* m_board; ///< which BOARD, no ownership here + const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, + ///< may be NULL. + PROGRESS_REPORTER* m_progressReporter; ///< may be NULL, no ownership + unsigned m_lastProgressLine; + unsigned m_lineCount; ///< for progress reporting - LINE_READER* m_reader; ///< no ownership here. - FILE* m_fp; ///< no ownership here. + LINE_READER* m_reader; ///< no ownership here. + FILE* m_fp; ///< no ownership here. - wxString m_field; ///< reused to stuff FOOTPRINT fields. - int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing? - LP_CACHE* m_cache; - bool m_showLegacyZoneWarning; + wxString m_field; ///< reused to stuff FOOTPRINT fields. + int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing? + LP_CACHE* m_cache; + bool m_showLegacyZoneWarning; - std::vector m_netCodes; ///< net codes mapping for boards being loaded - - /// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed. - void init( const PROPERTIES* aProperties ); + std::vector m_netCodes; ///< net codes mapping for boards being loaded double biuToDisk; ///< convert from BIUs to disk engineering units ///< with this scale factor diff --git a/pcbnew/plugins/pcad/pcad_plugin.cpp b/pcbnew/plugins/pcad/pcad_plugin.cpp index 9356d00a43..b87a3ee2ad 100644 --- a/pcbnew/plugins/pcad/pcad_plugin.cpp +++ b/pcbnew/plugins/pcad/pcad_plugin.cpp @@ -66,7 +66,8 @@ const wxString PCAD_PLUGIN::GetFileExtension() const BOARD* PCAD_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, - const PROPERTIES* aProperties, PROJECT* aProject ) + const PROPERTIES* aProperties, PROJECT* aProject, + PROGRESS_REPORTER* aProgressReporter ) { wxXmlDocument xmlDoc; diff --git a/pcbnew/plugins/pcad/pcad_plugin.h b/pcbnew/plugins/pcad/pcad_plugin.h index 8bd1a614d6..897374413a 100644 --- a/pcbnew/plugins/pcad/pcad_plugin.h +++ b/pcbnew/plugins/pcad/pcad_plugin.h @@ -40,10 +40,11 @@ public: const wxString PluginName() const override; - BOARD* Load( const wxString& aFileName, - BOARD* aAppendToMe, - const PROPERTIES* aProperties = nullptr, - PROJECT* aProject = nullptr ) override; + BOARD* Load( const wxString& aFileName, + BOARD* aAppendToMe, + const PROPERTIES* aProperties = nullptr, + PROJECT* aProject = nullptr, + PROGRESS_REPORTER* aProgressReporter = nullptr ) override; const wxString GetFileExtension() const override; diff --git a/pcbnew/tools/pcb_control.cpp b/pcbnew/tools/pcb_control.cpp index a6fb1763b6..acb8892b00 100644 --- a/pcbnew/tools/pcb_control.cpp +++ b/pcbnew/tools/pcb_control.cpp @@ -55,6 +55,7 @@ #include #include #include +#include using namespace std::placeholders; @@ -1018,8 +1019,10 @@ int PCB_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName ) props["page_width"] = xbuf; props["page_height"] = ybuf; + WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Loading PCB" ), 1 ); + editFrame->GetDesignSettings().GetNetClasses().Clear(); - pi.Load( fileName, brd, &props ); + pi.Load( fileName, brd, &props, nullptr, &progressReporter ); } catch( const IO_ERROR& ioe ) {