Revise symbol rescuer to support symbol library table.

Refactor rescue objects so that they can support derivation.

Factor out legacy rescuer code to perform legacy project rescues.

Create new symbol library table rescuer for rescuing symbol library table
based projects.

Perform the correct rescue type on project load.

Add symbol library table remapping support to the tools menu for run on
demand as applicable.

Add flag to SCH_SCREENS::UpdateSymbolLinks() to allow forcing the symbol
link updates when the library modification hash has not changed.
This commit is contained in:
Wayne Stambaugh 2017-10-21 20:48:25 -04:00
parent 36f6d4a1f4
commit c1f7c1778a
19 changed files with 961 additions and 558 deletions

View File

@ -444,9 +444,6 @@ LIB_ALIAS* PART_LIBS::FindLibraryAlias( const LIB_ID& aLibId, const wxString& aL
}
/* searches all libraries in the list for an entry, using a case insensitive comparison.
* Used to find an entry, when the normal (case sensitive) search fails.
*/
void PART_LIBS::FindLibraryNearEntries( std::vector<LIB_ALIAS*>& aCandidates,
const wxString& aEntryName,
const wxString& aLibraryName )

View File

@ -196,15 +196,18 @@ public:
void Place( SCH_EDIT_FRAME* frame, wxDC* DC ) { };
/**
* Function CheckComponentsToPartsLink
* initializes or reinitializes the weak reference
* to the LIB_PART for each SCH_COMPONENT found in m_drawList.
* Initialize or reinitialize the weak reference to the #LIB_PART for each #SCH_COMPONENT
* found in m_drawList.
*
* It must be called from:
* - Draw function
* - when loading a schematic file
* - before creating a netlist (in case a library is modified)
* - whenever a symbol library is modified
*
* @param aForce true forces a refresh even if the library modification has hasn't changed.
*/
void CheckComponentsToPartsLinks();
void UpdateSymbolLinks( bool aForce = false );
/**
* Function Draw
@ -588,11 +591,12 @@ public:
* found in the full schematic.
*
* It must be called from:
* - Draw function
* - draw functions
* - when loading a schematic file
* - before creating a netlist (in case a library is modified)
* - whenever any of the libraries are modified.
*/
void UpdateSymbolLinks();
void UpdateSymbolLinks( bool aForce = false );
void TestDanglingEnds();

View File

@ -1215,7 +1215,7 @@ void DIALOG_EDIT_COMPONENT_IN_SCHEMATIC::UpdateFields( wxCommandEvent& event )
SCH_COMPONENT copy( *m_cmp );
std::list<SCH_COMPONENT*> components;
components.push_back( &copy );
InvokeDialogUpdateFields( m_parent, components, false );
InvokeDialogUpdateFields( GetParent(), components, false );
// Copy fields from the modified component copy to the dialog buffer
m_FieldsBuf.clear();

View File

@ -38,9 +38,10 @@ class DIALOG_RESCUE_EACH: public DIALOG_RESCUE_EACH_BASE
{
public:
/**
* Constructor
* This dialog asks the user which rescuable, cached parts he wants to rescue.
*
* Any rejects will be pruned from aCandidates.
*
* @param aParent - the SCH_EDIT_FRAME calling this
* @param aRescuer - the active RESCUER instance
* @param aAskShowAgain - if true, a "Never Show Again" button will be included
@ -81,7 +82,7 @@ DIALOG_RESCUE_EACH::DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, RESCUER& aRescu
// Set the info message, customized to include the proper suffix.
wxString info_message =
_( "It looks like this project was made using older schematic component libraries.\n"
_( "It looks like this project was made using older schematic symbol libraries.\n"
"Some parts may need to be relinked to a different symbol name, and some symbols\n"
"may need to be \"rescued\" (cloned and renamed) into a new library.\n"
"\n"
@ -157,6 +158,7 @@ void DIALOG_RESCUE_EACH::PopulateInstanceList()
wxVector<wxVariant> data;
int count = 0;
for( SCH_COMPONENT* each_component : *m_Rescuer->GetComponents() )
{
if( each_component->GetLibId().Format() != UTF8( selected_part.GetRequestedName() ) )
@ -290,9 +292,9 @@ void DIALOG_RESCUE_EACH::OnNeverShowClick( wxCommandEvent& aEvent )
wxMessageDialog dlg( m_Parent,
_( "Stop showing this tool?\n"
"No changes will be made.\n\n"
"This setting can be changed from the \"Component Libraries\" dialog,\n"
"This setting can be changed from the \"Symbol Libraries\" dialog,\n"
"and the tool can be activated manually from the \"Tools\" menu." ),
_( "Rescue Components" ), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
_( "Rescue Symbolss" ), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION );
int resp = dlg.ShowModal ();
if( resp == wxID_YES )

View File

@ -237,7 +237,7 @@ void DIALOG_SYMBOL_REMAP::remapSymbolsToLibTable( REPORTER& aReporter )
}
aReporter.Report( _( "Symbol library table mapping complete!" ), REPORTER::RPT_INFO );
schematic.UpdateSymbolLinks();
schematic.UpdateSymbolLinks( true );
}

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2008-2017 KiCad Developers, see change_log.txt for contributors.
*
* This program is free software; you can redistribute it and/or
@ -65,6 +65,7 @@ enum id_eeschema_frm
/* Schematic editor main menubar IDs. */
ID_RESCUE_CACHED,
ID_EDIT_SYM_LIB_TABLE,
ID_REMAP_SYMBOLS,
/* Schematic editor horizontal toolbar IDs */
ID_HIERARCHY,

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2013-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2013 CERN (www.cern.ch)
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
*
@ -329,22 +329,16 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
UpdateFileHistory( fullFileName );
// Check to see whether some old library parts need to be rescued
// Only do this if RescueNeverShow was not set.
wxConfigBase *config = Kiface().KifaceSettings();
bool rescueNeverShow = false;
config->Read( RescueNeverShowEntry, &rescueNeverShow, false );
if( !rescueNeverShow )
{
RescueProject( false );
}
SCH_SCREENS schematic;
// Convert old projects over to use symbol library table.
if( schematic.HasNoFullyDefinedLibIds() )
{
// Ignore the never show rescue setting for one last rescue of legacy symbol
// libraries before remapping to the symbol library table. This ensures the
// best remapping results.
RescueLegacyProject( false );
// Make backups of current schematics just in case something goes wrong.
for( SCH_SCREEN* screen = schematic.GetFirst(); screen; screen = schematic.GetNext() )
SaveEEFile( screen, false, CREATE_BACKUP_FILE );
@ -353,6 +347,17 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
dlgRemap.ShowQuasiModal();
}
else
{
// Check to see whether some old library parts need to be rescued
// Only do this if RescueNeverShow was not set.
wxConfigBase *config = Kiface().KifaceSettings();
bool rescueNeverShow = false;
config->Read( RescueNeverShowEntry, &rescueNeverShow, false );
if( !rescueNeverShow )
RescueSymbolLibTableProject( false );
}
schematic.UpdateSymbolLinks(); // Update all symbol library links for all sheets.
GetScreen()->TestDanglingEnds(); // Only perform the dangling end test on root sheet.

View File

@ -108,6 +108,7 @@ bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
DisplayError( this, msg );
return false;
}
}
if( part )
{
@ -116,7 +117,6 @@ bool SCH_EDIT_FRAME::CreateArchiveLibrary( const wxString& aFileName )
}
}
}
}
try
{

View File

@ -274,7 +274,7 @@ again." );
#endif
// Build links between each components and its part lib LIB_PART
aScreen->CheckComponentsToPartsLinks();
aScreen->UpdateSymbolLinks();
aScreen->TestDanglingEnds();

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2016 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2009-2016 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2009 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
@ -489,8 +489,14 @@ void prepareToolsMenu( wxMenu* aParentMenu )
AddMenuItem( aParentMenu,
ID_RESCUE_CACHED,
_( "&Rescue Old Component" ),
_( "Find old components in project and rename/rescue them" ),
_( "&Rescue Symbols" ),
_( "Find old symbols in project and rename/rescue them" ),
KiBitmap( rescue_xpm ) );
AddMenuItem( aParentMenu,
ID_REMAP_SYMBOLS,
_( "Remap Symbols" ),
_( "Remap legacy library symbols to symbol library table" ),
KiBitmap( rescue_xpm ) );
aParentMenu->AppendSeparator();

View File

@ -122,7 +122,7 @@ bool SCH_EDIT_FRAME::CreateNetlist( int aFormat, const wxString& aFullFileName,
SCH_SCREENS schematic;
schematic.UpdateSymbolLinks();
SCH_SHEET_LIST sheets( g_RootSheet );
sheets.AnnotatePowerSymbols( Prj().SchLibs() );
sheets.AnnotatePowerSymbols();
schematic.SchematicCleanUp();
}

View File

@ -27,10 +27,13 @@
#include <confirm.h>
#include <invoke_sch_dialog.h>
#include <kicad_device_context.h>
#include <kiway.h>
#include <project_rescue.h>
#include <sch_component.h>
#include <sch_sheet.h>
#include <schframe.h>
#include <symbol_lib_table.h>
#include <viewlib_frame.h>
#include <wildcards_and_files_ext.h>
#include <cctype>
@ -40,117 +43,16 @@
typedef std::pair<SCH_COMPONENT*, wxString> COMPONENT_NAME_PAIR;
/**
* Function save_library
* writes the library out to disk. Returns true on success.
*
* @param aLibrary - Library to write
* @param aEditFrame - the calling SCH_EDIT_FRAME
*/
static bool save_library( PART_LIB* aLibrary, SCH_EDIT_FRAME* aEditFrame )
{
try
{
aLibrary->Save( false );
}
catch( ... /* IO_ERROR ioe */ )
{
wxString msg = wxString::Format( _( "Failed to create component library file '%s'" ),
GetChars( aLibrary->GetFullFileName() )
);
DisplayError( aEditFrame, msg );
return false;
}
return true;
}
/**
* Function insert_library
* inserts a library into the project and refreshes libraries.
*
* @param aProject - project that will be modified
* @param aLibrary - PART_LIB to add
* @param aIndex - index in the list at which the library is to be inserted
*
* @return true on success, false on failure
*/
static bool insert_library( PROJECT *aProject, PART_LIB *aLibrary, size_t aIndex )
{
wxArrayString libNames;
wxString libPaths;
wxString libName = aLibrary->GetName();
PART_LIBS *libs = dynamic_cast<PART_LIBS*>( aProject->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
if( !libs )
{
libs = new PART_LIBS();
aProject->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
}
try
{
PART_LIBS::LibNamesAndPaths( aProject, false, &libPaths, &libNames );
// Make sure the library is not already in the list
while( libNames.Index( libName ) != wxNOT_FOUND )
libNames.Remove( libName );
// Add the library to the list and save
libNames.Insert( libName, aIndex );
PART_LIBS::LibNamesAndPaths( aProject, true, &libPaths, &libNames );
}
catch( const IO_ERROR& )
{
// Could not get or save the current libraries.
return false;
}
// Save the old libraries in case there is a problem after clear(). We'll
// put them back in.
boost::ptr_vector<PART_LIB> libsSave;
libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
aProject->SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
libs = new PART_LIBS();
try
{
libs->LoadAllLibraries( aProject );
}
catch( const PARSE_ERROR& )
{
// Some libraries were not found. There's no point in showing the error,
// because it was already shown. Just don't do anything.
}
catch( const IO_ERROR& )
{
// Restore the old list
libs->clear();
libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
return false;
}
aProject->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
// Update the schematic symbol library links since the library list has changed.
SCH_SCREENS schematic;
schematic.UpdateSymbolLinks();
return true;
}
// Helper sort function, used in get_components, to sort a component list by lib_id
static bool sort_by_libid( const SCH_COMPONENT* ref, SCH_COMPONENT* cmp )
{
return ref->GetLibId() < cmp->GetLibId();
}
/**
* Function get_components
* Fills a vector with all of the project's components, to ease iterating over them.
* Fill a vector with all of the project's components, to ease iterating over them.
*
* The list is sorted by lib id, therefore components using the same library
* symbol are grouped, allowing later faster calculations (one library search by group
* of symbols)
@ -168,18 +70,21 @@ static void get_components( std::vector<SCH_COMPONENT*>& aComponents )
{
if( item->Type() != SCH_COMPONENT_T )
continue;
SCH_COMPONENT* component = static_cast<SCH_COMPONENT*>( item );
aComponents.push_back( component );
}
}
if( aComponents.empty() )
return;
// sort aComponents by lib part. Components will be grouped by same lib part.
std::sort( aComponents.begin(), aComponents.end(), sort_by_libid );
}
/**
* Function find_component
* Search the libraries for the first component with a given name.
*
* @param aName - name to search for
@ -199,6 +104,7 @@ static LIB_PART* find_component( wxString aName, PART_LIBS* aLibs, bool aCached
continue;
part = each_lib.FindPart( aName );
if( part )
break;
}
@ -207,50 +113,27 @@ static LIB_PART* find_component( wxString aName, PART_LIBS* aLibs, bool aCached
}
void RESCUER::RemoveDuplicates()
static wxFileName GetRescueLibraryFileName()
{
std::vector<wxString> names_seen;
for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
it != m_all_candidates.end(); )
{
bool seen_already = false;
for( wxString& name_seen : names_seen )
{
if( name_seen == it->GetRequestedName() )
{
seen_already = true;
break;
}
}
if( seen_already )
{
it = m_all_candidates.erase( it );
}
else
{
names_seen.push_back( it->GetRequestedName() );
++it;
}
}
wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
fn.SetName( fn.GetName() + wxT( "-rescue" ) );
fn.SetExt( SchematicLibraryFileExtension );
return fn;
}
class RESCUE_CASE_CANDIDATE: public RESCUE_CANDIDATE
RESCUE_CASE_CANDIDATE::RESCUE_CASE_CANDIDATE( const wxString& aRequestedName,
const wxString& aNewName,
LIB_PART* aLibCandidate )
{
wxString m_requested_name;
wxString m_new_name;
LIB_PART* m_lib_candidate;
m_requested_name = aRequestedName;
m_new_name = aNewName;
m_lib_candidate = aLibCandidate;
}
public:
/**
* Function FindRescues
* Grab all possible RESCUE_CASE_CANDIDATES into a vector.
* @param aRescuer - the working RESCUER instance.
* @param aCandidates - the vector the will hold the candidates.
*/
static void FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
void RESCUE_CASE_CANDIDATE::FindRescues( RESCUER& aRescuer,
boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
{
typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
candidate_map_t candidate_map;
@ -275,18 +158,18 @@ public:
LIB_ID id( wxEmptyString, part_name );
case_sensitive_match = aRescuer.GetLibs()->FindLibraryAlias( id );
case_sensitive_match = aRescuer.GetPrj()->SchLibs()->FindLibraryAlias( id );
if( !case_sensitive_match )
// the case sensitive match failed. Try a case insensitive match
aRescuer.GetLibs()->FindLibraryNearEntries( case_insensitive_matches, part_name );
aRescuer.GetPrj()->SchLibs()->FindLibraryNearEntries( case_insensitive_matches,
part_name );
}
if( case_sensitive_match || !( case_insensitive_matches.size() ) )
continue;
RESCUE_CASE_CANDIDATE candidate(
part_name, case_insensitive_matches[0]->GetName(),
RESCUE_CASE_CANDIDATE candidate( part_name, case_insensitive_matches[0]->GetName(),
case_insensitive_matches[0]->GetPart() );
candidate_map[part_name] = candidate;
@ -299,31 +182,16 @@ public:
}
}
/**
* Constructor RESCUE_CANDIDATE
* @param aRequestedName - the name the schematic asks for
* @param aNewName - the name we want to change it to
* @param aLibCandidate - the part that will give us
*/
RESCUE_CASE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName,
LIB_PART* aLibCandidate )
: m_requested_name( aRequestedName ),
m_new_name( aNewName ),
m_lib_candidate( aLibCandidate ) { }
RESCUE_CASE_CANDIDATE() { m_lib_candidate = NULL; }
virtual wxString GetRequestedName() const override { return m_requested_name; }
virtual wxString GetNewName() const override { return m_new_name; }
virtual LIB_PART* GetLibCandidate() const override { return m_lib_candidate; }
virtual wxString GetActionDescription() const override
wxString RESCUE_CASE_CANDIDATE::GetActionDescription() const
{
wxString action;
action.Printf( _( "Rename to %s" ), m_new_name );
return action;
}
virtual bool PerformAction( RESCUER* aRescuer ) override
bool RESCUE_CASE_CANDIDATE::PerformAction( RESCUER* aRescuer )
{
for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
{
@ -337,28 +205,32 @@ public:
each_component->ClearFlags();
aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
}
return true;
}
};
class RESCUE_CACHE_CANDIDATE: public RESCUE_CANDIDATE
RESCUE_CACHE_CANDIDATE::RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName,
const wxString& aNewName,
LIB_PART* aCacheCandidate,
LIB_PART* aLibCandidate )
{
wxString m_requested_name;
wxString m_new_name;
LIB_PART* m_cache_candidate;
LIB_PART* m_lib_candidate;
m_requested_name = aRequestedName;
m_new_name = aNewName;
m_cache_candidate = aCacheCandidate;
m_lib_candidate = aLibCandidate;
}
static std::unique_ptr<PART_LIB> m_rescue_lib;
public:
/**
* Function FindRescues
* Grab all possible RESCUE_CACHE_CANDIDATEs into a vector.
* @param aRescuer - the working RESCUER instance.
* @param aCandidates - the vector the will hold the candidates.
*/
static void FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
RESCUE_CACHE_CANDIDATE::RESCUE_CACHE_CANDIDATE()
{
m_cache_candidate = NULL;
m_lib_candidate = NULL;
}
void RESCUE_CACHE_CANDIDATE::FindRescues( RESCUER& aRescuer,
boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
{
typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
candidate_map_t candidate_map;
@ -380,22 +252,24 @@ public:
// A new part name is found (a new group starts here).
// Search the symbol names candidates only once for this group:
old_part_name = part_name;
cache_match = find_component( part_name, aRescuer.GetLibs(), /* aCached */ true );
cache_match = find_component( part_name, aRescuer.GetPrj()->SchLibs(), true );
LIB_ID id( wxEmptyString, part_name );
lib_match = aRescuer.GetLibs()->FindLibPart( id );
lib_match = aRescuer.GetPrj()->SchLibs()->FindLibPart( id );
// Test whether there is a conflict
if( !cache_match || !lib_match )
continue;
if( !cache_match->PinsConflictWith( *lib_match, /* aTestNums */ true,
/* aTestNames */ true, /* aTestType */ true, /* aTestOrientation */ true,
/* aTestLength */ false ))
if( !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
continue;
RESCUE_CACHE_CANDIDATE candidate(
part_name, part_name + part_name_suffix,
cache_match, lib_match );
// May have been rescued already.
wxString new_name = part_name;
if( new_name.Find( part_name_suffix ) == wxNOT_FOUND )
new_name += part_name_suffix;
RESCUE_CACHE_CANDIDATE candidate( part_name, new_name, cache_match, lib_match );
candidate_map[part_name] = candidate;
}
@ -408,57 +282,21 @@ public:
}
}
/**
* Constructor RESCUE_CACHE_CANDIDATE
* @param aRequestedName - the name the schematic asks for
* @param aNewName - the name we want to change it to
* @param aCacheCandidate - the part from the cache
* @param aLibCandidate - the part that would be loaded from the library
*/
RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName,
LIB_PART* aCacheCandidate, LIB_PART* aLibCandidate )
: m_requested_name( aRequestedName ),
m_new_name( aNewName ),
m_cache_candidate( aCacheCandidate ),
m_lib_candidate( aLibCandidate ) { }
RESCUE_CACHE_CANDIDATE()
: m_cache_candidate( NULL ), m_lib_candidate( NULL ) {}
virtual wxString GetRequestedName() const override { return m_requested_name; }
virtual wxString GetNewName() const override { return m_new_name; }
virtual LIB_PART* GetCacheCandidate() const override { return m_cache_candidate; }
virtual LIB_PART* GetLibCandidate() const override { return m_lib_candidate; }
virtual wxString GetActionDescription() const override
wxString RESCUE_CACHE_CANDIDATE::GetActionDescription() const
{
wxString action;
action.Printf( _( "Rescue %s as %s" ), m_requested_name, m_new_name );
return action;
}
/**
* Function OpenRescueLibrary
* Creates the new rescue library. Must be called before calling any PerformAction()s.
*/
static void OpenRescueLibrary()
bool RESCUE_CACHE_CANDIDATE::PerformAction( RESCUER* aRescuer )
{
wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
fn.SetName( fn.GetName() + wxT( "-rescue" ) );
fn.SetExt( SchematicLibraryFileExtension );
std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA,
fn.GetFullPath() ) );
m_rescue_lib = std::move( rescue_lib );
m_rescue_lib->EnableBuffering();
}
virtual bool PerformAction( RESCUER* aRescuer ) override
{
LIB_PART new_part( *m_cache_candidate, m_rescue_lib.get() );
LIB_PART new_part( *m_cache_candidate );
new_part.SetName( m_new_name );
new_part.RemoveAllAliases();
RESCUE_CACHE_CANDIDATE::m_rescue_lib.get()->AddPart( &new_part );
aRescuer->AddPart( &new_part );
for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
{
@ -472,49 +310,129 @@ public:
each_component->ClearFlags();
aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
}
return true;
}
/**
* Function WriteRescueLibrary
* Writes out the rescue library. Called after successful PerformAction()s. If this fails,
* undo the actions.
* @return True on success.
*/
static bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame, PROJECT* aProject )
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::RESCUE_SYMBOL_LIB_TABLE_CANDIDATE(
const LIB_ID& aRequestedId,
const LIB_ID& aNewId,
LIB_PART* aCacheCandidate,
LIB_PART* aLibCandidate ) : RESCUE_CANDIDATE()
{
if( !save_library( m_rescue_lib.get(), aEditFrame ) )
return false;
return insert_library( aProject, m_rescue_lib.get(), 0 );
m_requested_id = aRequestedId;
m_requested_name = aRequestedId.GetLibItemName();
m_new_id = aNewId;
m_lib_candidate = aLibCandidate;
m_cache_candidate = aCacheCandidate;
}
};
std::unique_ptr<PART_LIB> RESCUE_CACHE_CANDIDATE::m_rescue_lib;
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::RESCUE_SYMBOL_LIB_TABLE_CANDIDATE()
{
m_cache_candidate = NULL;
m_lib_candidate = NULL;
}
void RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::FindRescues(
RESCUER& aRescuer,
boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates )
{
typedef std::map<LIB_ID, RESCUE_SYMBOL_LIB_TABLE_CANDIDATE> candidate_map_t;
candidate_map_t candidate_map;
// Remember the list of components is sorted by LIB_ID.
// So a search in libraries is made only once by group
LIB_PART* cache_match = nullptr;
LIB_PART* lib_match = nullptr;
LIB_ID old_part_id;
wxString part_name_suffix = aRescuer.GetPartNameSuffix();
for( SCH_COMPONENT* each_component : *( aRescuer.GetComponents() ) )
{
LIB_ID part_id = each_component->GetLibId();
if( old_part_id != part_id )
{
// A new part name is found (a new group starts here).
// Search the symbol names candidates only once for this group:
old_part_id = part_id;
cache_match = find_component( part_id.GetLibItemName(), aRescuer.GetPrj()->SchLibs(),
true );
lib_match = aRescuer.GetFrame()->GetLibPart( part_id );
// Test whether there is a conflict
if( !cache_match || !lib_match )
continue;
if( !cache_match->PinsConflictWith( *lib_match, true, true, true, true, false ) )
continue;
// May have been rescued already.
wxString new_name = part_id.GetLibItemName();
if( new_name.Find( part_name_suffix ) == wxNOT_FOUND )
new_name += part_name_suffix;
LIB_ID new_id( GetRescueLibraryFileName().GetName(), new_name );
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE candidate( part_id, new_id, cache_match, lib_match );
candidate_map[part_id] = candidate;
}
}
// Now, dump the map into aCandidates
for( const candidate_map_t::value_type& each_pair : candidate_map )
{
aCandidates.push_back( new RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( each_pair.second ) );
}
}
wxString RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::GetActionDescription() const
{
wxString action;
action.Printf( _( "Rescue to %s" ), m_new_id.Format().wx_str() );
return action;
}
bool RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::PerformAction( RESCUER* aRescuer )
{
LIB_PART new_part( *m_cache_candidate );
new_part.SetLibId( m_new_id );
new_part.SetName( m_new_id.GetLibItemName() );
new_part.RemoveAllAliases();
aRescuer->AddPart( &new_part );
for( SCH_COMPONENT* each_component : *aRescuer->GetComponents() )
{
if( each_component->GetLibId() != m_requested_id )
continue;
each_component->SetLibId( m_new_id );
each_component->ClearFlags();
aRescuer->LogRescue( each_component, m_requested_id.Format(), m_new_id.Format() );
}
return true;
}
RESCUER::RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject )
{
get_components( m_components );
m_prj = &aProject;
m_libs = m_prj->SchLibs();
m_edit_frame = &aEditFrame;
}
void RESCUER::FindCandidates()
{
RESCUE_CASE_CANDIDATE::FindRescues( *this, m_all_candidates );
RESCUE_CACHE_CANDIDATE::FindRescues( *this, m_all_candidates );
}
void RESCUER::InvokeDialog( bool aAskShowAgain )
{
InvokeDialogRescueEach( m_edit_frame, *this, aAskShowAgain );
}
void RESCUER::LogRescue( SCH_COMPONENT *aComponent, const wxString &aOldName,
const wxString &aNewName )
{
@ -533,6 +451,7 @@ bool RESCUER::DoRescues()
if( ! each_candidate->PerformAction( this ) )
return false;
}
return true;
}
@ -554,6 +473,7 @@ wxString RESCUER::GetPartNameSuffix()
{
wxString suffix = wxT( "-RESCUE-" );
wxString pname = GetPrj()->GetProjectName();
for( size_t i = 0; i < pname.Len(); ++i )
{
if( isspace( pname[i].GetValue() ) )
@ -566,13 +486,27 @@ wxString RESCUER::GetPartNameSuffix()
}
bool SCH_EDIT_FRAME::RescueProject( bool aRunningOnDemand )
bool SCH_EDIT_FRAME::RescueLegacyProject( bool aRunningOnDemand )
{
RESCUER rescuer( *this, Prj() );
LEGACY_RESCUER rescuer( *this, Prj() );
rescuer.FindCandidates();
return rescueProject( rescuer, aRunningOnDemand );
}
if( ! rescuer.GetCandidateCount() )
bool SCH_EDIT_FRAME::RescueSymbolLibTableProject( bool aRunningOnDemand )
{
SYMBOL_LIB_TABLE_RESCUER rescuer( *this, Prj() );
return rescueProject( rescuer, aRunningOnDemand );
}
bool SCH_EDIT_FRAME::rescueProject( RESCUER& aRescuer, bool aRunningOnDemand )
{
aRescuer.FindCandidates();
if( ! aRescuer.GetCandidateCount() )
{
if( aRunningOnDemand )
{
@ -580,16 +514,17 @@ bool SCH_EDIT_FRAME::RescueProject( bool aRunningOnDemand )
_( "Project Rescue Helper" ) );
dlg.ShowModal();
}
return true;
}
rescuer.RemoveDuplicates();
aRescuer.RemoveDuplicates();
rescuer.InvokeDialog( !aRunningOnDemand );
aRescuer.InvokeDialog( !aRunningOnDemand );
// If no components were rescued, let the user know what's going on. He might
// If no symbols were rescued, let the user know what's going on. He might
// have clicked cancel by mistake, and should have some indication of that.
if( !rescuer.GetChosenCandidateCount() )
if( !aRescuer.GetChosenCandidateCount() )
{
wxMessageDialog dlg( this, _( "No symbols were rescued." ),
_( "Project Rescue Helper" ) );
@ -601,17 +536,20 @@ bool SCH_EDIT_FRAME::RescueProject( bool aRunningOnDemand )
return true;
}
RESCUE_CACHE_CANDIDATE::OpenRescueLibrary();
aRescuer.OpenRescueLibrary();
if( !rescuer.DoRescues() )
if( !aRescuer.DoRescues() )
{
rescuer.UndoRescues();
aRescuer.UndoRescues();
return false;
}
RESCUE_CACHE_CANDIDATE::WriteRescueLibrary( this, &Prj() );
aRescuer.WriteRescueLibrary( this );
Prj().SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
LIB_VIEW_FRAME* viewer = (LIB_VIEW_FRAME*) Kiway().Player( FRAME_SCH_VIEWER, false );
if( viewer )
viewer->ReCreateListLib();
// Clean up wire ends
GetScreen()->SchematicCleanUp();
@ -620,3 +558,251 @@ bool SCH_EDIT_FRAME::RescueProject( bool aRunningOnDemand )
return true;
}
void RESCUER::RemoveDuplicates()
{
std::vector<wxString> names_seen;
for( boost::ptr_vector<RESCUE_CANDIDATE>::iterator it = m_all_candidates.begin();
it != m_all_candidates.end(); )
{
bool seen_already = false;
for( wxString& name_seen : names_seen )
{
if( name_seen == it->GetRequestedName() )
{
seen_already = true;
break;
}
}
if( seen_already )
{
it = m_all_candidates.erase( it );
}
else
{
names_seen.push_back( it->GetRequestedName() );
++it;
}
}
}
void LEGACY_RESCUER::FindCandidates()
{
RESCUE_CASE_CANDIDATE::FindRescues( *this, m_all_candidates );
RESCUE_CACHE_CANDIDATE::FindRescues( *this, m_all_candidates );
}
void LEGACY_RESCUER::InvokeDialog( bool aAskShowAgain )
{
InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
}
void LEGACY_RESCUER::OpenRescueLibrary()
{
wxFileName fn = GetRescueLibraryFileName();
std::unique_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() ) );
m_rescue_lib = std::move( rescue_lib );
m_rescue_lib->EnableBuffering();
}
bool LEGACY_RESCUER::WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame )
{
try
{
m_rescue_lib->Save( false );
}
catch( ... /* IO_ERROR ioe */ )
{
wxString msg;
msg.Printf( _( "Failed to create symbol library file '%s'" ),
m_rescue_lib->GetFullFileName() );
DisplayError( aEditFrame, msg );
return false;
}
wxArrayString libNames;
wxString libPaths;
wxString libName = m_rescue_lib->GetName();
PART_LIBS *libs = dynamic_cast<PART_LIBS*>( m_prj->GetElem( PROJECT::ELEM_SCH_PART_LIBS ) );
if( !libs )
{
libs = new PART_LIBS();
m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
}
try
{
PART_LIBS::LibNamesAndPaths( m_prj, false, &libPaths, &libNames );
// Make sure the library is not already in the list
while( libNames.Index( libName ) != wxNOT_FOUND )
libNames.Remove( libName );
// Add the library to the top of the list and save.
libNames.Insert( libName, 0 );
PART_LIBS::LibNamesAndPaths( m_prj, true, &libPaths, &libNames );
}
catch( const IO_ERROR& )
{
// Could not get or save the current libraries.
return false;
}
// Save the old libraries in case there is a problem after clear(). We'll
// put them back in.
boost::ptr_vector<PART_LIB> libsSave;
libsSave.transfer( libsSave.end(), libs->begin(), libs->end(), *libs );
m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
libs = new PART_LIBS();
try
{
libs->LoadAllLibraries( m_prj );
}
catch( const PARSE_ERROR& )
{
// Some libraries were not found. There's no point in showing the error,
// because it was already shown. Just don't do anything.
}
catch( const IO_ERROR& )
{
// Restore the old list
libs->clear();
libs->transfer( libs->end(), libsSave.begin(), libsSave.end(), libsSave );
return false;
}
m_prj->SetElem( PROJECT::ELEM_SCH_PART_LIBS, libs );
// Update the schematic symbol library links since the library list has changed.
SCH_SCREENS schematic;
schematic.UpdateSymbolLinks();
return true;
}
void LEGACY_RESCUER::AddPart( LIB_PART* aNewPart )
{
wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
aNewPart->SetLib( m_rescue_lib.get() );
m_rescue_lib->AddPart( aNewPart );
}
SYMBOL_LIB_TABLE_RESCUER::SYMBOL_LIB_TABLE_RESCUER( SCH_EDIT_FRAME& aEditFrame,
PROJECT& aProject ) :
RESCUER( aEditFrame, aProject )
{
m_properties = std::make_unique<PROPERTIES>();
}
void SYMBOL_LIB_TABLE_RESCUER::FindCandidates()
{
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE::FindRescues( *this, m_all_candidates );
RESCUE_CACHE_CANDIDATE::FindRescues( *this, m_all_candidates );
}
void SYMBOL_LIB_TABLE_RESCUER::InvokeDialog( bool aAskShowAgain )
{
InvokeDialogRescueEach( m_edit_frame, static_cast< RESCUER& >( *this ), aAskShowAgain );
}
void SYMBOL_LIB_TABLE_RESCUER::OpenRescueLibrary()
{
m_pi.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) );
(*m_properties)[ SCH_LEGACY_PLUGIN::PropBuffering ] = "";
}
bool SYMBOL_LIB_TABLE_RESCUER::WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame )
{
wxString msg;
wxFileName fn = GetRescueLibraryFileName();
// If the rescue library already exists in the symbol library table no need save it to add
// it to the table.
if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
{
try
{
m_pi->SaveLibrary( fn.GetFullPath() );
}
catch( const IO_ERROR& ioe )
{
msg.Printf( _( "Failed to save rescue library %s." ), fn.GetFullPath() );
DisplayErrorMessage( aEditFrame, msg, ioe.What() );
return false;
}
wxString uri = "${KIPRJMOD}/" + fn.GetFullName();
SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW( fn.GetName(), uri,
wxString( "Legacy" ) );
m_prj->SchSymbolLibTable()->InsertRow( row );
fn = wxFileName( m_prj->GetProjectPath(), SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
try
{
m_prj->SchSymbolLibTable()->Save( fn.GetFullPath() );
}
catch( const IO_ERROR& ioe )
{
msg.Printf( _( "Error occurred saving project specific symbol library table." ) );
DisplayErrorMessage( aEditFrame, msg, ioe.What() );
return false;
}
}
// Relaod the symbol library table.
m_prj->SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
// This can only happen if the symbol library table file was currupted on write.
if( !m_prj->SchSymbolLibTable() )
return false;
// Update the schematic symbol library links since the library list has changed.
SCH_SCREENS schematic;
schematic.UpdateSymbolLinks( true );
return true;
}
void SYMBOL_LIB_TABLE_RESCUER::AddPart( LIB_PART* aNewPart )
{
wxCHECK_RET( aNewPart, "Invalid LIB_PART pointer." );
wxFileName fn = GetRescueLibraryFileName();
try
{
if( !m_prj->SchSymbolLibTable()->HasLibrary( fn.GetName() ) )
m_pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *aNewPart ), m_properties.get() );
else
m_prj->SchSymbolLibTable()->SaveSymbol( fn.GetName(), new LIB_PART( *aNewPart ) );
}
catch( ... /* IO_ERROR */ )
{
}
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Chris Pavlina <pavlina.chris@gmail.com>
* Copyright (C) 2015 KiCad Developers, see change_log.txt for contributors.
* Copyright (C) 2015-2017 KiCad Developers, see change_log.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
@ -37,15 +37,22 @@
* (if aSilentIfNone is true, the notification is silenced).
*/
#include <schframe.h>
#include <vector>
#include <wx/string.h>
#include <boost/ptr_container/ptr_vector.hpp>
#include <properties.h>
#include <class_libentry.h>
#include <sch_legacy_plugin.h>
class LIB_PART;
class SCH_COMPONENT;
class RESCUER;
class SCH_EDIT_FRAME;
class SCH_LEGACY_PLUGIN;
enum RESCUE_TYPE
{
@ -53,45 +60,45 @@ enum RESCUE_TYPE
RESCUE_CASE,
};
class RESCUE_CANDIDATE
{
protected:
wxString m_requested_name;
wxString m_new_name;
LIB_PART* m_lib_candidate;
public:
virtual ~RESCUE_CANDIDATE() {}
/**
* Function GetRequestedName
* Get the name that was originally requested in the schematic
*/
virtual wxString GetRequestedName() const = 0;
virtual wxString GetRequestedName() const { return m_requested_name; }
/**
* Function GetNewName
* Get the name we're proposing changing it to
*/
virtual wxString GetNewName() const = 0;
virtual wxString GetNewName() const { return m_new_name; }
/**
* Function GetCacheCandidate
* Get the part that can be loaded from the project cache, if possible, or
* else NULL.
*/
virtual LIB_PART* GetCacheCandidate() const { return NULL; }
/**
* Function GetLibCandidate
* Get the part the would be loaded from the libraries, if possible, or else
* NULL.
*/
virtual LIB_PART* GetLibCandidate() const { return NULL; }
virtual LIB_PART* GetLibCandidate() const { return m_lib_candidate; }
/**
* Function GetActionDescription
* Get a description of the action proposed, for displaying in the UI.
*/
virtual wxString GetActionDescription() const = 0;
/**
* Function PerformAction
* Perform the actual rescue action. If successful, this must log the rescue using
* RESCUER::LogRescue to allow it to be reversed.
* @return True on success.
@ -99,6 +106,103 @@ public:
virtual bool PerformAction( RESCUER* aRescuer ) = 0;
};
class RESCUE_CASE_CANDIDATE : public RESCUE_CANDIDATE
{
public:
/**
* Grab all possible RESCUE_CASE_CANDIDATE objects into a vector.
*
* @param aRescuer - the working RESCUER instance.
* @param aCandidates - the vector the will hold the candidates.
*/
static void FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates );
/**
* Constructor RESCUE_CANDIDATE
* @param aRequestedName - the name the schematic asks for
* @param aNewName - the name we want to change it to
* @param aLibCandidate - the part that will give us
*/
RESCUE_CASE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName,
LIB_PART* aLibCandidate );
RESCUE_CASE_CANDIDATE() { m_lib_candidate = NULL; }
virtual wxString GetActionDescription() const override;
virtual bool PerformAction( RESCUER* aRescuer ) override;
};
class RESCUE_CACHE_CANDIDATE: public RESCUE_CANDIDATE
{
LIB_PART* m_cache_candidate;
public:
/**
* Grab all possible #RESCUE_CACHE_CANDIDATE objectss into a vector.
*
* @param aRescuer - the working RESCUER instance.
* @param aCandidates - the vector the will hold the candidates.
*/
static void FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates );
/**
* Constructor RESCUE_CACHE_CANDIDATE
* @param aRequestedName - the name the schematic asks for
* @param aNewName - the name we want to change it to
* @param aCacheCandidate - the part from the cache
* @param aLibCandidate - the part that would be loaded from the library
*/
RESCUE_CACHE_CANDIDATE( const wxString& aRequestedName, const wxString& aNewName,
LIB_PART* aCacheCandidate, LIB_PART* aLibCandidate );
RESCUE_CACHE_CANDIDATE();
virtual LIB_PART* GetCacheCandidate() const override { return m_cache_candidate; }
virtual wxString GetActionDescription() const override;
virtual bool PerformAction( RESCUER* aRescuer ) override;
};
class RESCUE_SYMBOL_LIB_TABLE_CANDIDATE : public RESCUE_CANDIDATE
{
LIB_ID m_requested_id;
LIB_ID m_new_id;
LIB_PART* m_cache_candidate;
public:
/**
* Grab all possible RESCUE_SYMBOL_LIB_TABLE_CANDIDATE objects into a vector.
*
* @param aRescuer - the working RESCUER instance.
* @param aCandidates - the vector the will hold the candidates.
*/
static void FindRescues( RESCUER& aRescuer, boost::ptr_vector<RESCUE_CANDIDATE>& aCandidates );
/**
* Constructor RESCUE_CANDIDATE
* @param aRequestedName - the name the schematic asks for
* @param aNewName - the name we want to change it to
* @param aCacheCandidate - the part from the cache
* @param aLibCandidate - the part that would be loaded from the library
*/
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE( const LIB_ID& aRequestedId, const LIB_ID& aNewId,
LIB_PART* aCacheCandidate, LIB_PART* aLibCandidate);
RESCUE_SYMBOL_LIB_TABLE_CANDIDATE();
virtual LIB_PART* GetCacheCandidate() const override { return m_cache_candidate; }
virtual wxString GetActionDescription() const override;
virtual bool PerformAction( RESCUER* aRescuer ) override;
};
class RESCUE_LOG
{
public:
@ -107,12 +211,13 @@ public:
wxString new_name;
};
class RESCUER
{
protected:
friend class DIALOG_RESCUE_EACH;
std::vector<SCH_COMPONENT*> m_components;
PART_LIBS* m_libs;
PROJECT* m_prj;
SCH_EDIT_FRAME* m_edit_frame;
@ -125,74 +230,124 @@ public:
RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject );
/**
* Function FindCandidates
* Populate the RESCUER with all possible candidates.
* Writes out the rescue library. Called after successful PerformAction()s. If this fails,
* undo the actions.
*
* @return True on success.
*/
void FindCandidates();
virtual bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame ) = 0;
virtual void OpenRescueLibrary() = 0;
/**
* Populate the RESCUER with all possible candidates.
*/
virtual void FindCandidates() = 0;
virtual void AddPart( LIB_PART* aNewPart ) = 0;
/**
* Display a dialog to allow the user to select rescues.
*
* @param aAskShowAgain - whether the "Never Show Again" button should be visible
*/
virtual void InvokeDialog( bool aAskShowAgain ) = 0;
SCH_EDIT_FRAME* GetFrame() { return m_edit_frame; }
/**
* Function RemoveDuplicates
* Filter out duplicately named rescue candidates.
*/
void RemoveDuplicates();
/**
* Function GetCandidateCount
* Returen the number of rescue candidates found.
*/
size_t GetCandidateCount() { return m_all_candidates.size(); }
/**
* Function GetChosenCandidateCount
* Get the number of resuce candidates chosen by the user.
*/
size_t GetChosenCandidateCount() { return m_chosen_candidates.size(); }
/**
* Function GetComponents
* Get the list of symbols that need rescued.
*/
std::vector<SCH_COMPONENT*>* GetComponents() { return &m_components; }
/**
* Function GetLibs
*/
PART_LIBS* GetLibs() { return m_libs; }
/**
* Function GetPrj
* Return the #SCH_PROJECT object for access to the symbol libraries.
*/
PROJECT* GetPrj() { return m_prj; }
/**
* Function GetPartNameSuffix
* Return the suffix to add to rescued parts.
*/
wxString GetPartNameSuffix();
/**
* Function InvokeDialog
* Display a dialog to allow the user to select rescues.
* @param aAskShowAgain - whether the "Never Show Again" button should be visible
*/
void InvokeDialog( bool aAskShowAgain );
/**
* Function LogRescue
* Used by individual RESCUE_CANDIDATEs to log a rescue for undoing.
* Used by individual #RESCUE_CANDIDATE objects to log a rescue for undoing.
*/
void LogRescue( SCH_COMPONENT *aComponent, const wxString& aOldName,
const wxString& aNewName );
/**
* Function DoRescues
* Perform all chosen rescue actions, logging them to be undone if necessary.
*
* @return True on success
*/
bool DoRescues();
/**
* Function UndoRescues
* Reverse the effects of all rescues on the project.
*/
void UndoRescues();
};
class LEGACY_RESCUER : public RESCUER
{
private:
std::unique_ptr<PART_LIB> m_rescue_lib;
PART_LIBS* m_libs;
public:
LEGACY_RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject ) :
RESCUER( aEditFrame, aProject )
{
}
virtual void FindCandidates() override;
virtual void InvokeDialog( bool aAskShowAgain ) override;
virtual void OpenRescueLibrary() override;
virtual bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame ) override;
virtual void AddPart( LIB_PART* aNewPart ) override;
};
class SYMBOL_LIB_TABLE_RESCUER : public RESCUER
{
private:
SCH_PLUGIN::SCH_PLUGIN_RELEASER m_pi;
std::unique_ptr< PROPERTIES > m_properties; ///< Library plugin properties
public:
SYMBOL_LIB_TABLE_RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject );
virtual void FindCandidates() override;
virtual void InvokeDialog( bool aAskShowAgain ) override;
virtual void OpenRescueLibrary() override;
virtual bool WriteRescueLibrary( SCH_EDIT_FRAME *aEditFrame ) override;
virtual void AddPart( LIB_PART* aNewPart ) override;
};
#endif // _LIB_CACHE_RESCUE_H_

View File

@ -40,7 +40,7 @@
LIB_ALIAS* SchGetLibAlias( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aLibTable, PART_LIB* aCacheLib,
wxWindow* aParent, bool aShowErrorMsg )
{
wxCHECK_MSG( aLibId.IsValid(), NULL, "LIB_ID is not valid." );
// wxCHECK_MSG( aLibId.IsValid(), NULL, "LIB_ID is not valid." );
wxCHECK_MSG( aLibTable, NULL, "Invalid symbol library table." );
LIB_ALIAS* alias = NULL;
@ -309,7 +309,7 @@ void SCH_BASE_FRAME::OnEditSymbolLibTable( wxCommandEvent& aEvent )
LIB_ALIAS* SCH_BASE_FRAME::GetLibAlias( const LIB_ID& aLibId, bool aUseCacheLib,
bool aShowErrorMsg )
{
wxCHECK_MSG( aLibId.IsValid(), NULL, "LIB_ID is not valid." );
// wxCHECK_MSG( aLibId.IsValid(), NULL, "LIB_ID is not valid." );
PART_LIB* cache = ( aUseCacheLib ) ? Prj().SchLibs()->GetCacheLibrary() : NULL;
@ -319,7 +319,7 @@ LIB_ALIAS* SCH_BASE_FRAME::GetLibAlias( const LIB_ID& aLibId, bool aUseCacheLib,
LIB_PART* SCH_BASE_FRAME::GetLibPart( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
{
wxCHECK_MSG( aLibId.IsValid(), NULL, "LIB_ID is not valid." );
// wxCHECK_MSG( aLibId.IsValid(), NULL, "LIB_ID is not valid." );
PART_LIB* cache = ( aUseCacheLib ) ? Prj().SchLibs()->GetCacheLibrary() : NULL;

View File

@ -1744,6 +1744,8 @@ const EDA_RECT SCH_COMPONENT::GetBoundingBox() const
void SCH_COMPONENT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList )
{
wxString msg;
// part and alias can differ if alias is not the root
if( PART_SPTR part = m_part.lock() )
{
@ -1759,7 +1761,7 @@ void SCH_COMPONENT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList )
GetRef( m_currentSheetPath ),
DARKCYAN ) );
wxString msg = part->IsPower() ? _( "Power symbol" ) : _( "Value" );
msg = part->IsPower() ? _( "Power symbol" ) : _( "Value" );
aList.push_back( MSG_PANEL_ITEM( msg, GetField( VALUE )->GetShownText(), DARKCYAN ) );
@ -1800,8 +1802,20 @@ void SCH_COMPONENT::GetMsgPanelInfo( MSG_PANEL_ITEMS& aList )
aList.push_back( MSG_PANEL_ITEM( _( "Value" ), GetField( VALUE )->GetShownText(),
DARKCYAN ) );
aList.push_back( MSG_PANEL_ITEM( _( "Component" ), GetLibId().GetLibItemName(), BROWN ) );
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), _( "Error: symbol not found!!!" ), RED ) );
aList.push_back( MSG_PANEL_ITEM( _( "Symbol" ), GetLibId().GetLibItemName(), BROWN ) );
wxString libNickname = GetLibId().GetLibNickname();
if( libNickname.empty() )
{
aList.push_back( MSG_PANEL_ITEM( _( "Library" ),
_( "No library defined!!!" ), RED ) );
}
else
{
msg.Printf( _( "Symbol not found in %s!!!" ), libNickname );
aList.push_back( MSG_PANEL_ITEM( _( "Library" ), msg , RED ) );
}
}
}

View File

@ -479,12 +479,13 @@ static void parseQuotedString( wxString& aString, FILE_LINE_READER& aReader,
*/
class SCH_LEGACY_PLUGIN_CACHE
{
static int m_modHash; // Keep track of the modification status of the library.
wxFileName m_libFileName; // Absolute path and file name is required here.
wxDateTime m_fileModTime;
LIB_ALIAS_MAP m_aliases; // Map of names of LIB_ALIAS pointers.
bool m_isWritable;
bool m_isModified;
int m_modHash; // Keep track of the modification status of the library.
int m_versionMajor;
int m_versionMinor;
int m_libType; // Is this cache a component or symbol library.
@ -2031,11 +2032,13 @@ void SCH_LEGACY_PLUGIN::saveText( SCH_TEXT* aText )
}
int SCH_LEGACY_PLUGIN_CACHE::m_modHash = 1; // starts at 1 and goes up
SCH_LEGACY_PLUGIN_CACHE::SCH_LEGACY_PLUGIN_CACHE( const wxString& aFullPathAndFileName ) :
m_libFileName( aFullPathAndFileName ),
m_isWritable( true ),
m_isModified( false ),
m_modHash( 1 )
m_isModified( false )
{
m_versionMajor = -1;
m_versionMinor = -1;

View File

@ -527,7 +527,7 @@ bool SCH_SCREEN::Save( FILE* aFile ) const
}
void SCH_SCREEN::CheckComponentsToPartsLinks()
void SCH_SCREEN::UpdateSymbolLinks( bool aForce )
{
// Initialize or reinitialize the pointer to the LIB_PART for each component
// found in m_drawList, but only if needed (change in lib or schematic)
@ -539,7 +539,7 @@ void SCH_SCREEN::CheckComponentsToPartsLinks()
int mod_hash = libs->GetModifyHash();
// Must we resolve?
if( m_modification_sync != mod_hash )
if( (m_modification_sync != mod_hash) || aForce )
{
SCH_TYPE_COLLECTOR c;
@ -561,7 +561,7 @@ void SCH_SCREEN::Draw( EDA_DRAW_PANEL* aCanvas, wxDC* aDC, GR_DRAWMODE aDrawMode
*/
// Ensure links are up to date, even if a library was reloaded for some reason:
CheckComponentsToPartsLinks();
UpdateSymbolLinks();
for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() )
{
@ -582,7 +582,7 @@ void SCH_SCREEN::Draw( EDA_DRAW_PANEL* aCanvas, wxDC* aDC, GR_DRAWMODE aDrawMode
void SCH_SCREEN::Plot( PLOTTER* aPlotter )
{
// Ensure links are up to date, even if a library was reloaded for some reason:
CheckComponentsToPartsLinks();
UpdateSymbolLinks();
for( SCH_ITEM* item = m_drawList.begin(); item; item = item->Next() )
{
@ -1508,10 +1508,10 @@ int SCH_SCREENS::GetMarkerCount( enum MARKER_BASE::TYPEMARKER aMarkerType,
}
void SCH_SCREENS::UpdateSymbolLinks()
void SCH_SCREENS::UpdateSymbolLinks( bool aForce )
{
for( SCH_SCREEN* screen = GetFirst(); screen; screen = GetNext() )
screen->CheckComponentsToPartsLinks();
screen->UpdateSymbolLinks( aForce );
}

View File

@ -58,6 +58,7 @@
#include <invoke_sch_dialog.h>
#include <dialogs/dialog_schematic_find.h>
#include <dialog_symbol_remap.h>
#include <wx/display.h>
#include <build_version.h>
@ -251,6 +252,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_TOOL( ID_POPUP_SCH_CALL_LIBEDIT_AND_LOAD_CMP, SCH_EDIT_FRAME::OnOpenLibraryEditor )
EVT_TOOL( ID_TO_LIBVIEW, SCH_EDIT_FRAME::OnOpenLibraryViewer )
EVT_TOOL( ID_RESCUE_CACHED, SCH_EDIT_FRAME::OnRescueProject )
EVT_MENU( ID_REMAP_SYMBOLS, SCH_EDIT_FRAME::OnRemapSymbols )
EVT_TOOL( ID_RUN_PCB, SCH_EDIT_FRAME::OnOpenPcbnew )
EVT_TOOL( ID_RUN_PCB_MODULE_EDITOR, SCH_EDIT_FRAME::OnOpenPcbModuleEditor )
@ -333,6 +335,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_UPDATE_UI( ID_SAVE_PROJECT, SCH_EDIT_FRAME::OnUpdateSave )
EVT_UPDATE_UI( ID_UPDATE_ONE_SHEET, SCH_EDIT_FRAME::OnUpdateSaveSheet )
EVT_UPDATE_UI( ID_POPUP_SCH_LEAVE_SHEET, SCH_EDIT_FRAME::OnUpdateHierarchySheet )
EVT_UPDATE_UI( ID_REMAP_SYMBOLS, SCH_EDIT_FRAME::OnUpdateRemapSymbols )
/* Search dialog events. */
EVT_FIND_CLOSE( wxID_ANY, SCH_EDIT_FRAME::OnFindDialogClose )
@ -823,6 +826,15 @@ void SCH_EDIT_FRAME::OnUpdateSave( wxUpdateUIEvent& aEvent )
}
void SCH_EDIT_FRAME::OnUpdateRemapSymbols( wxUpdateUIEvent& aEvent )
{
SCH_SCREENS schematic;
// The remapping can only be performed on legacy projects.
aEvent.Enable( schematic.HasNoFullyDefinedLibIds() );
}
void SCH_EDIT_FRAME::OnUpdateSaveSheet( wxUpdateUIEvent& aEvent )
{
aEvent.Enable( GetScreen()->IsModify() );
@ -1249,7 +1261,20 @@ void SCH_EDIT_FRAME::OnOpenLibraryEditor( wxCommandEvent& event )
void SCH_EDIT_FRAME::OnRescueProject( wxCommandEvent& event )
{
RescueProject( true );
SCH_SCREENS schematic;
if( schematic.HasNoFullyDefinedLibIds() )
RescueLegacyProject( true );
else
RescueSymbolLibTableProject( true );
}
void SCH_EDIT_FRAME::OnRemapSymbols( wxCommandEvent& event )
{
DIALOG_SYMBOL_REMAP dlgRemap( this );
dlgRemap.ShowQuasiModal();
}

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras wanadoo.fr
* Copyright (C) 2008-2017 Wayne Stambaugh <stambaughw@verizon.net>
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
@ -64,6 +64,7 @@ class DIALOG_SCH_FIND;
class wxFindDialogEvent;
class wxFindReplaceData;
class SCHLIB_FILTER;
class RESCUER;
/// enum used in RotationMiroir()
@ -890,6 +891,7 @@ private:
void OnOpenCvpcb( wxCommandEvent& event );
void OnOpenLibraryEditor( wxCommandEvent& event );
void OnRescueProject( wxCommandEvent& event );
void OnRemapSymbols( wxCommandEvent& aEvent );
void OnPreferencesOptions( wxCommandEvent& event );
void OnCancelCurrentCommand( wxCommandEvent& aEvent );
@ -910,6 +912,7 @@ private:
void OnUpdateSave( wxUpdateUIEvent& aEvent );
void OnUpdateSaveSheet( wxUpdateUIEvent& aEvent );
void OnUpdateHierarchySheet( wxUpdateUIEvent& aEvent );
void OnUpdateRemapSymbols( wxUpdateUIEvent& aEvent );
/**
* Function UpdateTitle
@ -1378,7 +1381,9 @@ public:
* if there are no components to rescue, and a "Never Show Again" button is
* displayed.
*/
bool RescueProject( bool aRunningOnDemand );
bool rescueProject( RESCUER& aRescuer, bool aRunningOnDemand );
bool RescueLegacyProject( bool aRunningOnDemand );
bool RescueSymbolLibTableProject( bool aRunningOnDemand );
/**
* Function PrintPage