Library Manager: logic

This commit is contained in:
Maciej Suminski 2017-11-12 18:55:20 +01:00
parent 769c6a8d51
commit a789b735e9
14 changed files with 1988 additions and 441 deletions

View File

@ -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

View File

@ -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,

View File

@ -38,6 +38,7 @@
#include <class_library.h>
#include <wildcards_and_files_ext.h>
#include <eeschema_id.h>
#include <lib_manager.h>
#include <wx/filename.h>
@ -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() );

658
eeschema/lib_manager.cpp Normal file
View File

@ -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 <maciej.suminski@cern.ch>
*
* 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 <lib_manager.h>
#include <class_libentry.h>
#include <class_library.h>
#include <libeditframe.h>
#include <kiway.h>
#include <profile.h>
#include <symbol_lib_table.h>
#include <sch_legacy_plugin.h>
#include <list>
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_ALIAS*> LIB_MANAGER::GetAliases( const wxString& aLibrary ) const
{
std::list<LIB_ALIAS*> 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<unsigned int>::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<unsigned int>::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<LIB_PART*> 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<PART_BUFFER>( 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;
}

347
eeschema/lib_manager.h Normal file
View File

@ -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 <maciej.suminski@cern.ch>
*
* 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 <map>
#include <list>
#include <deque>
#include <set>
#include <memory>
#include <wx/arrstr.h>
#include <lib_manager_adapter.h>
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<LIB_ALIAS*> 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<PART_BUFFER> PTR;
typedef std::weak_ptr<PART_BUFFER> 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<PART_BUFFER::PTR>& GetBuffers() const
{
return m_parts;
}
///> Returns all aliases of buffered parts
const std::map<wxString, PART_BUFFER::WEAK_PTR>& 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<wxString, PART_BUFFER::WEAK_PTR> m_aliases;
std::deque<PART_BUFFER::PTR> m_parts;
///> Buffer to keep deleted parts until the library is saved
std::deque<PART_BUFFER::PTR> 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<wxString, LIB_BUFFER> m_libs;
LIB_MANAGER_ADAPTER::PTR m_adapter;
LIB_MANAGER_ADAPTER* getAdapter() { return static_cast<LIB_MANAGER_ADAPTER*>( m_adapter.get() ); }
};
#endif /* LIB_MANAGER_H */

View File

@ -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 <maciej.suminski@cern.ch>
*
* 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 <lib_manager_adapter.h>
#include <lib_manager.h>
#include <class_libentry.h>
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<CMP_TREE_NODE>& 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 )
{
}

View File

@ -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 <maciej.suminski@cern.ch>
*
* 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 <cmp_tree_model_adapter_base.h>
#include <map>
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<wxString, int> m_libHashes;
int getSyncHash() const
{
int hash = 0;
for( const auto& h : m_libHashes )
hash += h.second;
return hash;
}
};
#endif /* LIB_MANAGER_ADAPTER_H */

View File

@ -46,6 +46,9 @@
#include <wildcards_and_files_ext.h>
#include <schframe.h>
#include <symbol_lib_table.h>
#include <lib_manager.h>
#include <cmp_tree_pane.h>
#include <component_tree.h>
#include <dialog_choose_component.h>
#include <cmp_tree_model_adapter.h>
@ -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();
}

View File

@ -37,6 +37,7 @@
#include <gr_basic.h>
#include <schframe.h>
#include <msgpanel.h>
#include <confirm.h>
#include <general.h>
#include <eeschema_id.h>
@ -44,6 +45,10 @@
#include <class_library.h>
#include <lib_polyline.h>
#include <lib_pin.h>
#include <lib_manager.h>
#include <widgets/cmp_tree_pane.h>
#include <widgets/component_tree.h>
#include <symbol_lib_table.h>
#include <kicad_device_context.h>
@ -53,7 +58,7 @@
#include <dialogs/dialog_edit_component_in_lib.h>
#include <dialogs/dialog_lib_edit_pin_table.h>
#include <widgets/component_tree.h>
#include <wildcards_and_files_ext.h>
#include <menus_helpers.h>
@ -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<wxMenu> menuLibrary = std::make_unique<wxMenu>();
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<wxMenu> menuPart = std::make_unique<wxMenu>();
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();
}

View File

@ -4,6 +4,8 @@
* Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2004-2017 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* 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()
};

View File

@ -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.

View File

@ -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" ) );

View File

@ -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 <maciej.suminski@cern.ch>
*
* 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 <component_tree.h>
#include <eeschema_id.h>
#include <lib_manager.h>
#include <libeditframe.h>
#include <symbol_lib_table.h>
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<wxMenu> menuLibrary = std::make_unique<wxMenu>();
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<wxMenu> menuPart = std::make_unique<wxMenu>();
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<wxMenu> menuNoSelection = std::make_unique<wxMenu>();
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 );
}

View File

@ -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 <maciej.suminski@cern.ch>
*
* 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 <wx/panel.h>
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 */