summaryrefslogtreecommitdiff
path: root/pcbnew/dialogs/wizard_3DShape_Libs_downloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'pcbnew/dialogs/wizard_3DShape_Libs_downloader.cpp')
-rw-r--r--pcbnew/dialogs/wizard_3DShape_Libs_downloader.cpp543
1 files changed, 543 insertions, 0 deletions
diff --git a/pcbnew/dialogs/wizard_3DShape_Libs_downloader.cpp b/pcbnew/dialogs/wizard_3DShape_Libs_downloader.cpp
new file mode 100644
index 0000000..08e61ff
--- /dev/null
+++ b/pcbnew/dialogs/wizard_3DShape_Libs_downloader.cpp
@@ -0,0 +1,543 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2015 CERN
+ * Code derived from "wizard_add_fplib.cpp" ( author Maciej Suminski <maciej.suminski@cern.ch> )
+ * Copyright (C) 2014-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 Wizard for selecting and dowloading D shapes libraries of footprints
+ * consisting of 3 steps:
+ * - select source and destination (Github URL and local folder)
+ * - pick and select libraries
+ * - download files
+ */
+
+#include <wx/wx.h>
+#include <wx/uri.h>
+#include <wx/dir.h>
+#include <wx/progdlg.h>
+
+#include <pgm_base.h>
+#include <project.h>
+#include <wizard_3DShape_Libs_downloader.h>
+#include <confirm.h>
+#include <3d_viewer.h>
+
+#include <../github/github_getliblist.h>
+
+// a key to store the default Kicad Github 3D libs URL
+#define KICAD_3DLIBS_URL_KEY wxT( "kicad_3Dlib_url" )
+#define KICAD_3DLIBS_LAST_DOWNLOAD_DIR wxT( "kicad_3Dlib_last_download_dir" )
+
+#define DEFAULT_GITHUB_3DSHAPES_LIBS_URL \
+ wxT( "https://github.com/KiCad/kicad-library/tree/master/modules/packages3d" )
+
+void Invoke3DShapeLibsDownloaderWizard( wxTopLevelWindow* aParent )
+{
+ WIZARD_3DSHAPE_LIBS_DOWNLOADER wizard( aParent );
+ wizard.RunWizard( wizard.GetFirstPage() );
+}
+
+
+WIZARD_3DSHAPE_LIBS_DOWNLOADER::WIZARD_3DSHAPE_LIBS_DOWNLOADER( wxWindow* aParent ) :
+ WIZARD_3DSHAPE_LIBS_DOWNLOADER_BASE( aParent )
+{
+ m_welcomeDlg = m_pages[0];
+ m_githubListDlg = m_pages[1];
+ m_reviewDlg = m_pages[2];
+
+ // Initialize default download dir (local target folder of 3D shapes libs)
+ wxString default_path;
+ wxGetEnv( KISYS3DMOD, &default_path );
+
+ wxConfigBase* cfg = Pgm().CommonSettings();
+ wxString tmp;
+ cfg->Read( KICAD_3DLIBS_LAST_DOWNLOAD_DIR, &tmp, default_path );
+ setDownloadDir( tmp );
+
+ // Restore the Github 3D shapes libs url
+ wxString githubUrl;
+ cfg->Read( KICAD_3DLIBS_URL_KEY, &githubUrl );
+
+ if( githubUrl.IsEmpty() )
+ githubUrl = DEFAULT_GITHUB_3DSHAPES_LIBS_URL;
+
+ SetGithubURL( githubUrl );
+
+
+ // Give the 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();
+
+ setupDialogOrder();
+ updateGithubControls();
+
+ // When starting m_textCtrlGithubURL has the focus, and the text is selected,
+ // and not fully visible.
+ // Forcing deselection does not work, at least on W7 with wxWidgets 3.0.2
+ // So (and also because m_textCtrlGithubURL and m_downloadDir are rarely modified
+ // the focus is given to an other widget.
+ m_hyperlinkGithubKicad->SetFocus();
+
+ Connect( wxEVT_RADIOBUTTON, wxCommandEventHandler( WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnSourceCheck ), NULL, this );
+ Connect( wxEVT_CHECKLISTBOX, wxCommandEventHandler( WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnCheckGithubList ), NULL, this );
+}
+
+
+WIZARD_3DSHAPE_LIBS_DOWNLOADER::~WIZARD_3DSHAPE_LIBS_DOWNLOADER()
+{
+ // 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_3DLIBS_URL_KEY, GetGithubURL() );
+ cfg->Write( KICAD_3DLIBS_LAST_DOWNLOAD_DIR, getDownloadDir() );
+}
+
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnPageChanged( wxWizardEvent& aEvent )
+{
+ SetBitmap( KiBitmap( wizard_add_fplib_icon_xpm ) );
+ enableNext( true );
+
+ if( GetCurrentPage() == m_githubListDlg )
+ setupGithubList();
+ else if( GetCurrentPage() == m_reviewDlg )
+ setupReview();
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnCheckGithubList( wxCommandEvent& aEvent )
+{
+ wxArrayInt dummy;
+
+ enableNext( m_checkList3Dlibnames->GetCheckedItems( dummy ) > 0 );
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnSourceCheck( wxCommandEvent& aEvent )
+{
+ updateGithubControls();
+ setupDialogOrder();
+}
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnGridLibReviewSize( wxSizeEvent& event )
+{
+ // Adjust the width of the column 1 afo m_gridLibReview (library names) to the
+ // max available width.
+ int gridwidth = m_gridLibReview->GetClientSize().x;
+ gridwidth -= m_gridLibReview->GetColSize( 0 ) + m_gridLibReview->GetColLabelSize();
+
+ if( gridwidth < 200 )
+ gridwidth = 200;
+
+ m_gridLibReview->SetColSize( 1, gridwidth );
+
+ event.Skip();
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::setupReview()
+{
+ // Prepare the last page of the wizard.
+
+ m_LocalFolderInfo->SetLabel( getDownloadDir() );
+
+ wxArrayInt checkedIndices;
+ m_checkList3Dlibnames->GetCheckedItems( checkedIndices );
+
+ m_libraries.Clear();
+
+ // populate m_libraries with the name of libraries, without the github path:
+ for( unsigned int ii = 0; ii < checkedIndices.GetCount(); ++ii )
+ {
+ m_libraries.Add( m_checkList3Dlibnames->GetString( checkedIndices[ii] ).AfterLast( '/' ) );
+ }
+
+ // Adjust number of rows in m_gridLibReview:
+ int delta = m_libraries.GetCount() - m_gridLibReview->GetNumberRows();
+
+ if( delta < 0 )
+ m_gridLibReview->DeleteRows( -delta );
+ else if( delta > 0 )
+ m_gridLibReview->AppendRows( delta );
+
+ // For user info, verify the existence of these libs in local folder
+ wxArrayString liblist;
+ wxFileName fn;
+ fn.AssignDir( getDownloadDir() );
+
+ for( unsigned int ii = 0; ii < m_libraries.GetCount(); ++ii )
+ {
+ fn.SetName( m_libraries[ii] );
+
+ wxDir dirs;
+ bool isNew = ! dirs.Exists( fn.GetFullPath() );
+ wxString info = isNew ? _( "New" ) : _( "Update" );
+
+ liblist.Add( info + wxT(" ") + m_libraries[ii] );
+
+ m_gridLibReview->SetCellValue( ii, 0, info );
+ m_gridLibReview->SetCellValue( ii, 1, m_libraries[ii] );
+ }
+
+ m_gridLibReview->AutoSizeColumn( 0 );
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnSelectAll3Dlibs( wxCommandEvent& aEvent )
+{
+ for( unsigned int i = 0; i < m_checkList3Dlibnames->GetCount(); ++i )
+ m_checkList3Dlibnames->Check( i, true );
+
+ // The list might be empty, e.g. in case of download error
+ wxArrayInt dummy;
+ enableNext( m_checkList3Dlibnames->GetCheckedItems( dummy ) > 0 );
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnUnselectAll3Dlibs( wxCommandEvent& aEvent )
+{
+ for( unsigned int i = 0; i < m_checkList3Dlibnames->GetCount(); ++i )
+ m_checkList3Dlibnames->Check( i, false );
+
+ enableNext( false );
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnChangeSearch( wxCommandEvent& aEvent )
+{
+ wxString searchPhrase = m_searchCtrl3Dlibs->GetValue().Lower();
+
+ // Store the current selection
+ wxArrayInt checkedIndices;
+ m_checkList3Dlibnames->GetCheckedItems( checkedIndices );
+ wxArrayString checkedStrings;
+
+ for( unsigned int i = 0; i < checkedIndices.GetCount(); ++i )
+ checkedStrings.Add( m_checkList3Dlibnames->GetString( checkedIndices[i] ).AfterLast( '/' ) );
+
+ m_checkList3Dlibnames->Clear();
+
+ // Rebuild the list, putting the matching entries on the top
+ int matching = 0; // number of entries matching the search phrase
+ for( unsigned int i = 0; i < m_githubLibs.GetCount(); ++i )
+ {
+ const wxString& lib = m_githubLibs[i].AfterLast( '/' );
+ bool wasChecked = ( checkedStrings.Index( lib ) != wxNOT_FOUND );
+ int insertedIdx = -1;
+
+ if( !searchPhrase.IsEmpty() && lib.Lower().Contains( searchPhrase ) )
+ {
+ insertedIdx = m_checkList3Dlibnames->Insert( lib, matching++ );
+ m_checkList3Dlibnames->SetSelection( insertedIdx );
+ }
+ else
+ insertedIdx = m_checkList3Dlibnames->Append( lib );
+
+ if( wasChecked )
+ m_checkList3Dlibnames->Check( insertedIdx );
+ }
+
+ if( !m_checkList3Dlibnames->IsEmpty() )
+ m_checkList3Dlibnames->EnsureVisible( 0 );
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnWizardFinished( wxWizardEvent& aEvent )
+{
+ // we download a localy copy of the libraries
+ wxString error;
+
+ if( !downloadGithubLibsFromList( m_libraries, &error ) )
+ {
+ DisplayError( GetParent(), error );
+ }
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnBrowseButtonClick( wxCommandEvent& aEvent )
+{
+ wxString path = getDownloadDir();
+
+ path = wxDirSelector( _("Choose a folder to save the downloaded libraries" ),
+ path, 0, wxDefaultPosition, this );
+
+ if( !path.IsEmpty() && wxDirExists( path ) )
+ {
+ setDownloadDir( path );
+ updateGithubControls();
+ }
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnDefault3DPathButtonClick( wxCommandEvent& event )
+{
+ wxString default_path;
+ wxGetEnv( KISYS3DMOD, &default_path );
+
+ if( !default_path.IsEmpty() && wxDirExists( default_path ) )
+ {
+ setDownloadDir( default_path );
+ updateGithubControls();
+ }
+ else
+ wxMessageBox( _( "KISYS3DMOD path not defined , or not existing" ) );
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnCheckSaveCopy( wxCommandEvent& aEvent )
+{
+ updateGithubControls();
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::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 );
+ getter.Get3DshapesLibsList( &aList, filter3dshapeslibraries );
+
+ wxEndBusyCursor();
+}
+
+
+// Download the .pretty libraries folders found in aUrlList and store them on disk
+// in a master folder
+bool WIZARD_3DSHAPE_LIBS_DOWNLOADER::downloadGithubLibsFromList( wxArrayString& aUrlList,
+ wxString* aErrorMessage )
+{
+ // Display a progress bar to show the download state
+ // The title is updated for each downloaded library.
+ // the state will be updated by downloadOneLib() for each file.
+ wxProgressDialog pdlg( _( "Downloading 3D libraries" ), wxEmptyString,
+ aUrlList.GetCount(), GetParent(),
+ wxPD_CAN_ABORT | wxPD_APP_MODAL | wxPD_AUTO_HIDE );
+
+ wxString url_base = GetGithubURL();
+
+ // Download libs:
+ for( unsigned ii = 0; ii < aUrlList.GetCount(); ii++ )
+ {
+ wxString& libsrc_name = aUrlList[ii];
+
+ // Extract the lib name from the full URL:
+ wxString url = GetGithubURL() + wxT( "/" ) + libsrc_name;
+ wxFileName fn( libsrc_name );
+ // Set our local path
+ fn.SetPath( getDownloadDir() );
+ wxString libdst_name = fn.GetFullPath();
+
+ // Display the name of the library to download in the wxProgressDialog
+ pdlg.SetTitle( wxString::Format( wxT("%s [%d/%d]" ),
+ libsrc_name.AfterLast( '/' ).GetData(),
+ ii + 1, aUrlList.GetCount() ) );
+
+ if( !wxDirExists( libdst_name ) )
+ wxMkdir( libdst_name );
+
+ if( !downloadOneLib( url, libdst_name, &pdlg, aErrorMessage ) )
+ return false;
+ }
+
+ return true;
+}
+
+
+bool WIZARD_3DSHAPE_LIBS_DOWNLOADER::downloadOneLib( const wxString& aLibURL,
+ const wxString& aLocalLibName, wxProgressDialog * aIndicator,
+ wxString* aErrorMessage )
+{
+ wxArrayString fileslist;
+
+ bool success;
+
+ // Get the list of candidate files: with ext .wrl or .wings
+ do
+ {
+ GITHUB_GETLIBLIST getter( aLibURL );
+ success = getter.Get3DshapesLibsList( &fileslist, filter3dshapesfiles );
+ } while( 0 );
+
+ if( !success )
+ return false;
+
+ // Load each file in list:
+ wxURI repo( aLibURL );
+
+ wxString server = repo.GetServer();
+
+ // Github gives the current url of files inside .3dshapes folders like:
+ // "https://github.com/KiCad/kicad-library/blob/master/modules/packages3d/Capacitors_SMD.3dshapes/C_0402.wrl"
+ // which displays a html page showing the file in html form.
+ //
+ // the URL of the corresponding raw file is
+ // "https://github.com/KiCad/kicad-library/raw/master/modules/packages3d/Capacitors_SMD.3dshapes/C_0402.wrl"
+ //
+ // However Github redirects this current url to raw.githubusercontent.com/fullfilename
+ // when trying to download raw files.
+ // "https://github.com/KiCad/kicad-library/raw/master/modules/packages3d/Capacitors_SMD.3dshapes/C_0402.wrl"
+ // would be redirected to:
+ // "https://raw.githubusercontent.com/KiCad/kicad-library/master/modules/packages3d/Capacitors_SMD.3dshapes/C_0402.wrl"
+ // So use raw.githubusercontent.com instead of github.com
+ // (and removes the "/raw" in path) speed up the downloads (x2 faster).
+ //
+ // wxURI has no way to change the server name, so we need to use tricks to make the URL.
+ //
+ // Comment this next line to use the github.com URL
+#define FORCE_GITHUB_RAW_URL
+
+#ifdef FORCE_GITHUB_RAW_URL
+ if( server.Cmp( wxT( "github.com" ) ) == 0 )
+ server = wxT( "raw.githubusercontent.com" );
+#endif
+
+ wxString full_url_base = repo.GetScheme() + wxT( "://" ) + server;
+ wxString target_full_url;
+
+ for( unsigned ii = 0; ii < fileslist.GetCount(); ii++ )
+ {
+ target_full_url = full_url_base + fileslist[ii];
+
+#ifdef FORCE_GITHUB_RAW_URL
+ // Remove "blob/" in URL string to build the URL on "raw.githubusercontent.com"
+ // server from "github.com" URL string:
+ target_full_url.Replace( wxT( "blob/" ), wxT( "" ) );
+#else
+ // Replace "blob" by "raw" in URL to access the raw file itself, not the html page
+ // on "github.com" server
+ target_full_url.Replace( wxT( "blob" ), wxT( "raw" ) );
+#endif
+ aIndicator->SetRange( fileslist.GetCount() );
+ bool abort = !aIndicator->Update( ii, target_full_url.AfterLast( '/' ) );
+
+ if( abort )
+ {
+ if( aErrorMessage )
+ *aErrorMessage << _( "Aborted by user" );
+ return false;
+ }
+
+ // Download the current file.
+ // Get3DshapesLibsList actually downloads and stores the target_full_url content.
+ GITHUB_GETLIBLIST getter( target_full_url );
+ success = getter.Get3DshapesLibsList( NULL, NULL );
+
+ if( !success )
+ break;
+
+ wxFileName fn;
+ fn.AssignDir( aLocalLibName );
+ fn.SetFullName( fileslist[ii].AfterLast( '/' ) );
+
+ // The entire downloaded file is stored in getter buffer
+ const std::string& buffer = getter.GetBuffer();
+
+ // Write is "as this". It can be a binary file.
+ wxFile file(fn.GetFullPath(), wxFile::write);
+ file.Write( &buffer[0], buffer.size() );
+ }
+
+ return success;
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::setupGithubList()
+{
+ // Enable 'Next' only if there is at least one library selected
+ wxArrayInt checkedIndices;
+ m_checkList3Dlibnames->GetCheckedItems( checkedIndices );
+ enableNext( checkedIndices.GetCount() > 0 );
+
+ // Update only if necessary
+ if( m_githubLibs.GetCount() == 0 )
+ getLibsListGithub( m_githubLibs );
+
+ m_searchCtrl3Dlibs->Clear();
+
+ // Clear the review list so it will be reloaded
+ m_libraries.clear();
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::updateGithubControls()
+{
+ bool valid = wxFileName::IsDirWritable( getDownloadDir() );
+
+ // Shows or not the warning text if the target 3d folder does not exist, or is not
+ // writable.
+ m_invalidDirWarningText->Show( !valid );
+ m_bitmapDirWarn->Show( !valid );
+
+ // If the dialog starts with m_invalidDirWarningText and m_bitmapDirWarn not shown
+ // the size and position of the sizer containing these widgets can be incorrect,
+ // until a wxSizeEvent is fired, and the widgets are not shown, or truncated,
+ // at least on Windows. So fire a dummy wxSizeEvent if the size looks bad
+ if( m_invalidDirWarningText->IsShown() && m_invalidDirWarningText->GetSize().x < 2 )
+ {
+ wxSizeEvent event( GetSize() );
+ wxPostEvent( this, event );
+ }
+
+ // Allow to go further only if there is a valid target directory selected
+ enableNext( valid );
+}
+
+// Called when the local folder name is edited.
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::OnLocalFolderChange( wxCommandEvent& event )
+{
+ updateGithubControls();
+}
+
+
+void WIZARD_3DSHAPE_LIBS_DOWNLOADER::setupDialogOrder()
+{
+ m_welcomeDlg->SetNext( m_githubListDlg );
+ m_githubListDlg->SetPrev( m_welcomeDlg );
+ m_githubListDlg->SetNext( m_reviewDlg );
+ m_reviewDlg->SetPrev( m_githubListDlg );
+}
+