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 )
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{
87}
88
89
91{
92 return m_chooserPanel->GetSelectedLibId( aUnit );
93}
94
95
97{
98 m_chooserPanel->SelectLibId( aLibId );
99}
100
101
103{
105}
106
107
108DESIGN_BLOCK* DESIGN_BLOCK_PANE::GetDesignBlock( const LIB_ID& aLibId, bool aUseCacheLib, bool aShowErrorMsg )
109{
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
156 FILEEXT::KiCadDesignBlockLibPathExtension, false, &tableChooser ) )
157 {
158 return wxEmptyString;
159 }
160
161 isGlobal = tableChooser.GetUseGlobalTable();
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 );
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 );
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 {
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
328 {
329 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
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
370 {
371 wxString msg = wxString::Format( _( "Library '%s' is read only." ), libname );
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.
Definition: app_settings.h:108
@ 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 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.
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
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(const wxString &aTitle, bool doOpen, wxFileName &aFilename, const wxString &wildcard, const wxString &ext, bool isDirectory, FILEDLG_HOOK_NEW_LIBRARY *aFileDlgHook=nullptr)
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:50
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)
virtual const wxString DesignBlockLibTblName() const
Return the path and file name of this projects design block library table.
Definition: project.cpp:185
virtual DESIGN_BLOCK_LIB_TABLE * DesignBlockLibs()
Return the table of design block libraries.
Definition: project.cpp:432
wxString wx_str() const
Definition: utf8.cpp:45
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
This file is part of the common library.
PGM_BASE & Pgm()
The global program "get" accessor.
Definition: pgm_base.cpp:902
see class PGM_BASE
Definition of file extensions used in Kicad.