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, see <https://www.gnu.org/licenses/>.
18 */
19
20#include <design_block.h>
22#include <design_block_io.h>
23#include <paths.h>
24#include <env_paths.h>
25#include <pgm_base.h>
26#include <common.h>
27#include <kidialog.h>
32#include <kiface_base.h>
33#include <core/kicad_algo.h>
34#include <template_fieldnames.h>
35#include <wx/sizer.h>
36#include <wx/textdlg.h>
37#include <confirm.h>
39#include <tool/tool_manager.h>
40
42 std::vector<LIB_ID>& aHistoryList ) :
43 WX_PANEL( aParent ),
44 m_frame( aParent )
45{
46 m_frame->Bind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
47 m_frame->Bind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
48}
49
50
52{
53 m_frame->Unbind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
54 m_frame->Unbind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
55}
56
57
58void DESIGN_BLOCK_PANE::OnLanguageChanged( wxCommandEvent& aEvent )
59{
60 if( m_chooserPanel )
61 m_chooserPanel->ShowChangedLanguage();
62
64
65 aEvent.Skip();
66}
67
68
69void DESIGN_BLOCK_PANE::OnClosed( wxAuiManagerEvent& aEvent )
70{
71 if( APP_SETTINGS_BASE* cfg = m_frame->config() )
72 {
73 if( IsShownOnScreen() ) // Ensure the panel is shown when trying to save its size
74 m_frame->SaveSettings( cfg );
75 }
76
77 aEvent.Skip();
78}
79
80
82{
83 m_chooserPanel->SaveSettings();
84}
85
86
88{
89 return m_chooserPanel->GetSelectedLibId( aUnit );
90}
91
92
94{
95 m_chooserPanel->SelectLibId( aLibId );
96}
97
98
100{
101 m_chooserPanel->RefreshLibs();
102}
103
104
105DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
106{
107 DESIGN_BLOCK_LIBRARY_ADAPTER* prjLibs = m_frame->Prj().DesignBlockLibs();
108
109 wxCHECK_MSG( prjLibs, nullptr, wxS( "Invalid design block library table." ) );
110
111 DESIGN_BLOCK* designBlock = nullptr;
112
113 try
114 {
115 designBlock = prjLibs->DesignBlockLoadWithOptionalNickname( aLibId, true );
116 }
117 catch( const IO_ERROR& ioe )
118 {
119 if( aShowErrorMsg )
120 {
121 wxString msg = wxString::Format( _( "Error loading design block %s from library '%s'." ),
122 aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str() );
123 DisplayErrorMessage( m_frame, msg, ioe.What() );
124 }
125 }
126
127 return designBlock;
128}
129
130
131DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetSelectedDesignBlock( bool aUseCacheLib, bool aShowErrorMsg )
132{
133 if( !GetSelectedLibId().IsValid() )
134 return nullptr;
135
136 return GetDesignBlock( GetSelectedLibId(), aUseCacheLib, aShowErrorMsg );
137}
138
139
140wxString DESIGN_BLOCK_PANE::CreateNewDesignBlockLibrary( const wxString& aDialogTitle )
141{
142 return createNewDesignBlockLibrary( aDialogTitle );
143}
144
145
146wxString DESIGN_BLOCK_PANE::createNewDesignBlockLibrary( const wxString& aDialogTitle )
147{
148 wxFileName fn;
149 static bool isGlobal = true;
150 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
151
152 if( !m_frame->LibraryFileBrowser( aDialogTitle, false, fn, FILEEXT::KiCadDesignBlockLibPathWildcard(),
153 FILEEXT::KiCadDesignBlockLibPathExtension, false, &tableChooser ) )
154 {
155 return wxEmptyString;
156 }
157
158 isGlobal = tableChooser.GetUseGlobalTable();
159
160 wxString libPath = fn.GetFullPath();
161
163
164 // We can save libs only using DESIGN_BLOCK_IO_MGR::KICAD_SEXP format (.pretty libraries)
166
167 try
168 {
170
171 bool writable = false;
172 bool exists = false;
173
174 try
175 {
176 writable = pi->IsLibraryWritable( libPath );
177 exists = fn.Exists();
178 }
179 catch( const IO_ERROR& )
180 {
181 // best efforts....
182 }
183
184 if( exists )
185 {
186 if( !writable )
187 {
188 wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
189 m_frame->ShowInfoBarError( msg );
190 return wxEmptyString;
191 }
192 else
193 {
194 wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
195 KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
196 dlg.SetOKLabel( _( "Overwrite" ) );
197 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
198
199 if( dlg.ShowModal() == wxID_CANCEL )
200 return wxEmptyString;
201
202 pi->DeleteLibrary( libPath );
203 }
204 }
205
206 pi->CreateLibrary( libPath );
207 }
208 catch( const IO_ERROR& ioe )
209 {
210 DisplayError( m_frame, ioe.What() );
211 return wxEmptyString;
212 }
213
214 AddDesignBlockLibrary( aDialogTitle, libPath, scope );
215
216 return libPath;
217}
218
219
220bool DESIGN_BLOCK_PANE::AddDesignBlockLibrary( const wxString& aDialogTitle, const wxString& aFilename,
221 LIBRARY_TABLE_SCOPE aScope )
222{
223 DESIGN_BLOCK_LIBRARY_ADAPTER* adapter = m_frame->Prj().DesignBlockLibs();
225
226 wxFileName fn( aFilename );
227 wxString libPath = fn.GetFullPath();
228 wxString libName = fn.GetName();
229
230 if( libName.IsEmpty() )
231 return false;
232
233 // Open a dialog to ask for a description
234 wxString description = wxGetTextFromUser( _( "Enter a description for the library:" ), aDialogTitle,
235 wxEmptyString, m_frame );
236
238
241
242 wxString type = DESIGN_BLOCK_IO_MGR::ShowType( lib_type );
243
244 // KiCad lib is our default guess. So it might not have the .kicad_blocks extension
245 // In this case, the extension is part of the library name
247 libName = fn.GetFullName();
248
249 // try to use path normalized to an environmental variable or project path
250 wxString normalizedPath = NormalizePath( libPath, &Pgm().GetLocalEnvVariables(), &m_frame->Prj() );
251
252 std::optional<LIBRARY_TABLE*> optTable = manager.Table( LIBRARY_TABLE_TYPE::DESIGN_BLOCK, aScope );
253 wxCHECK( optTable.has_value(), false );
254 LIBRARY_TABLE* table = optTable.value();
255
256 bool success = true;
257 LIBRARY_TABLE_ROW& newRow = table->InsertRow();
258
259 newRow.SetNickname( libName );
260 newRow.SetURI( normalizedPath );
261 newRow.SetType( type );
262 newRow.SetDescription( description );
263
264 table->Save().map_error(
265 [&]( const LIBRARY_ERROR& aError )
266 {
267 DisplayError( m_frame, _( "Error saving library table:\n\n" ) + aError.message );
268 success = false;
269 } );
270
271 if( success )
272 {
273 manager.ReloadTables( aScope, { LIBRARY_TABLE_TYPE::DESIGN_BLOCK } );
274 adapter->LoadOne( libName );
275
276 LIB_ID libID( libName, wxEmptyString );
277 RefreshLibs();
278 SelectLibId( libID );
279 }
280
281 return true;
282}
283
284
285bool DESIGN_BLOCK_PANE::DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm )
286{
287 if( aLibName.IsEmpty() )
288 {
289 DisplayErrorMessage( m_frame, _( "Please select a library to delete." ) );
290 return false;
291 }
292
293 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( aLibName ) )
294 {
295 wxString msg = wxString::Format( _( "Library '%s' is read only." ), aLibName );
296 m_frame->ShowInfoBarError( msg );
297 return false;
298 }
299
300 // Confirmation
301 wxString msg = wxString::Format( _( "Delete design block library '%s' from disk? This will "
302 "delete all design blocks within the library." ),
303 aLibName.GetData() );
304
305 if( aConfirm && !IsOK( m_frame, msg ) )
306 return false;
307
308 try
309 {
310 m_frame->Prj().DesignBlockLibs()->DeleteLibrary( aLibName );
311 }
312 catch( const IO_ERROR& ioe )
313 {
314 DisplayError( m_frame, ioe.What() );
315 return false;
316 }
317
318 msg.Printf( _( "Design block library '%s' deleted" ), aLibName.GetData() );
319 m_frame->SetStatusText( msg );
320
321 RefreshLibs();
322
323 return true;
324}
325
326
327bool DESIGN_BLOCK_PANE::DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm )
328{
329 if( !aLibId.IsValid() )
330 return false;
331
332 wxString libname = aLibId.GetLibNickname();
333 wxString dbname = aLibId.GetLibItemName();
334
335 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
336 {
337 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
338 m_frame->ShowInfoBarError( msg );
339 return false;
340 }
341
342 // Confirmation
343 wxString msg = wxString::Format( _( "Delete design block '%s' in library '%s' from disk?" ),
344 dbname.GetData(), libname.GetData() );
345
346 if( aConfirm && !IsOK( m_frame, msg ) )
347 return false;
348
349 try
350 {
351 m_frame->Prj().DesignBlockLibs()->DeleteDesignBlock( libname, dbname );
352 }
353 catch( const IO_ERROR& ioe )
354 {
355 DisplayError( m_frame, ioe.What() );
356 return false;
357 }
358
359 msg.Printf( _( "Design block '%s' deleted from library '%s'" ), dbname.GetData(), libname.GetData() );
360
361 m_frame->SetStatusText( msg );
362
363 RefreshLibs();
364
365 return true;
366}
367
368
370{
371 if( !aLibId.IsValid() )
372 return false;
373
374 wxString libname = aLibId.GetLibNickname();
375
376 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
377 {
378 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
379 m_frame->ShowInfoBarError( msg );
380 return false;
381 }
382
383 std::unique_ptr<DESIGN_BLOCK> designBlock( GetDesignBlock( aLibId, true, true ) );
384
385 if( !designBlock )
386 return false;
387
388 wxString originalName = designBlock->GetLibId().GetLibItemName();
389 DIALOG_DESIGN_BLOCK_PROPERTIES dlg( m_frame, designBlock.get() );
390
391 if( dlg.ShowModal() != wxID_OK )
392 return false;
393
394 wxString newName = designBlock->GetLibId().GetLibItemName();
395
396 try
397 {
398 if( originalName != newName )
399 {
400 if( m_frame->Prj().DesignBlockLibs()->DesignBlockExists( libname, newName ) )
401 {
402 if( !checkOverwrite( m_frame, libname, newName ) )
403 return false;
404 }
405
406 m_frame->Prj().DesignBlockLibs()->SaveDesignBlock( libname, designBlock.get() );
407 m_frame->Prj().DesignBlockLibs()->DeleteDesignBlock( libname, originalName );
408 }
409 else
410 {
411 m_frame->Prj().DesignBlockLibs()->SaveDesignBlock( libname, designBlock.get() );
412 }
413 }
414 catch( const IO_ERROR& ioe )
415 {
416 DisplayError( m_frame, ioe.What() );
417 return false;
418 }
419
420 RefreshLibs();
421 SelectLibId( designBlock->GetLibId() );
422
423 return true;
424}
425
426
427bool DESIGN_BLOCK_PANE::checkOverwrite( wxWindow* aFrame, wxString& libname, wxString& newName )
428{
429 wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ),
430 newName.GetData(), libname.GetData() );
431
432 if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
433 != wxID_OK )
434 {
435 return false;
436 }
437
438 return true;
439}
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
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:38
void DoNotShowCheckbox(wxString file, int line)
Shows the 'do not show again' checkbox.
Definition kidialog.cpp:51
int ShowModal() override
Definition kidialog.cpp:89
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:45
bool IsValid() const
Check if this LID_ID is valid.
Definition lib_id.h:168
const UTF8 & GetLibItemName() const
Definition lib_id.h:98
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Definition lib_id.h:83
virtual LIBRARY_MANAGER & GetLibraryManager() const
Definition pgm_base.h:126
wxString wx_str() const
Definition utf8.cpp:41
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:24
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:165
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:274
void DisplayErrorMessage(wxWindow *aParent, const wxString &aText, const wxString &aExtraInfo)
Display an error message with aMessage.
Definition confirm.cpp:217
void DisplayError(wxWindow *aParent, const wxString &aText)
Display an error or warning message box with aMessage.
Definition confirm.cpp:192
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.
see class PGM_BASE
wxString message
std::vector< std::vector< std::string > > table
Definition of file extensions used in Kicad.