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 
50 #ifdef BUILD_GITHUB_PLUGIN
51 #include <../github/github_getliblist.h>
52 #endif
53 
54 // a key to store the default Kicad Github libs URL
55 #define KICAD_FPLIBS_URL_KEY wxT( "kicad_fplib_url" )
56 #define KICAD_FPLIBS_LAST_DOWNLOAD_DIR wxT( "kicad_fplib_last_download_dir" )
57 
58 // Filters for the file picker
59 static const int FILTER_COUNT = 4;
60 static const struct
61 {
62  wxString m_Description;
63  wxString m_Extension;
64  bool m_IsFile;
67 {
68  { "KiCad (folder with .kicad_mod files)", "kicad_mod", false, IO_MGR::KICAD_SEXP },
69  { "Eagle 6.x (*.lbr)", "lbr", true, IO_MGR::EAGLE },
70  { "KiCad legacy (*.mod)", "mod", true, IO_MGR::LEGACY },
71  { "Geda (folder with *.fp files)", "fp", false, IO_MGR::GEDA_PCB },
72 };
73 
74 
75 // Returns the filter string for the file picker
76 static wxString getFilterString()
77 {
78  wxString filterInit = _( "All supported library formats|" );
79  wxString filter;
80 
81  for( int i = 0; i < FILTER_COUNT; ++i )
82  {
83  // Init part
84  if( i != 0 )
85  filterInit += ";";
86 
87  filterInit += "*." + fileFilters[i].m_Extension;
88 
89  // Rest of the filter string
90  filter += "|" + fileFilters[i].m_Description +
91  "|" + ( fileFilters[i].m_IsFile ? "*." + fileFilters[i].m_Extension : "" );
92  }
93 
94  return filterInit + filter;
95 }
96 
97 
98 // Tries to guess the plugin type basing on the path
99 static OPT<IO_MGR::PCB_FILE_T> getPluginType( const wxString& aPath )
100 {
101  if( ( aPath.StartsWith( "http://" ) || aPath.StartsWith( "https://" ) ) )
103 
104  wxFileName path( aPath );
105 
106  for( int i = 0; i < FILTER_COUNT; ++i )
107  {
108  bool ok = false;
109 
110  if( fileFilters[i].m_IsFile )
111  {
112  ok = path.IsFileReadable() && path.GetExt() == fileFilters[i].m_Extension;
113  }
114  else if( path.IsDirReadable() )
115  {
116  // Plugin expects a directory containing files with a specific extension
117  wxDir dir( aPath );
118 
119  if( dir.IsOpened() )
120  {
121  wxString filename;
122 
123  dir.GetFirst( &filename, "*." + fileFilters[i].m_Extension, wxDIR_FILES );
124 
125  ok = !filename.IsEmpty();
126  }
127  }
128 
129  if( ok )
130  return OPT<IO_MGR::PCB_FILE_T>( fileFilters[i].m_Plugin );
131  }
132 
133  return NULLOPT;
134 }
135 
136 
137 // Checks if a filename fits specific filter
138 static bool passesFilter( const wxString& aFileName, int aFilterIndex )
139 {
140  wxASSERT( aFilterIndex <= FILTER_COUNT );
141  wxFileName file( aFileName );
142  OPT<IO_MGR::PCB_FILE_T> result = getPluginType( aFileName );
143 
144  if( !result ) // does not match any supported plugin
145  return false;
146 
147  if( aFilterIndex == 0 ) // any plugin will do
148  return true;
149 
150  return ( fileFilters[aFilterIndex - 1].m_Plugin == *result );
151 }
152 
153 
154 WIZARD_FPLIB_TABLE::LIBRARY::LIBRARY( const wxString& aPath, const wxString& aDescription ) :
155  m_path( aPath ), m_description( aDescription ), m_status( NOT_CHECKED )
156 {
157  m_plugin = getPluginType( aPath );
158 }
159 
160 
162 {
163  if( !m_plugin )
164  {
165  m_status = LIBRARY::INVALID;
166  return false;
167  }
168 
169  PLUGIN* p = IO_MGR::PluginFind( *m_plugin );
170  wxArrayString footprints;
171 
172  if( !p )
173  {
174  m_status = LIBRARY::INVALID;
175  return false;
176  }
177 
178  try
179  {
180  p->FootprintEnumerate( footprints, m_path );
181  }
182  catch( IO_ERROR& )
183  {
184  m_status = LIBRARY::INVALID;
185  return false;
186  }
187 
188  if( footprints.GetCount() == 0 )
189  {
190  m_status = LIBRARY::INVALID;
191  return false;
192  }
193 
194  m_status = LIBRARY::OK;
195  return true;
196 }
197 
198 
200 {
201  if( !m_plugin )
202  return _( "UNKNOWN" );
203 
204  switch( *m_plugin )
205  {
206  case IO_MGR::LEGACY:
207  return wxT( "Legacy" );
208 
209  case IO_MGR::KICAD_SEXP:
210  return wxT( "KiCad" );
211 
212  case IO_MGR::EAGLE:
213  return wxT( "Eagle" );
214 
215  case IO_MGR::GEDA_PCB:
216  return wxT( "Geda-PCB" );
217 
218  case IO_MGR::GITHUB:
219  return wxT( "Github" );
220 
221  default:
222  return _( "UNKNOWN" );
223  }
224 
225  /*PLUGIN* p = IO_MGR::PluginFind( *m_plugin );
226 
227  if( !p )
228  return _( "UNKNOWN" );
229 
230  return p->PluginName();*/
231 }
232 
233 
234 wxString WIZARD_FPLIB_TABLE::LIBRARY::GetRelativePath( const wxString& aBase, const wxString& aSubstitution ) const
235 {
236  wxFileName libPath( m_path );
237 
238  // Check if the library path belongs to the project folder
239  if( libPath.MakeRelativeTo( aBase ) && !libPath.GetFullPath().StartsWith( ".." ) )
240  {
241  return wxString( aSubstitution + "/" + libPath.GetFullPath() );
242  }
243 
244  // Probably on another drive, so the relative path will not work
245  return wxEmptyString;
246 }
247 
248 
250 {
251  const wxString& global_env = FP_LIB_TABLE::GlobalPathEnvVariableName();
252  const wxString& project_env = PROJECT_VAR_NAME;
253  const wxString& github_env( "KIGITHUB" );
254 
255  wxString rel_path;
256 
257  // KISYSMOD check
258  rel_path = replaceEnv( global_env );
259 
260  if( !rel_path.IsEmpty() )
261  return rel_path;
262 
263  // KIGITHUB check
264  rel_path = replaceEnv( github_env, false );
265 
266  if( !rel_path.IsEmpty() )
267  return rel_path;
268 
269  // KIPRJMOD check
270  if( aScope == PROJECT )
271  {
272  rel_path = replaceEnv( project_env );
273 
274  if( !rel_path.IsEmpty() )
275  return rel_path;
276  }
277 
278  // Return the full path
279  return m_path;
280 }
281 
282 
284 {
285  if( !m_description.IsEmpty() )
286  return m_description;
287 
288  wxFileName filename( m_path );
289  return filename.GetName();
290 }
291 
292 
293 wxString WIZARD_FPLIB_TABLE::LIBRARY::replaceEnv( const wxString& aEnvVar, bool aFilePath ) const
294 {
295  wxString env_path;
296 
297  if( !wxGetEnv( aEnvVar, &env_path ) )
298  return wxEmptyString;
299 
300  //return GetRelativePath( m_path, wxString( "$(" + aEnvVar + ")" ) );
301 
302  wxString result( m_path );
303 
304  if( result.Replace( env_path, wxString( "$(" + aEnvVar + ")" ) ) )
305  return result;
306 
307  return wxEmptyString;
308 }
309 
310 
312  WIZARD_FPLIB_TABLE_BASE( aParent ), m_welcomeDlg( m_pages[0] ),
315 {
316  m_filePicker->SetFilter( getFilterString() );
317 
318  // Initialize default download dir
319  wxString default_path;
320  wxGetEnv( FP_LIB_TABLE::GlobalPathEnvVariableName(), &default_path );
321  setDownloadDir( default_path );
322  m_filePicker->SetPath( default_path );
323 
324  // Restore the Github url
325  wxString githubUrl;
326 
327  wxConfigBase* cfg = Pgm().CommonSettings();
328  cfg->Read( KICAD_FPLIBS_URL_KEY, &githubUrl );
330 
331 
332  if( !m_lastGithubDownloadDirectory.IsEmpty() )
333  {
336  } else {
337  m_lastGithubDownloadDirectory = default_path;
338  }
339 
340  if( githubUrl.IsEmpty() )
341  githubUrl = wxT( "https://github.com/KiCad" );
342 
343  SetGithubURL( githubUrl );
344 
345  // Give the minimal size to the dialog, which allows displaying any page
346  wxSize minsize;
347 
348  for( unsigned ii = 0; ii < m_pages.size(); ii++ )
349  {
350  wxSize size = m_pages[ii]->GetSizer()->CalcMin();
351  minsize.x = std::max( minsize.x, size.x );
352  minsize.y = std::max( minsize.y, size.y );
353  }
354 
355  SetMinSize( minsize );
356  SetPageSize( minsize );
357  GetSizer()->SetSizeHints( this );
358  Center();
359 
360  if( !m_radioAddGithub->GetValue() && !m_radioAddLocal->GetValue() )
361  m_radioAddLocal->SetValue( true );
362 
365 
366  Connect( wxEVT_RADIOBUTTON, wxCommandEventHandler( WIZARD_FPLIB_TABLE::OnSourceCheck ), NULL, this );
367  Connect( wxEVT_DIRCTRL_SELECTIONCHANGED, wxCommandEventHandler( WIZARD_FPLIB_TABLE::OnSelectFiles ), NULL, this );
368  Connect( wxEVT_CHECKLISTBOX, wxCommandEventHandler( WIZARD_FPLIB_TABLE::OnCheckGithubList ), NULL, this );
369 }
370 
371 
373 {
374  // Use this if you want to store kicad lib URL in pcbnew/cvpcb section config:
375 // wxConfigBase* cfg = Kiface().KifaceSettings();
376 
377  // Use this if you want to store kicad lib URL in common section config:
378  wxConfigBase* cfg = Pgm().CommonSettings();
379  cfg->Write( KICAD_FPLIBS_URL_KEY, GetGithubURL() );
380 }
381 
382 
384 {
385  if( m_radioAddGithub->GetValue() )
386  return GITHUB;
387 
388  wxASSERT( m_radioAddLocal->GetValue() );
389 
390  return LOCAL;
391 }
392 
393 
395 {
396  if( m_radioGlobal->GetValue() )
397  return GLOBAL;
398 
399  wxASSERT( m_radioProject->GetValue() );
400 
401  return PROJECT;
402 }
403 
404 
405 void WIZARD_FPLIB_TABLE::OnPageChanged( wxWizardEvent& aEvent )
406 {
407  SetBitmap( KiBitmap( wizard_add_fplib_icon_xpm ) );
408  enableNext( true );
409 
410 #ifdef BUILD_GITHUB_PLUGIN
411  if( GetCurrentPage() == m_githubListDlg )
412  setupGithubList();
413  else
414 #endif
415  if( GetCurrentPage() == m_fileSelectDlg )
416  setupFileSelect();
417  else if( GetCurrentPage() == m_reviewDlg )
418  setupReview();
419 }
420 
421 
422 void WIZARD_FPLIB_TABLE::OnSelectFiles( wxCommandEvent& aEvent )
423 {
424  int filterIdx = m_filePicker->GetFilterIndex();
425 
426  if( m_selectedFilter != filterIdx )
427  {
428  m_selectedFilter = filterIdx;
429 
430  // Process the event again, as in the first iteration we cannot get the list of selected items
431  wxCommandEvent ev( wxEVT_DIRCTRL_SELECTIONCHANGED );
432  AddPendingEvent( ev );
433  return;
434  }
435 
436  enableNext( checkFiles() );
437 }
438 
439 
440 void WIZARD_FPLIB_TABLE::OnCheckGithubList( wxCommandEvent& aEvent )
441 {
442  wxArrayInt dummy;
443 
444  enableNext( m_checkListGH->GetCheckedItems( dummy ) > 0 );
445 }
446 
447 
448 void WIZARD_FPLIB_TABLE::OnSourceCheck( wxCommandEvent& aEvent )
449 {
452 }
453 
454 
455 void WIZARD_FPLIB_TABLE::OnSelectAllGH( wxCommandEvent& aEvent )
456 {
457  for( unsigned int i = 0; i < m_checkListGH->GetCount(); ++i )
458  m_checkListGH->Check( i, true );
459 
460  // The list might be empty, e.g. in case of download error
461  wxArrayInt dummy;
462  enableNext( m_checkListGH->GetCheckedItems( dummy ) > 0 );
463 }
464 
465 
466 void WIZARD_FPLIB_TABLE::OnUnselectAllGH( wxCommandEvent& aEvent )
467 {
468  for( unsigned int i = 0; i < m_checkListGH->GetCount(); ++i )
469  m_checkListGH->Check( i, false );
470 
471  enableNext( false );
472 }
473 
474 
475 void WIZARD_FPLIB_TABLE::OnChangeSearch( wxCommandEvent& aEvent )
476 {
477  wxString searchPhrase = m_searchCtrlGH->GetValue().Lower();
478 
479  // Store the current selection
480  wxArrayInt checkedIndices;
481  m_checkListGH->GetCheckedItems( checkedIndices );
482  wxArrayString checkedStrings;
483 
484  for( unsigned int i = 0; i < checkedIndices.GetCount(); ++i )
485  checkedStrings.Add( m_checkListGH->GetString( checkedIndices[i] ).AfterLast( '/' ) );
486 
487  m_checkListGH->Clear();
488 
489  // Rebuild the list, putting the matching entries on the top
490  int matching = 0; // number of entries matching the search phrase
491  for( unsigned int i = 0; i < m_githubLibs.GetCount(); ++i )
492  {
493  const wxString& lib = m_githubLibs[i].AfterLast( '/' );
494  bool wasChecked = ( checkedStrings.Index( lib ) != wxNOT_FOUND );
495  int insertedIdx = -1;
496 
497  if( !searchPhrase.IsEmpty() && lib.Lower().Contains( searchPhrase ) )
498  {
499  insertedIdx = m_checkListGH->Insert( lib, matching++ );
500  m_checkListGH->SetSelection( insertedIdx );
501  }
502  else
503  insertedIdx = m_checkListGH->Append( lib );
504 
505  if( wasChecked )
506  m_checkListGH->Check( insertedIdx );
507  }
508 
509  if( !m_checkListGH->IsEmpty() )
510  m_checkListGH->EnsureVisible( 0 );
511 }
512 
513 
514 void WIZARD_FPLIB_TABLE::OnWizardFinished( wxWizardEvent& aEvent )
515 {
516 #ifdef BUILD_GITHUB_PLUGIN
517  // Shall we download a localy copy of the libraries
518  if( GetLibSource() == GITHUB && m_downloadGithub->GetValue() )
519  {
520  wxString error;
521  wxArrayString libs;
522 
523  // Prepare a list of libraries to download
524  for( std::vector<LIBRARY>::const_iterator it = m_libraries.begin();
525  it != m_libraries.end(); ++it )
526  {
527  wxASSERT( it->GetPluginType() == IO_MGR::GITHUB );
528 
529  if( it->GetStatus() != LIBRARY::INVALID )
530  libs.Add( it->GetAbsolutePath() );
531  }
532 
533  if( !downloadGithubLibsFromList( libs, &error ) )
534  {
535  DisplayError( this, error );
536  m_libraries.clear();
537  }
538  else
539  {
540  // Now libraries are stored locally, so update the paths to point to the download folder
541  for( std::vector<LIBRARY>::iterator it = m_libraries.begin();
542  it != m_libraries.end(); ++it )
543  {
544  wxString path = it->GetAbsolutePath();
545  path.Replace( GetGithubURL(), getDownloadDir() );
546  it->setPath( path );
547  it->setPluginType( IO_MGR::KICAD_SEXP );
548  }
549  }
550  }
551 #endif
552 }
553 
554 
555 void WIZARD_FPLIB_TABLE::OnBrowseButtonClick( wxCommandEvent& aEvent )
556 {
557  wxString path = getDownloadDir();
558 
559  path = wxDirSelector( _("Choose a folder to save the downloaded libraries" ),
560  path, 0, wxDefaultPosition, this );
561 
562  if( !path.IsEmpty() && wxDirExists( path ) )
563  {
564  setDownloadDir( path );
565 
566  wxConfigBase* cfg = Pgm().CommonSettings();
567  cfg->Write( KICAD_FPLIBS_LAST_DOWNLOAD_DIR, path );
568 
570  }
571 }
572 
573 
574 void WIZARD_FPLIB_TABLE::OnCheckSaveCopy( wxCommandEvent& aEvent )
575 {
577 }
578 
579 
581 {
582  // Get current selection (files & directories)
583  wxArrayString candidates;
584  m_filePicker->GetPaths( candidates );
585 
586  // Workaround, when you change filters "/" is automatically selected
587  int slash_index = candidates.Index( "/", true, true );
588  if( slash_index != wxNOT_FOUND )
589  candidates.RemoveAt( slash_index, 1 );
590 
591  if( candidates.IsEmpty() )
592  return false;
593 
594  // Verify all the files/folders comply to the selected library type filter
595  for( unsigned int i = 0; i < candidates.GetCount(); ++i )
596  {
597  if( !passesFilter( candidates[i], m_filePicker->GetFilterIndex() ) )
598  return false;
599  }
600 
601  return true;
602 }
603 
604 
605 #ifdef BUILD_GITHUB_PLUGIN
606 void WIZARD_FPLIB_TABLE::getLibsListGithub( wxArrayString& aList )
607 {
608  wxBeginBusyCursor();
609 
610  // Be sure there is no trailing '/' at the end of the repo name
611  wxString git_url = m_textCtrlGithubURL->GetValue();
612 
613  if( git_url.EndsWith( wxT( "/" ) ) )
614  {
615  git_url.RemoveLast();
616  m_textCtrlGithubURL->SetValue( git_url );
617  }
618 
619  GITHUB_GETLIBLIST getter( git_url );
620  getter.GetFootprintLibraryList( aList );
621 
622  wxEndBusyCursor();
623 }
624 
625 
626 // Download the .pretty libraries found in aUrlLis and store them on disk
627 // in a master folder
628 bool WIZARD_FPLIB_TABLE::downloadGithubLibsFromList( wxArrayString& aUrlList,
629  wxString* aErrorMessage )
630 {
631  // Display a progress bar to show the downlaod state
632  wxProgressDialog pdlg( _( "Downloading libraries" ), wxEmptyString, aUrlList.GetCount() );
633 
634  // Download libs:
635  for( unsigned ii = 0; ii < aUrlList.GetCount(); ii++ )
636  {
637  wxString& libsrc_name = aUrlList[ii];
638  wxString libdst_name;
639 
640  // Extract the lib name from the full URL:
641  wxURI url( libsrc_name );
642  wxFileName fn( url.GetPath() );
643  // Set our local path
644  fn.SetPath( getDownloadDir() );
645  libdst_name = fn.GetFullPath();
646 
647  if( !wxDirExists( libdst_name ) )
648  wxMkdir( libdst_name );
649 
650  pdlg.Update( ii, libsrc_name );
651  pdlg.Refresh();
652  pdlg.Update();
653 
654  try
655  {
658 
659  wxArrayString footprints;
660 
661  src->FootprintEnumerate( footprints, libsrc_name );
662 
663  for( unsigned i = 0; i < footprints.size(); ++i )
664  {
665  std::unique_ptr<MODULE> m( src->FootprintLoad( libsrc_name, footprints[i] ) );
666  dst->FootprintSave( libdst_name, m.get() );
667  // m is deleted here by unique_ptr.
668  }
669  }
670  catch( const IO_ERROR& ioe )
671  {
672  if( aErrorMessage )
673  aErrorMessage->Printf( _( "Error:\n'%s'\nwhile downloading library:\n'%s'" ),
674  GetChars( ioe.What() ), GetChars( libsrc_name ) );
675  return false;
676  }
677  }
678 
679  return true;
680 }
681 
682 
684 {
685  // Enable 'Next' only if there is at least one library selected
686  wxArrayInt checkedIndices;
687  m_checkListGH->GetCheckedItems( checkedIndices );
688  enableNext( checkedIndices.GetCount() > 0 );
689 
690  // Update only if necessary
691  if( m_githubLibs.GetCount() == 0 )
693 
694  m_searchCtrlGH->Clear();
695 
696  // Clear the review list so it will be reloaded
697  m_libraries.clear();
698  m_listCtrlReview->DeleteAllItems();
699 }
700 #endif /* BUILD_GITHUB_PLUGIN */
701 
702 
704 {
705 #ifndef BUILD_GITHUB_PLUGIN
706  m_radioAddGithub->Enable( false );
707 #endif
708 
709  // Disable inputs that have no meaning for the selected source
710  bool githubEnabled = ( GetLibSource() == GITHUB );
711  m_textCtrlGithubURL->Enable( githubEnabled );
712  m_downloadGithub->Enable( githubEnabled );
713  m_downloadDir->Enable( githubEnabled && wantLocalCopy() );
714  m_btnBrowse->Enable( githubEnabled && wantLocalCopy() );
715 
716  bool valid = !( githubEnabled && wantLocalCopy() ) || wxFileName::IsDirWritable( getDownloadDir() );
717 
718  // Do not allow to go further unless there is a valid directory selected
719  m_invalidDir->Show( !valid );
720  enableNext( valid );
721 }
722 
723 
725 {
726  // No need to update, the review list is ready
727  if( m_listCtrlReview->GetItemCount() != 0 )
728  return;
729 
730  switch( GetLibSource() )
731  {
732  case LOCAL:
733  {
734  wxArrayString libs;
735  m_filePicker->GetPaths( libs );
736 
737  // Workaround, when you change filters "/" is automatically selected
738  int slash_index = libs.Index( "/", true, true );
739  if( slash_index != wxNOT_FOUND )
740  libs.RemoveAt( slash_index, 1 );
741 
742  m_libraries.reserve( libs.GetCount() );
743 
744  for( unsigned int i = 0; i < libs.GetCount(); ++i )
745  m_libraries.push_back( libs[i] );
746  }
747  break;
748 
749  case GITHUB:
750  {
751  wxArrayInt checkedLibs;
752  m_checkListGH->GetCheckedItems( checkedLibs );
753 
754  m_libraries.reserve( checkedLibs.GetCount() );
755 
756  for( unsigned int i = 0; i < checkedLibs.GetCount(); ++i )
757  m_libraries.push_back( GetGithubURL() + "/" + m_checkListGH->GetString( checkedLibs[i] ) );
758  }
759  break;
760 
761  default:
762  wxASSERT( false );
763  break;
764  }
765 }
766 
767 
769 {
770  // Alternate the wizard pages flow depending on the selected option
771  switch( GetLibSource() )
772  {
773  case LOCAL:
774  m_welcomeDlg->SetNext( m_fileSelectDlg );
775  m_fileSelectDlg->SetPrev( m_welcomeDlg );
776 
777  m_fileSelectDlg->SetNext( m_reviewDlg );
778  m_reviewDlg->SetPrev( m_fileSelectDlg );
779  break;
780 
781  case GITHUB:
782  m_welcomeDlg->SetNext( m_githubListDlg );
783  m_githubListDlg->SetPrev( m_welcomeDlg );
784 
785  m_githubListDlg->SetNext( m_reviewDlg );
786  m_reviewDlg->SetPrev( m_githubListDlg );
787  break;
788 
789  default:
790  wxASSERT( false );
791  break;
792  }
793 }
794 
795 
797 {
798  // Disable the button until something is selected
799  enableNext( checkFiles() );
800 
801  // Clear the review list so it will be reloaded
802  m_libraries.clear();
803  m_listCtrlReview->DeleteAllItems();
804 }
805 
806 
808 {
809  wxBeginBusyCursor();
810  updateLibraries();
811 
812  int libTotalCount = m_libraries.size();
813  int libCount = 0;
814  bool validate = true;
815  wxProgressDialog progressDlg( _( "Please wait..." ), _( "Validating libraries" ),
816  libTotalCount, this,
817  wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_AUTO_HIDE );
818 
819  m_dvLibName->SetWidth( 280 );
820 
821  // Prepare the review list
822  m_listCtrlReview->DeleteAllItems();
823 
824  for( std::vector<LIBRARY>::iterator it = m_libraries.begin(); it != m_libraries.end(); ++it )
825  {
826  wxVector<wxVariant> row;
827  LIBRARY::STATUS status = it->GetStatus();
828 
829  // Check if the library contents is valid
830  if( status == LIBRARY::NOT_CHECKED && validate )
831  {
832  it->Test();
833  status = it->GetStatus();
834  }
835 
836  row.push_back( wxVariant( it->GetDescription() ) );
837 
838  switch( it->GetStatus() )
839  {
841  row.push_back( wxVariant( _( "NOT CHECKED" ) ) );
842  break;
843 
844  case LIBRARY::OK:
845  row.push_back( wxVariant( _( "OK" ) ) );
846  break;
847 
848  case LIBRARY::INVALID:
849  row.push_back( wxVariant( _( "INVALID" ) ) );
850  break;
851  }
852 
853  row.push_back( wxVariant( it->GetPluginName() ) );
854 
855  m_listCtrlReview->AppendItem( row );
856 
857  ++libCount;
858  if( !progressDlg.Update( libCount, wxString::Format( _( "Validating libraries %d/%d" ),
859  libCount, libTotalCount ) ) )
860  validate = false;
861  }
862 
863  // The list should never be empty, but who knows?
864  enableNext( m_listCtrlReview->GetItemCount() > 0 );
865 
866  wxEndBusyCursor();
867 }
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 'Next' 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
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
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:57
wxWizardPageSimple *const m_targetDlg
void OnSelectAllGH(wxCommandEvent &aEvent) override
wxGenericDirCtrl * m_filePicker
void OnWizardFinished(wxWizardEvent &aEvent) override
Class RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destruct...
Definition: io_mgr.h:546
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:36
static const struct @14 fileFilters[FILTER_COUNT]
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
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:53
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
Class PLUGIN is a base class that BOARD loading and saving plugins should derive from.
Definition: io_mgr.h:265
VTBL_ENTRY wxConfigBase * CommonSettings() const
Definition: pgm_base.h:145
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:51
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:73
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:58
void OnBrowseButtonClick(wxCommandEvent &aEvent) override
Class GITHUB_GETLIBLIST implements a portion of pcbnew's PLUGIN interface to provide read only access...
S-expression Pcbnew file format.
Definition: io_mgr.h:54
#define KICAD_FPLIBS_URL_KEY
Wizard for selecting footprint libraries consisting of 4 steps:
void updateGithubControls()
Enables Github widgets depending on the selected options.