diff --git a/eeschema/symbol_editor/symbol_edit_frame.cpp b/eeschema/symbol_editor/symbol_edit_frame.cpp index 5a5d8ffc80..a7704c1d35 100644 --- a/eeschema/symbol_editor/symbol_edit_frame.cpp +++ b/eeschema/symbol_editor/symbol_edit_frame.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -1307,3 +1308,123 @@ void SYMBOL_EDIT_FRAME::LoadSymbolFromSchematic( const std::unique_ptr DisplaySymbolDatasheet(); Refresh(); } + + +bool SYMBOL_EDIT_FRAME::addLibTableEntry( const wxString& aLibFile, TABLE_SCOPE aScope ) +{ + wxFileName fn = aLibFile; + wxFileName libTableFileName( Prj().GetProjectPath(), + SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() ); + wxString libNickname = fn.GetName(); + SYMBOL_LIB_TABLE* libTable = Prj().SchSymbolLibTable(); + const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables(); + + if( libTable->HasLibrary( libNickname ) ) + { + wxString tmp; + int suffix = 1; + + while( libTable->HasLibrary( libNickname ) ) + { + tmp.Printf( "%s%d", fn.GetName(), suffix ); + libNickname = tmp; + suffix += 1; + } + } + + SYMBOL_LIB_TABLE_ROW* row = new SYMBOL_LIB_TABLE_ROW(); + row->SetNickName( libNickname ); + + wxString normalizedPath = NormalizePath( aLibFile, &envVars, Prj().GetProjectPath() ); + + if( aScope == GLOBAL_LIB_TABLE ) + { + libTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable(); + libTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName(); + + // We cannot normalize against the current project path when saving to global table. + normalizedPath = NormalizePath( aLibFile, &envVars, wxEmptyString ); + } + + if( normalizedPath.IsEmpty() ) + normalizedPath = aLibFile; + + row->SetFullURI( normalizedPath ); + + wxCHECK( libTable->InsertRow( row ), false ); + + try + { + libTable->Save( libTableFileName.GetFullPath() ); + } + catch( const IO_ERROR& ioe ) + { + wxString msg; + msg.Printf( _( "Error saving %s symbol library table." ), + ( aScope == GLOBAL_LIB_TABLE ) ? _( "global" ) : _( "project" ) ); + + wxMessageDialog dlg( this, msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); + dlg.SetExtendedMessage( ioe.What() ); + dlg.ShowModal(); + + return false; + } + + return true; +} + + +bool SYMBOL_EDIT_FRAME::replaceLibTableEntry( const wxString& aLibNickname, + const wxString& aLibFile ) +{ + // Check the global library table first because checking the project library table + // checks the global library table as well due to library chaining. + bool isGlobalTable = true; + wxFileName libTableFileName = SYMBOL_LIB_TABLE::GetGlobalTableFileName();; + const ENV_VAR_MAP& envVars = Pgm().GetLocalEnvVariables(); + SYMBOL_LIB_TABLE* libTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable(); + SYMBOL_LIB_TABLE_ROW* row = libTable->FindRow( aLibNickname ); + + if( !row ) + { + libTableFileName.SetPath( Prj().GetProjectPath() ); + libTableFileName.SetName( SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() ); + libTable = Prj().SchSymbolLibTable(); + isGlobalTable = false; + row = libTable->FindRow( aLibNickname ); + } + + wxCHECK( row, false ); + + wxString projectPath; + + if( !isGlobalTable ) + projectPath = Prj().GetProjectPath(); + + wxString normalizedPath = NormalizePath( aLibFile, &envVars, projectPath ); + + if( normalizedPath.IsEmpty() ) + normalizedPath = aLibFile; + + row->SetFullURI( normalizedPath ); + row->SetType( "KiCad" ); + + try + { + libTable->Save( libTableFileName.GetFullPath() ); + } + catch( const IO_ERROR& ioe ) + { + wxString msg; + msg.Printf( _( "Error saving %s symbol library table." ), + ( isGlobalTable ) ? _( "global" ) : _( "project" ) ); + + wxMessageDialog dlg( this, msg, _( "File Save Error" ), wxOK | wxICON_ERROR ); + dlg.SetExtendedMessage( ioe.What() ); + dlg.ShowModal(); + + return false; + } + + return true; +} diff --git a/eeschema/symbol_editor/symbol_edit_frame.h b/eeschema/symbol_editor/symbol_edit_frame.h index 6df2b34bea..6fd47f1227 100644 --- a/eeschema/symbol_editor/symbol_edit_frame.h +++ b/eeschema/symbol_editor/symbol_edit_frame.h @@ -469,6 +469,35 @@ private: ///< Rename LIB_PART aliases to avoid conflicts before adding a symbol to a library. void ensureUniqueName( LIB_PART* aPart, const wxString& aLibrary ); + enum TABLE_SCOPE + { + GLOBAL_LIB_TABLE, + PROJECT_LIB_TABLE + }; + + /** + * Add \a aLibFile to the symbol library table defined by \a aScope. + * + * @note The library defined by \a aLibFile must be a KiCad (s-expression) library. + * + * @param aLibFile is the full path and file name of the symbol library to add to the table. + * @param aScope defines if \a aLibFile is added to the global or project library table. + * @return true if successful or false if a failure occurs. + */ + bool addLibTableEntry( const wxString& aLibFile, TABLE_SCOPE aScope = GLOBAL_LIB_TABLE ); + + /** + * Replace the file path of the symbol library table entry \a aLibNickname with \a aLibFile. + * + * @note The library defined by \a aLibFile must be a KiCad (s-expression) library. + * + * @param aLibNickmane is the nickname of an existing library table entry. + * @param aLibFile is the full path and file name of the symbol library to replace in the + * table. + * @return true if successful or false if a failure occurs. + */ + bool replaceLibTableEntry( const wxString& aLibNickname, const wxString& aLibFile ); + DECLARE_EVENT_TABLE() public: diff --git a/eeschema/symbol_editor/symbol_editor.cpp b/eeschema/symbol_editor/symbol_editor.cpp index 356a2c9057..b518eb81e3 100644 --- a/eeschema/symbol_editor/symbol_editor.cpp +++ b/eeschema/symbol_editor/symbol_editor.cpp @@ -45,6 +45,92 @@ #include +/** + * Helper control to inquire user what to do on library save as operation. + */ +class SAVE_AS_HELPER : public wxPanel +{ +public: + SAVE_AS_HELPER( wxWindow* aParent ) : + wxPanel( aParent ) + { + m_simpleSaveAs = new wxRadioButton( this, wxID_ANY, _( "Normal save as operation" ), + wxDefaultPosition, wxDefaultSize, wxRB_GROUP ); + m_simpleSaveAs->SetToolTip( _( "Do not perform any additional operations after saving " + "library." ) ); + m_replaceTableEntry = new wxRadioButton( this, wxID_ANY, + _( "Replace library table entry" ) ); + m_replaceTableEntry->SetToolTip( _( "Replacy symbol library table entry with new library." + "\n\nThe original library will no longer be avaliable " + "for use." ) ); + m_addGlobalTableEntry = new wxRadioButton( this, wxID_ANY, + _( "Add new global library table entry" ) ); + m_addGlobalTableEntry->SetToolTip( _( "Add new entry to the global symbol library table." + "\n\nThe symbol library table nickname is suffixed " + "with\nan integer to ensure no duplicate table " + "entries." ) ); + m_addProjectTableEntry = new wxRadioButton( this, wxID_ANY, + _( "Add new project library table entry" ) ); + m_addProjectTableEntry->SetToolTip( _( "Add new entry to the project symbol library table." + "\n\nThe symbol library table nickname is suffixed " + "with\nan integer to ensure no duplicate table " + "entries." ) ); + + wxBoxSizer* sizer = new wxBoxSizer( wxHORIZONTAL ); + sizer->Add( m_simpleSaveAs, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 5 ); + sizer->Add( m_replaceTableEntry, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5 ); + sizer->Add( m_addGlobalTableEntry, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5 ); + sizer->Add( m_addProjectTableEntry, 0, wxRIGHT | wxALIGN_CENTER_VERTICAL, 5 ); + + SetSizerAndFit( sizer ); + } + + enum SAH_TYPE + { + UNDEFINED = -1, + NORMAL_SAVE_AS, + REPLACE_TABLE_ENTRY, + ADD_GLOBAL_TABLE_ENTRY, + ADD_PROJECT_TABLE_ENTRY + }; + + SAH_TYPE GetOption() const + { + if( m_simpleSaveAs->GetValue() ) + return SAH_TYPE::NORMAL_SAVE_AS; + else if( m_replaceTableEntry->GetValue() ) + return SAH_TYPE::REPLACE_TABLE_ENTRY; + else if( m_addGlobalTableEntry->GetValue() ) + return ADD_GLOBAL_TABLE_ENTRY; + else if( m_addProjectTableEntry->GetValue() ) + return ADD_PROJECT_TABLE_ENTRY; + else + return UNDEFINED; + } + + /** + * Create a new panel to add to a wxFileDialog object. + * + * The caller owns the created object and is responsible for deleting it. + * + * @param aParent is the parent window that will own the created object. + * @return the newly created panel to add to the wxFileDialog. + */ + static wxWindow* Create( wxWindow* aParent ) + { + wxCHECK( aParent, nullptr ); + + return new SAVE_AS_HELPER( aParent ); + } + +private: + wxRadioButton* m_simpleSaveAs; + wxRadioButton* m_replaceTableEntry; + wxRadioButton* m_addGlobalTableEntry; + wxRadioButton* m_addProjectTableEntry; +}; + + void SYMBOL_EDIT_FRAME::updateTitle() { wxString lib = GetCurLib(); @@ -1026,6 +1112,7 @@ bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile ) { wxFileName fn; wxString msg; + SAVE_AS_HELPER::SAH_TYPE type = SAVE_AS_HELPER::SAH_TYPE::UNDEFINED; SCH_IO_MGR::SCH_FILE_T fileType = SCH_IO_MGR::SCH_FILE_T::SCH_KICAD; PROJECT& prj = Prj(); @@ -1056,6 +1143,8 @@ bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile ) default_path, fn.GetFullName(), wildcards, wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); + dlg.SetExtraControlCreator( &SAVE_AS_HELPER::Create ); + if( dlg.ShowModal() == wxID_CANCEL ) return false; @@ -1065,6 +1154,11 @@ bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile ) if( fn.GetExt().IsEmpty() ) fn.SetExt( KiCadSymbolLibFileExtension ); + + const SAVE_AS_HELPER* sah = dynamic_cast( dlg.GetExtraControl() ); + wxCHECK( sah, false ); + + type = sah->GetOption(); } else { @@ -1091,7 +1185,40 @@ bool SYMBOL_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile ) } if( !aNewFile ) + { m_libMgr->ClearLibraryModified( aLibrary ); + } + else + { + bool resyncLibTree = false; + wxString originalLibNickname = getTargetLib(); + + switch( type ) + { + case SAVE_AS_HELPER::SAH_TYPE::REPLACE_TABLE_ENTRY: + resyncLibTree = replaceLibTableEntry( originalLibNickname, fn.GetFullPath() ); + break; + + case SAVE_AS_HELPER::SAH_TYPE::ADD_GLOBAL_TABLE_ENTRY: + resyncLibTree = addLibTableEntry( fn.GetFullPath() ); + break; + + case SAVE_AS_HELPER::SAH_TYPE::ADD_PROJECT_TABLE_ENTRY: + resyncLibTree = addLibTableEntry( fn.GetFullPath(), PROJECT_LIB_TABLE ); + break; + + case SAVE_AS_HELPER::SAH_TYPE::NORMAL_SAVE_AS: + default: + break; + } + + if( resyncLibTree ) + { + FreezeSearchTree(); + SyncLibraries( true ); + ThawSearchTree(); + } + } ClearMsgPanel(); msg.Printf( _( "Symbol library file \"%s\" saved" ), fn.GetFullPath() );