KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
design_block_pane.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, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
24#include <design_block.h>
26#include <paths.h>
27#include <env_paths.h>
28#include <pgm_base.h>
29#include <common.h>
30#include <kidialog.h>
34#include <kiface_base.h>
35#include <core/kicad_algo.h>
36#include <template_fieldnames.h>
37#include <wx/button.h>
38#include <wx/checkbox.h>
39#include <wx/sizer.h>
40#include <wx/choicdlg.h>
41#include <wx/msgdlg.h>
42#include <wx/textdlg.h>
43#include <confirm.h>
45#include <tool/tool_manager.h>
46
48 std::vector<LIB_ID>& aHistoryList ) : WX_PANEL( aParent ), m_frame( aParent )
49{
50 m_frame->Bind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
51 m_frame->Bind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
52}
53
54
56{
57 m_frame->Unbind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
58 m_frame->Unbind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
59}
60
61
62void DESIGN_BLOCK_PANE::OnLanguageChanged( wxCommandEvent& aEvent )
63{
64 if( m_chooserPanel )
66
68
69 aEvent.Skip();
70}
71
72
73void DESIGN_BLOCK_PANE::OnClosed( wxAuiManagerEvent& aEvent )
74{
75 if( APP_SETTINGS_BASE* cfg = m_frame->config() )
76 {
77 if( IsShownOnScreen() ) // Ensure the panel is shown when trying to save its size
78 m_frame->SaveSettings( cfg );
79 }
80
81 aEvent.Skip();
82}
83
84
86{
88}
89
90
92{
93 return m_chooserPanel->GetSelectedLibId( aUnit );
94}
95
96
98{
99 m_chooserPanel->SelectLibId( aLibId );
100}
101
102
104{
106}
107
108
109DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
110{
112
113 wxCHECK_MSG( prjLibs, nullptr, wxS( "Invalid design block library table." ) );
114
115 DESIGN_BLOCK* designBlock = nullptr;
116
117 try
118 {
119 designBlock = prjLibs->DesignBlockLoadWithOptionalNickname( aLibId, true );
120 }
121 catch( const IO_ERROR& ioe )
122 {
123 if( aShowErrorMsg )
124 {
125 wxString msg = wxString::Format( _( "Error loading design block %s from library '%s'." ),
126 aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str() );
127 DisplayErrorMessage( m_frame, msg, ioe.What() );
128 }
129 }
130
131 return designBlock;
132}
133
134
135DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetSelectedDesignBlock( bool aUseCacheLib, bool aShowErrorMsg )
136{
137 if( !GetSelectedLibId().IsValid() )
138 return nullptr;
139
140 return GetDesignBlock( GetSelectedLibId(), aUseCacheLib, aShowErrorMsg );
141}
142
143
144wxString DESIGN_BLOCK_PANE::CreateNewDesignBlockLibrary( const wxString& aLibName, const wxString& aProposedName )
145{
146 return createNewDesignBlockLibrary( aLibName, aProposedName, selectDesignBlockLibTable() );
147}
148
149
150wxString DESIGN_BLOCK_PANE::createNewDesignBlockLibrary( const wxString& aLibName, const wxString& aProposedName,
151 DESIGN_BLOCK_LIB_TABLE* aTable )
152{
153 if( aTable == nullptr )
154 return wxEmptyString;
155
156 wxFileName fn;
157 bool doAdd = false;
158 bool isGlobal = ( aTable == &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable() );
159 wxString initialPath = aProposedName;
160
161 if( initialPath.IsEmpty() )
162 initialPath = isGlobal ? PATHS::GetDefaultUserDesignBlocksPath() : m_frame->Prj().GetProjectPath();
163
164 if( aLibName.IsEmpty() )
165 {
166 fn = initialPath;
167
169 FILEEXT::KiCadDesignBlockLibPathExtension, false, isGlobal, initialPath ) )
170 {
171 return wxEmptyString;
172 }
173
174 doAdd = true;
175 }
176 else
177 {
179
180 if( !fn.IsAbsolute() )
181 {
182 fn.SetName( aLibName );
183 fn.MakeAbsolute( initialPath );
184 }
185 }
186
187 // We can save libs only using DESIGN_BLOCK_IO_MGR::KICAD_SEXP format (.pretty libraries)
189 wxString libPath = fn.GetFullPath();
190
191 try
192 {
194
195 bool writable = false;
196 bool exists = false;
197
198 try
199 {
200 writable = pi->IsLibraryWritable( libPath );
201 exists = fn.Exists();
202 }
203 catch( const IO_ERROR& )
204 {
205 // best efforts....
206 }
207
208 if( exists )
209 {
210 if( !writable )
211 {
212 wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
214 return wxEmptyString;
215 }
216 else
217 {
218 wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
219 KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
220 dlg.SetOKLabel( _( "Overwrite" ) );
221 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
222
223 if( dlg.ShowModal() == wxID_CANCEL )
224 return wxEmptyString;
225
226 pi->DeleteLibrary( libPath );
227 }
228 }
229
230 pi->CreateLibrary( libPath );
231 }
232 catch( const IO_ERROR& ioe )
233 {
234 DisplayError( m_frame, ioe.What() );
235 return wxEmptyString;
236 }
237
238 if( doAdd )
239 AddDesignBlockLibrary( libPath, aTable );
240
241 return libPath;
242}
243
244
245bool DESIGN_BLOCK_PANE::AddDesignBlockLibrary( const wxString& aFilename, DESIGN_BLOCK_LIB_TABLE* aTable )
246{
247 if( aTable == nullptr )
248 aTable = selectDesignBlockLibTable();
249
250 if( aTable == nullptr )
251 return wxEmptyString;
252
253 bool isGlobal = ( aTable == &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable() );
254
255 wxFileName fn( aFilename );
256
257 if( aFilename.IsEmpty() )
258 {
262 {
263 return false;
264 }
265 }
266
267 wxString libPath = fn.GetFullPath();
268 wxString libName = fn.GetName();
269
270 if( libName.IsEmpty() )
271 return false;
272
273 // Open a dialog to ask for a description
274 wxString description = wxGetTextFromUser( _( "Enter a description for the library:" ), _( "Library Description" ),
275 wxEmptyString, m_frame );
276
278
281
282 wxString type = DESIGN_BLOCK_IO_MGR::ShowType( lib_type );
283
284 // KiCad lib is our default guess. So it might not have the .kicad_blocks extension
285 // In this case, the extension is part of the library name
287 libName = fn.GetFullName();
288
289 // try to use path normalized to an environmental variable or project path
290 wxString normalizedPath = NormalizePath( libPath, &Pgm().GetLocalEnvVariables(), &m_frame->Prj() );
291
292 try
293 {
295 new DESIGN_BLOCK_LIB_TABLE_ROW( libName, normalizedPath, type, wxEmptyString, description );
296 aTable->InsertRow( row );
297
298 if( isGlobal )
300 else
302 }
303 catch( const IO_ERROR& ioe )
304 {
305 DisplayError( m_frame, ioe.What() );
306 return false;
307 }
308
309 LIB_ID libID( libName, wxEmptyString );
310 RefreshLibs();
311 SelectLibId( libID );
312
313 return true;
314}
315
316
317bool DESIGN_BLOCK_PANE::DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm )
318{
319 if( aLibName.IsEmpty() )
320 {
321 DisplayErrorMessage( m_frame, _( "Please select a library to delete." ) );
322 return false;
323 }
324
325 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( aLibName ) )
326 {
327 wxString msg = wxString::Format( _( "Library '%s' is read only." ), aLibName );
329 return false;
330 }
331
332 // Confirmation
333 wxString msg = wxString::Format( _( "Delete design block library '%s' from disk? This will "
334 "delete all design blocks within the library." ),
335 aLibName.GetData() );
336
337 if( aConfirm && !IsOK( m_frame, msg ) )
338 return false;
339
340 try
341 {
343 }
344 catch( const IO_ERROR& ioe )
345 {
346 DisplayError( m_frame, ioe.What() );
347 return false;
348 }
349
350 msg.Printf( _( "Design block library '%s' deleted" ), aLibName.GetData() );
351 m_frame->SetStatusText( msg );
352
353 RefreshLibs();
354
355 return true;
356}
357
358
359bool DESIGN_BLOCK_PANE::DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm )
360{
361 if( !aLibId.IsValid() )
362 return false;
363
364 wxString libname = aLibId.GetLibNickname();
365 wxString dbname = aLibId.GetLibItemName();
366
368 {
369 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
371 return false;
372 }
373
374 // Confirmation
375 wxString msg = wxString::Format( _( "Delete design block '%s' in library '%s' from disk?" ),
376 dbname.GetData(), libname.GetData() );
377
378 if( aConfirm && !IsOK( m_frame, msg ) )
379 return false;
380
381 try
382 {
383 m_frame->Prj().DesignBlockLibs()->DesignBlockDelete( libname, dbname );
384 }
385 catch( const IO_ERROR& ioe )
386 {
387 DisplayError( m_frame, ioe.What() );
388 return false;
389 }
390
391 msg.Printf( _( "Design block '%s' deleted from library '%s'" ), dbname.GetData(), libname.GetData() );
392
393 m_frame->SetStatusText( msg );
394
395 RefreshLibs();
396
397 return true;
398}
399
400
402{
403 if( !aLibId.IsValid() )
404 return false;
405
406 wxString libname = aLibId.GetLibNickname();
407 wxString dbname = aLibId.GetLibItemName();
408
410 {
411 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
413 return false;
414 }
415
416 DESIGN_BLOCK* designBlock = GetDesignBlock( aLibId, true, true );
417
418 if( !designBlock )
419 return false;
420
421 wxString originalName = designBlock->GetLibId().GetLibItemName();
422 DIALOG_DESIGN_BLOCK_PROPERTIES dlg( m_frame, designBlock );
423
424 if( dlg.ShowModal() != wxID_OK )
425 return false;
426
427 wxString newName = designBlock->GetLibId().GetLibItemName();
428
429 try
430 {
431 if( originalName != newName )
432 {
433 if( m_frame->Prj().DesignBlockLibs()->DesignBlockExists( libname, newName ) )
434 if( !checkOverwrite( m_frame, libname, newName ) )
435 return false;
436
437 m_frame->Prj().DesignBlockLibs()->DesignBlockSave( libname, designBlock );
438 m_frame->Prj().DesignBlockLibs()->DesignBlockDelete( libname, originalName );
439 }
440 else
441 m_frame->Prj().DesignBlockLibs()->DesignBlockSave( libname, designBlock );
442 }
443 catch( const IO_ERROR& ioe )
444 {
445 DisplayError( m_frame, ioe.What() );
446 return false;
447 }
448
449 RefreshLibs();
450 SelectLibId( designBlock->GetLibId() );
451
452 return true;
453}
454
455
456bool DESIGN_BLOCK_PANE::checkOverwrite( wxWindow* aFrame, wxString& libname, wxString& newName )
457{
458 wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ),
459 newName.GetData(), libname.GetData() );
460
461 if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
462 != wxID_OK )
463 {
464 return false;
465 }
466
467 return true;
468}
469
470
472{
473 // If no project is loaded, always work with the global table
474 if( m_frame->Prj().IsNullProject() )
475 {
477
478 if( aOptional )
479 {
480 wxMessageDialog dlg( m_frame, _( "Add the library to the global library table?" ),
481 _( "Add To Global Library Table" ), wxYES_NO );
482
483 if( dlg.ShowModal() != wxID_OK )
484 ret = nullptr;
485 }
486
487 return ret;
488 }
489
490 wxArrayString libTableNames;
491 libTableNames.Add( _( "Global" ) );
492 libTableNames.Add( _( "Project" ) );
493
494 wxSingleChoiceDialog dlg( m_frame, _( "Choose the Library Table to add the library to:" ),
495 _( "Add To Library Table" ), libTableNames );
496
497 if( aOptional )
498 {
499 dlg.FindWindow( wxID_CANCEL )->SetLabel( _( "Skip" ) );
500 dlg.FindWindow( wxID_OK )->SetLabel( _( "Add" ) );
501 }
502
503 if( dlg.ShowModal() != wxID_OK )
504 return nullptr;
505
506 switch( dlg.GetSelection() )
507 {
509 case 1: return m_frame->Prj().DesignBlockLibs();
510 default: return nullptr;
511 }
512}
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
Definition: app_settings.h:92
@ KICAD_SEXP
S-expression KiCad file format.
static const wxString ShowType(DESIGN_BLOCK_FILE_T aFileType)
static DESIGN_BLOCK_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath, int aCtl=0)
static DESIGN_BLOCK_IO * FindPlugin(DESIGN_BLOCK_FILE_T aFileType)
Hold a record identifying a library accessed by the appropriate design block library #PLUGIN object i...
void DesignBlockLibDelete(const wxString &aNickname)
static wxString GetGlobalTableFileName()
bool IsDesignBlockLibWritable(const wxString &aNickname)
Return true if the library given by aNickname is writable.
void DesignBlockDelete(const wxString &aNickname, const wxString &aDesignBlockName)
Delete the aDesignBlockName from the library given by aNickname.
SAVE_T DesignBlockSave(const wxString &aNickname, const DESIGN_BLOCK *aDesignBlock, bool aOverwrite=true)
Write aDesignBlock to an existing library given by aNickname.
DESIGN_BLOCK * DesignBlockLoadWithOptionalNickname(const LIB_ID &aDesignBlockId, bool aKeepUUID=false)
Load a design block having aDesignBlockId with possibly an empty nickname.
bool DesignBlockExists(const wxString &aNickname, const wxString &aDesignBlockName)
Indicates whether or not the given design block already exists in the given library.
static DESIGN_BLOCK_LIB_TABLE & GetGlobalLibTable()
bool AddDesignBlockLibrary(const wxString &aFilename, DESIGN_BLOCK_LIB_TABLE *aTable)
Add an existing library to either the global or project library table.
bool DeleteDesignBlockLibrary(const wxString &aLibName, bool aConfirm)
bool checkOverwrite(wxWindow *aFrame, wxString &libname, wxString &newName)
bool DeleteDesignBlockFromLibrary(const LIB_ID &aLibId, bool aConfirm)
~DESIGN_BLOCK_PANE() override
void SelectLibId(const LIB_ID &aLibId)
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
DESIGN_BLOCK_PANE(EDA_DRAW_FRAME *aParent, const LIB_ID *aPreselect, std::vector< LIB_ID > &aHistoryList)
DESIGN_BLOCK * GetDesignBlock(const LIB_ID &aLibId, bool aUseCacheLib, bool aShowErrorMsg)
Load design block from design block library table.
DESIGN_BLOCK_LIB_TABLE * selectDesignBlockLibTable(bool aOptional=false)
PANEL_DESIGN_BLOCK_CHOOSER * m_chooserPanel
bool EditDesignBlockProperties(const LIB_ID &aLibId)
virtual void setLabelsAndTooltips()=0
wxString createNewDesignBlockLibrary(const wxString &aLibName, const wxString &aProposedName, DESIGN_BLOCK_LIB_TABLE *aTable)
wxString CreateNewDesignBlockLibrary(const wxString &aLibName=wxEmptyString, const wxString &aProposedName=wxEmptyString)
If a library name is given, creates a new design block library in the project folder with the given n...
virtual void OnLanguageChanged(wxCommandEvent &aEvent)
EDA_DRAW_FRAME * m_frame
DESIGN_BLOCK * GetSelectedDesignBlock(bool aUseCacheLib, bool aShowErrorMsg)
void OnClosed(wxAuiManagerEvent &aEvent)
const LIB_ID & GetLibId() const
Definition: design_block.h:37
int ShowModal() override
virtual APP_SETTINGS_BASE * config() const
Return the settings object used in SaveSettings(), and is overloaded in KICAD_MANAGER_FRAME.
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, WX_INFOBAR::MESSAGE_TYPE aType=WX_INFOBAR::MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
The base class for create windows for drawing purpose.
void SaveSettings(APP_SETTINGS_BASE *aCfg) override
Save common frame parameters to a configuration data file.
bool LibraryFileBrowser(bool doOpen, wxFileName &aFilename, const wxString &wildcard, const wxString &ext, bool isDirectory=false, bool aIsGlobal=false, const wxString &aGlobalPath=wxEmptyString)
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
Definition: ki_exception.h:77
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:30
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition: kidialog.h:43
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition: kidialog.cpp:51
int ShowModal() override
Definition: kidialog.cpp:95
PROJECT & Prj() const
Return a reference to the PROJECT associated with this KIWAY.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:49
bool IsValid() const
Check if this LID_ID is valid.
Definition: lib_id.h:172
const UTF8 & GetLibItemName() const
Definition: lib_id.h:102
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition: lib_id.h:87
bool InsertRow(LIB_TABLE_ROW *aRow, bool doReplace=false)
Adds aRow if it does not already exist or if doReplace is true.
void Save(const wxString &aFileName) const
Write this library table to aFileName in s-expression form.
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
To be called after this dialog returns from ShowModal().
void RefreshLibs(bool aProgress=false)
void SelectLibId(const LIB_ID &aLibId)
static wxString GetDefaultUserDesignBlocksPath()
Gets the default path we point users to create projects.
Definition: paths.cpp:110
virtual const wxString DesignBlockLibTblName() const
Return the path and file name of this projects design block library table.
Definition: project.cpp:182
virtual const wxString GetProjectPath() const
Return the full path of the project.
Definition: project.cpp:146
virtual DESIGN_BLOCK_LIB_TABLE * DesignBlockLibs()
Return the table of design block libraries.
Definition: project.cpp:429
virtual bool IsNullProject() const
Check if this project is a null project (i.e.
Definition: project.cpp:164
wxString wx_str() const
Definition: utf8.cpp:45
wxString EnsureFileExtension(const wxString &aFilename, const wxString &aExtension)
It's annoying to throw up nag dialogs when the extension isn't right.
Definition: common.cpp:425
The common library.
int OKOrCancelDialog(wxWindow *aParent, const wxString &aWarning, const wxString &aMessage, const wxString &aDetailedMessage, const wxString &aOKLabel, const wxString &aCancelLabel, bool *aApplyToAll)
Display a warning dialog with aMessage and returns the user response.
Definition: confirm.cpp:143
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:249
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition: confirm.cpp:194
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:170
This file is part of the common library.
#define _(s)
wxString NormalizePath(const wxFileName &aFilePath, const ENV_VAR_MAP *aEnvVars, const wxString &aProjectPath)
Normalize a file path to an environmental variable, if possible.
Definition: env_paths.cpp:73
Helper functions to substitute paths with environmental variables.
static const std::string KiCadDesignBlockLibPathExtension
static wxString KiCadDesignBlockLibPathWildcard()
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition: io_mgr.h:33
This file is part of the common library.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:1071
see class PGM_BASE
Definition of file extensions used in Kicad.