2020-09-08 19:51:22 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2020 Roberto Fernandez Bautista <roberto.fer.bau@gmail.com>
|
2021-12-09 00:14:04 +00:00
|
|
|
* Copyright (C) 2020-2021 KiCad Developers, see AUTHORS.txt for contributors.
|
2020-09-08 19:51:22 +00:00
|
|
|
*
|
|
|
|
* 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @file cadstar_pcb_archive_plugin.cpp
|
|
|
|
* @brief Pcbnew PLUGIN for CADSTAR PCB Archive (*.cpa) format: an ASCII format
|
|
|
|
* based on S-expressions.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sch_plugins/cadstar/cadstar_sch_archive_loader.h>
|
|
|
|
#include <sch_plugins/cadstar/cadstar_sch_archive_plugin.h>
|
|
|
|
|
2023-02-26 22:37:05 +00:00
|
|
|
#include <lib_symbol.h>
|
|
|
|
#include <progress_reporter.h>
|
2022-11-06 16:51:52 +00:00
|
|
|
#include <string_utf8_map.h>
|
2020-09-08 19:51:22 +00:00
|
|
|
#include <sch_screen.h>
|
|
|
|
#include <sch_sheet.h>
|
|
|
|
#include <schematic.h>
|
2023-02-26 16:27:25 +00:00
|
|
|
#include <sch_plugins/kicad/sch_sexpr_plugin.h>
|
2020-09-20 21:08:46 +00:00
|
|
|
#include <wildcards_and_files_ext.h>
|
2020-09-08 19:51:22 +00:00
|
|
|
|
|
|
|
|
|
|
|
const wxString CADSTAR_SCH_ARCHIVE_PLUGIN::GetName() const
|
|
|
|
{
|
|
|
|
return wxT( "CADSTAR Schematic Archive" );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const wxString CADSTAR_SCH_ARCHIVE_PLUGIN::GetFileExtension() const
|
|
|
|
{
|
2023-02-26 22:37:05 +00:00
|
|
|
return CadstarSchematicFileExtension;
|
2020-09-08 19:51:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const wxString CADSTAR_SCH_ARCHIVE_PLUGIN::GetLibraryFileExtension() const
|
|
|
|
{
|
2023-02-26 22:37:05 +00:00
|
|
|
return CadstarPartsLibraryFileExtension;
|
2020-09-08 19:51:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int CADSTAR_SCH_ARCHIVE_PLUGIN::GetModifyHash() const
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SCH_SHEET* CADSTAR_SCH_ARCHIVE_PLUGIN::Load( const wxString& aFileName, SCHEMATIC* aSchematic,
|
2022-11-06 16:51:52 +00:00
|
|
|
SCH_SHEET* aAppendToMe, const STRING_UTF8_MAP* aProperties )
|
2020-09-08 19:51:22 +00:00
|
|
|
{
|
2023-02-26 16:27:25 +00:00
|
|
|
wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr );
|
2020-09-08 19:51:22 +00:00
|
|
|
|
2020-09-20 21:08:46 +00:00
|
|
|
SCH_SHEET* rootSheet = nullptr;
|
|
|
|
|
2020-09-08 19:51:22 +00:00
|
|
|
|
|
|
|
if( aAppendToMe )
|
|
|
|
{
|
|
|
|
wxCHECK_MSG( aSchematic->IsValid(), nullptr, "Can't append to a schematic with no root!" );
|
2020-09-20 21:08:46 +00:00
|
|
|
rootSheet = &aSchematic->Root();
|
2020-09-08 19:51:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-09-20 21:08:46 +00:00
|
|
|
rootSheet = new SCH_SHEET( aSchematic );
|
|
|
|
rootSheet->SetFileName( aFileName );
|
2021-12-09 00:14:04 +00:00
|
|
|
aSchematic->SetRoot( rootSheet );
|
2020-09-08 19:51:22 +00:00
|
|
|
}
|
|
|
|
|
2020-09-20 21:08:46 +00:00
|
|
|
if( !rootSheet->GetScreen() )
|
2020-09-08 19:51:22 +00:00
|
|
|
{
|
2020-09-20 21:08:46 +00:00
|
|
|
SCH_SCREEN* screen = new SCH_SCREEN( aSchematic );
|
2020-09-08 19:51:22 +00:00
|
|
|
screen->SetFileName( aFileName );
|
2020-09-20 21:08:46 +00:00
|
|
|
rootSheet->SetScreen( screen );
|
|
|
|
}
|
|
|
|
|
2023-02-26 16:27:25 +00:00
|
|
|
CADSTAR_SCH_ARCHIVE_LOADER csaLoader( aFileName, m_reporter, m_progressReporter );
|
|
|
|
csaLoader.Load( aSchematic, rootSheet );
|
|
|
|
|
|
|
|
// SAVE SYMBOLS TO PROJECT LIBRARY:
|
2020-09-20 21:08:46 +00:00
|
|
|
SYMBOL_LIB_TABLE* libTable = aSchematic->Prj().SchSymbolLibTable();
|
|
|
|
|
2023-02-26 16:27:25 +00:00
|
|
|
wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." );
|
2020-09-20 21:08:46 +00:00
|
|
|
|
|
|
|
// Lets come up with a nice library name
|
|
|
|
wxString libName = aSchematic->Prj().GetProjectName();
|
|
|
|
|
|
|
|
if( libName.IsEmpty() )
|
|
|
|
{
|
|
|
|
wxFileName fn( rootSheet->GetFileName() );
|
|
|
|
libName = fn.GetName();
|
2020-09-08 19:51:22 +00:00
|
|
|
}
|
|
|
|
|
2020-09-20 21:08:46 +00:00
|
|
|
if( libName.IsEmpty() )
|
|
|
|
libName = "noname";
|
|
|
|
|
2020-12-17 23:32:23 +00:00
|
|
|
libName = LIB_ID::FixIllegalChars( libName, true );
|
2020-09-20 21:08:46 +00:00
|
|
|
|
2023-02-26 16:27:25 +00:00
|
|
|
wxFileName libFileName( aSchematic->Prj().GetProjectPath(), libName,
|
|
|
|
KiCadSymbolLibFileExtension );
|
2020-09-20 21:08:46 +00:00
|
|
|
|
|
|
|
SCH_PLUGIN::SCH_PLUGIN_RELEASER sch_plugin;
|
|
|
|
sch_plugin.set( SCH_IO_MGR::FindPlugin( SCH_IO_MGR::SCH_KICAD ) );
|
|
|
|
|
|
|
|
if( !libTable->HasLibrary( libName ) )
|
|
|
|
{
|
|
|
|
// Create a new empty symbol library.
|
|
|
|
sch_plugin->CreateSymbolLib( libFileName.GetFullPath() );
|
|
|
|
wxString libTableUri = "${KIPRJMOD}/" + libFileName.GetFullName();
|
|
|
|
|
|
|
|
// Add the new library to the project symbol library table.
|
|
|
|
libTable->InsertRow(
|
|
|
|
new SYMBOL_LIB_TABLE_ROW( libName, libTableUri, wxString( "KiCad" ) ) );
|
|
|
|
|
|
|
|
// Save project symbol library table.
|
2023-02-26 16:27:25 +00:00
|
|
|
wxFileName fn( aSchematic->Prj().GetProjectPath(),
|
|
|
|
SYMBOL_LIB_TABLE::GetSymbolLibTableFileName() );
|
2020-09-20 21:08:46 +00:00
|
|
|
|
|
|
|
// So output formatter goes out of scope and closes the file before reloading.
|
|
|
|
{
|
|
|
|
FILE_OUTPUTFORMATTER formatter( fn.GetFullPath() );
|
|
|
|
libTable->Format( &formatter, 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Relaod the symbol library table.
|
|
|
|
aSchematic->Prj().SetElem( PROJECT::ELEM_SYMBOL_LIB_TABLE, NULL );
|
|
|
|
aSchematic->Prj().SchSymbolLibTable();
|
|
|
|
}
|
2020-09-13 21:42:17 +00:00
|
|
|
|
2023-02-26 16:27:25 +00:00
|
|
|
// set properties to prevent save file on every symbol save
|
|
|
|
STRING_UTF8_MAP properties;
|
|
|
|
properties.emplace( SCH_SEXPR_PLUGIN::PropBuffering, "" );
|
|
|
|
|
|
|
|
for( LIB_SYMBOL* const& symbol : csaLoader.GetLoadedSymbols() )
|
|
|
|
sch_plugin->SaveSymbol( libFileName.GetFullPath(), symbol, &properties );
|
2020-09-20 21:08:46 +00:00
|
|
|
|
|
|
|
sch_plugin->SaveLibrary( libFileName.GetFullPath() );
|
2020-09-13 21:42:17 +00:00
|
|
|
|
2023-02-26 16:27:25 +00:00
|
|
|
// Link up all symbols in the design to the newly created library
|
|
|
|
for( SCH_SHEET_PATH& sheet : aSchematic->GetSheets() )
|
|
|
|
{
|
|
|
|
for( SCH_ITEM* item : sheet.LastScreen()->Items().OfType( SCH_SYMBOL_T ) )
|
|
|
|
{
|
|
|
|
SCH_SYMBOL* sym = static_cast<SCH_SYMBOL*>( item );
|
|
|
|
|
|
|
|
if( sym->GetLibId().IsLegacy() )
|
|
|
|
{
|
|
|
|
LIB_ID libid = sym->GetLibId();
|
|
|
|
libid.SetLibNickname( libName );
|
|
|
|
sym->SetLibId( libid );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-08-18 21:19:28 +00:00
|
|
|
// Need to fix up junctions after import to retain connectivity
|
|
|
|
aSchematic->FixupJunctions();
|
|
|
|
|
2020-09-20 21:08:46 +00:00
|
|
|
return rootSheet;
|
2020-09-08 19:51:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CADSTAR_SCH_ARCHIVE_PLUGIN::CheckHeader( const wxString& aFileName )
|
|
|
|
{
|
2020-09-19 22:05:02 +00:00
|
|
|
// TODO: write a parser for the cpa header. For now assume it is valid
|
|
|
|
// and throw exceptions when parsing
|
2020-09-08 19:51:22 +00:00
|
|
|
return true;
|
|
|
|
}
|
2023-02-26 22:37:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
void CADSTAR_SCH_ARCHIVE_PLUGIN::EnumerateSymbolLib( wxArrayString& aSymbolNameList,
|
|
|
|
const wxString& aLibraryPath,
|
|
|
|
const STRING_UTF8_MAP* aProperties )
|
|
|
|
{
|
|
|
|
std::vector<LIB_SYMBOL*> symbols;
|
|
|
|
EnumerateSymbolLib( symbols, aLibraryPath, aProperties );
|
|
|
|
|
|
|
|
for( LIB_SYMBOL*& sym : symbols )
|
|
|
|
aSymbolNameList.Add( sym->GetName() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CADSTAR_SCH_ARCHIVE_PLUGIN::EnumerateSymbolLib( std::vector<LIB_SYMBOL*>& aSymbolList,
|
|
|
|
const wxString& aLibraryPath,
|
|
|
|
const STRING_UTF8_MAP* aProperties )
|
|
|
|
{
|
2023-03-07 21:38:15 +00:00
|
|
|
static std::vector<LIB_SYMBOL*> cached;
|
|
|
|
static wxString cachedPath;
|
|
|
|
|
|
|
|
if(cachedPath == aLibraryPath)
|
|
|
|
{
|
|
|
|
aSymbolList = cached;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-02-26 22:37:05 +00:00
|
|
|
wxFileName fn( aLibraryPath );
|
|
|
|
fn.SetExt( "csa" );
|
|
|
|
fn.SetName( "symbol" );
|
|
|
|
|
|
|
|
CADSTAR_SCH_ARCHIVE_LOADER csaLoader( fn.GetFullPath(), m_reporter, m_progressReporter );
|
2023-03-07 21:38:15 +00:00
|
|
|
aSymbolList = csaLoader.LoadPartsLib( aLibraryPath );
|
|
|
|
cachedPath = aLibraryPath;
|
|
|
|
cached = aSymbolList;
|
2023-02-26 22:37:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
LIB_SYMBOL* CADSTAR_SCH_ARCHIVE_PLUGIN::LoadSymbol( const wxString& aLibraryPath,
|
|
|
|
const wxString& aAliasName,
|
|
|
|
const STRING_UTF8_MAP* aProperties )
|
|
|
|
{
|
2023-03-07 21:38:15 +00:00
|
|
|
std::vector<LIB_SYMBOL*> symbols;
|
|
|
|
EnumerateSymbolLib( symbols, aLibraryPath, aProperties );
|
|
|
|
|
|
|
|
for( LIB_SYMBOL*& sym : symbols )
|
|
|
|
{
|
|
|
|
if( sym->GetName() == aAliasName )
|
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
|
2023-02-26 22:37:05 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CADSTAR_SCH_ARCHIVE_PLUGIN::GetAvailableSymbolFields( std::vector<wxString>& aNames )
|
|
|
|
{
|
|
|
|
std::set<wxString> fieldNames;
|
|
|
|
|
|
|
|
for( auto& [libnameStr, libSymbol] : m_libCache )
|
|
|
|
{
|
|
|
|
std::vector<LIB_FIELD*> fields;
|
|
|
|
libSymbol->GetFields( fields );
|
|
|
|
|
|
|
|
for( LIB_FIELD* field : fields )
|
|
|
|
{
|
|
|
|
if( field->IsMandatory() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
fieldNames.insert( field->GetName() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::copy( fieldNames.begin(), fieldNames.end(), std::back_inserter( aNames ) );
|
|
|
|
}
|