KiCad PCB EDA Suite
dialog_exchange_modules.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) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
5  * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2013 Wayne Stambaugh <stambaughw@gmail.com>
7  * Copyright (C) 1992-2017 KiCad Developers, see AUTHORS.txt for contributors.
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, you may find one here:
21  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
22  * or you may search the http://www.gnu.org website for the version 2 license,
23  * or you may write to the Free Software Foundation, Inc.,
24  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25  */
26 
27 #include <fctsys.h>
28 #include <class_drawpanel.h>
29 #include <class_draw_panel_gal.h>
30 #include <confirm.h>
31 #include <kicad_string.h>
32 #include <wxPcbStruct.h>
33 #include <macros.h>
34 #include <board_commit.h>
35 
36 #include <class_board.h>
37 #include <class_module.h>
38 #include <project.h>
39 #include <wx_html_report_panel.h>
40 
41 #include <pcbnew.h>
44 #include <kiway.h>
45 
46 
47 static bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName );
48 
49 
51 
52 
54  DIALOG_EXCHANGE_MODULE_BASE( parent ), m_commit( parent )
55 {
56  m_parent = parent;
57  m_currentModule = Module;
58  init();
59  GetSizer()->Fit( this );
60  GetSizer()->SetSizeHints( this );
61  Center();
62 }
63 
64 
65 void DIALOG_EXCHANGE_MODULE::OnQuit( wxCommandEvent& event )
66 {
67  m_selectionMode = m_Selection->GetSelection();
68  Show( false );
69  EndQuasiModal( wxID_CANCEL );
70 }
71 
72 
74 {
75  SetFocus();
76 
79  m_CmpValue->AppendText( m_currentModule->GetValue() );
81  m_Selection->SetString( 0, wxString::Format(
82  _( "Change footprint of '%s'" ),
84  wxString fpname = m_CurrentFootprintFPID->GetValue().AfterLast( ':' );
85 
86  if( fpname.IsEmpty() ) // Happens for old fp names
87  fpname = m_CurrentFootprintFPID->GetValue();
88 
89  m_Selection->SetString( 1, wxString::Format(
90  _( "Change footprints '%s'" ),
91  GetChars( fpname.Left( 12 ) ) ) );
92 
93  m_Selection->SetSelection( m_selectionMode );
94 
95  // Enable/disable widgets:
96  wxCommandEvent event;
97  OnSelectionClicked( event );
98 }
99 
100 
101 void DIALOG_EXCHANGE_MODULE::OnOkClick( wxCommandEvent& event )
102 {
103  m_selectionMode = m_Selection->GetSelection();
104  bool result = false;
105 
108 
109  switch( m_Selection->GetSelection() )
110  {
111  case 0:
112  result = changeCurrentFootprint();
113  break;
114 
115  case 1:
116  result = changeSameFootprints( false );
117  break;
118 
119  case 2:
120  result = changeSameFootprints( true );
121  break;
122 
123  case 3:
124  result = changeAllFootprints();
125  break;
126  }
127 
128  if( result )
129  {
131  m_parent->Compile_Ratsnest( NULL, true );
132 
133  m_parent->GetCanvas()->Refresh();
134  }
135 
136  m_commit.Push( wxT( "Changed footprint" ) );
137 }
138 
139 
140 void DIALOG_EXCHANGE_MODULE::OnSelectionClicked( wxCommandEvent& event )
141 {
142  bool enable = true;
143 
144  switch( m_Selection->GetSelection() )
145  {
146  case 0:
147  case 1:
148  case 2:
149  break;
150 
151  case 3:
152  enable = false;
153  break;
154  }
155 
156  m_NewFootprintFPID->Enable( enable );
157  m_Browsebutton->Enable( enable );
158 }
159 
160 
161 void DIALOG_EXCHANGE_MODULE::RebuildCmpList( wxCommandEvent& event )
162 {
163  wxString msg;
164  REPORTER& reporter = m_MessageWindow->Reporter();
167 
168  // Build the .cmp file name from the board name
169  wxFileName fn = m_parent->GetBoard()->GetFileName();
170  fn.SetExt( ComponentFileExtension );
171 
172  if( RecreateCmpFile( m_parent->GetBoard(), fn.GetFullPath() ) )
173  {
174  msg.Printf( _( "File '%s' created\n" ), GetChars( fn.GetFullPath() ) );
175  reporter.Report( msg, REPORTER::RPT_INFO );
176  }
177  else
178  {
179  msg.Printf( _( "** Could not create file '%s' ***\n" ),
180  GetChars( fn.GetFullPath() ) );
181  reporter.Report( msg, REPORTER::RPT_ERROR );
182  }
183 }
184 
185 
187 {
188  wxString newmodulename = m_NewFootprintFPID->GetValue();
189 
190  if( newmodulename == wxEmptyString )
191  return false;
192 
193  return change_1_Module( m_currentModule, newmodulename, true );
194 }
195 
196 
198 {
199  wxString msg;
200  MODULE* Module;
201  MODULE* PtBack;
202  bool change = false;
203  wxString newmodulename = m_NewFootprintFPID->GetValue();
204  wxString value;
205  LIB_ID lib_reference;
206  bool check_module_value = false;
207  int ShowErr = 3; // Post 3 error messages max.
208 
209  if( m_parent->GetBoard()->m_Modules == NULL )
210  return false;
211 
212  if( newmodulename == wxEmptyString )
213  return false;
214 
215  lib_reference = m_currentModule->GetFPID();
216 
217  if( aUseValue )
218  {
219  check_module_value = true;
220  value = m_currentModule->GetValue();
221  msg.Printf( _( "Change footprint %s -> %s (for value = %s)?" ),
223  GetChars( newmodulename ),
225  }
226  else
227  {
228  msg.Printf( _( "Change footprint %s -> %s ?" ),
229  GetChars( FROM_UTF8( lib_reference.Format().c_str() ) ),
230  GetChars( newmodulename ) );
231  }
232 
233  if( !IsOK( this, msg ) )
234  return false;
235 
236  /* The change is done from the last module because
237  * change_1_Module () modifies the last item in the list.
238  *
239  * note: for the first module in chain (the last here), Module->Back()
240  * points the board or is NULL
241  */
242  Module = m_parent->GetBoard()->m_Modules.GetLast();
243 
244  for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
245  {
246  PtBack = Module->Back();
247 
248  if( lib_reference != Module->GetFPID() )
249  continue;
250 
251  if( check_module_value )
252  {
253  if( value.CmpNoCase( Module->GetValue() ) != 0 )
254  continue;
255  }
256 
257  if( change_1_Module( Module, newmodulename, ShowErr ) )
258  change = true;
259  else if( ShowErr )
260  ShowErr--;
261  }
262 
263  return change;
264 }
265 
266 
268 {
269  MODULE* Module, * PtBack;
270  bool change = false;
271  int ShowErr = 3; // Post 3 error max.
272 
273  if( m_parent->GetBoard()->m_Modules == NULL )
274  return false;
275 
276  if( !IsOK( this, _( "Are you sure you want to change all footprints?" ) ) )
277  return false;
278 
279  /* The change is done from the last module because the function
280  * change_1_Module () modifies the last module in the list
281  *
282  * note: for the first module in chain (the last here), Module->Back()
283  * points the board or is NULL
284  */
285  Module = m_parent->GetBoard()->m_Modules.GetLast();
286 
287  for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
288  {
289  PtBack = Module->Back();
290 
291  if( change_1_Module( Module, Module->GetFPID(), ShowErr ) )
292  change = true;
293  else if( ShowErr )
294  ShowErr--;
295  }
296 
297  return change;
298 }
299 
300 
302  const LIB_ID& aNewFootprintFPID,
303  bool aShowError )
304 {
305  MODULE* newModule;
306  wxString msg;
307 
308  if( aModule == NULL )
309  return false;
310 
311  wxBusyCursor dummy;
312  REPORTER& reporter = m_MessageWindow->Reporter();
313 
314  // Copy parameters from the old footprint.
315  LIB_ID oldFootprintFPID = aModule->GetFPID();
316 
317  // Load module.
318  msg.Printf( _( "Change footprint '%s' (from '%s') to '%s'" ),
319  GetChars( aModule->GetReference() ),
320  oldFootprintFPID.Format().c_str(),
321  aNewFootprintFPID.Format().c_str() );
322 
323  newModule = m_parent->LoadFootprint( aNewFootprintFPID );
324 
325  if( newModule == NULL ) // New module not found.
326  {
327  msg << ": " << _( "footprint not found" );
328  reporter.Report( msg, REPORTER::RPT_ERROR );
329  return false;
330  }
331 
332  m_parent->Exchange_Module( aModule, newModule, m_commit );
333 
334  if( aModule == m_currentModule )
335  m_currentModule = newModule;
336 
337  msg += ": OK";
338  reporter.Report( msg, REPORTER::RPT_ACTION );
339 
340  return true;
341 }
342 
343 
345  MODULE* aNewModule,
346  BOARD_COMMIT& aCommit )
347 {
348  aNewModule->SetParent( GetBoard() );
349 
350  /* place module without ratsnest refresh: this will be made later
351  * when all modules are on board */
352  PlaceModule( aNewModule, NULL, true );
353 
354  // Copy full placement and pad net names (when possible)
355  // but not local settings like clearances (use library values)
356  aOldModule->CopyNetlistSettings( aNewModule, false );
357 
358  // Copy reference and value
359  aNewModule->SetReference( aOldModule->GetReference() );
360  aNewModule->SetValue( aOldModule->GetValue() );
361 
362  // Compare the footprint name only, in case the nickname is empty or in case
363  // user moved the footprint to a new library. Chances are if footprint name is
364  // same then the footprint is very nearly the same and the two texts should
365  // be kept at same size, position, and rotation.
366  if( aNewModule->GetFPID().GetLibItemName() == aOldModule->GetFPID().GetLibItemName() )
367  {
368  aNewModule->Reference().SetEffects( aOldModule->Reference() );
369  aNewModule->Value().SetEffects( aOldModule->Value() );
370  }
371 
372  // Updating other parameters
373  aNewModule->SetTimeStamp( aOldModule->GetTimeStamp() );
374  aNewModule->SetPath( aOldModule->GetPath() );
375 
376  aCommit.Remove( aOldModule );
377  aCommit.Add( aNewModule );
378 
379  // @todo LEGACY should be unnecessary
380  GetBoard()->m_Status_Pcb = 0;
381  aNewModule->ClearFlags();
382 }
383 
384 
385 // Displays the list of available footprints in library name and select a footprint.
387 {
388  wxString newname;
389 
390  newname = m_parent->SelectFootprint( m_parent, wxEmptyString, wxEmptyString, wxEmptyString,
391  Prj().PcbFootprintLibs() );
392 
393  if( newname != wxEmptyString )
394  m_NewFootprintFPID->SetValue( newname );
395 }
396 
397 
399 {
400  wxString newname;
401 
403 
404  if( frame->ShowModal( &newname, this ) )
405  {
406  m_NewFootprintFPID->SetValue( newname );
407  }
408 
409  frame->Destroy();
410 }
411 
412 
413 void PCB_EDIT_FRAME::RecreateCmpFileFromBoard( wxCommandEvent& aEvent )
414 {
415  wxFileName fn;
416  MODULE* module = GetBoard()->m_Modules;
417  wxString msg;
418  wxString wildcard;
419 
420  if( module == NULL )
421  {
422  DisplayError( this, _( "No footprints!" ) );
423  return;
424  }
425 
426  // Build the .cmp file name from the board name
427  fn = GetBoard()->GetFileName();
428  fn.SetExt( ComponentFileExtension );
429  wildcard = ComponentFileWildcard();
430 
431  wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
432 
433  wxFileDialog dlg( this, _( "Save Footprint Association File" ), pro_dir,
434  fn.GetFullName(), wildcard,
435  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
436 
437  if( dlg.ShowModal() == wxID_CANCEL )
438  return;
439 
440  fn = dlg.GetPath();
441 
442  if( ! RecreateCmpFile( GetBoard(), fn.GetFullPath() ) )
443  {
444  msg.Printf( _( "Could not create file '%s'" ), GetChars(fn.GetFullPath() ) );
445  DisplayError( this, msg );
446  return;
447  }
448 }
449 
450 
451 bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName )
452 {
453  FILE* cmpFile;
454 
455  cmpFile = wxFopen( aFullCmpFileName, wxT( "wt" ) );
456 
457  if( cmpFile == NULL )
458  return false;
459 
460  fprintf( cmpFile, "Cmp-Mod V01 Created by PcbNew date = %s\n", TO_UTF8( DateAndTime() ) );
461 
462  MODULE* module = aBrd->m_Modules;
463  for( ; module != NULL; module = module->Next() )
464  {
465  fprintf( cmpFile, "\nBeginCmp\n" );
466  fprintf( cmpFile, "TimeStamp = %8.8lX\n", (unsigned long)module->GetTimeStamp() );
467  fprintf( cmpFile, "Path = %s\n", TO_UTF8( module->GetPath() ) );
468  fprintf( cmpFile, "Reference = %s;\n",
469  !module->GetReference().IsEmpty() ?
470  TO_UTF8( module->GetReference() ) : "[NoRef]" );
471  fprintf( cmpFile, "ValeurCmp = %s;\n",
472  !module->GetValue().IsEmpty() ?
473  TO_UTF8( module->GetValue() ) : "[NoVal]" );
474  fprintf( cmpFile, "IdModule = %s;\n", module->GetFPID().Format().c_str() );
475  fprintf( cmpFile, "EndCmp\n" );
476  }
477 
478  fprintf( cmpFile, "\nEndListe\n" );
479  fclose( cmpFile );
480 
481  return true;
482 }
KICAD_T Type() const
Function Type()
Definition: base_struct.h:225
void RecreateCmpFileFromBoard(wxCommandEvent &aEvent)
Function RecreateBOMFileFromBoard Recreates a .cmp file from the current loaded board this is the sam...
Class KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a porti...
Definition: kiway_player.h:111
TEXTE_MODULE & Reference()
Definition: class_module.h:483
KIWAY & Kiway() const
Function Kiway returns a reference to the KIWAY that this object has an opportunity to participate in...
Definition: kiway_player.h:60
static wxString FROM_UTF8(const char *cstring)
function FROM_UTF8 converts a UTF8 encoded C string to a wxString for all wxWidgets build modes...
Definition: macros.h:53
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL) override
Update the board display after modifying it bu a python script (note: it is automatically called by a...
Definition: draw_panel.cpp:325
This file is part of the common library.
EDA_DRAW_PANEL * GetCanvas()
Definition: draw_frame.h:331
wxString ComponentFileWildcard()
void ViewAndSelectFootprint(wxCommandEvent &event) override
void Exchange_Module(MODULE *aOldModule, MODULE *aNewModule, BOARD_COMMIT &aCommit)
Function Exchange_Module Replaces OldModule by NewModule, using OldModule settings: position...
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
void OnOkClick(wxCommandEvent &event) override
Class BOARD to handle a board.
MODULE * Next() const
Definition: class_module.h:120
void OnQuit(wxCommandEvent &event) override
BOARD * GetBoard() const
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:467
bool changeSameFootprints(bool aUseValue)
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
A logical library item identifier and consists of various portions much like a URI.
Definition: lib_id.h:51
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true) override
Executes the changes.
static bool RecreateCmpFile(BOARD *aBrd, const wxString &aFullCmpFileName)
Class DIALOG_EXCHANGE_MODULE_BASE.
This file contains miscellaneous commonly used macros and functions.
void PlaceModule(MODULE *aModule, wxDC *aDC, bool aDoNotRecreateRatsnest=false)
Function PlaceModule places aModule at the current cursor position and updates module coordinates wit...
Definition: modules.cpp:352
const LIB_ID & GetFPID() const
Definition: class_module.h:184
void OnSelectionClicked(wxCommandEvent &event) override
#define TO_UTF8(wxstring)
Macro TO_UTF8 converts a wxString to a UTF8 encoded C string for all wxWidgets build modes...
Definition: macros.h:47
PROJECT & Prj() const
Function Prj returns a reference to the PROJECT "associated with" this KIWAY.
class MODULE, a footprint
Definition: typeinfo.h:89
VTBL_ENTRY KIWAY_PLAYER * Player(FRAME_T aFrameType, bool doCreate=true, KIWAY_PLAYER *aParent=NULL)
Function Player returns the KIWAY_PLAYER* given a FRAME_T.
Definition: kiway.cpp:302
const wxString ComponentFileExtension
T * GetLast() const
Function GetLast returns the last T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:170
void SetParent(EDA_ITEM *aParent)
Definition: base_struct.h:240
const wxString & GetFileName() const
Definition: class_board.h:234
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:482
const UTF8 & GetLibItemName() const
Definition: lib_id.h:115
REPORTER & Reporter()
returns the reporter object that reports to this panel
The common library.
void SetReference(const wxString &aReference)
Function SetReference.
Definition: class_module.h:449
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
MODULE * Back() const
Definition: class_module.h:121
bool Show(bool show) override
void Compile_Ratsnest(wxDC *aDC, bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:56
void EndQuasiModal(int retCode)
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
void Flush()
Forces updating the HTML page, after the report is built in lazy mode
bool change_1_Module(MODULE *aModule, const LIB_ID &aNewFootprintFPID, bool eShowError)
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
DIALOG_EXCHANGE_MODULE(PCB_EDIT_FRAME *aParent, MODULE *aModule)
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
Definition: loadcmp.cpp:316
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
void Clear()
clears the report panel
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:169
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:439
DLIST< MODULE > m_Modules
Definition: class_board.h:245
const char * c_str() const
Definition: utf8.h:107
void SetValue(const wxString &aValue)
Function SetValue.
Definition: class_module.h:476
virtual REPORTER & Report(const wxString &aText, SEVERITY aSeverity=RPT_UNDEFINED)=0
Function Report is a pure virtual function to override in the derived object.
UTF8 Format() const
Definition: lib_id.cpp:263
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:281
void SetEffects(const TEXTE_MODULE &aSrc)
Function SetEffects sets the text effects from another instance.
void CopyNetlistSettings(MODULE *aModule, bool aCopyLocalSettings)
Function CopyNetlistSettings copies the netlist settings to aModule.
Module description (excepted pads)
const wxString & GetPath() const
Definition: class_module.h:193
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:73
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:131
VTBL_ENTRY bool ShowModal(wxString *aResult=NULL, wxWindow *aResultantFocusWindow=NULL)
Function ShowModal puts up this wxFrame as if it were a modal dialog, with all other instantiated wxF...
void SetPath(const wxString &aPath)
Definition: class_module.h:194
void BrowseAndSelectFootprint(wxCommandEvent &event) override
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:229
timestamp_t GetTimeStamp() const
Definition: base_struct.h:231
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:230
wxString SelectFootprint(EDA_DRAW_FRAME *aWindow, const wxString &aLibraryName, const wxString &aMask, const wxString &aKeyWord, FP_LIB_TABLE *aTable)
Function SelectFootprint displays a list of modules found in all libraries or a given library...
Definition: loadcmp.cpp:362
int m_Status_Pcb
Flags used in ratsnest calculation and update.
Definition: class_board.h:237
void RebuildCmpList(wxCommandEvent &event) override