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-2020 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 
26 #include <functional>
27 using namespace std::placeholders;
28 
29 #include <class_board.h>
30 #include <class_module.h>
31 #include <confirm.h>
35 #include <dialog_helpers.h>
36 #include <footprint_edit_frame.h>
37 #include <footprint_info_impl.h>
38 #include <footprint_tree_pane.h>
39 #include <footprint_viewer_frame.h>
40 #include <fp_lib_table.h>
41 #include <io_mgr.h>
42 #include <kicad_string.h>
43 #include <kiway.h>
44 #include <lib_id.h>
45 #include <macros.h>
46 #include <pcb_draw_panel_gal.h>
47 #include <pcb_edit_frame.h>
48 #include <pcbnew.h>
49 #include <pcbnew_settings.h>
50 #include <pgm_base.h>
51 #include <view/view_controls.h>
52 #include <widgets/lib_tree.h>
54 
55 #include "fp_tree_model_adapter.h"
56 
57 
58 static wxArrayString s_ModuleHistoryList;
59 static unsigned s_ModuleHistoryMaxCount = 8;
60 
61 static void AddModuleToHistory( const wxString& aName )
62 {
63  // Remove duplicates
64  for( int ii = s_ModuleHistoryList.GetCount() - 1; ii >= 0; --ii )
65  {
66  if( s_ModuleHistoryList[ ii ] == aName )
67  s_ModuleHistoryList.RemoveAt( (size_t) ii );
68  }
69 
70  // Add the new name at the beginning of the history list
71  s_ModuleHistoryList.Insert( aName, 0 );
72 
73  // Remove extra names
74  while( s_ModuleHistoryList.GetCount() >= s_ModuleHistoryMaxCount )
75  s_ModuleHistoryList.RemoveAt( s_ModuleHistoryList.GetCount() - 1 );
76 }
77 
78 
79 static void clearModuleItemFlags( BOARD_ITEM* aItem )
80 {
81  aItem->ClearFlags();
82 }
83 
84 #include <bitmaps.h>
86 {
87  bool is_last_fp_from_brd = IsCurrentFPFromBoard();
88 
89  MODULE* newModule;
91 
92  if( frame == NULL ) // happens if no board editor opened
93  return false;
94 
95  if( aModule == NULL )
96  {
97  if( !frame->GetBoard() || !frame->GetBoard()->GetFirstModule() )
98  return false;
99 
100  aModule = SelectFootprintFromBoard( frame->GetBoard() );
101  }
102 
103  if( aModule == NULL )
104  return false;
105 
106  if( !Clear_Pcb( true ) )
107  return false;
108 
109  newModule = (MODULE*) aModule->Duplicate();
110  newModule->SetParent( GetBoard() );
111  newModule->SetLink( aModule->m_Uuid );
112 
113  newModule->ClearFlags();
114  newModule->RunOnChildren( std::bind( &clearModuleItemFlags, _1 ) );
115 
116  AddModuleToBoard( newModule );
117 
118  // Clear references to any net info, because the footprint editor
119  // does know any thing about nets handled by the current edited board.
120  // Morever we do not want to save any reference to an unknown net when
121  // saving the footprint in lib cache
122  // so we force the ORPHANED dummy net info for all pads
123  newModule->ClearAllNets();
124 
125  GetCanvas()->GetViewControls()->SetCrossHairCursorPosition( VECTOR2D( 0, 0 ), false );
126  PlaceModule( newModule );
127  newModule->SetPosition( wxPoint( 0, 0 ) ); // cursor in GAL may not be initialized at the moment
128 
129  // Put it on FRONT layer,
130  // because this is the default in ModEdit, and in libs
131  if( newModule->GetLayer() != F_Cu )
132  newModule->Flip( newModule->GetPosition(), frame->Settings().m_FlipLeftRight );
133 
134  // Put it in orientation 0,
135  // because this is the default orientation in ModEdit, and in libs
136  newModule->SetOrientation( 0 );
137 
138  Zoom_Automatique( false );
139 
140  m_adapter->SetPreselectNode( newModule->GetFPID(), 0 );
141 
142  ClearUndoRedoList();
143  GetScreen()->ClrModify();
144 
145  // Update the save items if needed.
146  if( !is_last_fp_from_brd )
147  {
148  ReCreateMenuBar();
149  ReCreateHToolbar();
150 
151  if( IsSearchTreeShown() )
152  ToggleSearchTree();
153  }
154 
155  Update3DView( true );
156  updateView();
157  GetCanvas()->Refresh();
158  m_treePane->GetLibTree()->RefreshLibTree(); // update any previously-highlighted items
159 
160  return true;
161 }
162 
163 
165 {
166  // Close the current non-modal Lib browser if opened, and open a new one, in "modal" mode:
167  FOOTPRINT_VIEWER_FRAME* viewer;
169 
170  if( viewer )
171  {
172  viewer->Destroy();
173  // Destroy() does not immediately delete the viewer, if some events are pending.
174  // (for this reason delete operator cannot be used blindly with "top level" windows)
175  // so gives a slice of time to delete the viewer frame.
176  // This is especially important in OpenGL mode to avoid recreating context before
177  // the old one is deleted
178  wxSafeYield();
179  }
180 
181  SetFocus();
182 
183  // Creates the modal Lib browser:
185 
186  wxString fpid;
187  int ret = viewer->ShowModal( &fpid, this );
188  (void) ret; // make static analyser quiet
189 
190  viewer->Destroy();
191 
192  return fpid;
193 }
194 
195 
197 {
198  FP_LIB_TABLE* fpTable = Prj().PcbFootprintLibs();
199  wxString moduleName;
200  LIB_ID fpid;
201  MODULE* module = NULL;
202 
203  static wxString lastComponentName;
204 
205  // Load footprint files:
206  WX_PROGRESS_REPORTER* progressReporter = new WX_PROGRESS_REPORTER( this,
207  _( "Loading Footprint Libraries" ), 3 );
208  GFootprintList.ReadFootprintFiles( fpTable, nullptr, progressReporter );
209  bool cancel = progressReporter->WasCancelled();
210  progressReporter->Destroy();
211 
212  if( cancel )
213  return nullptr;
214 
217 
218  auto adapterPtr( FP_TREE_MODEL_ADAPTER::Create( this, fpTable ) );
219  auto adapter = static_cast<FP_TREE_MODEL_ADAPTER*>( adapterPtr.get() );
220 
221  std::vector<LIB_TREE_ITEM*> historyInfos;
222 
223  for( auto const& item : s_ModuleHistoryList )
224  {
225  LIB_TREE_ITEM* fp_info = GFootprintList.GetModuleInfo( item );
226 
227  // this can be null, for example, if the footprint has been deleted from a library.
228  if( fp_info != nullptr )
229  historyInfos.push_back( fp_info );
230  }
231 
232  adapter->DoAddLibrary( "-- " + _( "Recently Used" ) + " --", wxEmptyString, historyInfos, true );
233 
234  if( aPreselect.IsValid() )
235  adapter->SetPreselectNode( aPreselect, 0 );
236  else if( historyInfos.size() )
237  adapter->SetPreselectNode( historyInfos[0]->GetLibId(), 0 );
238 
239  adapter->AddLibraries();
240 
241  wxString title;
242  title.Printf( _( "Choose Footprint (%d items loaded)" ), adapter->GetItemCount() );
243 
244  DIALOG_CHOOSE_FOOTPRINT dialog( this, title, adapterPtr );
245 
246  if( dialog.ShowQuasiModal() == wxID_CANCEL )
247  return NULL;
248 
249  if( dialog.IsExternalBrowserSelected() )
250  {
251  // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e.
252  // <lib_name>/<footprint name> or LIB_ID format "lib_name:fp_name:rev#"
253  moduleName = SelectFootprintFromLibBrowser();
254 
255  if( moduleName.IsEmpty() ) // Cancel command
256  return NULL;
257  else
258  fpid.Parse( moduleName, LIB_ID::ID_PCB );
259  }
260  else
261  {
262  fpid = dialog.GetSelectedLibId();
263 
264  if( !fpid.IsValid() )
265  return NULL;
266  else
267  moduleName = fpid.Format();
268  }
269 
270  try
271  {
272  module = loadFootprint( fpid );
273  }
274  catch( const IO_ERROR& )
275  {
276  }
277 
278  if( module )
279  {
280  lastComponentName = moduleName;
281  AddModuleToHistory( moduleName );
282  }
283 
284  return module;
285 }
286 
287 
289 {
290  MODULE* module = NULL;
291 
292  try
293  {
294  module = loadFootprint( aFootprintId );
295  }
296  catch( const IO_ERROR& )
297  {
298  }
299 
300  return module;
301 }
302 
303 
305 {
306  FP_LIB_TABLE* fptbl = Prj().PcbFootprintLibs();
307 
308  wxCHECK_MSG( fptbl, NULL, wxT( "Cannot look up LIB_ID in NULL FP_LIB_TABLE." ) );
309 
310  MODULE *module = nullptr;
311  try
312  {
313  module = fptbl->FootprintLoadWithOptionalNickname( aFootprintId );
314  }
315  catch( const IO_ERROR& )
316  {
317  }
318 
319  // If the module is found, clear all net info,
320  // to be sure there is no broken links
321  // to any netinfo list (should be not needed, but it can be edited from
322  // the footprint editor )
323  if( module )
324  module->ClearAllNets();
325 
326  return module;
327 }
328 
329 
331 {
332  static wxString oldName; // Save name of last module selected.
333 
334  wxString fpname;
335  wxString msg;
336  wxArrayString listnames;
337 
338  for( auto module : aPcb->Modules() )
339  listnames.Add( module->GetReference() );
340 
341  msg.Printf( _( "Footprints [%u items]" ), (unsigned) listnames.GetCount() );
342 
343  wxArrayString headers;
344 
345  headers.Add( _( "Footprint" ) );
346 
347  std::vector<wxArrayString> itemsToDisplay;
348 
349  // Conversion from wxArrayString to vector of ArrayString
350  for( unsigned i = 0; i < listnames.GetCount(); i++ )
351  {
352  wxArrayString item;
353 
354  item.Add( listnames[i] );
355  itemsToDisplay.push_back( item );
356  }
357 
358  EDA_LIST_DIALOG dlg( this, msg, headers, itemsToDisplay, wxEmptyString );
359 
360  if( dlg.ShowModal() == wxID_OK )
361  fpname = dlg.GetTextSelection();
362  else
363  return NULL;
364 
365  oldName = fpname;
366 
367  for( auto mod : aPcb->Modules() )
368  {
369  if( fpname == mod->GetReference() )
370  return mod;
371  }
372 
373  return nullptr;
374 }
375 
376 
377 bool FOOTPRINT_EDIT_FRAME::SaveLibraryAs( const wxString& aLibraryPath )
378 {
379  const wxString& curLibPath = aLibraryPath;
380  wxString dstLibPath = CreateNewLibrary( wxEmptyString, aLibraryPath );
381 
382  if( !dstLibPath )
383  return false; // user aborted in CreateNewLibrary()
384 
385  wxBusyCursor dummy;
386  wxString msg;
387 
390 
391  try
392  {
393  PLUGIN::RELEASER cur( IO_MGR::PluginFind( curType ) );
394  PLUGIN::RELEASER dst( IO_MGR::PluginFind( dstType ) );
395 
396  wxArrayString footprints;
397 
398  cur->FootprintEnumerate( footprints, curLibPath, false );
399 
400  for( unsigned i = 0; i < footprints.size(); ++i )
401  {
402  const MODULE* footprint = cur->GetEnumeratedFootprint( curLibPath, footprints[i] );
403  dst->FootprintSave( dstLibPath, footprint );
404 
405  msg = wxString::Format( _( "Footprint \"%s\" saved" ), footprints[i] );
406  SetStatusText( msg );
407  }
408  }
409  catch( const IO_ERROR& ioe )
410  {
411  DisplayError( this, ioe.What() );
412  return false;
413  }
414 
415  msg = wxString::Format( _( "Footprint library \"%s\" saved as \"%s\"." ),
416  curLibPath,
417  dstLibPath );
418 
419  DisplayInfoMessage( this, msg );
420 
421  SetStatusText( wxEmptyString );
422  return true;
423 }
424 
425 
426 static MODULE* s_ModuleInitialCopy = NULL; // Copy of module for abort/undo command
427 
428 static PICKED_ITEMS_LIST s_PickedList; // a pick-list to save initial module
429 // and dragged tracks
430 
431 
433 {
434  wxString moduleName;
435  wxArrayString fplist;
436 
437  // Build list of available fp references, to display them in dialog
438  for( auto fp : GetBoard()->Modules() )
439  fplist.Add( fp->GetReference() + wxT(" ( ") + fp->GetValue() + wxT(" )") );
440 
441  fplist.Sort();
442 
443  DIALOG_GET_FOOTPRINT_BY_NAME dlg( this, fplist );
444 
445  if( dlg.ShowModal() != wxID_OK ) //Aborted by user
446  return NULL;
447 
448  moduleName = dlg.GetValue();
449  moduleName.Trim( true );
450  moduleName.Trim( false );
451 
452  if( !moduleName.IsEmpty() )
453  {
454  for( auto mod : GetBoard()->Modules() )
455  {
456  if( mod->GetReference().CmpNoCase( moduleName ) == 0 )
457  return mod;
458  }
459  }
460 
461  return nullptr;
462 }
463 
464 
465 void PCB_BASE_FRAME::PlaceModule( MODULE* aModule, bool aRecreateRatsnest )
466 {
467  if( aModule == 0 )
468  return;
469 
470  OnModify();
471 
472  if( aModule->IsNew() )
473  {
474  SaveCopyInUndoList( aModule, UNDO_REDO::NEWITEM );
475  }
476  else if( aModule->IsMoving() )
477  {
478  ITEM_PICKER picker( nullptr, aModule, UNDO_REDO::CHANGED );
479  picker.SetLink( s_ModuleInitialCopy );
480  s_PickedList.PushItem( picker );
481  s_ModuleInitialCopy = NULL; // the picker is now owner of s_ModuleInitialCopy.
482  }
483 
484  if( s_PickedList.GetCount() )
485  {
486  SaveCopyInUndoList( s_PickedList, UNDO_REDO::UNSPECIFIED );
487 
488  // Clear list, but DO NOT delete items, because they are owned by the saved undo
489  // list and they therefore in use
491  }
492 
493  aModule->SetPosition( (wxPoint) GetCanvas()->GetViewControls()->GetCursorPosition() );
494  aModule->ClearFlags();
495 
496  delete s_ModuleInitialCopy;
498 
499  if( aRecreateRatsnest )
500  m_Pcb->GetConnectivity()->Update( aModule );
501 
502  if( aRecreateRatsnest )
503  Compile_Ratsnest( true );
504 
505  SetMsgPanel( aModule );
506 }
507 
508 
void DisplayError(wxWindow *aParent, const wxString &aText, int aDisplayTime)
Display an error or warning message box with aMessage.
Definition: confirm.cpp:239
wxString SelectFootprintFromLibBrowser()
Function SelectFootprintFromLibBrowser launches the footprint viewer to select the name of a footprin...
void SetLink(const KIID &aLink)
Definition: class_module.h:568
static void AddModuleToHistory(const wxString &aName)
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.
void RunOnChildren(const std::function< void(BOARD_ITEM *)> &aFunction)
Function RunOnChildren.
FOOTPRINT_INFO * GetModuleInfo(const wxString &aFootprintId)
Get info for a module by id.
bool IsExternalBrowserSelected() const
Function IsExternalBrowserSelected.
This file is part of the common library.
BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class,...
VIEW_CONTROLS class definition.
A mix-in to provide polymorphism between items stored in libraries (symbols, aliases and footprints).
Definition: lib_tree_item.h:39
PROJECT & Prj()
Definition: kicad.cpp:318
static PICKED_ITEMS_LIST s_PickedList
bool IsMoving() const
Definition: base_struct.h:200
Component library viewer main window.
void DisplayErrors(wxTopLevelWindow *aCaller=NULL)
MODULE * SelectFootprintFromLibTree(LIB_ID aPreselect=LIB_ID())
Function SelectFootprintFromLibTree opens a dialog to select a footprint.
EDA_LIST_DIALOG.
void PushItem(const ITEM_PICKER &aItem)
Function PushItem pushes aItem to the top of the list.
const LIB_ID & GetFPID() const
Definition: class_module.h:228
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
bool IsValid() const
Definition: lib_id.h:171
void SetLink(EDA_ITEM *aItem)
unsigned GetCount() const
Function GetCount.
static PCB_FILE_T GuessPluginTypeFromLibPath(const wxString &aLibPath)
Function GuessPluginTypeFromLibPath returns a plugin type given a footprint library's libPath.
Definition: io_mgr.cpp:128
virtual void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:196
This file contains miscellaneous commonly used macros and functions.
bool IsNew() const
Definition: base_struct.h:199
MODULE * SelectFootprintFromBoard(BOARD *aPcb)
Display the list of modules currently existing on the BOARD.
RELEASER releases a PLUGIN in the context of a potential thrown exception, through its destructor.
Definition: io_mgr.h:580
DIALOG_GET_FOOTPRINT_BY_NAME is a helper dialog to select a footprint by its reference One can enter ...
FOOTPRINT_LIST_IMPL GFootprintList
The global footprint info table.
static PTR Create(EDA_BASE_FRAME *aParent, LIB_TABLE *aLibs)
Factory function: create a model adapter in a reference-counting container.
void ClearAllNets()
Function ClearAllNets Clear (i.e.
Multi-thread safe progress reporter dialog, intended for use of tasks that paralleize reporting back ...
static MODULE * s_ModuleInitialCopy
#define NULL
VECTOR2< double > VECTOR2D
Definition: vector2d.h:593
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:343
virtual const wxString What() const
A composite of Problem() and Where()
Definition: exceptions.cpp:29
MODULES & Modules()
Definition: class_board.h:249
bool SaveLibraryAs(const wxString &aLibraryPath)
Save a library to a new name and/or library type.
int ShowQuasiModal()
void Flip(const wxPoint &aCentre, bool aFlipLeftRight) override
Function Flip Flip this object, i.e.
MODULE * GetFirstModule() const
Gets the first module in the list (used in footprint viewer/editor) or NULL if none.
Definition: class_board.h:310
LIB_ID GetSelectedLibId() const
To be called after this dialog returns from ShowModal().
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
PICKED_ITEMS_LIST is a holder to handle information on schematic or board items.
UTF8 Format() const
Definition: lib_id.cpp:237
void Add(BOARD_ITEM *aItem, ADD_MODE aMode=ADD_MODE::INSERT) override
void SetOrientation(double aNewAngle)
static unsigned s_ModuleHistoryMaxCount
BOARD * GetBoard()
const KIID m_Uuid
Definition: base_struct.h:162
VTBL_ENTRY FP_LIB_TABLE * PcbFootprintLibs(KIWAY &aKiway)
Return the table of footprint libraries.
Definition: project.cpp:286
BOARD_ITEM * Duplicate() const override
Function Duplicate creates a copy of a BOARD_ITEM.
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:201
static LIB_PART * dummy()
Used to draw a dummy shape when a LIB_PART is not found in library.
BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:178
#define _(s)
Definition: 3d_actions.cpp:33
static PLUGIN * PluginFind(PCB_FILE_T aFileType)
Function PluginFind returns a PLUGIN which the caller can use to import, export, save,...
Definition: io_mgr.cpp:62
PCB_EDIT_FRAME is the main frame for Pcbnew.
PCBNEW_SETTINGS & Settings()
unsigned GetErrorCount() const
void ClearItemsList()
Function ClearItemsList deletes only the list of pickers, NOT the picked data itself.
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:233
static void clearModuleItemFlags(BOARD_ITEM *aItem)
MODULE * FootprintLoadWithOptionalNickname(const LIB_ID &aFootprintId)
Function FootprintLoadWithOptionalNickname loads a footprint having aFootprintId with possibly an emp...
MODULE * GetFootprintFromBoardByReference()
Function GetFootprintFromBoardByReference.
wxPoint GetPosition() const override
Definition: class_module.h:219
BOARD * GetBoard() const
void PlaceModule(MODULE *aModule, bool aRecreateRatsnest=true)
Function PlaceModule places aModule at the current cursor position and updates module coordinates wit...
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:54
void DisplayInfoMessage(wxWindow *aParent, const wxString &aMessage, const wxString &aExtraInfo)
Display an informational message box with aMessage.
Definition: confirm.cpp:267
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
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
MODULE * loadFootprint(const LIB_ID &aFootprintId)
Function loadFootprint attempts to load aFootprintId from the footprint library table.
static wxArrayString s_ModuleHistoryList
KIWAY Kiway