/** * @file wizard_add_fplib.cpp */ /* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr * Copyright (C) 1992-2015 KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * 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, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ /** @brief this code creates a wizard to add entries in the footprint library table. * The wizard contains 3 pages: * The first is the selection of the type of libraries (plugin type): * * Kicad .pretty library (actually a folder containing .kicad_mod footprint files) * * Gihtub .pretty on line library, accessible via a internet connection * * Legacy library (old .mod format file containing footprints desc) * * Eagle xml V6 library (.lbr files) * * Geda-PCB library (actually a folder containing .fp footprint files * The second is the selection of path management: * use environment variable or absolute path. * When using an environment variable, selec it * The third is the library list selection * It allows entering entries by running a tool to select a set of libraries * The tool depend on the type of lib (files/folder/urls): * * multi files selector * * multi folder selector * * multi URL selector (via a web viewer) * The path and the plugin type comes from the selection, and a library nickname * is built from the path. */ #include #include #include #include #include #include #include // For PROJECT_VAR_NAME definition #include // For KISYSMOD definition #include #include #include // a key to store the default Kicad Github libs URL #define KICAD_FPLIBS_URL_KEY wxT( "kicad_fplib_url" ) // key to store last options of th wizard #define WIZARD_LAST_PLUGIN_KEY wxT( "wizard_plugin" ) #define WIZARD_LAST_PATHOPTION_KEY wxT( "wizard_path_option" ) // static members to store last choices during a session int WIZARD_FPLIB_TABLE::m_last_plugin_choice = 0; int WIZARD_FPLIB_TABLE::m_last_defaultpath_choice = 2; WIZARD_FPLIB_TABLE::WIZARD_FPLIB_TABLE( wxWindow* aParent, wxArrayString& aEnvVariableList ) : WIZARD_FPLIB_TABLE_BASE( aParent ) { initDlg( aEnvVariableList ); // Allows github plugin selection only when the plugin is compiled: #ifndef BUILD_GITHUB_PLUGIN m_rbFpLibFormat->Enable( GITHUB_PLUGIN, false ); if( m_rbFpLibFormat->GetSelection() == GITHUB_PLUGIN ) m_rbFpLibFormat->SetSelection( KICAD_PLUGIN ); #endif // Currently, I (JPC) do not know the best way to add/store // what is currently called env variables // So do not show tools to change them, // but do not remove the code, just in case m_buttonAddEV->Show( false ); m_buttonRemoveEV->Show( false ); #ifndef BUILD_GITHUB_PLUGIN m_buttonGithubLibList->Show( false ); #endif // Gives a minimal size to the dialog, which allows displaying any page wxSize minsize; for( unsigned ii = 0; ii < m_pages.size(); ii++ ) { wxSize size = m_pages[ii]->GetSizer()->CalcMin(); minsize.x = std::max( minsize.x, size.x ); minsize.y = std::max( minsize.y, size.y ); } SetMinSize( minsize ); SetPageSize( minsize ); GetSizer()->SetSizeHints( this ); Center(); } WIZARD_FPLIB_TABLE::~WIZARD_FPLIB_TABLE() { // Use this if you want to store kicad lib URL in pcbnew/cvpcb section config: // wxConfigBase* cfg = Kiface().KifaceSettings(); // Use this if you want to store kicad lib URL in common section config: wxConfigBase* cfg = Pgm().CommonSettings(); cfg->Write( KICAD_FPLIBS_URL_KEY, m_textCtrlGithubURL->GetValue() ); m_last_plugin_choice = m_rbFpLibFormat->GetSelection(); m_last_defaultpath_choice = m_rbPathManagement->GetSelection(); cfg->Write( WIZARD_LAST_PLUGIN_KEY, m_last_plugin_choice ); cfg->Write( WIZARD_LAST_PATHOPTION_KEY, m_last_defaultpath_choice ); } void WIZARD_FPLIB_TABLE::initDlg( wxArrayString& aEnvVariableList ) { m_currLibDescr = NULL; SetBitmap( KiBitmap( wizard_add_fplib_icon_xpm ) ); wxString msg; wxConfigBase* cfg = Pgm().CommonSettings(); cfg->Read( WIZARD_LAST_PLUGIN_KEY, &m_last_plugin_choice ); cfg->Read( WIZARD_LAST_PATHOPTION_KEY, &m_last_defaultpath_choice ); cfg->Read( KICAD_FPLIBS_URL_KEY, &msg ); if( msg.IsEmpty() ) // Give our current KiCad github URL msg = wxT( "http://github.com/KiCad" ); // Be sure there is no trailing '/' at the end of the repo name if( msg.EndsWith( wxT("/" ) ) ) msg.RemoveLast(); m_textCtrlGithubURL->SetValue( msg ); // KIGITHUB is frequently used (examples in docs, and other place) // So add it if it not yet in list, but if it is defined as env var // (note this env var is not hardcoded or existing in kicad sources) if( aEnvVariableList.Index( wxT("KIGITHUB"), false ) == wxNOT_FOUND ) { // Not yet in use in lib table, see in env. vars wxString evValue; wxGetEnv( wxT("KIGITHUB"), &evValue ); // Not yet in use in lib table, but it is defined in environment, // so add it, just in case if( ! evValue.IsEmpty() ) aEnvVariableList.Add( wxT("KIGITHUB") ); } m_rowPrjEnvVarPosition = 0; m_predefinedEnvVarCnt = aEnvVariableList.GetCount(); for( int row = 0; row < m_predefinedEnvVarCnt; row++ ) { if( GetEnvVarCount() <= row ) m_gridEnvironmentVariablesList->AppendRows(1); m_gridEnvironmentVariablesList->SetCellValue( row, 0, aEnvVariableList[row] ); if( aEnvVariableList[row] == PROJECT_VAR_NAME ) m_rowPrjEnvVarPosition = row; wxString evValue; if( wxGetEnv( aEnvVariableList[row], &evValue ) ) m_gridEnvironmentVariablesList->SetCellValue( row, 1, evValue ); // All these env var are defined outside the wizard, // and cannot be modified in this dialog m_gridEnvironmentVariablesList->SetReadOnly( row, 0, true ); m_gridEnvironmentVariablesList->SetReadOnly( row, 1, true ); } m_gridEnvironmentVariablesList->Fit(); m_buttonRemoveEV->Enable( GetEnvVarCount() > m_predefinedEnvVarCnt ); m_gridEnvironmentVariablesList->AutoSizeColumns(); m_rbFpLibFormat->SetSelection( m_last_plugin_choice ); m_rbPathManagement->SetSelection( m_last_defaultpath_choice ); wxCommandEvent event; updateFromPlugingChoice(); OnPathManagementSelection( event ); } int WIZARD_FPLIB_TABLE::HasGithubEnvVarCompatible() { // Return true if at least one env var defines a url relative to github for( int row = 0; row < GetEnvVarCount(); row++ ) { if( m_gridEnvironmentVariablesList->GetCellValue( wxGridCellCoords( row, 1 ) ).Lower().StartsWith( "http" ) ) return row; } return -1; } bool WIZARD_FPLIB_TABLE::ValidateOptions() { // Some choices can be conficting or do not work. // Warn the user when this is the case wxString msg; if( getSelectedEnvVarValue().IsEmpty() ) { // PROJECT_PATH option cannot be used with empty local path if( m_rbPathManagement->GetSelection() == PROJECT_PATH ) { msg = _("The project path is empty and this option is not valid.\n" "Looks like you are running the wizard outside a project."); wxMessageBox( msg ); return false; } else if( m_rbPathManagement->GetSelection() != ABSOLUTE_PATH ) { wxMessageBox( wxString::Format( _("The default path defined by env var \"%s\" is empty.\nCannot use it"), GetChars( getSelectedEnvVar() ) ) ); return false; } } else { if( IsGithubPlugin() ) { // Github plugin cannot be used with local path; Need absolute path or valid URL if( !getSelectedEnvVarValue().Lower().StartsWith( "http" ) ) { msg = _("Github Plugin uses a valid Internet URL starting by http.\n" "Cannot be used as URL"); wxMessageBox( msg ); return false; } } else { if( getSelectedEnvVarValue().Lower().StartsWith( "http" ) ) { msg = _("This default path looks strange.\n" "Cannot be used for a file path"); wxMessageBox( msg ); return false; } } } // Other conficts: TODO return true; } void WIZARD_FPLIB_TABLE::OnPluginSelection( wxCommandEvent& event ) { updateFromPlugingChoice(); } void WIZARD_FPLIB_TABLE::updateFromPlugingChoice() { #ifdef BUILD_GITHUB_PLUGIN m_buttonGithubLibList->Show( IsGithubPlugin() || IsKicadPlugin() ); #endif // update dialog options and widgets depending on a plugin choice // Project path has no sense for GITHUB_PLUGIN bool enablePrjPathOpt = not IsGithubPlugin(); // Project path cannot be used if unknown if( m_gridEnvironmentVariablesList->GetCellValue( wxGridCellCoords( m_rowPrjEnvVarPosition, 1 ) ).IsEmpty() ) enablePrjPathOpt = false; m_rbPathManagement->Enable( PROJECT_PATH, enablePrjPathOpt ); // Sometimes only the choice "absolute path" is allowed; // Force this choice, at least make it the default choice bool force_absolute_path = false; // For github plugin, the project path is not allowed if( ( m_rbPathManagement->GetSelection() == PROJECT_PATH ) && !enablePrjPathOpt ) force_absolute_path = true; // For github plugin, at least one github compatible path must exist // If no github path, force absolute path int first_github_envvar = HasGithubEnvVarCompatible(); if( IsGithubPlugin() ) { if( first_github_envvar < 0 ) force_absolute_path = true; else if( !getSelectedEnvVarValue().StartsWith( "http" ) ) m_gridEnvironmentVariablesList->SelectRow( first_github_envvar ); } if( force_absolute_path ) m_rbPathManagement->SetSelection( ABSOLUTE_PATH ); } void WIZARD_FPLIB_TABLE::OnPathManagementSelection( wxCommandEvent& event ) { // Disable irrevant options, and enable others. int row_count = GetEnvVarCount(); switch( m_rbPathManagement->GetSelection() ) { case PROJECT_PATH: // Choice = path relative to the project m_gridEnvironmentVariablesList->Enable( true ); m_buttonAddEV->Enable( false ); m_gridEnvironmentVariablesList->ShowRow( PROJECT_PATH ); for( int row = 0; row < row_count; row++ ) { if( row == PROJECT_PATH ) continue; m_gridEnvironmentVariablesList->HideRow( row ); } break; case ENV_VAR_PATH: // Choice = path relative to env var m_gridEnvironmentVariablesList->Enable( true ); m_buttonAddEV->Enable( true ); for( int row = 0; row < row_count; row++ ) m_gridEnvironmentVariablesList->ShowRow( row ); break; case ABSOLUTE_PATH: // Choice = path relative to the project m_gridEnvironmentVariablesList->Enable( false ); m_buttonAddEV->Enable( false ); break; } } void WIZARD_FPLIB_TABLE::OnAddEVariable( wxCommandEvent& event ) { m_gridEnvironmentVariablesList->AppendRows( 1 ); m_gridEnvironmentVariablesList->AutoSizeColumns(); m_buttonRemoveEV->Enable( GetEnvVarCount() > m_predefinedEnvVarCnt ); m_gridEnvironmentVariablesList->SetGridCursor( GetEnvVarCount()-1, 0 ); } void WIZARD_FPLIB_TABLE::OnRemoveEVariable( wxCommandEvent& event ) { wxArrayInt selectedRows = m_gridEnvironmentVariablesList->GetSelectedRows(); int row_cursor = m_gridEnvironmentVariablesList->GetGridCursorRow(); if( selectedRows.size() == 0 && row_cursor >= 0 ) selectedRows.Add( row_cursor ); std::sort( selectedRows.begin(), selectedRows.end() ); for( int ii = selectedRows.GetCount()-1; ii >= 0; ii-- ) { int row = selectedRows[ii]; // don't remove them env var. which are already existing in lib table if( row > m_predefinedEnvVarCnt-1 ) m_gridEnvironmentVariablesList->DeleteRows( row, 1 ); } m_gridEnvironmentVariablesList->SelectRow( m_gridEnvironmentVariablesList->GetGridCursorRow() ); m_buttonRemoveEV->Enable( GetEnvVarCount() > m_predefinedEnvVarCnt ); } void WIZARD_FPLIB_TABLE::OnSelectEnvVarCell( wxGridEvent& event ) { // Ensure the selected row is also the row which have the focus. // useful when the user want to delete a row, and select it by the mouse m_gridEnvironmentVariablesList->SelectRow( event.GetRow() ); } wxString WIZARD_FPLIB_TABLE::getSelectedEnvVar() { wxString envVar; wxArrayInt selectedRows = m_gridEnvironmentVariablesList->GetSelectedRows(); int row = selectedRows.GetCount() ? selectedRows[0] : m_gridEnvironmentVariablesList->GetGridCursorRow(); switch( m_rbPathManagement->GetSelection() ) { case ENV_VAR_PATH: // Choice = path relative to env var envVar = m_gridEnvironmentVariablesList->GetCellValue( wxGridCellCoords( row, 0 ) ); break; case PROJECT_PATH: // Choice = path relative to the project envVar = PROJECT_VAR_NAME; break; case ABSOLUTE_PATH: // Choice = absolute path default: break; } return envVar; } wxString WIZARD_FPLIB_TABLE::getSelectedEnvVarValue() { wxString envVarValue; wxArrayInt selectedRows = m_gridEnvironmentVariablesList->GetSelectedRows(); int row = selectedRows.GetCount() ? selectedRows[0] : m_gridEnvironmentVariablesList->GetGridCursorRow(); switch( m_rbPathManagement->GetSelection() ) { case ENV_VAR_PATH: // Choice = path relative tp env var envVarValue = m_gridEnvironmentVariablesList->GetCellValue( wxGridCellCoords( row, 1 ) ); break; case PROJECT_PATH: // Choice = path relative to the project envVarValue = m_gridEnvironmentVariablesList->GetCellValue( wxGridCellCoords( m_rowPrjEnvVarPosition, 1 ) ); break; case ABSOLUTE_PATH: // Choice = absolute path default: break; } return envVarValue; } void WIZARD_FPLIB_TABLE::OnPageChanged( wxWizardEvent& event ) { if( GetCurrentPage() == m_pages[2] ) setLastPage(); else if( GetCurrentPage() == m_pages[1] ) setSecondPage(); } void WIZARD_FPLIB_TABLE::OnPageChanging( wxWizardEvent& event ) { if( !( GetCurrentPage() == m_pages[1] && event.GetDirection() ) ) return; if( ! ValidateOptions() ) { event.Veto(); return; } if( ( m_rbPathManagement->GetSelection() != ABSOLUTE_PATH ) && ( IsGithubPlugin() ) ) { wxURI uri( getSelectedEnvVarValue() ); // We cannot use wxURL to test the validity of the url, because // wxURL does not know https protocol we are using, and aways returns // error for url starting by https bool badurl = !uri.HasPath(); if( badurl ) { wxMessageBox( wxString::Format( _("The URL defined by env var \"%s\" is an incorrect URL.\nCannot use it"), GetChars( getSelectedEnvVar() ) ) ); event.Veto(); } } } bool WIZARD_FPLIB_TABLE::setSecondPage() { // Init parameters for the second wizard page: this is only // the current library description. updateFromPlugingChoice(); delete m_currLibDescr; m_currLibDescr = NULL; switch( m_rbFpLibFormat->GetSelection() ) { case 0: // Kicad lib type m_currLibDescr = new LIB_DESCR_KICAD; m_buttonGithubLibList->SetLabel( _("Download Github Libs") ); break; case 1: // Github lib type m_currLibDescr = new LIB_DESCR_GITHUB; m_buttonGithubLibList->SetLabel( _("Github Libs List") ); break; case 2: // Legacy lib type m_currLibDescr = new LIB_DESCR_LEGACY; break; case 3: // Eagle V6 lib type m_currLibDescr = new LIB_DESCR_EAGLE; break; case 4: // Geda lib type m_currLibDescr = new LIB_DESCR_GEDA; break; } if( IsGithubPlugin() ) { #ifdef KICAD_USE_WEBKIT m_buttonAddLib->SetLabel( _("Add Libs with WebViewer") ); #else m_buttonAddLib->SetLabel( _("Add FP Library entry") ); #endif } else m_buttonAddLib->SetLabel( _("Add FP Libraries") ); return m_currLibDescr!= NULL; } bool WIZARD_FPLIB_TABLE::setLastPage() // Init prms for the last wizard page { // Update texts in last wizard page m_textPluginType->SetLabel( m_rbFpLibFormat->GetStringSelection() ); switch( m_rbPathManagement->GetSelection() ) { case ENV_VAR_PATH: // Choice = path relative env var case PROJECT_PATH: // Choice = path relative to the project m_currLibDescr->m_EnvVarName = getSelectedEnvVar(); m_currLibDescr->m_DefaultPath = getSelectedEnvVarValue(); m_currLibDescr->m_IsAbsolutePath = false; m_textOption->SetLabel( wxString::Format( wxT("%s (%s)"), m_rbPathManagement->GetStringSelection().GetData(), getSelectedEnvVar().GetData() ) ); m_textPath->SetLabel( getSelectedEnvVarValue() ); break; case ABSOLUTE_PATH: // Choice = absolute path m_currLibDescr->m_IsAbsolutePath = true; m_textOption->SetLabel( m_rbPathManagement->GetStringSelection() ); if( IsGithubPlugin() ) m_textPath->SetLabel( _("Full URL") ); else m_textPath->SetLabel( _("Full filename") ); break; } return true; } void WIZARD_FPLIB_TABLE::OnAddFpLibs( wxCommandEvent& event ) { if( m_currLibDescr->m_IsFile ) selectLibsFiles(); else if( m_currLibDescr->m_IsGitHub ) selectLibsGithubWithWebViewer(); else selectLibsFolders(); m_gridFpListLibs->SetGridCursor( GetLibsCount()-1, 0 ); m_gridFpListLibs->SelectRow( GetLibsCount()-1 ); } void WIZARD_FPLIB_TABLE::selectLibsFiles() // select a set of library files { wxString msk = wxT("*.") + m_currLibDescr->m_Ext; wxFileDialog dlg( this, _("Select Library Files"), m_currLibDescr->m_DefaultPath, wxEmptyString, msk, wxFD_DEFAULT_STYLE|wxFD_FILE_MUST_EXIST|wxFD_MULTIPLE ); dlg.ShowModal(); wxArrayString filepaths; dlg.GetPaths( filepaths ); // Create the nickname: currently make it from the filename wxArrayString nicknames; wxFileName fn; for( unsigned ii = 0; ii < filepaths.GetCount(); ii++ ) { fn = filepaths[ii]; nicknames.Add( fn.GetName() ); if( m_currLibDescr->m_IsAbsolutePath || m_currLibDescr->m_DefaultPath.IsEmpty() ) { filepaths[ii] = fn.GetPathWithSep(); } else { if( ! fn.MakeRelativeTo( m_currLibDescr->m_DefaultPath ) ) filepaths[ii] = fn.GetFullPath(); else filepaths[ii].Printf( wxT("${%s}%c%s"), GetChars( m_currLibDescr->m_EnvVarName ), fn.GetPathSeparator(), GetChars( fn.GetFullPath() ) ); } #ifdef __WINDOWS__ // We store paths using Unix notation, which also works fine on Windows filepaths[ii].Replace( wxT("\\"), wxT("/") ); #endif } populateLibList( nicknames, filepaths, m_currLibDescr->m_PluginName ); m_gridFpListLibs->AutoSizeColumns(); } void WIZARD_FPLIB_TABLE::populateLibList( const wxArrayString& aNickNames, const wxArrayString& aPaths, const wxString& aPluginName ) { if( aPaths.GetCount() <= 0 ) return; // Ensure there is room for selected libs int first_row = m_gridFpListLibs->GetTable()->GetRowsCount(); m_gridFpListLibs->AppendRows( aPaths.GetCount() ); // Populates the library list for( unsigned ii = 0; ii < aPaths.GetCount(); ii++ ) { int jj = first_row + ii; // Add the nickname: currently make it from filename m_gridFpListLibs->SetCellValue( jj, 0, aNickNames[ii] ); // Add the full path: m_gridFpListLibs->SetCellValue( jj, 1, aPaths[ii] ); // Add the plugin name: m_gridFpListLibs->SetCellValue( jj, 2, aPluginName ); m_gridFpListLibs->SetReadOnly( jj, 2, true ); } m_gridFpListLibs->Fit(); } // A helper dialog to show and select a set of directories class DIALOG_SELECT_DIRLIST : public DIALOG_SELECT_DIRLIST_BASE { public: DIALOG_SELECT_DIRLIST( wxWindow* parent, const wxString& aDefaultPath ): DIALOG_SELECT_DIRLIST_BASE( parent, wxID_ANY ) { if( !aDefaultPath.IsEmpty() ) m_dirCtrl->SetPath( aDefaultPath ); Layout(); GetSizer()->Fit( this ); GetSizer()->SetSizeHints(this); Centre(); } ~DIALOG_SELECT_DIRLIST() {}; void GetPaths( wxArrayString& aPaths ) { m_dirCtrl->GetPaths( aPaths ); } }; void WIZARD_FPLIB_TABLE::selectLibsFolders() // select a set of library folders { DIALOG_SELECT_DIRLIST dlg( this, m_currLibDescr->m_DefaultPath ); if( dlg.ShowModal() != wxID_OK ) return; wxArrayString filepaths; dlg.GetPaths( filepaths ); // Create the nickname: currently make it from the filename wxArrayString nicknames; wxFileName fn; for( unsigned ii = 0; ii < filepaths.GetCount(); ii++ ) { fn = filepaths[ii]; nicknames.Add( fn.GetName() ); fn.AssignDir( filepaths[ii] ); if( m_currLibDescr->m_IsAbsolutePath || m_currLibDescr->m_DefaultPath.IsEmpty() ) { filepaths[ii] = fn.GetFullPath(); } else { if( ! fn.MakeRelativeTo( m_currLibDescr->m_DefaultPath ) ) filepaths[ii] = fn.GetFullPath(); else filepaths[ii].Printf( wxT("${%s}%c%s"), GetChars( m_currLibDescr->m_EnvVarName ), fn.GetPathSeparator(), GetChars( fn.GetFullPath() ) ); } #ifdef __WINDOWS__ // We store paths using Unix notation, which also works fine on Windows filepaths[ii].Replace( wxT("\\"), wxT("/") ); #endif // Remove trailing path separator, if any. if( filepaths[ii].EndsWith( wxT("/") ) ) filepaths[ii].RemoveLast(); } populateLibList( nicknames, filepaths, m_currLibDescr->m_PluginName ); } #ifdef KICAD_USE_WEBKIT // A helper function to run the wen viewer (see webviewer.cpp) extern int RunWebViewer( wxWindow * aParent, const wxString& aUrlOnStart, wxArrayString* aUrlListSelection = NULL ); #endif void WIZARD_FPLIB_TABLE::selectLibsGithubWithWebViewer() // select a set of library on Github { // A string array to store the URLs selected from the web viewer: wxArrayString urls; // Run the web viewer and open the default URL: the default path // or our github library repos wxString defaultURL = m_currLibDescr->m_DefaultPath; if( defaultURL.IsEmpty() ) defaultURL = wxT( "https://github.com/KiCad" ); #ifdef KICAD_USE_WEBKIT RunWebViewer( this, defaultURL, &urls ); #else // If the Web Viewer is not available, just add a template // to the fp lib table. // The user have to edit it urls.Add( defaultURL + wxT("/newlibname.pretty") ); #endif installGithubLibsFromList( urls ); } void WIZARD_FPLIB_TABLE::installGithubLibsFromList( wxArrayString& aUrlList ) { // add the libs found in aUrlList, after calculating a nickname and // replacing the path by an env variable, if needed // Create the nickname: currently make it from the url wxArrayString filepaths; wxArrayString nicknames; for( unsigned ii = 0; ii < aUrlList.GetCount(); ii++ ) { wxString urlstring( aUrlList[ii] ); wxURI uri( urlstring ); // We cannot use wxURL to test the validity of the url, because // wxURL does not know https protocol we are using, and aways returns // error for URLs starting by https. Hope this test is enough if( uri.HasPath() ) nicknames.Add( uri.GetPath().AfterLast( '/').BeforeLast( '.' ) ); else continue; // Should not happen: bad URL if( m_currLibDescr->m_IsAbsolutePath || m_currLibDescr->m_DefaultPath.IsEmpty() ) { filepaths.Add( aUrlList[ii] ); // use the full URL } else { wxString shortURI; if( aUrlList[ii].Lower().StartsWith( m_currLibDescr->m_DefaultPath.Lower(), &shortURI ) ) { shortURI.Prepend( wxT("${") + m_currLibDescr->m_EnvVarName + wxT("}") ); filepaths.Add( shortURI ); } else // keep the full URL filepaths.Add( aUrlList[ii] ); // use the full URL } } populateLibList( nicknames, filepaths, m_currLibDescr->m_PluginName ); } void WIZARD_FPLIB_TABLE::OnRemoveFpLibs( wxCommandEvent& event ) { wxArrayInt selectedRows = m_gridFpListLibs->GetSelectedRows(); int row_cursor = m_gridFpListLibs->GetGridCursorRow(); if( selectedRows.size() == 0 && row_cursor >= 0 ) selectedRows.Add( row_cursor ); std::sort( selectedRows.begin(), selectedRows.end() ); for( int ii = selectedRows.GetCount()-1; ii >= 0; ii-- ) { int row = selectedRows[ii]; m_gridFpListLibs->DeleteRows( row, 1 ); } m_gridFpListLibs->SelectRow( m_gridFpListLibs->GetGridCursorRow() ); } #ifdef BUILD_GITHUB_PLUGIN #include <../github/github_getliblist.h> void WIZARD_FPLIB_TABLE::OnGithubLibsList( wxCommandEvent& event ) { wxArrayString liblist; getLibsListGithub( liblist ); if( liblist.GetCount() == 0 ) // No lib selected return; if( IsKicadPlugin() ) { wxString msg; if( !downloadGithubLibsFromList( liblist, &msg ) ) { wxMessageBox( msg ); return; } } else installGithubLibsFromList( liblist ); } void WIZARD_FPLIB_TABLE::getLibsListGithub( wxArrayString& aList ) { wxBeginBusyCursor(); // Be sure there is no trailing '/' at the end of the repo name wxString git_url = m_textCtrlGithubURL->GetValue(); if( git_url.EndsWith( wxT("/" ) ) ) { git_url.RemoveLast(); m_textCtrlGithubURL->SetValue( git_url ); } GITHUB_GETLIBLIST getter( git_url ); wxArrayString fullList; getter.GetLibraryList( fullList ); wxEndBusyCursor(); wxArrayInt choices; wxString msg( _( "Urls detected as footprint .pretty libraries.\n" "Selected urls will be added to the current footprint library list" ) ); if( wxGetSelectedChoices( choices, msg, _( "Footprint libraries" ), fullList, this ) <= 0 ) return; // Add selected url in list for( unsigned ii = 0; ii < choices.GetCount(); ii++ ) { wxString& url = fullList[choices[ii]]; aList.Add( url ); } } // Download the .pretty libraries found in aUrlLis and store them on disk // in a master folder bool WIZARD_FPLIB_TABLE::downloadGithubLibsFromList( wxArrayString& aUrlList, wxString * aErrorMessage ) { wxString masterFolder; wxString default_path; wxGetEnv( FP_LIB_TABLE::GlobalPathEnvVariableName(), &default_path ); masterFolder = wxDirSelector( _("Output Folder" ), default_path, 0, wxDefaultPosition, this ); if( masterFolder.IsEmpty() ) // Aborted by user { if( aErrorMessage ) *aErrorMessage = _( "Aborted" ); return false; } if( !wxDirExists( masterFolder ) ) { if( aErrorMessage ) aErrorMessage->Printf( _( "Folder '%s' does not exists" ), GetChars( masterFolder ) ); return false; } // Display a progress bar to show the downlaod state wxProgressDialog pdlg( _("Download libraries"), wxEmptyString, aUrlList.GetCount() ); // Download libs: for( unsigned ii = 0; ii < aUrlList.GetCount(); ii++ ) { wxString& libsrc_name = aUrlList[ii]; wxString libdst_name; // Extract the lib name from the full URL: wxURI url( libsrc_name ); wxFileName fn( url.GetPath() ); // Set our local path fn.SetPath( masterFolder ); libdst_name = fn.GetFullPath(); if( !wxDirExists( libdst_name ) ) wxMkdir( libdst_name ); pdlg.Update( ii, libsrc_name); try { PLUGIN::RELEASER src( IO_MGR::PluginFind( IO_MGR::GITHUB ) ); PLUGIN::RELEASER dst( IO_MGR::PluginFind( IO_MGR::KICAD ) ); wxArrayString footprints = src->FootprintEnumerate( libsrc_name ); for( unsigned i = 0; i < footprints.size(); ++i ) { std::auto_ptr m( src->FootprintLoad( libsrc_name, footprints[i] ) ); dst->FootprintSave( libdst_name, m.get() ); // m is deleted here by auto_ptr. } } catch( const IO_ERROR& ioe ) { if( aErrorMessage ) aErrorMessage->Printf( _("Error:\n'%s'\nwhile downloading library:\n'%s'"), GetChars( ioe.errorText ), GetChars( libsrc_name ) ); return false; } } return true; } #endif