kicad-developers team mailing list archive
-
kicad-developers team
-
Mailing list archive
-
Message #18824
Re: [PATCH] lib-cache-rescue upgrade
No - I attached another in response to JP's recent mail about Coverity.
Here it is again:
Chris,
Is this patch good to go? I'm having trouble keeping up with the patch
volume so I want to make sure before I commit it.
Thanks,
Wayne
On 6/18/2015 3:07 PM, Chris Pavlina wrote:
> Hi all,
>
> It's come to my attention that we have another old project compatibility
> issue:
>
>
https://forum.kicad.info/t/exisiting-schematic-component-not-being-found-in-library-error/976
>
> The behavior when loading a very old project with case-insensitive part
> names isn't nice at all, there's no easy way to change them over. It
> gives suggestions for new part names, but you still have to change them
> one by one.
>
> I adapted lib-cache-rescue into a more generic project-rescue, which can
> handle multiple types of rescue cases, and added one for missing symbols
> with differently cased versions available.
>
> It looks roughly like this now (though I've changed the descriptive text
> at the top since taking that screenshot):
>
> http://misc.c4757p.com/newrescue.png
>
> Please, as many people as possible, try this out.
>
> --
> Chris
>
>
>
> _______________________________________________
> Mailing list: https://launchpad.net/~kicad-developers
> Post to : kicad-developers@xxxxxxxxxxxxxxxxxxx
> Unsubscribe : https://launchpad.net/~kicad-developers
> More help : https://help.launchpad.net/ListHelp
>
_______________________________________________
Mailing list: https://launchpad.net/~kicad-developers
Post to : kicad-developers@xxxxxxxxxxxxxxxxxxx
Unsubscribe : https://launchpad.net/~kicad-developers
More help : https://help.launchpad.net/ListHelp
diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt
index 0982735..d6cc1cd 100644
--- a/eeschema/CMakeLists.txt
+++ b/eeschema/CMakeLists.txt
@@ -114,7 +114,6 @@ set( EESCHEMA_SRCS
libedit_undo_redo.cpp
lib_arc.cpp
lib_bezier.cpp
- lib_cache_rescue.cpp
lib_circle.cpp
lib_collectors.cpp
lib_draw_item.cpp
@@ -139,6 +138,7 @@ set( EESCHEMA_SRCS
plot_schematic_PS.cpp
plot_schematic_PDF.cpp
plot_schematic_SVG.cpp
+ project_rescue.cpp
sch_base_frame.cpp
sch_bitmap.cpp
sch_bus_entry.cpp
diff --git a/eeschema/class_library.cpp b/eeschema/class_library.cpp
index 4fac061..bbda657 100644
--- a/eeschema/class_library.cpp
+++ b/eeschema/class_library.cpp
@@ -38,7 +38,7 @@
#include <richio.h>
#include <config_params.h>
#include <wildcards_and_files_ext.h>
-#include <lib_cache_rescue.h>
+#include <project_rescue.h>
//#include <richio.h>
#include <general.h>
diff --git a/eeschema/dialogs/dialog_rescue_each.cpp b/eeschema/dialogs/dialog_rescue_each.cpp
index 8b896f4..31c424a 100644
--- a/eeschema/dialogs/dialog_rescue_each.cpp
+++ b/eeschema/dialogs/dialog_rescue_each.cpp
@@ -32,7 +32,7 @@
#include <set>
#include <vector>
#include <boost/foreach.hpp>
-#include <lib_cache_rescue.h>
+#include <project_rescue.h>
#include <eeschema_config.h>
class DIALOG_RESCUE_EACH: public DIALOG_RESCUE_EACH_BASE
@@ -43,24 +43,19 @@ public:
* This dialog asks the user which rescuable, cached parts he wants to rescue.
* Any rejects will be pruned from aCandidates.
* @param aCaller - the SCH_EDIT_FRAME calling this
- * @param aCandidates - the list of RESCUE_CANDIDATES
- * @param aComponents - a vector of all the components in the schematic
+ * @param aRescuer - the active RESCUER instance
* @param aAskShowAgain - if true, a "Never Show Again" button will be included
*/
- DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, std::vector<RESCUE_CANDIDATE>& aCandidates,
- std::vector<SCH_COMPONENT*>& aComponents, bool aAskShowAgain );
+ DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, RESCUER& aRescuer, bool aAskShowAgain );
~DIALOG_RESCUE_EACH();
private:
SCH_EDIT_FRAME* m_Parent;
wxConfigBase* m_Config;
- std::vector<RESCUE_CANDIDATE>* m_Candidates;
- std::vector<SCH_COMPONENT*>* m_Components;
+ RESCUER* m_Rescuer;
bool m_AskShowAgain;
- bool m_insideUpdateEvent;
-
bool TransferDataToWindow();
bool TransferDataFromWindow();
void PopulateConflictList();
@@ -75,31 +70,22 @@ private:
};
-DIALOG_RESCUE_EACH::DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, std::vector<RESCUE_CANDIDATE>& aCandidates,
- std::vector<SCH_COMPONENT*>& aComponents, bool aAskShowAgain )
-
+DIALOG_RESCUE_EACH::DIALOG_RESCUE_EACH( SCH_EDIT_FRAME* aParent, RESCUER& aRescuer,
+ bool aAskShowAgain )
: DIALOG_RESCUE_EACH_BASE( aParent ),
m_Parent( aParent ),
- m_Candidates( &aCandidates ),
- m_Components( &aComponents ),
- m_AskShowAgain( aAskShowAgain ),
- m_insideUpdateEvent( false )
+ m_Rescuer( &aRescuer ),
+ m_AskShowAgain( aAskShowAgain )
{
m_Config = Kiface().KifaceSettings();
m_stdButtonsOK->SetDefault();
// Set the info message, customized to include the proper suffix.
- wxString info_message;
- info_message.Printf(
- _( "This project uses symbols that no longer match the ones in the system libraries.\n"
- "Using this tool, you can rescue these cached symbols into a new library.\n"
- "\n"
- "Choose \"Rescue\" for any parts you would like to save from this project's cache,\n"
- "or press \"Cancel\" to allow the symbols to be updated to the new versions.\n"
- "\n"
- "All rescued components will be renamed with a new suffix of \"-RESCUE-%s\"\n"
- "to avoid naming conflicts." ),
- Prj().GetProjectName() );
+ wxString info_message =
+ _( "It looks like this project was made using older schematic component libraries.\n"
+ "Some parts may need to be relinked to a different symbol name, and some symbols\n"
+ "may need to be \"rescued\" into a new library.\n"
+ "The following changes are recommended to update the project.\n" );
m_lblInfo->SetLabel( info_message );
}
@@ -114,8 +100,9 @@ bool DIALOG_RESCUE_EACH::TransferDataToWindow()
if( !wxDialog::TransferDataToWindow() )
return false;
- m_ListOfConflicts->AppendToggleColumn( _( "Rescue symbol" ) );
- m_ListOfConflicts->AppendTextColumn( _( "Symbol name" ) );
+ m_ListOfConflicts->AppendToggleColumn( _( "Accept" ) );
+ m_ListOfConflicts->AppendTextColumn( _( "Symbol" ) );
+ m_ListOfConflicts->AppendTextColumn( _( "Action" ) );
m_ListOfInstances->AppendTextColumn( _( "Reference" ) );
m_ListOfInstances->AppendTextColumn( _( "Value" ) );
PopulateConflictList();
@@ -136,11 +123,13 @@ bool DIALOG_RESCUE_EACH::TransferDataToWindow()
void DIALOG_RESCUE_EACH::PopulateConflictList()
{
wxVector<wxVariant> data;
- BOOST_FOREACH( RESCUE_CANDIDATE& each_candidate, *m_Candidates )
+ BOOST_FOREACH( RESCUE_CANDIDATE& each_candidate, m_Rescuer->m_all_candidates )
{
data.clear();
data.push_back( wxVariant( true ) );
- data.push_back( each_candidate.requested_name );
+ data.push_back( each_candidate.GetRequestedName() );
+ data.push_back( each_candidate.GetActionDescription() );
+
m_ListOfConflicts->AppendItem( data );
}
}
@@ -155,12 +144,12 @@ void DIALOG_RESCUE_EACH::PopulateInstanceList()
if( row == wxNOT_FOUND )
row = 0;
- RESCUE_CANDIDATE& selected_part = (*m_Candidates)[row];
+ RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row];
wxVector<wxVariant> data;
- BOOST_FOREACH( SCH_COMPONENT* each_component, *m_Components )
+ BOOST_FOREACH( SCH_COMPONENT* each_component, *m_Rescuer->GetComponents() )
{
- if( each_component->GetPartName() != selected_part.requested_name )
+ if( each_component->GetPartName() != selected_part.GetRequestedName() )
continue;
SCH_FIELD* valueField = each_component->GetField( 1 );
@@ -181,9 +170,10 @@ void DIALOG_RESCUE_EACH::OnHandleCachePreviewRepaint( wxPaintEvent& aRepaintEven
if( row == wxNOT_FOUND )
row = 0;
- RESCUE_CANDIDATE& selected_part = (*m_Candidates)[row];
+ RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row];
- renderPreview( selected_part.cache_candidate, 0, m_componentViewOld );
+ if( selected_part.GetCacheCandidate() )
+ renderPreview( selected_part.GetCacheCandidate(), 0, m_componentViewOld );
}
@@ -194,9 +184,10 @@ void DIALOG_RESCUE_EACH::OnHandleLibraryPreviewRepaint( wxPaintEvent& aRepaintEv
if( row == wxNOT_FOUND )
row = 0;
- RESCUE_CANDIDATE& selected_part = (*m_Candidates)[row];
+ RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row];
- renderPreview( selected_part.lib_candidate, 0, m_componentViewNew );
+ if( selected_part.GetLibCandidate() )
+ renderPreview( selected_part.GetLibCandidate(), 0, m_componentViewNew );
}
@@ -269,19 +260,15 @@ bool DIALOG_RESCUE_EACH::TransferDataFromWindow()
if( !wxDialog::TransferDataFromWindow() )
return false;
- std::vector<RESCUE_CANDIDATE>::iterator it = m_Candidates->begin();
- for( size_t index = 0; it != m_Candidates->end(); ++index )
+ for( size_t index = 0; index < m_Rescuer->GetCandidateCount(); ++index )
{
wxVariant val;
m_ListOfConflicts->GetValue( val, index, 0 );
bool rescue_part = val.GetBool();
- if( !rescue_part )
- m_Candidates->erase( it );
- else
- ++it;
+ if( rescue_part )
+ m_Rescuer->m_chosen_candidates.push_back( &m_Rescuer->m_all_candidates[index] );
}
-
return true;
}
@@ -299,7 +286,7 @@ void DIALOG_RESCUE_EACH::OnNeverShowClick( wxCommandEvent& aEvent )
if( resp == wxID_YES )
{
m_Config->Write( RESCUE_NEVER_SHOW_KEY, true );
- m_Candidates->clear();
+ m_Rescuer->m_chosen_candidates.clear();
Close();
}
}
@@ -307,14 +294,13 @@ void DIALOG_RESCUE_EACH::OnNeverShowClick( wxCommandEvent& aEvent )
void DIALOG_RESCUE_EACH::OnCancelClick( wxCommandEvent& aEvent )
{
- m_Candidates->clear();
+ m_Rescuer->m_chosen_candidates.clear();
DIALOG_RESCUE_EACH_BASE::OnCancelClick( aEvent );
}
-int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, std::vector<RESCUE_CANDIDATE>& aCandidates,
- std::vector<SCH_COMPONENT*>& aComponents, bool aAskShowAgain )
+int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, RESCUER& aRescuer, bool aAskShowAgain )
{
- DIALOG_RESCUE_EACH dlg( aCaller, aCandidates, aComponents, aAskShowAgain );
+ DIALOG_RESCUE_EACH dlg( aCaller, aRescuer, aAskShowAgain );
return dlg.ShowModal();
}
diff --git a/eeschema/dialogs/dialog_rescue_each_base.cpp b/eeschema/dialogs/dialog_rescue_each_base.cpp
index 2e7549d..99cdbcc 100644
--- a/eeschema/dialogs/dialog_rescue_each_base.cpp
+++ b/eeschema/dialogs/dialog_rescue_each_base.cpp
@@ -20,7 +20,7 @@ DIALOG_RESCUE_EACH_BASE::DIALOG_RESCUE_EACH_BASE( wxWindow* parent, wxWindowID i
m_lblInfo->Wrap( 500 );
bSizerMain->Add( m_lblInfo, 0, wxALL|wxEXPAND, 5 );
- m_staticText5 = new wxStaticText( this, wxID_ANY, _("Symbols with cache/library conflicts:"), wxDefaultPosition, wxDefaultSize, 0 );
+ m_staticText5 = new wxStaticText( this, wxID_ANY, _("Symbols to update:"), wxDefaultPosition, wxDefaultSize, 0 );
m_staticText5->Wrap( -1 );
m_staticText5->SetFont( wxFont( wxNORMAL_FONT->GetPointSize(), 70, 90, 92, false, wxEmptyString ) );
diff --git a/eeschema/dialogs/dialog_rescue_each_base.fbp b/eeschema/dialogs/dialog_rescue_each_base.fbp
index dee774b..fcc7882 100644
--- a/eeschema/dialogs/dialog_rescue_each_base.fbp
+++ b/eeschema/dialogs/dialog_rescue_each_base.fbp
@@ -208,7 +208,7 @@
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
- <property name="label">Symbols with cache/library conflicts:</property>
+ <property name="label">Symbols to update:</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp
index 39922f5..3bf97b9 100644
--- a/eeschema/files-io.cpp
+++ b/eeschema/files-io.cpp
@@ -43,7 +43,7 @@
#include <sch_sheet_path.h>
#include <sch_component.h>
#include <wildcards_and_files_ext.h>
-#include <lib_cache_rescue.h>
+#include <project_rescue.h>
#include <eeschema_config.h>
@@ -307,7 +307,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
UpdateFileHistory( fullFileName );
- // Check to see whether some old, cached library parts need to be rescued
+ // 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;
@@ -315,7 +315,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector<wxString>& aFileSet, in
if( !rescueNeverShow )
{
- if( RescueCacheConflicts( false ) )
+ if( RescueProject( false ) )
{
GetScreen()->CheckComponentsToPartsLinks();
GetScreen()->TestDanglingEnds();
diff --git a/eeschema/invoke_sch_dialog.h b/eeschema/invoke_sch_dialog.h
index 0a9cbe4..e4395ee 100644
--- a/eeschema/invoke_sch_dialog.h
+++ b/eeschema/invoke_sch_dialog.h
@@ -48,8 +48,7 @@ class wxDialog;
class LIB_PART;
class PART_LIBS;
class SCH_COMPONENT;
-class RESCUE_CANDIDATE;
-class RESCUE_LOG;
+class RESCUER;
// Often this is not used in the prototypes, since wxFrame is good enough and would
// represent maximum information hiding.
@@ -60,12 +59,10 @@ class SCH_EDIT_FRAME;
* This dialog asks the user which rescuable, cached parts he wants to rescue.
* Any rejects will be pruned from aCandidates.
* @param aCaller - the SCH_EDIT_FRAME calling this
- * @param aCandidates - the list of RESCUE_CANDIDATES
- * @param aComponents - a vector of all the components in the schematic
+ * @param aRescuer - the active RESCUER instance
* @param aAskShowAgain - if true, a "Never Show Again" button will be included
*/
-int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, std::vector<RESCUE_CANDIDATE>& aCandidates,
- std::vector<SCH_COMPONENT*>& aComponents, bool aAskShowAgain );
+int InvokeDialogRescueEach( SCH_EDIT_FRAME* aCaller, RESCUER& aRescuer, bool aAskShowAgain );
/// Create and show DIALOG_ANNOTATE and return whatever
/// DIALOG_ANNOTATE::ShowModal() returns.
diff --git a/eeschema/lib_cache_rescue.cpp b/eeschema/lib_cache_rescue.cpp
deleted file mode 100644
index da74997..0000000
--- a/eeschema/lib_cache_rescue.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2015 Chris Pavlina <pavlina.chris@xxxxxxxxx>
- * Copyright (C) 2015 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
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you may find one here:
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- * or you may search the http://www.gnu.org website for the version 2 license,
- * or you may write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include <class_drawpanel.h>
-#include <class_library.h>
-#include <confirm.h>
-#include <invoke_sch_dialog.h>
-#include <kicad_device_context.h>
-#include <lib_cache_rescue.h>
-#include <sch_component.h>
-#include <sch_sheet.h>
-#include <schframe.h>
-#include <wildcards_and_files_ext.h>
-
-#include <boost/foreach.hpp>
-#include <map>
-
-
-typedef std::pair<SCH_COMPONENT*, wxString> COMPONENT_NAME_PAIR;
-
-
-/**
- * Function save_library
- * writes the library out to disk. Returns true on success.
- *
- * @param aFileName - Filename to receive the library
- * @param aLibrary - Library to write
- * @param aEditFrame - the calling SCH_EDIT_FRAME
- */
-static bool save_library( const wxString& aFileName, PART_LIB* aLibrary, SCH_EDIT_FRAME* aEditFrame )
-{
- try
- {
- FILE_OUTPUTFORMATTER formatter( aFileName );
-
- if( !aLibrary->Save( formatter ) )
- {
- wxString msg = wxString::Format( _(
- "An error occurred attempting to save component library '%s'." ),
- GetChars( aFileName )
- );
- DisplayError( aEditFrame, msg );
- return false;
- }
- }
- catch( ... /* IO_ERROR ioe */ )
- {
- wxString msg = wxString::Format( _(
- "Failed to create component library file '%s'" ),
- GetChars( aFileName )
- );
- 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 ) throw( boost::bad_pointer )
-{
- 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 );
- }
-
- 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 );
-
- // 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& e )
- {
- // 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& e )
- {
- // 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 );
-
- return true;
-}
-
-
-/**
- * Function get_components
- * Fills a vector with all of the project's components, to ease iterating over them.
- *
- * @param aComponents - a vector that will take the components
- */
-static void get_components( std::vector<SCH_COMPONENT*>& aComponents )
-{
- SCH_SCREENS screens;
- for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
- {
- for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
- {
- if( item->Type() != SCH_COMPONENT_T ) continue;
- SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( item );
- aComponents.push_back( component );
- }
- }
-}
-
-
-/**
- * Function find_component
- * Search the libraries for the first component with a given name.
- *
- * @param aName - name to search for
- * @param aLibs - the loaded PART_LIBS
- * @param aCached - whether we are looking for the cached part
- */
-static LIB_PART* find_component( wxString aName, PART_LIBS* aLibs, bool aCached )
-{
- LIB_PART *part = NULL;
-
- BOOST_FOREACH( PART_LIB& each_lib, *aLibs )
- {
- if( aCached && !each_lib.IsCache() )
- continue;
-
- if( !aCached && each_lib.IsCache() )
- continue;
-
- part = each_lib.FindPart( aName );
- if( part )
- break;
- }
-
- return part;
-}
-
-
-/**
- * Function find_rescues
- * Search components for any that request a part that conflicts with the
- * library parts.
- *
- * This is done from the component side to track requested aliases.
- *
- * @param aComponents - a vector of components to scan
- * @param aLibs - the loaded PART_LIBS
- * @param aCandidates - a vector to hold rescue candidates
- */
-static void find_rescues( std::vector<SCH_COMPONENT*>& aComponents, PART_LIBS* aLibs,
- std::vector<RESCUE_CANDIDATE>& aCandidates )
-{
- // We need to narrow down the list and avoid having multiple copies of the
- // same name. Therefore, we'll assemble in a map first, before pushing to
- // the vector.
- typedef std::map<wxString, RESCUE_CANDIDATE> candidate_map_t;
- candidate_map_t candidate_map;
- BOOST_FOREACH( SCH_COMPONENT* each_component, aComponents )
- {
- wxString part_name( each_component->GetPartName() );
- LIB_PART* cache_match = find_component( part_name, aLibs, /* aCached */ true );
- LIB_PART* lib_match = find_component( part_name, aLibs, /* aCached */ false );
-
- // 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 ))
- continue;
-
- RESCUE_CANDIDATE candidate;
- candidate.requested_name = part_name;
- candidate.cache_candidate = cache_match;
- candidate.lib_candidate = lib_match;
-
- candidate_map[part_name] = candidate;
- }
-
- // Now, dump the map into aCandidates
- BOOST_FOREACH( const candidate_map_t::value_type& each_pair, candidate_map )
- {
- aCandidates.push_back( each_pair.second );
- }
-}
-
-
-/**
- * Function create_rescue_library
- * Creates and returns a PART_LIB object for storing rescued components.
- * @param aFileName - wxFileName to receive the library's file name
- */
-static PART_LIB* create_rescue_library( wxFileName& aFileName )
-{
- wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
- fn.SetName( fn.GetName() + wxT( "-rescue" ) );
- fn.SetExt( SchematicLibraryFileExtension );
- aFileName.SetPath( fn.GetPath() );
- aFileName.SetName( fn.GetName() );
- aFileName.SetExt( wxT( "lib" ) );
- return new PART_LIB( LIBRARY_TYPE_EESCHEMA, fn.GetFullPath() );
-}
-
-
-/**
- * Function rescue_components
- * Rescues components from aCandidates into aLibrary
- * @param aCandidates - list of final rescue candidates to be rescued
- * @param aLibrary - library for them to be rescued into
- * @param aSuffix - part name suffix to apply to them
- */
-static void rescue_components( std::vector<RESCUE_CANDIDATE>& aCandidates, PART_LIB* aLibrary, const wxString &aSuffix )
-{
- BOOST_FOREACH( RESCUE_CANDIDATE& each_candidate, aCandidates )
- {
- LIB_PART new_part( *each_candidate.cache_candidate, aLibrary );
- new_part.SetName( each_candidate.requested_name + aSuffix );
- new_part.RemoveAllAliases();
- aLibrary->AddPart( &new_part );
- }
-}
-
-
-/**
- * Function update_components
- * Update components to reflect changed names of rescued parts.
- * Saves components with the original names to aRescueLog to allow recovering from errors and
- * displaying summary.
- *
- * @param aComponents - a populated list of all components
- * @param aCandidates - list of rescue candidates
- * @param aSuffix - part name suffix
- * @param aRescueLog - rescue log
- */
-static void update_components( std::vector<SCH_COMPONENT*>& aComponents, std::vector<RESCUE_CANDIDATE>& aCandidates,
- const wxString& aSuffix, std::vector<RESCUE_LOG>& aRescueLog )
-{
- BOOST_FOREACH( RESCUE_CANDIDATE& each_candidate, aCandidates )
- {
- BOOST_FOREACH( SCH_COMPONENT* each_component, aComponents )
- {
- if( each_component->GetPartName() != each_candidate.requested_name ) continue;
-
- wxString new_name = each_candidate.requested_name + aSuffix;
- each_component->SetPartName( new_name );
-
- RESCUE_LOG log_item;
- log_item.component = each_component;
- log_item.old_name = each_candidate.requested_name;
- log_item.new_name = new_name;
- aRescueLog.push_back( log_item );
- }
- }
-}
-
-
-bool SCH_EDIT_FRAME::RescueCacheConflicts( bool aRunningOnDemand )
-{
- // Data that will be used throughout the operation
- std::vector<RESCUE_CANDIDATE> candidates;
- std::vector<SCH_COMPONENT*> components;
- PART_LIBS* libs;
- wxString part_name_suffix;
- PROJECT* prj;
-
- // Prepare data
- get_components( components );
- prj = &Prj();
- libs = prj->SchLibs();
- part_name_suffix = wxT( "-RESCUE-" ) + prj->GetProjectName();
-
- // Start!
- find_rescues( components, libs, candidates );
- if( candidates.empty() )
- {
- if( aRunningOnDemand )
- {
- wxMessageDialog dlg( this, _( "There are no conflicting symbols to rescue from the cache." ) );
- dlg.ShowModal();
- }
- return true;
- }
- InvokeDialogRescueEach( this, candidates, components, /* aAskShowAgain */ !aRunningOnDemand );
- wxFileName library_fn;
- std::auto_ptr<PART_LIB> rescue_lib( create_rescue_library( library_fn ) );
- rescue_components( candidates, rescue_lib.get(), part_name_suffix );
-
- // If no components 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( candidates.empty() )
- {
- wxMessageDialog dlg( this, _( "No cached symbols were rescued." ) );
- dlg.ShowModal();
- return true;
- }
-
- if( !save_library( library_fn.GetFullPath(), rescue_lib.get(), this ) )
- {
- // Save failed. Do not update the components.
- return false;
- }
-
- // Update components to reflect changed names
- std::vector<RESCUE_LOG> rescue_log;
- update_components( components, candidates, part_name_suffix, rescue_log );
-
- wxASSERT( !rescue_log.empty() );
-
- // Try inserting the library into the project
- if( insert_library( prj, rescue_lib.get(), 0 ) )
- {
- // Clean up wire ends
- INSTALL_UNBUFFERED_DC( dc, m_canvas );
- GetScreen()->SchematicCleanUp( NULL, &dc );
- m_canvas->Refresh( true );
- OnModify();
-
- return true;
- }
- else
- {
- // Unsuccessful! Restore all the components
- BOOST_FOREACH( RESCUE_LOG& rescue_log_item, rescue_log )
- {
- rescue_log_item.component->SetPartName( rescue_log_item.old_name );
- }
- wxMessageDialog dlg( this, _( "An error occurred while attempting to rescue components. No changes have been made." ) );
- dlg.ShowModal();
- return false;
- }
-}
diff --git a/eeschema/lib_cache_rescue.h b/eeschema/lib_cache_rescue.h
deleted file mode 100644
index b84138f..0000000
--- a/eeschema/lib_cache_rescue.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2015 Chris Pavlina <pavlina.chris@xxxxxxxxx>
- * Copyright (C) 2015 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
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, you may find one here:
- * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
- * or you may search the http://www.gnu.org website for the version 2 license,
- * or you may write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef _LIB_CACHE_RESCUE_H_
-#define _LIB_CACHE_RESCUE_H_
-
-/* This code handles the case where an old schematic has parts that have
- * changed in the system libraries, such that their pins no longer line up.
- * The function of note is a member of SCH_EDIT_FRAME, defined thus:
- *
- * bool SCH_EDIT_FRAME::RescueCacheConflicts( bool aSilentIfNone );
- *
- * When this is called, a list of component names referring to conflicting
- * symbols is compiled. If this list is empty, then the function displays
- * a notification and returns (if aSilentIfNone is true, the notification is
- * silenced).
- *
- * The user is then prompted to select which parts he would like to rescue.
- * Any remaining after he's through are rescued: they are renamed to avoid
- * further conflicts, and then they are copied into a new library. The
- * schematic components are updated to link to these new names, the library
- * is saved, and the library is added to the project at the top of the
- * search path.
- */
-
-#include <vector>
-#include <wx/string.h>
-
-class LIB_PART;
-class SCH_COMPONENT;
-
-class RESCUE_CANDIDATE
-{
-public:
- wxString requested_name;
- LIB_PART* cache_candidate;
- LIB_PART* lib_candidate;
-};
-
-class RESCUE_LOG
-{
-public:
- SCH_COMPONENT* component;
- wxString old_name;
- wxString new_name;
-};
-
-#endif // _LIB_CACHE_RESCUE_H_
diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp
index d3f1205..c959c25 100644
--- a/eeschema/menubar.cpp
+++ b/eeschema/menubar.cpp
@@ -433,8 +433,8 @@ void SCH_EDIT_FRAME::ReCreateMenuBar()
AddMenuItem( toolsMenu,
ID_RESCUE_CACHED,
- _( "&Rescue Cached Components" ),
- _( "Find old components in the project cache and rescue them to a new library" ),
+ _( "&Rescue Old Components" ),
+ _( "Find old components in the project and rename/rescue them" ),
KiBitmap( copycomponent_xpm ) );
toolsMenu->AppendSeparator();
diff --git a/eeschema/project_rescue.cpp b/eeschema/project_rescue.cpp
new file mode 100644
index 0000000..7150928
--- /dev/null
+++ b/eeschema/project_rescue.cpp
@@ -0,0 +1,540 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Chris Pavlina <pavlina.chris@xxxxxxxxx>
+ * Copyright (C) 2015 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <class_drawpanel.h>
+#include <class_library.h>
+#include <confirm.h>
+#include <invoke_sch_dialog.h>
+#include <kicad_device_context.h>
+#include <project_rescue.h>
+#include <sch_component.h>
+#include <sch_sheet.h>
+#include <schframe.h>
+#include <wildcards_and_files_ext.h>
+
+#include <boost/foreach.hpp>
+#include <map>
+
+
+typedef std::pair<SCH_COMPONENT*, wxString> COMPONENT_NAME_PAIR;
+
+
+/**
+ * Function save_library
+ * writes the library out to disk. Returns true on success.
+ *
+ * @param aFileName - Filename to receive the library
+ * @param aLibrary - Library to write
+ * @param aEditFrame - the calling SCH_EDIT_FRAME
+ */
+static bool save_library( const wxString& aFileName, PART_LIB* aLibrary, SCH_EDIT_FRAME* aEditFrame )
+{
+ try
+ {
+ FILE_OUTPUTFORMATTER formatter( aFileName );
+
+ if( !aLibrary->Save( formatter ) )
+ {
+ wxString msg = wxString::Format( _(
+ "An error occurred attempting to save component library '%s'." ),
+ GetChars( aFileName )
+ );
+ DisplayError( aEditFrame, msg );
+ return false;
+ }
+ }
+ catch( ... /* IO_ERROR ioe */ )
+ {
+ wxString msg = wxString::Format( _(
+ "Failed to create component library file '%s'" ),
+ GetChars( aFileName )
+ );
+ 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 ) throw( boost::bad_pointer )
+{
+ 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 );
+ }
+
+ 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 );
+
+ // 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& e )
+ {
+ // 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& e )
+ {
+ // 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 );
+
+ return true;
+}
+
+
+/**
+ * Function get_components
+ * Fills a vector with all of the project's components, to ease iterating over them.
+ *
+ * @param aComponents - a vector that will take the components
+ */
+static void get_components( std::vector<SCH_COMPONENT*>& aComponents )
+{
+ SCH_SCREENS screens;
+ for( SCH_SCREEN* screen = screens.GetFirst(); screen; screen = screens.GetNext() )
+ {
+ for( SCH_ITEM* item = screen->GetDrawItems(); item; item = item->Next() )
+ {
+ if( item->Type() != SCH_COMPONENT_T ) continue;
+ SCH_COMPONENT* component = dynamic_cast<SCH_COMPONENT*>( item );
+ aComponents.push_back( component );
+ }
+ }
+}
+
+
+/**
+ * Function find_component
+ * Search the libraries for the first component with a given name.
+ *
+ * @param aName - name to search for
+ * @param aLibs - the loaded PART_LIBS
+ * @param aCached - whether we are looking for the cached part
+ */
+static LIB_PART* find_component( wxString aName, PART_LIBS* aLibs, bool aCached )
+{
+ LIB_PART *part = NULL;
+
+ BOOST_FOREACH( PART_LIB& each_lib, *aLibs )
+ {
+ if( aCached && !each_lib.IsCache() )
+ continue;
+
+ if( !aCached && each_lib.IsCache() )
+ continue;
+
+ part = each_lib.FindPart( aName );
+ if( part )
+ break;
+ }
+
+ return part;
+}
+
+
+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;
+ BOOST_FOREACH( 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;
+ }
+ }
+}
+
+
+class RESCUE_CASE_CANDIDATE: public RESCUE_CANDIDATE
+{
+ wxString m_requested_name;
+ wxString m_new_name;
+ LIB_PART* m_lib_candidate;
+
+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 )
+ {
+ typedef std::map<wxString, RESCUE_CASE_CANDIDATE> candidate_map_t;
+ candidate_map_t candidate_map;
+
+ BOOST_FOREACH( SCH_COMPONENT* each_component, *( aRescuer.GetComponents() ) )
+ {
+ wxString part_name( each_component->GetPartName() );
+
+ LIB_PART* case_sensitive_match = find_component( part_name, aRescuer.GetLibs(), /* aCached */ true );
+ std::vector<LIB_ALIAS*> case_insensitive_matches;
+ aRescuer.GetLibs()->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(),
+ case_insensitive_matches[0]->GetPart() );
+ candidate_map[part_name] = candidate;
+ }
+
+ // Now, dump the map into aCandidates
+ BOOST_FOREACH( const candidate_map_t::value_type& each_pair, candidate_map )
+ {
+ aCandidates.push_back( new RESCUE_CASE_CANDIDATE( each_pair.second ) );
+ }
+ }
+
+ /**
+ * 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() {}
+
+ virtual wxString GetRequestedName() const { return m_requested_name; }
+ virtual wxString GetNewName() const { return m_new_name; }
+ virtual LIB_PART* GetLibCandidate() const { return m_lib_candidate; }
+ virtual wxString GetActionDescription() const
+ {
+ wxString action;
+ action.Printf( _( "Rename to %s" ), m_new_name );
+ return action;
+ }
+
+ virtual bool PerformAction( RESCUER* aRescuer )
+ {
+ BOOST_FOREACH( SCH_COMPONENT* each_component, *aRescuer->GetComponents() )
+ {
+ if( each_component->GetPartName() != m_requested_name ) continue;
+ each_component->SetPartName( m_new_name );
+ aRescuer->LogRescue( each_component, m_requested_name, m_new_name );
+ }
+ return true;
+ }
+};
+
+
+class RESCUE_CACHE_CANDIDATE: public RESCUE_CANDIDATE
+{
+ wxString m_requested_name;
+ wxString m_new_name;
+ LIB_PART* m_cache_candidate;
+ LIB_PART* m_lib_candidate;
+
+ static std::auto_ptr<PART_LIB> m_rescue_lib;
+ static wxFileName m_library_fn;
+
+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 )
+ {
+ typedef std::map<wxString, RESCUE_CACHE_CANDIDATE> candidate_map_t;
+ candidate_map_t candidate_map;
+
+ wxString part_name_suffix = wxT( "-RESCUE-" ) + aRescuer.GetPrj()->GetProjectName();
+
+ BOOST_FOREACH( SCH_COMPONENT* each_component, *( aRescuer.GetComponents() ) )
+ {
+ wxString part_name( each_component->GetPartName() );
+
+ LIB_PART* cache_match = find_component( part_name, aRescuer.GetLibs(), /* aCached */ true );
+ LIB_PART* lib_match = find_component( part_name, aRescuer.GetLibs(), /* aCached */ false );
+
+ // 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 ))
+ continue;
+
+ RESCUE_CACHE_CANDIDATE candidate(
+ part_name, part_name + part_name_suffix,
+ cache_match, lib_match );
+ candidate_map[part_name] = candidate;
+ }
+
+ // Now, dump the map into aCandidates
+ BOOST_FOREACH( const candidate_map_t::value_type& each_pair, candidate_map )
+ {
+ aCandidates.push_back( new RESCUE_CACHE_CANDIDATE( each_pair.second ) );
+ }
+ }
+
+ /**
+ * 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() {}
+
+ virtual wxString GetRequestedName() const { return m_requested_name; }
+ virtual wxString GetNewName() const { return m_new_name; }
+ virtual LIB_PART* GetCacheCandidate() const { return m_cache_candidate; }
+ virtual LIB_PART* GetLibCandidate() const { return m_lib_candidate; }
+ virtual wxString 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()
+ {
+ wxFileName fn( g_RootSheet->GetScreen()->GetFileName() );
+ fn.SetName( fn.GetName() + wxT( "-rescue" ) );
+ fn.SetExt( SchematicLibraryFileExtension );
+ m_library_fn.SetPath( fn.GetPath() );
+ m_library_fn.SetName( fn.GetName() );
+ m_library_fn.SetExt( wxT( "lib" ) );
+
+ std::auto_ptr<PART_LIB> rescue_lib( new PART_LIB( LIBRARY_TYPE_EESCHEMA,
+ fn.GetFullPath() ) );
+
+ m_rescue_lib = rescue_lib;
+ }
+
+ virtual bool PerformAction( RESCUER* aRescuer )
+ {
+ LIB_PART new_part( *m_cache_candidate, m_rescue_lib.get() );
+ new_part.SetName( m_new_name );
+ new_part.RemoveAllAliases();
+ RESCUE_CACHE_CANDIDATE::m_rescue_lib.get()->AddPart( &new_part );
+
+ BOOST_FOREACH( SCH_COMPONENT* each_component, *aRescuer->GetComponents() )
+ {
+ if( each_component->GetPartName() != m_requested_name ) continue;
+ each_component->SetPartName( m_new_name );
+ 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 )
+ {
+
+ if( !save_library( m_library_fn.GetFullPath(), m_rescue_lib.get(), aEditFrame ) )
+ return false;
+ return insert_library( aProject, m_rescue_lib.get(), 0 );
+ }
+};
+
+std::auto_ptr<PART_LIB> RESCUE_CACHE_CANDIDATE::m_rescue_lib;
+wxFileName RESCUE_CACHE_CANDIDATE::m_library_fn;
+
+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 )
+{
+ RESCUE_LOG logitem;
+ logitem.component = aComponent;
+ logitem.old_name = aOldName;
+ logitem.new_name = aNewName;
+ m_rescue_log.push_back( logitem );
+}
+
+
+bool RESCUER::DoRescues()
+{
+ BOOST_FOREACH( RESCUE_CANDIDATE* each_candidate, m_chosen_candidates )
+ {
+ if( ! each_candidate->PerformAction( this ) )
+ return false;
+ }
+ return true;
+}
+
+
+void RESCUER::UndoRescues()
+{
+ BOOST_FOREACH( RESCUE_LOG& each_logitem, m_rescue_log )
+ {
+ each_logitem.component->SetPartName( each_logitem.old_name );
+ }
+}
+
+
+bool SCH_EDIT_FRAME::RescueProject( bool aRunningOnDemand )
+{
+ // Data that will be used throughout the operation
+ std::vector<RESCUE_CANDIDATE> candidates;
+ wxString part_name_suffix;
+
+ RESCUER rescuer( *this, Prj() );
+
+ rescuer.FindCandidates();
+
+ if( ! rescuer.GetCandidateCount() )
+ {
+ if( aRunningOnDemand )
+ {
+ wxMessageDialog dlg( this, _( "This project has nothing to rescue." ) );
+ dlg.ShowModal();
+ }
+ return true;
+ }
+
+ rescuer.RemoveDuplicates();
+
+ rescuer.InvokeDialog( !aRunningOnDemand );
+
+ // If no components 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() )
+ {
+ wxMessageDialog dlg( this, _( "No symbols were rescued." ) );
+ dlg.ShowModal();
+ return true;
+ }
+
+ RESCUE_CACHE_CANDIDATE::OpenRescueLibrary();
+
+ if( !rescuer.DoRescues() )
+ {
+ rescuer.UndoRescues();
+ return false;
+ }
+
+ RESCUE_CACHE_CANDIDATE::WriteRescueLibrary( this, &Prj() );
+
+ Prj().SetElem( PROJECT::ELEM_SCH_PART_LIBS, NULL );
+
+ // Clean up wire ends
+ INSTALL_UNBUFFERED_DC( dc, m_canvas );
+ GetScreen()->SchematicCleanUp( NULL, &dc );
+ m_canvas->Refresh( true );
+ OnModify();
+
+ return true;
+}
diff --git a/eeschema/project_rescue.h b/eeschema/project_rescue.h
new file mode 100644
index 0000000..bc961da
--- /dev/null
+++ b/eeschema/project_rescue.h
@@ -0,0 +1,190 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 Chris Pavlina <pavlina.chris@xxxxxxxxx>
+ * Copyright (C) 2015 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
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef _LIB_CACHE_RESCUE_H_
+#define _LIB_CACHE_RESCUE_H_
+
+/* This code handles the case where an old schematic was made before
+ * various changes were made, either to KiCad or to the libraries, and
+ * the project needs to be recovered. The function of note is a member
+ * of SCH_EDIT_FRAME, defined thus:
+ *
+ * bool SCH_EDIT_FRAME::RescueProject( bool aSilentIfNone );
+ *
+ * When this is called, a list of problematic components is compiled. If
+ * this list is empty, then the function displays a notification and returns
+ * (if aSilentIfNone is true, the notification is silenced).
+ */
+
+#include <schframe.h>
+
+#include <vector>
+#include <wx/string.h>
+#include <boost/ptr_container/ptr_vector.hpp>
+
+class LIB_PART;
+class SCH_COMPONENT;
+class RESCUER;
+
+enum RESCUE_TYPE
+{
+ RESCUE_CONFLICT,
+ RESCUE_CASE,
+};
+
+class RESCUE_CANDIDATE
+{
+public:
+ /**
+ * Function GetRequestedName
+ * Get the name that was originally requested in the schematic
+ */
+ virtual wxString GetRequestedName() const = 0;
+
+ /**
+ * Function GetNewName
+ * Get the name we're proposing changing it to
+ */
+ virtual wxString GetNewName() const = 0;
+
+ /**
+ * 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; }
+
+ /**
+ * 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.
+ */
+ virtual bool PerformAction( RESCUER* aRescuer ) = 0;
+};
+
+class RESCUE_LOG
+{
+public:
+ SCH_COMPONENT* component;
+ wxString old_name;
+ wxString new_name;
+};
+
+class RESCUER
+{
+ friend class DIALOG_RESCUE_EACH;
+
+ std::vector<SCH_COMPONENT*> m_components;
+ PART_LIBS* m_libs;
+ PROJECT* m_prj;
+ SCH_EDIT_FRAME* m_edit_frame;
+
+ boost::ptr_vector<RESCUE_CANDIDATE> m_all_candidates;
+ std::vector<RESCUE_CANDIDATE*> m_chosen_candidates;
+
+ std::vector<RESCUE_LOG> m_rescue_log;
+
+public:
+ RESCUER( SCH_EDIT_FRAME& aEditFrame, PROJECT& aProject );
+
+ /**
+ * Function FindCandidates
+ * Populate the RESCUER with all possible candidates.
+ */
+ void FindCandidates();
+
+ /**
+ * Function RemoveDuplicates
+ * Filter out duplicately named rescue candidates.
+ */
+ void RemoveDuplicates();
+
+ /**
+ * Function GetCandidateCount
+ */
+ size_t GetCandidateCount() { return m_all_candidates.size(); }
+
+ /**
+ * Function GetChosenCandidateCount
+ */
+ size_t GetChosenCandidateCount() { return m_chosen_candidates.size(); }
+
+ /**
+ * Function GetComponents
+ */
+ std::vector<SCH_COMPONENT*>* GetComponents() { return &m_components; }
+
+ /**
+ * Function GetLibs
+ */
+ PART_LIBS* GetLibs() { return m_libs; }
+
+ /**
+ * Function GetPrj
+ */
+ PROJECT* GetPrj() { return m_prj; }
+
+ /**
+ * 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.
+ */
+ 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();
+};
+
+#endif // _LIB_CACHE_RESCUE_H_
diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp
index 769d6cd..9053a56 100644
--- a/eeschema/schframe.cpp
+++ b/eeschema/schframe.cpp
@@ -243,7 +243,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
EVT_TOOL( ID_RUN_LIBRARY, SCH_EDIT_FRAME::OnOpenLibraryEditor )
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::OnRescueCached )
+ EVT_TOOL( ID_RESCUE_CACHED, SCH_EDIT_FRAME::OnRescueProject )
EVT_TOOL( ID_RUN_PCB, SCH_EDIT_FRAME::OnOpenPcbnew )
EVT_TOOL( ID_RUN_PCB_MODULE_EDITOR, SCH_EDIT_FRAME::OnOpenPcbModuleEditor )
@@ -1120,9 +1120,9 @@ void SCH_EDIT_FRAME::OnOpenLibraryEditor( wxCommandEvent& event )
}
}
-void SCH_EDIT_FRAME::OnRescueCached( wxCommandEvent& event )
+void SCH_EDIT_FRAME::OnRescueProject( wxCommandEvent& event )
{
- RescueCacheConflicts( true );
+ RescueProject( true );
}
void SCH_EDIT_FRAME::OnExit( wxCommandEvent& event )
diff --git a/eeschema/schframe.h b/eeschema/schframe.h
index 9f55bb1..38fb7e5 100644
--- a/eeschema/schframe.h
+++ b/eeschema/schframe.h
@@ -832,7 +832,7 @@ private:
void OnOpenPcbModuleEditor( wxCommandEvent& event );
void OnOpenCvpcb( wxCommandEvent& event );
void OnOpenLibraryEditor( wxCommandEvent& event );
- void OnRescueCached( wxCommandEvent& event );
+ void OnRescueProject( wxCommandEvent& event );
void OnPreferencesOptions( wxCommandEvent& event );
void OnCancelCurrentCommand( wxCommandEvent& aEvent );
@@ -1307,10 +1307,13 @@ public:
bool CreateArchiveLibrary( const wxString& aFileName );
/**
- * Function RescueCacheConflicts
- * exports components from the '-cache' library that conflict with parts
- * in the project libraries to a new library, renaming them to add a suffix
- * of the root document's name to avoid conflicts.
+ * Function RescueProject
+ * performs rescue operations to recover old projects from before certain
+ * changes were made.
+ *
+ * - Exports cached symbols that conflict with new symbols to a separate
+ * library
+ * - Renames symbols named before libraries were case sensitive
*
* @param aRunningOnDemand - indicates whether the tool has been called up by the user
* (as opposed to being run automatically). If true, an information dialog is
@@ -1318,7 +1321,7 @@ public:
* if there are no components to rescue, and a "Never Show Again" button is
* displayed.
*/
- bool RescueCacheConflicts( bool aRunningOnDemand );
+ bool RescueProject( bool aRunningOnDemand );
/**
* Function PrintPage
References