You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

508 lines
14 KiB

17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
17 years ago
  1. /**
  2. * @file xchgmod.cpp
  3. */
  4. /*
  5. * This program source code file is part of KiCad, a free EDA CAD application.
  6. *
  7. * Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
  8. * Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  9. * Copyright (C) 2013-2016 Wayne Stambaugh <stambaughw@verizon.net>
  10. * Copyright (C) 1992-2016 KiCad Developers, see AUTHORS.txt for contributors.
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; either version 2
  15. * of the License, or (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. * GNU General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, you may find one here:
  24. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  25. * or you may search the http://www.gnu.org website for the version 2 license,
  26. * or you may write to the Free Software Foundation, Inc.,
  27. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  28. */
  29. #include <fctsys.h>
  30. #include <class_drawpanel.h>
  31. #include <class_draw_panel_gal.h>
  32. #include <confirm.h>
  33. #include <kicad_string.h>
  34. #include <wxPcbStruct.h>
  35. #include <macros.h>
  36. #include <board_commit.h>
  37. #include <class_board.h>
  38. #include <class_module.h>
  39. #include <project.h>
  40. #include <pcbnew.h>
  41. #include <dialog_exchange_modules_base.h>
  42. #include <wildcards_and_files_ext.h>
  43. #include <kiway.h>
  44. static bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName );
  45. class DIALOG_EXCHANGE_MODULE : public DIALOG_EXCHANGE_MODULE_BASE
  46. {
  47. private:
  48. PCB_EDIT_FRAME* m_parent;
  49. MODULE* m_currentModule;
  50. static int m_selectionMode; // Remember the last exchange option
  51. public:
  52. DIALOG_EXCHANGE_MODULE( PCB_EDIT_FRAME* aParent, MODULE* aModule );
  53. ~DIALOG_EXCHANGE_MODULE() { };
  54. private:
  55. void OnSelectionClicked( wxCommandEvent& event ) override;
  56. void OnOkClick( wxCommandEvent& event ) override;
  57. void OnQuit( wxCommandEvent& event ) override;
  58. void BrowseAndSelectFootprint( wxCommandEvent& event ) override;
  59. void ViewAndSelectFootprint( wxCommandEvent& event ) override;
  60. void RebuildCmpList( wxCommandEvent& event ) override;
  61. void init();
  62. bool changeCurrentFootprint();
  63. bool changeSameFootprints( bool aUseValue);
  64. bool changeAllFootprints();
  65. bool change_1_Module( MODULE* aModule,
  66. const LIB_ID& aNewFootprintFPID,
  67. bool eShowError );
  68. BOARD_COMMIT m_commit;
  69. };
  70. int DIALOG_EXCHANGE_MODULE::m_selectionMode = 0;
  71. DIALOG_EXCHANGE_MODULE::DIALOG_EXCHANGE_MODULE( PCB_EDIT_FRAME* parent, MODULE* Module ) :
  72. DIALOG_EXCHANGE_MODULE_BASE( parent ), m_commit( parent )
  73. {
  74. m_parent = parent;
  75. m_currentModule = Module;
  76. init();
  77. GetSizer()->Fit( this );
  78. GetSizer()->SetSizeHints( this );
  79. Center();
  80. }
  81. int PCB_EDIT_FRAME::InstallExchangeModuleFrame( MODULE* Module )
  82. {
  83. DIALOG_EXCHANGE_MODULE dialog( this, Module );
  84. return dialog.ShowQuasiModal();
  85. }
  86. void DIALOG_EXCHANGE_MODULE::OnQuit( wxCommandEvent& event )
  87. {
  88. m_selectionMode = m_Selection->GetSelection();
  89. Show( false );
  90. EndQuasiModal( wxID_CANCEL );
  91. }
  92. void DIALOG_EXCHANGE_MODULE::init()
  93. {
  94. SetFocus();
  95. m_CurrentFootprintFPID->AppendText( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
  96. m_NewFootprintFPID->AppendText( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) );
  97. m_CmpValue->AppendText( m_currentModule->GetValue() );
  98. m_CmpReference->AppendText( m_currentModule->GetReference() );
  99. m_Selection->SetString( 0, wxString::Format(
  100. _( "Change footprint of '%s'" ),
  101. GetChars( m_currentModule->GetReference() ) ) );
  102. wxString fpname = m_CurrentFootprintFPID->GetValue().AfterLast( ':' );
  103. if( fpname.IsEmpty() ) // Happens for old fp names
  104. fpname = m_CurrentFootprintFPID->GetValue();
  105. m_Selection->SetString( 1, wxString::Format(
  106. _( "Change footprints '%s'" ),
  107. GetChars( fpname.Left( 12 ) ) ) );
  108. m_Selection->SetSelection( m_selectionMode );
  109. // Enable/disable widgets:
  110. wxCommandEvent event;
  111. OnSelectionClicked( event );
  112. }
  113. void DIALOG_EXCHANGE_MODULE::OnOkClick( wxCommandEvent& event )
  114. {
  115. m_selectionMode = m_Selection->GetSelection();
  116. bool result = false;
  117. switch( m_Selection->GetSelection() )
  118. {
  119. case 0:
  120. result = changeCurrentFootprint();
  121. break;
  122. case 1:
  123. result = changeSameFootprints( false );
  124. break;
  125. case 2:
  126. result = changeSameFootprints( true );
  127. break;
  128. case 3:
  129. result = changeAllFootprints();
  130. break;
  131. }
  132. if( result )
  133. {
  134. if( m_parent->GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  135. m_parent->Compile_Ratsnest( NULL, true );
  136. m_parent->GetCanvas()->Refresh();
  137. }
  138. m_commit.Push( wxT( "Changed footprint" ) );
  139. }
  140. void DIALOG_EXCHANGE_MODULE::OnSelectionClicked( wxCommandEvent& event )
  141. {
  142. bool enable = true;
  143. switch( m_Selection->GetSelection() )
  144. {
  145. case 0:
  146. case 1:
  147. case 2:
  148. break;
  149. case 3:
  150. enable = false;
  151. break;
  152. }
  153. m_NewFootprintFPID->Enable( enable );
  154. m_Browsebutton->Enable( enable );
  155. }
  156. void DIALOG_EXCHANGE_MODULE::RebuildCmpList( wxCommandEvent& event )
  157. {
  158. wxFileName fn;
  159. wxString msg;
  160. // Build the .cmp file name from the board name
  161. fn = m_parent->GetBoard()->GetFileName();
  162. fn.SetExt( ComponentFileExtension );
  163. if( RecreateCmpFile( m_parent->GetBoard(), fn.GetFullPath() ) )
  164. {
  165. msg.Printf( _( "File '%s' created\n" ),
  166. GetChars( fn.GetFullPath() ) );
  167. }
  168. else
  169. {
  170. msg.Printf( _( "** Could not create file '%s' ***\n" ),
  171. GetChars( fn.GetFullPath() ) );
  172. }
  173. m_WinMessages->AppendText( msg );
  174. }
  175. bool DIALOG_EXCHANGE_MODULE::changeCurrentFootprint()
  176. {
  177. wxString newmodulename = m_NewFootprintFPID->GetValue();
  178. if( newmodulename == wxEmptyString )
  179. return false;
  180. return change_1_Module( m_currentModule, newmodulename, true );
  181. }
  182. bool DIALOG_EXCHANGE_MODULE::changeSameFootprints( bool aUseValue )
  183. {
  184. wxString msg;
  185. MODULE* Module;
  186. MODULE* PtBack;
  187. bool change = false;
  188. wxString newmodulename = m_NewFootprintFPID->GetValue();
  189. wxString value;
  190. LIB_ID lib_reference;
  191. bool check_module_value = false;
  192. int ShowErr = 3; // Post 3 error messages max.
  193. if( m_parent->GetBoard()->m_Modules == NULL )
  194. return false;
  195. if( newmodulename == wxEmptyString )
  196. return false;
  197. lib_reference = m_currentModule->GetFPID();
  198. if( aUseValue )
  199. {
  200. check_module_value = true;
  201. value = m_currentModule->GetValue();
  202. msg.Printf( _( "Change footprint %s -> %s (for value = %s)?" ),
  203. GetChars( FROM_UTF8( m_currentModule->GetFPID().Format().c_str() ) ),
  204. GetChars( newmodulename ),
  205. GetChars( m_currentModule->GetValue() ) );
  206. }
  207. else
  208. {
  209. msg.Printf( _( "Change footprint %s -> %s ?" ),
  210. GetChars( FROM_UTF8( lib_reference.Format().c_str() ) ),
  211. GetChars( newmodulename ) );
  212. }
  213. if( !IsOK( this, msg ) )
  214. return false;
  215. /* The change is done from the last module because
  216. * change_1_Module () modifies the last item in the list.
  217. *
  218. * note: for the first module in chain (the last here), Module->Back()
  219. * points the board or is NULL
  220. */
  221. Module = m_parent->GetBoard()->m_Modules.GetLast();
  222. for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
  223. {
  224. PtBack = Module->Back();
  225. if( lib_reference != Module->GetFPID() )
  226. continue;
  227. if( check_module_value )
  228. {
  229. if( value.CmpNoCase( Module->GetValue() ) != 0 )
  230. continue;
  231. }
  232. if( change_1_Module( Module, newmodulename, ShowErr ) )
  233. change = true;
  234. else if( ShowErr )
  235. ShowErr--;
  236. }
  237. return change;
  238. }
  239. bool DIALOG_EXCHANGE_MODULE::changeAllFootprints()
  240. {
  241. MODULE* Module, * PtBack;
  242. bool change = false;
  243. int ShowErr = 3; // Post 3 error max.
  244. if( m_parent->GetBoard()->m_Modules == NULL )
  245. return false;
  246. if( !IsOK( this, _( "Are you sure you want to change all footprints?" ) ) )
  247. return false;
  248. /* The change is done from the last module because the function
  249. * change_1_Module () modifies the last module in the list
  250. *
  251. * note: for the first module in chain (the last here), Module->Back()
  252. * points the board or is NULL
  253. */
  254. Module = m_parent->GetBoard()->m_Modules.GetLast();
  255. for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
  256. {
  257. PtBack = Module->Back();
  258. if( change_1_Module( Module, Module->GetFPID(), ShowErr ) )
  259. change = true;
  260. else if( ShowErr )
  261. ShowErr--;
  262. }
  263. return change;
  264. }
  265. bool DIALOG_EXCHANGE_MODULE::change_1_Module( MODULE* aModule,
  266. const LIB_ID& aNewFootprintFPID,
  267. bool aShowError )
  268. {
  269. MODULE* newModule;
  270. wxString line;
  271. if( aModule == NULL )
  272. return false;
  273. wxBusyCursor dummy;
  274. // Copy parameters from the old module.
  275. LIB_ID oldFootprintFPID = aModule->GetFPID();
  276. // Load module.
  277. line.Printf( _( "Change footprint '%s' (from '%s') to '%s'" ),
  278. GetChars( aModule->GetReference() ),
  279. oldFootprintFPID.Format().c_str(),
  280. aNewFootprintFPID.Format().c_str() );
  281. m_WinMessages->AppendText( line );
  282. newModule = m_parent->LoadFootprint( aNewFootprintFPID );
  283. if( newModule == NULL ) // New module not found, redraw the old one.
  284. {
  285. m_WinMessages->AppendText( wxT( " No\n" ) );
  286. return false;
  287. }
  288. m_parent->Exchange_Module( aModule, newModule, m_commit );
  289. if( aModule == m_currentModule )
  290. m_currentModule = newModule;
  291. m_WinMessages->AppendText( wxT( " OK\n" ) );
  292. return true;
  293. }
  294. void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule,
  295. MODULE* aNewModule,
  296. BOARD_COMMIT& aCommit )
  297. {
  298. aNewModule->SetParent( GetBoard() );
  299. /* place module without ratsnest refresh: this will be made later
  300. * when all modules are on board */
  301. PlaceModule( aNewModule, NULL, true );
  302. // Copy full placement and pad net names (when possible)
  303. // but not local settings like clearances (use library values)
  304. aOldModule->CopyNetlistSettings( aNewModule, false );
  305. // Copy reference and value
  306. aNewModule->SetReference( aOldModule->GetReference() );
  307. aNewModule->SetValue( aOldModule->GetValue() );
  308. // Updating other parameters
  309. aNewModule->SetTimeStamp( aOldModule->GetTimeStamp() );
  310. aNewModule->SetPath( aOldModule->GetPath() );
  311. aCommit.Remove( aOldModule );
  312. aCommit.Add( aNewModule );
  313. // @todo LEGACY should be unnecessary
  314. GetBoard()->m_Status_Pcb = 0;
  315. aNewModule->ClearFlags();
  316. }
  317. // Displays the list of available footprints in library name and select a footprint.
  318. void DIALOG_EXCHANGE_MODULE::BrowseAndSelectFootprint( wxCommandEvent& event )
  319. {
  320. wxString newname;
  321. newname = m_parent->SelectFootprint( m_parent, wxEmptyString, wxEmptyString, wxEmptyString,
  322. Prj().PcbFootprintLibs() );
  323. if( newname != wxEmptyString )
  324. m_NewFootprintFPID->SetValue( newname );
  325. }
  326. void DIALOG_EXCHANGE_MODULE::ViewAndSelectFootprint( wxCommandEvent& event )
  327. {
  328. wxString newname;
  329. KIWAY_PLAYER* frame = Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true );
  330. if( frame->ShowModal( &newname, this ) )
  331. {
  332. m_NewFootprintFPID->SetValue( newname );
  333. }
  334. frame->Destroy();
  335. }
  336. void PCB_EDIT_FRAME::RecreateCmpFileFromBoard( wxCommandEvent& aEvent )
  337. {
  338. wxFileName fn;
  339. MODULE* module = GetBoard()->m_Modules;
  340. wxString msg;
  341. wxString wildcard;
  342. if( module == NULL )
  343. {
  344. DisplayError( this, _( "No footprints!" ) );
  345. return;
  346. }
  347. // Build the .cmp file name from the board name
  348. fn = GetBoard()->GetFileName();
  349. fn.SetExt( ComponentFileExtension );
  350. wildcard = wxGetTranslation( ComponentFileWildcard );
  351. wxString pro_dir = wxPathOnly( Prj().GetProjectFullName() );
  352. wxFileDialog dlg( this, _( "Save Footprint Association File" ), pro_dir,
  353. fn.GetFullName(), wildcard,
  354. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  355. if( dlg.ShowModal() == wxID_CANCEL )
  356. return;
  357. fn = dlg.GetPath();
  358. if( ! RecreateCmpFile( GetBoard(), fn.GetFullPath() ) )
  359. {
  360. msg.Printf( _( "Could not create file '%s'" ), GetChars(fn.GetFullPath() ) );
  361. DisplayError( this, msg );
  362. return;
  363. }
  364. }
  365. bool RecreateCmpFile( BOARD * aBrd, const wxString& aFullCmpFileName )
  366. {
  367. FILE* cmpFile;
  368. cmpFile = wxFopen( aFullCmpFileName, wxT( "wt" ) );
  369. if( cmpFile == NULL )
  370. return false;
  371. fprintf( cmpFile, "Cmp-Mod V01 Created by PcbNew date = %s\n", TO_UTF8( DateAndTime() ) );
  372. MODULE* module = aBrd->m_Modules;
  373. for( ; module != NULL; module = module->Next() )
  374. {
  375. fprintf( cmpFile, "\nBeginCmp\n" );
  376. fprintf( cmpFile, "TimeStamp = %8.8lX\n", (unsigned long)module->GetTimeStamp() );
  377. fprintf( cmpFile, "Path = %s\n", TO_UTF8( module->GetPath() ) );
  378. fprintf( cmpFile, "Reference = %s;\n",
  379. !module->GetReference().IsEmpty() ?
  380. TO_UTF8( module->GetReference() ) : "[NoRef]" );
  381. fprintf( cmpFile, "ValeurCmp = %s;\n",
  382. !module->GetValue().IsEmpty() ?
  383. TO_UTF8( module->GetValue() ) : "[NoVal]" );
  384. fprintf( cmpFile, "IdModule = %s;\n", module->GetFPID().Format().c_str() );
  385. fprintf( cmpFile, "EndCmp\n" );
  386. }
  387. fprintf( cmpFile, "\nEndListe\n" );
  388. fclose( cmpFile );
  389. return true;
  390. }