diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp index 054d4d814d..a63853d4ca 100644 --- a/common/wildcards_and_files_ext.cpp +++ b/common/wildcards_and_files_ext.cpp @@ -284,6 +284,12 @@ wxString FILEEXT::KiCadSchematicFileWildcard() } +wxString FILEEXT::AltiumProjectFilesWildcard() +{ + return _( "Altium Project files" ) + AddFileExtListToFilter( { "PrjPcb" } ); +} + + wxString FILEEXT::CadstarArchiveFilesWildcard() { return _( "CADSTAR Archive files" ) + AddFileExtListToFilter( { "csa", "cpa" } ); diff --git a/eeschema/cross-probing.cpp b/eeschema/cross-probing.cpp index 51d85ca68d..1e46759f54 100644 --- a/eeschema/cross-probing.cpp +++ b/eeschema/cross-probing.cpp @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -34,7 +35,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -835,6 +838,55 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) switch( mail.Command() ) { + case MAIL_ADD_LOCAL_LIB: + { + std::stringstream ss( payload ); + std::string file; + SYMBOL_LIB_TABLE* symLibTbl = PROJECT_SCH::SchSymbolLibTable( &Prj() ); + + wxCHECK_RET( symLibTbl, "Could not load symbol lib table." ); + + while( std::getline( ss, file, '\n' ) ) + { + if( file.empty() ) + continue; + + wxFileName fn( file ); + IO_RELEASER pi; + SCH_IO_MGR::SCH_FILE_T type = SCH_IO_MGR::GuessPluginTypeFromLibPath( fn.GetFullPath() ); + + if( type == SCH_IO_MGR::SCH_FILE_UNKNOWN ) + { + wxLogTrace( "KIWAY", "Unknown file type: %s", fn.GetFullPath() ); + continue; + } + + pi.reset( SCH_IO_MGR::FindPlugin( type ) ); + + if( !symLibTbl->HasLibrary( fn.GetName() ) ) + { + symLibTbl->InsertRow( new SYMBOL_LIB_TABLE_ROW( fn.GetName(), fn.GetFullPath(), + SCH_IO_MGR::ShowType( type ) ) ); + wxString tblName = Prj().SymbolLibTableName(); + + try + { + symLibTbl->Save( tblName ); + } + catch( const IO_ERROR& ioe ) + { + wxLogError( _( "Error saving project-specific library table:\n\n%s" ), ioe.What() ); + } + } + } + + Kiway().ExpressMail( FRAME_CVPCB, MAIL_RELOAD_LIB, payload ); + Kiway().ExpressMail( FRAME_SCH_SYMBOL_EDITOR, MAIL_RELOAD_LIB, payload ); + Kiway().ExpressMail( FRAME_SCH_VIEWER, MAIL_RELOAD_LIB, payload ); + + break; + } + case MAIL_CROSS_PROBE: ExecuteRemoteCommand( payload.c_str() ); break; @@ -957,7 +1009,6 @@ void SCH_EDIT_FRAME::KiwayMailIn( KIWAY_EXPRESS& mail ) std::string fnameStr; wxCHECK( std::getline( ss, fnameStr, delim ), /* void */ ); - wxASSERT( !fnameStr.empty() ); int importFormat; diff --git a/eeschema/files-io.cpp b/eeschema/files-io.cpp index 645bbd0b2a..b41e0ac7c8 100644 --- a/eeschema/files-io.cpp +++ b/eeschema/files-io.cpp @@ -1330,7 +1330,8 @@ bool SCH_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType, case SCH_IO_MGR::SCH_EASYEDAPRO: { // We insist on caller sending us an absolute path, if it does not, we say it's a bug. - wxCHECK_MSG( filename.IsAbsolute(), false, + // Unless we are passing the files in aproperties, in which case aFileName can be empty. + wxCHECK_MSG( aFileName.IsEmpty() || filename.IsAbsolute(), false, wxS( "Import schematic: path is not absolute!" ) ); try diff --git a/eeschema/sch_io/altium/altium_parser_sch.cpp b/eeschema/sch_io/altium/altium_parser_sch.cpp index 5c4a6faa9c..f832ce888a 100644 --- a/eeschema/sch_io/altium/altium_parser_sch.cpp +++ b/eeschema/sch_io/altium/altium_parser_sch.cpp @@ -160,6 +160,7 @@ ASCH_SYMBOL::ASCH_SYMBOL( const std::map& aProps ) { wxASSERT( ReadRecord( aProps ) == ALTIUM_SCH_RECORD::COMPONENT ); + uniqueid = ALTIUM_PROPS_UTILS::ReadString( aProps, "UNIQUEID", "" ); currentpartid = ALTIUM_PROPS_UTILS::ReadInt( aProps, "CURRENTPARTID", ALTIUM_COMPONENT_NONE ); libreference = ALTIUM_PROPS_UTILS::ReadString( aProps, "LIBREFERENCE", "" ); sourcelibraryname = ALTIUM_PROPS_UTILS::ReadString( aProps, "SOURCELIBRARYNAME", "" ); diff --git a/eeschema/sch_io/altium/altium_parser_sch.h b/eeschema/sch_io/altium/altium_parser_sch.h index ecb3411edd..92e5b70ac3 100644 --- a/eeschema/sch_io/altium/altium_parser_sch.h +++ b/eeschema/sch_io/altium/altium_parser_sch.h @@ -151,6 +151,7 @@ struct ASCH_SYMBOL { int currentpartid; int m_indexInSheet; + wxString uniqueid; wxString libreference; wxString sourcelibraryname; wxString componentdescription; diff --git a/eeschema/sch_io/altium/sch_io_altium.cpp b/eeschema/sch_io/altium/sch_io_altium.cpp index dced71d852..5ae7463e6b 100644 --- a/eeschema/sch_io/altium/sch_io_altium.cpp +++ b/eeschema/sch_io/altium/sch_io_altium.cpp @@ -376,11 +376,80 @@ wxFileName SCH_IO_ALTIUM::getLibFileName() } +SCH_SHEET* SCH_IO_ALTIUM::LoadSchematicProject( SCHEMATIC* aSchematic, const std::map* aProperties ) +{ + int x = 1; + int y = 1; + int page = 2; // Start at page 2 since page 1 is the root sheet. + + std::map sheets; + wxFileName project( aProperties->at( "project_file" ) ); + + for( auto& [ key, filestring] : *aProperties ) + { + if( !key.starts_with( "sch" ) ) + continue; + + VECTOR2I pos = VECTOR2I( x * schIUScale.MilsToIU( 1000 ), + y * schIUScale.MilsToIU( 1000 ) ); + + wxFileName fn( filestring ); + wxFileName kicad_fn( fn ); + std::unique_ptr sheet = std::make_unique( m_rootSheet, pos ); + SCH_SCREEN* screen = new SCH_SCREEN( m_schematic ); + sheet->SetScreen( screen ); + + kicad_fn.SetExt( FILEEXT::KiCadSchematicFileExtension ); + kicad_fn.SetPath( aSchematic->Prj().GetProjectPath() ); + sheet->SetFileName( fn.GetFullPath() ); + screen->SetFileName( sheet->GetFileName() ); + + wxCHECK2( sheet && screen, continue ); + + wxString pageNo = wxString::Format( wxT( "%d" ), page++ ); + + m_sheetPath.push_back( sheet.get() ); + ParseAltiumSch( fn.GetFullPath() ); + + m_sheetPath.SetPageNumber( pageNo ); + m_sheetPath.pop_back(); + + SCH_SCREEN* currentScreen = m_rootSheet->GetScreen(); + + wxCHECK2( currentScreen, continue ); + + sheet->SetParent( m_sheetPath.Last() ); + SCH_SHEET* sheetPtr = sheet.release(); + currentScreen->Append( sheetPtr ); + sheets[fn.GetFullPath()] = sheetPtr; + + x += 2; + + if( x > 10 ) // Start next row of sheets. + { + x = 1; + y += 2; + } + } + + // If any of the sheets in the project is a subsheet, then remove the sheet from the root sheet. + // The root sheet only contains sheets that are not referenced by any other sheet in a + // pseudo-flat structure. + for( auto& [ filestring, sheet ] : sheets ) + { + if( m_rootSheet->CountSheets( filestring ) > 1 ) + getCurrentScreen()->Remove( sheet ); + } + + return m_rootSheet; +} + + SCH_SHEET* SCH_IO_ALTIUM::LoadSchematicFile( const wxString& aFileName, SCHEMATIC* aSchematic, SCH_SHEET* aAppendToMe, const std::map* aProperties ) { - wxCHECK( !aFileName.IsEmpty() && aSchematic, nullptr ); + wxCHECK( ( !aFileName.IsEmpty() || !aProperties->empty() ) && aSchematic, nullptr ); wxFileName fileName( aFileName ); fileName.SetExt( FILEEXT::KiCadSchematicFileExtension ); @@ -419,6 +488,18 @@ SCH_SHEET* SCH_IO_ALTIUM::LoadSchematicFile( const wxString& aFileName, SCHEMATI const_cast( m_rootSheet->m_Uuid ) = screen->GetUuid(); } + m_sheetPath.push_back( m_rootSheet ); + + SCH_SCREEN* rootScreen = m_rootSheet->GetScreen(); + wxCHECK( rootScreen, nullptr ); + + SCH_SHEET_INSTANCE sheetInstance; + + sheetInstance.m_Path = m_sheetPath.Path(); + sheetInstance.m_PageNumber = wxT( "#" ); + + rootScreen->m_sheetInstances.emplace_back( sheetInstance ); + SYMBOL_LIB_TABLE* libTable = PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() ); wxCHECK_MSG( libTable, nullptr, "Could not load symbol lib table." ); @@ -452,19 +533,10 @@ SCH_SHEET* SCH_IO_ALTIUM::LoadSchematicFile( const wxString& aFileName, SCHEMATI PROJECT_SCH::SchSymbolLibTable( &m_schematic->Prj() ); } - m_sheetPath.push_back( m_rootSheet ); - - SCH_SCREEN* rootScreen = m_rootSheet->GetScreen(); - wxCHECK( rootScreen, nullptr ); - - SCH_SHEET_INSTANCE sheetInstance; - - sheetInstance.m_Path = m_sheetPath.Path(); - sheetInstance.m_PageNumber = wxT( "#" ); - - rootScreen->m_sheetInstances.emplace_back( sheetInstance ); - - ParseAltiumSch( aFileName ); + if( aFileName.empty() ) + LoadSchematicProject( aSchematic, aProperties ); + else + ParseAltiumSch( aFileName ); if( m_reporter ) { @@ -1447,6 +1519,7 @@ void SCH_IO_ALTIUM::ParseComponent( int aIndex, const std::map( symbol->m_Uuid ) = KIID( elem.uniqueid ); symbol->SetPosition( elem.location + m_sheetOffset ); for( SCH_FIELD& field : symbol->GetFields() ) @@ -1454,6 +1527,15 @@ void SCH_IO_ALTIUM::ParseComponent( int aIndex, const std::mapSetOrientation( elem.orientation ); + + // If Altium has defined a library from which we have the part, + // use this as the designated source library. + if( !elem.sourcelibraryname.IsEmpty() ) + { + wxFileName fn( elem.sourcelibraryname ); + libId.SetLibNickname( fn.GetName() ); + } + symbol->SetLibId( libId ); symbol->SetUnit( std::max( 0, elem.currentpartid ) ); symbol->GetField( FIELD_T::DESCRIPTION )->SetText( elem.componentdescription ); diff --git a/eeschema/sch_io/altium/sch_io_altium.h b/eeschema/sch_io/altium/sch_io_altium.h index b62385274d..1e431d7681 100644 --- a/eeschema/sch_io/altium/sch_io_altium.h +++ b/eeschema/sch_io/altium/sch_io_altium.h @@ -96,6 +96,9 @@ public: SCH_SHEET* aAppendToMe = nullptr, const std::map* aProperties = nullptr ) override; + SCH_SHEET* LoadSchematicProject( SCHEMATIC* aSchematic, + const std::map* aProperties ); + // unimplemented functions. Will trigger a not_implemented IO error. //void SaveLibrary( const wxString& aFileName, const PROPERTIES* aProperties = NULL ) override; diff --git a/eeschema/sch_sheet.cpp b/eeschema/sch_sheet.cpp index 0402fd4062..b6642be8e7 100644 --- a/eeschema/sch_sheet.cpp +++ b/eeschema/sch_sheet.cpp @@ -814,6 +814,23 @@ bool SCH_SHEET::LocatePathOfScreen( SCH_SCREEN* aScreen, SCH_SHEET_PATH* aList ) } +int SCH_SHEET::CountSheets( const wxString& aFilename ) const +{ + int count = 0; + + if( m_screen ) + { + if( m_screen->GetFileName().Cmp( aFilename ) == 0 ) + count++; + + for( SCH_ITEM* aItem : m_screen->Items().OfType( SCH_SHEET_T ) ) + count += static_cast( aItem )->CountSheets( aFilename ); + } + + return count; +} + + int SCH_SHEET::CountSheets() const { int count = 1; //1 = this!! diff --git a/eeschema/sch_sheet.h b/eeschema/sch_sheet.h index b8b556bf71..83f5c0cedb 100644 --- a/eeschema/sch_sheet.h +++ b/eeschema/sch_sheet.h @@ -305,6 +305,14 @@ public: */ int CountSheets() const; + /** + * Count the number of sheets that refer to a specific file + * including all of the subsheets. + * @param aFileName The filename to search for. + * @return the full count of sheets+subsheets that refer to aFileName + */ + int CountSheets( const wxString& aFileName ) const; + /** * Return the filename corresponding to this sheet. * diff --git a/include/mail_type.h b/include/mail_type.h index 40a2e797ef..69201ed9fa 100644 --- a/include/mail_type.h +++ b/include/mail_type.h @@ -51,6 +51,7 @@ enum MAIL_T MAIL_PCB_GET_NETLIST, // Fetch a netlist from PCB layout MAIL_PCB_UPDATE_LINKS, // Update the schematic symbol paths in the PCB's footprints MAIL_SCH_REFRESH, // Tell the schematic editor to refresh the display. + MAIL_ADD_LOCAL_LIB, // Add a local library to the project library table MAIL_LIB_EDIT, MAIL_FP_EDIT, MAIL_RELOAD_LIB, // Reload Library List if one was added diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h index 68c2e97185..be8f7d457f 100644 --- a/include/wildcards_and_files_ext.h +++ b/include/wildcards_and_files_ext.h @@ -247,6 +247,7 @@ public: static wxString CsvFileWildcard(); static wxString PcbFileWildcard(); static wxString CadstarArchiveFilesWildcard(); + static wxString AltiumProjectFilesWildcard(); static wxString EagleFilesWildcard(); static wxString EasyEdaArchiveWildcard(); static wxString EasyEdaProFileWildcard(); diff --git a/kicad/import_proj.cpp b/kicad/import_proj.cpp index 842b478859..1abb06e5f8 100644 --- a/kicad/import_proj.cpp +++ b/kicad/import_proj.cpp @@ -24,7 +24,9 @@ #include #include +#include #include +#include #include #include @@ -32,14 +34,21 @@ #include #include +#include +#include + #include #include +#include +#include #include #include #include #include +#include + IMPORT_PROJ_HELPER::IMPORT_PROJ_HELPER( KICAD_MANAGER_FRAME* aFrame, const std::vector& aSchFileExtensions, @@ -146,16 +155,22 @@ void IMPORT_PROJ_HELPER::ImportIndividualFile( KICAD_T aFT, int aImportedFileTyp if( appImportFile.empty() ) return; - KIWAY_PLAYER* frame = m_frame->Kiway().Player( frame_type, true ); + doImport( appImportFile, frame_type, aImportedFileType ); +} + + +void IMPORT_PROJ_HELPER::doImport( const wxString& aFile, FRAME_T aFrameType, int aImportedFileType ) +{ + KIWAY_PLAYER* frame = m_frame->Kiway().Player( aFrameType, true ); std::stringstream ss; - ss << aImportedFileType << '\n' << TO_UTF8( appImportFile ); + ss << aImportedFileType << '\n' << TO_UTF8( aFile ); for( const auto& [key, value] : m_properties ) ss << '\n' << key << '\n' << value.wx_str(); std::string packet = ss.str(); - frame->Kiway().ExpressMail( frame_type, MAIL_IMPORT_FILE, packet, m_frame ); + frame->Kiway().ExpressMail( aFrameType, MAIL_IMPORT_FILE, packet, m_frame ); if( !frame->IsShownOnScreen() ) frame->Show( true ); @@ -202,6 +217,96 @@ void IMPORT_PROJ_HELPER::EasyEDAProProjectHandler() } +void IMPORT_PROJ_HELPER::addLocalLibraries( const std::set& aNames, FRAME_T aFrameType ) +{ + KIWAY_PLAYER* frame = m_frame->Kiway().Player( aFrameType, true ); + + std::stringstream ss; + + for( const wxString& name : aNames ) + { + wxFileName fname( name ); + fname.MakeAbsolute( m_InputFile.GetPath() ); + ss << TO_UTF8( fname.GetFullPath() ) << '\n'; + } + + std::string packet = ss.str(); + frame->Kiway().ExpressMail( aFrameType, MAIL_ADD_LOCAL_LIB, packet, m_frame ); +} + + +void IMPORT_PROJ_HELPER::AltiumProjectHandler() +{ + wxFFileInputStream stream( m_InputFile.GetFullPath() ); + + if( !stream.IsOk() ) + return; + + wxFileConfig config( stream ); + wxString groupname; + long groupid; + + std::set sch_file; + std::set pcb_file; + std::set sch_libs; + std::set pcb_libs; + + for( bool more = config.GetFirstGroup( groupname, groupid ); more; + more = config.GetNextGroup( groupname, groupid ) ) + { + if( !groupname.StartsWith( wxS( "Document" ) ) ) + continue; + + wxString number = groupname.Mid( 8 ); + long docNumber; + + if( !number.ToLong( &docNumber ) ) + continue; + + wxString path = config.Read( groupname + wxS( "/DocumentPath" ), wxEmptyString ); + + if( path.empty() ) + continue; + + wxFileName fname( path ); + + if( !fname.IsAbsolute() ) + fname.MakeAbsolute( m_InputFile.GetPath() ); + + if( !fname.GetExt().CmpNoCase( "PCBDOC" ) ) + pcb_file.insert( fname.GetFullPath() ); + + if( !fname.GetExt().CmpNoCase( "SCHDOC" ) ) + sch_file.insert( fname.GetFullPath() ); + + if( !fname.GetExt().CmpNoCase( "PCBLIB" ) ) + pcb_libs.insert( fname.GetFullPath() ); + + if( !fname.GetExt().CmpNoCase( "SCHLIB" ) ) + sch_libs.insert( fname.GetFullPath() ); + } + + addLocalLibraries( sch_libs, FRAME_SCH ); + addLocalLibraries( pcb_libs, FRAME_PCB_EDITOR ); + + m_properties["project_file"] = m_InputFile.GetFullPath(); + + int ii = 0; + + for( auto& path : sch_file ) + { + std::string key = "sch" + std::to_string( ii++ ); + m_properties[key] = path.ToStdString(); + } + + if( !sch_file.empty() ) + doImport( "", FRAME_SCH, SCH_IO_MGR::SCH_ALTIUM ); + + if( !pcb_file.empty() ) + doImport( *pcb_file.begin(), FRAME_PCB_EDITOR, PCB_IO_MGR::ALTIUM_DESIGNER ); +} + + void IMPORT_PROJ_HELPER::ImportFiles( int aImportedSchFileType, int aImportedPcbFileType ) { m_properties.clear(); @@ -211,6 +316,12 @@ void IMPORT_PROJ_HELPER::ImportFiles( int aImportedSchFileType, int aImportedPcb { EasyEDAProProjectHandler(); } + else if( aImportedSchFileType == SCH_IO_MGR::SCH_ALTIUM + || aImportedPcbFileType == PCB_IO_MGR::ALTIUM_DESIGNER ) + { + AltiumProjectHandler(); + return; + } ImportIndividualFile( SCHEMATIC_T, aImportedSchFileType ); ImportIndividualFile( PCB_T, aImportedPcbFileType ); diff --git a/kicad/import_proj.h b/kicad/import_proj.h index 48551a2aa8..cf626e609f 100644 --- a/kicad/import_proj.h +++ b/kicad/import_proj.h @@ -23,8 +23,10 @@ #include #include #include +#include #include +#include class KICAD_MANAGER_FRAME; @@ -69,7 +71,13 @@ private: void OutputCopyError( const wxFileName& aSrc, const wxFileName& aFileCopy ); void ImportIndividualFile( KICAD_T aKicad_T, int aImportedFileType ); + void doImport( const wxString& aFile, FRAME_T aFrameType, int aImportedFileType ); + + void addLocalLibraries( const std::set& aLibName, FRAME_T aFrameType ); + void EasyEDAProProjectHandler(); + + void AltiumProjectHandler(); }; #endif \ No newline at end of file diff --git a/kicad/import_project.cpp b/kicad/import_project.cpp index 22b0254538..f9b8e8e5b7 100644 --- a/kicad/import_project.cpp +++ b/kicad/import_project.cpp @@ -141,6 +141,14 @@ void KICAD_MANAGER_FRAME::ImportNonKiCadProject( const wxString& aWindowTitle, } +void KICAD_MANAGER_FRAME::OnImportAltiumProjectFiles( wxCommandEvent& event ) +{ + ImportNonKiCadProject( _( "Import Altium Project Files" ), + FILEEXT::AltiumProjectFilesWildcard(), { "SchDoc" }, { "PcbDoc" }, + SCH_IO_MGR::SCH_ALTIUM, PCB_IO_MGR::ALTIUM_DESIGNER ); +} + + void KICAD_MANAGER_FRAME::OnImportCadstarArchiveFiles( wxCommandEvent& event ) { ImportNonKiCadProject( _( "Import CADSTAR Archive Project Files" ), diff --git a/kicad/kicad_id.h b/kicad/kicad_id.h index 86d8aa4139..a89f578ee0 100644 --- a/kicad/kicad_id.h +++ b/kicad/kicad_id.h @@ -72,6 +72,7 @@ enum id_kicad_frm { ID_IMPORT_EAGLE_PROJECT, ID_IMPORT_EASYEDA_PROJECT, ID_IMPORT_EASYEDAPRO_PROJECT, + ID_IMPORT_ALTIUM_PROJECT, ID_GIT_INITIALIZE_PROJECT, // Initialize a new git repository in an existing project ID_GIT_CLONE_PROJECT, // Clone a project from a remote repository diff --git a/kicad/kicad_manager_frame.cpp b/kicad/kicad_manager_frame.cpp index c5b24309d7..b09b7143b6 100644 --- a/kicad/kicad_manager_frame.cpp +++ b/kicad/kicad_manager_frame.cpp @@ -107,6 +107,7 @@ BEGIN_EVENT_TABLE( KICAD_MANAGER_FRAME, EDA_BASE_FRAME ) EVT_MENU( ID_IMPORT_EAGLE_PROJECT, KICAD_MANAGER_FRAME::OnImportEagleFiles ) EVT_MENU( ID_IMPORT_EASYEDA_PROJECT, KICAD_MANAGER_FRAME::OnImportEasyEdaFiles ) EVT_MENU( ID_IMPORT_EASYEDAPRO_PROJECT, KICAD_MANAGER_FRAME::OnImportEasyEdaProFiles ) + EVT_MENU( ID_IMPORT_ALTIUM_PROJECT, KICAD_MANAGER_FRAME::OnImportAltiumProjectFiles ) // Range menu events EVT_MENU_RANGE( ID_LANGUAGE_CHOICE, ID_LANGUAGE_CHOICE_END, diff --git a/kicad/kicad_manager_frame.h b/kicad/kicad_manager_frame.h index 83f106cc1c..c14925b5bf 100644 --- a/kicad/kicad_manager_frame.h +++ b/kicad/kicad_manager_frame.h @@ -101,6 +101,11 @@ public: const std::vector& aPcbFileExtensions, int aSchFileType, int aPcbFileType ); + /** + * Open dialog to import Altium project files. + */ + void OnImportAltiumProjectFiles( wxCommandEvent& event ); + /** * Open dialog to import CADSTAR Schematic and PCB Archive files. */ diff --git a/kicad/menubar.cpp b/kicad/menubar.cpp index 62d19e6ad7..f68c2b61d9 100644 --- a/kicad/menubar.cpp +++ b/kicad/menubar.cpp @@ -112,6 +112,10 @@ void KICAD_MANAGER_FRAME::doReCreateMenuBar() importMenu->SetTitle( _( "Import Non-KiCad Project..." ) ); importMenu->SetIcon( BITMAPS::import_project ); + importMenu->Add( _( "Altium Project..." ), + _( "Import Altium Schematic and PCB (*.PrjPcb)" ), + ID_IMPORT_ALTIUM_PROJECT, + BITMAPS::import_project ); importMenu->Add( _( "CADSTAR Project..." ), _( "Import CADSTAR Archive Schematic and PCB (*.csa, *.cpa)" ), ID_IMPORT_CADSTAR_ARCHIVE_PROJECT, diff --git a/pcbnew/files.cpp b/pcbnew/files.cpp index 5c2662970f..2f51c96524 100644 --- a/pcbnew/files.cpp +++ b/pcbnew/files.cpp @@ -1275,6 +1275,14 @@ bool PCB_EDIT_FRAME::importFile( const wxString& aFileName, int aFileType, case PCB_IO_MGR::EASYEDAPRO: return OpenProjectFiles( std::vector( 1, aFileName ), KICTL_NONKICAD_ONLY | KICTL_IMPORT_LIB ); + break; + + case PCB_IO_MGR::ALTIUM_DESIGNER: + case PCB_IO_MGR::ALTIUM_CIRCUIT_MAKER: + case PCB_IO_MGR::ALTIUM_CIRCUIT_STUDIO: + case PCB_IO_MGR::SOLIDWORKS_PCB: + return OpenProjectFiles( std::vector( 1, aFileName ), + KICTL_NONKICAD_ONLY ); default: break; } diff --git a/pcbnew/pcb_io/altium/altium_parser_pcb.cpp b/pcbnew/pcb_io/altium/altium_parser_pcb.cpp index 29f035669b..d40a233f78 100644 --- a/pcbnew/pcb_io/altium/altium_parser_pcb.cpp +++ b/pcbnew/pcb_io/altium/altium_parser_pcb.cpp @@ -362,6 +362,13 @@ ACOMPONENT6::ACOMPONENT6( ALTIUM_BINARY_PARSER& aReader ) commenton = ALTIUM_PROPS_UTILS::ReadBool( props, wxT( "COMMENTON" ), false ); sourcedesignator = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCEDESIGNATOR" ), wxT( "" ) ); + sourceUniqueID = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCEUNIQUEID" ), wxT( "" ) ); + + // Remove leading backslash from sourceUniqueID to match schematic component unique IDs + if( sourceUniqueID.starts_with( wxT( "\\" ) ) ) + sourceUniqueID = sourceUniqueID.Mid( 1 ); + + sourceHierachicalPath = ALTIUM_PROPS_UTILS::ReadString( props, wxT( "SOURCEHIERARCHICALPATH" ), wxT( "" ) ); sourcefootprintlibrary = ALTIUM_PROPS_UTILS::ReadUnicodeString( props, wxT( "SOURCEFOOTPRINTLIBRARY" ), wxT( "" ) ); pattern = ALTIUM_PROPS_UTILS::ReadUnicodeString( props, wxT( "PATTERN" ), wxT( "" ) ); diff --git a/pcbnew/pcb_io/altium/altium_parser_pcb.h b/pcbnew/pcb_io/altium/altium_parser_pcb.h index dfd7620554..1d21f39396 100644 --- a/pcbnew/pcb_io/altium/altium_parser_pcb.h +++ b/pcbnew/pcb_io/altium/altium_parser_pcb.h @@ -409,6 +409,8 @@ struct ACOMPONENT6 bool locked; bool nameon; bool commenton; + wxString sourceUniqueID; + wxString sourceHierachicalPath; wxString sourcedesignator; wxString sourcefootprintlibrary; wxString pattern; diff --git a/pcbnew/pcb_io/altium/altium_pcb.cpp b/pcbnew/pcb_io/altium/altium_pcb.cpp index 1af55e9e73..9728c3ec9f 100644 --- a/pcbnew/pcb_io/altium/altium_pcb.cpp +++ b/pcbnew/pcb_io/altium/altium_pcb.cpp @@ -1329,6 +1329,16 @@ void ALTIUM_PCB::ParseComponents6Data( const ALTIUM_PCB_COMPOUND_FILE& aAltiumPc footprint->SetReference( reference ); + KIID id( elem.sourceUniqueID ); + KIID pathid( elem.sourceHierachicalPath ); + KIID_PATH path; + path.push_back( pathid ); + path.push_back( id ); + + footprint->SetPath( path ); + footprint->SetSheetname( elem.sourceHierachicalPath ); + footprint->SetSheetfile( elem.sourceHierachicalPath + wxT( ".kicad_sch" )); + footprint->SetLocked( elem.locked ); footprint->Reference().SetVisible( elem.nameon ); footprint->Value().SetVisible( elem.commenton ); diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_designer.cpp b/pcbnew/pcb_io/altium/pcb_io_altium_designer.cpp index bcb5f23f26..8d8960a4f6 100644 --- a/pcbnew/pcb_io/altium/pcb_io_altium_designer.cpp +++ b/pcbnew/pcb_io/altium/pcb_io_altium_designer.cpp @@ -341,3 +341,14 @@ FOOTPRINT* PCB_IO_ALTIUM_DESIGNER::FootprintLoad( const wxString& aLibraryPath, aFootprintName, aLibraryPath ) ); } + + +std::vector PCB_IO_ALTIUM_DESIGNER::GetImportedCachedLibraryFootprints() +{ + std::vector footprints; + + for( FOOTPRINT* fp : m_board->Footprints() ) + footprints.push_back( fp ); + + return footprints; +} \ No newline at end of file diff --git a/pcbnew/pcb_io/altium/pcb_io_altium_designer.h b/pcbnew/pcb_io/altium/pcb_io_altium_designer.h index 9e3a905df3..fa218917ec 100644 --- a/pcbnew/pcb_io/altium/pcb_io_altium_designer.h +++ b/pcbnew/pcb_io/altium/pcb_io_altium_designer.h @@ -64,6 +64,8 @@ public: bool aKeepUUID = false, const std::map* aProperties = nullptr ) override; + std::vector GetImportedCachedLibraryFootprints() override; + //bool FootprintExists( const wxString& aLibraryPath, const wxString& aFootprintName, const PROPERTIES* aProperties = nullptr ); bool IsLibraryWritable( const wxString& aLibraryPath ) override { return false; }