Move library table editing dialog to new system
This commit is contained in:
@@ -65,7 +65,84 @@
|
||||
#include <paths.h>
|
||||
#include <macros.h>
|
||||
|
||||
// clang-format off
|
||||
|
||||
/**
|
||||
* Container that describes file type info for the add a library options
|
||||
*/
|
||||
struct SUPPORTED_FILE_TYPE
|
||||
{
|
||||
wxString m_Description; ///< Description shown in the file picker dialog.
|
||||
wxString m_FileFilter; ///< Filter used for file pickers if m_IsFile is true.
|
||||
wxString m_FolderSearchExtension; ///< In case of folders it stands for extensions of files
|
||||
///< stored inside.
|
||||
bool m_IsFile; ///< Whether the library is a folder or a file.
|
||||
DESIGN_BLOCK_IO_MGR::DESIGN_BLOCK_FILE_T m_Plugin;
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Traverser implementation that looks to find any and all "folder" libraries by looking for files
|
||||
* with a specific extension inside folders
|
||||
*/
|
||||
class LIBRARY_TRAVERSER : public wxDirTraverser
|
||||
{
|
||||
public:
|
||||
LIBRARY_TRAVERSER( std::vector<std::string> aSearchExtensions, wxString aInitialDir ) :
|
||||
m_searchExtensions( aSearchExtensions ), m_currentDir( aInitialDir )
|
||||
{
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnFile( const wxString& aFileName ) override
|
||||
{
|
||||
wxFileName file( aFileName );
|
||||
|
||||
for( const std::string& ext : m_searchExtensions )
|
||||
{
|
||||
if( file.GetExt().IsSameAs( ext, false ) )
|
||||
m_foundDirs.insert( { m_currentDir, 1 } );
|
||||
}
|
||||
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
virtual wxDirTraverseResult OnOpenError( const wxString& aOpenErrorName ) override
|
||||
{
|
||||
m_failedDirs.insert( { aOpenErrorName, 1 } );
|
||||
return wxDIR_IGNORE;
|
||||
}
|
||||
|
||||
bool HasDirectoryOpenFailures() { return m_failedDirs.size() > 0; }
|
||||
|
||||
virtual wxDirTraverseResult OnDir( const wxString& aDirName ) override
|
||||
{
|
||||
m_currentDir = aDirName;
|
||||
return wxDIR_CONTINUE;
|
||||
}
|
||||
|
||||
void GetPaths( wxArrayString& aPathArray )
|
||||
{
|
||||
for( std::pair<const wxString, int>& foundDirsPair : m_foundDirs )
|
||||
aPathArray.Add( foundDirsPair.first );
|
||||
}
|
||||
|
||||
void GetFailedPaths( wxArrayString& aPathArray )
|
||||
{
|
||||
for( std::pair<const wxString, int>& failedDirsPair : m_failedDirs )
|
||||
aPathArray.Add( failedDirsPair.first );
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_searchExtensions;
|
||||
wxString m_currentDir;
|
||||
std::unordered_map<wxString, int> m_foundDirs;
|
||||
std::unordered_map<wxString, int> m_failedDirs;
|
||||
};
|
||||
|
||||
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
/**
|
||||
* This class builds a wxGridTableBase by wrapping an #DESIGN_BLOCK_LIB_TABLE object.
|
||||
*/
|
||||
@@ -1065,7 +1142,7 @@ void PANEL_DESIGN_BLOCK_LIB_TABLE::populateEnvironReadOnlyTable()
|
||||
|
||||
//-----</event handlers>---------------------------------
|
||||
|
||||
|
||||
#endif
|
||||
size_t PANEL_DESIGN_BLOCK_LIB_TABLE::m_pageNdx = 0;
|
||||
|
||||
|
||||
@@ -1081,12 +1158,14 @@ void InvokeEditDesignBlockLibTable( KIWAY* aKiway, wxWindow *aParent )
|
||||
|
||||
if( aKiway->Prj().IsNullProject() )
|
||||
projectTable = nullptr;
|
||||
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
dlg.InstallPanel( new PANEL_DESIGN_BLOCK_LIB_TABLE( &dlg, &aKiway->Prj(), globalTable,
|
||||
globalTablePath,
|
||||
projectTable, projectTablePath,
|
||||
aKiway->Prj().GetProjectPath() ) );
|
||||
|
||||
#endif
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
return;
|
||||
|
||||
|
||||
@@ -699,7 +699,7 @@ void GRID_TRICKS::paste_clipboard()
|
||||
{
|
||||
wxLogNull doNotLog; // disable logging of failed clipboard actions
|
||||
|
||||
if( m_grid->IsEditable() && wxTheClipboard->Open() )
|
||||
if( m_grid->IsEditable() && ( wxTheClipboard->IsOpened() || wxTheClipboard->Open() ) )
|
||||
{
|
||||
if( wxTheClipboard->IsSupported( wxDF_TEXT )
|
||||
|| wxTheClipboard->IsSupported( wxDF_UNICODETEXT ) )
|
||||
|
||||
@@ -89,6 +89,8 @@ void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
|
||||
|
||||
bool showSettings = false;
|
||||
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
if( m_sel_row_count == 1 && tbl->At( m_sel_row_start )->SupportsSettingsDialog() )
|
||||
{
|
||||
showSettings = true;
|
||||
@@ -96,6 +98,7 @@ void LIB_TABLE_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
|
||||
wxString::Format( _( "Library settings for %s..." ),
|
||||
tbl->GetValue( m_sel_row_start, 2 ) ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
if( showActivate || showDeactivate || showSetVisible || showUnsetVisible || showSettings )
|
||||
menu.AppendSeparator();
|
||||
@@ -137,9 +140,12 @@ void LIB_TABLE_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
|
||||
}
|
||||
else if( menu_id == LIB_TABLE_GRID_TRICKS_LIBRARY_SETTINGS )
|
||||
{
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
LIB_TABLE_ROW* row = tbl->At( m_sel_row_start );
|
||||
row->Refresh();
|
||||
row->ShowSettingsDialog( m_grid->GetParent() );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
|
||||
#include <common.h>
|
||||
#include <list>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <paths.h>
|
||||
#include <pgm_base.h>
|
||||
#include <richio.h>
|
||||
#include <trace_helpers.h>
|
||||
#include <wildcards_and_files_ext.h>
|
||||
|
||||
@@ -47,7 +49,7 @@ LIBRARY_MANAGER::~LIBRARY_MANAGER() = default;
|
||||
void LIBRARY_MANAGER::loadTables( const wxString& aTablePath, LIBRARY_TABLE_SCOPE aScope )
|
||||
{
|
||||
auto getTarget =
|
||||
[&]() -> std::vector<std::unique_ptr<LIBRARY_TABLE>>&
|
||||
[&]() -> std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>&
|
||||
{
|
||||
switch( aScope )
|
||||
{
|
||||
@@ -55,14 +57,14 @@ void LIBRARY_MANAGER::loadTables( const wxString& aTablePath, LIBRARY_TABLE_SCOP
|
||||
return m_tables;
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::PROJECT:
|
||||
return m_project_tables;
|
||||
return m_projectTables;
|
||||
|
||||
default:
|
||||
wxCHECK_MSG( false, m_tables, "Invalid scope passed to loadTables" );
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
|
||||
std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>& aTarget = getTarget();
|
||||
|
||||
aTarget.clear();
|
||||
|
||||
@@ -73,13 +75,62 @@ void LIBRARY_MANAGER::loadTables( const wxString& aTablePath, LIBRARY_TABLE_SCOP
|
||||
wxFileName fn( aTablePath, name );
|
||||
|
||||
if( fn.IsFileReadable() )
|
||||
aTarget.emplace_back( std::make_unique<LIBRARY_TABLE>( fn, aScope ) );
|
||||
{
|
||||
auto table = std::make_unique<LIBRARY_TABLE>( fn, aScope );
|
||||
aTarget[table->Type()] = std::move( table );
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogTrace( traceLibraries, "No library table found at %s", fn.GetFullPath() );
|
||||
}
|
||||
}
|
||||
|
||||
for( const std::unique_ptr<LIBRARY_TABLE>& t : aTarget )
|
||||
t->LoadNestedTables();
|
||||
for( const std::unique_ptr<LIBRARY_TABLE>& t : aTarget | std::views::values )
|
||||
loadNestedTables( *t );
|
||||
}
|
||||
|
||||
|
||||
void LIBRARY_MANAGER::loadNestedTables( LIBRARY_TABLE& aRootTable )
|
||||
{
|
||||
std::unordered_set<wxString> seenTables;
|
||||
|
||||
std::function<void(LIBRARY_TABLE&)> processOneTable =
|
||||
[&]( LIBRARY_TABLE& aTable )
|
||||
{
|
||||
seenTables.insert( aTable.Path() );
|
||||
|
||||
for( LIBRARY_TABLE_ROW& row : aTable.Rows() )
|
||||
{
|
||||
if( row.Type() == wxT( "Table" ) )
|
||||
{
|
||||
wxFileName file( row.URI() );
|
||||
|
||||
// URI may be relative to parent
|
||||
file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
|
||||
|
||||
WX_FILENAME::ResolvePossibleSymlinks( file );
|
||||
wxString src = file.GetFullPath();
|
||||
|
||||
if( seenTables.contains( src ) )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "Library table %s has already been loaded!",
|
||||
src );
|
||||
row.SetOk( false );
|
||||
row.SetErrorDescription(
|
||||
_( "A reference to this library table already exists" ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
auto child = std::make_unique<LIBRARY_TABLE>( file, aRootTable.Scope() );
|
||||
|
||||
processOneTable( *child );
|
||||
|
||||
m_childTables.insert( { row.URI(), std::move( child ) } );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
processOneTable( aRootTable );
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +167,29 @@ std::optional<LIBRARY_MANAGER_ADAPTER*> LIBRARY_MANAGER::Adapter( LIBRARY_TABLE_
|
||||
}
|
||||
|
||||
|
||||
std::optional<LIBRARY_TABLE*> LIBRARY_MANAGER::Table( LIBRARY_TABLE_TYPE aType,
|
||||
LIBRARY_TABLE_SCOPE aScope ) const
|
||||
{
|
||||
switch( aScope )
|
||||
{
|
||||
case LIBRARY_TABLE_SCOPE::BOTH:
|
||||
case LIBRARY_TABLE_SCOPE::UNINITIALIZED:
|
||||
wxCHECK_MSG( false, std::nullopt, "Table() requires a single scope" );
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::GLOBAL:
|
||||
wxCHECK( m_tables.contains( aType ), std::nullopt );
|
||||
return m_tables.at( aType ).get();
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::PROJECT:
|
||||
// TODO: handle multiple projects
|
||||
wxCHECK( m_projectTables.contains( aType ), std::nullopt );
|
||||
return m_projectTables.at( aType ).get();
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
std::vector<const LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::Rows( LIBRARY_TABLE_TYPE aType,
|
||||
LIBRARY_TABLE_SCOPE aScope,
|
||||
bool aIncludeInvalid ) const
|
||||
@@ -123,7 +197,9 @@ std::vector<const LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::Rows( LIBRARY_TABLE_TYPE
|
||||
std::map<wxString, const LIBRARY_TABLE_ROW*> rows;
|
||||
std::vector<wxString> rowOrder;
|
||||
|
||||
std::list<std::ranges::ref_view<const std::vector<std::unique_ptr<LIBRARY_TABLE>>>> tables;
|
||||
std::list<std::ranges::ref_view<
|
||||
const std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>>
|
||||
>> tables;
|
||||
|
||||
switch( aScope )
|
||||
{
|
||||
@@ -132,11 +208,11 @@ std::vector<const LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::Rows( LIBRARY_TABLE_TYPE
|
||||
break;
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::PROJECT:
|
||||
tables = { std::views::all( m_project_tables ) };
|
||||
tables = { std::views::all( m_projectTables ) };
|
||||
break;
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::BOTH:
|
||||
tables = { std::views::all( m_tables ), std::views::all( m_project_tables ) };
|
||||
tables = { std::views::all( m_tables ), std::views::all( m_projectTables ) };
|
||||
break;
|
||||
|
||||
case LIBRARY_TABLE_SCOPE::UNINITIALIZED:
|
||||
@@ -157,8 +233,8 @@ std::vector<const LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::Rows( LIBRARY_TABLE_TYPE
|
||||
{
|
||||
if( row.Type() == "Table" )
|
||||
{
|
||||
wxCHECK2( aTable->Children().contains( row.Nickname() ), continue );
|
||||
processTable( aTable->Children().at( row.Nickname() ) );
|
||||
wxCHECK2( m_childTables.contains( row.URI() ), continue );
|
||||
processTable( m_childTables.at( row.URI() ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,8 +248,11 @@ std::vector<const LIBRARY_TABLE_ROW*> LIBRARY_MANAGER::Rows( LIBRARY_TABLE_TYPE
|
||||
}
|
||||
};
|
||||
|
||||
for( const std::unique_ptr<LIBRARY_TABLE>& table : std::views::join( tables ) )
|
||||
for( const std::unique_ptr<LIBRARY_TABLE>& table :
|
||||
std::views::join( tables ) | std::views::values )
|
||||
{
|
||||
processTable( table );
|
||||
}
|
||||
|
||||
std::vector<const LIBRARY_TABLE_ROW*> ret;
|
||||
|
||||
@@ -206,7 +285,7 @@ void LIBRARY_MANAGER::LoadProjectTables( const wxString& aProjectPath )
|
||||
}
|
||||
else
|
||||
{
|
||||
m_project_tables.clear();
|
||||
m_projectTables.clear();
|
||||
wxLogTrace( traceLibraries,
|
||||
"New project path %s is not readable, not loading project tables",
|
||||
aProjectPath );
|
||||
@@ -214,6 +293,41 @@ void LIBRARY_MANAGER::LoadProjectTables( const wxString& aProjectPath )
|
||||
}
|
||||
|
||||
|
||||
LIBRARY_RESULT<void> LIBRARY_MANAGER::Save( LIBRARY_TABLE* aTable ) const
|
||||
{
|
||||
wxCHECK( aTable, tl::unexpected( LIBRARY_ERROR( "Internal error" ) ) );
|
||||
|
||||
// TODO(JE) clean this up; shouldn't need to iterate
|
||||
for( const std::unique_ptr<LIBRARY_TABLE>& t : m_tables | std::views::values )
|
||||
{
|
||||
if( t.get() == aTable )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "Saving %s", aTable->Path() );
|
||||
wxFileName fn( aTable->Path() );
|
||||
// This should already be normalized, but just in case...
|
||||
fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS );
|
||||
|
||||
try
|
||||
{
|
||||
PRETTIFIED_FILE_OUTPUTFORMATTER formatter( fn.GetFullPath(), KICAD_FORMAT::FORMAT_MODE::LIBRARY_TABLE );
|
||||
aTable->Format( &formatter );
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "Exception while saving: %s", e.What() );
|
||||
return tl::unexpected( LIBRARY_ERROR( e.What() ) );
|
||||
}
|
||||
|
||||
return LIBRARY_RESULT<void>();
|
||||
}
|
||||
}
|
||||
|
||||
// Unmanaged table? TODO(JE) should this happen?
|
||||
wxLogTrace( traceLibraries, "Can't save %s; unmanaged library", aTable->Path() );
|
||||
return tl::unexpected( LIBRARY_ERROR( "Internal error" ) );
|
||||
}
|
||||
|
||||
|
||||
std::optional<wxString> LIBRARY_MANAGER::GetFullURI( LIBRARY_TABLE_TYPE aType,
|
||||
const wxString& aNickname,
|
||||
bool aSubstituted ) const
|
||||
@@ -232,6 +346,14 @@ std::optional<wxString> LIBRARY_MANAGER::GetFullURI( LIBRARY_TABLE_TYPE aType,
|
||||
}
|
||||
|
||||
|
||||
wxString LIBRARY_MANAGER::ExpandURI( const wxString& aShortURI, const PROJECT& aProject )
|
||||
{
|
||||
wxFileName path( ExpandEnvVarSubstitutions( aShortURI, &aProject ) );
|
||||
path.MakeAbsolute();
|
||||
return path.GetFullPath();
|
||||
}
|
||||
|
||||
|
||||
bool LIBRARY_MANAGER::UrisAreEquivalent( const wxString& aURI1, const wxString& aURI2 )
|
||||
{
|
||||
// Avoid comparing filenames as wxURIs
|
||||
|
||||
@@ -18,8 +18,6 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <lib_table_base.h>
|
||||
@@ -31,6 +29,19 @@
|
||||
#include <xnode.h>
|
||||
|
||||
|
||||
bool LIBRARY_TABLE_ROW::operator==( const LIBRARY_TABLE_ROW& aOther ) const
|
||||
{
|
||||
return m_scope == aOther.m_scope
|
||||
&& m_nickname == aOther.m_nickname
|
||||
&& m_uri == aOther.m_uri
|
||||
&& m_type == aOther.m_type
|
||||
&& m_options == aOther.m_options
|
||||
&& m_description == aOther.m_description
|
||||
&& m_disabled == aOther.m_disabled
|
||||
&& m_hidden == aOther.m_hidden;
|
||||
}
|
||||
|
||||
|
||||
std::map<std::string, UTF8> LIBRARY_TABLE_ROW::GetOptionsMap() const
|
||||
{
|
||||
return LIB_TABLE::ParseOptions( TO_UTF8( m_options ) );
|
||||
@@ -46,8 +57,7 @@ LIBRARY_TABLE::LIBRARY_TABLE( const wxFileName &aPath, LIBRARY_TABLE_SCOPE aScop
|
||||
WX_FILENAME::ResolvePossibleSymlinks( file );
|
||||
m_path = file.GetAbsolutePath();
|
||||
|
||||
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> ir =
|
||||
parser.Parse( m_path.ToStdString() );
|
||||
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> ir = parser.Parse( m_path.ToStdString() );
|
||||
|
||||
if( ir.has_value() )
|
||||
{
|
||||
@@ -62,10 +72,33 @@ LIBRARY_TABLE::LIBRARY_TABLE( const wxFileName &aPath, LIBRARY_TABLE_SCOPE aScop
|
||||
|
||||
|
||||
LIBRARY_TABLE::LIBRARY_TABLE( const wxString &aBuffer, LIBRARY_TABLE_SCOPE aScope ) :
|
||||
m_path( wxEmptyString ),
|
||||
m_scope( aScope )
|
||||
{
|
||||
m_ok = false;
|
||||
// TODO
|
||||
LIBRARY_TABLE_PARSER parser;
|
||||
|
||||
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> ir =
|
||||
parser.ParseBuffer( aBuffer.ToStdString() );
|
||||
|
||||
if( ir.has_value() )
|
||||
{
|
||||
m_ok = initFromIR( *ir );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ok = false;
|
||||
m_errorDescription = ir.error().description;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LIBRARY_TABLE::operator==( const LIBRARY_TABLE& aOther ) const
|
||||
{
|
||||
return m_path == aOther.m_path
|
||||
&& m_scope == aOther.m_scope
|
||||
&& m_type == aOther.m_type
|
||||
&& m_version == aOther.m_version
|
||||
&& m_rows == aOther.m_rows;
|
||||
}
|
||||
|
||||
|
||||
@@ -108,56 +141,9 @@ bool LIBRARY_TABLE::addRowFromIR( const LIBRARY_TABLE_ROW_IR& aIR )
|
||||
}
|
||||
|
||||
|
||||
// TODO(JE) this shouldn't be called from ctor and probably shouldn't be in LIBRARY_TABLE at all,
|
||||
// but instead in LIBRARY_MANAGER - just opening one LIBRARY_TABLE shouldn't necessarily attempt a
|
||||
// load on all the child tables
|
||||
void LIBRARY_TABLE::LoadNestedTables()
|
||||
{
|
||||
std::unordered_set<wxString> seenTables;
|
||||
|
||||
std::function<void(LIBRARY_TABLE&)> processOneTable =
|
||||
[&]( LIBRARY_TABLE& aTable )
|
||||
{
|
||||
seenTables.insert( aTable.Path() );
|
||||
|
||||
for( LIBRARY_TABLE_ROW& row : aTable.m_rows )
|
||||
{
|
||||
if( row.m_type == wxT( "Table" ) )
|
||||
{
|
||||
wxFileName file( row.m_uri );
|
||||
|
||||
// URI may be relative to parent
|
||||
file.MakeAbsolute( wxFileName( aTable.Path() ).GetPath() );
|
||||
|
||||
WX_FILENAME::ResolvePossibleSymlinks( file );
|
||||
wxString src = file.GetFullPath();
|
||||
|
||||
if( seenTables.contains( src ) )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "Library table %s has already been loaded!",
|
||||
src );
|
||||
row.m_ok = false;
|
||||
row.m_errorDescription = _( "A reference to this library table already exists" );
|
||||
continue;
|
||||
}
|
||||
|
||||
auto child = std::make_unique<LIBRARY_TABLE>( file, m_scope );
|
||||
|
||||
processOneTable( *child );
|
||||
|
||||
aTable.m_children.insert( { row.m_nickname, std::move( child ) } );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
processOneTable( *this );
|
||||
}
|
||||
|
||||
|
||||
void LIBRARY_TABLE::Format( OUTPUTFORMATTER* aOutput ) const
|
||||
{
|
||||
if( !IsOk() )
|
||||
return;
|
||||
wxCHECK_MSG( IsOk(), /* void */, "Don't attempt to format a table that isn't OK!" );
|
||||
|
||||
static const std::map<LIBRARY_TABLE_TYPE, wxString> types = {
|
||||
{ LIBRARY_TABLE_TYPE::SYMBOL, "sym_lib_table" },
|
||||
|
||||
@@ -192,3 +192,43 @@ tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> LIBRARY_TABLE_PARSER::Parse(
|
||||
|
||||
return state.model;
|
||||
}
|
||||
|
||||
|
||||
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> LIBRARY_TABLE_PARSER::ParseBuffer(
|
||||
const std::string& aBuffer )
|
||||
{
|
||||
memory_input in( aBuffer, "" );
|
||||
LIBRARY_TABLE_PARSER_STATE state;
|
||||
wxLogTrace( traceLibraries, "LIBRARY_TABLE_PARSER::Parse from string buffer" );
|
||||
|
||||
try
|
||||
{
|
||||
if( !parse<LIB_TABLE_FILE, LIBRARY_TABLE_PARSER_ACTION>( in, state ) )
|
||||
{
|
||||
wxLogTrace( traceLibraries, "Parsing failed without throwing" );
|
||||
wxString msg =
|
||||
wxString::Format( _( "An unexpected error occurred while reading library table") );
|
||||
return tl::unexpected( LIBRARY_PARSE_ERROR( { .description = msg } ) );
|
||||
}
|
||||
}
|
||||
catch( const parse_error& e )
|
||||
{
|
||||
const auto& p = e.positions().front();
|
||||
std::string msg = fmt::format( "Error at line {}, column {}:\n{}\n{:>{}}\n{}",
|
||||
p.line, p.column, in.line_at( p ), "^", p.column,
|
||||
e.message() );
|
||||
|
||||
wxLogTrace( traceLibraries, "%s", msg.c_str() );
|
||||
|
||||
wxString description = wxString::Format( _( "Syntax error at line %zu, column %zu" ),
|
||||
p.line, p.column );
|
||||
|
||||
return tl::unexpected( LIBRARY_PARSE_ERROR( {
|
||||
.description = description,
|
||||
.line = p.line,
|
||||
.column = p.column
|
||||
} ) );
|
||||
}
|
||||
|
||||
return state.model;
|
||||
}
|
||||
|
||||
+7
-4
@@ -609,10 +609,15 @@ void FILE_OUTPUTFORMATTER::write( const char* aOutBuf, int aCount )
|
||||
|
||||
|
||||
PRETTIFIED_FILE_OUTPUTFORMATTER::PRETTIFIED_FILE_OUTPUTFORMATTER( const wxString& aFileName,
|
||||
KICAD_FORMAT::FORMAT_MODE aFormatMode,
|
||||
const wxChar* aMode,
|
||||
char aQuoteChar ) :
|
||||
OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar )
|
||||
OUTPUTFORMATTER( OUTPUTFMTBUFZ, aQuoteChar ),
|
||||
m_mode( aFormatMode )
|
||||
{
|
||||
if( ADVANCED_CFG::GetCfg().m_CompactSave && m_mode == KICAD_FORMAT::FORMAT_MODE::NORMAL )
|
||||
m_mode = KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES;
|
||||
|
||||
m_fp = wxFopen( aFileName, aMode );
|
||||
|
||||
if( !m_fp )
|
||||
@@ -636,9 +641,7 @@ bool PRETTIFIED_FILE_OUTPUTFORMATTER::Finish()
|
||||
if( !m_fp )
|
||||
return false;
|
||||
|
||||
KICAD_FORMAT::Prettify( m_buf, ADVANCED_CFG::GetCfg().m_CompactSave
|
||||
? KICAD_FORMAT::FORMAT_MODE::COMPACT_TEXT_PROPERTIES
|
||||
: KICAD_FORMAT::FORMAT_MODE::NORMAL );
|
||||
KICAD_FORMAT::Prettify( m_buf, m_mode );
|
||||
|
||||
if( fwrite( m_buf.c_str(), m_buf.length(), 1, m_fp ) != 1 )
|
||||
THROW_IO_ERROR( strerror( errno ) );
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
#include <project.h>
|
||||
#include <panel_sym_lib_table.h>
|
||||
#include <lib_id.h>
|
||||
#include <symbol_lib_table.h>
|
||||
#include <lib_table_lexer.h>
|
||||
#include <libraries/library_table.h>
|
||||
#include <libraries/library_manager.h>
|
||||
#include <lib_table_grid_tricks.h>
|
||||
#include <widgets/wx_grid.h>
|
||||
#include <confirm.h>
|
||||
@@ -40,10 +40,13 @@
|
||||
#include <env_paths.h>
|
||||
#include <functional>
|
||||
#include <eeschema_id.h>
|
||||
#include <env_vars.h>
|
||||
#include <sch_io/sch_io.h>
|
||||
#include <symbol_edit_frame.h>
|
||||
#include <symbol_viewer_frame.h>
|
||||
#include <sch_edit_frame.h>
|
||||
#include <kiway.h>
|
||||
#include <lib_table_base.h>
|
||||
#include <paths.h>
|
||||
#include <pgm_base.h>
|
||||
#include <settings/settings_manager.h>
|
||||
@@ -56,7 +59,6 @@
|
||||
#include <project_sch.h>
|
||||
|
||||
|
||||
|
||||
// clang-format off
|
||||
|
||||
/**
|
||||
@@ -84,38 +86,39 @@ enum {
|
||||
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Build a wxGridTableBase by wrapping an #SYMBOL_LIB_TABLE object.
|
||||
*/
|
||||
class SYMBOL_LIB_TABLE_GRID : public LIB_TABLE_GRID, public SYMBOL_LIB_TABLE
|
||||
class SYMBOL_LIB_TABLE_GRID : public LIB_TABLE_GRID
|
||||
{
|
||||
friend class PANEL_SYM_LIB_TABLE;
|
||||
friend class SYMBOL_GRID_TRICKS;
|
||||
|
||||
protected:
|
||||
LIB_TABLE_ROW* at( size_t aIndex ) override { return &m_rows.at( aIndex ); }
|
||||
LIBRARY_TABLE_ROW& at( size_t aIndex ) override { return m_table.Rows().at( aIndex ); }
|
||||
|
||||
size_t size() const override { return m_rows.size(); }
|
||||
size_t size() const override { return m_table.Rows().size(); }
|
||||
|
||||
LIB_TABLE_ROW* makeNewRow() override
|
||||
LIBRARY_TABLE_ROW makeNewRow() override
|
||||
{
|
||||
return dynamic_cast< LIB_TABLE_ROW* >( new SYMBOL_LIB_TABLE_ROW );
|
||||
return LIBRARY_TABLE_ROW();
|
||||
}
|
||||
|
||||
LIB_TABLE_ROWS_ITER begin() override { return m_rows.begin(); }
|
||||
LIBRARY_TABLE_ROWS_ITER begin() override { return m_table.Rows().begin(); }
|
||||
|
||||
LIB_TABLE_ROWS_ITER insert( LIB_TABLE_ROWS_ITER aIterator, LIB_TABLE_ROW* aRow ) override
|
||||
LIBRARY_TABLE_ROWS_ITER insert( LIBRARY_TABLE_ROWS_ITER aIterator,
|
||||
const LIBRARY_TABLE_ROW& aRow ) override
|
||||
{
|
||||
return m_rows.insert( aIterator, aRow );
|
||||
return m_table.Rows().insert( aIterator, aRow );
|
||||
}
|
||||
|
||||
void push_back( LIB_TABLE_ROW* aRow ) override { m_rows.push_back( aRow ); }
|
||||
void push_back( const LIBRARY_TABLE_ROW& aRow ) override { m_table.Rows().push_back( aRow ); }
|
||||
|
||||
LIB_TABLE_ROWS_ITER erase( LIB_TABLE_ROWS_ITER aFirst, LIB_TABLE_ROWS_ITER aLast ) override
|
||||
LIBRARY_TABLE_ROWS_ITER erase( LIBRARY_TABLE_ROWS_ITER aFirst,
|
||||
LIBRARY_TABLE_ROWS_ITER aLast ) override
|
||||
{
|
||||
return m_rows.erase( aFirst, aLast );
|
||||
return m_table.Rows().erase( aFirst, aLast );
|
||||
}
|
||||
|
||||
LIBRARY_TABLE& Table() { return m_table; }
|
||||
|
||||
public:
|
||||
void SetValue( int aRow, int aCol, const wxString &aValue ) override
|
||||
{
|
||||
@@ -126,10 +129,9 @@ public:
|
||||
// If setting a filepath, attempt to auto-detect the format
|
||||
if( aCol == COL_URI )
|
||||
{
|
||||
LIB_TABLE_ROW* row = at( (size_t) aRow );
|
||||
wxString fullURI = row->GetFullURI( true );
|
||||
|
||||
SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( fullURI );
|
||||
LIBRARY_TABLE_ROW& row = at( static_cast<size_t>(aRow) );
|
||||
wxString uri = LIBRARY_MANAGER::ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() );
|
||||
SCH_IO_MGR::SCH_FILE_T pluginType = SCH_IO_MGR::GuessPluginTypeFromLibPath( uri );
|
||||
|
||||
if( pluginType == SCH_IO_MGR::SCH_FILE_UNKNOWN )
|
||||
pluginType = SCH_IO_MGR::SCH_KICAD;
|
||||
@@ -139,12 +141,17 @@ public:
|
||||
}
|
||||
|
||||
|
||||
SYMBOL_LIB_TABLE_GRID( const SYMBOL_LIB_TABLE& aTableToEdit )
|
||||
SYMBOL_LIB_TABLE_GRID( const LIBRARY_TABLE& aTableToEdit ) :
|
||||
m_table( aTableToEdit )
|
||||
{
|
||||
m_rows = aTableToEdit.m_rows;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Working copy of a table
|
||||
LIBRARY_TABLE m_table;
|
||||
};
|
||||
|
||||
|
||||
class SYMBOL_GRID_TRICKS : public LIB_TABLE_GRID_TRICKS
|
||||
{
|
||||
public:
|
||||
@@ -164,27 +171,27 @@ public:
|
||||
protected:
|
||||
DIALOG_EDIT_LIBRARY_TABLES* m_dialog;
|
||||
|
||||
virtual void optionsEditor( int aRow ) override
|
||||
void optionsEditor( int aRow ) override
|
||||
{
|
||||
SYMBOL_LIB_TABLE_GRID* tbl = (SYMBOL_LIB_TABLE_GRID*) m_grid->GetTable();
|
||||
|
||||
if( tbl->GetNumberRows() > aRow )
|
||||
{
|
||||
LIB_TABLE_ROW* row = tbl->at( (size_t) aRow );
|
||||
const wxString& options = row->GetOptions();
|
||||
wxString result = options;
|
||||
LIBRARY_TABLE_ROW& row = tbl->at( static_cast<size_t>( aRow ) );
|
||||
const wxString& options = row.Options();
|
||||
wxString result = options;
|
||||
std::map<std::string, UTF8> choices;
|
||||
|
||||
SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( row->GetType() );
|
||||
SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( row.Type() );
|
||||
IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
|
||||
pi->GetLibraryOptions( &choices );
|
||||
|
||||
DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row->GetNickName(), choices, options, &result );
|
||||
DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row.Nickname(), choices, options, &result );
|
||||
dlg.ShowModal();
|
||||
|
||||
if( options != result )
|
||||
{
|
||||
row->SetOptions( result );
|
||||
row.SetOptions( result );
|
||||
m_grid->Refresh();
|
||||
}
|
||||
}
|
||||
@@ -193,42 +200,30 @@ protected:
|
||||
|
||||
/// handle specialized clipboard text, with leading "(sym_lib_table" or
|
||||
/// spreadsheet formatted text.
|
||||
virtual void paste_text( const wxString& cb_text ) override
|
||||
void paste_text( const wxString& cb_text ) override
|
||||
{
|
||||
SYMBOL_LIB_TABLE_GRID* tbl = (SYMBOL_LIB_TABLE_GRID*) m_grid->GetTable();
|
||||
size_t ndx = cb_text.find( "(sym_lib_table" );
|
||||
SYMBOL_LIB_TABLE_GRID* tbl = static_cast<SYMBOL_LIB_TABLE_GRID*>( m_grid->GetTable() );
|
||||
|
||||
if( ndx != std::string::npos )
|
||||
if( size_t ndx = cb_text.find( "(sym_lib_table" ); ndx != std::string::npos )
|
||||
{
|
||||
// paste the SYMBOL_LIB_TABLE_ROWs of s-expression (sym_lib_table), starting
|
||||
// at column 0 regardless of current cursor column.
|
||||
|
||||
STRING_LINE_READER slr( TO_UTF8( cb_text ), wxS( "Clipboard" ) );
|
||||
LIB_TABLE_LEXER lexer( &slr );
|
||||
SYMBOL_LIB_TABLE tmp_tbl;
|
||||
bool parsed = true;
|
||||
|
||||
try
|
||||
if( LIBRARY_TABLE tempTable( cb_text, tbl->Table().Scope() ); tempTable.IsOk() )
|
||||
{
|
||||
tmp_tbl.Parse( &lexer );
|
||||
std::ranges::copy( tempTable.Rows(),
|
||||
std::inserter( tbl->Table().Rows(), tbl->Table().Rows().begin() ) );
|
||||
|
||||
if( tbl->GetView() )
|
||||
{
|
||||
wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, 0, 0 );
|
||||
tbl->GetView()->ProcessTableMessage( msg );
|
||||
}
|
||||
}
|
||||
catch( PARSE_ERROR& pe )
|
||||
else
|
||||
{
|
||||
DisplayError( m_dialog, pe.What() );
|
||||
parsed = false;
|
||||
DisplayError( m_dialog, tempTable.ErrorDescription() );
|
||||
}
|
||||
|
||||
if( parsed )
|
||||
{
|
||||
// make sure the table is big enough...
|
||||
if( tmp_tbl.GetCount() > (unsigned) tbl->GetNumberRows() )
|
||||
tbl->AppendRows( tmp_tbl.GetCount() - tbl->GetNumberRows() );
|
||||
|
||||
for( unsigned i = 0; i < tmp_tbl.GetCount(); ++i )
|
||||
tbl->ReplaceRow( i, tmp_tbl.At( i ).clone() );
|
||||
}
|
||||
|
||||
m_grid->AutoSizeColumns( false );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -250,6 +245,8 @@ protected:
|
||||
|
||||
m_grid->AutoSizeColumns( false );
|
||||
}
|
||||
|
||||
m_grid->AutoSizeColumns( false );
|
||||
}
|
||||
|
||||
bool supportsVisibilityColumn() override
|
||||
@@ -288,10 +285,11 @@ void PANEL_SYM_LIB_TABLE::setupGrid( WX_GRID* aGrid )
|
||||
m_parent, aGrid, &cfg->m_lastSymbolLibDir, true, m_project->GetProjectPath(),
|
||||
[]( WX_GRID* grid, int row ) -> wxString
|
||||
{
|
||||
auto* libTable = static_cast<SYMBOL_LIB_TABLE_GRID*>( grid->GetTable() );
|
||||
auto* tableRow = static_cast<SYMBOL_LIB_TABLE_ROW*>( libTable->at( row ) );
|
||||
auto libTable = static_cast<SYMBOL_LIB_TABLE_GRID*>( grid->GetTable() );
|
||||
LIBRARY_TABLE_ROW& tableRow = libTable->at( row );
|
||||
SCH_IO_MGR::SCH_FILE_T pi_type = SCH_IO_MGR::EnumFromStr( tableRow.Type() );
|
||||
|
||||
IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( tableRow->GetFileType() ) );
|
||||
IO_RELEASER<SCH_IO> pi( SCH_IO_MGR::FindPlugin( pi_type ) );
|
||||
|
||||
if( pi )
|
||||
{
|
||||
@@ -335,20 +333,17 @@ void PANEL_SYM_LIB_TABLE::setupGrid( WX_GRID* aGrid )
|
||||
};
|
||||
|
||||
|
||||
PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PROJECT* aProject,
|
||||
SYMBOL_LIB_TABLE* aGlobalTable,
|
||||
const wxString& aGlobalTablePath,
|
||||
SYMBOL_LIB_TABLE* aProjectTable,
|
||||
const wxString& aProjectTablePath ) :
|
||||
PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PROJECT* aProject ) :
|
||||
PANEL_SYM_LIB_TABLE_BASE( aParent ),
|
||||
m_globalTable( aGlobalTable ),
|
||||
m_projectTable( aProjectTable ),
|
||||
m_project( aProject ),
|
||||
m_parent( aParent )
|
||||
{
|
||||
std::optional<LIBRARY_TABLE*> table =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL, LIBRARY_TABLE_SCOPE::GLOBAL );
|
||||
wxASSERT( table );
|
||||
// wxGrid only supports user owned tables if they exist past end of ~wxGrid(),
|
||||
// so make it a grid owned table.
|
||||
m_global_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *m_globalTable ), true );
|
||||
m_global_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *table.value() ) );
|
||||
|
||||
for( const SCH_IO_MGR::SCH_FILE_T& type : SCH_IO_MGR::SCH_FILE_T_vector )
|
||||
{
|
||||
@@ -371,9 +366,12 @@ PANEL_SYM_LIB_TABLE::PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, P
|
||||
|
||||
setupGrid( m_global_grid );
|
||||
|
||||
if( m_projectTable )
|
||||
std::optional<LIBRARY_TABLE*> projectTable =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL, LIBRARY_TABLE_SCOPE::PROJECT );
|
||||
|
||||
if( projectTable )
|
||||
{
|
||||
m_project_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *m_projectTable ), true );
|
||||
m_project_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *projectTable.value() ), true );
|
||||
setupGrid( m_project_grid );
|
||||
}
|
||||
else
|
||||
@@ -567,45 +565,6 @@ bool PANEL_SYM_LIB_TABLE::verifyTables()
|
||||
}
|
||||
}
|
||||
|
||||
for( SYMBOL_LIB_TABLE* table : { global_model(), project_model() } )
|
||||
{
|
||||
if( !table )
|
||||
continue;
|
||||
|
||||
for( unsigned int r = 0; r < table->GetCount(); ++r )
|
||||
{
|
||||
SYMBOL_LIB_TABLE_ROW& row = dynamic_cast<SYMBOL_LIB_TABLE_ROW&>( table->At( r ) );
|
||||
|
||||
// Newly-added rows won't have set this yet
|
||||
row.SetParent( table );
|
||||
|
||||
if( !row.GetIsEnabled() )
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
if( row.Refresh() )
|
||||
{
|
||||
if( table == global_model() )
|
||||
m_parent->m_GlobalTableChanged = true;
|
||||
else
|
||||
m_parent->m_ProjectTableChanged = true;
|
||||
}
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Symbol library '%s' failed to load." ), row.GetNickName() );
|
||||
|
||||
wxWindow* topLevelParent = wxGetTopLevelParent( this );
|
||||
wait.reset();
|
||||
wxMessageDialog errdlg( topLevelParent, msg + wxS( "\n" ) + ioe.What(), _( "Error Loading Library" ) );
|
||||
errdlg.ShowModal();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -809,7 +768,15 @@ void PANEL_SYM_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
|
||||
m_cur_grid->OnMoveRowUp(
|
||||
[&]( int row )
|
||||
{
|
||||
cur_model()->ChangeRowOrder( row, -1 );
|
||||
SYMBOL_LIB_TABLE_GRID* tbl = cur_model();
|
||||
int curRow = m_cur_grid->GetGridCursorRow();
|
||||
|
||||
std::vector<LIBRARY_TABLE_ROW>& rows = tbl->Table().Rows();
|
||||
|
||||
auto current = rows.begin() + curRow;
|
||||
auto prev = rows.begin() + curRow - 1;
|
||||
|
||||
std::iter_swap( current, prev );
|
||||
|
||||
// Update the wxGrid
|
||||
wxGridTableMessage msg( cur_model(), wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row - 1, 0 );
|
||||
@@ -823,7 +790,14 @@ void PANEL_SYM_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
|
||||
m_cur_grid->OnMoveRowDown(
|
||||
[&]( int row )
|
||||
{
|
||||
cur_model()->ChangeRowOrder( row, 1 );
|
||||
SYMBOL_LIB_TABLE_GRID* tbl = cur_model();
|
||||
int curRow = m_cur_grid->GetGridCursorRow();
|
||||
std::vector<LIBRARY_TABLE_ROW>& rows = tbl->Table().Rows();
|
||||
|
||||
auto current = rows.begin() + curRow;
|
||||
auto next = rows.begin() + curRow + 1;
|
||||
|
||||
std::iter_swap( current, next );
|
||||
|
||||
// Update the wxGrid
|
||||
wxGridTableMessage msg( cur_model(), wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row, 0 );
|
||||
@@ -845,7 +819,6 @@ void PANEL_SYM_LIB_TABLE::onReset( wxCommandEvent& event )
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
DIALOG_GLOBAL_SYM_LIB_TABLE_CONFIG dlg( m_parent );
|
||||
|
||||
if( dlg.ShowModal() == wxID_OK )
|
||||
@@ -855,7 +828,12 @@ void PANEL_SYM_LIB_TABLE::onReset( wxCommandEvent& event )
|
||||
wxGridTableBase* table = m_global_grid->GetTable();
|
||||
m_global_grid->DestroyTable( table );
|
||||
|
||||
m_global_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *m_globalTable ), true );
|
||||
std::optional<LIBRARY_TABLE*> newTable =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
|
||||
LIBRARY_TABLE_SCOPE::GLOBAL );
|
||||
wxASSERT( newTable );
|
||||
|
||||
m_global_grid->SetTable( new SYMBOL_LIB_TABLE_GRID( *newTable.value() ) );
|
||||
m_global_grid->PopEventHandler( true );
|
||||
setupGrid( m_global_grid );
|
||||
m_parent->m_GlobalTableChanged = true;
|
||||
@@ -1001,16 +979,29 @@ bool PANEL_SYM_LIB_TABLE::TransferDataFromWindow()
|
||||
if( !verifyTables() )
|
||||
return false;
|
||||
|
||||
if( *global_model() != *m_globalTable )
|
||||
std::optional<LIBRARY_TABLE*> optTable =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL, LIBRARY_TABLE_SCOPE::GLOBAL );
|
||||
wxCHECK( optTable, false );
|
||||
LIBRARY_TABLE* globalTable = *optTable;
|
||||
|
||||
if( global_model()->Table() != *globalTable )
|
||||
{
|
||||
m_parent->m_GlobalTableChanged = true;
|
||||
m_globalTable->TransferRows( global_model()->m_rows );
|
||||
*globalTable = global_model()->Table();
|
||||
}
|
||||
|
||||
if( project_model() && *project_model() != *m_projectTable )
|
||||
optTable = Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL,
|
||||
LIBRARY_TABLE_SCOPE::PROJECT );
|
||||
|
||||
if( optTable && project_model() )
|
||||
{
|
||||
m_parent->m_ProjectTableChanged = true;
|
||||
m_projectTable->TransferRows( project_model()->m_rows );
|
||||
LIBRARY_TABLE* projectTable = *optTable;
|
||||
|
||||
if( project_model()->Table() != *projectTable )
|
||||
{
|
||||
m_parent->m_ProjectTableChanged = true;
|
||||
*projectTable = project_model()->Table();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1057,7 +1048,7 @@ void PANEL_SYM_LIB_TABLE::populateEnvironReadOnlyTable()
|
||||
// not used yet. It is automatically set by KiCad to the directory holding
|
||||
// the current project.
|
||||
unique.insert( PROJECT_VAR_NAME );
|
||||
unique.insert( SYMBOL_LIB_TABLE::GlobalPathEnvVariableName() );
|
||||
unique.insert( ENV_VAR::GetVersionedEnvVarName( wxS( "SYMBOL_DIR" ) ) );
|
||||
|
||||
for( const wxString& evName : unique )
|
||||
{
|
||||
@@ -1098,19 +1089,19 @@ void PANEL_SYM_LIB_TABLE::onSizeGrid( wxSizeEvent& event )
|
||||
|
||||
SYMBOL_LIB_TABLE_GRID* PANEL_SYM_LIB_TABLE::global_model() const
|
||||
{
|
||||
return (SYMBOL_LIB_TABLE_GRID*) m_global_grid->GetTable();
|
||||
return static_cast<SYMBOL_LIB_TABLE_GRID*>( m_global_grid->GetTable() );
|
||||
}
|
||||
|
||||
|
||||
SYMBOL_LIB_TABLE_GRID* PANEL_SYM_LIB_TABLE::project_model() const
|
||||
{
|
||||
return m_project_grid ? (SYMBOL_LIB_TABLE_GRID*) m_project_grid->GetTable() : nullptr;
|
||||
return m_project_grid ? static_cast<SYMBOL_LIB_TABLE_GRID*>( m_project_grid->GetTable() ) : nullptr;
|
||||
}
|
||||
|
||||
|
||||
SYMBOL_LIB_TABLE_GRID* PANEL_SYM_LIB_TABLE::cur_model() const
|
||||
{
|
||||
return (SYMBOL_LIB_TABLE_GRID*) m_cur_grid->GetTable();
|
||||
return static_cast<SYMBOL_LIB_TABLE_GRID*>( m_cur_grid->GetTable() );
|
||||
}
|
||||
|
||||
|
||||
@@ -1119,25 +1110,12 @@ size_t PANEL_SYM_LIB_TABLE::m_pageNdx = 0;
|
||||
|
||||
void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
|
||||
{
|
||||
auto* symbolEditor = (SYMBOL_EDIT_FRAME*) aKiway->Player( FRAME_SCH_SYMBOL_EDITOR, false );
|
||||
|
||||
SYMBOL_LIB_TABLE* globalTable = &SYMBOL_LIB_TABLE::GetGlobalLibTable();
|
||||
wxString globalTablePath = SYMBOL_LIB_TABLE::GetGlobalTableFileName();
|
||||
SYMBOL_LIB_TABLE* projectTable = nullptr;
|
||||
wxString projectPath = aKiway->Prj().GetProjectPath();
|
||||
wxFileName projectTableFn( projectPath, SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
||||
wxString msg;
|
||||
wxString currentLib;
|
||||
|
||||
// TODO(JE)
|
||||
// Don't allow editing project tables if no project is open
|
||||
// if( !aKiway->Prj().IsNullProject() )
|
||||
// projectTable = PROJECT_SCH::SchSymbolLibTable( &aKiway->Prj() );
|
||||
auto symbolEditor = static_cast<SYMBOL_EDIT_FRAME*>( aKiway->Player( FRAME_SCH_SYMBOL_EDITOR,
|
||||
false ) );
|
||||
wxString msg;
|
||||
|
||||
if( symbolEditor )
|
||||
{
|
||||
currentLib = symbolEditor->GetCurLib();
|
||||
|
||||
// This prevents an ugly crash on OSX (https://bugs.launchpad.net/kicad/+bug/1765286)
|
||||
symbolEditor->FreezeLibraryTree();
|
||||
|
||||
@@ -1159,8 +1137,7 @@ void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
|
||||
DIALOG_EDIT_LIBRARY_TABLES dlg( aParent, _( "Symbol Libraries" ) );
|
||||
dlg.SetKiway( &dlg, aKiway );
|
||||
|
||||
dlg.InstallPanel( new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj(), globalTable, globalTablePath,
|
||||
projectTable, projectTableFn.GetFullPath() ) );
|
||||
dlg.InstallPanel( new PANEL_SYM_LIB_TABLE( &dlg, &aKiway->Prj() ) );
|
||||
|
||||
if( dlg.ShowModal() == wxID_CANCEL )
|
||||
{
|
||||
@@ -1172,28 +1149,31 @@ void InvokeSchEditSymbolLibTable( KIWAY* aKiway, wxWindow *aParent )
|
||||
|
||||
if( dlg.m_GlobalTableChanged )
|
||||
{
|
||||
try
|
||||
{
|
||||
globalTable->Save( globalTablePath );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Error saving global library table:\n\n%s" ), ioe.What() );
|
||||
wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
|
||||
}
|
||||
std::optional<LIBRARY_TABLE*> optTable =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL, LIBRARY_TABLE_SCOPE::GLOBAL );
|
||||
wxCHECK( optTable, /* void */ );
|
||||
LIBRARY_TABLE* globalTable = *optTable;
|
||||
|
||||
Pgm().GetLibraryManager().Save( globalTable ).map_error(
|
||||
[]( const LIBRARY_ERROR& aError )
|
||||
{
|
||||
wxMessageBox( wxString::Format( _( "Error saving global library table:\n\n%s" ), aError.message ),
|
||||
_( "File Save Error" ), wxOK | wxICON_ERROR );
|
||||
} );
|
||||
}
|
||||
|
||||
std::optional<LIBRARY_TABLE*> projectTable =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::SYMBOL, LIBRARY_TABLE_SCOPE::PROJECT );
|
||||
|
||||
if( projectTable && dlg.m_ProjectTableChanged )
|
||||
{
|
||||
try
|
||||
{
|
||||
projectTable->Save( projectTableFn.GetFullPath() );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
msg.Printf( _( "Error saving project-specific library table:\n\n%s" ), ioe.What() );
|
||||
wxMessageBox( msg, _( "File Save Error" ), wxOK | wxICON_ERROR );
|
||||
}
|
||||
Pgm().GetLibraryManager().Save( *projectTable ).map_error(
|
||||
[]( const LIBRARY_ERROR& aError )
|
||||
{
|
||||
wxMessageBox( wxString::Format( _( "Error saving project-specific library table:\n\n%s" ),
|
||||
aError.message ),
|
||||
_( "File Save Error" ), wxOK | wxICON_ERROR );
|
||||
} );
|
||||
}
|
||||
|
||||
if( symbolEditor )
|
||||
|
||||
@@ -36,9 +36,7 @@ class PANEL_SYM_LIB_TABLE : public PANEL_SYM_LIB_TABLE_BASE
|
||||
{
|
||||
|
||||
public:
|
||||
PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PROJECT* m_project,
|
||||
SYMBOL_LIB_TABLE* aGlobal, const wxString& aGlobalTablePath,
|
||||
SYMBOL_LIB_TABLE* aProject, const wxString& aProjectTablePath );
|
||||
PANEL_SYM_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PROJECT* m_project );
|
||||
virtual ~PANEL_SYM_LIB_TABLE();
|
||||
|
||||
private:
|
||||
@@ -84,10 +82,6 @@ private:
|
||||
*/
|
||||
bool allowAutomaticPluginTypeSelection( wxString& aLibraryPath );
|
||||
|
||||
private:
|
||||
// Caller's tables are modified only on OK button and successful verification.
|
||||
SYMBOL_LIB_TABLE* m_globalTable;
|
||||
SYMBOL_LIB_TABLE* m_projectTable;
|
||||
PROJECT* m_project;
|
||||
|
||||
DIALOG_EDIT_LIBRARY_TABLES* m_parent;
|
||||
|
||||
@@ -165,9 +165,7 @@ std::optional<LIB_DATA*> SYMBOL_LIBRARY_MANAGER_ADAPTER::fetchIfLoaded(
|
||||
|
||||
wxString SYMBOL_LIBRARY_MANAGER_ADAPTER::getUri( const LIBRARY_TABLE_ROW* aRow )
|
||||
{
|
||||
wxFileName path( ExpandEnvVarSubstitutions( aRow->URI(), &Pgm().GetSettingsManager().Prj() ) );
|
||||
path.MakeAbsolute();
|
||||
return path.GetFullPath();
|
||||
return LIBRARY_MANAGER::ExpandURI( aRow->URI(), Pgm().GetSettingsManager().Prj() );
|
||||
}
|
||||
|
||||
|
||||
@@ -367,7 +365,7 @@ void SYMBOL_LIBRARY_MANAGER_ADAPTER::AsyncLoad()
|
||||
{
|
||||
lib->plugin->EnumerateSymbolLib( dummyList, getUri( lib->row ), &options );
|
||||
// TODO(JE) remove testing delay
|
||||
std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
|
||||
//std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
|
||||
lib->status.load_status = LOAD_STATUS::LOADED;
|
||||
}
|
||||
catch( IO_ERROR& e )
|
||||
@@ -504,8 +502,8 @@ std::optional<wxString> SYMBOL_LIBRARY_MANAGER_ADAPTER::GetLibraryDescription( c
|
||||
bool SYMBOL_LIBRARY_MANAGER_ADAPTER::HasLibrary( const wxString& aNickname,
|
||||
bool aCheckEnabled ) const
|
||||
{
|
||||
if( std::optional<const LIB_DATA*> r = fetchIfLoaded( aNickname ); const LIB_DATA* lib = *r )
|
||||
return !aCheckEnabled || !lib->row->Disabled();
|
||||
if( std::optional<const LIB_DATA*> r = fetchIfLoaded( aNickname ); r.has_value() )
|
||||
return !aCheckEnabled || !( *r )->row->Disabled();
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -513,9 +511,11 @@ bool SYMBOL_LIBRARY_MANAGER_ADAPTER::HasLibrary( const wxString& aNickname,
|
||||
|
||||
std::optional<LIB_STATUS> SYMBOL_LIBRARY_MANAGER_ADAPTER::GetLibraryStatus( const wxString& aNickname ) const
|
||||
{
|
||||
// TODO(JE) should return status even if not loaded, so don't use fetchIfLoaded
|
||||
if( std::optional<const LIB_DATA*> result = fetchIfLoaded( aNickname ) )
|
||||
return ( *result )->status;
|
||||
if( m_libraries.contains( aNickname ) )
|
||||
return m_libraries.at( aNickname ).status;
|
||||
|
||||
if( GlobalLibraries.contains( aNickname ) )
|
||||
return GlobalLibraries.at( aNickname ).status;
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
+51
-37
@@ -20,7 +20,7 @@
|
||||
#ifndef __LIB_TABLE_GRID_H__
|
||||
#define __LIB_TABLE_GRID_H__
|
||||
|
||||
#include <lib_table_base.h>
|
||||
#include <libraries/library_table.h>
|
||||
#include <string_utils.h>
|
||||
#include <wx/grid.h>
|
||||
|
||||
@@ -61,19 +61,22 @@ public:
|
||||
|
||||
wxString GetValue( int aRow, int aCol ) override
|
||||
{
|
||||
if( aRow < (int) size() )
|
||||
wxCHECK( aRow >= 0, wxEmptyString );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
|
||||
if( row < size() )
|
||||
{
|
||||
const LIB_TABLE_ROW* r = at( (size_t) aRow );
|
||||
const LIBRARY_TABLE_ROW& r = at( row );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
case COL_NICKNAME: return UnescapeString( r->GetNickName() );
|
||||
case COL_URI: return r->GetFullURI();
|
||||
case COL_TYPE: return r->GetType();
|
||||
case COL_OPTIONS: return r->GetOptions();
|
||||
case COL_DESCR: return r->GetDescr();
|
||||
case COL_ENABLED: return r->GetIsEnabled() ? wxT( "1" ) : wxT( "0" );
|
||||
case COL_VISIBLE: return r->GetIsVisible() ? wxT( "1" ) : wxT( "0" );
|
||||
case COL_NICKNAME: return UnescapeString( r.Nickname() );
|
||||
case COL_URI: return r.URI();
|
||||
case COL_TYPE: return r.Type();
|
||||
case COL_OPTIONS: return r.Options();
|
||||
case COL_DESCR: return r.Description();
|
||||
case COL_ENABLED: return r.Disabled() ? wxT( "0" ) : wxT( "1" );
|
||||
case COL_VISIBLE: return r.Hidden() ? wxT( "0" ) : wxT( "1" );
|
||||
default: return wxEmptyString;
|
||||
}
|
||||
}
|
||||
@@ -101,39 +104,48 @@ public:
|
||||
|
||||
bool GetValueAsBool( int aRow, int aCol ) override
|
||||
{
|
||||
if( aRow < (int) size() && aCol == COL_ENABLED )
|
||||
return at( (size_t) aRow )->GetIsEnabled();
|
||||
else if( aRow < (int) size() && aCol == COL_VISIBLE )
|
||||
return at( (size_t) aRow )->GetIsVisible();
|
||||
wxCHECK( aRow >= 0, false );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
|
||||
if( row < size() && aCol == COL_ENABLED )
|
||||
return !at( row ).Disabled();
|
||||
else if( row < size() && aCol == COL_VISIBLE )
|
||||
return !at( row ).Hidden();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetValue( int aRow, int aCol, const wxString& aValue ) override
|
||||
{
|
||||
if( aRow < (int) size() )
|
||||
wxCHECK( aRow >= 0, /* void */ );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
|
||||
if( row < size() )
|
||||
{
|
||||
LIB_TABLE_ROW* r = at( (size_t) aRow );
|
||||
LIBRARY_TABLE_ROW& r = at( row );
|
||||
|
||||
switch( aCol )
|
||||
{
|
||||
case COL_NICKNAME: r->SetNickName( EscapeString( aValue, CTX_LIBID ) ); break;
|
||||
case COL_URI: r->SetFullURI( aValue ); break;
|
||||
case COL_TYPE: r->SetType( aValue ); break;
|
||||
case COL_OPTIONS: r->SetOptions( aValue ); break;
|
||||
case COL_DESCR: r->SetDescr( aValue ); break;
|
||||
case COL_ENABLED: r->SetEnabled( aValue == wxT( "1" ) ); break;
|
||||
case COL_VISIBLE: r->SetVisible( aValue == wxT( "1" ) ); break;
|
||||
case COL_NICKNAME: r.SetNickname( EscapeString( aValue, CTX_LIBID ) ); break;
|
||||
case COL_URI: r.SetURI( aValue ); break;
|
||||
case COL_TYPE: r.SetType( aValue ); break;
|
||||
case COL_OPTIONS: r.SetOptions( aValue ); break;
|
||||
case COL_DESCR: r.SetDescription( aValue ); break;
|
||||
case COL_ENABLED: r.SetDisabled( aValue == wxT( "0" ) ); break;
|
||||
case COL_VISIBLE: r.SetHidden( aValue == wxT( "0" ) ); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SetValueAsBool( int aRow, int aCol, bool aValue ) override
|
||||
{
|
||||
if( aRow < (int) size() && aCol == COL_ENABLED )
|
||||
at( (size_t) aRow )->SetEnabled( aValue );
|
||||
else if( aRow < (int) size() && aCol == COL_VISIBLE )
|
||||
at( (size_t) aRow )->SetVisible( aValue );
|
||||
wxCHECK( aRow >= 0, /* void */ );
|
||||
size_t row = static_cast<size_t>( aRow );
|
||||
|
||||
if( row < size() && aCol == COL_ENABLED )
|
||||
at( row ).SetDisabled( !aValue );
|
||||
else if( row < size() && aCol == COL_VISIBLE )
|
||||
at( row ).SetHidden( !aValue );
|
||||
}
|
||||
|
||||
bool IsEmptyCell( int aRow, int aCol ) override
|
||||
@@ -188,7 +200,7 @@ public:
|
||||
// aPos+aNumRows may wrap here, so both ends of the range are tested.
|
||||
if( aPos < size() && aPos + aNumRows <= size() )
|
||||
{
|
||||
LIB_TABLE_ROWS_ITER start = begin() + aPos;
|
||||
LIBRARY_TABLE_ROWS_ITER start = begin() + aPos;
|
||||
erase( start, start + aNumRows );
|
||||
|
||||
if( GetView() )
|
||||
@@ -225,33 +237,35 @@ public:
|
||||
{
|
||||
for( size_t i = 0; i < size(); ++i )
|
||||
{
|
||||
LIB_TABLE_ROW* row = at( i );
|
||||
LIBRARY_TABLE_ROW& row = at( i );
|
||||
|
||||
if( row->GetNickName() == aNickname )
|
||||
if( row.Nickname() == aNickname )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
LIB_TABLE_ROW* At( size_t aIndex )
|
||||
LIBRARY_TABLE_ROW& At( size_t aIndex )
|
||||
{
|
||||
return at( aIndex );
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual LIB_TABLE_ROW* at( size_t aIndex ) = 0;
|
||||
virtual LIBRARY_TABLE_ROW& at( size_t aIndex ) = 0;
|
||||
|
||||
virtual size_t size() const = 0;
|
||||
|
||||
virtual LIB_TABLE_ROW* makeNewRow() = 0;
|
||||
virtual LIBRARY_TABLE_ROW makeNewRow() = 0;
|
||||
|
||||
virtual LIB_TABLE_ROWS_ITER begin() = 0;
|
||||
virtual LIBRARY_TABLE_ROWS_ITER begin() = 0;
|
||||
|
||||
virtual LIB_TABLE_ROWS_ITER insert( LIB_TABLE_ROWS_ITER aIterator, LIB_TABLE_ROW* aRow ) = 0;
|
||||
virtual LIBRARY_TABLE_ROWS_ITER insert( LIBRARY_TABLE_ROWS_ITER aIterator,
|
||||
const LIBRARY_TABLE_ROW& aRow ) = 0;
|
||||
|
||||
virtual void push_back( LIB_TABLE_ROW* aRow ) = 0;
|
||||
virtual void push_back( const LIBRARY_TABLE_ROW& aRow ) = 0;
|
||||
|
||||
virtual LIB_TABLE_ROWS_ITER erase( LIB_TABLE_ROWS_ITER aFirst, LIB_TABLE_ROWS_ITER aLast ) = 0;
|
||||
virtual LIBRARY_TABLE_ROWS_ITER erase( LIBRARY_TABLE_ROWS_ITER aFirst,
|
||||
LIBRARY_TABLE_ROWS_ITER aLast ) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ template<typename ResultType>
|
||||
using LIBRARY_RESULT = tl::expected<ResultType, LIBRARY_ERROR>;
|
||||
|
||||
class LIBRARY_MANAGER_ADAPTER;
|
||||
class PROJECT;
|
||||
|
||||
|
||||
class KICOMMON_API LIBRARY_MANAGER
|
||||
@@ -56,6 +57,9 @@ public:
|
||||
|
||||
std::optional<LIBRARY_MANAGER_ADAPTER*> Adapter( LIBRARY_TABLE_TYPE aType ) const;
|
||||
|
||||
std::optional<LIBRARY_TABLE*> Table( LIBRARY_TABLE_TYPE aType,
|
||||
LIBRARY_TABLE_SCOPE aScope ) const;
|
||||
|
||||
/**
|
||||
* Returns a flattened list of libraries of the given type
|
||||
* @param aType determines which type of libraries to return (symbol, footprint, ...)
|
||||
@@ -80,6 +84,8 @@ public:
|
||||
|
||||
void LoadProjectTables( const wxString& aProjectPath );
|
||||
|
||||
LIBRARY_RESULT<void> Save( LIBRARY_TABLE* aTable ) const;
|
||||
|
||||
/**
|
||||
* Return the full location specifying URI for the LIB, either in original UI form or
|
||||
* in environment variable expanded form.
|
||||
@@ -92,13 +98,22 @@ public:
|
||||
std::optional<wxString> GetFullURI( LIBRARY_TABLE_TYPE aType, const wxString& aNickname,
|
||||
bool aSubstituted = false ) const;
|
||||
|
||||
static wxString ExpandURI( const wxString& aShortURI, const PROJECT& aProject );
|
||||
|
||||
static bool UrisAreEquivalent( const wxString& aURI1, const wxString& aURI2 );
|
||||
|
||||
private:
|
||||
void loadTables( const wxString& aTablePath, LIBRARY_TABLE_SCOPE aScope );
|
||||
|
||||
std::vector<std::unique_ptr<LIBRARY_TABLE>> m_tables;
|
||||
std::vector<std::unique_ptr<LIBRARY_TABLE>> m_project_tables;
|
||||
void loadNestedTables( LIBRARY_TABLE& aTable );
|
||||
|
||||
std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>> m_tables;
|
||||
|
||||
/// Map of full URI to table object for tables that are referenced by global or project tables
|
||||
std::map<wxString, std::unique_ptr<LIBRARY_TABLE>> m_childTables;
|
||||
|
||||
// TODO: support multiple projects
|
||||
std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_TABLE>> m_projectTables;
|
||||
|
||||
std::map<LIBRARY_TABLE_TYPE, std::unique_ptr<LIBRARY_MANAGER_ADAPTER>> m_adapters;
|
||||
};
|
||||
|
||||
@@ -57,18 +57,38 @@ public:
|
||||
|
||||
LIBRARY_TABLE_ROW() = default;
|
||||
|
||||
bool operator==( const LIBRARY_TABLE_ROW& aOther ) const;
|
||||
|
||||
void SetNickname( const wxString& aNickname ) { m_nickname = aNickname; }
|
||||
const wxString& Nickname() const { return m_nickname; }
|
||||
|
||||
void SetURI( const wxString& aUri ) { m_uri = aUri; }
|
||||
const wxString& URI() const { return m_uri; }
|
||||
|
||||
void SetType( const wxString& aType ) { m_type = aType; }
|
||||
const wxString& Type() const { return m_type; }
|
||||
|
||||
void SetOptions( const wxString& aOptions ) { m_options = aOptions; }
|
||||
const wxString& Options() const { return m_options; }
|
||||
|
||||
void SetDescription( const wxString& aDescription ) { m_description = aDescription; }
|
||||
const wxString& Description() const { return m_description; }
|
||||
|
||||
void SetScope( LIBRARY_TABLE_SCOPE aScope ) { m_scope = aScope; }
|
||||
LIBRARY_TABLE_SCOPE Scope() const { return m_scope; }
|
||||
|
||||
void SetDisabled( bool aDisabled = true ) { m_disabled = aDisabled; }
|
||||
bool Disabled() const { return m_disabled; }
|
||||
|
||||
void SetHidden( bool aHidden = true ) { m_hidden = aHidden; }
|
||||
bool Hidden() const { return m_hidden; }
|
||||
|
||||
std::map<std::string, UTF8> GetOptionsMap() const;
|
||||
|
||||
void SetOk( bool aOk = true ) { m_ok = aOk; }
|
||||
bool IsOk() const { return m_ok; }
|
||||
|
||||
void SetErrorDescription( const wxString& aDescription ) { m_errorDescription = aDescription; }
|
||||
const wxString& ErrorDescription() const { return m_errorDescription; }
|
||||
|
||||
private:
|
||||
@@ -86,6 +106,10 @@ private:
|
||||
};
|
||||
|
||||
|
||||
typedef std::vector<LIBRARY_TABLE_ROW>::iterator LIBRARY_TABLE_ROWS_ITER;
|
||||
typedef std::vector<LIBRARY_TABLE_ROW>::const_iterator LIBRARY_TABLE_ROWS_CITER;
|
||||
|
||||
|
||||
class KICOMMON_API LIBRARY_TABLE
|
||||
{
|
||||
public:
|
||||
@@ -105,8 +129,7 @@ public:
|
||||
|
||||
~LIBRARY_TABLE() = default;
|
||||
|
||||
// TODO move out of this class
|
||||
void LoadNestedTables();
|
||||
bool operator==( const LIBRARY_TABLE& aOther ) const;
|
||||
|
||||
const wxString& Path() const { return m_path; }
|
||||
void SetPath( const wxString &aPath ) { m_path = aPath; }
|
||||
@@ -114,6 +137,9 @@ public:
|
||||
LIBRARY_TABLE_TYPE Type() const { return m_type; }
|
||||
void SetType( const LIBRARY_TABLE_TYPE aType ) { m_type = aType; }
|
||||
|
||||
void SetScope( LIBRARY_TABLE_SCOPE aScope ) { m_scope = aScope; }
|
||||
LIBRARY_TABLE_SCOPE Scope() const { return m_scope; }
|
||||
|
||||
std::optional<int> Version() const{ return m_version; }
|
||||
void SetVersion( const std::optional<int> &aVersion ) { m_version = aVersion; }
|
||||
|
||||
@@ -123,8 +149,6 @@ public:
|
||||
const std::vector<LIBRARY_TABLE_ROW>& Rows() const { return m_rows; }
|
||||
std::vector<LIBRARY_TABLE_ROW>& Rows() { return m_rows; }
|
||||
|
||||
const std::map<wxString, std::unique_ptr<LIBRARY_TABLE>>& Children() { return m_children; }
|
||||
|
||||
void Format( OUTPUTFORMATTER* aOutput ) const;
|
||||
|
||||
private:
|
||||
@@ -146,8 +170,6 @@ private:
|
||||
wxString m_errorDescription;
|
||||
|
||||
std::vector<LIBRARY_TABLE_ROW> m_rows;
|
||||
|
||||
std::map<wxString, std::unique_ptr<LIBRARY_TABLE>> m_children;
|
||||
};
|
||||
|
||||
#endif //LIBRARY_TABLE_H
|
||||
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
|
||||
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> Parse( const std::filesystem::path& aPath );
|
||||
|
||||
tl::expected<LIBRARY_TABLE_IR, LIBRARY_PARSE_ERROR> ParseBuffer( const std::string& aBuffer );
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
+5
-2
@@ -40,6 +40,7 @@
|
||||
|
||||
#include <ki_exception.h>
|
||||
#include <kicommon.h>
|
||||
#include <io/kicad/kicad_io_utils.h>
|
||||
|
||||
/**
|
||||
* This is like sprintf() but the output is appended to a std::string instead of to a
|
||||
@@ -520,8 +521,9 @@ protected:
|
||||
class KICOMMON_API PRETTIFIED_FILE_OUTPUTFORMATTER : public OUTPUTFORMATTER
|
||||
{
|
||||
public:
|
||||
PRETTIFIED_FILE_OUTPUTFORMATTER( const wxString& aFileName, const wxChar* aMode = wxT( "wt" ),
|
||||
char aQuoteChar = '"' );
|
||||
PRETTIFIED_FILE_OUTPUTFORMATTER( const wxString& aFileName,
|
||||
KICAD_FORMAT::FORMAT_MODE aFormatMode = KICAD_FORMAT::FORMAT_MODE::NORMAL,
|
||||
const wxChar* aMode = wxT( "wt" ), char aQuoteChar = '"' );
|
||||
|
||||
~PRETTIFIED_FILE_OUTPUTFORMATTER();
|
||||
|
||||
@@ -537,6 +539,7 @@ protected:
|
||||
private:
|
||||
FILE* m_fp;
|
||||
std::string m_buf;
|
||||
KICAD_FORMAT::FORMAT_MODE m_mode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -38,6 +38,14 @@
|
||||
class OUTPUTFORMATTER;
|
||||
class KIID;
|
||||
|
||||
|
||||
/**
|
||||
* An extension of wxXmlAttribute that stores a variant type rather than just a string.
|
||||
* Technically, XML requires that all attribute values be strings, but since XNODE is
|
||||
* primarily used for s-expression formatting rather than XML formatting, and KiCad's
|
||||
* s-expression format permits integer and floating-point numeric values in lists, this
|
||||
* class allows storage of the source value so that it can be properly formatted in the output.
|
||||
*/
|
||||
class KICOMMON_API XATTR : public wxXmlAttribute
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -74,46 +74,49 @@
|
||||
#include <project_pcb.h>
|
||||
#include <common.h>
|
||||
#include <dialog_HTML_reporter_base.h>
|
||||
#include <libraries/library_manager.h>
|
||||
#include <widgets/wx_html_report_box.h>
|
||||
|
||||
|
||||
/**
|
||||
* This class builds a wxGridTableBase by wrapping an #FP_LIB_TABLE object.
|
||||
*/
|
||||
class FP_LIB_TABLE_GRID : public LIB_TABLE_GRID, public FP_LIB_TABLE
|
||||
class FP_LIB_TABLE_GRID : public LIB_TABLE_GRID
|
||||
{
|
||||
friend class PANEL_FP_LIB_TABLE;
|
||||
friend class FP_GRID_TRICKS;
|
||||
|
||||
protected:
|
||||
LIB_TABLE_ROW* at( size_t aIndex ) override { return &m_rows.at( aIndex ); }
|
||||
LIBRARY_TABLE_ROW& at( size_t aIndex ) override { return m_table.Rows().at( aIndex ); }
|
||||
|
||||
size_t size() const override { return m_rows.size(); }
|
||||
size_t size() const override { return m_table.Rows().size(); }
|
||||
|
||||
LIB_TABLE_ROW* makeNewRow() override
|
||||
LIBRARY_TABLE_ROW makeNewRow() override
|
||||
{
|
||||
return dynamic_cast< LIB_TABLE_ROW* >( new FP_LIB_TABLE_ROW );
|
||||
return LIBRARY_TABLE_ROW();
|
||||
}
|
||||
|
||||
LIB_TABLE_ROWS_ITER begin() override { return m_rows.begin(); }
|
||||
LIBRARY_TABLE_ROWS_ITER begin() override { return m_table.Rows().begin(); }
|
||||
|
||||
LIB_TABLE_ROWS_ITER insert( LIB_TABLE_ROWS_ITER aIterator, LIB_TABLE_ROW* aRow ) override
|
||||
LIBRARY_TABLE_ROWS_ITER insert( LIBRARY_TABLE_ROWS_ITER aIterator,
|
||||
const LIBRARY_TABLE_ROW& aRow ) override
|
||||
{
|
||||
return m_rows.insert( aIterator, aRow );
|
||||
return m_table.Rows().insert( aIterator, aRow );
|
||||
}
|
||||
|
||||
void push_back( LIB_TABLE_ROW* aRow ) override { m_rows.push_back( aRow ); }
|
||||
void push_back( const LIBRARY_TABLE_ROW& aRow ) override { m_table.Rows().push_back( aRow ); }
|
||||
|
||||
LIB_TABLE_ROWS_ITER erase( LIB_TABLE_ROWS_ITER aFirst, LIB_TABLE_ROWS_ITER aLast ) override
|
||||
LIBRARY_TABLE_ROWS_ITER erase( LIBRARY_TABLE_ROWS_ITER aFirst,
|
||||
LIBRARY_TABLE_ROWS_ITER aLast ) override
|
||||
{
|
||||
return m_rows.erase( aFirst, aLast );
|
||||
return m_table.Rows().erase( aFirst, aLast );
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
FP_LIB_TABLE_GRID( const FP_LIB_TABLE& aTableToEdit )
|
||||
FP_LIB_TABLE_GRID( const LIBRARY_TABLE& aTableToEdit ) :
|
||||
m_table( aTableToEdit )
|
||||
{
|
||||
m_rows = aTableToEdit.m_rows;
|
||||
}
|
||||
|
||||
void SetValue( int aRow, int aCol, const wxString &aValue ) override
|
||||
@@ -125,10 +128,9 @@ public:
|
||||
// If setting a filepath, attempt to auto-detect the format
|
||||
if( aCol == COL_URI )
|
||||
{
|
||||
LIB_TABLE_ROW* row = at( (size_t) aRow );
|
||||
wxString fullURI = row->GetFullURI( true );
|
||||
|
||||
PCB_IO_MGR::PCB_FILE_T pluginType = PCB_IO_MGR::GuessPluginTypeFromLibPath( fullURI );
|
||||
LIBRARY_TABLE_ROW& row = at( (size_t) aRow );
|
||||
wxString uri = LIBRARY_MANAGER::ExpandURI( row.URI(), Pgm().GetSettingsManager().Prj() );
|
||||
PCB_IO_MGR::PCB_FILE_T pluginType = PCB_IO_MGR::GuessPluginTypeFromLibPath( uri );
|
||||
|
||||
if( pluginType == PCB_IO_MGR::FILE_TYPE_NONE )
|
||||
pluginType = PCB_IO_MGR::KICAD_SEXP;
|
||||
@@ -136,6 +138,10 @@ public:
|
||||
SetValue( aRow, COL_TYPE, PCB_IO_MGR::ShowType( pluginType ) );
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/// Working copy of a table
|
||||
LIBRARY_TABLE m_table;
|
||||
};
|
||||
|
||||
|
||||
@@ -163,21 +169,21 @@ protected:
|
||||
|
||||
if( tbl->GetNumberRows() > aRow )
|
||||
{
|
||||
LIB_TABLE_ROW* row = tbl->at( (size_t) aRow );
|
||||
const wxString& options = row->GetOptions();
|
||||
LIBRARY_TABLE_ROW& row = tbl->at( static_cast<size_t>( aRow ) );
|
||||
const wxString& options = row.Options();
|
||||
wxString result = options;
|
||||
std::map<std::string, UTF8> choices;
|
||||
|
||||
PCB_IO_MGR::PCB_FILE_T pi_type = PCB_IO_MGR::EnumFromStr( row->GetType() );
|
||||
PCB_IO_MGR::PCB_FILE_T pi_type = PCB_IO_MGR::EnumFromStr( row.Type() );
|
||||
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( pi_type ) );
|
||||
pi->GetLibraryOptions( &choices );
|
||||
|
||||
DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row->GetNickName(), choices, options, &result );
|
||||
DIALOG_PLUGIN_OPTIONS dlg( m_dialog, row.Nickname(), choices, options, &result );
|
||||
dlg.ShowModal();
|
||||
|
||||
if( options != result )
|
||||
{
|
||||
row->SetOptions( result );
|
||||
row.SetOptions( result );
|
||||
m_grid->Refresh();
|
||||
}
|
||||
}
|
||||
@@ -187,6 +193,8 @@ protected:
|
||||
/// spreadsheet formatted text.
|
||||
void paste_text( const wxString& cb_text ) override
|
||||
{
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
FP_LIB_TABLE_GRID* tbl = (FP_LIB_TABLE_GRID*) m_grid->GetTable();
|
||||
size_t ndx = cb_text.find( "(fp_lib_table" );
|
||||
|
||||
@@ -242,6 +250,7 @@ protected:
|
||||
|
||||
m_grid->AutoSizeColumns( false );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -290,8 +299,8 @@ void PANEL_FP_LIB_TABLE::setupGrid( WX_GRID* aGrid )
|
||||
[this]( WX_GRID* grid, int row ) -> wxString
|
||||
{
|
||||
auto* libTable = static_cast<FP_LIB_TABLE_GRID*>( grid->GetTable() );
|
||||
auto* tableRow = static_cast<FP_LIB_TABLE_ROW*>( libTable->at( row ) );
|
||||
PCB_IO_MGR::PCB_FILE_T fileType = tableRow->GetFileType();
|
||||
LIBRARY_TABLE_ROW& tableRow = libTable->at( row );
|
||||
PCB_IO_MGR::PCB_FILE_T fileType = PCB_IO_MGR::EnumFromStr( tableRow.Type() );
|
||||
const IO_BASE::IO_FILE_DESC& pluginDesc = m_supportedFpFiles.at( fileType );
|
||||
|
||||
if( pluginDesc.m_IsFile )
|
||||
@@ -345,7 +354,12 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PRO
|
||||
m_projectBasePath( aProjectBasePath ),
|
||||
m_parent( aParent )
|
||||
{
|
||||
m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *aGlobalTable ), true );
|
||||
std::optional<LIBRARY_TABLE*> table =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::FOOTPRINT,
|
||||
LIBRARY_TABLE_SCOPE::GLOBAL );
|
||||
wxASSERT( table );
|
||||
|
||||
m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *table.value() ), true );
|
||||
|
||||
// add Cut, Copy, and Paste to wxGrids
|
||||
m_path_subs_grid->PushEventHandler( new GRID_TRICKS( m_path_subs_grid ) );
|
||||
@@ -369,7 +383,10 @@ PANEL_FP_LIB_TABLE::PANEL_FP_LIB_TABLE( DIALOG_EDIT_LIBRARY_TABLES* aParent, PRO
|
||||
|
||||
if( aProjectTable )
|
||||
{
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
m_project_grid->SetTable( new FP_LIB_TABLE_GRID( *aProjectTable ), true );
|
||||
#endif
|
||||
setupGrid( m_project_grid );
|
||||
}
|
||||
else
|
||||
@@ -688,6 +705,8 @@ void PANEL_FP_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
|
||||
m_cur_grid->OnMoveRowUp(
|
||||
[&]( int row )
|
||||
{
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
FP_LIB_TABLE_GRID* tbl = cur_model();
|
||||
boost::ptr_vector<LIB_TABLE_ROW>::auto_type move_me = tbl->m_rows.release( tbl->m_rows.begin() + row );
|
||||
|
||||
@@ -696,6 +715,7 @@ void PANEL_FP_LIB_TABLE::moveUpHandler( wxCommandEvent& event )
|
||||
// Update the wxGrid
|
||||
wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row - 1, 0 );
|
||||
tbl->GetView()->ProcessTableMessage( msg );
|
||||
#endif
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -705,6 +725,8 @@ void PANEL_FP_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
|
||||
m_cur_grid->OnMoveRowDown(
|
||||
[&]( int row )
|
||||
{
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
FP_LIB_TABLE_GRID* tbl = cur_model();
|
||||
boost::ptr_vector<LIB_TABLE_ROW>::auto_type move_me = tbl->m_rows.release( tbl->m_rows.begin() + row );
|
||||
|
||||
@@ -713,6 +735,7 @@ void PANEL_FP_LIB_TABLE::moveDownHandler( wxCommandEvent& event )
|
||||
// Update the wxGrid
|
||||
wxGridTableMessage msg( tbl, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, row, 0 );
|
||||
tbl->GetView()->ProcessTableMessage( msg );
|
||||
#endif
|
||||
} );
|
||||
}
|
||||
|
||||
@@ -1001,7 +1024,12 @@ void PANEL_FP_LIB_TABLE::onReset( wxCommandEvent& event )
|
||||
wxGridTableBase* table = m_global_grid->GetTable();
|
||||
m_global_grid->DestroyTable( table );
|
||||
|
||||
m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *m_globalTable ), true );
|
||||
std::optional<LIBRARY_TABLE*> newTable =
|
||||
Pgm().GetLibraryManager().Table( LIBRARY_TABLE_TYPE::FOOTPRINT,
|
||||
LIBRARY_TABLE_SCOPE::GLOBAL );
|
||||
wxASSERT( newTable );
|
||||
|
||||
m_global_grid->SetTable( new FP_LIB_TABLE_GRID( *newTable.value() ), true );
|
||||
m_global_grid->PopEventHandler( true );
|
||||
setupGrid( m_global_grid );
|
||||
m_parent->m_GlobalTableChanged = true;
|
||||
@@ -1035,6 +1063,8 @@ bool PANEL_FP_LIB_TABLE::TransferDataFromWindow()
|
||||
|
||||
if( verifyTables() )
|
||||
{
|
||||
// TODO(JE) library tables
|
||||
#if 0
|
||||
if( *global_model() != *m_globalTable )
|
||||
{
|
||||
m_parent->m_GlobalTableChanged = true;
|
||||
@@ -1046,7 +1076,7 @@ bool PANEL_FP_LIB_TABLE::TransferDataFromWindow()
|
||||
m_parent->m_ProjectTableChanged = true;
|
||||
m_projectTable->TransferRows( project_model()->m_rows );
|
||||
}
|
||||
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -103,9 +103,6 @@ BOOST_AUTO_TEST_CASE( ParseAndConstruct )
|
||||
wxString::Format( "Expected error '%s' but got '%s'",
|
||||
expected_error, table.ErrorDescription() ) );
|
||||
|
||||
// TODO this should move to manager test suite
|
||||
table.LoadNestedTables();
|
||||
|
||||
// Non-parsed tables can't be formatted
|
||||
if( !table.IsOk() )
|
||||
continue;
|
||||
@@ -141,7 +138,7 @@ BOOST_AUTO_TEST_CASE( Manager )
|
||||
LIBRARY_MANAGER manager;
|
||||
manager.LoadGlobalTables();
|
||||
|
||||
BOOST_REQUIRE( manager.Rows( LIBRARY_TABLE_TYPE::SYMBOL ).size() == 2 );
|
||||
BOOST_REQUIRE( manager.Rows( LIBRARY_TABLE_TYPE::SYMBOL ).size() == 3 );
|
||||
BOOST_REQUIRE( manager.Rows( LIBRARY_TABLE_TYPE::FOOTPRINT ).size() == 146 );
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user