From 80eb5460f9b60486cbcc0b60b3f623cf3dad4951 Mon Sep 17 00:00:00 2001 From: Chris Pavlina Date: Mon, 22 Jun 2015 11:38:54 -0400 Subject: [PATCH] Eeschema: component library rescue improvements. * Fix case sensitive component library name searches * Factor out rescue code into a generic rescue project class. --- eeschema/CMakeLists.txt | 2 +- eeschema/class_library.cpp | 2 +- eeschema/dialogs/dialog_rescue_each.cpp | 86 ++- eeschema/dialogs/dialog_rescue_each_base.cpp | 2 +- eeschema/dialogs/dialog_rescue_each_base.fbp | 2 +- eeschema/files-io.cpp | 6 +- eeschema/invoke_sch_dialog.h | 9 +- eeschema/lib_cache_rescue.cpp | 385 ------------- eeschema/lib_cache_rescue.h | 69 --- eeschema/menubar.cpp | 4 +- eeschema/project_rescue.cpp | 540 +++++++++++++++++++ eeschema/project_rescue.h | 190 +++++++ eeschema/schframe.cpp | 6 +- eeschema/schframe.h | 15 +- 14 files changed, 790 insertions(+), 528 deletions(-) delete mode 100644 eeschema/lib_cache_rescue.cpp delete mode 100644 eeschema/lib_cache_rescue.h create mode 100644 eeschema/project_rescue.cpp create mode 100644 eeschema/project_rescue.h diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 0982735632..d6cc1cd923 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 4fac061ba5..bbda65770b 100644 --- a/eeschema/class_library.cpp +++ b/eeschema/class_library.cpp @@ -38,7 +38,7 @@ #include #include #include -#include +#include //#include #include diff --git a/eeschema/dialogs/dialog_rescue_each.cpp b/eeschema/dialogs/dialog_rescue_each.cpp index 8b896f41ee..31c424a357 100644 --- a/eeschema/dialogs/dialog_rescue_each.cpp +++ b/eeschema/dialogs/dialog_rescue_each.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include 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& aCandidates, - std::vector& 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* m_Candidates; - std::vector* 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& aCandidates, - std::vector& 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 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 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::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& aCandidates, - std::vector& 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 2e7549d7b0..99cdbcc0eb 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 dee774b535..fcc78827eb 100644 --- a/eeschema/dialogs/dialog_rescue_each_base.fbp +++ b/eeschema/dialogs/dialog_rescue_each_base.fbp @@ -208,7 +208,7 @@ 0 0 wxID_ANY - Symbols with cache/library conflicts: + Symbols to update: 0 diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 39922f595e..3bf97b94b4 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include @@ -307,7 +307,7 @@ bool SCH_EDIT_FRAME::OpenProjectFiles( const std::vector& 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& 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 0a9cbe42eb..e4395ee2b3 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& aCandidates, - std::vector& 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 da74997ee1..0000000000 --- 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 - * 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -typedef std::pair 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( 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 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& 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( 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& aComponents, PART_LIBS* aLibs, - std::vector& 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 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& 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& aComponents, std::vector& aCandidates, - const wxString& aSuffix, std::vector& 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 candidates; - std::vector 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 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; - 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 b84138f4bb..0000000000 --- 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 - * 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 -#include - -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 23ae7fffb1..f07ccd2116 100644 --- a/eeschema/menubar.cpp +++ b/eeschema/menubar.cpp @@ -431,8 +431,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 0000000000..7150928532 --- /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 + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +typedef std::pair 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( 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 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& 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( 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 names_seen; + + for( boost::ptr_vector::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& aCandidates ) + { + typedef std::map 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 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 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& aCandidates ) + { + typedef std::map 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 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 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 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 0000000000..bc961da326 --- /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 + * 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 + +#include +#include +#include + +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 m_components; + PART_LIBS* m_libs; + PROJECT* m_prj; + SCH_EDIT_FRAME* m_edit_frame; + + boost::ptr_vector m_all_candidates; + std::vector m_chosen_candidates; + + std::vector 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* 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 769d6cdc1a..9053a56b87 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 9f55bb1192..38fb7e59b7 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