ADDED New Library functionality to Footprint/Symbol Save As.

Fixes https://gitlab.com/kicad/code/kicad/issues/2343
This commit is contained in:
Jeff Young 2022-04-19 19:09:19 +01:00
parent 84f620a96e
commit 08f15fe587
9 changed files with 226 additions and 117 deletions

View File

@ -34,6 +34,8 @@ EDA_LIST_DIALOG_BASE::EDA_LIST_DIALOG_BASE( wxWindow* parent, wxWindowID id, con
bSizerMain->Add( bMargins, 1, wxEXPAND|wxRIGHT|wxLEFT, 5 );
m_ButtonsSizer = new wxBoxSizer( wxHORIZONTAL );
m_sdbSizer = new wxStdDialogButtonSizer();
m_sdbSizerOK = new wxButton( this, wxID_OK );
m_sdbSizer->AddButton( m_sdbSizerOK );
@ -41,7 +43,10 @@ EDA_LIST_DIALOG_BASE::EDA_LIST_DIALOG_BASE( wxWindow* parent, wxWindowID id, con
m_sdbSizer->AddButton( m_sdbSizerCancel );
m_sdbSizer->Realize();
bSizerMain->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 );
m_ButtonsSizer->Add( m_sdbSizer, 1, wxALL, 5 );
bSizerMain->Add( m_ButtonsSizer, 0, wxEXPAND, 5 );
this->SetSizer( bSizerMain );

View File

@ -260,20 +260,31 @@
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND|wxALL</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">m_sdbSizer</property>
<property name="permission">protected</property>
<property name="name">m_ButtonsSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">public</property>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">1</property>
<object class="wxStdDialogButtonSizer" expanded="1">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_sdbSizer</property>
<property name="permission">protected</property>
</object>
</object>
</object>
</object>
</object>

View File

@ -47,6 +47,7 @@ class EDA_LIST_DIALOG_BASE : public DIALOG_SHIM
public:
wxBoxSizer* m_ButtonsSizer;
EDA_LIST_DIALOG_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~EDA_LIST_DIALOG_BASE();

View File

@ -828,13 +828,13 @@ bool SYMBOL_EDIT_FRAME::SynchronizePins()
}
bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
wxString SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
{
// Select the target library table (global/project)
SYMBOL_LIB_TABLE* libTable = selectSymLibTable();
if( !libTable )
return false;
return wxEmptyString;
wxFileName fn = m_libMgr->GetUniqueLibraryName();
@ -843,18 +843,18 @@ bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
( libTable == &SYMBOL_LIB_TABLE::GetGlobalLibTable() ),
PATHS::GetDefaultUserSymbolsPath() ) )
{
return false;
return wxEmptyString;
}
wxString libName = fn.GetName();
if( libName.IsEmpty() )
return false;
return wxEmptyString;
if( m_libMgr->LibraryExists( libName ) )
{
DisplayError( this, wxString::Format( _( "Library '%s' already exists." ), libName ) );
return false;
return wxEmptyString;
}
if( aCreateNew )
@ -862,9 +862,10 @@ bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
if( !m_libMgr->CreateLibrary( fn.GetFullPath(), libTable ) )
{
DisplayError( this, wxString::Format( _( "Could not create the library file '%s'.\n"
"Make sure you have write permissions and try again." ),
"Make sure you have write permissions and "
"try again." ),
fn.GetFullPath() ) );
return false;
return wxEmptyString;
}
}
else
@ -872,7 +873,7 @@ bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
if( !m_libMgr->AddLibrary( fn.GetFullPath(), libTable ) )
{
DisplayError( this, _( "Could not open the library file." ) );
return false;
return wxEmptyString;
}
}
@ -882,7 +883,7 @@ bool SYMBOL_EDIT_FRAME::AddLibraryFile( bool aCreateNew )
std::string packet = fn.GetFullPath().ToStdString();
this->Kiway().ExpressMail( FRAME_SCH_SYMBOL_EDITOR, MAIL_LIB_EDIT, packet );
return true;
return fn.GetFullPath();
}

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2014 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2017 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
@ -44,6 +44,7 @@ class LIB_TREE_NODE;
class LIB_ID;
class SYMBOL_LIBRARY_MANAGER;
class SYMBOL_EDITOR_SETTINGS;
class EDA_LIST_DIALOG;
/**
@ -121,7 +122,7 @@ public:
/**
* Create or add an existing library to the symbol library table.
*/
bool AddLibraryFile( bool aCreateNew );
wxString AddLibraryFile( bool aCreateNew );
/**
* Create a new symbol in the selected library.
@ -369,6 +370,9 @@ private:
// Set up the tool framework
void setupTools();
EDA_LIST_DIALOG* buildSaveAsDialog( const wxString& aSymbolName,
const wxString& aLibraryPreselect );
void saveSymbolAs();
/**

View File

@ -3,7 +3,7 @@
*
* Copyright (C) 2019 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
* Copyright (C) 2004-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -646,6 +646,68 @@ void SYMBOL_EDIT_FRAME::SaveSymbolAs()
}
static int ID_SAVE_AS_NAME = 4172;
static int ID_MAKE_NEW_LIBRARY = 4173;
EDA_LIST_DIALOG* SYMBOL_EDIT_FRAME::buildSaveAsDialog( const wxString& aSymbolName,
const wxString& aLibraryPreselect )
{
SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable();
std::vector<wxString> libNicknames = tbl->GetLogicalLibs();
wxArrayString headers;
std::vector<wxArrayString> itemsToDisplay;
headers.Add( _( "Nickname" ) );
headers.Add( _( "Description" ) );
for( const wxString& nickname : libNicknames )
{
wxArrayString item;
item.Add( nickname );
item.Add( tbl->GetDescription( nickname ) );
itemsToDisplay.push_back( item );
}
EDA_LIST_DIALOG* dlg = new EDA_LIST_DIALOG( this, _( "Save Symbol As" ), headers,
itemsToDisplay, aLibraryPreselect );
dlg->SetListLabel( _( "Save in library:" ) );
dlg->SetOKLabel( _( "Save" ) );
wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* label = new wxStaticText( dlg, wxID_ANY, _( "Name:" ) );
bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
wxTextCtrl* nameTextCtrl = new wxTextCtrl( dlg, ID_SAVE_AS_NAME, aSymbolName );
bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxButton* newLibraryButton = new wxButton( dlg, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
dlg->m_ButtonsSizer->Prepend( 80, 20 );
dlg->m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
dlg->GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
dlg->Bind( wxEVT_BUTTON,
[dlg]( wxCommandEvent& )
{
dlg->EndModal( ID_MAKE_NEW_LIBRARY );
}, ID_MAKE_NEW_LIBRARY );
// Move nameTextCtrl to the head of the tab-order
if( dlg->GetChildren().DeleteObject( nameTextCtrl ) )
dlg->GetChildren().Insert( nameTextCtrl );
dlg->SetInitialFocus( nameTextCtrl );
dlg->Layout();
dlg->GetSizer()->Fit( dlg );
return dlg;
}
void SYMBOL_EDIT_FRAME::saveSymbolAs()
{
LIB_SYMBOL* symbol = getTargetSymbol();
@ -653,57 +715,36 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
if( symbol )
{
LIB_ID old_lib_id = symbol->GetLibId();
wxString old_name = old_lib_id.GetLibItemName();
wxString old_lib = old_lib_id.GetLibNickname();
wxString symbolName = old_lib_id.GetLibItemName();
wxString libraryName = old_lib_id.GetLibNickname();
bool done = false;
SYMBOL_LIB_TABLE* tbl = Prj().SchSymbolLibTable();
wxArrayString headers;
std::vector< wxArrayString > itemsToDisplay;
std::vector< wxString > libNicknames = tbl->GetLogicalLibs();
std::unique_ptr<EDA_LIST_DIALOG> dlg;
headers.Add( _( "Nickname" ) );
headers.Add( _( "Description" ) );
for( const wxString& name : libNicknames )
while( !done )
{
wxArrayString item;
item.Add( name );
item.Add( tbl->GetDescription( name ) );
itemsToDisplay.push_back( item );
dlg.reset( buildSaveAsDialog( symbolName, libraryName ) );
int ret = dlg->ShowModal();
if( ret == wxID_CANCEL )
{
return;
}
else if( ret == wxID_OK )
{
done = true;
}
else if( ret == ID_MAKE_NEW_LIBRARY )
{
wxFileName newLibrary( AddLibraryFile( true ) );
libraryName = newLibrary.GetName();
}
}
EDA_LIST_DIALOG dlg( this, _( "Save Symbol As" ), headers, itemsToDisplay, old_lib );
dlg.SetListLabel( _( "Save in library:" ) );
dlg.SetOKLabel( _( "Save" ) );
libraryName = dlg->GetTextSelection();
wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ),
wxDefaultPosition, wxDefaultSize, 0 );
bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, old_name,
wxDefaultPosition, wxDefaultSize, 0 );
bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxSizer* mainSizer = dlg.GetSizer();
mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
// Move nameTextCtrl to the head of the tab-order
if( dlg.GetChildren().DeleteObject( nameTextCtrl ) )
dlg.GetChildren().Insert( nameTextCtrl );
dlg.SetInitialFocus( nameTextCtrl );
dlg.Layout();
mainSizer->Fit( &dlg );
if( dlg.ShowModal() != wxID_OK )
return; // canceled by user
wxString new_lib = dlg.GetTextSelection();
if( new_lib.IsEmpty() )
if( libraryName.IsEmpty() )
{
DisplayError( this, _( "No library specified. Symbol could not be saved." ) );
return;
@ -712,30 +753,30 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
// @todo Either check the selecteced library to see if the parent symbol name is in
// the new library and/or copy the parent symbol as well. This is the lazy
// solution to ensure derived symbols do not get orphaned.
if( symbol->IsAlias() && new_lib != old_lib )
if( symbol->IsAlias() && libraryName != old_lib_id.GetLibNickname() )
{
DisplayError( this, _( "Derived symbols must be saved in the same library as their "
"parent symbol." ) );
return;
}
wxString new_name = nameTextCtrl->GetValue();
new_name.Trim( true );
new_name.Trim( false );
new_name.Replace( " ", "_" );
symbolName = static_cast<wxTextCtrl*>( dlg->FindWindow( ID_SAVE_AS_NAME ) )->GetValue();
symbolName.Trim( true );
symbolName.Trim( false );
symbolName.Replace( " ", "_" );
if( new_name.IsEmpty() )
if( symbolName.IsEmpty() )
{
// This is effectively a cancel. No need to nag the user about it.
return;
}
// Test if there is a symbol with this name already.
if( m_libMgr->SymbolExists( new_name, new_lib ) )
if( m_libMgr->SymbolExists( symbolName, libraryName ) )
{
wxString msg = wxString::Format( _( "Symbol '%s' already exists in library '%s'" ),
new_name,
new_lib );
symbolName,
libraryName );
KIDIALOG errorDlg( this, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
errorDlg.SetOKLabel( _( "Overwrite" ) );
@ -746,12 +787,12 @@ void SYMBOL_EDIT_FRAME::saveSymbolAs()
}
LIB_SYMBOL new_symbol( *symbol );
new_symbol.SetName( new_name );
new_symbol.SetName( symbolName );
m_libMgr->UpdateSymbol( &new_symbol, new_lib );
m_libMgr->UpdateSymbol( &new_symbol, libraryName );
SyncLibraries( false );
m_treePane->GetLibTree()->SelectLibId( LIB_ID( new_lib, new_symbol.GetName() ) );
LoadSymbol( new_name, new_lib, m_unit );
m_treePane->GetLibTree()->SelectLibId( LIB_ID( libraryName, new_symbol.GetName() ) );
LoadSymbol( symbolName, libraryName, m_unit );
}
}

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 1992-2021 KiCad Developers, see AUTHORS.txt for contributors.
* Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@ -31,6 +31,7 @@ class FP_LIB_TABLE;
class FOOTPRINT_TREE_PANE;
class SYMBOL_LIBRARY_MANAGER;
class FOOTPRINT_EDITOR_SETTINGS;
class EDA_LIST_DIALOG;
namespace PCB { struct IFACE; } // A KIFACE coded in pcbnew.cpp
@ -320,6 +321,9 @@ protected:
/// protected so only friend PCB::IFACE::CreateWindow() can act as sole factory.
FOOTPRINT_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent );
EDA_LIST_DIALOG* buildSaveAsDialog( const wxString& aFootprintName,
const wxString& aLibraryPreselect );
/**
* Make sure the footprint info list is loaded (with a progress dialog) and then initialize
* the footprint library tree.

View File

@ -975,22 +975,17 @@ bool FOOTPRINT_EDIT_FRAME::SaveFootprintToBoard( bool aAddNew )
}
bool FOOTPRINT_EDIT_FRAME::SaveFootprintAs( FOOTPRINT* aFootprint )
static int ID_SAVE_AS_NAME = 4172;
static int ID_MAKE_NEW_LIBRARY = 4173;
EDA_LIST_DIALOG* FOOTPRINT_EDIT_FRAME::buildSaveAsDialog( const wxString& aFootprintName,
const wxString& aLibraryPreselect )
{
if( aFootprint == nullptr )
return false;
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs();
SetMsgPanel( aFootprint );
wxString libraryName = aFootprint->GetFPID().GetLibNickname();
wxString footprintName = aFootprint->GetFPID().GetLibItemName();
bool updateValue = aFootprint->GetValue() == footprintName;
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs();
std::vector<wxString> nicknames = tbl->GetLogicalLibs();
wxArrayString headers;
std::vector<wxArrayString> itemsToDisplay;
std::vector<wxString> nicknames = tbl->GetLogicalLibs();
headers.Add( _( "Nickname" ) );
headers.Add( _( "Description" ) );
@ -1003,40 +998,87 @@ bool FOOTPRINT_EDIT_FRAME::SaveFootprintAs( FOOTPRINT* aFootprint )
itemsToDisplay.push_back( item );
}
EDA_LIST_DIALOG dlg( this, _( "Save Footprint As" ), headers, itemsToDisplay, libraryName );
dlg.SetListLabel( _( "Save in library:" ) );
dlg.SetOKLabel( _( "Save" ) );
EDA_LIST_DIALOG* dlg = new EDA_LIST_DIALOG( this, _( "Save Footprint As" ), headers,
itemsToDisplay, aLibraryPreselect );
dlg->SetListLabel( _( "Save in library:" ) );
dlg->SetOKLabel( _( "Save" ) );
wxBoxSizer* bNameSizer = new wxBoxSizer( wxHORIZONTAL );
wxStaticText* label = new wxStaticText( &dlg, wxID_ANY, _( "Name:" ),
wxDefaultPosition, wxDefaultSize, 0 );
wxStaticText* label = new wxStaticText( dlg, wxID_ANY, _( "Name:" ) );
bNameSizer->Add( label, 0, wxALIGN_CENTER_VERTICAL|wxTOP|wxBOTTOM|wxLEFT, 5 );
wxTextCtrl* nameTextCtrl = new wxTextCtrl( &dlg, wxID_ANY, footprintName,
wxDefaultPosition, wxDefaultSize, 0 );
wxTextCtrl* nameTextCtrl = new wxTextCtrl( dlg, ID_SAVE_AS_NAME, aFootprintName );
bNameSizer->Add( nameTextCtrl, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
wxTextValidator nameValidator( wxFILTER_EXCLUDE_CHAR_LIST );
nameValidator.SetCharExcludes( FOOTPRINT::StringLibNameInvalidChars( false ) );
nameTextCtrl->SetValidator( nameValidator );
wxSizer* mainSizer = dlg.GetSizer();
mainSizer->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
wxButton* newLibraryButton = new wxButton( dlg, ID_MAKE_NEW_LIBRARY, _( "New Library..." ) );
dlg->m_ButtonsSizer->Prepend( 80, 20 );
dlg->m_ButtonsSizer->Prepend( newLibraryButton, 0, wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT, 10 );
dlg->GetSizer()->Prepend( bNameSizer, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
dlg->Bind( wxEVT_BUTTON,
[dlg]( wxCommandEvent& )
{
dlg->EndModal( ID_MAKE_NEW_LIBRARY );
}, ID_MAKE_NEW_LIBRARY );
// Move nameTextCtrl to the head of the tab-order
if( dlg.GetChildren().DeleteObject( nameTextCtrl ) )
dlg.GetChildren().Insert( nameTextCtrl );
if( dlg->GetChildren().DeleteObject( nameTextCtrl ) )
dlg->GetChildren().Insert( nameTextCtrl );
dlg.SetInitialFocus( nameTextCtrl );
dlg->SetInitialFocus( nameTextCtrl );
dlg.Layout();
mainSizer->Fit( &dlg );
dlg->Layout();
dlg->GetSizer()->Fit( dlg );
if( dlg.ShowModal() != wxID_OK )
return false; // canceled by user
return dlg;
}
libraryName = dlg.GetTextSelection();
bool FOOTPRINT_EDIT_FRAME::SaveFootprintAs( FOOTPRINT* aFootprint )
{
if( aFootprint == nullptr )
return false;
FP_LIB_TABLE* tbl = Prj().PcbFootprintLibs();
SetMsgPanel( aFootprint );
wxString libraryName = aFootprint->GetFPID().GetLibNickname();
wxString footprintName = aFootprint->GetFPID().GetLibItemName();
bool updateValue = aFootprint->GetValue() == footprintName;
bool done = false;
std::unique_ptr<EDA_LIST_DIALOG> dlg;
while( !done )
{
dlg.reset( buildSaveAsDialog( footprintName, libraryName ) );
int ret = dlg->ShowModal();
if( ret == wxID_CANCEL )
{
return false;
}
else if( ret == wxID_OK )
{
done = true;
}
else if( ret == ID_MAKE_NEW_LIBRARY )
{
wxFileName newLibrary( CreateNewLibrary() );
libraryName = newLibrary.GetName();
}
}
libraryName = dlg->GetTextSelection();
if( libraryName.IsEmpty() )
{
@ -1044,7 +1086,7 @@ bool FOOTPRINT_EDIT_FRAME::SaveFootprintAs( FOOTPRINT* aFootprint )
return false;
}
footprintName = nameTextCtrl->GetValue();
footprintName = static_cast<wxTextCtrl*>( dlg->FindWindow( ID_SAVE_AS_NAME ) )->GetValue();
footprintName.Trim( true );
footprintName.Trim( false );

View File

@ -403,8 +403,8 @@ FOOTPRINT* FOOTPRINT_EDIT_FRAME::SelectFootprintFromBoard( BOARD* aPcb )
bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath )
{
const wxString& curLibPath = aLibraryPath;
wxString dstLibPath = CreateNewLibrary( wxEmptyString, aLibraryPath );
const wxString& curLibPath = aLibraryPath;
wxString dstLibPath = CreateNewLibrary( wxEmptyString, aLibraryPath );
if( !dstLibPath )
return false; // user aborted in CreateNewLibrary()