KiCad PCB EDA Suite
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
pcb_design_block_utils.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 <pgm_base.h>
25#include <kiway.h>
26#include <board_commit.h>
27#include <design_block.h>
29#include <footprint.h>
30#include <pad.h>
32#include <pcb_edit_frame.h>
33#include <pcb_io/pcb_io.h>
34#include <pcb_io/pcb_io_mgr.h>
35#include <wx/choicdlg.h>
36#include <wx/msgdlg.h>
37#include <wx/textdlg.h>
39#include <paths.h>
40#include <env_paths.h>
41#include <common.h>
42#include <confirm.h>
43#include <kidialog.h>
44#include <locale_io.h>
45#include <netinfo.h>
46#include <tool/tool_manager.h>
49#include <nlohmann/json.hpp>
50
51bool checkOverwriteDb( wxWindow* aFrame, wxString& libname, wxString& newName )
52{
53 wxString msg = wxString::Format( _( "Design block '%s' already exists in library '%s'." ), newName.GetData(),
54 libname.GetData() );
55
56 if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing design block?" ), _( "Overwrite" ) )
57 != wxID_OK )
58 {
59 return false;
60 }
61
62 return true;
63}
64
65
66bool checkOverwriteDbLayout( wxWindow* aFrame, const LIB_ID& aLibId )
67{
68 wxString msg = wxString::Format( _( "Design block '%s' already has a layout." ), aLibId.GetUniStringLibItemName() );
69
70 if( OKOrCancelDialog( aFrame, _( "Confirmation" ), msg, _( "Overwrite existing layout?" ), _( "Overwrite" ) )
71 != wxID_OK )
72 {
73 return false;
74 }
75
76 return true;
77}
78
79
80bool PCB_EDIT_FRAME::saveBoardAsFile( BOARD* aBoard, const wxString& aFileName, bool aHeadless )
81{
82 // Ensure the "C" locale is temporary set, before saving any file
83 // It also avoid wxWidget alerts about locale issues, later, when using Python 3
85
86 wxFileName pcbFileName( aFileName );
87
88 if( !IsWritable( pcbFileName ) )
89 {
90 if( !aHeadless )
91 {
92 DisplayError( this, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
93 pcbFileName.GetFullPath() ) );
94 }
95 return false;
96 }
97
98 try
99 {
101
102 wxASSERT( pcbFileName.IsAbsolute() );
103
104 pi->SaveBoard( pcbFileName.GetFullPath(), aBoard, nullptr );
105 }
106 catch( const IO_ERROR& ioe )
107 {
108 if( !aHeadless )
109 {
110 DisplayError( this, wxString::Format( _( "Error saving board file '%s'.\n%s" ), pcbFileName.GetFullPath(),
111 ioe.What() ) );
112 }
113
114 return false;
115 }
116
117 return true;
118}
119
120
121bool PCB_EDIT_FRAME::SaveBoardAsDesignBlock( const wxString& aLibraryName )
122{
123 // Make sure the user has selected a library to save into
125 {
126 DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
127 return false;
128 }
129
130 DESIGN_BLOCK blk;
131 wxFileName fn = wxFileNameFromPath( GetBoard()->GetFileName() );
132
133 blk.SetLibId( LIB_ID( aLibraryName, fn.GetName() ) );
134
135 DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, &blk );
136
137 if( dlg.ShowModal() != wxID_OK )
138 return false;
139
140 wxString libName = blk.GetLibId().GetLibNickname();
141 wxString newName = blk.GetLibId().GetLibItemName();
142
143 if( Prj().DesignBlockLibs()->DesignBlockExists( libName, newName ) && !checkOverwriteDb( this, libName, newName ) )
144 {
145 return false;
146 }
147
148 // Save a temporary copy of the schematic file, as the plugin is just going to move it
149 wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
150
151 if( !SavePcbCopy( tempFile, false, false ) )
152 {
153 DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
154 wxRemoveFile( tempFile );
155 return false;
156 }
157
158 blk.SetBoardFile( tempFile );
159
160 bool success = false;
161
162 try
163 {
164 success = Prj().DesignBlockLibs()->DesignBlockSave( aLibraryName, &blk ) == DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
165 }
166 catch( const IO_ERROR& ioe )
167 {
168 DisplayError( this, ioe.What() );
169 }
170
171 // Clean up the temporary file
172 wxRemoveFile( tempFile );
173
176
177 return success;
178}
179
180
182{
183 // Make sure the user has selected a library to save into
185 {
186 DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
187 return false;
188 }
189
190 DESIGN_BLOCK* blk = nullptr;
191
192 try
193 {
194 blk = Prj().DesignBlockLibs()->DesignBlockLoad( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
195 }
196 catch( const IO_ERROR& ioe )
197 {
198 DisplayError( this, ioe.What() );
199 return false;
200 }
201
202 if( !blk->GetBoardFile().IsEmpty() && !checkOverwriteDbLayout( this, aLibId ) )
203 {
204 return false;
205 }
206
207 // Save a temporary copy of the schematic file, as the plugin is just going to move it
208 wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
209
210 if( !SavePcbCopy( tempFile, false, false ) )
211 {
212 DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
213 wxRemoveFile( tempFile );
214 return false;
215 }
216
217 blk->SetBoardFile( tempFile );
218
219 bool success = false;
220
221 try
222 {
223 success = Prj().DesignBlockLibs()->DesignBlockSave( aLibId.GetLibNickname(), blk )
225 }
226 catch( const IO_ERROR& ioe )
227 {
228 DisplayError( this, ioe.What() );
229 }
230
231 // Clean up the temporary file
232 wxRemoveFile( tempFile );
233
236
237 return success;
238}
239
240
241bool PCB_EDIT_FRAME::saveSelectionToDesignBlock( const wxString& aNickname, PCB_SELECTION& aSelection,
242 DESIGN_BLOCK& aBlock )
243{
244 // Create a temporary board
245 BOARD* tempBoard = new BOARD();
247 tempBoard->SetProject( &Prj(), true );
248 tempBoard->SynchronizeProperties();
249
250 // For copying net info of selected items into the new board
251 auto addNetIfNeeded =
252 [&]( EDA_ITEM* aItem )
253 {
254 BOARD_CONNECTED_ITEM* cItem = dynamic_cast<BOARD_CONNECTED_ITEM*>( aItem );
255
256 if( cItem && cItem->GetNetCode() )
257 {
258 NETINFO_ITEM* netinfo = cItem->GetNet();
259
260 if( netinfo && !tempBoard->FindNet( netinfo->GetNetname() ) )
261 tempBoard->Add( netinfo );
262 }
263 };
264
265 // Copy the selected items to the temporary board
266 for( EDA_ITEM* item : aSelection )
267 {
268 EDA_ITEM* copy = item->Clone();
269 tempBoard->Add( static_cast<BOARD_ITEM*>( copy ), ADD_MODE::APPEND, false );
270
271 if( FOOTPRINT* fp = dynamic_cast<FOOTPRINT*>( item ) )
272 fp->RunOnChildren( addNetIfNeeded, RECURSE_MODE::NO_RECURSE );
273 else
274 addNetIfNeeded( copy );
275 }
276
277 // Rebuild connectivity, remove any unused nets
278 tempBoard->BuildListOfNets();
279 tempBoard->BuildConnectivity();
280
281 wxString tempFile = wxFileName::CreateTempFileName( "design_block" );
282
283 if( !saveBoardAsFile( tempBoard, tempFile, false ) )
284 {
285 DisplayErrorMessage( this, _( "Error saving temporary board file to create design block." ) );
286 wxRemoveFile( tempFile );
287 return false;
288 }
289
290 aBlock.SetBoardFile( tempFile );
291
292 bool success = false;
293
294 try
295 {
296 success = Prj().DesignBlockLibs()->DesignBlockSave( aNickname, &aBlock ) == DESIGN_BLOCK_LIB_TABLE::SAVE_OK;
297 }
298 catch( const IO_ERROR& ioe )
299 {
300 DisplayError( this, ioe.What() );
301 }
302
303 // Clean up the temporary file
304 wxRemoveFile( tempFile );
305
308
309 return success;
310}
311
312
313bool PCB_EDIT_FRAME::SaveSelectionAsDesignBlock( const wxString& aLibraryName )
314{
315 // Make sure the user has selected a library to save into
317 {
318 DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
319 return false;
320 }
321
322 // Get all selected items
323 PCB_SELECTION selection = m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
324
325 if( selection.Empty() )
326 {
327 DisplayErrorMessage( this, _( "Please select some items to save as a design block." ) );
328 return false;
329 }
330
331 DESIGN_BLOCK blk;
332 wxFileName fn = wxFileNameFromPath( GetBoard()->GetFileName() );
333
334 blk.SetLibId( LIB_ID( aLibraryName, fn.GetName() ) );
335
336 DIALOG_DESIGN_BLOCK_PROPERTIES dlg( this, &blk );
337
338 if( dlg.ShowModal() != wxID_OK )
339 return false;
340
341 wxString libName = blk.GetLibId().GetLibNickname();
342 wxString newName = blk.GetLibId().GetLibItemName();
343
344 if( Prj().DesignBlockLibs()->DesignBlockExists( libName, newName ) && !checkOverwriteDb( this, libName, newName ) )
345 {
346 return false;
347 }
348
349 return saveSelectionToDesignBlock( libName, selection, blk );
350}
351
352
354{
355 // Make sure the user has selected a library to save into
356 if( !aLibId.IsValid() )
357 {
358 DisplayErrorMessage( this, _( "Please select a library to save the design block to." ) );
359 return false;
360 }
361
362 // Get all selected items
363 PCB_SELECTION selection = m_toolManager->GetTool<PCB_SELECTION_TOOL>()->GetSelection();
364
365 if( selection.Empty() )
366 {
367 DisplayErrorMessage( this, _( "Please select some items to save as a design block." ) );
368 return false;
369 }
370
371 DESIGN_BLOCK* blk = nullptr;
372
373 try
374 {
375 blk = Prj().DesignBlockLibs()->DesignBlockLoad( aLibId.GetLibNickname(), aLibId.GetLibItemName() );
376 }
377 catch( const IO_ERROR& ioe )
378 {
379 DisplayError( this, ioe.What() );
380 return false;
381 }
382
383 if( !blk->GetBoardFile().IsEmpty() && !checkOverwriteDbLayout( this, aLibId ) )
384 {
385 return false;
386 }
387
388 return saveSelectionToDesignBlock( aLibId.GetLibNickname(), selection, *blk );
389}
A base class derived from BOARD_ITEM for items that can be connected and have a net,...
NETINFO_ITEM * GetNet() const
Return #NET_INFO object for a given item.
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
Definition: board_item.h:78
Information pertinent to a Pcbnew printed circuit board.
Definition: board.h:297
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT, bool aSkipConnectivity=false) override
Removes an item from the container.
Definition: board.cpp:1060
void BuildListOfNets()
Definition: board.h:860
NETINFO_ITEM * FindNet(int aNetcode) const
Search for a net with the given netcode.
Definition: board.cpp:2011
void SetDesignSettings(const BOARD_DESIGN_SETTINGS &aSettings)
Definition: board.cpp:952
bool BuildConnectivity(PROGRESS_REPORTER *aReporter=nullptr)
Build or rebuild the board connectivity database for the board, especially the list of connected item...
Definition: board.cpp:185
void SetProject(PROJECT *aProject, bool aReferenceOnly=false)
Link a board to a given project.
Definition: board.cpp:195
void SynchronizeProperties()
Copy the current project's text variables into the boards property cache.
Definition: board.cpp:2135
DESIGN_BLOCK * DesignBlockLoad(const wxString &aNickname, const wxString &aDesignBlockName, bool aKeepUUID=false)
Load a design block having 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.
void SelectLibId(const LIB_ID &aLibId)
LIB_ID GetSelectedLibId(int *aUnit=nullptr) const
void SetBoardFile(const wxString &aFile)
Definition: design_block.h:49
void SetLibId(const LIB_ID &aName)
Definition: design_block.h:36
const wxString & GetBoardFile() const
Definition: design_block.h:48
const LIB_ID & GetLibId() const
Definition: design_block.h:37
int ShowModal() override
bool IsWritable(const wxFileName &aFileName, bool aVerbose=true)
Check if aFileName can be written.
A base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:95
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
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 wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
Definition: lib_id.h:112
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
Instantiate the current locale within a scope in which you are expecting exceptions to be thrown.
Definition: locale_io.h:49
Handle the data for a net.
Definition: netinfo.h:56
const wxString & GetNetname() const
Definition: netinfo.h:114
BOARD * GetBoard() const
virtual BOARD_DESIGN_SETTINGS & GetDesignSettings() const
Return the BOARD_DESIGN_SETTINGS for the open project.
bool saveBoardAsFile(BOARD *aBoard, const wxString &aFileName, bool aHeadless=false)
Save a board object to a file.
bool SaveBoardToDesignBlock(const LIB_ID &aLibId)
bool saveSelectionToDesignBlock(const wxString &aNickname, PCB_SELECTION &aSelection, DESIGN_BLOCK &aBlock)
bool SavePcbCopy(const wxString &aFileName, bool aCreateProject=false, bool aHeadless=false)
Write the board data structures to aFileName.
bool SaveSelectionAsDesignBlock(const wxString &aLibraryName)
bool SaveSelectionToDesignBlock(const LIB_ID &aLibId)
bool SaveBoardAsDesignBlock(const wxString &aLibraryName)
PCB_DESIGN_BLOCK_PANE * m_designBlocksPane
static PCB_IO * PluginFind(PCB_FILE_T aFileType)
Return a #PLUGIN which the caller can use to import, export, save, or load design documents.
Definition: pcb_io_mgr.cpp:69
@ KICAD_SEXP
S-expression Pcbnew file format.
Definition: pcb_io_mgr.h:58
The selection tool: currently supports:
virtual DESIGN_BLOCK_LIB_TABLE * DesignBlockLibs()
Return the table of design block libraries.
Definition: project.cpp:429
bool Empty() const
Checks if there is anything selected.
Definition: selection.h:110
TOOL_MANAGER * m_toolManager
Definition: tools_holder.h:171
bool empty() const
Definition: utf8.h:104
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
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)
Helper functions to substitute paths with environmental variables.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
Definition: io_mgr.h:33
PROJECT & Prj()
Definition: kicad.cpp:597
This file is part of the common library.
bool checkOverwriteDb(wxWindow *aFrame, wxString &libname, wxString &newName)
bool checkOverwriteDbLayout(wxWindow *aFrame, const LIB_ID &aLibId)
see class PGM_BASE
bool checkOverwriteDb(wxWindow *aFrame, wxString &libname, wxString &newName)
std::vector< FAB_LAYER_COLOR > dummy
Definition of file extensions used in Kicad.