KiCad PCB EDA Suite
Loading...
Searching...
No Matches
project.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 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <wx/log.h>
21#include <wx/stdpaths.h> // required on Mac
23
24#include <algorithm>
25#include <pgm_base.h>
26#include <confirm.h>
27#include <core/kicad_algo.h>
29#include <string_utils.h>
30#include <kiface_ids.h>
31#include <kiway.h>
34#include <lockfile.h>
35#include <macros.h>
37#include <git2.h>
38#include <project.h>
39
41
43#include <trace_helpers.h>
47#include <title_block.h>
48#include <local_history.h>
49
50
51
53 m_readOnly( false ),
54 m_lockOverrideGranted( false ),
57 m_projectFile( nullptr ),
58 m_localSettings( nullptr )
59{
60 m_elems.fill( nullptr );
61}
62
63
65{
66 // careful here, this should work, but the virtual destructor may not
67 // be in the same link image as PROJECT.
68 for( unsigned i = 0; i < m_elems.size(); ++i )
69 {
70 SetElem( static_cast<PROJECT::ELEM>( i ), nullptr );
71 }
72}
73
74
79
80
81bool PROJECT::TextVarResolver( wxString* aToken ) const
82{
83 if( !m_projectFile )
84 return false;
85
86 if( aToken->IsSameAs( wxT( "PROJECTNAME" ) ) )
87 {
88 *aToken = GetProjectName();
89 return true;
90 }
91 else if( aToken->IsSameAs( wxT( "CURRENT_DATE" ) ) )
92 {
94 return true;
95 }
96 else if( aToken->IsSameAs( wxT( "CURRENT_TIME_HH_MM_SS" ) ) )
97 {
99 return true;
100 }
101 else if( aToken->IsSameAs( wxT( "CURRENT_TIME_LOCALE" ) ) )
102 {
104 return true;
105 }
106 else if( aToken->IsSameAs( wxT( "VCSHASH" ) ) )
107 {
109 return true;
110 }
111 else if( aToken->IsSameAs( wxT( "VCSSHORTHASH" ) ) )
112 {
114 return true;
115 }
116 else if( GetTextVars().count( *aToken ) > 0 )
117 {
118 *aToken = GetTextVars().at( *aToken );
119 return true;
120 }
121
122 return false;
123}
124
125
126std::map<wxString, wxString>& PROJECT::GetTextVars() const
127{
128 return GetProjectFile().m_TextVars;
129}
130
131
132void PROJECT::ApplyTextVars( const std::map<wxString, wxString>& aVarsMap )
133{
134 if( aVarsMap.size() == 0 )
135 return;
136
137 std::map<wxString, wxString>& existingVarsMap = GetTextVars();
138
139 for( const auto& var : aVarsMap )
140 {
141 // create or update the existing vars
142 existingVarsMap[var.first] = var.second;
143 }
144}
145
146
147void PROJECT::setProjectFullName( const wxString& aFullPathAndName )
148{
149 // Compare paths, rather than inodes, to be less surprising to the user.
150 // Create a temporary wxFileName to normalize the path
151 wxFileName candidate_path( aFullPathAndName );
152
153 // Edge transitions only. This is what clears the project
154 // data using the Clear() function.
155 if( m_project_name.GetFullPath() != candidate_path.GetFullPath() )
156 {
157 Clear(); // clear the data when the project changes.
158
159 wxLogTrace( tracePathsAndFiles, "%s: old:'%s' new:'%s'", __func__,
160 TO_UTF8( GetProjectFullName() ), TO_UTF8( aFullPathAndName ) );
161
162 m_project_name = aFullPathAndName;
163
164 wxASSERT( m_project_name.IsAbsolute() );
165 wxString ext = m_project_name.GetExt();
166
167 if( !ext.IsEmpty() && ext != FILEEXT::ProjectFileExtension )
168 {
169 wxLogDebug( wxT( "Project file has unexpected extension '%s', expected '%s'" ), ext,
172 }
173 }
174}
175
176
177const wxString PROJECT::GetProjectFullName() const
178{
179 return m_project_name.GetFullPath();
180}
181
182
183const wxString PROJECT::GetProjectPath() const
184{
185 return m_project_name.GetPathWithSep();
186}
187
188
189const wxString PROJECT::GetProjectDirectory() const
190{
191 return m_project_name.GetPath();
192}
193
194
195const wxString PROJECT::GetProjectName() const
196{
197 return m_project_name.GetName();
198}
199
200
202{
203 return m_project_name.GetName().IsEmpty();
204}
205
206
211
212
217
218
223
224
225void PROJECT::PinLibrary( const wxString& aLibrary, enum LIB_TYPE_T aLibType )
226{
228 std::vector<wxString>* pinnedLibsCfg = nullptr;
229 std::vector<wxString>* pinnedLibsFile = nullptr;
230
231 switch( aLibType )
232 {
234 pinnedLibsFile = &m_projectFile->m_PinnedSymbolLibs;
235 pinnedLibsCfg = &cfg->m_Session.pinned_symbol_libs;
236 break;
238 pinnedLibsFile = &m_projectFile->m_PinnedFootprintLibs;
239 pinnedLibsCfg = &cfg->m_Session.pinned_fp_libs;
240 break;
242 pinnedLibsFile = &m_projectFile->m_PinnedDesignBlockLibs;
243 pinnedLibsCfg = &cfg->m_Session.pinned_design_block_libs;
244 break;
245 default:
246 wxFAIL_MSG( "Cannot pin library: invalid library type" );
247 return;
248 }
249
250 if( !alg::contains( *pinnedLibsFile, aLibrary ) )
251 pinnedLibsFile->push_back( aLibrary );
252
254
255 if( !alg::contains( *pinnedLibsCfg, aLibrary ) )
256 pinnedLibsCfg->push_back( aLibrary );
257
258 cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
259}
260
261
262void PROJECT::UnpinLibrary( const wxString& aLibrary, enum LIB_TYPE_T aLibType )
263{
265 std::vector<wxString>* pinnedLibsCfg = nullptr;
266 std::vector<wxString>* pinnedLibsFile = nullptr;
267
268 switch( aLibType )
269 {
271 pinnedLibsFile = &m_projectFile->m_PinnedSymbolLibs;
272 pinnedLibsCfg = &cfg->m_Session.pinned_symbol_libs;
273 break;
275 pinnedLibsFile = &m_projectFile->m_PinnedFootprintLibs;
276 pinnedLibsCfg = &cfg->m_Session.pinned_fp_libs;
277 break;
279 pinnedLibsFile = &m_projectFile->m_PinnedDesignBlockLibs;
280 pinnedLibsCfg = &cfg->m_Session.pinned_design_block_libs;
281 break;
282 default:
283 wxFAIL_MSG( "Cannot unpin library: invalid library type" );
284 return;
285 }
286
287 std::erase( *pinnedLibsFile, aLibrary );
289
290 std::erase( *pinnedLibsCfg, aLibrary );
291 cfg->SaveToFile( Pgm().GetSettingsManager().GetPathForSettingsFile( cfg ) );
292}
293
294
295const wxString PROJECT::libTableName( const wxString& aLibTableName ) const
296{
297 wxFileName fn = GetProjectFullName();
298 wxString path = fn.GetPath();
299
300 // if there's no path to the project name, or the name as a whole is bogus or its not
301 // write-able then use a template file.
302 if( !fn.GetDirCount() || !fn.IsOk() || !wxFileName::IsDirWritable( path ) )
303 {
304 // return a template filename now.
305
306 // this next line is likely a problem now, since it relies on an
307 // application title which is no longer constant or known. This next line needs
308 // to be re-thought out.
309
310#ifdef __WXMAC__
311 fn.AssignDir( KIPLATFORM::ENV::GetUserConfigPath() );
312#else
313 // don't pollute home folder, temp folder seems to be more appropriate
314 fn.AssignDir( wxStandardPaths::Get().GetTempDir() );
315#endif
316
317#if defined( __WINDOWS__ )
318 fn.AppendDir( wxT( "kicad" ) );
319#endif
320
321 /*
322 * The library table name used when no project file is passed to the appropriate
323 * code. This is used temporarily to store the project specific library table
324 * until the project file being edited is saved. It is then moved to the correct
325 * file in the folder where the project file is saved.
326 */
327 fn.SetName( wxS( "prj-" ) + aLibTableName );
328 }
329 else // normal path.
330 {
331 fn.SetName( aLibTableName );
332 }
333
334 fn.ClearExt();
335
336 return fn.GetFullPath();
337}
338
339
340const wxString PROJECT::GetSheetName( const KIID& aSheetID )
341{
342 if( m_sheetNames.empty() )
343 {
344 for( const std::pair<KIID, wxString>& pair : GetProjectFile().GetSheets() )
345 m_sheetNames[pair.first] = pair.second;
346 }
347
348 if( m_sheetNames.count( aSheetID ) )
349 return m_sheetNames.at( aSheetID );
350 else
351 return aSheetID.AsString();
352}
353
354
355void PROJECT::SetRString( RSTRING_T aIndex, const wxString& aString )
356{
357 unsigned ndx = unsigned( aIndex );
358
359 if( ndx < m_rstrings.size() )
360 m_rstrings[ndx] = aString;
361 else
362 wxASSERT( 0 ); // bad index
363}
364
365
366const wxString& PROJECT::GetRString( RSTRING_T aIndex )
367{
368 unsigned ndx = unsigned( aIndex );
369
370 if( ndx < m_rstrings.size() )
371 {
372 return m_rstrings[ndx];
373 }
374 else
375 {
376 static wxString no_cookie_for_you;
377
378 wxASSERT( 0 ); // bad index
379
380 return no_cookie_for_you;
381 }
382}
383
384
386{
387 // This is virtual, so implement it out of line
388
389 if( static_cast<unsigned>( aIndex ) < m_elems.size() )
390 return m_elems[static_cast<unsigned>( aIndex )];
391
392 return nullptr;
393}
394
395
397{
398 // This is virtual, so implement it out of line
399 if( static_cast<unsigned>( aIndex ) < m_elems.size() )
400 {
401 delete m_elems[static_cast<unsigned>(aIndex)];
402 m_elems[static_cast<unsigned>( aIndex )] = aElem;
403 }
404}
405
406
407const wxString PROJECT::AbsolutePath( const wxString& aFileName ) const
408{
409 wxFileName fn = aFileName;
410
411 // Paths which start with an unresolved variable reference are more likely to be
412 // absolute than relative.
413 if( aFileName.StartsWith( wxT( "${" ) ) )
414 return aFileName;
415
416 if( !fn.IsAbsolute() )
417 {
418 wxString pro_dir = wxPathOnly( GetProjectFullName() );
419 fn.Normalize( FN_NORMALIZE_FLAGS | wxPATH_NORM_ENV_VARS, pro_dir );
420 }
421
422 return fn.GetFullPath();
423}
424
425
431
432
434{
435 std::scoped_lock lock( m_designBlockLibsMutex );
436
438 std::optional<LIBRARY_MANAGER_ADAPTER*> adapter = mgr.Adapter( LIBRARY_TABLE_TYPE::DESIGN_BLOCK );
439
440 if( !adapter )
441 {
443 std::make_unique<DESIGN_BLOCK_LIBRARY_ADAPTER>( mgr ) );
444
445 std::optional<LIBRARY_MANAGER_ADAPTER*> created = mgr.Adapter( LIBRARY_TABLE_TYPE::DESIGN_BLOCK );
446 wxCHECK( created && ( *created )->Type() == LIBRARY_TABLE_TYPE::DESIGN_BLOCK, nullptr );
447 return static_cast<DESIGN_BLOCK_LIBRARY_ADAPTER*>( *created );
448 }
449
450 wxCHECK( ( *adapter )->Type() == LIBRARY_TABLE_TYPE::DESIGN_BLOCK, nullptr );
451 return static_cast<DESIGN_BLOCK_LIBRARY_ADAPTER*>( *adapter );
452}
453
454
456{
457 return m_project_lock.get();
458}
459
460
462{
463 m_project_lock.reset( aLockFile );
464}
465
466
467void PROJECT::SaveToHistory( const wxString& aProjectPath, std::vector<HISTORY_FILE_DATA>& aFileData )
468{
469 wxString projectFile = GetProjectFullName();
470
471 if( projectFile.IsEmpty() )
472 return;
473
474 wxFileName projectFn( projectFile );
475 wxFileName requestedFn( aProjectPath );
476 // wxPATH_NORM_ALL is now deprecated.
477 // So define a similar option
478 int norm_opt = wxPATH_NORM_ENV_VARS|wxPATH_NORM_DOTS|wxPATH_NORM_TILDE|wxPATH_NORM_ABSOLUTE
479 |wxPATH_NORM_LONG|wxPATH_NORM_SHORTCUT;
480
481 if( !projectFn.Normalize( norm_opt ) || !requestedFn.Normalize( norm_opt ) )
482 return;
483
484 if( projectFn.GetFullPath() != requestedFn.GetFullPath() )
485 return;
486
487 HISTORY_FILE_DATA proEntry;
488 proEntry.relativePath = projectFn.GetFullName();
489 proEntry.sourcePath = projectFile;
490 aFileData.push_back( std::move( proEntry ) );
491
492 wxFileName prlFile( projectFn.GetPath(), projectFn.GetName(),
494
495 if( prlFile.FileExists() )
496 {
497 HISTORY_FILE_DATA prlEntry;
498 prlEntry.relativePath = prlFile.GetFullName();
499 prlEntry.sourcePath = prlFile.GetFullPath();
500 aFileData.push_back( std::move( prlEntry ) );
501 }
502}
An interface to the global shared library manager that is schematic-specific and linked to one projec...
virtual bool SaveToFile(const wxString &aDirectory="", bool aForce=false)
Calls Store() and then writes the contents of the JSON document to a file.
static wxString GetCurrentHash(const wxString &aProjectFile, bool aShort)
Return the current HEAD commit hash for the repository containing aProjectFile.
Definition kiid.h:44
wxString AsString() const
Definition kiid.cpp:242
A minimalistic software bus for communications between various DLLs/DSOs (DSOs) within the same KiCad...
Definition kiway.h:311
virtual KIFACE * KiFACE(FACE_T aFaceId, bool doLoad=true)
Return the KIFACE* given a FACE_T.
Definition kiway.cpp:207
@ FACE_PCB
pcbnew DSO
Definition kiway.h:319
std::optional< LIBRARY_MANAGER_ADAPTER * > Adapter(LIBRARY_TABLE_TYPE aType) const
void RegisterAdapter(LIBRARY_TABLE_TYPE aType, std::unique_ptr< LIBRARY_MANAGER_ADAPTER > &&aAdapter)
virtual COMMON_SETTINGS * GetCommonSettings() const
Definition pgm_base.cpp:528
virtual SETTINGS_MANAGER & GetSettingsManager() const
Definition pgm_base.h:124
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:126
A PROJECT can hold stuff it knows nothing about, in the form of _ELEM derivatives.
Definition project.h:89
std::map< wxString, wxString > m_TextVars
PROJECT_FILE * m_projectFile
Backing store for project data – owned by SETTINGS_MANAGER.
Definition project.h:369
void SetProjectLock(LOCKFILE *aLockFile)
Definition project.cpp:461
bool m_lockOverrideGranted
User granted override at project level.
Definition project.h:364
LOCKFILE * GetProjectLock() const
Definition project.cpp:455
@ SYMBOL_LIB
Definition project.h:190
@ DESIGN_BLOCK_LIB
Definition project.h:192
@ FOOTPRINT_LIB
Definition project.h:191
virtual const wxString GetProjectFullName() const
Return the full path and name of the project.
Definition project.cpp:177
virtual void SetElem(PROJECT::ELEM aIndex, _ELEM *aElem)
Definition project.cpp:396
virtual const wxString DesignBlockLibTblName() const
Return the path and file name of this projects design block library table.
Definition project.cpp:219
void PinLibrary(const wxString &aLibrary, enum LIB_TYPE_T aLibType)
Definition project.cpp:225
RSTRING_T
Retain a number of project specific wxStrings, enumerated here:
Definition project.h:214
std::map< KIID, wxString > m_sheetNames
Definition project.h:374
std::unique_ptr< LOCKFILE > m_project_lock
Lock.
Definition project.h:383
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition project.cpp:183
virtual const wxString GetProjectName() const
Return the short name of the project.
Definition project.cpp:195
int m_netclassesTicker
Update counter on netclasses.
Definition project.h:366
virtual const wxString SymbolLibTableName() const
Return the path and file name of this projects symbol library table.
Definition project.cpp:207
virtual _ELEM * GetElem(PROJECT::ELEM aIndex)
Get and set the elements for this project.
Definition project.cpp:385
virtual ~PROJECT()
Definition project.cpp:75
virtual void ApplyTextVars(const std::map< wxString, wxString > &aVarsMap)
Applies the given var map, it will create or update existing vars.
Definition project.cpp:132
virtual DESIGN_BLOCK_LIBRARY_ADAPTER * DesignBlockLibs()
Return the table of design block libraries.
Definition project.cpp:433
virtual bool TextVarResolver(wxString *aToken) const
Definition project.cpp:81
virtual PROJECT_FILE & GetProjectFile() const
Definition project.h:200
virtual const wxString GetSheetName(const KIID &aSheetID)
Return the name of the sheet identified by the given UUID.
Definition project.cpp:340
std::mutex m_designBlockLibsMutex
Synchronise access to DesignBlockLibs()
Definition project.h:386
std::array< _ELEM *, static_cast< unsigned int >(PROJECT::ELEM::COUNT)> m_elems
Definition project.h:380
virtual void elemsClear()
Delete all the _ELEMs and set their pointers to NULL.
Definition project.cpp:64
virtual const wxString FootprintLibTblName() const
Returns the path and filename of this project's footprint library table.
Definition project.cpp:213
virtual void SetRString(RSTRING_T aStringId, const wxString &aString)
Store a "retained string", which is any session and project specific string identified in enum RSTRIN...
Definition project.cpp:355
wxFileName m_project_name
<fullpath>/<basename>.pro
Definition project.h:361
void Clear()
Clear the _ELEMs and RSTRINGs.
Definition project.h:271
virtual FOOTPRINT_LIBRARY_ADAPTER * FootprintLibAdapter(KIWAY &aKiway)
Fetches the footprint library adapter from the PCB editor instance.
Definition project.cpp:426
PROJECT_LOCAL_SETTINGS * m_localSettings
Backing store for project local settings – owned by SETTINGS_MANAGER.
Definition project.h:372
virtual const wxString AbsolutePath(const wxString &aFileName) const
Fix up aFileName if it is relative to the project's directory to be an absolute path and filename.
Definition project.cpp:407
void SaveToHistory(const wxString &aProjectPath, std::vector< HISTORY_FILE_DATA > &aFileData)
Produce HISTORY_FILE_DATA entries for project files (.kicad_pro and .kicad_prl).
Definition project.cpp:467
int m_textVarsTicker
Update counter on text vars.
Definition project.h:365
void UnpinLibrary(const wxString &aLibrary, enum LIB_TYPE_T aLibType)
Definition project.cpp:262
std::array< wxString, RSTRING_COUNT > m_rstrings
Definition project.h:377
const wxString libTableName(const wxString &aLibTableName) const
Return the full path and file name of the project specific library table aLibTableName.
Definition project.cpp:295
virtual void setProjectFullName(const wxString &aFullPathAndName)
Set the full directory, basename, and extension of the project.
Definition project.cpp:147
bool m_readOnly
No project files will be written to disk.
Definition project.h:363
virtual const wxString GetProjectDirectory() const
Return the full path of the project DIRECTORY.
Definition project.cpp:189
virtual std::map< wxString, wxString > & GetTextVars() const
Definition project.cpp:126
PROJECT()
Definition project.cpp:52
virtual const wxString & GetRString(RSTRING_T aStringId)
Return a "retained string", which is any session and project specific string identified in enum RSTRI...
Definition project.cpp:366
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition project.cpp:201
ELEM
The set of #_ELEMs that a PROJECT can hold.
Definition project.h:68
bool SaveProject(const wxString &aFullPath=wxEmptyString, PROJECT *aProject=nullptr)
Save a loaded project.
static wxString GetCurrentTimeLocale()
static wxString GetCurrentTimeHHMMSS()
static wxString GetCurrentDate()
This file is part of the common library.
static const std::string SymbolLibraryTableFileName
static const std::string ProjectFileExtension
static const std::string ProjectLocalSettingsFileExtension
static const std::string DesignBlockLibraryTableFileName
static const std::string FootprintLibraryTableFileName
const wxChar *const tracePathsAndFiles
Flag to enable path and file name debug output.
@ KIFACE_FOOTPRINT_LIBRARY_ADAPTER
Definition kiface_ids.h:30
File locking utilities.
This file contains miscellaneous commonly used macros and functions.
wxString GetUserConfigPath()
Retrieves the operating system specific path for a user's configuration store.
bool contains(const _Container &__container, _Value __value)
Returns true if the container contains the given value.
Definition kicad_algo.h:96
PGM_BASE & Pgm()
The global program "get" accessor.
see class PGM_BASE
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::vector< wxString > pinned_design_block_libs
std::vector< wxString > pinned_fp_libs
std::vector< wxString > pinned_symbol_libs
Data produced by a registered saver on the UI thread, consumed by either the background local-history...
wxString sourcePath
For file-copy savers (small files like .kicad_pro)
wxString relativePath
Destination path relative to the project root.
Implement a participant in the KIWAY alchemy.
Definition kiway.h:152
IFACE KIFACE_BASE kiface("pcb_test_frame", KIWAY::FACE_PCB)
std::string path
wxLogTrace helper definitions.
Definition of file extensions used in Kicad.
#define FN_NORMALIZE_FLAGS
Default flags to pass to wxFileName::Normalize().
Definition wx_filename.h:35