Cache project text vars as properties in the PCB board file.

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

Fixes https://gitlab.com/kicad/code/kicad/issues/5005
This commit is contained in:
Jeff Young 2020-08-19 19:21:24 +01:00
parent b9c50c893c
commit 27b047ab3f
11 changed files with 123 additions and 117 deletions

View File

@ -381,7 +381,8 @@ enum Bracket
wxString ExpandTextVars( const wxString& aSource,
const std::function<bool( wxString* )>* aLocalResolver,
const PROJECT* aProject )
const PROJECT* aProject,
const std::function<bool( wxString* )>* aFallbackResolver )
{
wxString newbuf;
size_t sourceLen = aSource.length();
@ -413,6 +414,10 @@ wxString ExpandTextVars( const wxString& aSource,
{
newbuf.append( token );
}
else if( aFallbackResolver && (*aFallbackResolver)( &token ) )
{
newbuf.append( token );
}
else
{
// Token not resolved: leave the reference unchanged

View File

@ -330,7 +330,8 @@ const wxString ExpandEnvVarSubstitutions( const wxString& aString, PROJECT* aPro
*/
wxString ExpandTextVars( const wxString& aSource,
const std::function<bool( wxString* )>* aLocalResolver,
const PROJECT* aProject );
const PROJECT* aProject,
const std::function<bool( wxString* )>* aFallbackResolver = nullptr );
/**
* Replace any environment and/or text variables in file-path uris (leaving network-path URIs

View File

@ -68,9 +68,6 @@ BOARD::BOARD() :
// we have not loaded a board yet, assume latest until then.
m_fileFormatVersionAtLoad = LEGACY_BOARD_FILE_VERSION;
m_CurrentZoneContour = NULL; // This ZONE_CONTAINER handle the
// zone contour currently in progress
for( LAYER_NUM layer = 0; layer < PCB_LAYER_ID_COUNT; ++layer )
{
m_Layer[layer].m_name = GetStandardLayerName( ToLAYER_ID( layer ) );
@ -133,9 +130,6 @@ BOARD::~BOARD()
m_drawings.clear();
delete m_CurrentZoneContour;
m_CurrentZoneContour = NULL;
m_groups.clear();
}
@ -191,6 +185,18 @@ void BOARD::ClearProject()
}
bool BOARD::ResolveTextVar( wxString* token, int aDepth ) const
{
if( m_properties.count( *token ) )
{
*token = m_properties.at( *token );
return true;
}
return false;
}
wxPoint BOARD::GetPosition() const
{
return ZeroOffset;
@ -1300,6 +1306,13 @@ std::vector<wxString> BOARD::GetNetClassAssignmentCandidates()
}
void BOARD::SynchronizeProperties()
{
if( m_project )
SetProperties( m_project->GetTextVars() );
}
void BOARD::SynchronizeNetsAndNetClasses()
{
if( m_project )

View File

@ -25,23 +25,17 @@
#ifndef CLASS_BOARD_H_
#define CLASS_BOARD_H_
#include <tuple>
#include <board_design_settings.h>
#include <board_item_container.h>
#include <class_pcb_group.h>
#include <class_module.h>
#include <class_pad.h>
#include <common.h> // PAGE_INFO
#include <eda_rect.h>
#include <layers_id_colors_and_visibility.h>
#include <netinfo.h>
#include <pcb_plot_params.h>
#include <title_block.h>
#include <zone_settings.h>
#include <tools/pcbnew_selection.h>
#include <memory>
class BOARD_COMMIT;
class PCB_BASE_FRAME;
class PCB_EDIT_FRAME;
@ -186,25 +180,12 @@ class BOARD : public BOARD_ITEM_CONTAINER
friend class PCB_EDIT_FRAME;
private:
/// the board filename
wxString m_fileName;
/// MARKER_PCBs for clearance problems, owned by pointer.
MARKERS m_markers;
/// BOARD_ITEMs for drawings on the board, owned by pointer.
DRAWINGS m_drawings;
/// MODULES for components on the board, owned by pointer.
MODULES m_modules;
/// TRACKS for traces on the board, owned by pointer.
TRACKS m_tracks;
/// GROUPS for groups on the board, owned by pointer.
GROUPS m_groups;
/// edge zone descriptors, owned by pointer.
ZONE_CONTAINERS m_ZoneDescriptorList;
LAYER m_Layer[PCB_LAYER_ID_COUNT];
@ -215,7 +196,8 @@ private:
int m_fileFormatVersionAtLoad; // the version loaded from the file
std::shared_ptr<CONNECTIVITY_DATA> m_connectivity;
std::map<wxString, wxString> m_properties;
std::shared_ptr<CONNECTIVITY_DATA> m_connectivity;
PAGE_INFO m_paper;
TITLE_BLOCK m_titles; // text in lower right of screen and plots
@ -261,38 +243,17 @@ public:
const wxString &GetFileName() const { return m_fileName; }
TRACKS& Tracks()
{
return m_tracks;
}
const TRACKS& Tracks() const
{
return m_tracks;
}
TRACKS& Tracks() { return m_tracks; }
const TRACKS& Tracks() const { return m_tracks; }
MODULES& Modules()
{
return m_modules;
}
const MODULES& Modules() const
{
return m_modules;
}
MODULES& Modules() { return m_modules; }
const MODULES& Modules() const { return m_modules; }
DRAWINGS& Drawings()
{
return m_drawings;
}
DRAWINGS& Drawings() { return m_drawings; }
ZONE_CONTAINERS& Zones()
{
return m_ZoneDescriptorList;
}
ZONE_CONTAINERS& Zones() { return m_ZoneDescriptorList; }
MARKERS& Markers()
{
return m_markers;
}
MARKERS& Markers() { return m_markers; }
/**
* The groups must maintain the folowing invariants. These are checked by
@ -302,15 +263,14 @@ public:
* - If a group specifies a name, it must be unique
* - The graph of groups contianing subgroups must be acyclic.
*/
GROUPS& Groups()
{
return m_groups;
}
GROUPS& Groups() { return m_groups; }
const std::vector<BOARD_CONNECTED_ITEM*> AllConnectedItems();
/// zone contour currently in progress
ZONE_CONTAINER* m_CurrentZoneContour;
const std::map<wxString, wxString>& GetProperties() const { return m_properties; }
void SetProperties( const std::map<wxString, wxString>& aProps ) { m_properties = aProps; }
bool ResolveTextVar( wxString* token, int aDepth ) const;
/// Visibility settings stored in board prior to 6.0, only used for loading legacy files
LSET m_LegacyVisibleLayers;
@ -885,8 +845,11 @@ public:
*/
void SynchronizeNetsAndNetClasses();
/***************************************************************************/
/**
* Function SynchronizeProperties
* copies the current project's text variables into the boards property cache.
*/
void SynchronizeProperties();
wxString GetClass() const override
{

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
* Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -23,21 +23,11 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
/**
* @file class_pcb_text.cpp
* @brief Class TEXTE_PCB texts on copper or technical layers implementation
*/
#include <fctsys.h>
#include <gr_basic.h>
#include <base_struct.h>
#include <gr_text.h>
#include <pcb_edit_frame.h>
#include <base_units.h>
#include <bitmaps.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <class_board.h>
#include <class_pcb_text.h>
#include <pcb_painter.h>
@ -92,11 +82,17 @@ wxString TEXTE_PCB::GetShownText( int aDepth ) const
return false;
};
std::function<bool( wxString* )> boardTextResolver =
[&]( wxString* token ) -> bool
{
return board->ResolveTextVar( token, aDepth + 1 );
};
bool processTextVars = false;
wxString text = EDA_TEXT::GetShownText( &processTextVars );
if( processTextVars && aDepth < 10 )
text = ExpandTextVars( text, &pcbTextResolver, board->GetProject() );
text = ExpandTextVars( text, &pcbTextResolver, board->GetProject(), &boardTextResolver );
return text;
}

View File

@ -24,15 +24,11 @@
*/
#include <fctsys.h>
#include <gr_text.h>
#include <kicad_string.h>
#include <pcb_edit_frame.h>
#include <base_units.h>
#include <bitmaps.h>
#include <class_board.h>
#include <class_module.h>
#include <view/view.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
TEXTE_MODULE::TEXTE_MODULE( MODULE* parent, TEXT_TYPE text_type ) :
@ -428,6 +424,7 @@ wxString TEXTE_MODULE::GetShownText( int aDepth ) const
{
const MODULE* module = static_cast<MODULE*>( GetParent() );
wxASSERT( module );
const BOARD* board = module->GetBoard();
std::function<bool( wxString* )> moduleResolver =
[&]( wxString* token ) -> bool
@ -435,6 +432,12 @@ wxString TEXTE_MODULE::GetShownText( int aDepth ) const
return module && module->ResolveTextVar( token, aDepth );
};
std::function<bool( wxString* )> boardTextResolver =
[&]( wxString* token ) -> bool
{
return board->ResolveTextVar( token, aDepth + 1 );
};
bool processTextVars = false;
wxString text = EDA_TEXT::GetShownText( &processTextVars );
@ -446,7 +449,7 @@ wxString TEXTE_MODULE::GetShownText( int aDepth ) const
project = static_cast<BOARD*>( module->GetParent() )->GetProject();
if( aDepth < 10 )
text = ExpandTextVars( text, &moduleResolver, project );
text = ExpandTextVars( text, &moduleResolver, project, &boardTextResolver );
}
return text;

View File

@ -335,8 +335,8 @@ bool PCB_EDIT_FRAME::Files_io_from_id( int id )
{
bool addToHistory = false;
wxString orig_name;
wxFileName::SplitPath( GetBoard()->GetFileName(),
nullptr, nullptr, &orig_name, nullptr );
wxFileName::SplitPath( GetBoard()->GetFileName(), nullptr, nullptr, &orig_name,
nullptr );
if( orig_name.IsEmpty() )
{
@ -706,9 +706,12 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool addToHistory,
// TODO: this will break if we ever go multi-board
wxFileName projectFile( pcbFileName );
projectFile.SetExt( ProjectFileExtension );
bool projectFileExists = false;
if( aChangeProject && !projectFile.FileExists() )
projectFile.SetExt( ProjectFileExtension );
projectFileExists = projectFile.FileExists();
if( aChangeProject && !projectFileExists )
{
// If this is a new board, project filename won't be set yet
if( projectFile.GetFullPath() != Prj().GetProjectFullName() )
@ -720,11 +723,17 @@ bool PCB_EDIT_FRAME::SavePcbFile( const wxString& aFileName, bool addToHistory,
mgr->SaveProject( Prj().GetProjectFullName() );
mgr->UnloadProject( &Prj() );
mgr->LoadProject( projectFile.GetFullPath() );
// If no project to load then initialize project text vars with board properties
if( !mgr->LoadProject( projectFile.GetFullPath() ) )
Prj().GetTextVars() = GetBoard()->GetProperties();
GetBoard()->SetProject( &Prj() );
}
}
if( projectFileExists )
GetBoard()->SynchronizeProperties();
wxFileName tempFile( aFileName );
tempFile.SetName( wxT( "." ) + tempFile.GetName() );
tempFile.SetExt( tempFile.GetExt() + wxT( "$" ) );

View File

@ -23,11 +23,8 @@
*/
#include <fctsys.h>
#include <common.h>
#include <build_version.h> // LEGACY_BOARD_FILE_VERSION
#include <macros.h>
#include <wildcards_and_files_ext.h>
#include <advanced_config.h>
#include <base_units.h>
#include <trace_helpers.h>
@ -45,34 +42,13 @@
#include <kicad_plugin.h>
#include <pcb_parser.h>
#include <pcbnew_settings.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/wfstream.h>
#include <boost/ptr_container/ptr_map.hpp>
#include <memory.h>
#include <connectivity/connectivity_data.h>
#include <convert_basic_shapes_to_polygon.h> // for enum RECT_CHAMFER_POSITIONS definition
#include <kiface_i.h>
using namespace PCB_KEYS_T;
///> Removes empty nets (i.e. with node count equal zero) from net classes
void filterNetClass( const BOARD& aBoard, NETCLASS& aNetClass )
{
auto connectivity = aBoard.GetConnectivity();
for( NETCLASS::iterator it = aNetClass.begin(); it != aNetClass.end(); )
{
NETINFO_ITEM* netinfo = aBoard.FindNet( *it );
if( netinfo && connectivity->GetNodeCount( netinfo->GetNet() ) <= 0 ) // hopefully there are no nets with negative
aNetClass.Remove( it++ ); // node count, but you never know..
else
++it;
}
}
/**
* FP_CACHE_ITEM
* is helper class for creating a footprint library cache.
@ -606,6 +582,19 @@ void PCB_IO::formatNetInformation( BOARD* aBoard, int aNestLevel ) const
}
void PCB_IO::formatProperties( BOARD* aBoard, int aNestLevel ) const
{
for( const std::pair<const wxString, wxString>& prop : aBoard->GetProperties() )
{
m_out->Print( aNestLevel+1, "(property %s %s)\n",
m_out->Quotew( prop.first ).c_str(),
m_out->Quotew( prop.second ).c_str() );
}
m_out->Print( 0, "\n" );
}
void PCB_IO::formatHeader( BOARD* aBoard, int aNestLevel ) const
{
formatGeneral( aBoard, aNestLevel );
@ -615,13 +604,16 @@ void PCB_IO::formatHeader( BOARD* aBoard, int aNestLevel ) const
// Setup
formatSetup( aBoard, aNestLevel );
// Properties
formatProperties( aBoard, aNestLevel );
// Save net codes and names
formatNetInformation( aBoard, aNestLevel );
}
void PCB_IO::format( BOARD* aBoard, int aNestLevel ) const
{
std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_modules( aBoard->Modules().begin(),
aBoard->Modules().end() );
std::set<BOARD_ITEM*, BOARD_ITEM::ptr_cmp> sorted_drawings( aBoard->Drawings().begin(),

View File

@ -78,7 +78,8 @@ class TEXTE_PCB;
//#define SEXPR_BOARD_FILE_VERSION 20200808 // Add properties to modules
//#define SEXPR_BOARD_FILE_VERSION 20200809 // Add REMOVE_UNUSED_LAYERS option to vias and THT pads
//#define SEXPR_BOARD_FILE_VERSION 20200811 // Add groups
#define SEXPR_BOARD_FILE_VERSION 20200818 // Remove Status flag bitmap and setup counts
//#define SEXPR_BOARD_FILE_VERSION 20200818 // Remove Status flag bitmap and setup counts
#define SEXPR_BOARD_FILE_VERSION 20200819 // Add board-level properties
#define CTL_STD_LAYER_NAMES (1 << 0) ///< Use English Standard layer names
#define CTL_OMIT_NETS (1 << 1) ///< Omit pads net names (useless in library)
@ -235,6 +236,9 @@ protected:
/// formats the Nets and Netclasses
void formatNetInformation( BOARD* aBoard, int aNestLevel = 0 ) const;
/// formats the Nets and Netclasses
void formatProperties( BOARD* aBoard, int aNestLevel = 0 ) const;
/// writes everything that comes before the board_items, like settings and layers etc
void formatHeader( BOARD* aBoard, int aNestLevel = 0 ) const;

View File

@ -249,6 +249,21 @@ void PCB_PARSER::parseXY( int* aX, int* aY )
}
std::pair<wxString, wxString> PCB_PARSER::parseProperty()
{
wxString pName;
wxString pValue;
NeedSYMBOL();
pName = FromUTF8();
NeedSYMBOL();
pValue = FromUTF8();
NeedRIGHT();
return { pName, pValue };
}
void PCB_PARSER::parseEDA_TEXT( EDA_TEXT* aText )
{
wxCHECK_RET( CurTok() == T_effects,
@ -524,6 +539,7 @@ BOARD* PCB_PARSER::parseBOARD()
BOARD* PCB_PARSER::parseBOARD_unchecked()
{
T token;
std::map<wxString, wxString> properties;
parseHeader();
@ -559,6 +575,10 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
parseSetup();
break;
case T_property:
properties.insert( parseProperty() );
break;
case T_net:
parseNETINFO_ITEM();
break;
@ -620,6 +640,8 @@ BOARD* PCB_PARSER::parseBOARD_unchecked()
}
}
m_board->SetProperties( properties );
if( m_undefinedLayers.size() > 0 )
{
bool deleteItems;
@ -2603,11 +2625,7 @@ MODULE* PCB_PARSER::parseMODULE_unchecked( wxArrayString* aInitialComments )
break;
case T_property:
NeedSYMBOL();
name = FromUTF8();
NeedSYMBOL();
properties[ name ] = FromUTF8();
NeedRIGHT();
properties.insert( parseProperty() );
break;
case T_path:

View File

@ -238,6 +238,8 @@ class PCB_PARSER : public PCB_LEXER
void parseXY( int* aX, int* aY );
std::pair<wxString, wxString> parseProperty();
/**
* Function parseEDA_TEXT
* parses the common settings for any object derived from #EDA_TEXT.