Add progress reporting to CADSTAR Schematic & PCB importers

Fixes https://gitlab.com/kicad/code/kicad/-/issues/8685
This commit is contained in:
Roberto Fernandez Bautista 2021-09-09 22:15:38 +01:00
parent fbee62fc15
commit 625e56676a
11 changed files with 208 additions and 18 deletions

View File

@ -31,6 +31,7 @@
#include <eda_item.h>
#include <eda_text.h>
#include <macros.h>
#include <progress_reporter.h>
#include <string_utils.h>
#include <trigo.h>
@ -1963,6 +1964,8 @@ void CADSTAR_ARCHIVE_PARSER::PARTS::Parse( XNODE* aNode, PARSER_CONTEXT* aContex
{
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
}
aContext->CheckPointCallback();
}
}
@ -2313,7 +2316,7 @@ void CADSTAR_ARCHIVE_PARSER::InsertAttributeAtEnd( XNODE* aNode, wxString aValue
XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
const wxString& aFileTypeIdentifier )
const wxString& aFileTypeIdentifier, PROGRESS_REPORTER* aProgressReporter )
{
KEYWORD emptyKeywords[1] = {};
XNODE * iNode = nullptr, *cNode = nullptr;
@ -2323,15 +2326,32 @@ XNODE* CADSTAR_ARCHIVE_PARSER::LoadArchiveFile( const wxString& aFileName,
wxCSConv win1252( wxT( "windows-1252" ) );
wxMBConv* conv = &win1252; // Initial testing suggests file encoding to be Windows-1252
// More samples required.
// Open the file and get the file size
FILE* fp = wxFopen( aFileName, wxT( "rt" ) );
fseek( fp, 0L, SEEK_END );
long fileSize = ftell( fp );
rewind( fp );
if( !fp )
THROW_IO_ERROR( wxString::Format( _( "Cannot open file '%s'" ), aFileName ) );
DSNLEXER lexer( emptyKeywords, 0, fp, aFileName );
long currentPosition = 0;
while( ( tok = lexer.NextTok() ) != DSN_EOF )
{
if( aProgressReporter )
{
if( !aProgressReporter->KeepRefreshing() )
THROW_IO_ERROR( _( "File import cancelled by user." ) );
currentPosition = ftell( fp );
double currentprogress = static_cast<double>( currentPosition ) / fileSize;
aProgressReporter->SetCurrentProgress( currentprogress );
}
if( tok == DSN_RIGHT )
{
cNode = iNode;
@ -2547,6 +2567,38 @@ std::vector<CADSTAR_ARCHIVE_PARSER::CUTOUT> CADSTAR_ARCHIVE_PARSER::ParseAllChil
}
long CADSTAR_ARCHIVE_PARSER::GetNumberOfChildNodes( XNODE* aNode )
{
XNODE* childNodes = aNode->GetChildren();
long retval = 0;
for( ; childNodes; childNodes = childNodes->GetNext() )
retval++;
return retval;
}
long CADSTAR_ARCHIVE_PARSER::GetNumberOfStepsForReporting( XNODE* aRootNode, std::vector<wxString> aSubNodeChildrenToCount )
{
XNODE* level1Node = aRootNode->GetChildren();
long retval = 0;
for( ; level1Node; level1Node = level1Node->GetNext() )
{
for( wxString childNodeName : aSubNodeChildrenToCount )
{
if( level1Node->GetName() == childNodeName )
retval += GetNumberOfChildNodes( level1Node );
}
retval++;
}
return retval;
}
wxString CADSTAR_ARCHIVE_PARSER::HandleTextOverbar( wxString aCadstarString )
{
wxString escapedText = aCadstarString;
@ -2584,3 +2636,15 @@ void CADSTAR_ARCHIVE_PARSER::FixTextPositionNoAlignment( EDA_TEXT* aKiCadTextIte
aKiCadTextItem->Offset( positionOffset );
}
}
void CADSTAR_ARCHIVE_PARSER::checkPoint()
{
if( m_progressReporter )
{
m_progressReporter->AdvanceProgress();
if( !m_progressReporter->KeepRefreshing() )
THROW_IO_ERROR( _( "File import cancelled by user." ) );
}
}

View File

@ -77,6 +77,7 @@
class EDA_TEXT;
class wxXmlAttribute;
class PROGRESS_REPORTER;
/**
* @brief Helper functions and common structures for CADSTAR PCB and Schematic archive files.
@ -84,6 +85,9 @@ class wxXmlAttribute;
class CADSTAR_ARCHIVE_PARSER
{
public:
CADSTAR_ARCHIVE_PARSER() { m_progressReporter = nullptr; }
typedef wxString LINECODE_ID;
typedef wxString HATCHCODE_ID;
typedef wxString ROUTECODE_ID;
@ -185,6 +189,11 @@ public:
* consistent across text elements.
*/
std::set<TEXT_FIELD_NAME> InconsistentTextFields;
/**
* Callback function to report progress
*/
std::function<void()> CheckPointCallback = []() {};
};
/**
@ -1268,12 +1277,14 @@ public:
* @param aFileName
* @param aFileTypeIdentifier Identifier of the first node in the file to check against.
E.g. "CADSTARPCB"
* @param aProgressReporter Pointer to a Progress Reporter to report progress to.
* @return XNODE pointing to the top of the tree for further parsing. Each node has the first
* element as the node's name and subsequent elements as node attributes ("attr0",
* "attr1", "attr2", etc.). Caller is responsible for deleting to avoid memory leaks.
* @throws IO_ERROR
*/
static XNODE* LoadArchiveFile( const wxString& aFileName, const wxString& aFileTypeIdentifier );
static XNODE* LoadArchiveFile( const wxString& aFileName, const wxString& aFileTypeIdentifier,
PROGRESS_REPORTER* aProgressReporter = nullptr );
/**
* @brief
@ -1368,6 +1379,11 @@ public:
static std::vector<CUTOUT> ParseAllChildCutouts(
XNODE* aNode, PARSER_CONTEXT* aContext, bool aTestAllChildNodes = false );
static long GetNumberOfChildNodes( XNODE* aNode );
static long GetNumberOfStepsForReporting( XNODE* aRootNode,
std::vector<wxString> aSubNodeChildrenToCount );
/**
* @brief Convert a string with CADSTAR overbar characters to equivalent in KiCad
* @param aCadstarString Input string
@ -1389,8 +1405,12 @@ public:
: wxT( "" ) );
}
protected:
PARSER_CONTEXT m_context;
void checkPoint(); ///< Updates m_progressReporter or throws if user cancelled
PARSER_CONTEXT m_context;
PROGRESS_REPORTER* m_progressReporter; // optional; may be nullptr
}; // class CADSTAR_ARCHIVE_PARSER

View File

@ -32,6 +32,7 @@
#include <lib_polyline.h>
#include <lib_text.h>
#include <macros.h>
#include <progress_reporter.h>
#include <string_utils.h>
#include <sch_bus_entry.h>
#include <sch_edit_frame.h> //SYMBOL_ORIENTATION_T
@ -54,6 +55,9 @@ const wxString PartNameFieldName = "Part Name";
void CADSTAR_SCH_ARCHIVE_LOADER::Load( SCHEMATIC* aSchematic, SCH_SHEET* aRootSheet,
SCH_PLUGIN::SCH_PLUGIN_RELEASER* aSchPlugin, const wxFileName& aLibraryFileName )
{
if( m_progressReporter )
m_progressReporter->SetNumPhases( 3 ); // (0) Read file, (1) Parse file, (2) Load file
Parse();
LONGPOINT designLimit = Assignments.Settings.DesignLimit;
@ -87,17 +91,38 @@ void CADSTAR_SCH_ARCHIVE_LOADER::Load( SCHEMATIC* aSchematic, SCH_SHEET* aRootSh
m_plugin = aSchPlugin;
m_libraryFileName = aLibraryFileName;
if( m_progressReporter )
{
m_progressReporter->BeginPhase( 2 );
long numSteps = 11; // one step for each of below functions + one at the end of import
// Step 4 is by far the longest - add granularity in reporting
numSteps += Parts.PartDefinitions.size();
m_progressReporter->SetMaxProgress( numSteps );
}
loadTextVariables(); // Load text variables right at the start to ensure bounding box
// calculations work correctly for text items
checkPoint(); // Step 1
loadSheets();
checkPoint(); // Step 2
loadHierarchicalSheetPins();
checkPoint(); // Step 3
loadPartsLibrary();
checkPoint(); // Step 4, Subdivided into extra steps
loadSchematicSymbolInstances();
checkPoint(); // Step 5
loadBusses();
checkPoint(); // Step 6
loadNets();
checkPoint(); // Step 7
loadFigures();
checkPoint(); // Step 8
loadTexts();
checkPoint(); // Step 9
loadDocumentationSymbols();
checkPoint(); // Step 10
if( Schematic.VariantHierarchy.Variants.size() > 0 )
{
@ -219,6 +244,8 @@ void CADSTAR_SCH_ARCHIVE_LOADER::Load( SCHEMATIC* aSchematic, SCH_SHEET* aRootSh
}
}
checkPoint();
m_reporter->Report( _( "The CADSTAR design has been imported successfully.\n"
"Please review the import errors and warnings (if any)." ) );
}
@ -382,6 +409,8 @@ void CADSTAR_SCH_ARCHIVE_LOADER::loadPartsLibrary()
// been loaded correctly (saving us time later on)
m_partMap.insert( { partID, kiPart } );
}
checkPoint();
}
}

View File

@ -55,15 +55,17 @@ public:
// Size of tiny net labels when none present in original design
const int SMALL_LABEL_SIZE = KiROUND( (double) SCH_IU_PER_MM * 0.4 );
explicit CADSTAR_SCH_ARCHIVE_LOADER( wxString aFilename, REPORTER* aReporter )
: CADSTAR_SCH_ARCHIVE_PARSER( aFilename )
explicit CADSTAR_SCH_ARCHIVE_LOADER( wxString aFilename, REPORTER* aReporter,
PROGRESS_REPORTER* aProgressReporter ) :
CADSTAR_SCH_ARCHIVE_PARSER( aFilename )
{
m_schematic = nullptr;
m_rootSheet = nullptr;
m_plugin = nullptr;
m_schematic = nullptr;
m_rootSheet = nullptr;
m_plugin = nullptr;
m_designCenter.x = 0;
m_designCenter.y = 0;
m_reporter = aReporter;
m_reporter = aReporter;
m_progressReporter = aProgressReporter;
}

View File

@ -26,12 +26,29 @@
#include <convert_to_biu.h> // SCH_IU_PER_MM
#include <macros.h>
#include <sch_plugins/cadstar/cadstar_sch_archive_parser.h>
#include <progress_reporter.h>
#include <wx/translation.h>
void CADSTAR_SCH_ARCHIVE_PARSER::Parse()
{
XNODE* fileRootNode = LoadArchiveFile( Filename, wxT( "CADSTARSCM" ) );
if( m_progressReporter )
m_progressReporter->BeginPhase( 0 ); // Read file
XNODE* fileRootNode = LoadArchiveFile( Filename, wxT( "CADSTARSCM" ), m_progressReporter );
if( m_progressReporter )
{
m_progressReporter->BeginPhase( 1 ); // Parse File
std::vector<wxString> subNodeChildrenToCount = { wxT( "LIBRARY" ), wxT( "PARTS" ),
wxT( "SCHEMATIC" ) };
long numOfSteps = GetNumberOfStepsForReporting( fileRootNode, subNodeChildrenToCount );
m_progressReporter->SetMaxProgress( numOfSteps );
}
m_context.CheckPointCallback = [&](){ checkPoint(); };
XNODE* cNode = fileRootNode->GetChildren();
@ -124,6 +141,8 @@ void CADSTAR_SCH_ARCHIVE_PARSER::Parse()
{
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "[root]" ) );
}
checkPoint();
}
delete fileRootNode;
@ -441,6 +460,8 @@ void CADSTAR_SCH_ARCHIVE_PARSER::LIBRARY_SCM::Parse( XNODE* aNode, PARSER_CONTEX
{
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
}
aContext->CheckPointCallback();
}
}
@ -1181,6 +1202,8 @@ void CADSTAR_SCH_ARCHIVE_PARSER::CADSTAR_SCHEMATIC::Parse( XNODE* aNode, PARSER_
{
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
}
aContext->CheckPointCallback();
}
}

View File

@ -134,7 +134,7 @@ SCH_SHEET* CADSTAR_SCH_ARCHIVE_PLUGIN::Load( const wxString& aFileName, SCHEMATI
aSchematic->Prj().SchSymbolLibTable();
}
CADSTAR_SCH_ARCHIVE_LOADER csaFile( aFileName, m_reporter );
CADSTAR_SCH_ARCHIVE_LOADER csaFile( aFileName, m_reporter, m_progressReporter );
csaFile.Load( aSchematic, rootSheet, &sch_plugin, libFileName );
sch_plugin->SaveLibrary( libFileName.GetFullPath() );

View File

@ -42,6 +42,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;
@ -57,13 +62,16 @@ public:
CADSTAR_SCH_ARCHIVE_PLUGIN()
{
m_reporter = &WXLOG_REPORTER::GetInstance();
m_progressReporter = nullptr;
}
~CADSTAR_SCH_ARCHIVE_PLUGIN()
{
}
REPORTER* m_reporter; // current reporter for warnings/errors
private:
REPORTER* m_reporter; // current reporter for warnings/errors
PROGRESS_REPORTER* m_progressReporter; // optional; may be nullptr
};
#endif // CADSTAR_SCH_ARCHIVE_PLUGIN_H_

View File

@ -38,6 +38,7 @@
#include <pcb_text.h>
#include <project.h>
#include <pcb_track.h>
#include <progress_reporter.h>
#include <zone.h>
#include <convert_basic_shapes_to_polygon.h>
#include <trigo.h>
@ -52,6 +53,9 @@ void CADSTAR_PCB_ARCHIVE_LOADER::Load( BOARD* aBoard, PROJECT* aProject )
m_board = aBoard;
m_project = aProject;
if( m_progressReporter )
m_progressReporter->SetNumPhases( 3 ); // (0) Read file, (1) Parse file, (2) Load file
Parse();
LONGPOINT designLimit = Assignments.Technology.DesignLimit;
@ -90,6 +94,18 @@ void CADSTAR_PCB_ARCHIVE_LOADER::Load( BOARD* aBoard, PROJECT* aProject )
"PCB and the schematic. " ) );
}
if( m_progressReporter )
{
m_progressReporter->BeginPhase( 2 );
// Significantly most amount of time spent loading coppers compared to all the other steps
// (39 seconds vs max of 100ms in other steps). This is due to requirement of boolean
// operations to join them together into a single polygon.
long numSteps = Layout.Coppers.size();
m_progressReporter->SetMaxProgress( numSteps );
}
loadBoardStackup();
remapUnsureLayers();
loadDesignRules();
@ -103,7 +119,7 @@ void CADSTAR_PCB_ARCHIVE_LOADER::Load( BOARD* aBoard, PROJECT* aProject )
loadComponents();
loadDocumentationSymbols();
loadTemplates();
loadCoppers();
loadCoppers(); // Progress reporting is here as significantly most amount of time spent
calculateZonePriorities();
loadNets();
loadTextVariables();
@ -1946,6 +1962,8 @@ void CADSTAR_PCB_ARCHIVE_LOADER::loadCoppers()
{
COPPER& csCopper = copPair.second;
checkPoint();
if( !csCopper.PouredTemplateID.IsEmpty() )
{
ZONE* pouredZone = m_zonesMap.at( csCopper.PouredTemplateID );

View File

@ -39,8 +39,10 @@ class PCB_DIMENSION_BASE;
class CADSTAR_PCB_ARCHIVE_LOADER : public CADSTAR_PCB_ARCHIVE_PARSER
{
public:
explicit CADSTAR_PCB_ARCHIVE_LOADER(
wxString aFilename, LAYER_MAPPING_HANDLER aLayerMappingHandler, bool aLogLayerWarnings )
explicit CADSTAR_PCB_ARCHIVE_LOADER( wxString aFilename,
LAYER_MAPPING_HANDLER aLayerMappingHandler,
bool aLogLayerWarnings,
PROGRESS_REPORTER* aProgressReporter )
: CADSTAR_PCB_ARCHIVE_PARSER( aFilename )
{
m_layerMappingHandler = aLayerMappingHandler;
@ -53,6 +55,7 @@ public:
m_doneSpacingClassWarning = false;
m_doneNetClassWarning = false;
m_numNets = 0;
m_progressReporter = aProgressReporter;
}

View File

@ -26,12 +26,29 @@
#include <cadstar_pcb_archive_parser.h>
#include <convert_to_biu.h> // PCB_IU_PER_MM
#include <macros.h>
#include <progress_reporter.h>
#include <wx/translation.h>
void CADSTAR_PCB_ARCHIVE_PARSER::Parse()
{
XNODE* fileRootNode = LoadArchiveFile( Filename, wxT( "CADSTARPCB" ) );
if( m_progressReporter )
m_progressReporter->BeginPhase( 0 ); // Read file
XNODE* fileRootNode = LoadArchiveFile( Filename, wxT( "CADSTARPCB" ), m_progressReporter );
if( m_progressReporter )
{
m_progressReporter->BeginPhase( 1 ); // Parse File
std::vector<wxString> subNodeChildrenToCount = { wxT( "LIBRARY" ), wxT( "PARTS" ),
wxT( "LAYOUT" ) };
long numOfSteps = GetNumberOfStepsForReporting( fileRootNode, subNodeChildrenToCount );
m_progressReporter->SetMaxProgress( numOfSteps );
}
m_context.CheckPointCallback = [&](){ checkPoint(); };
XNODE* cNode = fileRootNode->GetChildren();
@ -102,6 +119,8 @@ void CADSTAR_PCB_ARCHIVE_PARSER::Parse()
{
THROW_UNKNOWN_NODE_IO_ERROR( cNode->GetName(), wxT( "[root]" ) );
}
checkPoint();
}
delete fileRootNode;
@ -1598,6 +1617,8 @@ void CADSTAR_PCB_ARCHIVE_PARSER::LIBRARY::Parse( XNODE* aNode, PARSER_CONTEXT* a
{
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
}
aContext->CheckPointCallback();
}
}
@ -2579,5 +2600,7 @@ void CADSTAR_PCB_ARCHIVE_PARSER::LAYOUT::Parse( XNODE* aNode, PARSER_CONTEXT* aC
{
THROW_UNKNOWN_NODE_IO_ERROR( cNodeName, aNode->GetName() );
}
aContext->CheckPointCallback();
}
}

View File

@ -113,8 +113,8 @@ BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppe
m_board = aAppendToMe ? aAppendToMe : new BOARD();
clearLoadedFootprints();
CADSTAR_PCB_ARCHIVE_LOADER tempPCB(
aFileName, m_layer_mapping_handler, m_show_layer_mapping_warnings );
CADSTAR_PCB_ARCHIVE_LOADER tempPCB( aFileName, m_layer_mapping_handler,
m_show_layer_mapping_warnings, aProgressReporter );
tempPCB.Load( m_board, aProject );
//center the board: