From a789b735e98bc076902f5ad09b4995c08a080bcf Mon Sep 17 00:00:00 2001 From: Maciej Suminski Date: Sun, 12 Nov 2017 18:55:20 +0100 Subject: [PATCH] Library Manager: logic --- eeschema/CMakeLists.txt | 3 + eeschema/eeschema_id.h | 28 +- eeschema/lib_export.cpp | 34 +- eeschema/lib_manager.cpp | 658 +++++++++++++++++++++++++++++ eeschema/lib_manager.h | 347 +++++++++++++++ eeschema/lib_manager_adapter.cpp | 207 +++++++++ eeschema/lib_manager_adapter.h | 78 ++++ eeschema/libedit.cpp | 416 +++++++++--------- eeschema/libeditframe.cpp | 318 +++++++++----- eeschema/libeditframe.h | 175 +++++--- eeschema/sch_base_frame.h | 2 +- eeschema/tool_lib.cpp | 4 +- eeschema/widgets/cmp_tree_pane.cpp | 102 +++++ eeschema/widgets/cmp_tree_pane.h | 57 +++ 14 files changed, 1988 insertions(+), 441 deletions(-) create mode 100644 eeschema/lib_manager.cpp create mode 100644 eeschema/lib_manager.h create mode 100644 eeschema/lib_manager_adapter.cpp create mode 100644 eeschema/lib_manager_adapter.h create mode 100644 eeschema/widgets/cmp_tree_pane.cpp create mode 100644 eeschema/widgets/cmp_tree_pane.h diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index 90ca44f013..a2e5924d3e 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -83,6 +83,7 @@ set( EESCHEMA_DLGS ) set( EESCHEMA_WIDGETS + widgets/cmp_tree_pane.cpp widgets/component_tree.cpp widgets/widget_eeschema_color_config.cpp widgets/pin_shape_combobox.cpp @@ -143,6 +144,8 @@ set( EESCHEMA_SRCS lib_draw_item.cpp lib_export.cpp lib_field.cpp + lib_manager.cpp + lib_manager_adapter.cpp lib_pin.cpp lib_polyline.cpp lib_rectangle.cpp diff --git a/eeschema/eeschema_id.h b/eeschema/eeschema_id.h index af4812e3c3..7a971f5852 100644 --- a/eeschema/eeschema_id.h +++ b/eeschema/eeschema_id.h @@ -185,32 +185,22 @@ enum id_eeschema_frm /* Library editor main menubar IDs. */ ID_LIBEDIT_DIMENSIONS, + /* Library editor: library edit events */ + ID_LIBEDIT_NEW_LIBRARY, + ID_LIBEDIT_ADD_LIBRARY, + ID_LIBEDIT_SAVE_LIBRARY, + ID_LIBEDIT_SAVE_LIBRARY_AS, + ID_LIBEDIT_SAVE_ALL_LIBS, + ID_LIBEDIT_REVERT_LIBRARY, + /* Library editor: part edit events */ ID_LIBEDIT_NEW_PART, ID_LIBEDIT_EDIT_PART, ID_LIBEDIT_IMPORT_PART, ID_LIBEDIT_EXPORT_PART, ID_LIBEDIT_SAVE_PART, - ID_LIBEDIT_SAVE_CURRENT_PART, - ID_LIBEDIT_REMOVE_PART, - ID_LIBEDIT_CUT_PART, - ID_LIBEDIT_COPY_PART, - ID_LIBEDIT_PASTE_PART, - ID_LIBEDIT_RENAME_PART, ID_LIBEDIT_REVERT_PART, - ID_LIBEDIT_DELETE_PART, - - /* Library editor: library edit events */ - - ID_LIBEDIT_NEW_LIBRARY, - ID_LIBEDIT_ADD_LIBRARY, - ID_LIBEDIT_SAVE_LIBRARY, - ID_LIBEDIT_SAVE_LIBRARY_AS, - ID_LIBEDIT_SAVE_CURRENT_LIB, // TODO merge with save_library? - ID_LIBEDIT_SAVE_CURRENT_LIB_AS, - ID_LIBEDIT_SAVE_ALL_LIBS, - ID_LIBEDIT_REVERT_LIBRARY, - ID_LIBEDIT_REMOVE_LIBRARY, + ID_LIBEDIT_REMOVE_PART, /* Library editor horizontal toolbar IDs. */ ID_DE_MORGAN_NORMAL_BUTT, diff --git a/eeschema/lib_export.cpp b/eeschema/lib_export.cpp index feb160d25b..4de3e16a55 100644 --- a/eeschema/lib_export.cpp +++ b/eeschema/lib_export.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -46,6 +47,7 @@ void LIB_EDIT_FRAME::OnImportPart( wxCommandEvent& event ) { wxString msg; m_lastDrawItem = NULL; + wxString libName = getTargetLib(); wxFileDialog dlg( this, _( "Import Symbol" ), m_mruPath, wxEmptyString, SchematicLibraryFileWildcard(), @@ -54,13 +56,13 @@ void LIB_EDIT_FRAME::OnImportPart( wxCommandEvent& event ) if( dlg.ShowModal() == wxID_CANCEL ) return; - wxFileName fn = dlg.GetPath(); - + wxFileName fn = dlg.GetPath(); m_mruPath = fn.GetPath(); wxArrayString symbols; SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) ); + // TODO dialog to select the part to be imported if there is more than one try { pi->EnumerateSymbolLib( symbols, fn.GetFullPath() ); @@ -79,25 +81,25 @@ void LIB_EDIT_FRAME::OnImportPart( wxCommandEvent& event ) return; } - LIB_ALIAS* entry = pi->LoadSymbol( fn.GetFullPath(), symbols[0] ); + wxString symbolName = symbols[0]; + LIB_ALIAS* entry = pi->LoadSymbol( fn.GetFullPath(), symbolName ); - if( LoadOneLibraryPartAux( entry, fn.GetFullPath() ) ) + if( m_libMgr->PartExists( symbols[0], libName ) ) { - DisplayLibInfos(); - GetScreen()->ClearUndoRedoList(); - Zoom_Automatique( false ); - - // This effectively adds a new symbol to the library. Set the modified flag so the - // save library toolbar button and menu entry are enabled. - OnModify(); + msg.Printf( _( "Symbol '%s' already exists in library '%s'." ), symbolName, libName ); + DisplayError( this, msg ); + return; } + + m_libMgr->UpdatePart( entry->GetPart(), libName ); + loadPart( symbolName, libName, 1 ); } void LIB_EDIT_FRAME::OnExportPart( wxCommandEvent& event ) { - wxString msg, title; - LIB_PART* part = GetCurPart(); + wxString msg, title; + LIB_PART* part = getTargetPart(); if( !part ) { @@ -173,12 +175,6 @@ void LIB_EDIT_FRAME::OnExportPart( wxCommandEvent& event ) } m_mruPath = fn.GetPath(); - - /// @todo Give the user a choice to add the new library to the symbol library table. - DisplayInfoMessage( this, _( "This library will not be available until it is added to the " - "symbol library table." ) ); - - GetScreen()->ClrModify(); m_drawItem = m_lastDrawItem = NULL; msg.Printf( _( "Symbol '%s' saved in library '%s'" ), part->GetName(), fn.GetFullPath() ); diff --git a/eeschema/lib_manager.cpp b/eeschema/lib_manager.cpp new file mode 100644 index 0000000000..66dbb227a7 --- /dev/null +++ b/eeschema/lib_manager.cpp @@ -0,0 +1,658 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * 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 3 + * 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: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 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 + + +LIB_MANAGER::LIB_MANAGER( LIB_EDIT_FRAME& aFrame ) + : m_frame( aFrame ), m_symbolTable( aFrame.Prj().SchSymbolLibTable() ) +{ + m_adapter = LIB_MANAGER_ADAPTER::Create( this ); + m_adapter->ShowUnits( true ); + Sync(); +} + + +void LIB_MANAGER::Sync() +{ + // TODO handle renaming libraries in the sym-lib-table dialog + // TODO using filepath as the key? + // TODO should not be compared with symboltable, but between the adapter and manager + // TODO move to treepane? + getAdapter()->Sync(); + + //int libTableHash = m_symbolTable->GetModifyHash(); + + //if( m_syncHash != libTableHash ) + //{ + //getAdapter()->Sync(); + //m_syncHash = libTableHash; + //} +} + + +int LIB_MANAGER::GetHash() const +{ + int hash = m_symbolTable->GetModifyHash(); + + for( const auto& libBuf : m_libs ) + hash += libBuf.second.GetHash(); + + return hash; +} + + +int LIB_MANAGER::GetLibraryHash( const wxString& aLibrary ) const +{ + const auto libBufIt = m_libs.find( aLibrary ); + return libBufIt != m_libs.end() ? libBufIt->second.GetHash() : 0; +} + + +wxArrayString LIB_MANAGER::GetLibraryNames() const +{ + wxArrayString res; + + for( const auto& libName : m_symbolTable->GetLogicalLibs() ) + res.Add( libName ); + + return res; +} + + +bool LIB_MANAGER::FlushAll() +{ + bool result = true; + + for( auto& libBuf : m_libs ) + result &= FlushLibrary( libBuf.first ); + + return result; +} + + +bool LIB_MANAGER::FlushLibrary( const wxString& aLibrary ) +{ + auto it = m_libs.find( aLibrary ); + + if( it == m_libs.end() ) // no changes to flush + return true; + + LIB_BUFFER& libBuf = it->second; + wxArrayString aliases; + m_symbolTable->EnumerateSymbolLib( aLibrary, aliases ); + + // TODO probably this could be implemented more efficiently + for( const auto& alias : aliases ) + m_symbolTable->DeleteAlias( aLibrary, alias ); + + // Assume all libraries are successfully saved + bool res = true; + + for( const auto& partBuf : libBuf.GetBuffers() ) + { + if( !libBuf.SaveBuffer( partBuf, m_symbolTable ) ) + { + // Something went wrong but try to save other libraries + res = false; + } + } + + if( res ) + libBuf.ClearDeletedBuffer(); + + return res; +} + + +bool LIB_MANAGER::IsLibraryModified( const wxString& aLibrary ) const +{ + wxCHECK( LibraryExists( aLibrary ), false ); + auto it = m_libs.find( aLibrary ); + return it != m_libs.end() ? it->second.IsModified() : false; +} + + +bool LIB_MANAGER::IsPartModified( const wxString& aAlias, const wxString& aLibrary ) const +{ + wxCHECK( LibraryExists( aLibrary ), false ); + auto libIt = m_libs.find( aLibrary ); + + if( libIt == m_libs.end() ) + return false; + + const LIB_BUFFER& buf = libIt->second; + auto partBuf = buf.GetBuffer( aAlias ); + return partBuf ? partBuf->IsModified() : false; +} + + +bool LIB_MANAGER::IsLibraryReadOnly( const wxString& aLibrary ) const +{ + wxCHECK( LibraryExists( aLibrary ), true ); + wxFileName fn( m_symbolTable->GetFullURI( aLibrary ) ); + return !fn.IsFileWritable(); +} + + +wxArrayString LIB_MANAGER::GetAliasNames( const wxString& aLibrary ) const +{ + wxArrayString names; + wxCHECK( LibraryExists( aLibrary ), names ); + + auto it = m_libs.find( aLibrary ); + + if( it == m_libs.end() ) + { + try + { + m_symbolTable->EnumerateSymbolLib( aLibrary, names ); + } + catch( IO_ERROR& e ) + { + return names; + } + } + else + { + names = it->second.GetAliasNames(); + } + + return names; +} + + +std::list LIB_MANAGER::GetAliases( const wxString& aLibrary ) const +{ + std::list ret; + wxCHECK( LibraryExists( aLibrary ), ret ); + + auto libIt = m_libs.find( aLibrary ); + + if( libIt != m_libs.end() ) + { + for( auto& partBuf : libIt->second.GetBuffers() ) + { + for( int i = 0; i < partBuf->GetPart()->GetAliasCount(); ++i ) + ret.push_back( partBuf->GetPart()->GetAlias( i ) ); + } + } + else + { + wxArrayString symbols; + + try + { + m_symbolTable->EnumerateSymbolLib( aLibrary, symbols ); + } + catch( IO_ERROR& e ) + { + return ret; + } + + for( const auto& symbol : symbols ) + ret.push_back( m_symbolTable->LoadSymbol( aLibrary, symbol ) ); + } + + return ret; +} + + +LIB_PART* LIB_MANAGER::GetBufferedPart( const wxString& aAlias, const wxString& aLibrary ) +{ + wxCHECK( LibraryExists( aLibrary ), nullptr ); + + // try the library buffers first + LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary ); + LIB_PART* bufferedPart = libBuf.GetPart( aAlias ); + + if( !bufferedPart ) // no buffer part found + { + // create a partCopy + LIB_ALIAS* alias = m_symbolTable->LoadSymbol( aLibrary, aAlias ); + wxCHECK( alias, nullptr ); + bufferedPart = new LIB_PART( *alias->GetPart(), nullptr ); + libBuf.CreateBuffer( bufferedPart, new SCH_SCREEN( &m_frame.Kiway() ) ); + } + + return bufferedPart; +} + + +SCH_SCREEN* LIB_MANAGER::GetScreen( const wxString& aAlias, const wxString& aLibrary ) +{ + wxCHECK( LibraryExists( aLibrary ), nullptr ); + wxCHECK( !aAlias.IsEmpty(), nullptr ); + auto it = m_libs.find( aLibrary ); + wxCHECK( it != m_libs.end(), nullptr ); + + LIB_BUFFER& buf = it->second; + auto partBuf = buf.GetBuffer( aAlias ); + return partBuf ? partBuf->GetScreen() : nullptr; +} + + +bool LIB_MANAGER::UpdatePart( LIB_PART* aPart, const wxString& aLibrary, wxString aOldName ) +{ + wxCHECK( LibraryExists( aLibrary ), false ); + wxCHECK( aPart, false ); + const wxString partName = aOldName.IsEmpty() ? aPart->GetName() : aOldName; + LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary ); + auto partBuf = libBuf.GetBuffer( partName ); + LIB_PART* partCopy = new LIB_PART( *aPart, nullptr ); + + if( partBuf ) + { + libBuf.UpdateBuffer( partBuf, partCopy ); + } + else // New entry + { + SCH_SCREEN* screen = new SCH_SCREEN( &m_frame.Kiway() ); + libBuf.CreateBuffer( partCopy, screen ); + screen->SetModify(); + } + + Sync(); // TODO update only the changed part + + return true; +} + + +bool LIB_MANAGER::FlushPart( const wxString& aAlias, const wxString& aLibrary ) +{ + auto it = m_libs.find( aLibrary ); + + if( it == m_libs.end() ) // no items to flush + return true; + + auto partBuf = it->second.GetBuffer( aAlias ); + wxCHECK( partBuf, false ); + + return it->second.SaveBuffer( partBuf, m_symbolTable ); +} + + +bool LIB_MANAGER::RevertPart( const wxString& aAlias, const wxString& aLibrary ) +{ + auto it = m_libs.find( aLibrary ); + + if( it == m_libs.end() ) // no items to flush + return true; + + auto partBuf = it->second.GetBuffer( aAlias ); + wxCHECK( partBuf, false ); + + partBuf->GetScreen()->ClrModify(); + partBuf->SetPart( new LIB_PART( *partBuf->GetOriginal() ) ); + + return true; +} + + +bool LIB_MANAGER::RevertLibrary( const wxString& aLibrary ) +{ + auto it = m_libs.find( aLibrary ); + + if( it == m_libs.end() ) // nothing to reverse + return false; + + m_libs.erase( it ); + getAdapter()->UpdateLibrary( aLibrary ); + + return true; +} + + +bool LIB_MANAGER::RemovePart( const wxString& aAlias, const wxString& aLibrary ) +{ + LIB_BUFFER& libBuf = getLibraryBuffer( aLibrary ); + auto partBuf = libBuf.GetBuffer( aAlias ); + wxCHECK( partBuf, false ); + + bool res = libBuf.DeleteBuffer( partBuf ); + getAdapter()->UpdateLibrary( aLibrary ); + + return res; +} + + +LIB_ALIAS* LIB_MANAGER::GetAlias( const wxString& aAlias, const wxString& aLibrary ) const +{ + // Try the library buffers first + auto libIt = m_libs.find( aLibrary ); + + if( libIt != m_libs.end() ) + { + LIB_PART* part = libIt->second.GetPart( aAlias ); + + if( part ) + return part->GetAlias( aAlias ); + } + + // Get the original part + return m_symbolTable->LoadSymbol( aLibrary, aAlias ); +} + + +bool LIB_MANAGER::PartExists( const wxString& aAlias, const wxString& aLibrary ) const +{ + auto libBufIt = m_libs.find( aLibrary ); + + if( libBufIt != m_libs.end() ) + return !!libBufIt->second.GetBuffer( aAlias ); + + return !!m_symbolTable->LoadSymbol( aLibrary, aAlias ); +} + + +bool LIB_MANAGER::LibraryExists( const wxString& aLibrary ) const +{ + if( m_libs.count( aLibrary ) > 0 ) + return true; + + return m_symbolTable->HasLibrary( aLibrary ); +} + + +wxString LIB_MANAGER::ValidateName( const wxString& aName ) +{ + wxString name( aName ); + name.Replace( " ", "_" ); + return name; +} + + +wxString LIB_MANAGER::GetUniqueLibraryName() const +{ + wxString name = "New_Library"; + + if( !LibraryExists( name ) ) + return name; + + name += "_"; + + for( unsigned int i = 0; i < std::numeric_limits::max(); ++i ) + { + if( !LibraryExists( name + wxString::Format( "%u", i ) ) ) + return name + wxString::Format( "%u", i ); + } + + wxFAIL; + return wxEmptyString; +} + + +wxString LIB_MANAGER::GetUniqueComponentName( const wxString& aLibrary ) const +{ + wxString name = "New_Component"; + + if( !PartExists( name, aLibrary ) ) + return name; + + name += "_"; + + for( unsigned int i = 0; i < std::numeric_limits::max(); ++i ) + { + if( !PartExists( name + wxString::Format( "%u", i ), aLibrary ) ) + return name + wxString::Format( "%u", i ); + } + + wxFAIL; + return wxEmptyString; +} + + +wxString LIB_MANAGER::getLibraryName( const wxString& aFilePath ) +{ + wxFileName fn( aFilePath ); + return fn.GetName(); +} + + +bool LIB_MANAGER::addLibrary( const wxString& aFilePath, bool aCreate ) +{ + wxString libName = getLibraryName( aFilePath ); + wxCHECK( !LibraryExists( libName ), false ); // either create or add an existing one + + // Select the target library table (global/project) + SYMBOL_LIB_TABLE* libTable = m_frame.SelectSymLibTable(); + wxCHECK( libTable, false ); + + SYMBOL_LIB_TABLE_ROW* libRow = new SYMBOL_LIB_TABLE_ROW( libName, aFilePath, + SCH_IO_MGR::ShowType( SCH_IO_MGR::SCH_LEGACY ) ); + libTable->InsertRow( libRow ); + + if( aCreate ) + libTable->CreateSymbolLib( libName ); + + getAdapter()->AddLibrary( libName ); + + return true; +} + + +LIB_MANAGER::LIB_BUFFER& LIB_MANAGER::getLibraryBuffer( const wxString& aLibrary ) +{ + auto it = m_libs.find( aLibrary ); + + if( it != m_libs.end() ) + return it->second; + + wxArrayString aliases; + auto ret = m_libs.emplace( aLibrary, LIB_BUFFER( aLibrary ) ); + LIB_BUFFER& buf = ret.first->second; + m_symbolTable->EnumerateSymbolLib( aLibrary, aliases ); + // set collecting the processed LIB_PARTs + std::set processed; + + for( const auto& aliasName : aliases ) + { + LIB_ALIAS* alias = m_symbolTable->LoadSymbol( aLibrary, aliasName ); + LIB_PART* part = alias->GetPart(); + + if( !processed.count( part ) ) + { + buf.CreateBuffer( new LIB_PART( *part, nullptr ), new SCH_SCREEN( &m_frame.Kiway() ) ); + processed.insert( part ); + } + } + + return buf; +} + + +LIB_MANAGER::PART_BUFFER::PART_BUFFER( LIB_PART* aPart, SCH_SCREEN* aScreen ) + : m_screen( aScreen ), m_part( aPart ) +{ + m_original = new LIB_PART( *aPart ); +} + + +LIB_MANAGER::PART_BUFFER::~PART_BUFFER() +{ + delete m_screen; + delete m_part; + delete m_original; +} + + +void LIB_MANAGER::PART_BUFFER::SetPart( LIB_PART* aPart ) +{ + wxCHECK( m_part != aPart, /* void */ ); + wxASSERT( aPart ); + delete m_part; + m_part = aPart; +} + + +void LIB_MANAGER::PART_BUFFER::SetOriginal( LIB_PART* aPart ) +{ + wxCHECK( m_original != aPart, /* void */ ); + wxASSERT( aPart ); + delete m_original; + m_original = aPart; +} + + +bool LIB_MANAGER::PART_BUFFER::IsModified() const +{ + return m_screen && m_screen->IsModify(); +} + + +wxArrayString LIB_MANAGER::LIB_BUFFER::GetAliasNames() const +{ + wxArrayString ret; + + for( const auto& alias : m_aliases ) + ret.push_back( alias.first ); + + return ret; +} + + +bool LIB_MANAGER::LIB_BUFFER::CreateBuffer( LIB_PART* aCopy, SCH_SCREEN* aScreen ) +{ + wxASSERT( m_aliases.count( aCopy->GetName() ) == 0 ); // only for new parts + wxASSERT( aCopy->GetLib() == nullptr ); + auto partBuf = std::make_shared( aCopy, aScreen ); + m_parts.push_back( partBuf ); + addAliases( partBuf ); + + // Set the parent library name, + // otherwise it is empty as no library has been given as the owner during object construction + LIB_ID libId = aCopy->GetLibId(); + libId.SetLibNickname( m_libName ); + aCopy->SetLibId( libId ); + ++m_hash; + + return true; +} + + +bool LIB_MANAGER::LIB_BUFFER::UpdateBuffer( LIB_MANAGER::PART_BUFFER::PTR aPartBuf, LIB_PART* aCopy ) +{ + bool ret = true; + + ret &= removeAliases( aPartBuf ); + aPartBuf->SetPart( aCopy ); + ret &= addAliases( aPartBuf ); + ++m_hash; + + return ret; +} + + +bool LIB_MANAGER::LIB_BUFFER::DeleteBuffer( LIB_MANAGER::PART_BUFFER::PTR aPartBuf ) +{ + auto partBufIt = std::find( m_parts.begin(), m_parts.end(), aPartBuf ); + wxCHECK( partBufIt != m_parts.end(), false ); + m_deleted.emplace_back( *partBufIt ); + m_parts.erase( partBufIt ); + ++m_hash; + + return removeAliases( aPartBuf ); +} + + +bool LIB_MANAGER::LIB_BUFFER::SaveBuffer( LIB_MANAGER::PART_BUFFER::PTR aPartBuf, + SYMBOL_LIB_TABLE* aLibTable ) +{ + wxCHECK( aPartBuf, false ); + + LIB_PART* part = aPartBuf->GetPart(); + wxCHECK( part, false ); + + // TODO Enable buffering to avoid to disable too frequent file saves + //PROPERTIES properties; + //properties.emplace( SCH_LEGACY_PLUGIN::PropBuffering, "" ); + + if( aLibTable->SaveSymbol( m_libName, new LIB_PART( *part ) ) == SYMBOL_LIB_TABLE::SAVE_OK ) + { + aPartBuf->GetScreen()->ClrModify(); + aPartBuf->SetOriginal( new LIB_PART( *part ) ); + ++m_hash; + return true; + } + + return false; +} + + +bool LIB_MANAGER::LIB_BUFFER::addAliases( PART_BUFFER::PTR aPartBuf ) +{ + LIB_PART* part = aPartBuf->GetPart(); + wxCHECK( part, false ); + bool ret = true; // Assume everything is ok + + for( int i = 0; i < part->GetAliasCount(); ++i ) + { + bool newAlias; + std::tie( std::ignore, newAlias ) = m_aliases.emplace( part->GetAlias( i )->GetName(), aPartBuf ); + + if( !newAlias ) // Overwrite check + { + wxFAIL; + ret = false; + } + } + + return ret; +} + + +bool LIB_MANAGER::LIB_BUFFER::removeAliases( PART_BUFFER::PTR aPartBuf ) +{ + LIB_PART* part = aPartBuf->GetPart(); + wxCHECK( part, false ); + bool ret = true; // Assume everything is ok + + for( int i = 0; i < part->GetAliasCount(); ++i ) + { + auto aliasIt = m_aliases.find( part->GetAlias( i )->GetName() ); + + if( aliasIt == m_aliases.end() ) + { + wxFAIL; + ret = false; + continue; + } + + // Be sure the alias belongs to the assigned owner + wxASSERT( aliasIt->second.lock() == aPartBuf ); + + m_aliases.erase( aliasIt ); + } + + return ret; +} diff --git a/eeschema/lib_manager.h b/eeschema/lib_manager.h new file mode 100644 index 0000000000..4ddbef5b12 --- /dev/null +++ b/eeschema/lib_manager.h @@ -0,0 +1,347 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * 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 3 + * 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: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIB_MANAGER_H +#define LIB_MANAGER_H + +#include +#include +#include +#include +#include +#include +#include + +class LIB_ALIAS; +class LIB_PART; +class LIB_BUFFER; +class PART_LIB; +class SCH_SCREEN; +class LIB_EDIT_FRAME; +class SYMBOL_LIB_TABLE; + +/** + * Class to handle modifications to the symbol libraries. + */ +class LIB_MANAGER +{ +public: + LIB_MANAGER( LIB_EDIT_FRAME& aFrame ); + + /** + * Updates the LIB_MANAGER data to account for the changes introduced to the project libraries. + * @see PROJECT::SchLibs() + */ + void Sync(); + + int GetHash() const; + + int GetLibraryHash( const wxString& aLibrary ) const; + + /** + * Returns the array of library names. + */ + wxArrayString GetLibraryNames() const; + + /** + * Returns a set containing all part names for a specific library. + */ + wxArrayString GetAliasNames( const wxString& aLibrary ) const; + + std::list GetAliases( const wxString& aLibrary ) const; + + /** + * Creates an empty library and adds it to the library table. The library file is created. + */ + bool CreateLibrary( const wxString& aFilePath ) + { + return addLibrary( aFilePath, true ); + } + + /** + * Adds an existing library. The library is added to the library table as well. + */ + bool AddLibrary( const wxString& aFilePath ) + { + return addLibrary( aFilePath, false ); + } + + /** + * Updates the part buffer with a new version of the part. + * It is required to save the library to use the updated part in the schematic editor. + */ + bool UpdatePart( LIB_PART* aPart, const wxString& aLibrary, wxString aOldName = wxEmptyString ); + + /** + * Removes the part from the part buffer. + * It is required to save the library to have the part removed in the schematic editor. + */ + bool RemovePart( const wxString& aName, const wxString& aLibrary ); + + /** + * Returns either an alias of a working LIB_PART copy, or alias of the original part if there + * is no working copy. + */ + LIB_ALIAS* GetAlias( const wxString& aAlias, const wxString& aLibrary ) const; + + /** + * Returns the part copy from the buffer. In case it does not exist yet, the copy is created. + * LIB_MANAGER retains the ownership. + */ + LIB_PART* GetBufferedPart( const wxString& aAlias, const wxString& aLibrary ); + + /** + * Returns the screen used to edit a specific part. LIB_MANAGER retains the ownership. + */ + SCH_SCREEN* GetScreen( const wxString& aAlias, const wxString& aLibrary ); + + /** + * Returns true if part with a specific alias exists in library (either original one or buffered). + */ + bool PartExists( const wxString& aAlias, const wxString& aLibrary ) const; + + /** + * Returns true if library exists. + */ + bool LibraryExists( const wxString& aLibrary ) const; + + /** + * Returns true if library has unsaved modifications. + */ + bool IsLibraryModified( const wxString& aLibrary ) const; + + /** + * Returns true if part has unsaved modifications. + */ + bool IsPartModified( const wxString& aAlias, const wxString& aLibrary ) const; + + /** + * Returns true if the library is stored in a read-only file. + * @return True on success, false otherwise. + */ + bool IsLibraryReadOnly( const wxString& aLibrary ) const; + + /** + * Saves part changes to the library copy used by the schematic editor. Not it is not + * necessarily saved to the file. + * @return True on success, false otherwise. + */ + bool FlushPart( const wxString& aAlias, const wxString& aLibrary ); + + /** + * Saves changes to the library copy used by the schematic editor. Note it is not + * necessarily saved to the file. + * @param aLibrary is the library name. + * @return True on success, false otherwise. + */ + bool FlushLibrary( const wxString& aLibrary ); + + /** + * Saves all changes to libraries. + * @return True if all changes have been flushed successfully, false otherwise. + */ + bool FlushAll(); + + /** + * Reverts unsaved changes for a particular part. + * @return True on success, false otherwise. + */ + bool RevertPart( const wxString& aAlias, const wxString& aLibrary ); + + /** + * Reverts unsaved changes for a particular library. + * @return True on success, false otherwise. + */ + bool RevertLibrary( const wxString& aLibrary ); + + /** + * Replaces all characters considered illegal in library/part names with underscores. + */ + static wxString ValidateName( const wxString& aName ); + + /** + * Returns a library name that is not currently in use. + * Used for generating names for new libraries. + */ + wxString GetUniqueLibraryName() const; + + /** + * Returns a component name that is not stored in a library. + * Used for generating names for new components. + */ + wxString GetUniqueComponentName( const wxString& aLibrary ) const; + + /** + * Returns the adapter object that provides the stored data. + */ + CMP_TREE_MODEL_ADAPTER_BASE::PTR& GetAdapter() { return m_adapter; } + +private: + ///> Parent frame + LIB_EDIT_FRAME& m_frame; + + ///> Extracts library name basing on the file name + static wxString getLibraryName( const wxString& aFilePath ); + + ///> Helper function to add either existing or create new library + bool addLibrary( const wxString& aFilePath, bool aCreate ); + + SYMBOL_LIB_TABLE* m_symbolTable; + + ///> Class to store a working copy of a LIB_PART object and editor context. + class PART_BUFFER + { + public: + PART_BUFFER( LIB_PART* aPart = nullptr, SCH_SCREEN* aScreen = nullptr ); + ~PART_BUFFER(); + + LIB_PART* GetPart() const { return m_part; } + void SetPart( LIB_PART* aPart ); + + LIB_PART* GetOriginal() const { return m_original; } + void SetOriginal( LIB_PART* aPart ); + + bool IsModified() const; + SCH_SCREEN* GetScreen() const { return m_screen; } + + typedef std::shared_ptr PTR; + typedef std::weak_ptr WEAK_PTR; + + private: + SCH_SCREEN* m_screen; + + ///> Working copy + LIB_PART* m_part; + + ///> Initial state of the part + LIB_PART* m_original; + }; + + + ///> Class to store a working copy of a library + class LIB_BUFFER + { + public: + LIB_BUFFER( const wxString& aLibrary ) + : m_libName( aLibrary ), m_hash( 1 ) + { + } + + bool IsModified() const + { + if( !m_deleted.empty() ) + return true; + + for( const auto& partBuf : m_parts ) + { + if( partBuf->IsModified() ) + return true; + } + + return false; + } + + int GetHash() const + { + return m_hash; + } + + ///> Returns all alias names for stored parts + wxArrayString GetAliasNames() const; + + ///> Returns the working copy of a LIB_PART object with specified alias + LIB_PART* GetPart( const wxString& aAlias ) const + { + auto buf = GetBuffer( aAlias ); + return buf ? buf->GetPart() : nullptr; + } + + ///> Creates a new buffer to store a part. LIB_BUFFER takes ownership of aCopy. + bool CreateBuffer( LIB_PART* aCopy, SCH_SCREEN* aScreen ); + + ///> Updates the stored part. LIB_BUFFER takes ownership of aCopy. + bool UpdateBuffer( PART_BUFFER::PTR aPartBuf, LIB_PART* aCopy ); + + bool DeleteBuffer( PART_BUFFER::PTR aPartBuf ); + + void ClearDeletedBuffer() + { + m_deleted.clear(); + } + + ///> Saves stored modifications to a Symbol Library Table + bool SaveBuffer( PART_BUFFER::PTR aPartBuf, SYMBOL_LIB_TABLE* aLibTable ); + + ///> Returns a part buffer with LIB_PART holding a particular alias + PART_BUFFER::PTR GetBuffer( const wxString& aAlias ) const + { + auto it = m_aliases.find( aAlias ); + return it != m_aliases.end() ? it->second.lock() : PART_BUFFER::PTR( nullptr ); + } + + ///> Returns all buffered parts + const std::deque& GetBuffers() const + { + return m_parts; + } + + ///> Returns all aliases of buffered parts + const std::map& GetAliases() const + { + return m_aliases; + } + + private: + ///> Creates alias entries for a particular part buffer + bool addAliases( PART_BUFFER::PTR aPartBuf ); + + ///> Removes alias entries for a particular part buffer + bool removeAliases( PART_BUFFER::PTR aPartBuf ); + + std::map m_aliases; + std::deque m_parts; + + ///> Buffer to keep deleted parts until the library is saved + std::deque m_deleted; + + /// Buffered library name + const wxString m_libName; + + int m_hash; + + friend class PART_BUFFER; + }; + + ///> Returns an existing library buffer or creates one to using + ///> Symbol Library Table to get the original data. + LIB_BUFFER& getLibraryBuffer( const wxString& aLibrary ); + + ///> The library buffers + std::map m_libs; + + LIB_MANAGER_ADAPTER::PTR m_adapter; + LIB_MANAGER_ADAPTER* getAdapter() { return static_cast( m_adapter.get() ); } +}; + +#endif /* LIB_MANAGER_H */ diff --git a/eeschema/lib_manager_adapter.cpp b/eeschema/lib_manager_adapter.cpp new file mode 100644 index 0000000000..8b73dfb5b4 --- /dev/null +++ b/eeschema/lib_manager_adapter.cpp @@ -0,0 +1,207 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * 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 3 + * 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: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + + +CMP_TREE_MODEL_ADAPTER_BASE::PTR LIB_MANAGER_ADAPTER::Create( LIB_MANAGER* aLibMgr ) +{ + auto adapter = new LIB_MANAGER_ADAPTER( aLibMgr ); + auto container = CMP_TREE_MODEL_ADAPTER_BASE::PTR( adapter ); + return container; +} + + +void LIB_MANAGER_ADAPTER::AddLibrary( const wxString& aLibNickname ) +{ + auto& lib_node = m_tree.AddLib( aLibNickname ); + ItemAdded( wxDataViewItem( nullptr ), ToItem( &lib_node ) ); + updateLibrary( lib_node ); + lib_node.AssignIntrinsicRanks(); + m_tree.AssignIntrinsicRanks(); +} + + +void LIB_MANAGER_ADAPTER::RemoveLibrary( const wxString& aLibNickname ) +{ + auto it = std::find_if( m_tree.Children.begin(), m_tree.Children.end(), + [&] ( std::unique_ptr& node ) { return node->Name == aLibNickname; } ); + + if( it != m_tree.Children.end() ) + { + ItemDeleted( wxDataViewItem( nullptr ), ToItem( it->get() ) ); + m_tree.Children.erase( it ); + } +} + + +void LIB_MANAGER_ADAPTER::UpdateLibrary( const wxString& aLibraryName ) +{ + CMP_TREE_NODE* node = findLibrary( aLibraryName ); + + if( !node ) + return; + + ItemChanged( ToItem( node ) ); +} + + +void LIB_MANAGER_ADAPTER::AddAliasList( const wxString& aNodeName, + const wxArrayString& aAliasNameList ) +{ + wxASSERT( false ); // TODO +} + + +bool LIB_MANAGER_ADAPTER::IsContainer( const wxDataViewItem& aItem ) const +{ + const CMP_TREE_NODE* node = ToNode( aItem ); + return node && node->Type == CMP_TREE_NODE::LIB; +} + + +void LIB_MANAGER_ADAPTER::Sync() +{ + if( getSyncHash() == m_libMgr->GetHash() ) + return; + + wxDataViewItem root( nullptr ); + + // Process already stored libraries + for( auto it = m_tree.Children.begin(); it != m_tree.Children.end(); /* iteration inside */ ) + { + int mgrHash = m_libMgr->GetLibraryHash( it->get()->Name ); + + if( mgrHash < 0 ) + { + deleteLibrary( * (CMP_TREE_NODE_LIB*) it->get() ); + it = m_tree.Children.erase( it ); + continue; + } + else if( mgrHash != m_libHashes[it->get()->Name] ) + { + updateLibrary( * (CMP_TREE_NODE_LIB*) it->get() ); + } + + ++it; + } + + // Look for new libraries + for( const auto& libName : m_libMgr->GetLibraryNames() ) + { + if( m_libHashes.count( libName ) == 0 ) + { + auto& libNode = m_tree.AddLib( libName ); // Use AddLibrary? + ItemAdded( root, ToItem( &libNode ) ); + updateLibrary( libNode ); + } + } + + Resort(); +} + + +void LIB_MANAGER_ADAPTER::updateLibrary( CMP_TREE_NODE_LIB& aLibNode ) +{ + wxDataViewItem parent = ToItem( &aLibNode ); + aLibNode.Children.clear(); + + for( auto alias : m_libMgr->GetAliases( aLibNode.Name ) ) + { + auto& aliasNode = aLibNode.AddAlias( alias ); + ItemAdded( parent, ToItem( &aliasNode ) ); + } + + // TODO faster? + /* + wxDataViewItemArray aliasItems; + aliasItems.reserve( aLibNode.Children.size() ); + + for( const auto& child : aLibNode.Children ) + aliasItems.Add( ToItem( child.get() ) ); + + ItemsAdded( parent, aliasItems ); + */ + + m_libHashes[aLibNode.Name] = m_libMgr->GetLibraryHash( aLibNode.Name ); +} + + +void LIB_MANAGER_ADAPTER::deleteLibrary( CMP_TREE_NODE_LIB& aLibNode ) +{ + wxASSERT( false ); +} + + +CMP_TREE_NODE* LIB_MANAGER_ADAPTER::findLibrary( const wxString& aLibNickName ) +{ + for( auto& lib : m_tree.Children ) + { + if( lib->Name == aLibNickName ) + return lib.get(); + } + + return nullptr; +} + + +bool LIB_MANAGER_ADAPTER::GetAttr( wxDataViewItem const& aItem, unsigned int aCol, + wxDataViewItemAttr& aAttr ) const +{ + // change attributes only for the name field + if( aCol != 0 ) + return false; + + auto node = ToNode( aItem ); + wxCHECK( node, false ); + + switch( node->Type ) + { + case CMP_TREE_NODE::LIB: + // mark modified libs with bold font + aAttr.SetBold( m_libMgr->IsLibraryModified( node->Name ) ); + break; + + case CMP_TREE_NODE::LIBID: + // mark modified part with bold font + aAttr.SetBold( m_libMgr->IsPartModified( node->Name, node->Parent->Name ) ); + + // mark aliases with italic font + aAttr.SetItalic( !node->IsRoot ); + break; + + default: + return false; + } + + return true; +} + + +LIB_MANAGER_ADAPTER::LIB_MANAGER_ADAPTER( LIB_MANAGER* aLibMgr ) + : m_libMgr( aLibMgr ) +{ +} diff --git a/eeschema/lib_manager_adapter.h b/eeschema/lib_manager_adapter.h new file mode 100644 index 0000000000..504c843cbf --- /dev/null +++ b/eeschema/lib_manager_adapter.h @@ -0,0 +1,78 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * 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 3 + * 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: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef LIB_MANAGER_ADAPTER_H +#define LIB_MANAGER_ADAPTER_H + +#include +#include + +class LIB_MANAGER; + +class LIB_MANAGER_ADAPTER : public CMP_TREE_MODEL_ADAPTER_BASE +{ +public: + static PTR Create( LIB_MANAGER* aLibs ); + + void AddLibrary( const wxString& aLibNickname ) override; + + void RemoveLibrary( const wxString& aLibNickname ); + + void AddAliasList( const wxString& aNodeName, const wxArrayString& aAliasNameList ) override; + + bool IsContainer( const wxDataViewItem& aItem ) const override; + + void UpdateLibrary( const wxString& aLibraryName ); + + void Sync(); + +protected: + void updateLibrary( CMP_TREE_NODE_LIB& aLibNode ); + + void deleteLibrary( CMP_TREE_NODE_LIB& aLibNode ); + + CMP_TREE_NODE* findLibrary( const wxString& aLibNickName ); + + bool GetAttr( wxDataViewItem const& aItem, unsigned int aCol, + wxDataViewItemAttr& aAttr ) const override; + + LIB_MANAGER_ADAPTER( LIB_MANAGER* aLibMgr ); + + LIB_MANAGER* m_libMgr; + + // TODO? use hashes to determine whcih libraries to update? + std::map m_libHashes; + + int getSyncHash() const + { + int hash = 0; + + for( const auto& h : m_libHashes ) + hash += h.second; + + return hash; + } +}; + +#endif /* LIB_MANAGER_ADAPTER_H */ diff --git a/eeschema/libedit.cpp b/eeschema/libedit.cpp index 853e34d150..21d5a0ad3d 100644 --- a/eeschema/libedit.cpp +++ b/eeschema/libedit.cpp @@ -46,6 +46,9 @@ #include #include #include +#include +#include +#include #include #include @@ -201,25 +204,19 @@ bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, const wxString& a return false; } - wxString cmpName = m_aliasName = aEntry->GetName(); - - LIB_PART* lib_part = aEntry->GetPart(); - - wxASSERT( lib_part ); - - LIB_PART* part = new LIB_PART( *lib_part ); // clone it and own it. - SetCurPart( part ); m_aliasName = aEntry->GetName(); + LIB_PART* lib_part = m_libMgr->GetBufferedPart( m_aliasName, aLibrary ); + wxASSERT( lib_part ); + SetScreen( m_libMgr->GetScreen( lib_part->GetName(), aLibrary ) ); + SetCurPart( new LIB_PART( *lib_part ) ); + SetCurLib( aLibrary ); + m_unit = 1; m_convert = 1; + SetShowDeMorgan( GetCurPart()->HasConversion() ); - m_showDeMorgan = false; - - if( part->HasConversion() ) - m_showDeMorgan = true; - - GetScreen()->ClrModify(); + Zoom_Automatique( false ); DisplayLibInfos(); UpdateAliasSelectList(); UpdatePartSelectList(); @@ -282,13 +279,181 @@ void LIB_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg ) } -void LIB_EDIT_FRAME::OnSaveActiveLibrary( wxCommandEvent& event ) +void LIB_EDIT_FRAME::OnSaveLibrary( wxCommandEvent& event ) { - SaveActiveLibrary( event.GetId() == ID_LIBEDIT_SAVE_CURRENT_LIB_AS ); + saveLibrary( getTargetLib(), event.GetId() == ID_LIBEDIT_SAVE_LIBRARY_AS ); + m_treePane->Refresh(); } -bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) +void LIB_EDIT_FRAME::OnSaveAllLibraries( wxCommandEvent& event ) +{ + wxASSERT( false ); +} + + +void LIB_EDIT_FRAME::OnRevertLibrary( wxCommandEvent& aEvent ) +{ + wxString libName = getTargetLib(); + bool currentLib = ( libName == GetCurLib() ); + + // Save the current part name/unit to reload after revert + wxString alias = m_aliasName; + int unit = m_unit; + + if( !IsOK( this, _( "The revert operation cannot be undone!\n\nRevert changes?" ) ) ) + return; + + if( currentLib ) + emptyScreen(); + + m_libMgr->RevertLibrary( libName ); + + if( currentLib && m_libMgr->PartExists( alias, libName ) ) + loadPart( alias, libName, unit ); +} + + +void LIB_EDIT_FRAME::OnCreateNewPart( wxCommandEvent& event ) +{ + m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); + m_drawItem = NULL; + + DIALOG_LIB_NEW_COMPONENT dlg( this ); + dlg.SetMinSize( dlg.GetSize() ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return; + + if( dlg.GetName().IsEmpty() ) + { + wxMessageBox( _( "This new symbol has no name and cannot be created." ) ); + return; + } + + wxString name = dlg.GetName(); + name.Replace( " ", "_" ); + + wxString lib = getTargetLib(); + + // Test if there is a component with this name already. + if( !lib.empty() && m_libMgr->PartExists( name, lib ) ) + { + wxString msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'" ), + name, lib ); + DisplayError( this, msg ); + return; + } + + LIB_PART* new_part = new LIB_PART( name ); + m_aliasName = new_part->GetName(); + + new_part->GetReferenceField().SetText( dlg.GetReference() ); + new_part->SetUnitCount( dlg.GetUnitCount() ); + + // Initialize new_part->m_TextInside member: + // if 0, pin text is outside the body (on the pin) + // if > 0, pin text is inside the body + new_part->SetConversion( dlg.GetAlternateBodyStyle() ); + SetShowDeMorgan( dlg.GetAlternateBodyStyle() ); + + if( dlg.GetPinNameInside() ) + { + new_part->SetPinNameOffset( dlg.GetPinTextPosition() ); + + if( new_part->GetPinNameOffset() == 0 ) + new_part->SetPinNameOffset( 1 ); + } + else + { + new_part->SetPinNameOffset( 0 ); + } + + ( dlg.GetPowerSymbol() ) ? new_part->SetPower() : new_part->SetNormal(); + new_part->SetShowPinNumbers( dlg.GetShowPinNumber() ); + new_part->SetShowPinNames( dlg.GetShowPinName() ); + new_part->LockUnits( dlg.GetLockItems() ); + + if( dlg.GetUnitCount() < 2 ) + new_part->LockUnits( false ); + + m_libMgr->UpdatePart( new_part, lib ); + loadPart( name, lib, 1 ); +} + + +void LIB_EDIT_FRAME::OnEditPart( wxCommandEvent& aEvent ) +{ + int unit = 0; + LIB_ID partId = m_treePane->GetCmpTree()->GetSelectedLibId( &unit ); + loadPart( partId.GetLibItemName(), partId.GetLibNickname(), unit ); +} + + +void LIB_EDIT_FRAME::OnSavePart( wxCommandEvent& aEvent ) +{ + LIB_ID libId = getTargetLibId(); + m_libMgr->FlushPart( libId.GetLibItemName(), libId.GetLibNickname() ); +} + + +void LIB_EDIT_FRAME::OnRemovePart( wxCommandEvent& aEvent ) +{ + LIB_ID libId = getTargetLibId(); + + if( m_libMgr->IsPartModified( libId.GetLibItemName(), libId.GetLibNickname() ) + && !IsOK( this, _( wxString::Format( "Component %s has been modified\n" + "Do you want to remove it from the library?", libId.GetLibItemName().c_str() ) ) ) ) + { + return; + } + + if( isCurrentPart( libId ) ) + emptyScreen(); + + m_libMgr->RemovePart( libId.GetLibItemName(), libId.GetLibNickname() ); +} + + +void LIB_EDIT_FRAME::OnRevertPart( wxCommandEvent& aEvent ) +{ + LIB_ID libId = getTargetLibId(); + bool currentPart = isCurrentPart( libId ); + int unit = m_unit; + + if( currentPart ) + emptyScreen(); + + m_libMgr->RevertPart( libId.GetLibItemName(), libId.GetLibNickname() ); + + if( currentPart && m_libMgr->PartExists( libId.GetLibItemName(), libId.GetLibNickname() ) ) + loadPart( libId.GetLibItemName(), libId.GetLibNickname(), unit ); +} + + +void LIB_EDIT_FRAME::loadPart( const wxString& aAlias, const wxString& aLibrary, int aUnit ) +{ + wxCHECK( m_libMgr->PartExists( aAlias, aLibrary ), /* void */ ); + LIB_PART* part = m_libMgr->GetBufferedPart( aAlias, aLibrary ); + LIB_ALIAS* alias = part ? part->GetAlias( aAlias ) : nullptr; + + if( !alias ) + { + wxString msg = wxString::Format( _( "Part name '%s' not found in library '%s'" ), + GetChars( aAlias ), GetChars( aLibrary ) ); + DisplayError( this, msg ); + return; + } + + m_lastDrawItem = m_drawItem = nullptr; + m_aliasName = aAlias; + m_unit = ( aUnit <= part->GetUnitCount() ? aUnit : 1 ); + + LoadOneLibraryPartAux( alias, aLibrary ); +} + + +bool LIB_EDIT_FRAME::saveLibrary( const wxString& aLibrary, bool aNewFile ) { wxFileName fn; wxString msg; @@ -296,18 +461,15 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); - wxString lib = GetCurLib(); + wxString lib = getTargetLib(); - if( !newFile && ( lib.empty() || !prj.SchSymbolLibTable()->HasLibrary( lib ) ) ) + if( !aNewFile && ( lib.empty() || !prj.SchSymbolLibTable()->HasLibrary( lib ) ) ) { DisplayError( this, _( "No library specified." ) ); return false; } - if( GetScreen()->IsModify() && !IsOK( this, _( "Include current symbol changes?" ) ) ) - return false; - - if( newFile ) + if( aNewFile ) { SEARCH_STACK* search = prj.SchSearchS(); @@ -392,7 +554,7 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) } // Copy the library and document files to the new destination library files. - if( newFile ) + if( aNewFile ) { wxFileName src = prj.SchSymbolLibTable()->GetFullURI( GetCurLib() ); @@ -417,21 +579,13 @@ bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile ) // Update symbol changes in library. if( GetScreen()->IsModify() ) { - SCH_PLUGIN::SCH_PLUGIN_RELEASER pi( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_LEGACY ) ); - - try - { - pi->SaveSymbol( fn.GetFullPath(), new LIB_PART( *GetCurPart() ) ); - } - catch( const IO_ERROR& ioe ) + if( !m_libMgr->FlushLibrary( lib ) ) { msg.Printf( _( "Failed to save changes to symbol library file '%s'" ), libFileName.GetFullPath() ); - DisplayErrorMessage( this, msg, ioe.What() ); + DisplayErrorMessage( this, _( "Error saving library" ), msg ); return false; } - - GetScreen()->ClrModify(); } msg.Printf( _( "Symbol library file '%s' saved" ), libFileName.GetFullPath() ); @@ -493,197 +647,3 @@ void LIB_EDIT_FRAME::DisplayCmpDoc() AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY ); AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY ); } - - -void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event ) -{ - wxString cmp_name; - wxArrayString nameList; - wxString msg; - - m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); - - m_lastDrawItem = NULL; - m_drawItem = NULL; - - LIB_PART *part = GetCurPart(); - wxString lib = GetCurLib(); - - if( lib.empty() ) - { - SelectActiveLibrary(); - - lib = GetCurLib(); - - if( !lib ) - { - DisplayError( this, _( "Please select a symbol library." ) ); - return; - } - } - - auto adapter( CMP_TREE_MODEL_ADAPTER::Create( Prj().SchSymbolLibTable() ) ); - - wxString name = part ? part->GetName() : wxString( wxEmptyString ); - adapter->SetPreselectNode( name, /* aUnit */ 0 ); - adapter->ShowUnits( false ); - adapter->AddLibrary( lib ); - - wxString dialogTitle; - dialogTitle.Printf( _( "Delete Symbol (%u items loaded)" ), adapter->GetComponentsCount() ); - - DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, adapter, m_convert, false ); - - if( dlg.ShowQuasiModal() == wxID_CANCEL ) - { - return; - } - - LIB_ID id; - - id = dlg.GetSelectedLibId(); - - if( !id.IsValid() ) - return; - - LIB_ALIAS* alias = Prj().SchSymbolLibTable()->LoadSymbol( id ); - - if( !alias ) - return; - - msg.Printf( _( "Delete symbol '%s' from library '%s'?" ), - id.GetLibItemName().wx_str(), id.GetLibNickname().wx_str() ); - - if( !IsOK( this, msg ) ) - return; - - part = GetCurPart(); - - if( !part || !part->HasAlias( id.GetLibItemName() ) ) - { - Prj().SchSymbolLibTable()->DeleteAlias( id.GetLibNickname(), id.GetLibItemName() ); - m_canvas->Refresh(); - return; - } - - // If deleting the current entry or removing one of the aliases for - // the current entry, sync the changes in the current entry as well. - - if( GetScreen()->IsModify() && !IsOK( this, _( - "The symbol being deleted has been modified." - " All changes will be lost. Discard changes?" ) ) ) - { - return; - } - - try - { - Prj().SchSymbolLibTable()->DeleteAlias( id.GetLibNickname(), id.GetLibItemName() ); - } - catch( ... /* IO_ERROR ioe */ ) - { - msg.Printf( _( "Error occurred deleting symbol '%s' from library '%s'" ), - id.GetLibItemName().wx_str(), id.GetLibNickname().wx_str() ); - DisplayError( this, msg ); - return; - } - - SetCurPart( NULL ); // delete CurPart - m_aliasName.Empty(); - m_canvas->Refresh(); -} - - -void LIB_EDIT_FRAME::CreateNewLibraryPart( wxCommandEvent& event ) -{ - wxString name; - - if( GetCurPart() && GetScreen()->IsModify() && !IsOK( this, _( - "All changes to the current symbol will be lost!\n\n" - "Clear the current symbol from the screen?" ) ) ) - { - return; - } - - m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() ); - - m_drawItem = NULL; - - DIALOG_LIB_NEW_COMPONENT dlg( this ); - - dlg.SetMinSize( dlg.GetSize() ); - - if( dlg.ShowModal() == wxID_CANCEL ) - return; - - if( dlg.GetName().IsEmpty() ) - { - wxMessageBox( _( "This new symbol has no name and cannot be created." ) ); - return; - } - - name = dlg.GetName(); - name.Replace( " ", "_" ); - - wxString lib = GetCurLib(); - - // Test if there a component with this name already. - if( !lib.empty() && Prj().SchSymbolLibTable()->LoadSymbol( lib, name ) != NULL ) - { - wxString msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'" ), - name, lib ); - DisplayError( this, msg ); - return; - } - - LIB_PART* new_part = new LIB_PART( name ); - - SetCurPart( new_part ); - m_aliasName = new_part->GetName(); - - new_part->GetReferenceField().SetText( dlg.GetReference() ); - new_part->SetUnitCount( dlg.GetUnitCount() ); - - // Initialize new_part->m_TextInside member: - // if 0, pin text is outside the body (on the pin) - // if > 0, pin text is inside the body - new_part->SetConversion( dlg.GetAlternateBodyStyle() ); - SetShowDeMorgan( dlg.GetAlternateBodyStyle() ); - - if( dlg.GetPinNameInside() ) - { - new_part->SetPinNameOffset( dlg.GetPinTextPosition() ); - - if( new_part->GetPinNameOffset() == 0 ) - new_part->SetPinNameOffset( 1 ); - } - else - { - new_part->SetPinNameOffset( 0 ); - } - - ( dlg.GetPowerSymbol() ) ? new_part->SetPower() : new_part->SetNormal(); - new_part->SetShowPinNumbers( dlg.GetShowPinNumber() ); - new_part->SetShowPinNames( dlg.GetShowPinName() ); - new_part->LockUnits( dlg.GetLockItems() ); - - if( dlg.GetUnitCount() < 2 ) - new_part->LockUnits( false ); - - m_unit = 1; - m_convert = 1; - - DisplayLibInfos(); - DisplayCmpDoc(); - UpdateAliasSelectList(); - UpdatePartSelectList(); - - m_editPinsPerPartOrConvert = new_part->UnitsLocked() ? true : false; - m_lastDrawItem = NULL; - - GetScreen()->ClearUndoRedoList(); - OnModify(); - - m_canvas->Refresh(); - m_mainToolBar->Refresh(); -} diff --git a/eeschema/libeditframe.cpp b/eeschema/libeditframe.cpp index 6248b93f79..ef65d78795 100644 --- a/eeschema/libeditframe.cpp +++ b/eeschema/libeditframe.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,10 @@ #include #include #include + +#include +#include +#include #include #include @@ -53,7 +58,7 @@ #include #include -#include +#include #include @@ -82,12 +87,25 @@ BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME ) EVT_SIZE( LIB_EDIT_FRAME::OnSize ) EVT_ACTIVATE( LIB_EDIT_FRAME::OnActivate ) - // Main horizontal toolbar. - EVT_TOOL( ID_LIBEDIT_SAVE_CURRENT_LIB, LIB_EDIT_FRAME::OnSaveActiveLibrary ) - EVT_TOOL( ID_LIBEDIT_DELETE_PART, LIB_EDIT_FRAME::DeleteOnePart ) - EVT_TOOL( ID_TO_LIBVIEW, LIB_EDIT_FRAME::OnOpenLibraryViewer ) - EVT_TOOL( ID_LIBEDIT_NEW_PART, LIB_EDIT_FRAME::CreateNewLibraryPart ) + // Library actions + EVT_TOOL( ID_LIBEDIT_NEW_LIBRARY, LIB_EDIT_FRAME::OnCreateNewLibrary ) + EVT_TOOL( ID_LIBEDIT_ADD_LIBRARY, LIB_EDIT_FRAME::OnAddLibrary ) + EVT_TOOL( ID_LIBEDIT_SAVE_LIBRARY, LIB_EDIT_FRAME::OnSaveLibrary ) + EVT_MENU( ID_LIBEDIT_SAVE_LIBRARY_AS, LIB_EDIT_FRAME::OnSaveLibrary ) + EVT_MENU( ID_LIBEDIT_SAVE_ALL_LIBS, LIB_EDIT_FRAME::OnSaveAllLibraries ) + EVT_TOOL( ID_LIBEDIT_REVERT_LIBRARY, LIB_EDIT_FRAME::OnRevertLibrary ) + // Part actions + EVT_TOOL( ID_LIBEDIT_NEW_PART, LIB_EDIT_FRAME::OnCreateNewPart ) + EVT_TOOL( ID_LIBEDIT_EDIT_PART, LIB_EDIT_FRAME::OnEditPart ) + EVT_TOOL( ID_LIBEDIT_IMPORT_PART, LIB_EDIT_FRAME::OnImportPart ) + EVT_TOOL( ID_LIBEDIT_EXPORT_PART, LIB_EDIT_FRAME::OnExportPart ) + EVT_TOOL( ID_LIBEDIT_SAVE_PART, LIB_EDIT_FRAME::OnSavePart ) + EVT_TOOL( ID_LIBEDIT_REVERT_PART, LIB_EDIT_FRAME::OnRevertPart ) + EVT_TOOL( ID_LIBEDIT_REMOVE_PART, LIB_EDIT_FRAME::OnRemovePart ) + + // Main horizontal toolbar. + EVT_TOOL( ID_TO_LIBVIEW, LIB_EDIT_FRAME::OnOpenLibraryViewer ) EVT_TOOL( wxID_UNDO, LIB_EDIT_FRAME::GetComponentFromUndoList ) EVT_TOOL( wxID_REDO, LIB_EDIT_FRAME::GetComponentFromRedoList ) EVT_TOOL( ID_LIBEDIT_GET_FRAME_EDIT_PART, LIB_EDIT_FRAME::OnEditComponentProperties ) @@ -98,9 +116,6 @@ BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME ) EVT_TOOL( ID_LIBEDIT_VIEW_DOC, LIB_EDIT_FRAME::OnViewEntryDoc ) EVT_TOOL( ID_LIBEDIT_EDIT_PIN_BY_PIN, LIB_EDIT_FRAME::Process_Special_Functions ) EVT_TOOL( ID_LIBEDIT_EDIT_PIN_BY_TABLE, LIB_EDIT_FRAME::OnOpenPinTable ) - EVT_TOOL( ID_LIBEDIT_EXPORT_PART, LIB_EDIT_FRAME::OnExportPart ) - EVT_TOOL( ID_LIBEDIT_IMPORT_PART, LIB_EDIT_FRAME::OnImportPart ) - EVT_TOOL( ID_LIBEDIT_SAVE_CURRENT_PART, LIB_EDIT_FRAME::OnSaveCurrentPart ) EVT_COMBOBOX( ID_LIBEDIT_SELECT_PART_NUMBER, LIB_EDIT_FRAME::OnSelectPart ) EVT_COMBOBOX( ID_LIBEDIT_SELECT_ALIAS, LIB_EDIT_FRAME::OnSelectAlias ) @@ -117,7 +132,6 @@ BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME ) // menubar commands EVT_MENU( wxID_EXIT, LIB_EDIT_FRAME::CloseWindow ) - EVT_MENU( ID_LIBEDIT_SAVE_CURRENT_LIB_AS, LIB_EDIT_FRAME::OnSaveActiveLibrary ) EVT_MENU( ID_LIBEDIT_GEN_PNG_FILE, LIB_EDIT_FRAME::OnPlotCurrentComponent ) EVT_MENU( ID_LIBEDIT_GEN_SVG_FILE, LIB_EDIT_FRAME::OnPlotCurrentComponent ) EVT_MENU( wxID_HELP, EDA_DRAW_FRAME::GetKicadHelp ) @@ -149,13 +163,13 @@ BEGIN_EVENT_TABLE( LIB_EDIT_FRAME, EDA_DRAW_FRAME ) // Update user interface elements. EVT_UPDATE_UI( ID_LIBEDIT_EXPORT_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) - EVT_UPDATE_UI( ID_LIBEDIT_SAVE_CURRENT_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) + EVT_UPDATE_UI( ID_LIBEDIT_SAVE_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) EVT_UPDATE_UI( ID_LIBEDIT_GET_FRAME_EDIT_FIELDS, LIB_EDIT_FRAME::OnUpdateEditingPart ) EVT_UPDATE_UI( ID_LIBEDIT_CHECK_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) EVT_UPDATE_UI( ID_LIBEDIT_GET_FRAME_EDIT_PART, LIB_EDIT_FRAME::OnUpdateEditingPart ) EVT_UPDATE_UI( wxID_UNDO, LIB_EDIT_FRAME::OnUpdateUndo ) EVT_UPDATE_UI( wxID_REDO, LIB_EDIT_FRAME::OnUpdateRedo ) - EVT_UPDATE_UI( ID_LIBEDIT_SAVE_CURRENT_LIB, LIB_EDIT_FRAME::OnUpdateSaveCurrentLib ) + EVT_UPDATE_UI( ID_LIBEDIT_SAVE_LIBRARY, LIB_EDIT_FRAME::OnUpdateSaveCurrentLib ) EVT_UPDATE_UI( ID_LIBEDIT_SAVE_LIBRARY_AS, LIB_EDIT_FRAME::OnUpdateSaveCurrentLibAs ) EVT_UPDATE_UI( ID_LIBEDIT_VIEW_DOC, LIB_EDIT_FRAME::OnUpdateViewDoc ) EVT_UPDATE_UI( ID_LIBEDIT_EDIT_PIN_BY_PIN, LIB_EDIT_FRAME::OnUpdatePinByPin ) @@ -189,7 +203,8 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : m_my_part = NULL; m_tempCopyComponent = NULL; - m_componentTree = nullptr; + m_treePane = nullptr; + m_libMgr = nullptr; // Delayed initialization if( m_textSize == -1 ) @@ -204,7 +219,8 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : LoadSettings( config() ); - SetScreen( new SCH_SCREEN( aKiway ) ); + m_dummyScreen = new SCH_SCREEN( aKiway ); + SetScreen( m_dummyScreen ); GetScreen()->m_Center = true; GetScreen()->SetMaxUndoItems( m_UndoRedoCountMax ); @@ -224,7 +240,9 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : if( m_canvas ) m_canvas->SetEnableBlockCommands( true ); - createComponentTree(); + m_libMgr = new LIB_MANAGER( *this ); + m_treePane = new CMP_TREE_PANE( this, m_libMgr ); + ReCreateMenuBar(); ReCreateHToolbar(); ReCreateVToolbar(); @@ -280,8 +298,8 @@ LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) : m_auimgr.AddPane( m_messagePanel, wxAuiPaneInfo( mesg ).Name( "MsgPanel" ).Bottom().Layer( 10 ) ); - m_auimgr.AddPane( m_componentTree, - wxAuiPaneInfo( vert ).Name( "ComponentTree" ).Left().Row( 1 ) ); + m_auimgr.AddPane( m_treePane, + wxAuiPaneInfo( vert ).Name( "ComponentTree" ).Left().Row( 1 ).Resizable().MinSize( 300, 400 ) ); m_auimgr.Update(); @@ -301,12 +319,14 @@ LIB_EDIT_FRAME::~LIB_EDIT_FRAME() Unbind( wxEVT_COMMAND_MENU_SELECTED, &LIB_EDIT_FRAME::OnEditSymbolLibTable, this, ID_EDIT_SYM_LIB_TABLE ); + // current screen is destroyed in EDA_DRAW_FRAME + SetScreen( m_dummyScreen ); + m_drawItem = m_lastDrawItem = NULL; delete m_tempCopyComponent; + delete m_libMgr; delete m_my_part; - m_my_part = NULL; - m_tempCopyComponent = NULL; } @@ -318,6 +338,7 @@ void LIB_EDIT_FRAME::SetDrawItem( LIB_ITEM* drawItem ) void LIB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) { + // TODO check all libraries for modifications if( GetScreen()->IsModify() ) { int ii = DisplayExitDialog( this, _( "Save the changes in the library before closing?" ) ); @@ -328,7 +349,7 @@ void LIB_EDIT_FRAME::OnCloseWindow( wxCloseEvent& Event ) break; case wxID_YES: - if( SaveActiveLibrary( false ) ) + if( saveLibrary( GetCurLib(), false ) ) break; // fall through: cancel the close because of an error @@ -458,15 +479,21 @@ void LIB_EDIT_FRAME::OnShowElectricalType( wxCommandEvent& event ) void LIB_EDIT_FRAME::OnToggleSearchTree( wxCommandEvent& event ) { - auto& treePane = m_auimgr.GetPane( m_componentTree ); + auto& treePane = m_auimgr.GetPane( m_treePane ); treePane.Show( !IsSearchTreeShown() ); m_auimgr.Update(); } +void LIB_EDIT_FRAME::OnEditSymbolLibTable( wxCommandEvent& aEvent ) +{ + SCH_BASE_FRAME::OnEditSymbolLibTable( aEvent ); +} + + bool LIB_EDIT_FRAME::IsSearchTreeShown() { - return m_auimgr.GetPane( m_componentTree ).IsShown(); + return m_auimgr.GetPane( m_treePane ).IsShown(); } @@ -515,17 +542,17 @@ void LIB_EDIT_FRAME::OnUpdateRedo( wxUpdateUIEvent& event ) void LIB_EDIT_FRAME::OnUpdateSaveCurrentLib( wxUpdateUIEvent& event ) { - wxString lib = GetCurLib(); + wxString lib = getTargetLib(); SYMBOL_LIB_TABLE* table = Prj().SchSymbolLibTable(); event.Enable( !lib.empty() && table->HasLibrary( lib ) && table->IsSymbolLibWritable( lib ) && - GetScreen()->IsModify() ); + m_libMgr->IsLibraryModified( lib ) ); } void LIB_EDIT_FRAME::OnUpdateSaveCurrentLibAs( wxUpdateUIEvent& event ) { - wxString lib = GetCurLib(); + wxString lib = getTargetLib(); SYMBOL_LIB_TABLE* table = Prj().SchSymbolLibTable(); event.Enable( !lib.empty() && table->HasLibrary( lib ) ); @@ -685,46 +712,6 @@ void LIB_EDIT_FRAME::OnSelectBodyStyle( wxCommandEvent& event ) } -void LIB_EDIT_FRAME::OnSaveCurrentPart( wxCommandEvent& aEvent ) -{ - LIB_PART* part = GetCurPart(); - - if( !part ) - { - DisplayError( this, _( "No part to save." ) ); - return; - } - - wxString libNickname = GetCurLib(); - - if( libNickname.empty() ) - SelectActiveLibrary(); - - libNickname = GetCurLib(); - - if( !libNickname ) - { - DisplayError( this, _( "No valid library specified." ) ); - return; - } - - try - { - Prj().SchSymbolLibTable()->SaveSymbol( libNickname, new LIB_PART( *part ) ); - } - catch( ... ) - { - wxString msg; - msg.Printf( _( "Unexpected error occured saving symbol '%s' to symbol library '%s'." ), - part->GetName(), libNickname ); - DisplayError( this, msg ); - return; - } - - refreshSchematic(); -} - - void LIB_EDIT_FRAME::Process_Special_Functions( wxCommandEvent& event ) { int id = event.GetId(); @@ -973,7 +960,7 @@ void LIB_EDIT_FRAME::OnActivate( wxActivateEvent& event ) } -wxString LIB_EDIT_FRAME::GetCurLib() +wxString LIB_EDIT_FRAME::GetCurLib() const { wxString libNickname = Prj().GetRString( PROJECT::SCH_LIBEDIT_CUR_LIB ); @@ -1003,16 +990,15 @@ wxString LIB_EDIT_FRAME::SetCurLib( const wxString& aLibNickname ) } -LIB_PART* LIB_EDIT_FRAME::GetCurPart() -{ - return m_my_part; -} - - void LIB_EDIT_FRAME::SetCurPart( LIB_PART* aPart ) { - delete m_my_part; - m_my_part = aPart; // take ownership here + wxASSERT( m_my_part != aPart ); + + if( m_my_part != aPart ) + { + delete m_my_part; + m_my_part = aPart; + } // retain in case this wxFrame is re-opened later on the same PROJECT Prj().SetRString( PROJECT::SCH_LIBEDIT_CUR_PART, aPart ? aPart->GetName() : wxString() ); @@ -1075,6 +1061,7 @@ void LIB_EDIT_FRAME::EditSymbolText( wxDC* DC, LIB_ITEM* DrawItem ) void LIB_EDIT_FRAME::OnEditComponentProperties( wxCommandEvent& event ) { bool partLocked = GetCurPart()->UnitsLocked(); + wxString oldName = GetCurPart()->GetName(); DIALOG_EDIT_COMPONENT_IN_LIBRARY dlg( this ); @@ -1088,6 +1075,8 @@ void LIB_EDIT_FRAME::OnEditComponentProperties( wxCommandEvent& event ) m_editPinsPerPartOrConvert = GetCurPart()->UnitsLocked() ? true : false; } + m_libMgr->UpdatePart( GetCurPart(), GetCurLib(), oldName ); + UpdateAliasSelectList(); UpdatePartSelectList(); DisplayLibInfos(); @@ -1391,50 +1380,11 @@ void LIB_EDIT_FRAME::deleteItem( wxDC* aDC ) } -void LIB_EDIT_FRAME::createComponentTree() +void LIB_EDIT_FRAME::OnModify() { - SYMBOL_LIB_TABLE* table = Prj().SchSymbolLibTable(); - auto adapter( CMP_TREE_MODEL_ADAPTER::Create( table ) ); - - for( const wxString& lib : table->GetLogicalLibs() ) - adapter->AddLibrary( lib ); - - adapter->ShowUnits( true ); - m_componentTree = new COMPONENT_TREE( this, table, adapter, COMPONENT_TREE::SEARCH ); - m_libMgr = new LIB_MANAGER( *this ); - - std::unique_ptr menuLibrary = std::make_unique(); - menuLibrary->Append( ID_LIBEDIT_NEW_LIBRARY, _( "New library..." ) ); - menuLibrary->Append( ID_LIBEDIT_ADD_LIBRARY, _( "Add existing library..." ) ); - menuLibrary->Append( ID_LIBEDIT_SAVE_LIBRARY, _( "Save library" ) ); - menuLibrary->Append( ID_LIBEDIT_SAVE_LIBRARY_AS, _( "Save library as..." ) ); - menuLibrary->Append( ID_LIBEDIT_REVERT_LIBRARY, _( "Revert library" ) ); - menuLibrary->Append( ID_LIBEDIT_REMOVE_LIBRARY, _( "Remove library" ) ); - menuLibrary->AppendSeparator(); - menuLibrary->Append( ID_LIBEDIT_NEW_PART, _( "New component..." ) ); - menuLibrary->Append( ID_LIBEDIT_PASTE_PART, _( "Paste component" ) ); - menuLibrary->Append( ID_LIBEDIT_IMPORT_PART, _( "Import component..." ) ); - - std::unique_ptr menuPart = std::make_unique(); - menuPart->Append( ID_LIBEDIT_EDIT_PART, _( "Edit" ) ); - menuPart->Append( ID_LIBEDIT_CUT_PART, _( "Cut" ) ); - menuPart->Append( ID_LIBEDIT_COPY_PART, _( "Copy" ) ); - menuPart->Append( ID_LIBEDIT_RENAME_PART, _( "Rename" ) ); - menuPart->Append( ID_LIBEDIT_REMOVE_PART, _( "Remove" ) ); - menuPart->Append( ID_LIBEDIT_EXPORT_PART, _( "Export..." ) ); - menuPart->Append( ID_LIBEDIT_SAVE_PART, _( "Save" ) ); - menuPart->Append( ID_LIBEDIT_REVERT_PART, _( "Revert" ) ); - menuPart->AppendSeparator(); - - // Append the library menu to the component menu - for( size_t i = 0; i < menuLibrary->GetMenuItemCount(); ++i ) - { - wxMenuItem* menuItem = menuLibrary->FindItemByPosition( i ); - menuPart->Append( menuItem->GetId(), menuItem->GetItemLabel() ); - } - - m_componentTree->SetMenu( CMP_TREE_NODE::ALIAS, std::move( menuPart ) ); - m_componentTree->SetMenu( CMP_TREE_NODE::LIB, std::move( menuLibrary ) ); + GetScreen()->SetModify(); + storeCurrentPart(); + m_treePane->GetCmpTree()->Refresh(); } @@ -1490,3 +1440,137 @@ void LIB_EDIT_FRAME::refreshSchematic() // in case any symbols have changed. Kiway().ExpressMail( FRAME_SCH, MAIL_SCH_REFRESH, std::string( "" ), this ); } + + +bool LIB_EDIT_FRAME::addLibraryFile( bool aCreateNew ) +{ + wxFileName fileName = getLibraryFileName( !aCreateNew ); + wxString libName = fileName.GetName(); + + if( libName.IsEmpty() ) + return false; + + if( m_libMgr->LibraryExists( libName ) ) + { + DisplayError( this, + wxString::Format( _( "Library '%s' already exists" ), GetChars( libName ) ) ); + return false; + } + + m_libMgr->AddLibrary( fileName.GetFullPath() ); + + if( aCreateNew ) + Prj().SchSymbolLibTable()->CreateSymbolLib( libName ); + + return true; +} + + +wxFileName LIB_EDIT_FRAME::getLibraryFileName( bool aExisting ) +{ + wxFileName fn = m_libMgr->GetUniqueLibraryName(); + fn.SetExt( SchematicLibraryFileExtension ); + + wxFileDialog dlg( this, + aExisting ? _( "Select Library" ) : _( "New Library" ), + Prj().GetProjectPath(), + aExisting ? wxString( wxEmptyString ) : fn.GetFullName() , + SchematicLibraryFileWildcard(), + aExisting ? wxFD_OPEN | wxFD_FILE_MUST_EXIST : + wxFD_SAVE | wxFD_CHANGE_DIR | wxFD_OVERWRITE_PROMPT ); + + if( dlg.ShowModal() == wxID_CANCEL ) + return wxFileName(); + + fn = dlg.GetPath(); + fn.SetExt( SchematicLibraryFileExtension ); + + return fn; +} + + +LIB_PART* LIB_EDIT_FRAME::getTargetPart() const +{ + LIB_ALIAS* alias = nullptr; + + if( m_treePane->GetCmpTree()->IsMenuActive() ) + { + LIB_ID libId = m_treePane->GetCmpTree()->GetSelectedLibId(); + alias = m_libMgr->GetAlias( libId.GetLibItemName(), libId.GetLibNickname() ); + } + else if( LIB_PART* part = GetCurPart() ) + { + alias = part->GetAlias( 0 ); + } + + return alias ? alias->GetPart() : nullptr; +} + + +LIB_ID LIB_EDIT_FRAME::getTargetLibId() const +{ + if( m_treePane->GetCmpTree()->IsMenuActive() ) + return m_treePane->GetCmpTree()->GetSelectedLibId(); + + if( LIB_PART* part = GetCurPart() ) + return part->GetLibId(); + + return LIB_ID(); +} + + +wxString LIB_EDIT_FRAME::getTargetLib() const +{ + if( m_treePane->GetCmpTree()->IsMenuActive() ) + { + LIB_ID libId = m_treePane->GetCmpTree()->GetSelectedLibId(); + return libId.GetLibNickname(); + } + else + { + return GetCurLib(); + } +} + + +SYMBOL_LIB_TABLE* LIB_EDIT_FRAME::SelectSymLibTable() +{ + wxArrayString libTableNames; + libTableNames.Add( _( "Global Symbol Library Table" ) ); + libTableNames.Add( _( "Project Symbol Library Table" ) ); + + switch( SelectSingleOption( this, _( "Select target symbol library table" ), + wxEmptyString, libTableNames ) ) + { + case 0: return &SYMBOL_LIB_TABLE::GetGlobalLibTable(); + case 1: return Prj().SchSymbolLibTable(); + } + + return nullptr; +} + + +void LIB_EDIT_FRAME::storeCurrentPart() +{ + if( m_my_part && !GetCurLib().IsEmpty() && GetScreen()->IsModify() ) + m_libMgr->UpdatePart( m_my_part, GetCurLib() ); // UpdatePart() makes a copy +} + + +bool LIB_EDIT_FRAME::isCurrentPart( const LIB_ID& aLibId ) const +{ + return ( GetCurPart() && aLibId == GetCurPart()->GetLibId() ); +} + + +void LIB_EDIT_FRAME::emptyScreen() +{ + SetCurLib( wxEmptyString ); + SetCurPart( nullptr ); + m_aliasName.Empty(); + m_drawItem = m_lastDrawItem = nullptr; + SetScreen( m_dummyScreen ); + m_dummyScreen->ClearUndoRedoList(); + Zoom_Automatique( false ); + Refresh(); +} diff --git a/eeschema/libeditframe.h b/eeschema/libeditframe.h index 3bb321cc9a..9ed710e8bb 100644 --- a/eeschema/libeditframe.h +++ b/eeschema/libeditframe.h @@ -4,6 +4,8 @@ * Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 2008 Wayne Stambaugh * Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors. + * Copyright (C) 2017 CERN + * @author Maciej Suminski * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -39,12 +41,14 @@ class SCH_EDIT_FRAME; +class SYMBOL_LIB_TABLE; class LIB_PART; class LIB_ALIAS; class LIB_FIELD; class DIALOG_LIB_EDIT_TEXT; -class COMPONENT_TREE; +class CMP_TREE_PANE; class LIB_ID; +class LIB_MANAGER; /** @@ -57,7 +61,8 @@ class LIB_EDIT_FRAME : public SCH_BASE_FRAME LIB_COLLECTOR m_collectedItems; ///< Used for hit testing. wxComboBox* m_partSelectBox; ///< a Box to select a part to edit (if any) wxComboBox* m_aliasSelectBox; ///< a box to select the alias to edit (if any) - COMPONENT_TREE* m_componentTree; ///< component search tree widget + CMP_TREE_PANE* m_treePane; ///< component search tree widget + LIB_MANAGER* m_libMgr; ///< manager taking care of temporary modificatoins /** Convert of the item currently being drawn. */ bool m_drawSpecificConvert; @@ -132,8 +137,6 @@ class LIB_EDIT_FRAME : public SCH_BASE_FRAME LIB_ITEM* locateItem( const wxPoint& aPosition, const KICAD_T aFilterList[] ); - void createComponentTree(); - public: LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ); @@ -141,7 +144,7 @@ public: ~LIB_EDIT_FRAME(); /** The nickname of the current library being edited and empty string if none. */ - wxString GetCurLib(); + wxString GetCurLib() const; /** Sets the current library nickname and returns the old library nickname. */ wxString SetCurLib( const wxString& aLibNickname ); @@ -151,7 +154,10 @@ public: * * This is a LIB_PART that I own, it is at best a copy of one in a library. */ - LIB_PART* GetCurPart(); + LIB_PART* GetCurPart() const + { + return m_my_part; + } /** * Take ownership of aPart and notes that it is the one currently being edited. @@ -208,6 +214,50 @@ public: void Process_Special_Functions( wxCommandEvent& event ); void OnSelectTool( wxCommandEvent& aEvent ); + /** + * Creates a new library. The library is added to the project libraries table. + */ + void OnCreateNewLibrary( wxCommandEvent& aEvent ) + { + addLibraryFile( true ); + } + + /** + * Adds an existing library. The library is added to the project libraries table. + */ + void OnAddLibrary( wxCommandEvent& aEvent ) + { + addLibraryFile( false ); + } + + /** + * The command event handler to save the changes to the current library. + * + * A backup file of the current library is saved with the .bak extension before the + * changes made to the library are saved. + */ + void OnSaveLibrary( wxCommandEvent& event ); + + /** + * Saves all changes in modified libraries. + */ + void OnSaveAllLibraries( wxCommandEvent& event ); + + /** + * Reverts unsaved changes in a library. + */ + void OnRevertLibrary( wxCommandEvent& aEvent ); + + /** + * Creates a new part in the selected library. + */ + void OnCreateNewPart( wxCommandEvent& aEvent ); + + /** + * Opens the selected part for editing. + */ + void OnEditPart( wxCommandEvent& aEvent ); + /** * Routine to read one part. * The format is that of libraries, but it loads only 1 component. @@ -217,12 +267,27 @@ public: void OnImportPart( wxCommandEvent& event ); /** - * Function OnExportPart - * creates a new library and backup the current component in this library or export + * Creates a new library and backup the current component in this library or exports * the component of the current library. */ void OnExportPart( wxCommandEvent& event ); + /** + * Saves a single part in the selected library. The library file is updated without including + * the remaining unsaved changes. + */ + void OnSavePart( wxCommandEvent& aEvent ); + + /** + * Reverts unsaved changes in a part, restoring to the last saved state. + */ + void OnRevertPart( wxCommandEvent& aEvent ); + + /** + * Removes a part from the working copy of a library. + */ + void OnRemovePart( wxCommandEvent& aEvent ); + void OnSelectAlias( wxCommandEvent& event ); void OnSelectPart( wxCommandEvent& event ); @@ -233,31 +298,12 @@ public: void OnToggleSearchTree( wxCommandEvent& event ); + void OnEditSymbolLibTable( wxCommandEvent& aEvent ) override; + bool IsSearchTreeShown(); - /** - * Delete a symbol from the current library. - * - * The deleted entry can be an alias or a component. If the entry is an alias, - * it is removed from the component and the list of alias is updated. If the - * entry is a component and the list of aliases is empty, the component and all - * it drawable items are deleted. Otherwise the first alias in the alias list - * becomes the new component name and the other aliases become dependent on - * renamed component. - * - * @note This only deletes the entry in memory. The file does not change. - */ - void DeleteOnePart( wxCommandEvent& event ); - - /** - * Create a new library symbol. - * - * If an old component is currently in edit, it is deleted. - */ - void CreateNewLibraryPart( wxCommandEvent& event ); - void OnEditComponentProperties( wxCommandEvent& event ); - void InstallFieldsEditorDialog( wxCommandEvent& event ); + void InstallFieldsEditorDialog( wxCommandEvent& event ); /** * Loads a symbol from the currently selected library. @@ -276,11 +322,12 @@ public: void OnOpenPinTable( wxCommandEvent& aEvent ); - void OnSaveCurrentPart( wxCommandEvent& aEvent ); - void OnUpdateSelectTool( wxUpdateUIEvent& aEvent ); void OnUpdateEditingPart( wxUpdateUIEvent& event ); - void OnUpdateNotEditingPart( wxUpdateUIEvent& event ); + void OnUpdateNotEditingPart( wxUpdateUIEvent& event ); // TODO? + void OnUpdatePartModified( wxUpdateUIEvent& aEvent ); + void OnUpdateLibModified( wxUpdateUIEvent& aEvent ); + void OnUpdateClipboardNotEmpty( wxUpdateUIEvent& aEvent ); void OnUpdateUndo( wxUpdateUIEvent& event ); void OnUpdateRedo( wxUpdateUIEvent& event ); void OnUpdateSaveCurrentLib( wxUpdateUIEvent& event ); @@ -357,10 +404,7 @@ public: * Must be called after a schematic change in order to set the "modify" flag of the * current screen. */ - void OnModify() - { - GetScreen()->SetModify(); - } + void OnModify(); const wxString& GetAliasName() { return m_aliasName; } @@ -427,6 +471,18 @@ public: bool IsEditingDrawItem() { return m_drawItem && m_drawItem->InEditMode(); } private: + void loadPart( const wxString& aLibrary, const wxString& aPart, int Unit ); + + /** + * Saves the changes to the current library. + * + * A backup file of the current library is saved with the .bak extension before the + * changes made to the library are saved. + * @param aLibrary is the library name. + * @param aNewFile Ask for a new file name to save the library. + * @return True if the library was successfully saved. + */ + bool saveLibrary( const wxString& aLibrary, bool aNewFile ); /** * Called when the frame is activated. Tests if the current library exists. @@ -445,24 +501,6 @@ private: */ void SelectActiveLibrary( const wxString& aLibrary = wxEmptyString ); - /** - * The command event handler to save the changes to the current library. - * - * A backup file of the current library is saved with the .bak extension before the - * changes made to the library are saved. - */ - void OnSaveActiveLibrary( wxCommandEvent& event ); - - /** - * Saves the changes to the current library. - * - * A backup file of the current library is saved with the .bak extension before the - * changes made to the library are saved. - * @param newFile Ask for a new file name to save the library. - * @return True if the library was successfully saved. - */ - bool SaveActiveLibrary( bool newFile ); - /** * Loads a symbol from the current active library, optionally setting the selected * unit and convert. @@ -653,6 +691,33 @@ public: */ void SVG_PlotComponent( const wxString& aFullFileName ); + /** + * Displays a dialog asking the user to select a symbol library table. + * @return Pointer to the selected symbol library table or nullptr if cancelled. + */ + SYMBOL_LIB_TABLE* SelectSymLibTable(); + + ///> Helper screen used when no part is loaded + SCH_SCREEN* m_dummyScreen; + + // TODO + // TODO move to tree pane? + LIB_PART* getTargetPart() const; + + LIB_ID getTargetLibId() const; + + wxString getTargetLib() const; + + bool addLibraryFile( bool aCreateNew ); + + wxFileName getLibraryFileName( bool aExisting ); + + void storeCurrentPart(); + + bool isCurrentPart( const LIB_ID& aLibId ) const; + + void emptyScreen(); + DECLARE_EVENT_TABLE() }; diff --git a/eeschema/sch_base_frame.h b/eeschema/sch_base_frame.h index ae673f1b41..121f0c62e1 100644 --- a/eeschema/sch_base_frame.h +++ b/eeschema/sch_base_frame.h @@ -201,7 +201,7 @@ public: const LIB_ID* aHighlight = nullptr, bool aAllowFields = true ); - void OnEditSymbolLibTable( wxCommandEvent& aEvent ); + virtual void OnEditSymbolLibTable( wxCommandEvent& aEvent ); /** * Load symbol from symbol library table. diff --git a/eeschema/tool_lib.cpp b/eeschema/tool_lib.cpp index 61b8f79a6c..d2f823765b 100644 --- a/eeschema/tool_lib.cpp +++ b/eeschema/tool_lib.cpp @@ -107,7 +107,7 @@ void LIB_EDIT_FRAME::ReCreateHToolbar() KiBitmap( new_library_xpm ), _( "Create a new library" ) ); - m_mainToolBar->AddTool( ID_LIBEDIT_SAVE_CURRENT_LIB, wxEmptyString, + m_mainToolBar->AddTool( ID_LIBEDIT_SAVE_LIBRARY, wxEmptyString, KiBitmap( save_library_xpm ), _( "Save current library" ) ); @@ -115,7 +115,7 @@ void LIB_EDIT_FRAME::ReCreateHToolbar() m_mainToolBar->AddTool( ID_LIBEDIT_NEW_PART, wxEmptyString, KiBitmap( new_component_xpm ), _( "Create new component" ) ); - m_mainToolBar->AddTool( ID_LIBEDIT_SAVE_CURRENT_PART, wxEmptyString, + m_mainToolBar->AddTool( ID_LIBEDIT_SAVE_PART, wxEmptyString, KiBitmap( save_part_in_mem_xpm ), // TODO change icon _( "Save component" ) ); diff --git a/eeschema/widgets/cmp_tree_pane.cpp b/eeschema/widgets/cmp_tree_pane.cpp new file mode 100644 index 0000000000..de8d77e6ee --- /dev/null +++ b/eeschema/widgets/cmp_tree_pane.cpp @@ -0,0 +1,102 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * 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 3 + * 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: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "cmp_tree_pane.h" + +#include +#include +#include +#include +#include + +CMP_TREE_PANE::CMP_TREE_PANE( LIB_EDIT_FRAME* aParent, LIB_MANAGER* aLibMgr ) + : wxPanel( aParent ), + m_libEditFrame( aParent ), + m_libMgr( aLibMgr ) +{ + // Create widgets + wxBoxSizer* boxSizer = new wxBoxSizer( wxVERTICAL ); + + m_tree = new COMPONENT_TREE( this, &SYMBOL_LIB_TABLE::GetGlobalLibTable(), + m_libMgr->GetAdapter(), COMPONENT_TREE::SEARCH ); + boxSizer->Add( m_tree, 1, wxEXPAND | wxALL, 5 ); + + SetSizer( boxSizer ); + Layout(); + boxSizer->Fit( this ); + + // Setup right click-context menus + std::unique_ptr menuLibrary = std::make_unique(); + menuLibrary->Append( ID_LIBEDIT_NEW_LIBRARY, _( "New library..." ) ); + menuLibrary->Append( ID_LIBEDIT_ADD_LIBRARY, _( "Add existing library..." ) ); + menuLibrary->Append( ID_LIBEDIT_SAVE_LIBRARY, _( "Save library" ) ); + menuLibrary->Append( ID_LIBEDIT_SAVE_LIBRARY_AS, _( "Save library as..." ) ); + menuLibrary->Append( ID_LIBEDIT_REVERT_LIBRARY, _( "Revert library" ) ); + menuLibrary->AppendSeparator(); + menuLibrary->Append( ID_LIBEDIT_NEW_PART, _( "New component..." ) ); + menuLibrary->Append( ID_LIBEDIT_IMPORT_PART, _( "Import component..." ) ); + + std::unique_ptr menuPart = std::make_unique(); + menuPart->Append( ID_LIBEDIT_EDIT_PART, _( "Edit" ) ); + menuPart->Append( ID_LIBEDIT_REMOVE_PART, _( "Remove" ) ); + menuPart->Append( ID_LIBEDIT_EXPORT_PART, _( "Export..." ) ); + menuPart->Append( ID_LIBEDIT_SAVE_PART, _( "Save" ) ); + menuPart->Append( ID_LIBEDIT_REVERT_PART, _( "Revert" ) ); + menuPart->AppendSeparator(); + + // Append the library menu to the component menu + for( size_t i = 0; i < menuLibrary->GetMenuItemCount(); ++i ) + { + wxMenuItem* menuItem = menuLibrary->FindItemByPosition( i ); + menuPart->Append( menuItem->GetId(), menuItem->GetItemLabel() ); + } + + std::unique_ptr menuNoSelection = std::make_unique(); + menuNoSelection->Append( ID_LIBEDIT_NEW_LIBRARY, _( "New library..." ) ); + menuNoSelection->Append( ID_LIBEDIT_ADD_LIBRARY, _( "Add existing library..." ) ); + + m_tree->SetMenu( CMP_TREE_NODE::LIBID, std::move( menuPart ) ); + m_tree->SetMenu( CMP_TREE_NODE::LIB, std::move( menuLibrary ) ); + m_tree->SetMenu( CMP_TREE_NODE::INVALID, std::move( menuNoSelection ) ); + + // Event handlers + Bind( COMPONENT_SELECTED, &CMP_TREE_PANE::onComponentSelected, this ); +} + + +CMP_TREE_PANE::~CMP_TREE_PANE() +{ + delete m_tree; +} + + +void CMP_TREE_PANE::onComponentSelected( wxCommandEvent& aEvent ) +{ + // Repost the event + wxCommandEvent evt( ID_LIBEDIT_EDIT_PART ); + // I cannot figure out why the two methods below do not work.. + //wxPostEvent( libEditFrame, evt ); + //wxQueueEvent( m_libEditFrame, new wxCommandEvent( ID_LIBEDIT_EDIT_PART ) ); + m_libEditFrame->OnEditPart( evt ); +} diff --git a/eeschema/widgets/cmp_tree_pane.h b/eeschema/widgets/cmp_tree_pane.h new file mode 100644 index 0000000000..da76d88173 --- /dev/null +++ b/eeschema/widgets/cmp_tree_pane.h @@ -0,0 +1,57 @@ +/* + * This program source code file is part of KiCad, a free EDA CAD application. + * + * Copyright (C) 2017 CERN + * @author Maciej Suminski + * + * 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 3 + * 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: + * https://www.gnu.org/licenses/gpl-3.0.html + * or you may search the http://www.gnu.org website for the version 3 license, + * or you may write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef CMP_TREE_PANE_H +#define CMP_TREE_PANE_H + +#include + +class COMPONENT_TREE; +class LIB_EDIT_FRAME; +class LIB_MANAGER; + +/** + * Library Editor pane with component tree and symbol library table selector. + */ +class CMP_TREE_PANE : public wxPanel +{ +public: + CMP_TREE_PANE( LIB_EDIT_FRAME* aParent, LIB_MANAGER* aLibMgr ); + ~CMP_TREE_PANE(); + + COMPONENT_TREE* GetCmpTree() const + { + return m_tree; + } + +protected: + void onSymLibTableSelected( wxCommandEvent& aEvent ); + void onComponentSelected( wxCommandEvent& aEvent ); + + LIB_EDIT_FRAME* m_libEditFrame; + COMPONENT_TREE* m_tree; ///< component search tree widget + LIB_MANAGER* m_libMgr; +}; + +#endif /* CMP_TREE_PANE_H */