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-2016 Wayne Stambaugh <stambaughw@verizon.net>
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 //#include <reporter.h>
41 
42 #include <pcbnew.h>
45 #include <kiway.h>
46 
47 
48 static bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName );
49 
50 
52 
53 
55  DIALOG_EXCHANGE_MODULE_BASE( parent ), m_commit( parent )
56 {
57  m_parent = parent;
58  m_currentModule = Module;
59  init();
60  GetSizer()->Fit( this );
61  GetSizer()->SetSizeHints( this );
62  Center();
63 }
64 
65 
66 void DIALOG_EXCHANGE_MODULE::OnQuit( wxCommandEvent& event )
67 {
68  m_selectionMode = m_Selection->GetSelection();
69  Show( false );
70  EndQuasiModal( wxID_CANCEL );
71 }
72 
73 
75 {
76  SetFocus();
77 
80  m_CmpValue->AppendText( m_currentModule->GetValue() );
82  m_Selection->SetString( 0, wxString::Format(
83  _( "Change footprint of '%s'" ),
85  wxString fpname = m_CurrentFootprintFPID->GetValue().AfterLast( ':' );
86 
87  if( fpname.IsEmpty() ) // Happens for old fp names
88  fpname = m_CurrentFootprintFPID->GetValue();
89 
90  m_Selection->SetString( 1, wxString::Format(
91  _( "Change footprints '%s'" ),
92  GetChars( fpname.Left( 12 ) ) ) );
93 
94  m_Selection->SetSelection( m_selectionMode );
95 
96  // Enable/disable widgets:
97  wxCommandEvent event;
98  OnSelectionClicked( event );
99 }
100 
101 
102 void DIALOG_EXCHANGE_MODULE::OnOkClick( wxCommandEvent& event )
103 {
104  m_selectionMode = m_Selection->GetSelection();
105  bool result = false;
106 
109 
110  switch( m_Selection->GetSelection() )
111  {
112  case 0:
113  result = changeCurrentFootprint();
114  break;
115 
116  case 1:
117  result = changeSameFootprints( false );
118  break;
119 
120  case 2:
121  result = changeSameFootprints( true );
122  break;
123 
124  case 3:
125  result = changeAllFootprints();
126  break;
127  }
128 
129  if( result )
130  {
132  m_parent->Compile_Ratsnest( NULL, true );
133 
134  m_parent->GetCanvas()->Refresh();
135  }
136 
137  m_commit.Push( wxT( "Changed footprint" ) );
138 }
139 
140 
141 void DIALOG_EXCHANGE_MODULE::OnSelectionClicked( wxCommandEvent& event )
142 {
143  bool enable = true;
144 
145  switch( m_Selection->GetSelection() )
146  {
147  case 0:
148  case 1:
149  case 2:
150  break;
151 
152  case 3:
153  enable = false;
154  break;
155  }
156 
157  m_NewFootprintFPID->Enable( enable );
158  m_Browsebutton->Enable( enable );
159 }
160 
161 
162 void DIALOG_EXCHANGE_MODULE::RebuildCmpList( wxCommandEvent& event )
163 {
164  wxString msg;
165  REPORTER& reporter = m_MessageWindow->Reporter();
168 
169  // Build the .cmp file name from the board name
170  wxFileName fn = m_parent->GetBoard()->GetFileName();
171  fn.SetExt( ComponentFileExtension );
172 
173  if( RecreateCmpFile( m_parent->GetBoard(), fn.GetFullPath() ) )
174  {
175  msg.Printf( _( "File '%s' created\n" ), GetChars( fn.GetFullPath() ) );
176  reporter.Report( msg, REPORTER::RPT_INFO );
177  }
178  else
179  {
180  msg.Printf( _( "** Could not create file '%s' ***\n" ),
181  GetChars( fn.GetFullPath() ) );
182  reporter.Report( msg, REPORTER::RPT_ERROR );
183  }
184 }
185 
186 
188 {
189  wxString newmodulename = m_NewFootprintFPID->GetValue();
190 
191  if( newmodulename == wxEmptyString )
192  return false;
193 
194  return change_1_Module( m_currentModule, newmodulename, true );
195 }
196 
197 
199 {
200  wxString msg;
201  MODULE* Module;
202  MODULE* PtBack;
203  bool change = false;
204  wxString newmodulename = m_NewFootprintFPID->GetValue();
205  wxString value;
206  LIB_ID lib_reference;
207  bool check_module_value = false;
208  int ShowErr = 3; // Post 3 error messages max.
209 
210  if( m_parent->GetBoard()->m_Modules == NULL )
211  return false;
212 
213  if( newmodulename == wxEmptyString )
214  return false;
215 
216  lib_reference = m_currentModule->GetFPID();
217 
218  if( aUseValue )
219  {
220  check_module_value = true;
221  value = m_currentModule->GetValue();
222  msg.Printf( _( "Change footprint %s -> %s (for value = %s)?" ),
224  GetChars( newmodulename ),
226  }
227  else
228  {
229  msg.Printf( _( "Change footprint %s -> %s ?" ),
230  GetChars( FROM_UTF8( lib_reference.Format().c_str() ) ),
231  GetChars( newmodulename ) );
232  }
233 
234  if( !IsOK( this, msg ) )
235  return false;
236 
237  /* The change is done from the last module because
238  * change_1_Module () modifies the last item in the list.
239  *
240  * note: for the first module in chain (the last here), Module->Back()
241  * points the board or is NULL
242  */
243  Module = m_parent->GetBoard()->m_Modules.GetLast();
244 
245  for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
246  {
247  PtBack = Module->Back();
248 
249  if( lib_reference != Module->GetFPID() )
250  continue;
251 
252  if( check_module_value )
253  {
254  if( value.CmpNoCase( Module->GetValue() ) != 0 )
255  continue;
256  }
257 
258  if( change_1_Module( Module, newmodulename, ShowErr ) )
259  change = true;
260  else if( ShowErr )
261  ShowErr--;
262  }
263 
264  return change;
265 }
266 
267 
269 {
270  MODULE* Module, * PtBack;
271  bool change = false;
272  int ShowErr = 3; // Post 3 error max.
273 
274  if( m_parent->GetBoard()->m_Modules == NULL )
275  return false;
276 
277  if( !IsOK( this, _( "Are you sure you want to change all footprints?" ) ) )
278  return false;
279 
280  /* The change is done from the last module because the function
281  * change_1_Module () modifies the last module in the list
282  *
283  * note: for the first module in chain (the last here), Module->Back()
284  * points the board or is NULL
285  */
286  Module = m_parent->GetBoard()->m_Modules.GetLast();
287 
288  for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
289  {
290  PtBack = Module->Back();
291 
292  if( change_1_Module( Module, Module->GetFPID(), ShowErr ) )
293  change = true;
294  else if( ShowErr )
295  ShowErr--;
296  }
297 
298  return change;
299 }
300 
301 
303  const LIB_ID& aNewFootprintFPID,
304  bool aShowError )
305 {
306  MODULE* newModule;
307  wxString msg;
308 
309  if( aModule == NULL )
310  return false;
311 
312  wxBusyCursor dummy;
313  REPORTER& reporter = m_MessageWindow->Reporter();
314 
315  // Copy parameters from the old footprint.
316  LIB_ID oldFootprintFPID = aModule->GetFPID();
317 
318  // Load module.
319  msg.Printf( _( "Change footprint '%s' (from '%s') to '%s'" ),
320  GetChars( aModule->GetReference() ),
321  oldFootprintFPID.Format().c_str(),
322  aNewFootprintFPID.Format().c_str() );
323 
324  newModule = m_parent->LoadFootprint( aNewFootprintFPID );
325 
326  if( newModule == NULL ) // New module not found.
327  {
328  msg << ": " << _( "footprint not found" );
329  reporter.Report( msg, REPORTER::RPT_ERROR );
330  return false;
331  }
332 
333  m_parent->Exchange_Module( aModule, newModule, m_commit );
334 
335  if( aModule == m_currentModule )
336  m_currentModule = newModule;
337 
338  msg += ": OK";
339  reporter.Report( msg, REPORTER::RPT_ACTION );
340 
341  return true;
342 }
343 
344 
346  MODULE* aNewModule,
347  BOARD_COMMIT& aCommit )
348 {
349  aNewModule->SetParent( GetBoard() );
350 
351  /* place module without ratsnest refresh: this will be made later
352  * when all modules are on board */
353  PlaceModule( aNewModule, NULL, true );
354 
355  // Copy full placement and pad net names (when possible)
356  // but not local settings like clearances (use library values)
357  aOldModule->CopyNetlistSettings( aNewModule, false );
358 
359  // Copy reference and value
360  aNewModule->SetReference( aOldModule->GetReference() );
361  aNewModule->SetValue( aOldModule->GetValue() );
362 
363  // Compare the footprint name only, in case the nickname is empty or in case
364  // user moved the footprint to a new library. Chances are if footprint name is
365  // same then the footprint is very nearly the same and the two texts should
366  // be kept at same size, position, and rotation.
367  if( aNewModule->GetFPID().GetLibItemName() == aOldModule->GetFPID().GetLibItemName() )
368  {
369  aNewModule->Reference().SetEffects( aOldModule->Reference() );
370  aNewModule->Value().SetEffects( aOldModule->Value() );
371  }
372 
373  // Updating other parameters
374  aNewModule->SetTimeStamp( aOldModule->GetTimeStamp() );
375  aNewModule->SetPath( aOldModule->GetPath() );
376 
377  aCommit.Remove( aOldModule );
378  aCommit.Add( aNewModule );
379 
380  // @todo LEGACY should be unnecessary
381  GetBoard()->m_Status_Pcb = 0;
382  aNewModule->ClearFlags();
383 }
384 
385 
386 // Displays the list of available footprints in library name and select a footprint.
388 {
389  wxString newname;
390 
391  newname = m_parent->SelectFootprint( m_parent, wxEmptyString, wxEmptyString, wxEmptyString,
392  Prj().PcbFootprintLibs() );
393 
394  if( newname != wxEmptyString )
395  m_NewFootprintFPID->SetValue( newname );
396 }
397 
398 
400 {
401  wxString newname;
402 
404 
405  if( frame->ShowModal( &newname, this ) )
406  {
407  m_NewFootprintFPID->SetValue( newname );
408  }
409 
410  frame->Destroy();
411 }
412 
413 
414 void PCB_EDIT_FRAME::RecreateCmpFileFromBoard( wxCommandEvent& aEvent )
415 {
416  wxFileName fn;
417  MODULE* module = GetBoard()->m_Modules;
418  wxString msg;
419  wxString wildcard;
420 
421  if( module == NULL )
422  {
423  DisplayError( this, _( "No footprints!" ) );
424  return;
425  }
426 
427  // Build the .cmp file name from the board name
428  fn = GetBoard()->GetFileName();
429  fn.SetExt( ComponentFileExtension );
430  wildcard = wxGetTranslation( ComponentFileWildcard );
431 
432  wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
433 
434  wxFileDialog dlg( this, _( "Save Footprint Association File" ), pro_dir,
435  fn.GetFullName(), wildcard,
436  wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
437 
438  if( dlg.ShowModal() == wxID_CANCEL )
439  return;
440 
441  fn = dlg.GetPath();
442 
443  if( ! RecreateCmpFile( GetBoard(), fn.GetFullPath() ) )
444  {
445  msg.Printf( _( "Could not create file '%s'" ), GetChars(fn.GetFullPath() ) );
446  DisplayError( this, msg );
447  return;
448  }
449 }
450 
451 
452 bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName )
453 {
454  FILE* cmpFile;
455 
456  cmpFile = wxFopen( aFullCmpFileName, wxT( "wt" ) );
457 
458  if( cmpFile == NULL )
459  return false;
460 
461  fprintf( cmpFile, "Cmp-Mod V01 Created by PcbNew date = %s\n", TO_UTF8( DateAndTime() ) );
462 
463  MODULE* module = aBrd->m_Modules;
464  for( ; module != NULL; module = module->Next() )
465  {
466  fprintf( cmpFile, "\nBeginCmp\n" );
467  fprintf( cmpFile, "TimeStamp = %8.8lX\n", (unsigned long)module->GetTimeStamp() );
468  fprintf( cmpFile, "Path = %s\n", TO_UTF8( module->GetPath() ) );
469  fprintf( cmpFile, "Reference = %s;\n",
470  !module->GetReference().IsEmpty() ?
471  TO_UTF8( module->GetReference() ) : "[NoRef]" );
472  fprintf( cmpFile, "ValeurCmp = %s;\n",
473  !module->GetValue().IsEmpty() ?
474  TO_UTF8( module->GetValue() ) : "[NoVal]" );
475  fprintf( cmpFile, "IdModule = %s;\n", module->GetFPID().Format().c_str() );
476  fprintf( cmpFile, "EndCmp\n" );
477  }
478 
479  fprintf( cmpFile, "\nEndListe\n" );
480  fclose( cmpFile );
481 
482  return true;
483 }
KICAD_T Type() const
Function Type()
Definition: base_struct.h:212
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:463
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:337
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:100
void OnQuit(wxCommandEvent &event) override
BOARD * GetBoard() const
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:447
bool changeSameFootprints(bool aUseValue)
Class REPORTER is a pure virtual class used to derive REPORTER objects from.
Definition: reporter.h:61
Class LIB_ID.
Definition: lib_id.h:56
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.
void SetTimeStamp(time_t aNewTimeStamp)
Definition: base_struct.h:217
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:164
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:101
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
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:227
const wxString & GetFileName() const
Definition: class_board.h:234
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:462
const UTF8 & GetLibItemName() const
Function GetLibItemName.
Definition: lib_id.h:129
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:429
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
MODULE * Back() const
Definition: class_module.h:101
bool Show(bool show) override
time_t GetTimeStamp() const
Definition: base_struct.h:218
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:419
const wxString ComponentFileExtension
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:456
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
Function Format.
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:268
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.
const wxString ComponentFileWildcard
Module description (excepted pads)
const wxString & GetPath() const
Definition: class_module.h:173
void DisplayError(wxWindow *parent, const wxString &text, int displaytime)
Function DisplayError displays an error or warning message box with aMessage.
Definition: confirm.cpp:71
bool IsOK(wxWindow *aParent, const wxString &aMessage)
Function IsOK displays a yes/no dialog with aMessage and returns the user response.
Definition: confirm.cpp:129
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:174
void BrowseAndSelectFootprint(wxCommandEvent &event) override
wxString DateAndTime()
Function DateAndTime.
Definition: string.cpp:229
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