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 <paths.h>
27#include <env_paths.h>
28#include <pgm_base.h>
29#include <common.h>
30#include <kidialog.h>
35#include <kiface_base.h>
36#include <core/kicad_algo.h>
37#include <template_fieldnames.h>
38#include <wx/sizer.h>
39#include <wx/textdlg.h>
40#include <confirm.h>
42#include <tool/tool_manager.h>
43
45 std::vector<LIB_ID>& aHistoryList ) :
46 WX_PANEL( aParent ),
47 m_frame( aParent )
48{
49 m_frame->Bind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
50 m_frame->Bind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
51}
52
53
55{
56 m_frame->Unbind( wxEVT_AUI_PANE_CLOSE, &DESIGN_BLOCK_PANE::OnClosed, this );
57 m_frame->Unbind( EDA_LANG_CHANGED, &DESIGN_BLOCK_PANE::OnLanguageChanged, this );
58}
59
60
61void DESIGN_BLOCK_PANE::OnLanguageChanged( wxCommandEvent& aEvent )
62{
63 if( m_chooserPanel )
64 m_chooserPanel->ShowChangedLanguage();
65
67
68 aEvent.Skip();
69}
70
71
72void DESIGN_BLOCK_PANE::OnClosed( wxAuiManagerEvent& aEvent )
73{
74 if( APP_SETTINGS_BASE* cfg = m_frame->config() )
75 {
76 if( IsShownOnScreen() ) // Ensure the panel is shown when trying to save its size
77 m_frame->SaveSettings( cfg );
78 }
79
80 aEvent.Skip();
81}
82
83
85{
86 m_chooserPanel->SaveSettings();
87}
88
89
91{
92 return m_chooserPanel->GetSelectedLibId( aUnit );
93}
94
95
97{
98 m_chooserPanel->SelectLibId( aLibId );
99}
100
101
103{
104 m_chooserPanel->RefreshLibs();
105}
106
107
108DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
109{
110 DESIGN_BLOCK_LIB_TABLE* prjLibs = m_frame->Prj().DesignBlockLibs();
111
112 wxCHECK_MSG( prjLibs, nullptr, wxS( "Invalid design block library table." ) );
113
114 DESIGN_BLOCK* designBlock = nullptr;
115
116 try
117 {
118 designBlock = prjLibs->DesignBlockLoadWithOptionalNickname( aLibId, true );
119 }
120 catch( const IO_ERROR& ioe )
121 {
122 if( aShowErrorMsg )
123 {
124 wxString msg = wxString::Format( _( "Error loading design block %s from library '%s'." ),
125 aLibId.GetLibItemName().wx_str(), aLibId.GetLibNickname().wx_str() );
126 DisplayErrorMessage( m_frame, msg, ioe.What() );
127 }
128 }
129
130 return designBlock;
131}
132
133
134DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetSelectedDesignBlock( bool aUseCacheLib, bool aShowErrorMsg )
135{
136 if( !GetSelectedLibId().IsValid() )
137 return nullptr;
138
139 return GetDesignBlock( GetSelectedLibId(), aUseCacheLib, aShowErrorMsg );
140}
141
142
143wxString DESIGN_BLOCK_PANE::CreateNewDesignBlockLibrary( const wxString& aDialogTitle )
144{
145 return createNewDesignBlockLibrary( aDialogTitle );
146}
147
148
149wxString DESIGN_BLOCK_PANE::createNewDesignBlockLibrary( const wxString& aDialogTitle )
150{
151 wxFileName fn;
152 bool isGlobal = false;
153 FILEDLG_HOOK_NEW_LIBRARY tableChooser( isGlobal );
154
155 if( !m_frame->LibraryFileBrowser( aDialogTitle, false, fn, FILEEXT::KiCadDesignBlockLibPathWildcard(),
156 FILEEXT::KiCadDesignBlockLibPathExtension, false, &tableChooser ) )
157 {
158 return wxEmptyString;
159 }
160
161 isGlobal = tableChooser.GetUseGlobalTable();
163 : m_frame->Prj().DesignBlockLibs();
164
165 // We can save libs only using DESIGN_BLOCK_IO_MGR::KICAD_SEXP format (.pretty libraries)
167 wxString libPath = fn.GetFullPath();
168
169 try
170 {
172
173 bool writable = false;
174 bool exists = false;
175
176 try
177 {
178 writable = pi->IsLibraryWritable( libPath );
179 exists = fn.Exists();
180 }
181 catch( const IO_ERROR& )
182 {
183 // best efforts....
184 }
185
186 if( exists )
187 {
188 if( !writable )
189 {
190 wxString msg = wxString::Format( _( "Library %s is read only." ), libPath );
191 m_frame->ShowInfoBarError( msg );
192 return wxEmptyString;
193 }
194 else
195 {
196 wxString msg = wxString::Format( _( "Library %s already exists." ), libPath );
197 KIDIALOG dlg( m_frame, msg, _( "Confirmation" ), wxOK | wxCANCEL | wxICON_WARNING );
198 dlg.SetOKLabel( _( "Overwrite" ) );
199 dlg.DoNotShowCheckbox( __FILE__, __LINE__ );
200
201 if( dlg.ShowModal() == wxID_CANCEL )
202 return wxEmptyString;
203
204 pi->DeleteLibrary( libPath );
205 }
206 }
207
208 pi->CreateLibrary( libPath );
209 }
210 catch( const IO_ERROR& ioe )
211 {
212 DisplayError( m_frame, ioe.What() );
213 return wxEmptyString;
214 }
215
216 AddDesignBlockLibrary( aDialogTitle, libPath, libTable );
217
218 return libPath;
219}
220
221
222bool DESIGN_BLOCK_PANE::AddDesignBlockLibrary( const wxString& aDialogTitle, const wxString& aFilename,
223 DESIGN_BLOCK_LIB_TABLE* aTable )
224{
225 bool isGlobal = ( aTable == &DESIGN_BLOCK_LIB_TABLE::GetGlobalLibTable() );
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:" ), _( "Library Description" ),
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 try
253 {
254 DESIGN_BLOCK_LIB_TABLE_ROW* row = new DESIGN_BLOCK_LIB_TABLE_ROW( libName, normalizedPath, type,
255 wxEmptyString, description );
256 aTable->InsertRow( row );
257
258 if( isGlobal )
260 else
261 aTable->Save( m_frame->Prj().DesignBlockLibTblName() );
262 }
263 catch( const IO_ERROR& ioe )
264 {
265 DisplayError( m_frame, ioe.What() );
266 return false;
267 }
268
269 LIB_ID libID( libName, wxEmptyString );
270 RefreshLibs();
271 SelectLibId( libID );
272
273 return true;
274}
275
276
277bool DESIGN_BLOCK_PANE::DeleteDesignBlockLibrary( const wxString& aLibName, bool aConfirm )
278{
279 if( aLibName.IsEmpty() )
280 {
281 DisplayErrorMessage( m_frame, _( "Please select a library to delete." ) );
282 return false;
283 }
284
285 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( aLibName ) )
286 {
287 wxString msg = wxString::Format( _( "Library '%s' is read only." ), aLibName );
288 m_frame->ShowInfoBarError( msg );
289 return false;
290 }
291
292 // Confirmation
293 wxString msg = wxString::Format( _( "Delete design block library '%s' from disk? This will "
294 "delete all design blocks within the library." ),
295 aLibName.GetData() );
296
297 if( aConfirm && !IsOK( m_frame, msg ) )
298 return false;
299
300 try
301 {
302 m_frame->Prj().DesignBlockLibs()->DesignBlockLibDelete( aLibName );
303 }
304 catch( const IO_ERROR& ioe )
305 {
306 DisplayError( m_frame, ioe.What() );
307 return false;
308 }
309
310 msg.Printf( _( "Design block library '%s' deleted" ), aLibName.GetData() );
311 m_frame->SetStatusText( msg );
312
313 RefreshLibs();
314
315 return true;
316}
317
318
319bool DESIGN_BLOCK_PANE::DeleteDesignBlockFromLibrary( const LIB_ID& aLibId, bool aConfirm )
320{
321 if( !aLibId.IsValid() )
322 return false;
323
324 wxString libname = aLibId.GetLibNickname();
325 wxString dbname = aLibId.GetLibItemName();
326
327 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
328 {
329 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
330 m_frame->ShowInfoBarError( msg );
331 return false;
332 }
333
334 // Confirmation
335 wxString msg = wxString::Format( _( "Delete design block '%s' in library '%s' from disk?" ),
336 dbname.GetData(), libname.GetData() );
337
338 if( aConfirm && !IsOK( m_frame, msg ) )
339 return false;
340
341 try
342 {
343 m_frame->Prj().DesignBlockLibs()->DesignBlockDelete( libname, dbname );
344 }
345 catch( const IO_ERROR& ioe )
346 {
347 DisplayError( m_frame, ioe.What() );
348 return false;
349 }
350
351 msg.Printf( _( "Design block '%s' deleted from library '%s'" ), dbname.GetData(), libname.GetData() );
352
353 m_frame->SetStatusText( msg );
354
355 RefreshLibs();
356
357 return true;
358}
359
360
362{
363 if( !aLibId.IsValid() )
364 return false;
365
366 wxString libname = aLibId.GetLibNickname();
367 wxString dbname = aLibId.GetLibItemName();
368
369 if( !m_frame->Prj().DesignBlockLibs()->IsDesignBlockLibWritable( libname ) )
370 {
371 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
372 m_frame->ShowInfoBarError( msg );
373 return false;
374 }
375
376 std::unique_ptr<DESIGN_BLOCK> designBlock( GetDesignBlock( aLibId, true, true ) );
377
378 if( !designBlock )
379 return false;
380
381 wxString originalName = designBlock->GetLibId().GetLibItemName();
382 DIALOG_DESIGN_BLOCK_PROPERTIES dlg( m_frame, designBlock.get() );
383
384 if( dlg.ShowModal() != wxID_OK )
385 return false;
386
387 wxString newName = designBlock->GetLibId().GetLibItemName();
388
389 try
390 {
391 if( originalName != newName )
392 {
393 if( m_frame->Prj().DesignBlockLibs()->DesignBlockExists( libname, newName ) )
394 if( !checkOverwrite( m_frame, libname, newName ) )
395 return false;
396
397 m_frame->Prj().DesignBlockLibs()->DesignBlockSave( libname, designBlock.get() );
398 m_frame->Prj().DesignBlockLibs()->DesignBlockDelete( libname, originalName );
399 }
400 else
401 {
402 m_frame->Prj().DesignBlockLibs()->DesignBlockSave( libname, designBlock.get() );
403 }
404 }
405 catch( const IO_ERROR& ioe )
406 {
407 DisplayError( m_frame, ioe.What() );
408 return false;
409 }
410
411 RefreshLibs();
412 SelectLibId( designBlock->GetLibId() );
413
414 return true;
415}
416
417
418bool DESIGN_BLOCK_PANE::checkOverwrite( wxWindow* aFrame, wxString& libname, wxString& newName )
419{
420 wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ),
421 newName.GetData(), libname.GetData() );
422
423 if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
424 != wxID_OK )
425 {
426 return false;
427 }
428
429 return true;
430}
431
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)
Hold a record identifying a library accessed by the appropriate design block library #PLUGIN object i...
static wxString GetGlobalTableFileName()
DESIGN_BLOCK * DesignBlockLoadWithOptionalNickname(const LIB_ID &aDesignBlockId, bool aKeepUUID=false)
Load a design block having aDesignBlockId with possibly an empty nickname.
static DESIGN_BLOCK_LIB_TABLE & GetGlobalLibTable()
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
bool AddDesignBlockLibrary(const wxString &aDialogTitle, const wxString &aFilename, DESIGN_BLOCK_LIB_TABLE *aTable)
Add an existing library to a library table (presumed to be either the global or project design block ...
DESIGN_BLOCK * GetSelectedDesignBlock(bool aUseCacheLib, bool aShowErrorMsg)
void OnClosed(wxAuiManagerEvent &aEvent)
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
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.
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:142
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Display a yes/no dialog with aMessage and returns the user response.
Definition confirm.cpp:251
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:169
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
PGM_BASE & Pgm()
The global program "get" accessor.
Definition pgm_base.cpp:913
see class PGM_BASE
Definition of file extensions used in Kicad.