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.

650 lines
18 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
14 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
14 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) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  8. * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include <fctsys.h>
  28. #include <class_drawpanel.h>
  29. #include <confirm.h>
  30. #include <kicad_string.h>
  31. #include <wxPcbStruct.h>
  32. #include <macros.h>
  33. #include <pcbcommon.h>
  34. #include <class_board.h>
  35. #include <class_module.h>
  36. #include <pcbnew.h>
  37. #include <dialog_exchange_modules_base.h>
  38. #include <wildcards_and_files_ext.h>
  39. static char* quiet_gcc_4_4_3; // GCC 4.4.3 and next ..
  40. int s_SelectionMode = 0; // Remember the last exchange option, when exit dialog.
  41. class DIALOG_EXCHANGE_MODULE : public DIALOG_EXCHANGE_MODULE_BASE
  42. {
  43. private:
  44. PCB_EDIT_FRAME* m_Parent;
  45. MODULE* m_CurrentModule;
  46. public:
  47. DIALOG_EXCHANGE_MODULE( PCB_EDIT_FRAME* aParent, MODULE* aModule );
  48. ~DIALOG_EXCHANGE_MODULE() { };
  49. private:
  50. void OnSelectionClicked( wxCommandEvent& event );
  51. void OnOkClick( wxCommandEvent& event );
  52. void OnQuit( wxCommandEvent& event );
  53. void BrowseAndSelectFootprint( wxCommandEvent& event );
  54. void Init();
  55. void Change_Current_Module();
  56. void Change_ModuleId( bool aUseValue );
  57. void Change_ModuleAll();
  58. int Maj_ListeCmp( const wxString& reference, const wxString& old_name,
  59. const wxString& new_name, bool ShowError );
  60. bool Change_1_Module( MODULE* Module,
  61. const wxString& new_module,
  62. PICKED_ITEMS_LIST* aUndoPickList,
  63. bool ShowError );
  64. };
  65. DIALOG_EXCHANGE_MODULE::DIALOG_EXCHANGE_MODULE( PCB_EDIT_FRAME* parent, MODULE* Module ) :
  66. DIALOG_EXCHANGE_MODULE_BASE( parent )
  67. {
  68. m_Parent = parent;
  69. m_CurrentModule = Module;
  70. Init();
  71. GetSizer()->Fit( this );
  72. GetSizer()->SetSizeHints( this );
  73. }
  74. void PCB_EDIT_FRAME::InstallExchangeModuleFrame( MODULE* Module )
  75. {
  76. DIALOG_EXCHANGE_MODULE dialog( this, Module );
  77. dialog.ShowModal();
  78. }
  79. void DIALOG_EXCHANGE_MODULE::OnQuit( wxCommandEvent& event )
  80. {
  81. s_SelectionMode = m_Selection->GetSelection();
  82. EndModal( 0 );
  83. }
  84. void DIALOG_EXCHANGE_MODULE::Init()
  85. {
  86. SetFocus();
  87. m_OldModule->AppendText( m_CurrentModule->GetLibRef() );
  88. m_NewModule->AppendText( m_CurrentModule->GetLibRef() );
  89. m_OldValue->AppendText( m_CurrentModule->GetValue() );
  90. m_Selection->SetSelection( s_SelectionMode );
  91. // Enable/disable widgets:
  92. wxCommandEvent event;
  93. OnSelectionClicked( event );
  94. }
  95. void DIALOG_EXCHANGE_MODULE::OnOkClick( wxCommandEvent& event )
  96. {
  97. s_SelectionMode = m_Selection->GetSelection();
  98. switch( m_Selection->GetSelection() )
  99. {
  100. case 0:
  101. Change_Current_Module();
  102. break;
  103. case 1:
  104. Change_ModuleId( false );
  105. break;
  106. case 2:
  107. Change_ModuleId( true );
  108. break;
  109. case 3:
  110. Change_ModuleAll();
  111. break;
  112. }
  113. }
  114. void DIALOG_EXCHANGE_MODULE::OnSelectionClicked( wxCommandEvent& event )
  115. {
  116. switch( m_Selection->GetSelection() )
  117. {
  118. case 0:
  119. case 1:
  120. case 2:
  121. m_NewModule->Enable( true );
  122. m_Browsebutton->Enable( true );
  123. break;
  124. case 3:
  125. m_NewModule->Enable( false );
  126. m_Browsebutton->Enable( false );
  127. break;
  128. }
  129. }
  130. /*
  131. * Updates the file name.CMP (if any) after an exchange module
  132. * (By command changeMod), if the modules are managed by this file
  133. *
  134. * If ShowError! = 0 displays error message if the file. Cmp is not found.
  135. * Return 1 if error
  136. */
  137. int DIALOG_EXCHANGE_MODULE::Maj_ListeCmp( const wxString& reference,
  138. const wxString& old_name,
  139. const wxString& new_name,
  140. bool ShowError )
  141. {
  142. wxFileName fn;
  143. wxFileName tmpFileName;
  144. FILE* FichCmp, * NewFile;
  145. char line[1024];
  146. wxString msg;
  147. if( old_name == new_name )
  148. return 0;
  149. /* Build CMP file name by changing the extension of NetList filename */
  150. fn = m_Parent->GetBoard()->GetFileName();
  151. fn.SetExt( ComponentFileExtension );
  152. FichCmp = wxFopen( fn.GetFullPath(), wxT( "rt" ) );
  153. if( FichCmp == NULL )
  154. {
  155. if( ShowError )
  156. {
  157. msg.Printf( _( "file <%s> not found" ), GetChars( fn.GetFullPath() ) );
  158. m_WinMessages->AppendText( msg );
  159. }
  160. return 1;
  161. }
  162. tmpFileName = fn;
  163. tmpFileName.SetExt( wxT( "$$$" ) );
  164. NewFile = wxFopen( tmpFileName.GetFullPath(), wxT( "wt" ) );
  165. if( NewFile == NULL )
  166. {
  167. if( ShowError )
  168. {
  169. msg.Printf( _( "Unable to create file <%s>" ),
  170. GetChars( tmpFileName.GetFullPath() ) );
  171. m_WinMessages->AppendText( msg );
  172. }
  173. return 1;
  174. }
  175. quiet_gcc_4_4_3 = fgets( line, sizeof(line), FichCmp );
  176. fprintf( NewFile, "Cmp-Mod V01 Created by PcbNew date = %s\n", TO_UTF8( DateAndTime() ) );
  177. bool start_descr = false;
  178. while( fgets( line, sizeof(line), FichCmp ) != NULL )
  179. {
  180. if( strnicmp( line, "Reference = ", 9 ) == 0 )
  181. {
  182. char buf[1024];
  183. strcpy( buf, line + 12 );
  184. strtok( buf, ";\n\r" );
  185. if( stricmp( buf, TO_UTF8( reference ) ) == 0 )
  186. {
  187. start_descr = true;
  188. }
  189. }
  190. if( (strnicmp( line, "Begin", 5 ) == 0) || (strnicmp( line, "End", 3 ) == 0) )
  191. {
  192. start_descr = false;
  193. }
  194. if( start_descr && strnicmp( line, "IdModule", 8 ) == 0 )
  195. {
  196. sprintf( line + 8, " = %s;\n", TO_UTF8( new_name ) );
  197. msg = wxT( " * in <" ) + fn.GetFullPath() + wxT( ">.\n" );
  198. m_WinMessages->AppendText( msg );
  199. start_descr = false;
  200. }
  201. fputs( line, NewFile );
  202. }
  203. fclose( FichCmp );
  204. fclose( NewFile );
  205. wxRemoveFile( fn.GetFullPath() );
  206. wxRenameFile( tmpFileName.GetFullPath(), fn.GetFullPath() );
  207. return 0;
  208. }
  209. /* Change the module at the current cursor position.
  210. * Retains the following:
  211. * - Same direction
  212. * - Same position
  213. * - Same text value and ref
  214. * - Same NetNames for pads same name
  215. */
  216. void DIALOG_EXCHANGE_MODULE::Change_Current_Module()
  217. {
  218. wxString newmodulename = m_NewModule->GetValue();
  219. if( newmodulename == wxEmptyString )
  220. return;
  221. PICKED_ITEMS_LIST pickList;
  222. if( Change_1_Module( m_CurrentModule, newmodulename, &pickList, true ) )
  223. {
  224. if( m_Parent->GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  225. m_Parent->Compile_Ratsnest( NULL, true );
  226. m_Parent->RefreshCanvas();
  227. }
  228. if( pickList.GetCount() )
  229. m_Parent->SaveCopyInUndoList( pickList, UR_UNSPECIFIED );
  230. }
  231. /*
  232. * Change of all modules with the same name as that lib
  233. * Retains:
  234. * - Same direction
  235. * - Same position
  236. * - Same text value and ref
  237. * - Same NetNames for pads same name
  238. * And replacing the old module with the new module
  239. * Note: m_CurrentModule no longer on the module reference
  240. * since it has been changed!
  241. */
  242. void DIALOG_EXCHANGE_MODULE::Change_ModuleId( bool aUseValue )
  243. {
  244. wxString msg;
  245. MODULE* Module, * PtBack;
  246. bool change = false;
  247. wxString newmodulename = m_NewModule->GetValue();
  248. wxString value, lib_reference;
  249. bool check_module_value = false;
  250. int ShowErr = 3; // Post 3 error messages max.
  251. if( m_Parent->GetBoard()->m_Modules == NULL )
  252. return;
  253. if( newmodulename == wxEmptyString )
  254. return;
  255. lib_reference = m_CurrentModule->GetLibRef();
  256. if( aUseValue )
  257. {
  258. check_module_value = true;
  259. value = m_CurrentModule->GetValue();
  260. msg.Printf( _( "Change modules %s -> %s (for value = %s)?" ),
  261. GetChars( m_CurrentModule->GetLibRef() ),
  262. GetChars( newmodulename ),
  263. GetChars( m_CurrentModule->GetValue() ) );
  264. }
  265. else
  266. {
  267. msg.Printf( _( "Change modules %s -> %s ?" ),
  268. GetChars( lib_reference ), GetChars( newmodulename ) );
  269. }
  270. if( !IsOK( this, msg ) )
  271. return;
  272. /* The change is done from the last module for the routine
  273. * Change_1_Module () modifies the last module in the list.
  274. */
  275. PICKED_ITEMS_LIST pickList;
  276. /* note: for the first module in chain (the last here), Module->Back()
  277. * points the board or is NULL
  278. */
  279. Module = m_Parent->GetBoard()->m_Modules.GetLast();
  280. for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
  281. {
  282. PtBack = Module->Back();
  283. if( lib_reference.CmpNoCase( Module->GetLibRef() ) != 0 )
  284. continue;
  285. if( check_module_value )
  286. {
  287. if( value.CmpNoCase( Module->GetValue() ) != 0 )
  288. continue;
  289. }
  290. if( Change_1_Module( Module, newmodulename, &pickList, ShowErr ) )
  291. change = true;
  292. else if( ShowErr )
  293. ShowErr--;
  294. }
  295. if( change )
  296. {
  297. if( m_Parent->GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  298. m_Parent->Compile_Ratsnest( NULL, true );
  299. m_Parent->RefreshCanvas();
  300. }
  301. if( pickList.GetCount() )
  302. m_Parent->SaveCopyInUndoList( pickList, UR_UNSPECIFIED );
  303. }
  304. /*
  305. * Change all modules with module of the same name in library.
  306. * Maintains:
  307. * - Same direction
  308. * - Same position
  309. * - Same text value and ref
  310. * - Same NetNames for pads same name
  311. */
  312. void DIALOG_EXCHANGE_MODULE::Change_ModuleAll()
  313. {
  314. MODULE* Module, * PtBack;
  315. bool change = false;
  316. int ShowErr = 3; // Post 3 error messages max.
  317. if( m_Parent->GetBoard()->m_Modules == NULL )
  318. return;
  319. if( !IsOK( this, _( "Change ALL modules ?" ) ) )
  320. return;
  321. /* The change is done from the last module for the routine
  322. * Change_1_Module () modifies the last module in the list
  323. */
  324. PICKED_ITEMS_LIST pickList;
  325. /* note: for the first module in chain (the last here), Module->Back()
  326. * points the board or is NULL
  327. */
  328. Module = m_Parent->GetBoard()->m_Modules.GetLast();
  329. for( ; Module && ( Module->Type() == PCB_MODULE_T ); Module = PtBack )
  330. {
  331. PtBack = Module->Back();
  332. if( Change_1_Module( Module, Module->GetLibRef(), &pickList, ShowErr ) )
  333. change = true;
  334. else if( ShowErr )
  335. ShowErr--;
  336. }
  337. if( change )
  338. {
  339. if( m_Parent->GetBoard()->IsElementVisible( RATSNEST_VISIBLE ) )
  340. m_Parent->Compile_Ratsnest( NULL, true );
  341. m_Parent->RefreshCanvas();
  342. }
  343. if( pickList.GetCount() )
  344. m_Parent->SaveCopyInUndoList( pickList, UR_UNSPECIFIED );
  345. }
  346. /*
  347. * Change the number empr module with the module name new_module
  348. * - Same direction
  349. * - Same position
  350. * - Same text value and ref
  351. * - Same NetNames for pads same name
  352. * Returns:
  353. * False if no change (if the new module is not free)
  354. * True if OK
  355. * Ratsnest must be recalculated after module exchange
  356. */
  357. bool DIALOG_EXCHANGE_MODULE::Change_1_Module( MODULE* Module,
  358. const wxString& new_module,
  359. PICKED_ITEMS_LIST* aUndoPickList,
  360. bool ShowError )
  361. {
  362. wxString namecmp, oldnamecmp;
  363. MODULE* NewModule;
  364. wxString line;
  365. if( Module == NULL )
  366. return false;
  367. wxBusyCursor dummy;
  368. /* Copy parameters from the old module. */
  369. oldnamecmp = Module->GetLibRef();
  370. namecmp = new_module;
  371. /* Load module. */
  372. line.Printf( _( "Change module %s (from %s) " ),
  373. GetChars( Module->GetReference() ),
  374. GetChars( oldnamecmp ) );
  375. m_WinMessages->AppendText( line );
  376. namecmp.Trim( true );
  377. namecmp.Trim( false );
  378. NewModule = m_Parent->GetModuleLibrary( wxEmptyString, namecmp, ShowError );
  379. if( NewModule == NULL ) /* New module not found, redraw the old one. */
  380. {
  381. m_WinMessages->AppendText( wxT( "No\n" ) );
  382. return false;
  383. }
  384. m_Parent->GetBoard()->Add( NewModule, ADD_APPEND );
  385. if( Module == m_CurrentModule )
  386. m_CurrentModule = NewModule;
  387. m_WinMessages->AppendText( wxT( "OK\n" ) );
  388. m_Parent->Exchange_Module( Module, NewModule, aUndoPickList );
  389. Maj_ListeCmp( NewModule->GetReference(), oldnamecmp, namecmp, ShowError );
  390. return true;
  391. }
  392. void PCB_EDIT_FRAME::Exchange_Module( MODULE* aOldModule,
  393. MODULE* aNewModule,
  394. PICKED_ITEMS_LIST* aUndoPickList )
  395. {
  396. wxPoint oldpos;
  397. D_PAD* pad, * old_pad;
  398. if( ( aOldModule->Type() != PCB_MODULE_T ) || ( aNewModule->Type() != PCB_MODULE_T ) )
  399. {
  400. wxMessageBox( wxT( "PCB_EDIT_FRAME::Exchange_Module() StuctType error" ) );
  401. return;
  402. }
  403. aNewModule->SetParent( GetBoard() );
  404. GetBoard()->m_Status_Pcb = 0;
  405. oldpos = GetScreen()->GetCrossHairPosition();
  406. GetScreen()->SetCrossHairPosition( aOldModule->GetPosition(), false );
  407. /* place module without ratsnest refresh: this will be made later
  408. * when all modules are on board
  409. */
  410. PlaceModule( aNewModule, NULL, true );
  411. GetScreen()->SetCrossHairPosition( oldpos, false );
  412. /* Flip footprint if needed */
  413. if( aOldModule->GetLayer() != aNewModule->GetLayer() )
  414. {
  415. aNewModule->Flip( aNewModule->GetPosition() );
  416. }
  417. /* Rotate footprint if needed */
  418. if( aOldModule->GetOrientation() != aNewModule->GetOrientation() )
  419. {
  420. Rotate_Module( NULL, aNewModule, aOldModule->GetOrientation(), false );
  421. }
  422. /* Update reference and value */
  423. aNewModule->SetReference( aOldModule->GetReference() );
  424. aNewModule->SetValue( aOldModule->GetValue() );
  425. /* Updating other parameters */
  426. aNewModule->SetTimeStamp( aOldModule->GetTimeStamp() );
  427. aNewModule->SetPath( aOldModule->GetPath() );
  428. /* Update pad netnames ( when possible) */
  429. pad = aNewModule->Pads();
  430. for( ; pad != NULL; pad = pad->Next() )
  431. {
  432. pad->SetNetname( wxEmptyString );
  433. pad->SetNet( 0 );
  434. old_pad = aOldModule->Pads();
  435. for( ; old_pad != NULL; old_pad = old_pad->Next() )
  436. {
  437. if( pad->PadNameEqual( old_pad ) )
  438. {
  439. pad->SetNetname( old_pad->GetNetname() );
  440. pad->SetNet( old_pad->GetNet() );
  441. }
  442. }
  443. }
  444. if( aUndoPickList )
  445. {
  446. GetBoard()->Remove( aOldModule );
  447. ITEM_PICKER picker_old( aOldModule, UR_DELETED );
  448. ITEM_PICKER picker_new( aNewModule, UR_NEW );
  449. aUndoPickList->PushItem( picker_old );
  450. aUndoPickList->PushItem( picker_new );
  451. }
  452. else
  453. {
  454. aOldModule->DeleteStructure();
  455. }
  456. GetBoard()->m_Status_Pcb = 0;
  457. aNewModule->ClearFlags();
  458. OnModify();
  459. }
  460. /*
  461. * Displays the list of modules in library name and select 1 name.
  462. */
  463. void DIALOG_EXCHANGE_MODULE::BrowseAndSelectFootprint( wxCommandEvent& event )
  464. {
  465. wxString newname;
  466. newname = m_Parent->SelectFootprint( m_Parent, wxEmptyString, wxEmptyString, wxEmptyString,
  467. m_Parent->GetFootprintLibraryTable() );
  468. if( newname != wxEmptyString )
  469. m_NewModule->SetValue( newname );
  470. }
  471. void PCB_EDIT_FRAME::RecreateCmpFileFromBoard( wxCommandEvent& aEvent )
  472. {
  473. wxFileName fn;
  474. FILE* FichCmp;
  475. char line[1024];
  476. MODULE* Module = GetBoard()->m_Modules;
  477. wxString msg;
  478. wxString wildcard;
  479. if( Module == NULL )
  480. {
  481. DisplayError( this, _( "No Modules!" ) );
  482. return;
  483. }
  484. /* Calculation file name by changing the extension name to NetList */
  485. fn = GetBoard()->GetFileName();
  486. fn.SetExt( ComponentFileExtension );
  487. wildcard = wxGetTranslation( ComponentFileWildcard );
  488. wxFileDialog dlg( this, _( "Save Component Files" ), wxGetCwd(),
  489. fn.GetFullName(), wildcard,
  490. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  491. if( dlg.ShowModal() == wxID_CANCEL )
  492. return;
  493. fn = dlg.GetPath();
  494. FichCmp = wxFopen( fn.GetFullPath(), wxT( "wt" ) );
  495. if( FichCmp == NULL )
  496. {
  497. msg = _( "Unable to create file " ) + fn.GetFullPath();
  498. DisplayError( this, msg );
  499. return;
  500. }
  501. quiet_gcc_4_4_3 = fgets( line, sizeof(line), FichCmp );
  502. fprintf( FichCmp, "Cmp-Mod V01 Genere par PcbNew le %s\n", TO_UTF8( DateAndTime() ) );
  503. for( ; Module != NULL; Module = Module->Next() )
  504. {
  505. fprintf( FichCmp, "\nBeginCmp\n" );
  506. fprintf( FichCmp, "TimeStamp = %8.8lX\n", Module->GetTimeStamp() );
  507. fprintf( FichCmp, "Path = %s\n", TO_UTF8( Module->GetPath() ) );
  508. fprintf( FichCmp, "Reference = %s;\n",
  509. !Module->GetReference().IsEmpty() ?
  510. TO_UTF8( Module->GetReference() ) : "[NoRef]" );
  511. fprintf( FichCmp, "ValeurCmp = %s;\n",
  512. !Module->GetValue().IsEmpty() ?
  513. TO_UTF8( Module->GetValue() ) : "[NoVal]" );
  514. fprintf( FichCmp, "IdModule = %s;\n", TO_UTF8( Module->GetLibRef() ) );
  515. fprintf( FichCmp, "EndCmp\n" );
  516. }
  517. fprintf( FichCmp, "\nEndListe\n" );
  518. fclose( FichCmp );
  519. }