Symbol library load performance enhancements.

1) Edit Symbol gets similar fix as Place Symbol
2) progress dialog updating reduced to once every 50ms
3) SearchText gets lazy normalization
4) TypeNames get lazy translation
5) default fieldNames get translated a single time per language change

These fixes reduce first-load-time of both Edit Symbol and Place Symbol
by about 2/3, and second-load-time of Edit Symbol to near-instantaneous.
This commit is contained in:
Jeff Young 2018-01-25 23:49:04 +00:00 committed by Wayne Stambaugh
parent 54ebd45749
commit 829c236437
23 changed files with 115 additions and 30 deletions

View File

@ -25,6 +25,7 @@
#include <eda_pattern_match.h>
#include <make_unique.h>
#include <utility>
#include <pgm_base.h>
// Each node gets this lowest score initially, without any matches applied.
@ -114,13 +115,24 @@ CMP_TREE_NODE::CMP_TREE_NODE()
CMP_TREE_NODE_UNIT::CMP_TREE_NODE_UNIT( CMP_TREE_NODE* aParent, int aUnit )
{
static void* locale = nullptr;
static wxString namePrefix;
// Fetching translations can take a surprising amount of time when loading libraries,
// so only do it when necessary.
if( Pgm().GetLocale() != locale )
{
namePrefix = _( "Unit" );
locale = Pgm().GetLocale();
}
Parent = aParent;
Type = UNIT;
Unit = aUnit;
LibId = aParent->LibId;
Name = _( "Unit" ) + " " + LIB_PART::SubReference( aUnit, false );
Name = namePrefix + " " + LIB_PART::SubReference( aUnit, false );
Desc = wxEmptyString;
MatchName = wxEmptyString;
@ -158,7 +170,7 @@ void CMP_TREE_NODE_LIB_ID::Update( LIB_ALIAS* aAlias )
// Search text spaces out keywords and description to penalize description
// matches - earlier matches are worth more.
MatchName = aAlias->GetName().Lower();
SearchText = (aAlias->GetKeyWords() + " " + Desc).Lower();
SearchText = (aAlias->GetKeyWords() + " " + Desc);
// Extract default footprint text
LIB_PART* part = aAlias->GetPart();
@ -177,7 +189,7 @@ void CMP_TREE_NODE_LIB_ID::Update( LIB_ALIAS* aAlias )
if( !footprint.IsEmpty() )
{
SearchText += " ";
SearchText += footprint.Lower();
SearchText += footprint;
}
Children.clear();
@ -195,6 +207,12 @@ void CMP_TREE_NODE_LIB_ID::UpdateScore( EDA_COMBINED_MATCHER& aMatcher )
if( Score <= 0 )
return; // Leaf nodes without scores are out of the game.
if( !SearchTextNormalized )
{
SearchText = SearchText.Lower();
SearchTextNormalized = true;
}
// Keywords and description we only count if the match string is at
// least two characters long. That avoids spurious, low quality
// matches. Most abbreviations are at three characters long.

View File

@ -100,6 +100,8 @@ public:
wxString Desc; ///< Description to be displayed
wxString MatchName; ///< Normalized name for matching
wxString SearchText; ///< Descriptive text to search
bool SearchTextNormalized; ///< Support for lazy normalization.
LIB_ID LibId; ///< LIB_ID determined by the parent library nickname and alias name.
int Unit; ///< Actual unit, or zero

View File

@ -92,7 +92,6 @@ LIB_ARC::LIB_ARC( LIB_PART* aParent ) : LIB_ITEM( LIB_ARC_T, aParent )
m_Width = 0;
m_Fill = NO_FILL;
m_isFillable = true;
m_typeName = _( "Arc" );
m_editState = 0;
m_lastEditState = 0;
m_editCenterDistance = 0.0;

View File

@ -91,6 +91,11 @@ public:
return wxT( "LIB_ARC" );
}
wxString GetTypeName() override
{
return _( "Arc" );
}
bool HitTest( const wxPoint& aPosition ) const override;
bool HitTest( const wxPoint& aPosition, int aThreshold, const TRANSFORM& aTransform ) const override;

View File

@ -47,7 +47,6 @@ LIB_BEZIER::LIB_BEZIER( LIB_PART* aParent ) :
m_Fill = NO_FILL;
m_Width = 0;
m_isFillable = true;
m_typeName = _( "Bezier" );
}

View File

@ -58,6 +58,10 @@ public:
return wxT( "LIB_BEZIER" );
}
wxString GetTypeName() override
{
return _( "Bezier" );
}
void AddPoint( const wxPoint& aPoint ) { m_BezierPoints.push_back( aPoint ); }

View File

@ -50,7 +50,6 @@ LIB_CIRCLE::LIB_CIRCLE( LIB_PART* aParent ) :
m_Width = 0;
m_Fill = NO_FILL;
m_isFillable = true;
m_typeName = _( "Circle" );
}

View File

@ -56,6 +56,10 @@ public:
return wxT( "LIB_CIRCLE" );
}
wxString GetTypeName() override
{
return _( "Circle" );
}
bool HitTest( const wxPoint& aPosition ) const override;

View File

@ -52,7 +52,6 @@ LIB_ITEM::LIB_ITEM( KICAD_T aType,
m_Convert = aConvert;
m_Fill = aFillType;
m_Parent = (EDA_ITEM*) aComponent;
m_typeName = _( "Undefined" );
m_isFillable = false;
m_eraseLastDrawItem = false;
}
@ -62,7 +61,7 @@ void LIB_ITEM::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList )
{
wxString msg;
aList.push_back( MSG_PANEL_ITEM( _( "Type" ), m_typeName, CYAN ) );
aList.push_back( MSG_PANEL_ITEM( _( "Type" ), GetTypeName(), CYAN ) );
if( m_Unit == 0 )
msg = _( "All" );

View File

@ -128,8 +128,6 @@ protected:
*/
FILL_T m_Fill;
wxString m_typeName; ///< Name of object displayed in the message panel.
wxPoint m_initialPos; ///< Temporary position when moving an existing item.
wxPoint m_initialCursorPos; ///< Initial cursor position at the beginning of a move.
@ -148,7 +146,11 @@ public:
virtual ~LIB_ITEM() { }
wxString GetTypeName() { return m_typeName; }
/**
* Provide a user-consumable name of the object type. Perform localization when
* called so that run-time language selection works.
*/
virtual wxString GetTypeName() = 0;
/**
* Begin an editing a component library draw item in \a aEditMode at \a aPosition.

View File

@ -84,8 +84,6 @@ void LIB_FIELD::Init( int id )
SetTextWidth( GetDefaultTextSize() );
SetTextHeight( GetDefaultTextSize() );
m_typeName = _( "Field" );
SetTextAngle( TEXT_ANGLE_HORIZ ); // constructor already did this.
m_rotate = false;

View File

@ -100,6 +100,11 @@ public:
return wxT( "LIB_FIELD" );
}
wxString GetTypeName() override
{
return _( "Field" );
}
/**
* Object constructor initialization helper.
*/

View File

@ -288,14 +288,15 @@ std::list<LIB_ALIAS*> LIB_MANAGER::GetAliases( const wxString& aLibrary ) const
}
else
{
wxArrayString symbols;
std::vector<LIB_ALIAS*> aliases;
try {
symTable()->EnumerateSymbolLib( aLibrary, symbols );
try
{
symTable()->LoadSymbolLib( aliases, aLibrary );
}
catch( IO_ERROR& ) {}
for( const auto& symbol : symbols )
ret.push_back( symTable()->LoadSymbol( aLibrary, symbol ) );
} catch( IO_ERROR& e ) {}
std::copy( aliases.begin(), aliases.end(), std::back_inserter( ret ) );
}
return ret;

View File

@ -54,8 +54,12 @@ bool LIB_MANAGER_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const
}
#define PROGRESS_INTERVAL_MILLIS 50
void LIB_MANAGER_ADAPTER::Sync( bool aForce, std::function<void(int, int, const wxString&)> aProgressCallback )
{
wxLongLong nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
int libMgrHash = m_libMgr->GetHash();
if( !aForce && m_lastSyncHash == libMgrHash )
@ -68,7 +72,12 @@ void LIB_MANAGER_ADAPTER::Sync( bool aForce, std::function<void(int, int, const
for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); /* iteration inside */ )
{
const wxString& name = it->get()->Name;
aProgressCallback( i++, max, name );
if( wxGetUTCTimeMillis() > nextUpdate )
{
aProgressCallback( i++, max, name );
nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
}
if( !m_libMgr->LibraryExists( name ) )
{
@ -88,7 +97,12 @@ void LIB_MANAGER_ADAPTER::Sync( bool aForce, std::function<void(int, int, const
{
if( m_libHashes.count( libName ) == 0 )
{
aProgressCallback( i++, max, libName );
if( wxGetUTCTimeMillis() > nextUpdate )
{
aProgressCallback( i++, max, libName );
nextUpdate = wxGetUTCTimeMillis() + PROGRESS_INTERVAL_MILLIS;
}
auto& lib_node = m_tree.AddLib( libName );
updateLibrary( lib_node );
m_tree.AssignIntrinsicRanks();

View File

@ -154,7 +154,6 @@ LIB_PIN::LIB_PIN( LIB_PART* aParent ) :
m_numTextSize = LIB_EDIT_FRAME::GetPinNumDefaultSize();
m_nameTextSize = LIB_EDIT_FRAME::GetPinNameDefaultSize();
m_width = 0;
m_typeName = _( "Pin" );
}

View File

@ -110,6 +110,11 @@ public:
return wxT( "LIB_PIN" );
}
wxString GetTypeName() override
{
return _( "Pin" );
}
#if defined(DEBUG)
void Show( int nestLevel, std::ostream& os ) const override;
#endif

View File

@ -48,7 +48,6 @@ LIB_POLYLINE::LIB_POLYLINE( LIB_PART* aParent ) :
m_Fill = NO_FILL;
m_Width = 0;
m_isFillable = true;
m_typeName = _( "PolyLine" );
m_ModifyIndex = 0;
}

View File

@ -57,6 +57,10 @@ public:
return wxT( "LIB_POLYLINE" );
}
wxString GetTypeName() override
{
return _( "PolyLine" );
}
void AddPoint( const wxPoint& aPoint );

View File

@ -48,7 +48,6 @@ LIB_RECTANGLE::LIB_RECTANGLE( LIB_PART* aParent ) :
m_Width = 0;
m_Fill = NO_FILL;
m_isFillable = true;
m_typeName = _( "Rectangle" );
m_isHeightLocked = false;
m_isWidthLocked = false;
m_isStartPointSelected = false;

View File

@ -59,6 +59,11 @@ public:
return wxT( "LIB_RECTANGLE" );
}
wxString GetTypeName() override
{
return _( "Rectangle" );
}
void SetEndPosition( const wxPoint& aPosition ) { m_End = aPosition; }
bool HitTest( const wxPoint& aPosition ) const override;

View File

@ -48,7 +48,6 @@ LIB_TEXT::LIB_TEXT( LIB_PART * aParent ) :
EDA_TEXT()
{
SetTextSize( wxSize( 50, 50 ) );
m_typeName = _( "Text" );
m_rotate = false;
m_updateText = false;
}

View File

@ -65,6 +65,11 @@ public:
return wxT( "LIB_TEXT" );
}
wxString GetTypeName() override
{
return _( "Text" );
}
/**
* Sets the text item string to \a aText.
*

View File

@ -26,33 +26,54 @@
#include <dsnlexer.h>
#include <fctsys.h>
#include <macros.h>
#include <pgm_base.h>
using namespace TFIELD_T;
const wxString TEMPLATE_FIELDNAME::GetDefaultFieldName( int aFieldNdx )
{
static void* locale = nullptr;
static wxString referenceDefault;
static wxString valueDefault;
static wxString footprintDefault;
static wxString datasheetDefault;
static wxString fieldDefault;
// Fetching translations can take a surprising amount of time when loading libraries,
// so only do it when necessary.
if( Pgm().GetLocale() != locale )
{
referenceDefault = _( "Reference" );
valueDefault = _( "Value" );
footprintDefault = _( "Footprint" );
datasheetDefault = _( "Datasheet" );
fieldDefault = _( "Field" );
locale = Pgm().GetLocale();
}
// Fixed values for the first few default fields used by EESCHEMA
// (mandatory fields)
switch( aFieldNdx )
{
case REFERENCE:
return _( "Reference" ); // The component reference, R1, C1, etc.
return referenceDefault; // The component reference, R1, C1, etc.
case VALUE:
return _( "Value" ); // The component value + name
return valueDefault; // The component value + name
case FOOTPRINT:
return _( "Footprint" ); // The footprint for use with Pcbnew
return footprintDefault; // The footprint for use with Pcbnew
case DATASHEET:
return _( "Datasheet" ); // Link to a datasheet for component
return datasheetDefault; // Link to a datasheet for component
default:
break;
}
// Other fields are use fields, give a default name:
wxString fieldName = _( "Field" );
wxString fieldName = fieldDefault;
fieldName << aFieldNdx;
return fieldName;
}