KiCad PCB EDA Suite
Loading...
Searching...
No Matches
startwizard_provider_libraries.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 * @author Jon Evans <[email protected]>
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <pgm_base.h>
26#include <paths.h>
29
30#include <magic_enum.hpp>
32#include <trace_helpers.h>
33#include <regex>
34#include <set>
35#include <wx/log.h>
36
37
39{
40public:
41 PANEL_STARTWIZARD_LIBRARIES( const std::shared_ptr<STARTWIZARD_PROVIDER_LIBRARIES_MODEL>& aModel,
42 wxWindow* aParent, STARTWIZARD* aWizard ) :
44 m_model( aModel ),
45 m_wizard( aWizard )
46 {
47 wxWindowBase::SetMaxSize( { FromDIP( 640 ), -1 } );
49 m_sizerWarning->Layout();
50
51 Bind( wxEVT_RADIOBUTTON, &PANEL_STARTWIZARD_LIBRARIES::OnModeChanged, this,
52 m_rbDefaultTables->GetId() );
53 Bind( wxEVT_RADIOBUTTON, &PANEL_STARTWIZARD_LIBRARIES::OnModeChanged, this,
54 m_rbImport->GetId() );
55 Bind( wxEVT_RADIOBUTTON, &PANEL_STARTWIZARD_LIBRARIES::OnModeChanged, this,
56 m_rbBlankTables->GetId() );
57
58 m_introText = m_stIntro->GetLabel();
59 m_warningText = m_stWarning->GetLabel();
60
64
65 m_containingSizer->Fit( this );
66 SetSize( GetBestSize() );
67 }
68
69 bool TransferDataFromWindow() override
70 {
71 if( m_rbDefaultTables->GetValue() )
73 else if( m_rbImport->GetValue() )
75 else
77
78 m_model->mode_initialized = true;
79
80 m_model->migrate_built_in_libraries = m_cbMigrateBuiltInLibraries->GetValue();
81
82 return true;
83 }
84
85 bool TransferDataToWindow() override
86 {
87 if( !m_model->mode_initialized )
88 {
89 // If the user is importing settings from a previous version, let's default to taking their
90 // library settings as well, since we can clean up old stock paths now.
91 if( auto settings = dynamic_cast<STARTWIZARD_PROVIDER_SETTINGS*>( m_wizard->GetProvider( "settings" ) ) )
92 {
93 if( settings->NeedsUserInput() )
95 else
97 }
98
99 m_model->mode_initialized = true;
100 }
101
102 switch( m_model->mode )
103 {
104 case STARTWIZARD_LIBRARIES_MODE::USE_DEFAULTS: m_rbDefaultTables->SetValue( true ); break;
105 case STARTWIZARD_LIBRARIES_MODE::IMPORT: m_rbImport->SetValue( true ); break;
106 case STARTWIZARD_LIBRARIES_MODE::CREATE_BLANK: m_rbBlankTables->SetValue( true ); break;
107 }
108
109 m_cbMigrateBuiltInLibraries->SetValue( m_model->migrate_built_in_libraries );
110
111 if( auto settings = dynamic_cast<STARTWIZARD_PROVIDER_SETTINGS*>( m_wizard->GetProvider( "settings" ) ) )
112 {
113 if( !settings->NeedsUserInput() )
114 {
115 // If the user didn't see the settings screen at all, just hide this option; we
116 // only offer import when we have the context of a previous version settings
117 // path selected by the user
118 m_rbImport->Show( false );
119 m_cbMigrateBuiltInLibraries->Show( false );
120 }
121 else if( settings->GetModel().mode == STARTWIZARD_SETTINGS_MODE::USE_DEFAULTS )
122 {
123 // But if they did see the screen and chose not to import, show the option but
124 // disable it as a breadcrumb that they can go back and choose to import settings
125 m_rbImport->Disable();
126
127 if( m_rbImport->GetValue() )
128 m_rbDefaultTables->SetValue( true );
129 }
130 else
131 {
132 m_rbImport->Enable();
133 }
134 }
135
137
139 m_stWarning->Show( m_showWarning );
140
141 return true;
142 }
143
145 {
146 wxString missingTablesText;
147 m_showWarning = false;
148
149 for( const LIBRARY_TABLE_TYPE& type : m_model->missing_tables )
150 {
153 {
154 wxLogTrace( traceLibraries, wxT( "Stock table path for %s is not valid; will show warning" ),
155 magic_enum::enum_name( type ) );
156 m_showWarning = true;
157 }
158
159 switch( type )
160 {
162 missingTablesText.Append( _( "Symbol library table" ) + "\n" );
163 break;
164
166 missingTablesText.Append( _( "Footprint library table" ) + "\n" );
167 break;
168
170 missingTablesText.Append( _( "Design Block library table" ) + "\n" );
171 break;
172
174 break;
175 }
176 }
177
178 m_stRequiredTables->SetLabel( missingTablesText.BeforeLast( '\n' ) );
179 }
180
181 void OnSize( wxSizeEvent& aEvt ) override
182 {
183 aEvt.Skip();
184
185 // Wrapping is destructive and the size can change a few times during construction, at least
186 // on macOS. Resetting the label makes wrapping work properly.
187 m_stIntro->SetLabel( m_introText );
188 m_stWarning->SetLabel( m_warningText );
189
190#if defined( __WXMAC__ )
191 m_stIntro->Wrap( GetClientSize().x - FromDIP( 20 ) );
192 m_stWarning->Wrap( GetClientSize().x - m_bmpWarning->GetSize().x - FromDIP( 28 ) );
193#elif defined( __WXMSW__ )
194 m_stIntro->Wrap( GetClientSize().x );
195 m_stWarning->Wrap( GetClientSize().x - m_bmpWarning->GetSize().x - FromDIP( 10 ) );
196#else
197 m_stIntro->Wrap( GetClientSize().x - FromDIP( 10 ) );
198 m_stWarning->Wrap( GetClientSize().x - m_bmpWarning->GetSize().x - FromDIP( 18 ) );
199#endif
200 }
201
202private:
203 void OnModeChanged( wxCommandEvent& aEvt )
204 {
205 aEvt.Skip();
207 }
208
210 {
211 m_cbMigrateBuiltInLibraries->Enable( m_rbImport->IsShown()
212 && m_rbImport->IsEnabled()
213 && m_rbImport->GetValue() );
214 }
215
216 std::shared_ptr<STARTWIZARD_PROVIDER_LIBRARIES_MODEL> m_model;
219 wxString m_introText;
221};
222
223
228
229
234
235
236wxPanel* STARTWIZARD_PROVIDER_LIBRARIES::GetWizardPanel( wxWindow* aParent, STARTWIZARD* aWizard )
237{
238 m_model = std::make_shared<STARTWIZARD_PROVIDER_LIBRARIES_MODEL>();
240 return new PANEL_STARTWIZARD_LIBRARIES( m_model, aParent, aWizard );
241}
242
243
245{
246 bool populateTables = m_model->mode == STARTWIZARD_LIBRARIES_MODE::USE_DEFAULTS;
247
248 if( m_model->mode == STARTWIZARD_LIBRARIES_MODE::IMPORT && m_model->migrate_built_in_libraries )
249 {
251 {
252 wxString tablePath = LIBRARY_MANAGER::DefaultGlobalTablePath( type );
253 wxString stockPath = LIBRARY_MANAGER::StockTablePath( type );
254
255 if( !LIBRARY_MANAGER::IsTableValid( tablePath ) )
256 continue;
257
258 wxFileName tableFile( tablePath );
260
261 if( !table.IsOk() )
262 continue;
263
264 const std::regex builtInPattern( type == LIBRARY_TABLE_TYPE::SYMBOL
265 ? R"(^\$\{KICAD\d+_SYMBOL_DIR\})"
266 : R"(^\$\{KICAD\d+_FOOTPRINT_DIR\})" );
267
268 bool insertStock = true;
269 std::set<wxString> toRemove;
270
271 for( LIBRARY_TABLE_ROW& row : table.Rows() )
272 {
273 if( std::regex_search( row.URI().ToStdString(), builtInPattern ) )
274 {
275 toRemove.insert( row.URI() );
276 wxLogTrace( traceLibraries, wxT( "Libraries migration: removing old stock row '%s'" ), row.URI() );
277 }
278 else if( row.Type() == LIBRARY_TABLE_ROW::TABLE_TYPE_NAME && row.Nickname() == wxT( "KiCad" ) )
279 {
280 insertStock = false;
281
282 if( row.URI().Matches( stockPath ) )
283 {
284 wxLogTrace( traceLibraries,
285 wxT( "Libraries migration: migrated table already has latest stock setup" ) );
286 }
287 else if( LIBRARY_MANAGER::IsTableValid( row.URI() ) && !LIBRARY_MANAGER::IsTableValid( stockPath ) )
288 {
289 wxLogTrace( traceLibraries,
290 wxT( "Libraries migration: migrated table has working stock table at "
291 "'%s' but calculated stock path '%s' is missing or invalid. Leaving alone." ),
292 row.URI(), stockPath );
293 }
294 else
295 {
296 wxLogTrace( traceLibraries,
297 wxT( "Libraries migration: migrated chained table URI from '%s' to '%s'" ),
298 row.URI(), stockPath );
299 row.SetDescription( _( "KiCad Default Libraries" ) );
300 row.SetURI( stockPath );
301 }
302 }
303 }
304
305 auto toErase = std::ranges::remove_if( table.Rows(),
306 [&]( const LIBRARY_TABLE_ROW& aRow )
307 {
308 return toRemove.contains( aRow.URI() );
309 } );
310
311 table.Rows().erase( toErase.begin(), toErase.end() );
312
313 if( insertStock )
314 {
315 wxLogTrace( traceLibraries, wxT( "Libraries migration: inserting chained default table" ) );
316 LIBRARY_TABLE_ROW chained = table.MakeRow();
318 chained.SetNickname( wxT( "KiCad" ) );
319 chained.SetDescription( _( "KiCad Default Libraries" ) );
320 chained.SetURI( stockPath );
321 table.Rows().insert( table.Rows().begin(), chained );
322 }
323
324 if( toRemove.size() || insertStock )
325 {
326 wxLogTrace( traceLibraries, wxT( "Libraries migration: removed %zu rows; saving" ), toRemove.size() );
327 table.Save();
328 }
329 else
330 {
331 wxLogTrace( traceLibraries, wxT( "Libraries migration: no actions needed" ) );
332 }
333 }
334 }
335
337 {
338 LIBRARY_MANAGER::CreateGlobalTable( type, populateTables );
339 }
340}
341
342
350
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Definition bitmap.cpp:110
static wxString DefaultGlobalTablePath(LIBRARY_TABLE_TYPE aType)
static std::vector< LIBRARY_TABLE_TYPE > InvalidGlobalTables()
static bool GlobalTablesValid()
static bool CreateGlobalTable(LIBRARY_TABLE_TYPE aType, bool aPopulateDefaultLibraries)
static wxString StockTablePath(LIBRARY_TABLE_TYPE aType)
static bool IsTableValid(const wxString &aPath)
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetDescription(const wxString &aDescription)
static const wxString TABLE_TYPE_NAME
void SetURI(const wxString &aUri)
PANEL_STARTWIZARD_LIBRARIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
PANEL_STARTWIZARD_LIBRARIES(const std::shared_ptr< STARTWIZARD_PROVIDER_LIBRARIES_MODEL > &aModel, wxWindow *aParent, STARTWIZARD *aWizard)
std::shared_ptr< STARTWIZARD_PROVIDER_LIBRARIES_MODEL > m_model
void OnSize(wxSizeEvent &aEvt) override
std::shared_ptr< STARTWIZARD_PROVIDER_LIBRARIES_MODEL > m_model
wxPanel * GetWizardPanel(wxWindow *aParent, STARTWIZARD *aWizard) override
void ApplyDefaults() override
Apply whatever actions and settings should happen if the user cancels the startup wizard.
STARTWIZARD_PROVIDER(const wxString &aPageName)
#define _(s)
const wxChar *const traceLibraries
Flag to enable library table and library manager tracing.
LIBRARY_TABLE_TYPE
see class PGM_BASE
std::vector< std::vector< std::string > > table
wxLogTrace helper definitions.