KiCad PCB EDA Suite
load_select_footprint.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 (C) 2018 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
5  * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
31 #include <functional>
32 using namespace std::placeholders;
33 
34 #include <fctsys.h>
35 #include <class_drawpanel.h>
36 #include <pcb_draw_panel_gal.h>
37 #include <confirm.h>
38 #include <eda_doc.h>
39 #include <kicad_string.h>
40 #include <pgm_base.h>
41 #include <kiway.h>
42 #include <pcb_edit_frame.h>
43 #include <dialog_helpers.h>
44 #include <filter_reader.h>
45 #include <gr_basic.h>
46 #include <macros.h>
47 #include <fp_lib_table.h>
48 #include <lib_id.h>
49 #include <footprint_tree_pane.h>
50 #include <class_board.h>
51 #include <class_module.h>
52 #include <io_mgr.h>
53 
54 #include <pcbnew.h>
55 #include <footprint_edit_frame.h>
56 #include <footprint_info.h>
57 #include <footprint_info_impl.h>
59 #include <footprint_viewer_frame.h>
62 #include <widgets/lib_tree.h>
63 #include "fp_tree_model_adapter.h"
64 
65 
66 static wxArrayString s_ModuleHistoryList;
67 static unsigned s_ModuleHistoryMaxCount = 8;
68 
69 static void AddModuleToHistory( const wxString& aName )
70 {
71  // Remove duplicates
72  for( int ii = s_ModuleHistoryList.GetCount() - 1; ii >= 0; --ii )
73  {
74  if( s_ModuleHistoryList[ ii ] == aName )
75  s_ModuleHistoryList.RemoveAt( (size_t) ii );
76  }
77 
78  // Add the new name at the beginning of the history list
79  s_ModuleHistoryList.Insert( aName, 0 );
80 
81  // Remove extra names
82  while( s_ModuleHistoryList.GetCount() >= s_ModuleHistoryMaxCount )
83  s_ModuleHistoryList.RemoveAt( s_ModuleHistoryList.GetCount() - 1 );
84 }
85 
86 
87 static void clearModuleItemFlags( BOARD_ITEM* aItem )
88 {
89  aItem->ClearFlags();
90 }
91 
92 
94 {
95  MODULE* newModule;
96  PCB_EDIT_FRAME* frame = (PCB_EDIT_FRAME*) Kiway().Player( FRAME_PCB, false );
97 
98  if( frame == NULL ) // happens if no board editor opened
99  return false;
100 
101  if( aModule == NULL )
102  {
103  if( ! frame->GetBoard() || ! frame->GetBoard()->m_Modules )
104  return false;
105 
106  aModule = SelectFootprintFromBoard( frame->GetBoard() );
107  }
108 
109  if( aModule == NULL )
110  return false;
111 
112  SetCurItem( NULL );
113 
114  if( !Clear_Pcb( true ) )
115  return false;
116 
117  GetBoard()->m_Status_Pcb = 0;
118  newModule = new MODULE( *aModule );
119  newModule->SetParent( GetBoard() );
120  newModule->SetLink( aModule->GetTimeStamp() );
121 
122  newModule->ClearFlags();
123  newModule->RunOnChildren( std::bind( &clearModuleItemFlags, _1 ) );
124 
125  AddModuleToBoard( newModule );
126 
127  // Clear references to any net info, because the footprint editor
128  // does know any thing about nets handled by the current edited board.
129  // Morever we do not want to save any reference to an unknown net when
130  // saving the footprint in lib cache
131  // so we force the ORPHANED dummy net info for all pads
132  newModule->ClearAllNets();
133 
134  SetCrossHairPosition( wxPoint( 0, 0 ) );
135  PlaceModule( newModule, NULL );
136  newModule->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment
137 
138  // Put it on FRONT layer,
139  // because this is the default in ModEdit, and in libs
140  if( newModule->GetLayer() != F_Cu )
141  newModule->Flip( newModule->GetPosition() );
142 
143  // Put it in orientation 0,
144  // because this is the default orientation in ModEdit, and in libs
145  Rotate_Module( NULL, newModule, 0, false );
146  Zoom_Automatique( false );
147 
148  m_adapter->SetPreselectNode( newModule->GetFPID(), 0 );
149 
150  GetScreen()->ClearUndoRedoList();
151  GetScreen()->ClrModify();
152 
153  Update3DView();
154 
155  if( IsGalCanvasActive() )
156  updateView();
157  m_canvas->Refresh();
158 
159  m_treePane->GetLibTree()->Refresh(); // update any previously-highlighted items
160 
161  return true;
162 }
163 
164 
166 {
167  // Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode:
168  FOOTPRINT_VIEWER_FRAME* viewer;
170 
171  if( viewer )
172  {
173  viewer->Destroy();
174  // Destroy() does not immediately delete the viewer, if some events are pending.
175  // (for this reason delete operator cannot be used blindly with "top level" windows)
176  // so gives a slice of time to delete the viewer frame.
177  // This is especially important in OpenGL mode to avoid recreating context before
178  // the old one is deleted
179  wxSafeYield();
180  }
181 
182  SetFocus();
183 
184  // Creates the modal Lib browser:
186 
187  wxString fpid;
188  int ret = viewer->ShowModal( &fpid, this );
189  (void) ret; // make static analyser quiet
190 
191  viewer->Destroy();
192 
193  return fpid;
194 }
195 
196 
198 {
199  FP_LIB_TABLE* fpTable = Prj().PcbFootprintLibs();
200  wxString moduleName;
201  LIB_ID fpid;
202  MODULE* module = NULL;
203 
204  static wxString lastComponentName;
205 
206  WX_PROGRESS_REPORTER progressReporter( this, _( "Loading Footprint Libraries" ), 3 );
207  GFootprintList.ReadFootprintFiles( fpTable, nullptr, &progressReporter );
208  progressReporter.Show( false );
209 
212 
213  auto adapterPtr( FP_TREE_MODEL_ADAPTER::Create( fpTable ) );
214  auto adapter = static_cast<FP_TREE_MODEL_ADAPTER*>( adapterPtr.get() );
215 
216  std::vector<LIB_TREE_ITEM*> historyInfos;
217 
218  for( auto const& item : s_ModuleHistoryList )
219  historyInfos.push_back( GFootprintList.GetModuleInfo( item ) );
220 
221  adapter->DoAddLibrary( "-- " + _( "Recently Used" ) + " --", wxEmptyString, historyInfos, true );
222 
223  if( !historyInfos.empty() )
224  adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 );
225 
226  adapter->AddLibraries();
227 
228  wxString title;
229  title.Printf( _( "Choose Footprint (%d items loaded)" ), adapter->GetItemCount() );
230 
231  DIALOG_CHOOSE_FOOTPRINT dialog( this, title, adapterPtr, aAllowBrowser );
232 
233  if( dialog.ShowQuasiModal() == wxID_CANCEL )
234  return NULL;
235 
236  if( dialog.IsExternalBrowserSelected() )
237  {
238  // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e.
239  // <lib_name>/<footprint name> or LIB_ID format "lib_name:fp_name:rev#"
240  moduleName = SelectFootprintFromLibBrowser();
241 
242  if( moduleName.IsEmpty() ) // Cancel command
243  return NULL;
244  else
245  fpid.Parse( moduleName, LIB_ID::ID_PCB );
246  }
247  else
248  {
249  fpid = dialog.GetSelectedLibId();
250 
251  if( !fpid.IsValid() )
252  return NULL;
253  else
254  moduleName = fpid.Format();
255  }
256 
257  try
258  {
259  module = loadFootprint( fpid );
260  }
261  catch( const IO_ERROR& ioe )
262  {
263  wxLogDebug( wxT( "Error loading footprint '%s'.\n\nError: %s" ),
264  fpid.Format().c_str(),
265  ioe.What() );
266  }
267 
268  if( module )
269  {
270  lastComponentName = moduleName;
271  AddModuleToHistory( moduleName );
272  }
273 
274  return module;
275 }
276 
277 
279 {
280  MODULE* module = NULL;
281 
282  try
283  {
284  module = loadFootprint( aFootprintId );
285  }
286  catch( const IO_ERROR& ioe )
287  {
288  wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ),
289  aFootprintId.Format().c_str(), GetChars( ioe.What() ) );
290  }
291 
292  return module;
293 }
294 
295 
297 {
298  FP_LIB_TABLE* fptbl = Prj().PcbFootprintLibs();
299 
300  wxCHECK_MSG( fptbl, NULL, wxT( "Cannot look up LIB_ID in NULL FP_LIB_TABLE." ) );
301 
302  MODULE *module = nullptr;
303  try
304  {
305  module = fptbl->FootprintLoadWithOptionalNickname( aFootprintId );
306  }
307  catch( const IO_ERROR& ioe )
308  {
309  wxLogDebug( wxT( "An error occurred attemping to load footprint '%s'.\n\nError: %s" ),
310  aFootprintId.Format().c_str(), GetChars( ioe.What() ) );
311  }
312 
313  // If the module is found, clear all net info,
314  // to be sure there is no broken links
315  // to any netinfo list (should be not needed, but it can be edited from
316  // the footprint editor )
317  if( module )
318  module->ClearAllNets();
319 
320  return module;
321 }
322 
323 
325 {
326  static wxString oldName; // Save name of last module selected.
327 
328  wxString fpname;
329  wxString msg;
330  wxArrayString listnames;
331  MODULE* module = aPcb->m_Modules;
332 
333  for( ; module; module = module->Next() )
334  listnames.Add( module->GetReference() );
335 
336  msg.Printf( _( "Footprints [%u items]" ), (unsigned) listnames.GetCount() );
337 
338  wxArrayString headers;
339 
340  headers.Add( _( "Footprint" ) );
341 
342  std::vector<wxArrayString> itemsToDisplay;
343 
344  // Conversion from wxArrayString to vector of ArrayString
345  for( unsigned i = 0; i < listnames.GetCount(); i++ )
346  {
347  wxArrayString item;
348 
349  item.Add( listnames[i] );
350  itemsToDisplay.push_back( item );
351  }
352 
353  EDA_LIST_DIALOG dlg( this, msg, headers, itemsToDisplay, wxEmptyString, NULL, NULL, SORT_LIST );
354 
355  if( dlg.ShowModal() == wxID_OK )
356  fpname = dlg.GetTextSelection();
357  else
358  return NULL;
359 
360  oldName = fpname;
361 
362  module = aPcb->m_Modules;
363 
364  for( ; module; module = module->Next() )
365  {
366  if( fpname == module->GetReference() )
367  break;
368  }
369 
370  return module;
371 }
372 
373 
374 bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath )
375 {
376  wxString curLibPath = aLibraryPath;
377  wxString dstLibPath = CreateNewLibrary();
378 
379  if( !dstLibPath )
380  return false; // user aborted in CreateNewLibrary()
381 
382  wxBusyCursor dummy;
383  wxString msg;
384 
387 
388  try
389  {
390  PLUGIN::RELEASER cur( IO_MGR::PluginFind( curType ) );
391  PLUGIN::RELEASER dst( IO_MGR::PluginFind( dstType ) );
392 
393  wxArrayString footprints;
394 
395  cur->FootprintEnumerate( footprints, curLibPath );
396 
397  for( unsigned i = 0; i < footprints.size(); ++i )
398  {
399  const MODULE* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] );
400  dst->FootprintSave( dstLibPath, footprint );
401 
402  msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] );
403  SetStatusText( msg );
404  }
405  }
406  catch( const IO_ERROR& ioe )
407  {
408  DisplayError( this, ioe.What() );
409  return false;
410  }
411 
412  msg = wxString::Format(
413  _( "Footprint library \"%s\" saved as \"%s\"." ),
414  GetChars( curLibPath ), GetChars( dstLibPath ) );
415 
416  DisplayInfoMessage( this, msg );
417 
418  SetStatusText( wxEmptyString );
419  return true;
420 }
void DoAddLibrary(wxString const &aNodeName, wxString const &aDesc, std::vector< LIB_TREE_ITEM * > const &aItemList, bool presorted)
Add the given list of components by alias.
bool IsValid() const
Definition: lib_id.h:171
wxString SelectFootprintFromLibBrowser()
Function SelectFootprintFromLibBrowser launches the footprint viewer to select the name of a footprin...
static void AddModuleToHistory(const wxString &aName)
MODULE * SelectFootprintFromLibTree(bool aUseFootprintViewer=true)
Function SelectFootprintFromLibTree opens a dialog to select a footprint.
bool ShowModal(wxString *aFootprint, wxWindow *aParent) override
Function ShowModal.
wxString GetTextSelection(int aColumn=0)
Function GetTextSelection return the selected text from aColumn in the wxListCtrl in the dialog...
Definition: displlst.cpp:156
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Function RunOnChildren.
virtual void FootprintEnumerate(wxArrayString &aFootprintNames, const wxString &aLibraryPath, const PROPERTIES *aProperties=NULL)
Return a list of footprint names contained within the library at aLibraryPath.
Definition: plugin.cpp:60
FOOTPRINT_INFO * GetModuleInfo(const wxString &aFootprintId)
Get info for a module by id.
This file is part of the common library.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
This file is part of the common library.
PROJECT & Prj()
Definition: kicad.cpp:292
void Flip(const wxPoint &aCentre) override
Function Flip Flip this object, i.e.
Class BOARD to handle a board.
virtual void FootprintSave(const wxString &aLibraryPath, const MODULE *aFootprint, const PROPERTIES *aProperties=NULL)
Function FootprintSave will write aModule to an existing library located at aLibraryPath.
Definition: plugin.cpp:93
Component library viewer main window.
MODULE * Next() const
Definition: class_module.h:123
void DisplayErrors(wxTopLevelWindow *aCaller=NULL)
virtual const MODULE * GetEnumeratedFootprint(const wxString &aLibraryPath, const wxString &aFootprintName, const PROPERTIES *aProperties=NULL)
Function GetEnumeratedFootprint a version of FootprintLoad() for use after FootprintEnumerate() for m...
Definition: plugin.cpp:75
BOARD * GetBoard() const
class EDA_LIST_DIALOG
bool IsExternalBrowserSelected() const
Function IsExternalBrowserSelected.
Dialog class to select a footprint from the libraries.
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
Definition of class FOOTPRINT_EDIT_FRAME.
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath)
Function GuessPluginTypeFromLibPath returns a plugin type given a footprint library&#39;s libPath...
Definition: io_mgr.cpp:124
This file contains miscellaneous commonly used macros and functions.
MODULE * SelectFootprintFromBoard(BOARD *aPcb)
Display the list of modules currently existing on the BOARD.
Class RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destruct...
Definition: io_mgr.h:563
FOOTPRINT_LIST_IMPL GFootprintList
The global footprint info table.
Definition: pcbnew.cpp:338
const LIB_ID & GetFPID() const
Definition: class_module.h:193
void ClearAllNets()
Function ClearAllNets Clear (i.e.
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, wxTopLevelWindow *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:300
bool SaveLibraryAs(const wxString &aLibraryPath)
Save a library to a new name and/or library type.
void SetLink(timestamp_t aLink)
Definition: class_module.h:578
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:216
int ShowQuasiModal()
The common library.
Helper dialog and control classes.
bool Load_Module_From_BOARD(MODULE *Module)
Load in Modedit a footprint from the main board.
void SetPosition(const wxPoint &aPos) override
static unsigned s_ModuleHistoryMaxCount
BOARD * GetBoard()
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
static PTR Create(LIB_TABLE *aLibs)
Factory function: create a model adapter in a reference-counting container.
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:33
static const wxChar * GetChars(const wxString &s)
Function GetChars returns a wxChar* to the actual wxChar* data within a wxString, and is helpful for ...
Definition: macros.h:92
see class PGM_BASE
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, CPTREE &aTree)
Function Format outputs a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:205
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:170
#define SORT_LIST
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:463
DLIST< MODULE > m_Modules
Definition: class_board.h:248
static PLUGIN * PluginFind(PCB_FILE_T aFileType)
Function PluginFind returns a PLUGIN which the caller can use to import, export, save, or load design documents.
Definition: io_mgr.cpp:58
const char * c_str() const
Definition: utf8.h:107
size_t i
Definition: json11.cpp:597
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
unsigned GetErrorCount() const
UTF8 Format() const
Definition: lib_id.cpp:237
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
bool ReadFootprintFiles(FP_LIB_TABLE *aTable, const wxString *aNickname=nullptr, PROGRESS_REPORTER *aProgressReporter=nullptr) override
Read all the footprints provided by the combination of aTable and aNickname.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
static void clearModuleItemFlags(BOARD_ITEM *aItem)
MODULE * FootprintLoadWithOptionalNickname(const LIB_ID &aFootprintId)
Function FootprintLoadWithOptionalNickname loads a footprint having aFootprintId with possibly an emp...
Module description (excepted pads)
int Parse(const UTF8 &aId, LIB_ID_TYPE aType, bool aFix=false)
Parse LIB_ID with the information from aId.
Definition: lib_id.cpp:122
PCB_FILE_T
Enum PCB_FILE_T is a set of file types that the IO_MGR knows about, and for which there has been a pl...
Definition: io_mgr.h:52
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Function DisplayInfoMessage displays an informational message box with aMessage.
Definition: confirm.cpp:277
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:245
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:76
const wxPoint GetPosition() const override
Definition: class_module.h:184
MODULE * loadFootprint(const LIB_ID &aFootprintId)
Function loadFootprint attempts to load aFootprintId from the footprint library table.
LIB_ID GetSelectedLibId() const
To be called after this dialog returns from ShowModal().
timestamp_t GetTimeStamp() const
Definition: base_struct.h:207
static wxArrayString s_ModuleHistoryList
KIWAY Kiway
int m_Status_Pcb
Flags used in ratsnest calculation and update.
Definition: class_board.h:240