KiCad PCB EDA Suite
dialog_exchange_footprints.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-2018 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 <kicad_string.h>
29 #include <class_drawpanel.h>
30 #include <pcb_edit_frame.h>
31 #include <macros.h>
32 #include <board_commit.h>
33 #include <bitmaps.h>
34 #include <class_board.h>
35 #include <class_module.h>
36 #include <project.h>
37 #include <wx_html_report_panel.h>
38 #include <kiway.h>
39 
41 
42 
43 #define ID_MATCH_FP_ALL 4200
44 #define ID_MATCH_FP_SELECTED 4201
45 #define ID_MATCH_FP_REF 4202
46 #define ID_MATCH_FP_VAL 4203
47 #define ID_MATCH_FP_ID 4204
48 
49 
54 
55 
57  bool updateMode, bool selectedMode ) :
59  m_commit( aParent ),
60  m_parent( aParent ),
61  m_currentModule( aModule ),
62  m_updateMode( updateMode )
63 {
64  wxString title = updateMode ? _( "Update Footprints from Library" ) : _( "Change Footprints" );
65  wxString verb = updateMode ? _( "Update" ) : _( "Change" );
66  wxString label;
67 
68  SetTitle( title );
69 
70  if( m_updateMode )
71  {
72  label.Printf( m_matchAll->GetLabel(), verb );
73  m_matchAll->SetLabel( label );
74  m_changeSizer->Show( false );
75  }
76  else
77  {
78  m_upperSizer->FindItem( m_matchAll )->Show( false );
79  m_newIDBrowseButton->SetBitmap( KiBitmap( small_library_xpm ) );
80  }
81 
82  if( m_currentModule )
83  {
84  label.Printf( m_matchSelected->GetLabel(), verb );
85  m_matchSelected->SetLabel( label );
86  m_newID->AppendText( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
87  }
88  else
89  m_upperSizer->FindItem( m_matchSelected )->Show( false );
90 
91  label.Printf( m_matchSpecifiedRef->GetLabel(), verb );
92  m_matchSpecifiedRef->SetLabel( label );
93 
94  // Use ChangeValue() instead of SetValue() so we don't generate events.
95  if( m_currentModule )
96  m_specifiedRef->ChangeValue( m_currentModule->GetReference() );
97 
98  label.Printf( m_matchSpecifiedValue->GetLabel(), verb );
99  m_matchSpecifiedValue->SetLabel( label );
100 
101  if( m_currentModule )
102  m_specifiedValue->ChangeValue( m_currentModule->GetValue() );
103 
104  label.Printf( m_matchSpecifiedID->GetLabel(), verb );
105  m_matchSpecifiedID->SetLabel( label );
106 
107  if( m_currentModule )
108  m_specifiedID->ChangeValue( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
109 
110  m_specifiedIDBrowseButton->SetBitmap( KiBitmap( small_library_xpm ) );
111 
112  m_upperSizer->SetEmptyCellSize( wxSize( 0, 0 ) );
113  m_upperSizer->RecalcSizes();
114 
115  // initialize match-mode
116  if( m_updateMode )
118  else
120 
121  wxCommandEvent event;
122  event.SetEventObject( this );
123 
124  switch( *m_matchMode )
125  {
126  case ID_MATCH_FP_ALL: OnMatchAllClicked( event ); break;
127  case ID_MATCH_FP_SELECTED: OnMatchSelectedClicked( event ); break;
128  case ID_MATCH_FP_REF: OnMatchRefClicked( event ); break;
129  case ID_MATCH_FP_VAL: OnMatchValueClicked( event ); break;
130  case ID_MATCH_FP_ID: OnMatchIDClicked( event ); break;
131  default: break;
132  }
133 
134  // DIALOG_SHIM needs a unique hash_key because classname is not sufficient
135  // because the update and change versions of this dialog have different controls.
136  m_hash_key = TO_UTF8( GetTitle() );
137 
138  // Ensure m_closeButton (with id = wxID_CANCEL) has the right label
139  // (to fix automatic renaming of button label )
140  m_sdbSizerCancel->SetLabel( _( "Close" ) );
141 
142  m_sdbSizerApply->SetDefault();
143 
144  // Now all widgets have the size fixed, call FinishDialogSettings
146 }
147 
148 
150 {
151  LIB_ID specifiedID;
152 
153  switch( *m_matchMode )
154  {
155  case ID_MATCH_FP_ALL:
156  return true;
158  return aModule == m_currentModule;
159  case ID_MATCH_FP_REF:
160  return WildCompareString( m_specifiedRef->GetValue(), aModule->GetReference(), false );
161  case ID_MATCH_FP_VAL:
162  return WildCompareString( m_specifiedValue->GetValue(), aModule->GetValue(), false );
163  case ID_MATCH_FP_ID:
164  specifiedID.Parse( m_specifiedID->GetValue(), LIB_ID::ID_PCB );
165  return aModule->GetFPID() == specifiedID;
166  default:
167  return false; // just to quiet compiler warnings....
168  }
169 }
170 
171 
173 {
174  switch( *m_matchMode )
175  {
176  case ID_MATCH_FP_ALL: return m_matchAll;
180  case ID_MATCH_FP_ID: return m_matchSpecifiedID;
181  default: return nullptr;
182  }
183 }
184 
185 
187 {
188  wxRadioButton* rb_button = getRadioButtonForMode();
189 
190  wxRadioButton* rb_butt_list[] =
191  {
192  m_matchAll,
197  nullptr // end of list
198  };
199 
200  // Ensure the button state is ok. Only one button can be checked
201  // Change button state only if its state is incorrect, otherwise
202  // we have issues depending on the platform.
203  for( int ii = 0; rb_butt_list[ii]; ++ii )
204  {
205  bool state = rb_butt_list[ii] == rb_button;
206 
207  if( rb_butt_list[ii]->GetValue() != state )
208  rb_butt_list[ii]->SetValue( state );
209  }
210 }
211 
212 
214 {
216 
217  if( event.GetEventObject() == this )
219  else
220  m_matchAll->SetFocus();
221 }
222 
223 
225 {
227 
228  if( event.GetEventObject() == this )
230  else
231  m_matchSelected->SetFocus();
232 }
233 
234 
236 {
238 
239  if( event.GetEventObject() == this )
241  else if( event.GetEventObject() != m_specifiedRef )
242  m_specifiedRef->SetFocus();
243 }
244 
245 
247 {
249 
250  if( event.GetEventObject() == this )
252  else if( event.GetEventObject() != m_specifiedValue )
253  m_specifiedValue->SetFocus();
254 }
255 
256 
257 void DIALOG_EXCHANGE_FOOTPRINTS::OnMatchIDClicked( wxCommandEvent& event )
258 {
260 
261  if( event.GetEventObject() == this )
263  else if( event.GetEventObject() != m_specifiedID )
264  m_specifiedID->SetFocus();
265 }
266 
267 
268 void DIALOG_EXCHANGE_FOOTPRINTS::OnApplyClicked( wxCommandEvent& event )
269 {
270  wxBusyCursor dummy;
271 
273  m_MessageWindow->Flush( true );
274 
275  if( processMatchingModules() )
276  {
278  m_parent->Compile_Ratsnest( NULL, true );
279 
280  m_parent->GetCanvas()->Refresh();
281  }
282 
283  m_commit.Push( wxT( "Changed footprint" ) );
284 }
285 
286 
288 {
289  MODULE* Module;
290  MODULE* PtBack;
291  bool change = false;
292  LIB_ID newFPID;
293  wxString value;
294 
295  if( !m_parent->GetBoard()->m_Modules )
296  return false;
297 
298  if( !m_updateMode )
299  {
300  newFPID.Parse( m_newID->GetValue(), LIB_ID::ID_PCB );
301 
302  if( !newFPID.IsValid() )
303  return false;
304  }
305 
306  /* The change is done from the last module because processModule() modifies the last item
307  * in the list.
308  * Note: for the first module in chain (the last here), Module->Back() points to the board
309  * or is NULL.
310  */
311  Module = m_parent->GetBoard()->m_Modules.GetLast();
312 
313  for( ; Module && Module->Type() == PCB_MODULE_T; Module = PtBack )
314  {
315  PtBack = Module->Back();
316 
317  if( !isMatch( Module ) )
318  continue;
319 
320  if( m_updateMode )
321  {
322  if( processModule( Module, Module->GetFPID()) )
323  change = true;
324  }
325  else
326  {
327  if( processModule( Module, newFPID ) )
328  change = true;
329  }
330  }
331 
332  return change;
333 }
334 
335 
336 bool DIALOG_EXCHANGE_FOOTPRINTS::processModule( MODULE* aModule, const LIB_ID& aNewFPID )
337 {
338  LIB_ID oldFPID = aModule->GetFPID();
339  REPORTER& reporter = m_MessageWindow->Reporter();
340  wxString msg;
341 
342  // Load new module.
343  msg.Printf( _( "%s footprint \"%s\" (from \"%s\") to \"%s\"" ),
344  m_updateMode ? _( "Update" ) : _( "Change" ),
345  aModule->GetReference(),
346  oldFPID.Format().c_str(),
347  aNewFPID.Format().c_str() );
348 
349  MODULE* newModule = m_parent->LoadFootprint( aNewFPID );
350 
351  if( !newModule )
352  {
353  msg << ": " << _( "*** footprint not found ***" );
354  reporter.Report( msg, REPORTER::RPT_ERROR );
355  return false;
356  }
357 
358  m_parent->Exchange_Module( aModule, newModule, m_commit,
359  m_removeExtraBox->GetValue(),
360  m_resetTextItemLayers->GetValue(),
361  m_resetTextItemEffects->GetValue() );
362 
363  if( aModule == m_currentModule )
364  m_currentModule = newModule;
365 
366  if( aModule == m_parent->GetCurItem() )
367  m_parent->SetCurItem( newModule );
368 
369  msg += ": OK";
370  reporter.Report( msg, REPORTER::RPT_ACTION );
371 
372  return true;
373 }
374 
375 
376 void processTextItem( const TEXTE_MODULE& aSrc, TEXTE_MODULE& aDest,
377  bool resetText, bool resetTextLayers, bool resetTextEffects )
378 {
379  if( !resetText )
380  aDest.SetText( aSrc.GetText() );
381 
382  if( !resetTextLayers )
383  {
384  aDest.SetLayer( aSrc.GetLayer() );
385  aDest.SetVisible( aSrc.IsVisible() );
386  }
387 
388  if( !resetTextEffects )
389  aDest.SetEffects( aSrc );
390 }
391 
392 
394 {
395  for( auto iItem = aModule->GraphicalItemsList().GetFirst(); iItem; iItem = iItem->Next() )
396  {
397  TEXTE_MODULE* candidate = dyn_cast<TEXTE_MODULE*>( iItem );
398 
399  if( candidate && candidate->GetText() == aRefItem->GetText() )
400  return candidate;
401  }
402 
403  return nullptr;
404 }
405 
406 
408  bool deleteExtraTexts,
409  bool resetTextLayers, bool resetTextEffects )
410 {
411  aDest->SetParent( GetBoard() );
412 
413  /* place module without ratsnest refresh: this will be made later
414  * when all modules are on board */
415  PlaceModule( aDest, nullptr, false );
416 
417  // Copy full placement and pad net names (when possible)
418  // but not local settings like clearances (use library values)
419  aSrc->CopyNetlistSettings( aDest, false );
420 
421  // Copy reference
422  processTextItem( aSrc->Reference(), aDest->Reference(),
423  // never reset reference text
424  false,
425  resetTextLayers, resetTextEffects );
426 
427  // Copy value
428  processTextItem( aSrc->Value(), aDest->Value(),
429  // reset value text only when it is a proxy for the footprint ID
430  // (cf replacing value "MountingHole-2.5mm" with "MountingHole-4.0mm")
431  aSrc->GetValue() == aSrc->GetFPID().GetLibItemName(),
432  resetTextLayers, resetTextEffects );
433 
434  // Copy fields in accordance with the reset* flags
435  for( BOARD_ITEM* item = aSrc->GraphicalItemsList().GetFirst(); item; item = item->Next() )
436  {
437  TEXTE_MODULE* srcItem = dyn_cast<TEXTE_MODULE*>( item );
438 
439  if( srcItem )
440  {
441  TEXTE_MODULE* destItem = getMatchingTextItem( srcItem, aDest );
442 
443  if( destItem )
444  processTextItem( *srcItem, *destItem, false, resetTextLayers, resetTextEffects );
445  else if( !deleteExtraTexts )
446  aDest->GraphicalItemsList().Append( new TEXTE_MODULE( *srcItem ) );
447  }
448  }
449 
450  // Updating other parameters
451  aDest->SetTimeStamp( aSrc->GetTimeStamp() );
452  aDest->SetPath( aSrc->GetPath() );
453 
454  aCommit.Remove( aSrc );
455  aCommit.Add( aDest );
456 
457  // @todo LEGACY should be unnecessary
458  GetBoard()->m_Status_Pcb = 0;
459  aDest->ClearFlags();
460 }
461 
462 
464 {
465  wxString newname;
466 
468 
469  if( frame->ShowModal( &newname, this ) )
470  {
471  if( event.GetEventObject() == m_newIDBrowseButton )
472  m_newID->SetValue( newname );
473  else
474  m_specifiedID->SetValue( newname );
475  }
476 
477  frame->Destroy();
478 }
479 
480 
bool IsValid() const
Definition: lib_id.h:171
KICAD_T Type() const
Function Type()
Definition: base_struct.h:201
Class KIWAY_PLAYER is a wxFrame capable of the OpenProjectFiles function, meaning it can load a porti...
Definition: kiway_player.h:120
TEXTE_MODULE & Reference()
Definition: class_module.h:513
void OnMatchIDClicked(wxCommandEvent &event) override
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 EDA_DRAW_PANEL * GetCanvas() const
Definition: draw_frame.h:388
virtual void SetLayer(PCB_LAYER_ID aLayer)
Function SetLayer sets the layer this item is on.
Class BOARD_ITEM is a base class for any item which can be embedded within the BOARD container class...
std::string m_hash_key
Definition: dialog_shim.h:144
COMMIT & Add(EDA_ITEM *aItem)
Adds a new item to the model
Definition: commit.h:78
virtual PCB_LAYER_ID GetLayer() const
Function GetLayer returns the primary layer this item is on.
Class BOARD to handle a board.
void Append(T *aNewElement)
Function Append adds aNewElement to the end of the list.
Definition: dlist.h:177
void Flush(bool aSort=false)
Forces updating the HTML page, after the report is built in lazy mode If aSort = true, the body messages will be ordered by severity
void FinishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
void SetVisible(bool aVisible)
Definition: eda_text.h:188
void SetCurItem(BOARD_ITEM *aItem, bool aDisplayInfo=true)
Function SetCurItem sets the currently selected item and displays it in the MsgPanel.
BOARD * GetBoard() const
const wxString & GetValue() const
Function GetValue.
Definition: class_module.h:497
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
void SetInitialFocus(wxWindow *aWindow)
Sets the window (usually a wxTextCtrl) that should be focused when the dialog is shown.
Definition: dialog_shim.h:86
Casted dyn_cast(From aObject)
Function dyn_cast()
Definition: typeinfo.h:61
This file contains miscellaneous commonly used macros and functions.
int g_matchModeForUpdateSelected
void OnMatchAllClicked(wxCommandEvent &event) override
BOARD_ITEM * Next() const
bool processModule(MODULE *aModule, const LIB_ID &aNewFPID)
const LIB_ID & GetFPID() const
Definition: class_module.h:193
#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
wxBitmap KiBitmap(BITMAP_DEF aBitmap)
Construct a wxBitmap from a memory record, held in a BITMAP_DEF.
Definition: bitmap.cpp:79
class MODULE, a footprint
Definition: typeinfo.h:89
#define ID_MATCH_FP_ID
Class DIALOG_EXCHANGE_FOOTPRINTS_BASE.
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
#define ID_MATCH_FP_ALL
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:216
TEXTE_MODULE & Value()
read/write accessors:
Definition: class_module.h:512
const UTF8 & GetLibItemName() const
Definition: lib_id.h:114
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Function WildCompareString compares a string against wild card (* and ?) pattern using the usual rule...
Definition: string.cpp:377
const wxString & GetText() const
Function GetText returns the string associated with the text object.
Definition: eda_text.h:143
REPORTER & Reporter()
returns the reporter object that reports to this panel
DIALOG_EXCHANGE_FOOTPRINTS(PCB_EDIT_FRAME *aParent, MODULE *aModule, bool updateMode, bool selectedMode)
void OnMatchSelectedClicked(wxCommandEvent &event) override
T * GetFirst() const
Function GetFirst returns the first T* in the list without removing it, or NULL if the list is empty...
Definition: dlist.h:163
#define ID_MATCH_FP_SELECTED
COMMIT & Remove(EDA_ITEM *aItem)
Removes a new item from the model
Definition: commit.h:90
MODULE * Back() const
Definition: class_module.h:124
#define ID_MATCH_FP_REF
int g_matchModeForExchangeSelected
void Compile_Ratsnest(wxDC *aDC, bool aDisplayStatus)
Function Compile_Ratsnest Create the entire board ratsnest.
Definition: ratsnest.cpp:53
BOARD * GetBoard()
TEXTE_MODULE * getMatchingTextItem(TEXTE_MODULE *aRefItem, MODULE *aModule)
void updateMatchModeRadioButtons(wxUpdateUIEvent &event) override
bool IsElementVisible(GAL_LAYER_ID aLayer) const
Function IsElementVisible tests whether a given element category is visible.
MODULE * LoadFootprint(const LIB_ID &aFootprintId)
Function LoadFootprint attempts to load aFootprintId from the footprint library table.
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...
const wxString & GetReference() const
Function GetReference.
Definition: class_module.h:463
DLIST< MODULE > m_Modules
Definition: class_board.h:248
bool IsVisible() const
Definition: eda_text.h:189
void OnApplyClicked(wxCommandEvent &event) override
void OnMatchRefClicked(wxCommandEvent &event) override
const char * c_str() const
Definition: utf8.h:107
#define ID_MATCH_FP_VAL
Class PCB_EDIT_FRAME is the main frame for Pcbnew.
virtual void Push(const wxString &aMessage=wxT("A commit"), bool aCreateUndoEntry=true, bool aSetDirtyBit=true) override
Executes the changes.
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:237
bool Destroy() override
Our version of Destroy() which is virtual from wxWidgets.
void ViewAndSelectFootprint(wxCommandEvent &event) override
void ClearFlags(STATUS_FLAGS aMask=EDA_ITEM_ALL_FLAGS)
Definition: base_struct.h:257
void SetEffects(const TEXTE_MODULE &aSrc)
Function SetEffects sets the text effects from another instance.
DLIST< BOARD_ITEM > & GraphicalItemsList()
Definition: class_module.h:166
void processTextItem(const TEXTE_MODULE &aSrc, TEXTE_MODULE &aDest, bool resetText, bool resetTextLayers, bool resetTextEffects)
void CopyNetlistSettings(MODULE *aModule, bool aCopyLocalSettings)
Function CopyNetlistSettings copies the netlist settings to aModule.
Module description (excepted pads)
virtual void Refresh(bool eraseBackground=true, const wxRect *rect=NULL)
const wxString & GetPath() const
Definition: class_module.h:202
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
int g_matchModeForExchange
BOARD_ITEM * GetCurItem()
void OnMatchValueClicked(wxCommandEvent &event) override
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:203
timestamp_t GetTimeStamp() const
Definition: base_struct.h:207
void Exchange_Module(MODULE *aSrc, MODULE *aDest, BOARD_COMMIT &aCommit, bool deleteExtraTexts=true, bool resetTextLayers=true, bool resetTextEffects=true)
Function Exchange_Module Replaces OldModule by NewModule, using OldModule settings: position...
void SetTimeStamp(timestamp_t aNewTimeStamp)
Definition: base_struct.h:206
int g_matchModeForUpdate
virtual void SetText(const wxString &aText)
Definition: eda_text.h:154
int m_Status_Pcb
Flags used in ratsnest calculation and update.
Definition: class_board.h:240