KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <design_block_io.h>
27#include <paths.h>
28#include <env_paths.h>
29#include <pgm_base.h>
30#include <common.h>
31#include <kidialog.h>
36#include <kiface_base.h>
37#include <core/kicad_algo.h>
38#include <template_fieldnames.h>
39#include <wx/sizer.h>
40#include <wx/textdlg.h>
41#include <confirm.h>
43#include <tool/tool_manager.h>
44
46 std::vector<LIB_ID>& aHistoryList ) :
47 WX_PANEL( aParent ),
48 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 )
65 m_chooserPanel->ShowChangedLanguage();
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{
87 m_chooserPanel->SaveSettings();
88}
89
90
92{
93 return m_chooserPanel->GetSelectedLibId( aUnit );
94}
95
96
98{
99 m_chooserPanel->SelectLibId( aLibId );
100}
101
102
104{
105 m_chooserPanel->RefreshLibs();
106}
107
108
109DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
110{
111 DESIGN_BLOCK_LIBRARY_ADAPTER* prjLibs = m_frame->Prj().DesignBlockLibs();
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& aDialogTitle )
145{
146 return createNewDesignBlockLibrary( aDialogTitle );
147}
148
149
150wxString DESIGN_BLOCK_PANE::createNewDesignBlockLibrary( const wxString& aDialogTitle )
151{
152 wxFileName fn;
153 static bool isGlobal = true;
154 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
155
156 if( !m_frame->LibraryFileBrowser( aDialogTitle, false, fn, FILEEXT::KiCadDesignBlockLibPathWildcard(),
157 FILEEXT::KiCadDesignBlockLibPathExtension, false, &tableChooser ) )
158 {
159 return wxEmptyString;
160 }
161
162 isGlobal = tableChooser.GetUseGlobalTable();
163
164 wxString libPath = fn.GetFullPath();
165
167
168 // We can save libs only using DESIGN_BLOCK_IO_MGR::KICAD_SEXP format (.pretty libraries)
170
171 try
172 {
174
175 bool writable = false;
176 bool exists = false;
177
178 try
179 {
180 writable = pi->IsLibraryWritable( libPath );
181 exists = fn.Exists();
182 }
183 catch( const IO_ERROR& )
184 {
185 // best efforts....
186 }
187
188 if( exists )
189 {
190 if( !writable )
191 {
192 wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
193 m_frame->ShowInfoBarError( msg );
194 return wxEmptyString;
195 }
196 else
197 {
198 wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
199 KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
200 dlg.SetOKLabel( _( "Overwrite" ) );
201 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
202
203 if( dlg.ShowModal() == wxID_CANCEL )
204 return wxEmptyString;
205
206 pi->DeleteLibrary( libPath );
207 }
208 }
209
210 pi->CreateLibrary( libPath );
211 }
212 catch( const IO_ERROR& ioe )
213 {
214 DisplayError( m_frame, ioe.What() );
215 return wxEmptyString;
216 }
217
218 AddDesignBlockLibrary( aDialogTitle, libPath, scope );
219
220 return libPath;
221}
222
223
224bool DESIGN_BLOCK_PANE::AddDesignBlockLibrary( const wxString& aDialogTitle, const wxString& aFilename,
225 LIBRARY_TABLE_SCOPE aScope )
226{
227 DESIGN_BLOCK_LIBRARY_ADAPTER* adapter = m_frame->Prj().DesignBlockLibs();
229
230 // TODO(JE) library tables -- figure out where Jeff's added aDialogTitle should be used?
231 bool isGlobal = ( aScope == LIBRARY_TABLE_SCOPE::GLOBAL );
232
233 wxFileName fn( aFilename );
234 wxString libPath = fn.GetFullPath();
235 wxString libName = fn.GetName();
236
237 if( libName.IsEmpty() )
238 return false;
239
240 // Open a dialog to ask for a description
241 wxString description = wxGetTextFromUser( _( "Enter a description for the library:" ), _( "Library Description" ),
242 wxEmptyString, m_frame );
243
245
248
249 wxString type = DESIGN_BLOCK_IO_MGR::ShowType( lib_type );
250
251 // KiCad lib is our default guess. So it might not have the .kicad_blocks extension
252 // In this case, the extension is part of the library name
254 libName = fn.GetFullName();
255
256 // try to use path normalized to an environmental variable or project path
257 wxString normalizedPath = NormalizePath( libPath, &Pgm().GetLocalEnvVariables(), &m_frame->Prj() );
258
259 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::DESIGN_BLOCK, aScope );
260 wxCHECK( optTable.has_value(), false );
261 LIBRARY_TABLE* table = optTable.value();
262
263 bool success = true;
264 LIBRARY_TABLE_ROW& newRow = table->InsertRow();
265
266 newRow.SetNickname( libName );
267 newRow.SetURI( normalizedPath );
268 newRow.SetType( type );
269 newRow.SetDescription( description );
270
271 table->Save().map_error(
272 [&]( const LIBRARY_ERROR& aError )
273 {
274 DisplayError( m_frame, _( "Error saving library table:\n\n" ) + aError.message );
275 success = false;
276 } );
277
278 if( success )
279 {
280 manager.ReloadTables( aScope, { LIBRARY_TABLE_TYPE::DESIGN_BLOCK } );
281 adapter->LoadOne( libName );
282
283 LIB_ID libID( libName, wxEmptyString );
284 RefreshLibs();
285 SelectLibId( libID );
286 }
287
288 return true;
289}
290
291
292bool DESIGN_BLOCK_PANE::DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm )
293{
294 if( aLibName.IsEmpty() )
295 {
296 DisplayErrorMessage( m_frame, _( "Please select a library to delete." ) );
297 return false;
298 }
299
300 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( aLibName ) )
301 {
302 wxString msg = wxString::Format( _( "Library '%s' is read only." ), aLibName );
303 m_frame->ShowInfoBarError( msg );
304 return false;
305 }
306
307 // Confirmation
308 wxString msg = wxString::Format( _( "Delete design block library '%s' from disk? This will "
309 "delete all design blocks within the library." ),
310 aLibName.GetData() );
311
312 if( aConfirm && !IsOK( m_frame, msg ) )
313 return false;
314
315 try
316 {
317 m_frame->Prj().DesignBlockLibs()->DeleteLibrary( aLibName );
318 }
319 catch( const IO_ERROR& ioe )
320 {
321 DisplayError( m_frame, ioe.What() );
322 return false;
323 }
324
325 msg.Printf( _( "Design block library '%s' deleted" ), aLibName.GetData() );
326 m_frame->SetStatusText( msg );
327
328 RefreshLibs();
329
330 return true;
331}
332
333
334bool DESIGN_BLOCK_PANE::DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm )
335{
336 if( !aLibId.IsValid() )
337 return false;
338
339 wxString libname = aLibId.GetLibNickname();
340 wxString dbname = aLibId.GetLibItemName();
341
342 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
343 {
344 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
345 m_frame->ShowInfoBarError( msg );
346 return false;
347 }
348
349 // Confirmation
350 wxString msg = wxString::Format( _( "Delete design block '%s' in library '%s' from disk?" ),
351 dbname.GetData(), libname.GetData() );
352
353 if( aConfirm && !IsOK( m_frame, msg ) )
354 return false;
355
356 try
357 {
358 m_frame->Prj().DesignBlockLibs()->DeleteDesignBlock( libname, dbname );
359 }
360 catch( const IO_ERROR& ioe )
361 {
362 DisplayError( m_frame, ioe.What() );
363 return false;
364 }
365
366 msg.Printf( _( "Design block '%s' deleted from library '%s'" ), dbname.GetData(), libname.GetData() );
367
368 m_frame->SetStatusText( msg );
369
370 RefreshLibs();
371
372 return true;
373}
374
375
377{
378 if( !aLibId.IsValid() )
379 return false;
380
381 wxString libname = aLibId.GetLibNickname();
382 wxString dbname = aLibId.GetLibItemName();
383
384 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
385 {
386 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
387 m_frame->ShowInfoBarError( msg );
388 return false;
389 }
390
391 std::unique_ptr<DESIGN_BLOCK> designBlock( GetDesignBlock( aLibId, true, true ) );
392
393 if( !designBlock )
394 return false;
395
396 wxString originalName = designBlock->GetLibId().GetLibItemName();
397 DIALOG_DESIGN_BLOCK_PROPERTIES dlg( m_frame, designBlock.get() );
398
399 if( dlg.ShowModal() != wxID_OK )
400 return false;
401
402 wxString newName = designBlock->GetLibId().GetLibItemName();
403
404 try
405 {
406 if( originalName != newName )
407 {
408 if( m_frame->Prj().DesignBlockLibs()->DesignBlockExists( libname, newName ) )
409 {
410 if( !checkOverwrite( m_frame, libname, newName ) )
411 return false;
412 }
413
414 m_frame->Prj().DesignBlockLibs()->SaveDesignBlock( libname, designBlock.get() );
415 m_frame->Prj().DesignBlockLibs()->DeleteDesignBlock( libname, originalName );
416 }
417 else
418 {
419 m_frame->Prj().DesignBlockLibs()->SaveDesignBlock( libname, designBlock.get() );
420 }
421 }
422 catch( const IO_ERROR& ioe )
423 {
424 DisplayError( m_frame, ioe.What() );
425 return false;
426 }
427
428 RefreshLibs();
429 SelectLibId( designBlock->GetLibId() );
430
431 return true;
432}
433
434
435bool DESIGN_BLOCK_PANE::checkOverwrite( wxWindow* aFrame, wxString& libname, wxString& newName )
436{
437 wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ),
438 newName.GetData(), libname.GetData() );
439
440 if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
441 != wxID_OK )
442 {
443 return false;
444 }
445
446 return true;
447}
APP_SETTINGS_BASE is a settings class that should be derived for each standalone KiCad application.
@ 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)
DESIGN_BLOCK * DesignBlockLoadWithOptionalNickname(const LIB_ID &aDesignBlockId, bool aKeepUUID=false)
Load a design block having aDesignBlockId with possibly an empty nickname.
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
bool DeleteDesignBlockLibrary(const wxString &aLibName, bool aConfirm)
bool checkOverwrite(wxWindow *aFrame, wxString &libname, wxString &newName)
bool DeleteDesignBlockFromLibrary(const LIB_ID &aLibId, bool aConfirm)
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.
wxString createNewDesignBlockLibrary(const wxString &aDialogTitle)
PANEL_DESIGN_BLOCK_CHOOSER * m_chooserPanel
bool EditDesignBlockProperties(const LIB_ID &aLibId)
virtual void setLabelsAndTooltips()=0
wxString CreateNewDesignBlockLibrary(const wxString &aDialogTitle)
Creates a new design block library.
virtual void OnLanguageChanged(wxCommandEvent &aEvent)
EDA_DRAW_FRAME * m_frame
DESIGN_BLOCK * GetSelectedDesignBlock(bool aUseCacheLib, bool aShowErrorMsg)
void OnClosed(wxAuiManagerEvent &aEvent)
bool AddDesignBlockLibrary(const wxString &aDialogTitle, const wxString &aFilename, LIBRARY_TABLE_SCOPE aScope)
Add an existing library to a library table (presumed to be either the global or project design block ...
int ShowModal() override
The base class for create windows for drawing purpose.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
Helper class to create more flexible dialogs, including 'do not show again' checkbox handling.
Definition kidialog.h:42
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:55
int ShowModal() override
Definition kidialog.cpp:93
void ReloadTables(LIBRARY_TABLE_SCOPE aScope, std::initializer_list< LIBRARY_TABLE_TYPE > aTablesToLoad={})
std::optional< LIBRARY_TABLE * > Table(LIBRARY_TABLE_TYPE aType, LIBRARY_TABLE_SCOPE aScope)
Retrieves a given table; creating a new empty project table if a valid project is loaded and the give...
void SetNickname(const wxString &aNickname)
void SetType(const wxString &aType)
void SetDescription(const wxString &aDescription)
void SetURI(const wxString &aUri)
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
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:131
wxString wx_str() const
Definition utf8.cpp:45
WX_PANEL(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxSize(-1,-1), long style=wxTAB_TRAVERSAL, const wxString &name=wxEmptyString)
Definition wx_panel.cpp:28
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:150
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:259
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:202
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:177
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
LIBRARY_TABLE_SCOPE
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:946
see class PGM_BASE
wxString message
Definition of file extensions used in Kicad.