KiCad PCB EDA Suite
wizard_add_fplib.cpp
Go to the documentation of this file.
1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2015 CERN
5  * @author Maciej Suminski <maciej.suminski@cern.ch>
6  * Copyright (C) 2014-2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
7  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
35 #include <memory>
36 #include <wx/wx.h>
37 #include <wx/uri.h>
38 #include <wx/dir.h>
39 #include <wx/progdlg.h>
40 
41 #include <pgm_base.h>
42 #include <project.h>
43 #include <wizard_add_fplib.h>
44 #include <fp_lib_table.h>
45 #include <confirm.h>
46 #include <bitmaps.h>
47 
48 #include <class_module.h>
49 #include <env_paths.h>
50 
51 #ifdef BUILD_GITHUB_PLUGIN
52 #include <../github/github_getliblist.h>
53 #endif
54 
55 // a key to store the default Kicad Github libs URL
56 #define KICAD_FPLIBS_URL_KEY wxT( "kicad_fplib_url" )
57 #define KICAD_FPLIBS_LAST_DOWNLOAD_DIR wxT( "kicad_fplib_last_download_dir" )
58 
59 // Filters for the file picker
60 static const int FILTER_COUNT = 4;
61 static const struct
62 {
63  wxString m_Description;
64  wxString m_Extension;
65  bool m_IsFile;
68 {
69  { "KiCad (folder with .kicad_mod files)", "kicad_mod", false, IO_MGR::KICAD_SEXP },
70  { "Eagle 6.x (*.lbr)", "lbr", true, IO_MGR::EAGLE },
71  { "KiCad legacy (*.mod)", "mod", true, IO_MGR::LEGACY },
72  { "Geda (folder with *.fp files)", "fp", false, IO_MGR::GEDA_PCB },
73 };
74 
75 
76 // Returns the filter string for the file picker
77 static wxString getFilterString()
78 {
79  wxString filterInit = _( "All supported library formats|" );
80  wxString filter;
81 
82  for( int i = 0; i < FILTER_COUNT; ++i )
83  {
84  // Init part
85  if( i != 0 )
86  filterInit += ";";
87 
88  filterInit += "*." + fileFilters[i].m_Extension;
89 
90  // Rest of the filter string
91  filter += "|" + fileFilters[i].m_Description +
92  "|" + ( fileFilters[i].m_IsFile ? "*." + fileFilters[i].m_Extension : "" );
93  }
94 
95  return filterInit + filter;
96 }
97 
98 
99 // Tries to guess the plugin type basing on the path
100 static OPT<IO_MGR::PCB_FILE_T> getPluginType( const wxString& aPath )
101 {
102  if( ( aPath.StartsWith( "http://" ) || aPath.StartsWith( "https://" ) ) )
104 
105  wxFileName path( aPath );
106 
107  for( int i = 0; i < FILTER_COUNT; ++i )
108  {
109  bool ok = false;
110 
111  if( fileFilters[i].m_IsFile )
112  {
113  ok = path.IsFileReadable() && path.GetExt() == fileFilters[i].m_Extension;
114  }
115  else if( path.IsDirReadable() )
116  {
117  // Plugin expects a directory containing files with a specific extension
118  wxDir dir( aPath );
119 
120  if( dir.IsOpened() )
121  {
122  wxString filename;
123 
124  dir.GetFirst( &filename, "*." + fileFilters[i].m_Extension, wxDIR_FILES );
125 
126  ok = !filename.IsEmpty();
127  }
128  }
129 
130  if( ok )
131  return OPT<IO_MGR::PCB_FILE_T>( fileFilters[i].m_Plugin );
132  }
133 
134  return NULLOPT;
135 }
136 
137 
138 // Checks if a filename fits specific filter
139 static bool passesFilter( const wxString& aFileName, int aFilterIndex )
140 {
141  wxASSERT( aFilterIndex <= FILTER_COUNT );
142  wxFileName file( aFileName );
143  OPT<IO_MGR::PCB_FILE_T> result = getPluginType( aFileName );
144 
145  if( !result ) // does not match any supported plugin
146  return false;
147 
148  if( aFilterIndex == 0 ) // any plugin will do
149  return true;
150 
151  return ( fileFilters[aFilterIndex - 1].m_Plugin == *result );
152 }
153 
154 
155 WIZARD_FPLIB_TABLE::LIBRARY::LIBRARY( const wxString& aPath, const wxString& aDescription ) :
156  m_path( aPath ), m_description( aDescription ), m_status( NOT_CHECKED )
157 {
158  m_plugin = getPluginType( aPath );
159 }
160 
161 
163 {
164  if( !m_plugin )
165  {
167  return false;
168  }
169 
170  std::unique_ptr<PLUGIN> p( IO_MGR::PluginFind( *m_plugin ) );
171  wxArrayString footprints;
172 
173  if( !p )
174  {
176  return false;
177  }
178 
179  try
180  {
181  p->FootprintEnumerate( footprints, m_path );
182  }
183  catch( IO_ERROR& )
184  {
186  return false;
187  }
188 
189  if( footprints.GetCount() == 0 )
190  {
192  return false;
193  }
194 
196  return true;
197 }
198 
199 
201 {
202  if( !m_plugin )
203  return _( "UNKNOWN" );
204 
205  return IO_MGR::ShowType( *m_plugin );
206 }
207 
208 
209 wxString WIZARD_FPLIB_TABLE::LIBRARY::GetRelativePath( const wxString& aBase, const wxString& aSubstitution ) const
210 {
211  wxFileName libPath( m_path );
212 
213  // Check if the library path belongs to the project folder
214  if( libPath.MakeRelativeTo( aBase ) && !libPath.GetFullPath().StartsWith( ".." ) )
215  {
216  return wxString( aSubstitution + "/" + libPath.GetFullPath() );
217  }
218 
219  // Probably on another drive, so the relative path will not work
220  return wxEmptyString;
221 }
222 
223 
225 {
226  const wxString& project_env = PROJECT_VAR_NAME;
227  const wxString& github_env( "KIGITHUB" );
228 
229  wxString rel_path;
230 
231  // The extra KIGITHUB and KIPRJCHECKS are still here since Pgm.GetLocalVariables() does not
232  // contain the KIPRJMOD env var, and the KIGITHUB does not pass the IsAbsolutePath check
233  // that happens in NormalizePath(...) since it starts with https://
234 
235  // KIGITHUB check
236  rel_path = replaceEnv( github_env, false );
237 
238  if( !rel_path.IsEmpty() )
239  return rel_path;
240 
241  // KIPRJMOD check
242  if( aScope == PROJECT )
243  {
244  rel_path = replaceEnv( project_env );
245 
246  if( !rel_path.IsEmpty() )
247  return rel_path;
248  }
249 
250  rel_path = NormalizePath( wxFileName( m_path ), &Pgm().GetLocalEnvVariables(), project_env );
251 
252  // If normalizePath failed, then rel_path will be empty, m_path is the full path.
253  if( rel_path.IsEmpty() )
254  return m_path;
255 
256  return rel_path;
257 }
258 
259 
261 {
262  if( !m_description.IsEmpty() )
263  return m_description;
264 
265  wxFileName filename( m_path );
266  return filename.GetName();
267 }
268 
269 
270 wxString WIZARD_FPLIB_TABLE::LIBRARY::replaceEnv( const wxString& aEnvVar, bool aFilePath ) const
271 {
272  wxString env_path;
273 
274  if( !wxGetEnv( aEnvVar, &env_path ) )
275  return wxEmptyString;
276 
277  //return GetRelativePath( m_path, wxString( "$(" + aEnvVar + ")" ) );
278 
279  wxString result( m_path );
280 
281  if( result.Replace( env_path, wxString( "$(" + aEnvVar + ")" ) ) )
282  return result;
283 
284  return wxEmptyString;
285 }
286 
287 
289  WIZARD_FPLIB_TABLE_BASE( aParent ), m_welcomeDlg( m_pages[0] ),
292 {
293  m_filePicker->SetFilter( getFilterString() );
294 
295  // Initialize default download dir
296  wxString default_path;
297  wxGetEnv( FP_LIB_TABLE::GlobalPathEnvVariableName(), &default_path );
298  setDownloadDir( default_path );
299  m_filePicker->SetPath( default_path );
300 
301  // Restore the Github url
302  wxString githubUrl;
303 
304  wxConfigBase* cfg = Pgm().CommonSettings();
305  cfg->Read( KICAD_FPLIBS_URL_KEY, &githubUrl );
307 
308 
309  if( !m_lastGithubDownloadDirectory.IsEmpty() )
310  {
313  } else {
314  m_lastGithubDownloadDirectory = default_path;
315  }
316 
317  if( githubUrl.IsEmpty() )
318  githubUrl = wxT( "https://github.com/KiCad" );
319 
320  SetGithubURL( githubUrl );
321 
322  // Give the minimal size to the dialog, which allows displaying any page
323  wxSize minsize;
324 
325  for( unsigned ii = 0; ii < m_pages.size(); ii++ )
326  {
327  wxSize size = m_pages[ii]->GetSizer()->CalcMin();
328  minsize.x = std::max( minsize.x, size.x );
329  minsize.y = std::max( minsize.y, size.y );
330  }
331 
332  SetMinSize( minsize );
333  SetPageSize( minsize );
334  GetSizer()->SetSizeHints( this );
335  Center();
336 
337  if( !m_radioAddGithub->GetValue() && !m_radioAddLocal->GetValue() )
338  m_radioAddLocal->SetValue( true );
339 
342 
343  Connect( wxEVT_RADIOBUTTON, wxCommandEventHandler( WIZARD_FPLIB_TABLE::OnSourceCheck ), NULL, this );
344  Connect( wxEVT_DIRCTRL_SELECTIONCHANGED, wxCommandEventHandler( WIZARD_FPLIB_TABLE::OnSelectFiles ), NULL, this );
345  Connect( wxEVT_CHECKLISTBOX, wxCommandEventHandler( WIZARD_FPLIB_TABLE::OnCheckGithubList ), NULL, this );
346 }
347 
348 
350 {
351  // Use this if you want to store kicad lib URL in pcbnew/cvpcb section config:
352 // wxConfigBase* cfg = Kiface().KifaceSettings();
353 
354  // Use this if you want to store kicad lib URL in common section config:
355  wxConfigBase* cfg = Pgm().CommonSettings();
356  cfg->Write( KICAD_FPLIBS_URL_KEY, GetGithubURL() );
357 }
358 
359 
361 {
362  if( m_radioAddGithub->GetValue() )
363  return GITHUB;
364 
365  wxASSERT( m_radioAddLocal->GetValue() );
366 
367  return LOCAL;
368 }
369 
370 
372 {
373  if( m_radioGlobal->GetValue() )
374  return GLOBAL;
375 
376  wxASSERT( m_radioProject->GetValue() );
377 
378  return PROJECT;
379 }
380 
381 
382 void WIZARD_FPLIB_TABLE::OnPageChanged( wxWizardEvent& aEvent )
383 {
384  SetBitmap( KiBitmap( wizard_add_fplib_icon_xpm ) );
385  enableNext( true );
386 
387 #ifdef BUILD_GITHUB_PLUGIN
388  if( GetCurrentPage() == m_githubListDlg )
389  setupGithubList();
390  else
391 #endif
392  if( GetCurrentPage() == m_fileSelectDlg )
393  setupFileSelect();
394  else if( GetCurrentPage() == m_reviewDlg )
395  setupReview();
396 }
397 
398 
399 void WIZARD_FPLIB_TABLE::OnSelectFiles( wxCommandEvent& aEvent )
400 {
401  int filterIdx = m_filePicker->GetFilterIndex();
402 
403  if( m_selectedFilter != filterIdx )
404  {
405  m_selectedFilter = filterIdx;
406 
407  // Process the event again, as in the first iteration we cannot get the list of selected items
408  wxCommandEvent ev( wxEVT_DIRCTRL_SELECTIONCHANGED );
409  AddPendingEvent( ev );
410  return;
411  }
412 
413  enableNext( checkFiles() );
414 }
415 
416 
417 void WIZARD_FPLIB_TABLE::OnCheckGithubList( wxCommandEvent& aEvent )
418 {
419  wxArrayInt dummy;
420 
421  enableNext( m_checkListGH->GetCheckedItems( dummy ) > 0 );
422 }
423 
424 
425 void WIZARD_FPLIB_TABLE::OnSourceCheck( wxCommandEvent& aEvent )
426 {
429 }
430 
431 
432 void WIZARD_FPLIB_TABLE::OnSelectAllGH( wxCommandEvent& aEvent )
433 {
434  for( unsigned int i = 0; i < m_checkListGH->GetCount(); ++i )
435  m_checkListGH->Check( i, true );
436 
437  // The list might be empty, e.g. in case of download error
438  wxArrayInt dummy;
439  enableNext( m_checkListGH->GetCheckedItems( dummy ) > 0 );
440 }
441 
442 
443 void WIZARD_FPLIB_TABLE::OnUnselectAllGH( wxCommandEvent& aEvent )
444 {
445  for( unsigned int i = 0; i < m_checkListGH->GetCount(); ++i )
446  m_checkListGH->Check( i, false );
447 
448  enableNext( false );
449 }
450 
451 
452 void WIZARD_FPLIB_TABLE::OnChangeSearch( wxCommandEvent& aEvent )
453 {
454  wxString searchPhrase = m_searchCtrlGH->GetValue().Lower();
455 
456  // Store the current selection
457  wxArrayInt checkedIndices;
458  m_checkListGH->GetCheckedItems( checkedIndices );
459  wxArrayString checkedStrings;
460 
461  for( unsigned int i = 0; i < checkedIndices.GetCount(); ++i )
462  checkedStrings.Add( m_checkListGH->GetString( checkedIndices[i] ).AfterLast( '/' ) );
463 
464  m_checkListGH->Clear();
465 
466  // Rebuild the list, putting the matching entries on the top
467  int matching = 0; // number of entries matching the search phrase
468  for( unsigned int i = 0; i < m_githubLibs.GetCount(); ++i )
469  {
470  const wxString& lib = m_githubLibs[i].AfterLast( '/' );
471  bool wasChecked = ( checkedStrings.Index( lib ) != wxNOT_FOUND );
472  int insertedIdx = -1;
473 
474  if( !searchPhrase.IsEmpty() && lib.Lower().Contains( searchPhrase ) )
475  {
476  insertedIdx = m_checkListGH->Insert( lib, matching++ );
477  m_checkListGH->SetSelection( insertedIdx );
478  }
479  else
480  insertedIdx = m_checkListGH->Append( lib );
481 
482  if( wasChecked )
483  m_checkListGH->Check( insertedIdx );
484  }
485 
486  if( !m_checkListGH->IsEmpty() )
487  m_checkListGH->EnsureVisible( 0 );
488 }
489 
490 
491 void WIZARD_FPLIB_TABLE::OnWizardFinished( wxWizardEvent& aEvent )
492 {
493 #ifdef BUILD_GITHUB_PLUGIN
494  // Shall we download a localy copy of the libraries
495  if( GetLibSource() == GITHUB && m_downloadGithub->GetValue() )
496  {
497  wxString error;
498  wxArrayString libs;
499 
500  // Prepare a list of libraries to download
501  for( std::vector<LIBRARY>::const_iterator it = m_libraries.begin();
502  it != m_libraries.end(); ++it )
503  {
504  wxASSERT( it->GetPluginType() == IO_MGR::GITHUB );
505 
506  if( it->GetStatus() != LIBRARY::INVALID )
507  libs.Add( it->GetAbsolutePath() );
508  }
509 
510  if( !downloadGithubLibsFromList( libs, &error ) )
511  {
512  DisplayError( this, error );
513  m_libraries.clear();
514  }
515  else
516  {
517  // Now libraries are stored locally, so update the paths to point to the download folder
518  for( std::vector<LIBRARY>::iterator it = m_libraries.begin();
519  it != m_libraries.end(); ++it )
520  {
521  wxString path = it->GetAbsolutePath();
522  path.Replace( GetGithubURL(), getDownloadDir() );
523  it->setPath( path );
524  it->setPluginType( IO_MGR::KICAD_SEXP );
525  }
526  }
527  }
528 #endif
529 }
530 
531 
532 void WIZARD_FPLIB_TABLE::OnBrowseButtonClick( wxCommandEvent& aEvent )
533 {
534  wxString path = getDownloadDir();
535 
536  path = wxDirSelector( _("Choose a folder to save the downloaded libraries" ),
537  path, 0, wxDefaultPosition, this );
538 
539  if( !path.IsEmpty() && wxDirExists( path ) )
540  {
541  setDownloadDir( path );
542 
543  wxConfigBase* cfg = Pgm().CommonSettings();
544  cfg->Write( KICAD_FPLIBS_LAST_DOWNLOAD_DIR, path );
545 
547  }
548 }
549 
550 
551 void WIZARD_FPLIB_TABLE::OnCheckSaveCopy( wxCommandEvent& aEvent )
552 {
554 }
555 
556 
558 {
559  // Get current selection (files & directories)
560  wxArrayString candidates;
561  m_filePicker->GetPaths( candidates );
562 
563  // Workaround, when you change filters "/" is automatically selected
564  int slash_index = candidates.Index( "/", true, true );
565  if( slash_index != wxNOT_FOUND )
566  candidates.RemoveAt( slash_index, 1 );
567 
568  if( candidates.IsEmpty() )
569  return false;
570 
571  // Verify all the files/folders comply to the selected library type filter
572  for( unsigned int i = 0; i < candidates.GetCount(); ++i )
573  {
574  if( !passesFilter( candidates[i], m_filePicker->GetFilterIndex() ) )
575  return false;
576  }
577 
578  return true;
579 }
580 
581 
582 #ifdef BUILD_GITHUB_PLUGIN
583 void WIZARD_FPLIB_TABLE::getLibsListGithub( wxArrayString& aList )
584 {
585  wxBeginBusyCursor();
586 
587  // Be sure there is no trailing '/' at the end of the repo name
588  wxString git_url = m_textCtrlGithubURL->GetValue();
589 
590  if( git_url.EndsWith( wxT( "/" ) ) )
591  {
592  git_url.RemoveLast();
593  m_textCtrlGithubURL->SetValue( git_url );
594  }
595 
596  GITHUB_GETLIBLIST getter( git_url );
597  getter.GetFootprintLibraryList( aList );
598 
599  wxEndBusyCursor();
600 }
601 
602 
603 // Download the .pretty libraries found in aUrlLis and store them on disk
604 // in a master folder
605 bool WIZARD_FPLIB_TABLE::downloadGithubLibsFromList( wxArrayString& aUrlList,
606  wxString* aErrorMessage )
607 {
608  // Display a progress bar to show the downlaod state
609  // for OSX do not enable wPD_APP_MODAL, keep wxPD_AUTO_HIDE
610  wxProgressDialog pdlg( _( "Downloading libraries" ), wxEmptyString, aUrlList.GetCount(),
611  this,
612 #ifndef __WXMAC__
613  wxPD_APP_MODAL |
614 #endif
615  wxPD_CAN_ABORT | wxPD_AUTO_HIDE );
616 
617  // Download libs:
618  for( unsigned ii = 0; ii < aUrlList.GetCount(); ii++ )
619  {
620  wxString& libsrc_name = aUrlList[ii];
621  wxString libdst_name;
622 
623  // Extract the lib name from the full URL:
624  wxURI url( libsrc_name );
625  wxFileName fn( url.GetPath() );
626  // Set our local path
627  fn.SetPath( getDownloadDir() );
628  libdst_name = fn.GetFullPath();
629 
630  if( !wxDirExists( libdst_name ) )
631  wxMkdir( libdst_name );
632 
633  pdlg.Update( ii, libsrc_name );
634  pdlg.Refresh();
635  pdlg.Update();
636 
637  try
638  {
641 
642  wxArrayString footprints;
643 
644  src->FootprintEnumerate( footprints, libsrc_name );
645 
646  for( unsigned i = 0; i < footprints.size(); ++i )
647  {
648  std::unique_ptr<MODULE> m( src->FootprintLoad( libsrc_name, footprints[i] ) );
649  dst->FootprintSave( libdst_name, m.get() );
650  // m is deleted here by unique_ptr.
651  }
652  }
653  catch( const IO_ERROR& ioe )
654  {
655  if( aErrorMessage )
656  aErrorMessage->Printf( _( "Error:\n\"%s\"\nwhile downloading library:\n\"%s\"" ),
657  GetChars( ioe.What() ), GetChars( libsrc_name ) );
658  return false;
659  }
660  }
661 
662  return true;
663 }
664 
665 
667 {
668  // Enable 'Next' only if there is at least one library selected
669  wxArrayInt checkedIndices;
670  m_checkListGH->GetCheckedItems( checkedIndices );
671  enableNext( checkedIndices.GetCount() > 0 );
672 
673  // Update only if necessary
674  if( m_githubLibs.GetCount() == 0 )
676 
677  m_searchCtrlGH->Clear();
678 
679  // Clear the review list so it will be reloaded
680  m_libraries.clear();
681  m_listCtrlReview->DeleteAllItems();
682 }
683 #endif /* BUILD_GITHUB_PLUGIN */
684 
685 
687 {
688 #ifndef BUILD_GITHUB_PLUGIN
689  m_radioAddGithub->Enable( false );
690 #endif
691 
692  // Disable inputs that have no meaning for the selected source
693  bool githubEnabled = ( GetLibSource() == GITHUB );
694  m_textCtrlGithubURL->Enable( githubEnabled );
695  m_downloadGithub->Enable( githubEnabled );
696  m_downloadDir->Enable( githubEnabled && wantLocalCopy() );
697  m_btnBrowse->Enable( githubEnabled && wantLocalCopy() );
698 
699  bool valid = !( githubEnabled && wantLocalCopy() ) || wxFileName::IsDirWritable( getDownloadDir() );
700 
701  // Do not allow to go further unless there is a valid directory selected
702  m_invalidDir->Show( !valid );
703  enableNext( valid );
704 }
705 
706 
708 {
709  // No need to update, the review list is ready
710  if( m_listCtrlReview->GetItemCount() != 0 )
711  return;
712 
713  switch( GetLibSource() )
714  {
715  case LOCAL:
716  {
717  wxArrayString libs;
718  m_filePicker->GetPaths( libs );
719 
720  // Workaround, when you change filters "/" is automatically selected
721  int slash_index = libs.Index( "/", true, true );
722  if( slash_index != wxNOT_FOUND )
723  libs.RemoveAt( slash_index, 1 );
724 
725  m_libraries.reserve( libs.GetCount() );
726 
727  for( unsigned int i = 0; i < libs.GetCount(); ++i )
728  m_libraries.push_back( libs[i] );
729  }
730  break;
731 
732  case GITHUB:
733  {
734  wxArrayInt checkedLibs;
735  m_checkListGH->GetCheckedItems( checkedLibs );
736 
737  m_libraries.reserve( checkedLibs.GetCount() );
738 
739  for( unsigned int i = 0; i < checkedLibs.GetCount(); ++i )
740  m_libraries.push_back( GetGithubURL() + "/" + m_checkListGH->GetString( checkedLibs[i] ) );
741  }
742  break;
743 
744  default:
745  wxASSERT( false );
746  break;
747  }
748 }
749 
750 
752 {
753  // Alternate the wizard pages flow depending on the selected option
754  switch( GetLibSource() )
755  {
756  case LOCAL:
757  m_welcomeDlg->SetNext( m_fileSelectDlg );
758  m_fileSelectDlg->SetPrev( m_welcomeDlg );
759 
760  m_fileSelectDlg->SetNext( m_reviewDlg );
761  m_reviewDlg->SetPrev( m_fileSelectDlg );
762  break;
763 
764  case GITHUB:
765  m_welcomeDlg->SetNext( m_githubListDlg );
766  m_githubListDlg->SetPrev( m_welcomeDlg );
767 
768  m_githubListDlg->SetNext( m_reviewDlg );
769  m_reviewDlg->SetPrev( m_githubListDlg );
770  break;
771 
772  default:
773  wxASSERT( false );
774  break;
775  }
776 }
777 
778 
780 {
781  // Disable the button until something is selected
782  enableNext( checkFiles() );
783 
784  // Clear the review list so it will be reloaded
785  m_libraries.clear();
786  m_listCtrlReview->DeleteAllItems();
787 }
788 
789 
791 {
792  wxBeginBusyCursor();
793  updateLibraries();
794 
795  int libTotalCount = m_libraries.size();
796  int libCount = 0;
797  bool validate = true;
798  // for OSX do not enable wPD_APP_MODAL, keep wxPD_AUTO_HIDE
799  wxProgressDialog progressDlg( _( "Please wait..." ), _( "Validating libraries" ),
800  libTotalCount, this,
801 #ifndef __WXMAC__
802  wxPD_APP_MODAL |
803 #endif
804  wxPD_CAN_ABORT | wxPD_AUTO_HIDE );
805 
806  m_dvLibName->SetWidth( 280 );
807 
808  // Prepare the review list
809  m_listCtrlReview->DeleteAllItems();
810 
811  for( std::vector<LIBRARY>::iterator it = m_libraries.begin(); it != m_libraries.end(); ++it )
812  {
813  wxVector<wxVariant> row;
814  LIBRARY::STATUS status = it->GetStatus();
815 
816  // Check if the library contents is valid
817  if( status == LIBRARY::NOT_CHECKED && validate )
818  {
819  it->Test();
820  status = it->GetStatus();
821  }
822 
823  row.push_back( wxVariant( it->GetDescription() ) );
824 
825  switch( it->GetStatus() )
826  {
828  row.push_back( wxVariant( _( "NOT CHECKED" ) ) );
829  break;
830 
831  case LIBRARY::OK:
832  row.push_back( wxVariant( _( "OK" ) ) );
833  break;
834 
835  case LIBRARY::INVALID:
836  row.push_back( wxVariant( _( "INVALID" ) ) );
837  break;
838  }
839 
840  row.push_back( wxVariant( it->GetPluginName() ) );
841 
842  m_listCtrlReview->AppendItem( row );
843 
844  ++libCount;
845  if( !progressDlg.Update( libCount, wxString::Format( _( "Validating libraries %d/%d" ),
846  libCount, libTotalCount ) ) )
847  validate = false;
848  }
849 
850  // The list should never be empty, but who knows?
851  enableNext( m_listCtrlReview->GetItemCount() > 0 );
852 
853  wxEndBusyCursor();
854 }
wxString GetGithubURL() const
Function GetGithubURL Returns the current Github repository URL set in the wizard.
Class PROJECT holds project specific data.
Definition: project.h:56
wxWizardPageSimple *const m_fileSelectDlg
void OnUnselectAllGH(wxCommandEvent &aEvent) override
virtual void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Return a list of footprint names contained within the library at aLibraryPath.
Definition: plugin.cpp:61
wxWizardPageSimple *const m_reviewDlg
Class WIZARD_FPLIB_TABLE_BASE.
LIB_SCOPE GetLibScope() const
Function GetLibScope Returns the scope for the added libraries (global / project specific).
wxString GetPluginName() const
Function GetPluginName Returns the plugin name, as used in the FPLIB table editor.
void OnCheckGithubList(wxCommandEvent &aEvent)
This file is part of the common library.
void enableNext(bool aEnable)
Enables/disable &#39;Next&#39; button
wxString GetAutoPath(LIB_SCOPE aScope) const
Function GetAutoPath Returns path that is either absolute or related to KISYSMOD/KIPRJMOD if the file...
static OPT< IO_MGR::PCB_FILE_T > getPluginType(const wxString &aPath)
static const int FILTER_COUNT
wxArrayString m_githubLibs
Cache for the downloaded Github library list
OPT< IO_MGR::PCB_FILE_T > m_plugin
virtual void FootprintSave(const wxString &aLibraryPath, const MODULE *aFootprint, const PROPERTIES *aProperties=NULL)
Function FootprintSave will write aModule to an existing library located at aLibraryPath.
Definition: plugin.cpp:94
static wxString getFilterString()
#define PROJECT_VAR_NAME
A variable name whose value holds the current project directory.
Definition: project.h:36
wxString GetDescription() const
Function GetDescription Returns the description for the library.
PGM_BASE & Pgm()
The global Program "get" accessor.
Definition: kicad.cpp:65
wxWizardPageSimple *const m_githubListDlg
bool GetFootprintLibraryList(wxArrayString &aList)
Fills aList by the name of footprint libraries found on the github repo.
static const wxString ShowType(PCB_FILE_T aFileType)
Function ShowType returns a brief name for a plugin, given aFileType enum.
Definition: io_mgr.cpp:77
IO_MGR::PCB_FILE_T m_Plugin
bool downloadGithubLibsFromList(wxArrayString &aUrlList, wxString *aErrorMessage)
Saves a list of Github libraries locally.
Geda PCB file formats.
Definition: io_mgr.h:58
wxWizardPageSimple *const m_targetDlg
void OnSelectAllGH(wxCommandEvent &aEvent) override
wxGenericDirCtrl * m_filePicker
void OnWizardFinished(wxWizardEvent &aEvent) override
static const struct @13 fileFilters[FILTER_COUNT]
Class RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destruct...
Definition: io_mgr.h:563
LIB_SOURCE GetLibSource() const
Function GetLibSource Returns the source of libraries (local / Github).
void getLibsListGithub(wxArrayString &aList)
Downloads the list of Github libraries
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Function KiBitmap constructs a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:78
bool wantLocalCopy() const
Does the user want a local copy of Github libraries?
void updateLibraries()
Updates m_libraries basing on dialogs contents
static const wxString GlobalPathEnvVariableName()
Function GlobalPathEnvVarVariableName.
wxString replaceEnv(const wxString &aEnvVar, bool aFilePath=true) const
Function replaceEnv replaces path with environmental variable if applicable.
wxString m_Description
Description shown in the file picker dialog.
bool checkFiles() const
Checks the selection in file picker
virtual MODULE * FootprintLoad(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL)
Function FootprintLoad loads a footprint having aFootprintName from the aLibraryPath containing a lib...
Definition: plugin.cpp:85
const auto NULLOPT
Definition: optional.h:9
LIB_SCOPE
Scope (global/project)
bool m_IsFile
Whether it is a folder or a file.
std::vector< LIBRARY > m_libraries
Libraries selected in the wizard
LIBRARY(const wxString &aPath, const wxString &aDescription=wxEmptyString)
STATUS
Possible states of validation.
void OnPageChanged(wxWizardEvent &aEvent) override
static bool passesFilter(const wxString &aFileName, int aFilterIndex)
void setDownloadDir(const wxString &aDir)
Sets the target directory for libraries downloaded from Github
void OnCheckSaveCopy(wxCommandEvent &aEvent) override
void SetGithubURL(const wxString &aUrl)
Function SetGithubURL Sets the current Github repository URL used by the wizard.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
Legacy Pcbnew file formats prior to s-expression.
Definition: io_mgr.h:54
see class PGM_BASE
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
WIZARD_FPLIB_TABLE(wxWindow *aParent)
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
#define max(a, b)
Definition: auxiliary.h:86
wxWizardPageSimple *const m_welcomeDlg
static PLUGIN * PluginFind(PCB_FILE_T aFileType)
Function PluginFind returns a PLUGIN which the caller can use to import, export, save, or load design documents.
Definition: io_mgr.cpp:58
VTBL_ENTRY wxConfigBase * CommonSettings() const
Definition: pgm_base.h:145
size_t i
Definition: json11.cpp:597
void OnSelectFiles(wxCommandEvent &aEvent)
void OnChangeSearch(wxCommandEvent &aEvent) override
wxString m_lastGithubDownloadDirectory
boost::optional< T > OPT
Definition: optional.h:7
bool Test()
Function Test Uses the associated plugin to validate the library contents.
wxString m_Extension
In case of folders it stands for extensions of files stored inside.
Module description (excepted pads)
wxString getDownloadDir()
Gets the current target for downloaded libraries
wxDataViewColumn * m_dvLibName
LIB_SOURCE
Source of the libraries (local files or Github)
void OnSourceCheck(wxCommandEvent &aEvent)
#define KICAD_FPLIBS_LAST_DOWNLOAD_DIR
wxString GetRelativePath(const wxString &aBase, const wxString &aSubstitution=wxEmptyString) const
Function GetRelativePath Returns the relative path, based on the input path with the base part replac...
PCB_FILE_T
Enum PCB_FILE_T is a set of file types that the IO_MGR knows about, and for which there has been a pl...
Definition: io_mgr.h:52
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:185
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
wxDataViewListCtrl * m_listCtrlReview
Read only http://github.com repo holding pretty footprints.
Definition: io_mgr.h:59
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalizes a file path to an environmental variable, if possible.
Definition: env_paths.cpp:67
void OnBrowseButtonClick(wxCommandEvent &aEvent) override
Class GITHUB_GETLIBLIST implements a portion of pcbnew&#39;s PLUGIN interface to provide read only access...
S-expression Pcbnew file format.
Definition: io_mgr.h:55
#define KICAD_FPLIBS_URL_KEY
Wizard for selecting footprint libraries consisting of 4 steps:
void updateGithubControls()
Enables Github widgets depending on the selected options.