/** * @file librairi.cpp * @brief Manage module (footprint) libraries. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // temporarily, for LoadMODULE() #define BACKUP_EXT wxT( "bak" ) #define FILETMP_EXT wxT( "$$$" ) #define EXPORT_IMPORT_LASTPATH_KEY wxT( "import_last_path" ) const wxString ModExportFileExtension( wxT( "emp" ) ); static const wxString ModExportFileWildcard( _( "KiCad foot print export files (*.emp)|*.emp" ) ); static const wxString ModImportFileWildcard( _( "GPcb foot print files (*)|*" ) ); MODULE* FOOTPRINT_EDIT_FRAME::Import_Module() { // use the clipboard for this in the future? wxString lastOpenedPathForLoading; wxConfig* config = wxGetApp().GetSettings(); if( config ) config->Read( EXPORT_IMPORT_LASTPATH_KEY, &lastOpenedPathForLoading ); wxString importWildCard = ModExportFileWildcard + wxT("|") + ModImportFileWildcard; wxFileDialog dlg( this, _( "Import Footprint Module" ), lastOpenedPathForLoading, wxEmptyString, importWildCard, wxFD_OPEN | wxFD_FILE_MUST_EXIST ); if( dlg.ShowModal() == wxID_CANCEL ) return NULL; FILE* file = wxFopen( dlg.GetPath(), wxT( "rt" ) ); if( file == NULL ) { wxString msg; msg.Printf( _( "File <%s> not found" ), GetChars( dlg.GetPath() ) ); DisplayError( this, msg ); return NULL; } if( config ) // Save file path { lastOpenedPathForLoading = wxPathOnly( dlg.GetPath() ); config->Write( EXPORT_IMPORT_LASTPATH_KEY, lastOpenedPathForLoading ); } LOCALE_IO toggle; FILE_LINE_READER fileReader( file, dlg.GetPath() ); FILTER_READER reader( fileReader ); // Read header and test file type reader.ReadLine(); char* line = reader.Line(); bool footprint_Is_GPCB_Format = false; if( strnicmp( line, FOOTPRINT_LIBRARY_HEADER, FOOTPRINT_LIBRARY_HEADER_CNT ) != 0 ) { if( strnicmp( line, "Element", 7 ) == 0 ) { footprint_Is_GPCB_Format = true; } else { DisplayError( this, _( "Not a module file" ) ); return NULL; } } // Read file: Search the description starting line (skip lib header) if( !footprint_Is_GPCB_Format ) { while( reader.ReadLine() ) { if( strnicmp( line, "$MODULE", 7 ) == 0 ) break; } } MODULE* module; if( footprint_Is_GPCB_Format ) { // @todo GEDA plugin module = new MODULE( GetBoard() ); module->Read_GPCB_Descr( dlg.GetPath() ); } else { try { PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); LEGACY_PLUGIN* lp = (LEGACY_PLUGIN*)(PLUGIN*)pi; lp->SetReader( &reader ); module = lp->LoadMODULE(); } catch( IO_ERROR ioe ) { DisplayError( this, ioe.errorText ); return NULL; } } // Insert footprint in list GetBoard()->Add( module ); // Display info : module->DisplayInfo( this ); PlaceModule( module, NULL ); GetBoard()->m_Status_Pcb = 0; GetBoard()->BuildListOfNets(); return module; } void FOOTPRINT_EDIT_FRAME::Export_Module( MODULE* aModule, bool aCreateSysLib ) { wxFileName fn; wxString msg, path, title, wildcard; wxConfig* config = wxGetApp().GetSettings(); if( aModule == NULL ) return; fn.SetName( aModule->m_LibRef ); fn.SetExt( aCreateSysLib ? FootprintLibFileExtension : ModExportFileExtension ); if( aCreateSysLib ) path = wxGetApp().ReturnLastVisitedLibraryPath(); else if( config ) config->Read( EXPORT_IMPORT_LASTPATH_KEY, &path ); title = aCreateSysLib ? _( "Create New Library" ) : _( "Export Module" ); wildcard = aCreateSysLib ? FootprintLibFileWildcard : ModExportFileWildcard; fn.SetPath( path ); wxFileDialog dlg( this, msg, fn.GetPath(), fn.GetFullName(), wxGetTranslation( wildcard ), wxFD_SAVE | wxFD_OVERWRITE_PROMPT ); if( dlg.ShowModal() == wxID_CANCEL ) return; fn = dlg.GetPath(); wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); if( !aCreateSysLib && config ) // Save file path { config->Write( EXPORT_IMPORT_LASTPATH_KEY, fn.GetPath() ); } wxString libPath = fn.GetFullPath(); try { // @todo : hard code this as IO_MGR::KICAD plugin, what would be the reason to "export" // any other single footprint type, with clipboard support coming? // Use IO_MGR::LEGACY for now, until the IO_MGR::KICAD plugin is ready. PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); try { // try to delete the library whether it exists or not, quietly. pi->FootprintLibDelete( libPath ); } catch( IO_ERROR ioe ) { // Ignore this, it will often happen and is not an error because // the library may not exist. If library was in a read only directory, // it will still exist as we get to the FootprintLibCreate() below. } pi->FootprintLibCreate( libPath ); pi->FootprintSave( libPath, aModule ); } catch( IO_ERROR ioe ) { DisplayError( this, ioe.errorText ); return; } msg.Printf( _( "Module exported in file <%s>" ), libPath.GetData() ); DisplayInfoMessage( this, msg ); } void FOOTPRINT_EDIT_FRAME::Delete_Module_In_Library( const wxString& aLibName ) { wxString footprintName = Select_1_Module_From_List( this, aLibName, wxEmptyString, wxEmptyString ); if( footprintName == wxEmptyString ) return; // Confirmation wxString msg = wxString::Format( _( "Ok to delete module '%s' in library '%s'" ), footprintName.GetData(), aLibName.GetData() ); if( !IsOK( this, msg ) ) return; try { PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); pi->FootprintDelete( aLibName, footprintName ); } catch( IO_ERROR ioe ) { DisplayError( NULL, ioe.errorText ); return; } msg.Printf( _( "Component '%s' deleted from library '%s'" ), footprintName.GetData(), aLibName.GetData() ); SetStatusText( msg ); } /* Save modules in a library: * param aNewModulesOnly: * true : save modules not already existing in this lib * false: save all modules */ void PCB_EDIT_FRAME::ArchiveModulesOnBoard( const wxString& aLibName, bool aNewModulesOnly ) { wxString fileName = aLibName; wxString path; if( GetBoard()->m_Modules == NULL ) { DisplayInfoMessage( this, _( "No modules to archive!" ) ); return; } path = wxGetApp().ReturnLastVisitedLibraryPath(); if( !aLibName ) { wxFileDialog dlg( this, _( "Library" ), path, wxEmptyString, wxGetTranslation( FootprintLibFileWildcard ), wxFD_SAVE ); if( dlg.ShowModal() == wxID_CANCEL ) return; fileName = dlg.GetPath(); } wxFileName fn( fileName ); wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() ); bool lib_exists = wxFileExists( fileName ); if( !aNewModulesOnly && lib_exists ) { wxString msg; msg.Printf( _( "Library %s exists, OK to replace ?" ), GetChars( fileName ) ); if( !IsOK( this, msg ) ) return; } m_canvas->SetAbortRequest( false ); try { PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); // Delete old library if we're replacing it entirely. if( lib_exists && !aNewModulesOnly ) { pi->FootprintLibDelete( fileName ); lib_exists = false; } if( !lib_exists ) { pi->FootprintLibCreate( fileName ); } if( !aNewModulesOnly ) { for( MODULE* m = GetBoard()->m_Modules; m; m = m->Next() ) { pi->FootprintSave( fileName, m ); } } else { for( MODULE* m = GetBoard()->m_Modules; m; m = m->Next() ) { if( !Save_Module_In_Library( fileName, m, false, false ) ) break; // Check for request to stop backup (ESCAPE key actuated) if( m_canvas->GetAbortRequest() ) break; } } } catch( IO_ERROR ioe ) { DisplayError( this, ioe.errorText ); return; } } bool PCB_BASE_FRAME::Save_Module_In_Library( const wxString& aLibName, MODULE* aModule, bool aOverwrite, bool aDisplayDialog ) { if( aModule == NULL ) return false; aModule->DisplayInfo( this ); if( !wxFileExists( aLibName ) ) { wxString msg = wxString::Format( _( "Library <%s> not found." ), aLibName.GetData() ); DisplayError( this, msg ); return false; } if( !IsWritable( aLibName ) ) return false; // Ask what to use as the footprint name in the library wxString footprintName = aModule->GetLibRef(); if( aDisplayDialog ) { wxTextEntryDialog dlg( this, _( "Name:" ), _( "Save Module" ), footprintName ); if( dlg.ShowModal() != wxID_OK ) return false; // canceled by user footprintName = dlg.GetValue(); footprintName.Trim( true ); footprintName.Trim( false ); if( footprintName.IsEmpty() ) return false; aModule->SetLibRef( footprintName ); } // Ensure this footprint has a libname if( footprintName.IsEmpty() ) { footprintName = wxT("noname"); aModule->SetLibRef( footprintName ); } MODULE* module_exists = NULL; try { PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); module_exists = pi->FootprintLoad( aLibName, footprintName ); if( module_exists ) { delete module_exists; // an existing footprint is found in current lib if( aDisplayDialog ) { wxString msg = wxString::Format( _( "Footprint '%s' already exists in library '%s'" ), footprintName.GetData(), aLibName.GetData() ); SetStatusText( msg ); } if( !aOverwrite ) { // Do not save the given footprint: an old one exists return true; } } // this always overwrites any existing footprint pi->FootprintSave( aLibName, aModule ); } catch( IO_ERROR ioe ) { DisplayError( this, ioe.errorText ); return false; } if( aDisplayDialog ) { wxString fmt = module_exists ? _( "Component [%s] replaced in <%s>" ) : _( "Component [%s] added in <%s>" ); wxString msg = wxString::Format( fmt, footprintName.GetData(), aLibName.GetData() ); SetStatusText( msg ); } return true; } MODULE* PCB_BASE_FRAME::Create_1_Module( const wxString& aModuleName ) { MODULE* Module; wxString moduleName; wxPoint newpos; moduleName = aModuleName; // Ask for the new module reference if( moduleName.IsEmpty() ) { wxTextEntryDialog dlg( this, _( "Module Reference:" ), _( "Module Creation" ), moduleName ); if( dlg.ShowModal() != wxID_OK ) return NULL; //Aborted by user moduleName = dlg.GetValue(); } moduleName.Trim( true ); moduleName.Trim( false ); if( moduleName.IsEmpty( ) ) { DisplayInfoMessage( this, _( "No reference, aborted" ) ); return NULL; } // Creates the new module and add it to the head of the linked list of modules Module = new MODULE( GetBoard() ); GetBoard()->Add( Module ); // Update parameters: position, timestamp ... newpos = GetScreen()->GetCrossHairPosition(); Module->SetPosition( newpos ); Module->SetLastEditTime(); // Update its name in lib Module->m_LibRef = moduleName; // Update reference: Module->m_Reference->m_Text = moduleName; Module->m_Reference->SetThickness( GetDesignSettings().m_ModuleTextWidth ); Module->m_Reference->SetSize( GetDesignSettings().m_ModuleTextSize ); // Set the value field to a default value Module->m_Value->m_Text = wxT( "VAL**" ); Module->m_Value->SetThickness( GetDesignSettings().m_ModuleTextWidth ); Module->m_Value->SetSize( GetDesignSettings().m_ModuleTextSize ); Module->SetPosition( wxPoint( 0, 0 ) ); Module->DisplayInfo( this ); return Module; } void FOOTPRINT_EDIT_FRAME::Select_Active_Library() { wxString msg; if( g_LibraryNames.GetCount() == 0 ) return; EDA_LIST_DIALOG dlg( this, _( "Select Active Library:" ), g_LibraryNames, m_CurrentLib ); if( dlg.ShowModal() != wxID_OK ) return; wxFileName fileName = wxFileName( wxEmptyString, dlg.GetTextSelection(), FootprintLibFileExtension ); fileName = wxGetApp().FindLibraryPath( fileName ); if( fileName.IsOk() && fileName.FileExists() ) { m_CurrentLib = dlg.GetTextSelection(); } else { msg.Printf( _( "The footprint library <%s> could not be found in any of the search paths." ), GetChars( dlg.GetTextSelection() ) ); DisplayError( this, msg ); m_CurrentLib.Empty(); } UpdateTitle(); } int FOOTPRINT_EDIT_FRAME::CreateLibrary( const wxString& aLibName ) { wxFileName fileName = aLibName; if( fileName.FileExists() ) { wxString msg = wxString::Format( _( "Library <%s> already exists." ), aLibName.GetData() ); DisplayError( this, msg ); return 0; } if( !IsWritable( fileName ) ) return 0; try { PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) ); pi->FootprintLibCreate( aLibName ); } catch( IO_ERROR ioe ) { DisplayError( this, ioe.errorText ); return 0; } return 1; // remember how many times we succeeded }