File open/import progress dialogs.

Fixes https://gitlab.com/kicad/code/kicad/issues/6864

Fixes https://gitlab.com/kicad/code/kicad/issues/2166
This commit is contained in:
Jeff Young 2021-06-23 23:53:08 +01:00
parent 1d6ad4a52a
commit 5fa5a73c6d
45 changed files with 643 additions and 158 deletions

View File

@ -167,8 +167,8 @@ FILE_LINE_READER::FILE_LINE_READER( const wxString& aFileName,
if( !m_fp ) if( !m_fp )
{ {
wxString msg = wxString::Format( wxString msg = wxString::Format( _( "Unable to open %s for reading." ),
_( "Unable to open filename \"%s\" for reading" ), aFileName.GetData() ); aFileName.GetData() );
THROW_IO_ERROR( msg ); 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() char* FILE_LINE_READER::ReadLine()
{ {
m_length = 0; m_length = 0;

View File

@ -369,14 +369,6 @@ bool PGM_SINGLE_TOP::OnPgmInit()
App().SetTopWindow( frame ); // wxApp gets a face. App().SetTopWindow( frame ); // wxApp gets a face.
App().SetAppDisplayName( frame->GetAboutTitle() ); 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, // 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 // any positional arguments are treated as a list of files to pass to OpenProjectFiles
frame->ParseArgs( parser ); frame->ParseArgs( parser );

View File

@ -61,6 +61,7 @@
#include <tools/ee_inspection_tool.h> #include <tools/ee_inspection_tool.h>
#include <paths.h> #include <paths.h>
#include <wx_filename.h> // For ::ResolvePossibleSymlinks #include <wx_filename.h> // For ::ResolvePossibleSymlinks
#include <widgets/progress_reporter.h>
bool SCH_EDIT_FRAME::SaveEEFile( SCH_SHEET* aSheet, bool aSaveUnderNewName ) bool SCH_EDIT_FRAME::SaveEEFile( SCH_SHEET* aSheet, bool aSaveUnderNewName )
{ {
@ -400,6 +401,9 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
SCH_PLUGIN* plugin = SCH_IO_MGR::FindPlugin( schFileType ); SCH_PLUGIN* plugin = SCH_IO_MGR::FindPlugin( schFileType );
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( plugin ); SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( plugin );
WX_PROGRESS_REPORTER progressReporter( this, _( "Loading Schematic" ), 1 );
pi->SetProgressReporter( &progressReporter );
bool failedLoad = false; bool failedLoad = false;
try try
{ {
@ -1117,20 +1121,19 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType )
try try
{ {
SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( fileType ) ); 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() ) ); Schematic().SetRoot( pi->Load( aFileName, &Schematic() ) );
if( reporter->m_Reporter->HasMessage() ) if( errorReporter.m_Reporter->HasMessage() )
{ {
reporter->m_Reporter->Flush(); // Build HTML messages errorReporter.m_Reporter->Flush(); // Build HTML messages
reporter->ShowModal(); 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 // 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 // to KiCad), so set it to an empty one
DS_DATA_MODEL& drawingSheet = DS_DATA_MODEL::GetTheInstance(); DS_DATA_MODEL& drawingSheet = DS_DATA_MODEL::GetTheInstance();

View File

@ -38,6 +38,7 @@ class KIWAY;
class LIB_SYMBOL; class LIB_SYMBOL;
class SYMBOL_LIB; class SYMBOL_LIB;
class PROPERTIES; class PROPERTIES;
class PROGRESS_REPORTER;
/** /**
@ -164,6 +165,11 @@ public:
*/ */
virtual void SetReporter( REPORTER* aReporter ) {} virtual void SetReporter( REPORTER* aReporter ) {}
/**
* Set an optional progress reporter.
*/
virtual void SetProgressReporter( PROGRESS_REPORTER* aReporter ) {}
/** /**
* Return the file extension for the #SCH_PLUGIN. * Return the file extension for the #SCH_PLUGIN.
*/ */

View File

@ -33,6 +33,7 @@
#include <wx/tokenzr.h> #include <wx/tokenzr.h>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include <wx/xml/xml.h> #include <wx/xml/xml.h>
#include <wx/msgdlg.h>
#include <symbol_library.h> #include <symbol_library.h>
#include <plugins/eagle/eagle_parser.h> #include <plugins/eagle/eagle_parser.h>
@ -60,6 +61,7 @@
#include <schematic.h> #include <schematic.h>
#include <symbol_lib_table.h> #include <symbol_lib_table.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <widgets/progress_reporter.h>
// Eagle schematic axes are aligned with x increasing left to right and Y increasing bottom to top // 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_rootSheet = nullptr;
m_currentSheet = 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* SCH_EAGLE_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) 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_filename = aFileName;
m_schematic = aSchematic; 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 // Load the document
wxXmlDocument xmlDocument; wxXmlDocument xmlDocument;
wxFFileInputStream stream( m_filename.GetFullPath() ); wxFFileInputStream stream( m_filename.GetFullPath() );
if( !stream.IsOk() || !xmlDocument.Load( stream ) ) 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() ) ); m_filename.GetFullPath() ) );
} }
@ -562,8 +595,68 @@ void SCH_EAGLE_PLUGIN::loadSchematic( wxXmlNode* aSchematicNode )
if( !sheetNode ) if( !sheetNode )
return; 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 ) while( partNode )
{ {
checkpoint();
std::unique_ptr<EPART> epart = std::make_unique<EPART>( partNode ); std::unique_ptr<EPART> epart = std::make_unique<EPART>( partNode );
// N.B. Eagle parts are case-insensitive in matching but we keep the display case // 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(); libraryNode = libraryNode->GetNext();
} }
m_pi->SaveLibrary( getLibFileName().GetFullPath() ); m_pi->SaveLibrary( getLibFileName().GetFullPath() );
} }
@ -734,6 +826,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
while( instanceNode ) while( instanceNode )
{ {
checkpoint();
loadInstance( instanceNode ); loadInstance( instanceNode );
instanceNode = instanceNode->GetNext(); instanceNode = instanceNode->GetNext();
} }
@ -746,6 +840,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
while( busNode ) while( busNode )
{ {
checkpoint();
// Get the bus name // Get the bus name
wxString busName = translateEagleBusName( busNode->GetAttribute( "name" ) ); wxString busName = translateEagleBusName( busNode->GetAttribute( "name" ) );
@ -762,6 +858,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
while( netNode ) while( netNode )
{ {
checkpoint();
// Get the net name and class // Get the net name and class
wxString netName = netNode->GetAttribute( "name" ); wxString netName = netNode->GetAttribute( "name" );
wxString netClass = netNode->GetAttribute( "class" ); wxString netClass = netNode->GetAttribute( "class" );
@ -792,6 +890,8 @@ void SCH_EAGLE_PLUGIN::loadSheet( wxXmlNode* aSheetNode, int aSheetIndex )
while( plainNode ) while( plainNode )
{ {
checkpoint();
wxString nodeName = plainNode->GetName(); wxString nodeName = plainNode->GetName();
if( nodeName == "text" ) if( nodeName == "text" )
@ -1371,8 +1471,8 @@ void SCH_EAGLE_PLUGIN::loadInstance( wxXmlNode* aInstanceNode )
} }
EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLibraryNode,
wxXmlNode* aLibraryNode, EAGLE_LIBRARY* aEagleLibrary ) EAGLE_LIBRARY* aEagleLibrary )
{ {
NODE_MAP libraryChildren = MapChildren( aLibraryNode ); NODE_MAP libraryChildren = MapChildren( aLibraryNode );
@ -1396,8 +1496,8 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary(
wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : ""; wxString prefix = edeviceset.prefix ? edeviceset.prefix.Get() : "";
NODE_MAP aDeviceSetChildren = MapChildren( devicesetNode ); NODE_MAP deviceSetChildren = MapChildren( devicesetNode );
wxXmlNode* deviceNode = getChildrenNodes( aDeviceSetChildren, "devices" ); wxXmlNode* deviceNode = getChildrenNodes( deviceSetChildren, "devices" );
// For each device in the device set: // For each device in the device set:
while( deviceNode ) while( deviceNode )
@ -1418,8 +1518,8 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary(
unique_ptr<LIB_SYMBOL> kpart( new LIB_SYMBOL( symbolName ) ); unique_ptr<LIB_SYMBOL> kpart( new LIB_SYMBOL( symbolName ) );
// Process each gate in the deviceset for this device. // Process each gate in the deviceset for this device.
wxXmlNode* gateNode = getChildrenNodes( aDeviceSetChildren, "gates" ); wxXmlNode* gateNode = getChildrenNodes( deviceSetChildren, "gates" );
int gates_count = countChildren( aDeviceSetChildren["gates"], "gate" ); int gates_count = countChildren( deviceSetChildren["gates"], "gate" );
kpart->SetUnitCount( gates_count ); kpart->SetUnitCount( gates_count );
kpart->LockUnits( true ); kpart->LockUnits( true );
@ -1437,10 +1537,11 @@ EAGLE_LIBRARY* SCH_EAGLE_PLUGIN::loadLibrary(
while( gateNode ) while( gateNode )
{ {
checkpoint();
EGATE egate = EGATE( gateNode ); EGATE egate = EGATE( gateNode );
aEagleLibrary->GateUnit[edeviceset.name + edevice.name + egate.name] = gateindex; aEagleLibrary->GateUnit[edeviceset.name + edevice.name + egate.name] = gateindex;
ispower = loadSymbol( aEagleLibrary->SymbolNodes[egate.symbol], kpart, &edevice, ispower = loadSymbol( aEagleLibrary->SymbolNodes[egate.symbol], kpart, &edevice,
gateindex, egate.name ); gateindex, egate.name );

View File

@ -87,6 +87,11 @@ public:
void SetReporter( REPORTER* aReporter ) override { m_reporter = aReporter; } void SetReporter( REPORTER* aReporter ) override { m_reporter = aReporter; }
void SetProgressReporter( PROGRESS_REPORTER* aReporter ) override
{
m_progressReporter = aReporter;
}
const wxString GetFileExtension() const override; const wxString GetFileExtension() const override;
const wxString GetLibraryFileExtension() const override; const wxString GetLibraryFileExtension() const override;
@ -99,8 +104,9 @@ public:
bool CheckHeader( const wxString& aFileName ) override; bool CheckHeader( const wxString& aFileName ) override;
private: private:
void checkpoint();
void loadDrawing( wxXmlNode* aDrawingNode ); void loadDrawing( wxXmlNode* aDrawingNode );
void loadLayerDefs( wxXmlNode* aLayers ); void loadLayerDefs( wxXmlNode* aLayers );
void loadSchematic( wxXmlNode* aSchematicNode ); void loadSchematic( wxXmlNode* aSchematicNode );
@ -120,15 +126,15 @@ private:
SCH_LAYER_ID kiCadLayer( int aEagleLayer ); SCH_LAYER_ID kiCadLayer( int aEagleLayer );
std::pair<VECTOR2I, const SEG*> findNearestLinePoint( const wxPoint& aPoint, std::pair<VECTOR2I, const SEG*> findNearestLinePoint( const wxPoint& aPoint,
const std::vector<SEG>& aLines ) const; const std::vector<SEG>& aLines ) const;
void loadSegments( wxXmlNode* aSegmentsNode, const wxString& aNetName, void loadSegments( wxXmlNode* aSegmentsNode, const wxString& aNetName,
const wxString& aNetClass ); const wxString& aNetClass );
SCH_LINE* loadWire( wxXmlNode* aWireNode ); SCH_LINE* loadWire( wxXmlNode* aWireNode );
SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName ); SCH_TEXT* loadLabel( wxXmlNode* aLabelNode, const wxString& aNetName );
SCH_JUNCTION* loadJunction( wxXmlNode* aJunction ); SCH_JUNCTION* loadJunction( wxXmlNode* aJunction );
SCH_TEXT* loadPlainText( wxXmlNode* aSchText ); SCH_TEXT* loadPlainText( wxXmlNode* aSchText );
void loadFrame( wxXmlNode* aFrameNode, std::vector<SCH_LINE*>& aLines ); void loadFrame( wxXmlNode* aFrameNode, std::vector<SCH_LINE*>& aLines );
bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_SYMBOL>& aSymbol, bool loadSymbol( wxXmlNode* aSymbolNode, std::unique_ptr<LIB_SYMBOL>& aSymbol,
EDEVICE* aDevice, int aGateNumber, const wxString& aGateName ); EDEVICE* aDevice, int aGateNumber, const wxString& aGateName );
@ -228,8 +234,13 @@ private:
EPART_MAP m_partlist; EPART_MAP m_partlist;
std::map<wxString, EAGLE_LIBRARY> m_eagleLibs; std::map<wxString, EAGLE_LIBRARY> m_eagleLibs;
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi; ///< Plugin to create the KiCad symbol library. SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi; ///< PI to create KiCad symbol library.
std::unique_ptr< PROPERTIES > m_properties; ///< Library plugin properties. 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<wxString, int> m_netCounts; std::map<wxString, int> m_netCounts;
std::map<int, SCH_LAYER_ID> m_layerMap; std::map<int, SCH_LAYER_ID> m_layerMap;

View File

@ -55,21 +55,48 @@
#include <sch_plugins/kicad/sch_sexpr_parser.h> #include <sch_plugins/kicad/sch_sexpr_parser.h>
#include <template_fieldnames.h> #include <template_fieldnames.h>
#include <trigo.h> #include <trigo.h>
#include <widgets/progress_reporter.h>
using namespace TSCHEMATIC_T; 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 ), SCHEMATIC_LEXER( aLineReader ),
m_requiredVersion( 0 ), m_requiredVersion( 0 ),
m_fieldId( 0 ), m_fieldId( 0 ),
m_unit( 1 ), 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() bool SCH_SEXPR_PARSER::parseBool()
{ {
T token = NextTok(); T token = NextTok();
@ -2090,6 +2117,8 @@ void SCH_SEXPR_PARSER::ParseSchematic( SCH_SHEET* aSheet, bool aIsCopyableOnly,
token = NextTok(); token = NextTok();
checkpoint();
if( !aIsCopyableOnly && token == T_page && m_requiredVersion <= 20200506 ) if( !aIsCopyableOnly && token == T_page && m_requiredVersion <= 20200506 )
token = T_paper; token = T_paper;

View File

@ -84,6 +84,13 @@ class SCH_SEXPR_PARSER : public SCHEMATIC_LEXER
int m_convert; ///< The current body style being parsed. int m_convert; ///< The current body style being parsed.
wxString m_symbolName; ///< The current symbol name. 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 ); void parseHeader( TSCHEMATIC_T::T aHeaderType, int aFileVersion );
inline long parseHex() inline long parseHex()
@ -184,7 +191,8 @@ class SCH_SEXPR_PARSER : public SCHEMATIC_LEXER
void parseBusAlias( SCH_SCREEN* aScreen ); void parseBusAlias( SCH_SCREEN* aScreen );
public: 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 ); void ParseLib( LIB_SYMBOL_MAP& aSymbolLibMap );

View File

@ -61,6 +61,7 @@
#include <ee_selection.h> #include <ee_selection.h>
#include <kicad_string.h> #include <kicad_string.h>
#include <wx_filename.h> // for ::ResolvePossibleSymlinks() #include <wx_filename.h> // for ::ResolvePossibleSymlinks()
#include <widgets/progress_reporter.h>
using namespace TSCHEMATIC_T; 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 ); 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 m_nextFreeFieldId = 100; // number arbitrarily > MANDATORY_FIELDS or SHEET_MANDATORY_FIELDS
} }
SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic, SCH_SHEET* SCH_SEXPR_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) 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 // 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. // 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 */ ); wxCHECK2( aItem->Type() == SCH_SHEET_T, /* do nothing */ );
auto sheet = static_cast<SCH_SHEET*>( aItem ); SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
// Recursion starts here. // Recursion starts here.
loadHierarchy( sheet ); loadHierarchy( sheet );
@ -538,7 +541,22 @@ void SCH_SEXPR_PLUGIN::loadFile( const wxString& aFileName, SCH_SHEET* aSheet )
{ {
FILE_LINE_READER reader( aFileName ); 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 ); parser.ParseSchematic( aSheet );
} }

View File

@ -79,6 +79,11 @@ public:
return wxT( "kicad_sym" ); 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 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 * 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 ); bool isBuffering( const PROPERTIES* aProperties );
protected: protected:
int m_version; ///< Version of file being loaded. int m_version; ///< Version of file being loaded.
int m_nextFreeFieldId; 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. wxString m_path; ///< Root project path for loading child sheets.
std::stack<wxString> m_currentPath;///< Stack to maintain nested sheet paths std::stack<wxString> m_currentPath; ///< Stack to maintain nested sheet paths
SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.. SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.
SCHEMATIC* m_schematic; ///< Passed to Load(), the schematic object being loaded SCHEMATIC* m_schematic;
OUTPUTFORMATTER* m_out; ///< The output formatter for saving SCH_SCREEN objects. OUTPUTFORMATTER* m_out; ///< The formatter for saving SCH_SCREEN objects.
SCH_SEXPR_PLUGIN_CACHE* m_cache; SCH_SEXPR_PLUGIN_CACHE* m_cache;
/// initialize PLUGIN like a constructor would. /// initialize PLUGIN like a constructor would.

View File

@ -41,6 +41,9 @@
#include <properties.h> #include <properties.h>
#include <trace_helpers.h> #include <trace_helpers.h>
#include <trigo.h> #include <trigo.h>
#include <confirm.h>
#include <widgets/progress_reporter.h>
#include <wx_filename.h> // For ::ResolvePossibleSymlinks()
#include <general.h> #include <general.h>
#include <sch_bitmap.h> #include <sch_bitmap.h>
@ -70,10 +73,8 @@
#include <lib_text.h> #include <lib_text.h>
#include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition #include <eeschema_id.h> // for MAX_UNIT_COUNT_PER_PACKAGE definition
#include <symbol_lib_table.h> // for PropPowerSymsOnly definition. #include <symbol_lib_table.h> // for PropPowerSymsOnly definition.
#include <confirm.h>
#include <tool/selection.h> #include <tool/selection.h>
#include <default_values.h> // For some default values #include <default_values.h> // For some default values
#include <wx_filename.h> // For ::ResolvePossibleSymlinks()
#define Mils2Iu( x ) Mils2iu( x ) #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 ); 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* SCH_LEGACY_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
SCH_SHEET* aAppendToMe, const PROPERTIES* aProperties ) 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 ); 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 ); loadHeader( reader, aScreen );
LoadContent( reader, aScreen, m_version ); LoadContent( reader, aScreen, m_version );
@ -782,6 +824,8 @@ void SCH_LEGACY_PLUGIN::LoadContent( LINE_READER& aReader, SCH_SCREEN* aScreen,
while( aReader.ReadLine() ) while( aReader.ReadLine() )
{ {
checkpoint();
char* line = aReader.Line(); char* line = aReader.Line();
while( *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 // Skip all lines until the end of header "EELAYER END" is found
while( aReader.ReadLine() ) while( aReader.ReadLine() )
{ {
checkpoint();
line = aReader.Line(); line = aReader.Line();
while( *line == ' ' ) while( *line == ' ' )

View File

@ -82,6 +82,11 @@ public:
return wxT( "lib" ); 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 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 * 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 ); static void FormatPart( LIB_SYMBOL* aSymbol, OUTPUTFORMATTER& aFormatter );
private: private:
void checkpoint();
void loadHierarchy( SCH_SHEET* aSheet ); void loadHierarchy( SCH_SHEET* aSheet );
void loadHeader( LINE_READER& aReader, SCH_SCREEN* aScreen ); void loadHeader( LINE_READER& aReader, SCH_SCREEN* aScreen );
void loadPageSettings( LINE_READER& aReader, SCH_SCREEN* aScreen ); void loadPageSettings( LINE_READER& aReader, SCH_SCREEN* aScreen );
@ -170,17 +176,21 @@ private:
bool isBuffering( const PROPERTIES* aProperties ); bool isBuffering( const PROPERTIES* aProperties );
protected: 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; ///< For throwing exceptions or errors on partial
wxString m_error; ///< 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. wxString m_path; ///< Root project path for loading child sheets.
std::stack<wxString> m_currentPath;///< Stack to maintain nested sheet paths std::stack<wxString> m_currentPath; ///< Stack to maintain nested sheet paths
SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.. SCH_SHEET* m_rootSheet; ///< The root sheet of the schematic being loaded.
OUTPUTFORMATTER* m_out; ///< The output formatter for saving SCH_SCREEN objects. OUTPUTFORMATTER* m_out; ///< The formatter for saving SCH_SCREEN objects.
SCH_LEGACY_PLUGIN_CACHE* m_cache; 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. /// initialize PLUGIN like a constructor would.
void init( SCHEMATIC* aSchematic, const PROPERTIES* aProperties = nullptr ); void init( SCHEMATIC* aSchematic, const PROPERTIES* aProperties = nullptr );

View File

@ -131,7 +131,7 @@ std::vector<SYMBOL_ASYNC_LOADER::LOADED_PAIR> SYMBOL_ASYNC_LOADER::worker()
} }
if( m_reporter ) if( m_reporter )
m_reporter->AdvancePhase( wxString::Format( _( "Loading library \"%s\"" ), nickname ) ); m_reporter->AdvancePhase( wxString::Format( _( "Loading library %s..." ), nickname ) );
} }
return ret; return ret;

View File

@ -225,6 +225,9 @@ public:
m_lineNum = 0; m_lineNum = 0;
} }
long int FileLength();
long int CurPos();
protected: protected:
bool m_iOwn; ///< if I own the file, I'll promise to close it, else not. 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. FILE* m_fp; ///< I may own this file, but might not.

View File

@ -665,18 +665,13 @@ int KICAD_MANAGER_CONTROL::ShowPlayer( const TOOL_EVENT& aEvent )
filepath = legacy_board.GetFullPath(); 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( !filepath.IsEmpty() )
{ {
if( !player->OpenProjectFiles( std::vector<wxString>( 1, filepath ) ) ) if( !player->OpenProjectFiles( std::vector<wxString>( 1, filepath ) ) )
return -1; return -1;
} }
player->Show( true );
} }
// Needed on Windows, other platforms do not use it, but it creates no issue // Needed on Windows, other platforms do not use it, but it creates no issue

View File

@ -38,6 +38,7 @@
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <widgets/infobar.h> #include <widgets/infobar.h>
#include <widgets/resettable_panel.h> #include <widgets/resettable_panel.h>
#include <widgets/progress_reporter.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include "dialog_board_setup.h" #include "dialog_board_setup.h"
@ -192,7 +193,10 @@ void DIALOG_BOARD_SETUP::OnAuxiliaryAction( wxCommandEvent& event )
try 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() ) if( importDlg.m_LayersOpt->GetValue() )
{ {

View File

@ -501,7 +501,7 @@ void PANEL_PCBNEW_COLOR_SETTINGS::createPreviewItems()
try try
{ {
pi.DoLoad( reader, m_preview->GetBoard(), nullptr ); pi.DoLoad( reader, m_preview->GetBoard(), nullptr, nullptr, 0 );
} }
catch( const IO_ERROR& ) catch( const IO_ERROR& )
{ {

View File

@ -25,7 +25,6 @@
#include <confirm.h> #include <confirm.h>
#include <core/arraydim.h> #include <core/arraydim.h>
#include <kicad_string.h>
#include <gestfich.h> #include <gestfich.h>
#include <pcb_edit_frame.h> #include <pcb_edit_frame.h>
#include <board_design_settings.h> #include <board_design_settings.h>
@ -48,6 +47,7 @@
#include <kiplatform/app.h> #include <kiplatform/app.h>
#include <widgets/appearance_controls.h> #include <widgets/appearance_controls.h>
#include <widgets/infobar.h> #include <widgets/infobar.h>
#include <widgets/progress_reporter.h>
#include <settings/settings_manager.h> #include <settings/settings_manager.h>
#include <paths.h> #include <paths.h>
#include <project/project_file.h> #include <project/project_file.h>
@ -56,7 +56,6 @@
#include <plugins/cadstar/cadstar_pcb_archive_plugin.h> #include <plugins/cadstar/cadstar_pcb_archive_plugin.h>
#include <plugins/kicad/kicad_plugin.h> #include <plugins/kicad/kicad_plugin.h>
#include <dialogs/dialog_imported_layers.h> #include <dialogs/dialog_imported_layers.h>
#include <tool/tool_manager.h>
#include <tools/pcb_actions.h> #include <tools/pcb_actions.h>
#include "footprint_info_impl.h" #include "footprint_info_impl.h"
#include <wx_filename.h> // For ::ResolvePossibleSymlinks() #include <wx_filename.h> // For ::ResolvePossibleSymlinks()
@ -691,12 +690,13 @@ bool PCB_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
props["page_width"] = xbuf; props["page_width"] = xbuf;
props["page_height"] = ybuf; props["page_height"] = ybuf;
WX_PROGRESS_REPORTER progressReporter( this, _( "Loading PCB" ), 1 );
#if USE_INSTRUMENTATION #if USE_INSTRUMENTATION
// measure the time to load a BOARD. // measure the time to load a BOARD.
unsigned startTime = GetRunningMicroSecs(); unsigned startTime = GetRunningMicroSecs();
#endif #endif
loadedBoard = pi->Load( fullFileName, NULL, &props, &Prj() ); loadedBoard = pi->Load( fullFileName, NULL, &props, &Prj(), &progressReporter );
#if USE_INSTRUMENTATION #if USE_INSTRUMENTATION
unsigned stopTime = GetRunningMicroSecs(); unsigned stopTime = GetRunningMicroSecs();

View File

@ -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, 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. // release the PLUGIN even if an exception is thrown.
PLUGIN::RELEASER pi( PluginFind( aFileType ) ); PLUGIN::RELEASER pi( PluginFind( aFileType ) );
if( (PLUGIN*) pi ) // test pi->plugin 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() ) ); THROW_IO_ERROR( wxString::Format( FMT_NOTFOUND, ShowType( aFileType ).GetData() ) );

View File

@ -37,6 +37,7 @@ class PLUGIN;
class FOOTPRINT; class FOOTPRINT;
class PROPERTIES; class PROPERTIES;
class PROJECT; class PROJECT;
class PROGRESS_REPORTER;
/** /**
* A factory which returns an instance of a #PLUGIN. * A factory which returns an instance of a #PLUGIN.
@ -210,7 +211,8 @@ public:
*/ */
static BOARD* Load( PCB_FILE_T aFileType, const wxString& aFileName, static BOARD* Load( PCB_FILE_T aFileType, const wxString& aFileName,
BOARD* aAppendToMe = nullptr, const PROPERTIES* aProperties = nullptr, 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 * 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. * it to be optionally NULL.
* @param aProject is the optional #PROJECT object primarily used by third party * @param aProject is the optional #PROJECT object primarily used by third party
* importers. * 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 * @return the successfully loaded board, or the same one as \a aAppendToMe if aAppendToMe
* was not NULL, and caller owns it. * was not NULL, and caller owns it.
* *
@ -304,7 +308,8 @@ public:
* possible. * possible.
*/ */
virtual BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, 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 * Return a container with the cached library footprints generated in the last call to

View File

@ -352,7 +352,8 @@ void CLIPBOARD_IO::Save( const wxString& aFileName, BOARD* aBoard,
BOARD* CLIPBOARD_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, 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; std::string result;

View File

@ -59,7 +59,8 @@ public:
BOARD_ITEM* Parse(); BOARD_ITEM* Parse();
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, 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 ); void SetBoard( BOARD* aBoard );

View File

@ -1164,9 +1164,10 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
m_gal->DrawPolygon( outline ); m_gal->DrawPolygon( outline );
} }
else else
{
m_gal->DrawPolygon( poly->Vertices() ); m_gal->DrawPolygon( poly->Vertices() );
}
// Now add on a rounded margin (using segments) if the margin > 0 // Now add on a rounded margin (using segments) if the margin > 0
if( margin.x > 0 ) if( margin.x > 0 )

View File

@ -44,7 +44,7 @@ static void not_implemented( PLUGIN* aPlugin, const char* aCaller )
BOARD* PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, BOARD* PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties,
PROJECT* aProject ) PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter )
{ {
not_implemented( this, __FUNCTION__ ); not_implemented( this, __FUNCTION__ );
return nullptr; return nullptr;

View File

@ -64,7 +64,8 @@ const wxString ALTIUM_CIRCUIT_MAKER_PLUGIN::GetFileExtension() const
BOARD* ALTIUM_CIRCUIT_MAKER_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, 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; m_props = aProperties;

View File

@ -39,7 +39,8 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, 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; const wxString GetFileExtension() const override;

View File

@ -64,7 +64,8 @@ const wxString ALTIUM_CIRCUIT_STUDIO_PLUGIN::GetFileExtension() const
BOARD* ALTIUM_CIRCUIT_STUDIO_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, 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; m_props = aProperties;

View File

@ -39,7 +39,7 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, 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; const wxString GetFileExtension() const override;

View File

@ -64,7 +64,8 @@ const wxString ALTIUM_DESIGNER_PLUGIN::GetFileExtension() const
BOARD* ALTIUM_DESIGNER_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, 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; m_props = aProperties;

View File

@ -41,7 +41,8 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, 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; const wxString GetFileExtension() const override;

View File

@ -106,7 +106,8 @@ std::vector<FOOTPRINT*> CADSTAR_PCB_ARCHIVE_PLUGIN::GetImportedCachedLibraryFoot
BOARD* CADSTAR_PCB_ARCHIVE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, 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_props = aProperties;
m_board = aAppendToMe ? aAppendToMe : new BOARD(); m_board = aAppendToMe ? aAppendToMe : new BOARD();

View File

@ -39,7 +39,8 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, 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; const wxString GetFileExtension() const override;

View File

@ -67,6 +67,7 @@ Load() TODO's
#include <properties.h> #include <properties.h>
#include <trigo.h> #include <trigo.h>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <widgets/progress_reporter.h>
#include <board.h> #include <board.h>
#include <board_design_settings.h> #include <board_design_settings.h>
@ -207,12 +208,14 @@ static void setKeepoutSettingsToZone( ZONE* aZone, LAYER_NUM aLayer )
} }
void ERULES::parse( wxXmlNode* aRules ) void ERULES::parse( wxXmlNode* aRules, std::function<void()> aCheckpoint )
{ {
wxXmlNode* child = aRules->GetChildren(); wxXmlNode* child = aRules->GetChildren();
while( child ) while( child )
{ {
aCheckpoint();
if( child->GetName() == "param" ) if( child->GetName() == "param" )
{ {
const wxString& name = child->GetAttribute( "name" ); const wxString& name = child->GetAttribute( "name" );
@ -273,9 +276,13 @@ void ERULES::parse( wxXmlNode* aRules )
EAGLE_PLUGIN::EAGLE_PLUGIN() : EAGLE_PLUGIN::EAGLE_PLUGIN() :
m_rules( new ERULES() ), m_rules( new ERULES() ),
m_xpath( new XPATH() ), m_xpath( new XPATH() ),
m_mod_time( wxDateTime::Now() ) m_progressReporter( nullptr ),
m_doneCount( 0 ),
m_lastProgressCount( 0 ),
m_totalCount( 0 ),
m_mod_time( wxDateTime::Now() )
{ {
using namespace std::placeholders; using namespace std::placeholders;
@ -305,6 +312,26 @@ const wxString EAGLE_PLUGIN::GetFileExtension() const
return wxT( "brd" ); 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 wxSize inline EAGLE_PLUGIN::kicad_fontz( const ECOORD& d, int aTextThickness ) const
{ {
// Eagle includes stroke thickness in the text size, KiCAD does not // 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, 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. LOCALE_IO toggle; // toggles on, then off, the C locale.
wxXmlNode* doc; wxXmlNode* doc;
@ -322,6 +350,7 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
init( aProperties ); init( aProperties );
m_board = aAppendToMe ? aAppendToMe : new BOARD(); m_board = aAppendToMe ? aAppendToMe : new BOARD();
m_progressReporter = aProgressReporter;
// Give the filename to the board if it's new // Give the filename to the board if it's new
if( !aAppendToMe ) if( !aAppendToMe )
@ -332,6 +361,14 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
try 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; wxFileName fn = aFileName;
// Load the document // Load the document
wxFFileInputStream stream( fn.GetFullPath() ); wxFFileInputStream stream( fn.GetFullPath() );
@ -339,7 +376,7 @@ BOARD* EAGLE_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
if( !stream.IsOk() || !xmlDocument.Load( stream ) ) 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() ) ); fn.GetFullPath() ) );
} }
@ -414,9 +451,7 @@ std::vector<FOOTPRINT*> EAGLE_PLUGIN::GetImportedCachedLibraryFootprints()
std::vector<FOOTPRINT*> retval; std::vector<FOOTPRINT*> retval;
for( std::pair<wxString, FOOTPRINT*> fp : m_templates ) for( std::pair<wxString, FOOTPRINT*> fp : m_templates )
{
retval.push_back( static_cast<FOOTPRINT*>( fp.second->Clone() ) ); retval.push_back( static_cast<FOOTPRINT*>( fp.second->Clone() ) );
}
return retval; return retval;
} }
@ -458,12 +493,53 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
wxXmlNode* board = drawingChildren["board"]; wxXmlNode* board = drawingChildren["board"];
NODE_MAP boardChildren = MapChildren( 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( "eagle.drawing" );
{ {
m_xpath->push( "board" ); m_xpath->push( "board" );
wxXmlNode* designrules = boardChildren["designrules"];
loadDesignRules( designrules ); loadDesignRules( designrules );
m_xpath->pop(); m_xpath->pop();
@ -472,7 +548,6 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
{ {
m_xpath->push( "layers" ); m_xpath->push( "layers" );
wxXmlNode* layers = drawingChildren["layers"];
loadLayerDefs( layers ); loadLayerDefs( layers );
mapEagleLayersToKicad(); mapEagleLayersToKicad();
@ -482,19 +557,12 @@ void EAGLE_PLUGIN::loadAllSections( wxXmlNode* aDoc )
{ {
m_xpath->push( "board" ); m_xpath->push( "board" );
wxXmlNode* plain = boardChildren["plain"];
loadPlain( plain ); loadPlain( plain );
wxXmlNode* signals = boardChildren["signals"];
loadSignals( signals ); loadSignals( signals );
wxXmlNode* libs = boardChildren["libraries"];
loadLibraries( libs ); loadLibraries( libs );
wxXmlNode* elems = boardChildren["elements"];
loadElements( elems ); loadElements( elems );
m_xpath->pop(); // "board" m_xpath->pop();
} }
m_xpath->pop(); // "eagle.drawing" m_xpath->pop(); // "eagle.drawing"
@ -506,7 +574,7 @@ void EAGLE_PLUGIN::loadDesignRules( wxXmlNode* aDesignRules )
if( aDesignRules ) if( aDesignRules )
{ {
m_xpath->push( "designrules" ); m_xpath->push( "designrules" );
m_rules->parse( aDesignRules ); m_rules->parse( aDesignRules, [this](){ checkpoint(); } );
m_xpath->pop(); // "designrules" m_xpath->pop(); // "designrules"
} }
} }
@ -533,9 +601,7 @@ void EAGLE_PLUGIN::loadLayerDefs( wxXmlNode* aLayers )
// find the subset of layers that are copper and active // find the subset of layers that are copper and active
if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) ) if( elayer.number >= 1 && elayer.number <= 16 && ( !elayer.active || *elayer.active ) )
{
cu.push_back( elayer ); cu.push_back( elayer );
}
layerNode = layerNode->GetNext(); 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 ) for( EITER it = cu.begin(); it != cu.end(); ++it, ++ki_layer_count )
{ {
if( ki_layer_count == 0 ) if( ki_layer_count == 0 )
{
m_cu_map[it->number] = F_Cu; m_cu_map[it->number] = F_Cu;
}
else if( ki_layer_count == int( cu.size()-1 ) ) else if( ki_layer_count == int( cu.size()-1 ) )
{
m_cu_map[it->number] = B_Cu; m_cu_map[it->number] = B_Cu;
}
else else
{ {
// some eagle boards do not have contiguous layer number sequences. // 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)* // (polygon | wire | text | circle | rectangle | frame | hole)*
while( gr ) while( gr )
{ {
checkpoint();
wxString grName = gr->GetName(); wxString grName = gr->GetName();
if( grName == "wire" ) if( grName == "wire" )
@ -945,6 +1017,8 @@ void EAGLE_PLUGIN::loadLibrary( wxXmlNode* aLib, const wxString* aLibName )
while( package ) while( package )
{ {
checkpoint();
m_xpath->push( "package", "name" ); m_xpath->push( "package", "name" );
wxString pack_ref = package->GetAttribute( "name" ); wxString pack_ref = package->GetAttribute( "name" );
@ -1018,6 +1092,8 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
while( element ) while( element )
{ {
checkpoint();
if( element->GetName() != "element" ) if( element->GetName() != "element" )
{ {
// Get next item // Get next item
@ -1039,7 +1115,7 @@ void EAGLE_PLUGIN::loadElements( wxXmlNode* aElements )
if( it == m_templates.end() ) 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.package.c_str() ),
FROM_UTF8( e.library.c_str() ) ); FROM_UTF8( e.library.c_str() ) );
THROW_IO_ERROR( emsg ); 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 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(); int diameter = e.diameter->ToPcbUnits();
pad->SetSize( wxSize( diameter, diameter ) ); pad->SetSize( wxSize( diameter, diameter ) );
@ -2148,6 +2224,9 @@ void EAGLE_PLUGIN::packageHole( FOOTPRINT* aFootprint, wxXmlNode* aTree, bool aC
{ {
EHOLE e( aTree ); EHOLE e( aTree );
if( e.drill.value == 0 )
return;
// we add a PAD_ATTRIB::NPTH pad to this footprint. // we add a PAD_ATTRIB::NPTH pad to this footprint.
PAD* pad = new PAD( aFootprint ); PAD* pad = new PAD( aFootprint );
aFootprint->Add( pad ); aFootprint->Add( pad );
@ -2188,7 +2267,7 @@ void EAGLE_PLUGIN::packageSMD( FOOTPRINT* aFootprint, wxXmlNode* aTree ) const
ESMD e( aTree ); ESMD e( aTree );
PCB_LAYER_ID layer = kicad_layer( e.layer ); PCB_LAYER_ID layer = kicad_layer( e.layer );
if( !IsCopperLayer( layer ) ) if( !IsCopperLayer( layer ) || e.dx.value == 0 || e.dy.value == 0 )
return; return;
PAD* pad = new PAD( aFootprint ); PAD* pad = new PAD( aFootprint );
@ -2304,6 +2383,8 @@ void EAGLE_PLUGIN::loadSignals( wxXmlNode* aSignals )
while( net ) while( net )
{ {
checkpoint();
bool sawPad = false; bool sawPad = false;
zones.clear(); zones.clear();
@ -2557,7 +2638,13 @@ void EAGLE_PLUGIN::mapEagleLayersToKicad()
inputDescs.push_back( layerDesc ); inputDescs.push_back( layerDesc );
} }
if( m_progressReporter && dynamic_cast<wxWindow*>( m_progressReporter ) )
dynamic_cast<wxWindow*>( m_progressReporter )->Hide();
m_layer_map = m_layer_mapping_handler( inputDescs ); m_layer_map = m_layer_mapping_handler( inputDescs );
if( m_progressReporter && dynamic_cast<wxWindow*>( m_progressReporter ))
dynamic_cast<wxWindow*>( m_progressReporter )->Show();
} }
PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const PCB_LAYER_ID EAGLE_PLUGIN::kicad_layer( int aEagleLayer ) const

View File

@ -78,7 +78,7 @@ struct ERULES
mdWireWire ( 0 ) mdWireWire ( 0 )
{} {}
void parse( wxXmlNode* aRules ); void parse( wxXmlNode* aRules, std::function<void()> aCheckpoint );
///< percent over 100%. 0-> not elongated, 100->twice as wide as is tall ///< percent over 100%. 0-> not elongated, 100->twice as wide as is tall
///< Goes into making a scaling factor for "long" pads. ///< Goes into making a scaling factor for "long" pads.
@ -131,7 +131,8 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, 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<FOOTPRINT*> GetImportedCachedLibraryFootprints() override; std::vector<FOOTPRINT*> GetImportedCachedLibraryFootprints() override;
@ -176,9 +177,11 @@ public:
private: private:
/// initialize PLUGIN like a constructor would, and futz with fresh BOARD if needed. /// 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. /// Convert an Eagle distance to a KiCad distance.
int kicad_y( const ECOORD& y ) const { return -y.ToPcbUnits(); } 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. 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 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_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_hole; ///< smallest diameter hole we find on Load(), in BIU.
int m_min_via; ///< smallest via we find on Load(), in BIU. int m_min_via; ///< smallest via we find on Load(), in BIU.

View File

@ -59,7 +59,8 @@ const wxString FABMASTER_PLUGIN::GetFileExtension() const
BOARD* FABMASTER_PLUGIN::Load( const wxString &aFileName, BOARD *aAppendToMe, 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; m_props = aProperties;

View File

@ -41,9 +41,11 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* Load( const wxString& aFileName,
BOARD* aAppendToMe, BOARD* aAppendToMe,
const PROPERTIES* aProperties = NULL, PROJECT* aProject = nullptr ) override; const PROPERTIES* aProperties = NULL,
PROJECT* aProject = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
const wxString GetFileExtension() const override; const wxString GetFileExtension() const override;

View File

@ -47,6 +47,7 @@
#include <plugins/kicad/pcb_parser.h> #include <plugins/kicad/pcb_parser.h>
#include <trace_helpers.h> #include <trace_helpers.h>
#include <pcb_track.h> #include <pcb_track.h>
#include <widgets/progress_reporter.h>
#include <wildcards_and_files_ext.h> #include <wildcards_and_files_ext.h>
#include <wx/dir.h> #include <wx/dir.h>
#include <wx/log.h> #include <wx/log.h>
@ -2188,11 +2189,26 @@ PCB_IO::~PCB_IO()
BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties, BOARD* PCB_IO::Load( const wxString& aFileName, BOARD* aAppendToMe, const PROPERTIES* aProperties,
PROJECT* aProject ) PROJECT* aProject, PROGRESS_REPORTER* aProgressReporter )
{ {
FILE_LINE_READER reader( aFileName ); 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 // Give the filename to the board if it's new
if( !aAppendToMe ) 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 ); init( aProperties );
m_parser->SetLineReader( &aReader ); m_parser->SetLineReader( &aReader );
m_parser->SetBoard( aAppendToMe ); m_parser->SetBoard( aAppendToMe );
m_parser->SetProgressReporter( aProgressReporter, &aReader, aLineCount );
BOARD* board; BOARD* board;

View File

@ -153,9 +153,11 @@ public:
const PROPERTIES* aProperties = nullptr ) override; const PROPERTIES* aProperties = nullptr ) override;
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, 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, void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
bool aBestEfforts, const PROPERTIES* aProperties = nullptr ) override; bool aBestEfforts, const PROPERTIES* aProperties = nullptr ) override;

View File

@ -28,13 +28,11 @@
*/ */
#include <cerrno> #include <cerrno>
#include <common.h>
#include <confirm.h> #include <confirm.h>
#include <macros.h> #include <macros.h>
#include <title_block.h> #include <title_block.h>
#include <trigo.h> #include <trigo.h>
#include <advanced_config.h>
#include <board.h> #include <board.h>
#include <board_design_settings.h> #include <board_design_settings.h>
#include <pcb_dimension.h> #include <pcb_dimension.h>
@ -54,10 +52,10 @@
#include <zones.h> #include <zones.h>
#include <plugins/kicad/pcb_parser.h> #include <plugins/kicad/pcb_parser.h>
#include <convert_basic_shapes_to_polygon.h> // for RECT_CHAMFER_POSITIONS definition #include <convert_basic_shapes_to_polygon.h> // for RECT_CHAMFER_POSITIONS definition
#include <template_fieldnames.h>
#include <math/util.h> // KiROUND, Clamp #include <math/util.h> // KiROUND, Clamp
#include <kicad_string.h> #include <kicad_string.h>
#include <wx/log.h> #include <wx/log.h>
#include <widgets/progress_reporter.h>
using namespace PCB_KEYS_T; 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() void PCB_PARSER::skipCurrent()
{ {
int curr_level = 0; int curr_level = 0;
@ -588,6 +607,8 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
for( token = NextTok(); token != T_RIGHT; token = NextTok() ) for( token = NextTok(); token != T_RIGHT; token = NextTok() )
{ {
checkpoint();
if( token != T_LEFT ) if( token != T_LEFT )
Expecting( T_LEFT ); Expecting( T_LEFT );

View File

@ -60,6 +60,7 @@ class PCB_VIA;
class ZONE; class ZONE;
class FP_3DMODEL; class FP_3DMODEL;
struct LAYER; struct LAYER;
class PROGRESS_REPORTER;
/** /**
@ -72,7 +73,11 @@ public:
PCB_PARSER( LINE_READER* aReader = nullptr ) : PCB_PARSER( LINE_READER* aReader = nullptr ) :
PCB_LEXER( aReader ), PCB_LEXER( aReader ),
m_board( nullptr ), m_board( nullptr ),
m_resetKIIDs( false ) m_resetKIIDs( false ),
m_progressReporter( nullptr ),
m_lineReader( nullptr ),
m_lastProgressLine( 0 ),
m_lineCount( 0 )
{ {
init(); init();
} }
@ -101,6 +106,15 @@ public:
m_resetKIIDs = true; 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(); BOARD_ITEM* Parse();
/** /**
@ -154,6 +168,8 @@ private:
*/ */
void init(); void init();
void checkpoint();
/** /**
* Create a mapping from the (short-lived) bug where layer names were translated. * Create a mapping from the (short-lived) bug where layer names were translated.
* *
@ -342,6 +358,11 @@ private:
bool m_showLegacyZoneWarning; 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. // 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 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 // we store info about the group declarations here during parsing and then resolve

View File

@ -88,6 +88,7 @@
#include <trigo.h> #include <trigo.h>
#include <confirm.h> #include <confirm.h>
#include <math/util.h> // for KiROUND #include <math/util.h> // for KiROUND
#include <widgets/progress_reporter.h>
typedef LEGACY_PLUGIN::BIU BIU; 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)) #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;
}
}
}
//-----<BOARD Load Functions>--------------------------------------------------- //-----<BOARD Load Functions>---------------------------------------------------
/// C string compare test for a specific length of characters. /// 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, 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. 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 ); FILE_LINE_READER reader( aFileName );
m_reader = &reader; // member function accessibility m_reader = &reader;
m_progressReporter = aProgressReporter;
checkVersion(); 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 ) ); loadAllSections( bool( aAppendToMe ) );
(void)boardDeleter.release(); // give it up so we dont delete it on exit (void)boardDeleter.release(); // give it up so we dont delete it on exit
m_progressReporter = nullptr;
return m_board; return m_board;
} }
@ -426,6 +467,8 @@ void LEGACY_PLUGIN::loadAllSections( bool doAppend )
while( ( line = READLINE( m_reader ) ) != NULL ) while( ( line = READLINE( m_reader ) ) != NULL )
{ {
checkpoint();
// put the more frequent ones at the top, but realize TRACKs are loaded as a group // put the more frequent ones at the top, but realize TRACKs are loaded as a group
if( TESTLINE( "$MODULE" ) ) if( TESTLINE( "$MODULE" ) )
@ -2200,6 +2243,8 @@ void LEGACY_PLUGIN::loadTrackList( int aStructType )
while( ( line = READLINE( m_reader ) ) != NULL ) while( ( line = READLINE( m_reader ) ) != NULL )
{ {
checkpoint();
// read two lines per loop iteration, each loop is one TRACK or VIA // read two lines per loop iteration, each loop is one TRACK or VIA
// example first line: // example first line:
// e.g. "Po 0 23994 28800 24400 28800 150 -1" for a track // 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_cu_count( 16 ), // for FootprintLoad()
m_board( nullptr ), m_board( nullptr ),
m_props( nullptr ), m_props( nullptr ),
m_progressReporter( nullptr ),
m_lastProgressLine( 0 ),
m_lineCount( 0 ),
m_reader( nullptr ), m_reader( nullptr ),
m_fp( nullptr ), m_fp( nullptr ),
m_cache( nullptr ) m_cache( nullptr )

View File

@ -74,7 +74,8 @@ public:
} }
BOARD* Load( const wxString& aFileName, BOARD* aAppendToMe, 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, void FootprintEnumerate( wxArrayString& aFootprintNames, const wxString& aLibraryPath,
bool aBestEfforts, bool aBestEfforts,
@ -101,6 +102,11 @@ public:
static LSET leg_mask2new( int cu_count, unsigned aMask ); static LSET leg_mask2new( int cu_count, unsigned aMask );
protected: 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, ///< Converts net code using the mapping table if available,
///< otherwise returns unchanged net code ///< otherwise returns unchanged net code
inline int getNetCode( int aNetCode ) inline int getNetCode( int aNetCode )
@ -174,24 +180,25 @@ protected:
void cacheLib( const wxString& aLibraryPath ); void cacheLib( const wxString& aLibraryPath );
protected: protected:
int m_cu_count; int m_cu_count;
wxString m_error; ///< for throwing exceptions wxString m_error; ///< for throwing exceptions
BOARD* m_board; ///< which BOARD, no ownership here BOARD* m_board; ///< which BOARD, no ownership here
const PROPERTIES* m_props; ///< passed via Save() or Load(), no ownership, may be NULL. 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. LINE_READER* m_reader; ///< no ownership here.
FILE* m_fp; ///< no ownership here. FILE* m_fp; ///< no ownership here.
wxString m_field; ///< reused to stuff FOOTPRINT fields. wxString m_field; ///< reused to stuff FOOTPRINT fields.
int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing? int m_loading_format_version; ///< which BOARD_FORMAT_VERSION am I Load()ing?
LP_CACHE* m_cache; LP_CACHE* m_cache;
bool m_showLegacyZoneWarning; bool m_showLegacyZoneWarning;
std::vector<int> m_netCodes; ///< net codes mapping for boards being loaded std::vector<int> 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 );
double biuToDisk; ///< convert from BIUs to disk engineering units double biuToDisk; ///< convert from BIUs to disk engineering units
///< with this scale factor ///< with this scale factor

View File

@ -66,7 +66,8 @@ const wxString PCAD_PLUGIN::GetFileExtension() const
BOARD* PCAD_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe, BOARD* PCAD_PLUGIN::Load( const wxString& aFileName, BOARD* aAppendToMe,
const PROPERTIES* aProperties, PROJECT* aProject ) const PROPERTIES* aProperties, PROJECT* aProject,
PROGRESS_REPORTER* aProgressReporter )
{ {
wxXmlDocument xmlDoc; wxXmlDocument xmlDoc;

View File

@ -40,10 +40,11 @@ public:
const wxString PluginName() const override; const wxString PluginName() const override;
BOARD* Load( const wxString& aFileName, BOARD* Load( const wxString& aFileName,
BOARD* aAppendToMe, BOARD* aAppendToMe,
const PROPERTIES* aProperties = nullptr, const PROPERTIES* aProperties = nullptr,
PROJECT* aProject = nullptr ) override; PROJECT* aProject = nullptr,
PROGRESS_REPORTER* aProgressReporter = nullptr ) override;
const wxString GetFileExtension() const override; const wxString GetFileExtension() const override;

View File

@ -55,6 +55,7 @@
#include <view/view_controls.h> #include <view/view_controls.h>
#include <footprint_viewer_frame.h> #include <footprint_viewer_frame.h>
#include <footprint_edit_frame.h> #include <footprint_edit_frame.h>
#include <widgets/progress_reporter.h>
using namespace std::placeholders; using namespace std::placeholders;
@ -1018,8 +1019,10 @@ int PCB_CONTROL::AppendBoard( PLUGIN& pi, wxString& fileName )
props["page_width"] = xbuf; props["page_width"] = xbuf;
props["page_height"] = ybuf; props["page_height"] = ybuf;
WX_PROGRESS_REPORTER progressReporter( editFrame, _( "Loading PCB" ), 1 );
editFrame->GetDesignSettings().GetNetClasses().Clear(); editFrame->GetDesignSettings().GetNetClasses().Clear();
pi.Load( fileName, brd, &props ); pi.Load( fileName, brd, &props, nullptr, &progressReporter );
} }
catch( const IO_ERROR& ioe ) catch( const IO_ERROR& ioe )
{ {