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.

689 lines
20 KiB

14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
14 years ago
15 years ago
14 years ago
14 years ago
15 years ago
15 years ago
14 years ago
14 years ago
14 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2012 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright (C) 2012 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
  6. * Copyright (C) 1992-2012 KiCad Developers, see AUTHORS.txt for contributors.
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU General Public License
  10. * as published by the Free Software Foundation; either version 2
  11. * of the License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, you may find one here:
  20. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  21. * or you may search the http://www.gnu.org website for the version 2 license,
  22. * or you may write to the Free Software Foundation, Inc.,
  23. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  24. */
  25. /**
  26. * @file pcbnew/loadcmp.cpp
  27. * @brief Footprints selection and loading functions.
  28. */
  29. #include <fctsys.h>
  30. #include <class_drawpanel.h>
  31. #include <confirm.h>
  32. #include <eda_doc.h>
  33. #include <kicad_string.h>
  34. #include <appl_wxstruct.h>
  35. #include <wxPcbStruct.h>
  36. #include <dialog_helpers.h>
  37. #include <filter_reader.h>
  38. #include <gr_basic.h>
  39. #include <macros.h>
  40. #include <pcbcommon.h>
  41. #include <fp_lib_table.h>
  42. #include <fpid.h>
  43. #include <class_board.h>
  44. #include <class_module.h>
  45. #include <io_mgr.h>
  46. #include <pcbnew.h>
  47. #include <module_editor_frame.h>
  48. #include <footprint_info.h>
  49. #include <dialog_get_component.h>
  50. #include <modview_frame.h>
  51. #include <wildcards_and_files_ext.h>
  52. static void DisplayCmpDoc( wxString& Name );
  53. static FOOTPRINT_LIST MList;
  54. bool FOOTPRINT_EDIT_FRAME::Load_Module_From_BOARD( MODULE* aModule )
  55. {
  56. MODULE* newModule;
  57. PCB_BASE_FRAME* parent = (PCB_BASE_FRAME*) GetParent();
  58. if( aModule == NULL )
  59. {
  60. if( ! parent->GetBoard() || ! parent->GetBoard()->m_Modules )
  61. return false;
  62. aModule = SelectFootprint( parent->GetBoard() );
  63. }
  64. if( aModule == NULL )
  65. return false;
  66. SetCurItem( NULL );
  67. Clear_Pcb( false );
  68. GetBoard()->m_Status_Pcb = 0;
  69. newModule = new MODULE( *aModule );
  70. newModule->SetParent( GetBoard() );
  71. newModule->SetLink( aModule->GetTimeStamp() );
  72. aModule = newModule;
  73. GetBoard()->Add( aModule );
  74. aModule->ClearFlags();
  75. GetBoard()->BuildListOfNets();
  76. SetCrossHairPosition( wxPoint( 0, 0 ) );
  77. PlaceModule( aModule, NULL );
  78. // Put it on FRONT layer,
  79. // because this is the default in ModEdit, and in libs
  80. if( aModule->GetLayer() != LAYER_N_FRONT )
  81. aModule->Flip( aModule->GetPosition() );
  82. // Put it in orientation 0,
  83. // because this is the default orientation in ModEdit, and in libs
  84. Rotate_Module( NULL, aModule, 0, false );
  85. GetScreen()->ClrModify();
  86. Zoom_Automatique( false );
  87. return true;
  88. }
  89. /*
  90. * Launch the footprint viewer to select the name of a footprint to load.
  91. * return the selected footprint name
  92. */
  93. wxString PCB_BASE_FRAME::SelectFootprintFromLibBrowser( void )
  94. {
  95. wxString fpname;
  96. wxSemaphore semaphore( 0, 1 );
  97. // Close the current Lib browser, if opened, and open a new one, in "modal" mode:
  98. FOOTPRINT_VIEWER_FRAME * viewer = FOOTPRINT_VIEWER_FRAME::GetActiveFootprintViewer();
  99. if( viewer )
  100. viewer->Destroy();
  101. viewer = new FOOTPRINT_VIEWER_FRAME( this, m_footprintLibTable, &semaphore,
  102. KICAD_DEFAULT_DRAWFRAME_STYLE | wxFRAME_FLOAT_ON_PARENT );
  103. // Show the library viewer frame until it is closed
  104. while( semaphore.TryWait() == wxSEMA_BUSY ) // Wait for viewer closing event
  105. {
  106. wxYield();
  107. wxMilliSleep( 50 );
  108. }
  109. #if !defined( USE_FP_LIB_TABLE )
  110. // Returns the full fp name, i.e. the lib name and th fp name,
  111. // separated by a '/' (/ is now an illegal char in fp names)
  112. fpname = viewer->GetSelectedLibraryFullName() + wxT( "/" ) + viewer->GetSelectedFootprint();
  113. #else
  114. fpname = viewer->GetSelectedLibrary() + wxT( ":" ) + viewer->GetSelectedFootprint();
  115. #endif
  116. viewer->Destroy();
  117. return fpname;
  118. }
  119. MODULE* PCB_BASE_FRAME::LoadModuleFromLibrary( const wxString& aLibrary,
  120. FP_LIB_TABLE* aTable,
  121. bool aUseFootprintViewer,
  122. wxDC* aDC )
  123. {
  124. MODULE* module = NULL;
  125. wxPoint curspos = GetCrossHairPosition();
  126. wxString moduleName, keys;
  127. wxString libName = aLibrary;
  128. bool allowWildSeach = true;
  129. static wxArrayString HistoryList;
  130. static wxString lastComponentName;
  131. // Ask for a component name or key words
  132. DIALOG_GET_COMPONENT dlg( this, HistoryList, _( "Load Module" ), aUseFootprintViewer );
  133. dlg.SetComponentName( lastComponentName );
  134. if( dlg.ShowModal() == wxID_CANCEL )
  135. return NULL;
  136. if( dlg.m_GetExtraFunction )
  137. {
  138. // SelectFootprintFromLibBrowser() returns the "full" footprint name, i.e.
  139. // <lib_name>/<footprint name> or FPID format "lib_name:fp_name:rev#"
  140. #if !defined( USE_FP_LIB_TABLE )
  141. wxString full_fpname = SelectFootprintFromLibBrowser();
  142. moduleName = full_fpname.AfterLast( '/' );
  143. libName = full_fpname.BeforeLast( '/' );
  144. #else
  145. moduleName = SelectFootprintFromLibBrowser();
  146. #endif
  147. }
  148. else
  149. {
  150. moduleName = dlg.GetComponentName();
  151. }
  152. if( moduleName.IsEmpty() ) // Cancel command
  153. {
  154. m_canvas->MoveCursorToCrossHair();
  155. return NULL;
  156. }
  157. if( dlg.IsKeyword() ) // Selection by keywords
  158. {
  159. allowWildSeach = false;
  160. keys = moduleName;
  161. moduleName = SelectFootprint( this, libName, wxEmptyString, keys, aTable );
  162. if( moduleName.IsEmpty() ) // Cancel command
  163. {
  164. m_canvas->MoveCursorToCrossHair();
  165. return NULL;
  166. }
  167. }
  168. else if( moduleName.Contains( wxT( "?" ) )
  169. || moduleName.Contains( wxT( "*" ) ) ) // Selection wild card
  170. {
  171. allowWildSeach = false;
  172. moduleName = SelectFootprint( this, libName, moduleName, wxEmptyString, aTable );
  173. if( moduleName.IsEmpty() )
  174. {
  175. m_canvas->MoveCursorToCrossHair();
  176. return NULL; // Cancel command.
  177. }
  178. }
  179. #if !defined( USE_FP_LIB_TABLE )
  180. module = GetModuleLibrary( libName, moduleName, false );
  181. #else
  182. FPID fpid;
  183. wxCHECK_MSG( fpid.Parse( moduleName ) < 0, NULL,
  184. wxString::Format( wxT( "Could not parse FPID string <%s>." ),
  185. GetChars( moduleName ) ) );
  186. try
  187. {
  188. module = loadFootprint( fpid );
  189. }
  190. catch( IO_ERROR ioe )
  191. {
  192. wxLogDebug( wxT( "An error occurred attemping to load footprint <%s>.\n\nError: %s" ),
  193. fpid.Format().c_str(), GetChars( ioe.errorText ) );
  194. }
  195. #endif
  196. if( !module && allowWildSeach ) // Search with wild card
  197. {
  198. allowWildSeach = false;
  199. wxString wildname = wxChar( '*' ) + moduleName + wxChar( '*' );
  200. moduleName = wildname;
  201. moduleName = SelectFootprint( this, libName, moduleName, wxEmptyString, aTable );
  202. if( moduleName.IsEmpty() )
  203. {
  204. m_canvas->MoveCursorToCrossHair();
  205. return NULL; // Cancel command.
  206. }
  207. else
  208. {
  209. #if !defined( USE_FP_LIB_TABLE )
  210. module = GetModuleLibrary( libName, moduleName, true );
  211. #else
  212. FPID fpid;
  213. wxCHECK_MSG( fpid.Parse( moduleName ) < 0, NULL,
  214. wxString::Format( wxT( "Could not parse FPID string <%s>." ),
  215. GetChars( moduleName ) ) );
  216. try
  217. {
  218. module = loadFootprint( fpid );
  219. }
  220. catch( IO_ERROR ioe )
  221. {
  222. wxLogDebug( wxT( "An error occurred attemping to load footprint <%s>.\n\nError: %s" ),
  223. fpid.Format().c_str(), GetChars( ioe.errorText ) );
  224. }
  225. #endif
  226. }
  227. }
  228. SetCrossHairPosition( curspos );
  229. m_canvas->MoveCursorToCrossHair();
  230. if( module )
  231. {
  232. GetBoard()->Add( module, ADD_APPEND );
  233. lastComponentName = moduleName;
  234. AddHistoryComponentName( HistoryList, moduleName );
  235. module->SetFlags( IS_NEW );
  236. module->SetLink( 0 );
  237. module->SetPosition( curspos );
  238. module->SetTimeStamp( GetNewTimeStamp() );
  239. GetBoard()->m_Status_Pcb = 0;
  240. // Put it on FRONT layer,
  241. // (Can be stored flipped if the lib is an archive built from a board)
  242. if( module->IsFlipped() )
  243. module->Flip( module->GetPosition() );
  244. // Place it in orientation 0,
  245. // even if it is not saved with orientation 0 in lib
  246. // (Can happen if the lib is an archive built from a board)
  247. Rotate_Module( NULL, module, 0, false );
  248. RecalculateAllTracksNetcode();
  249. if( aDC )
  250. module->Draw( m_canvas, aDC, GR_OR );
  251. }
  252. return module;
  253. }
  254. MODULE* PCB_BASE_FRAME::GetModuleLibrary( const wxString& aLibraryPath,
  255. const wxString& aFootprintName,
  256. bool aDisplayError )
  257. {
  258. if( aLibraryPath.IsEmpty() )
  259. return loadFootprintFromLibraries( aFootprintName, aDisplayError );
  260. else
  261. return loadFootprintFromLibrary( aLibraryPath, aFootprintName, aDisplayError );
  262. }
  263. MODULE* PCB_BASE_FRAME::loadFootprintFromLibrary( const wxString& aLibraryPath,
  264. const wxString& aFootprintName,
  265. bool aDisplayError )
  266. {
  267. try
  268. {
  269. PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );
  270. wxString libPath = wxGetApp().FindLibraryPath( aLibraryPath );
  271. MODULE* footprint = pi->FootprintLoad( libPath, aFootprintName );
  272. if( !footprint )
  273. {
  274. if( aDisplayError )
  275. {
  276. wxString msg = wxString::Format(
  277. _( "Footprint %s not found in library <%s>." ),
  278. aFootprintName.GetData(),
  279. libPath.GetData() );
  280. DisplayError( NULL, msg );
  281. }
  282. return NULL;
  283. }
  284. SetStatusText( wxEmptyString );
  285. return footprint;
  286. }
  287. catch( IO_ERROR ioe )
  288. {
  289. DisplayError( this, ioe.errorText );
  290. return NULL;
  291. }
  292. }
  293. MODULE* PCB_BASE_FRAME::loadFootprintFromLibraries(
  294. const wxString& aFootprintName, bool aDisplayError )
  295. {
  296. bool showed_error = false;
  297. MODULE* footprint = NULL;
  298. try
  299. {
  300. PLUGIN::RELEASER pi( IO_MGR::PluginFind( IO_MGR::LEGACY ) );
  301. for( unsigned ii = 0; ii < g_LibraryNames.GetCount(); ii++ )
  302. {
  303. wxFileName fn = wxFileName( wxEmptyString, g_LibraryNames[ii],
  304. LegacyFootprintLibPathExtension );
  305. wxString libPath = wxGetApp().FindLibraryPath( fn );
  306. if( !libPath )
  307. {
  308. if( aDisplayError && !showed_error )
  309. {
  310. wxString msg = wxString::Format(
  311. _( "PCB footprint library file <%s> not found in search paths." ),
  312. fn.GetFullName().GetData() );
  313. DisplayError( this, msg );
  314. showed_error = true;
  315. }
  316. continue;
  317. }
  318. footprint = pi->FootprintLoad( libPath, aFootprintName );
  319. if( footprint )
  320. {
  321. SetStatusText( wxEmptyString );
  322. return footprint;
  323. }
  324. }
  325. if( !footprint )
  326. {
  327. if( aDisplayError )
  328. {
  329. wxString msg = wxString::Format(
  330. _( "Footprint %s not found in any library." ),
  331. aFootprintName.GetData() );
  332. DisplayError( NULL, msg );
  333. }
  334. return NULL;
  335. }
  336. }
  337. catch( IO_ERROR ioe )
  338. {
  339. DisplayError( this, ioe.errorText );
  340. }
  341. return NULL;
  342. }
  343. MODULE* PCB_BASE_FRAME::loadFootprint( const FPID& aFootprintId )
  344. throw( IO_ERROR, PARSE_ERROR )
  345. {
  346. wxCHECK_MSG( m_footprintLibTable != NULL, NULL,
  347. wxT( "Cannot look up FPID in NULL FP_LIB_TABLE." ) );
  348. wxString nickname = FROM_UTF8( aFootprintId.GetLibNickname().c_str() );
  349. wxString fpname = FROM_UTF8( aFootprintId.GetFootprintName().c_str() );
  350. return m_footprintLibTable->FootprintLoad( nickname, fpname );
  351. }
  352. wxString PCB_BASE_FRAME::SelectFootprint( EDA_DRAW_FRAME* aWindow,
  353. const wxString& aLibraryName,
  354. const wxString& aMask,
  355. const wxString& aKeyWord,
  356. FP_LIB_TABLE* aTable )
  357. {
  358. static wxString OldName; // Save the name of the last module loaded.
  359. wxString CmpName;
  360. wxString msg;
  361. wxArrayString libraries;
  362. FP_LIB_TABLE libTable;
  363. std::vector< wxArrayString > rows;
  364. #if !defined( USE_FP_LIB_TABLE )
  365. if( aLibraryName.IsEmpty() )
  366. {
  367. libraries = g_LibraryNames;
  368. }
  369. else
  370. {
  371. libraries.Add( aLibraryName );
  372. }
  373. if( libraries.IsEmpty() )
  374. {
  375. DisplayError( aWindow, _( "No footprint libraries were specified." ) );
  376. return wxEmptyString;
  377. }
  378. MList.ReadFootprintFiles( libraries );
  379. #else
  380. wxASSERT( aTable != NULL );
  381. if( !MList.ReadFootprintFiles( aTable, !aLibraryName ? NULL : &aLibraryName ) )
  382. {
  383. msg.Format( _( "Error occurred attempting to load footprint library <%s>:\n\n" ),
  384. GetChars( aLibraryName ) );
  385. if( !MList.m_filesNotFound.IsEmpty() )
  386. msg += _( "Files not found:\n\n" ) + MList.m_filesNotFound;
  387. if( !MList.m_filesInvalid.IsEmpty() )
  388. msg += _("\n\nFile load errors:\n\n" ) + MList.m_filesInvalid;
  389. DisplayError( this, msg );
  390. return wxEmptyString;
  391. }
  392. #endif
  393. if( MList.GetCount() == 0 )
  394. {
  395. wxString tmp;
  396. for( unsigned i = 0; i < libraries.GetCount(); i++ )
  397. {
  398. tmp += libraries[i] + wxT( "\n" );
  399. }
  400. msg.Printf( _( "No footprints could be read from library file(s):\n\n%s\nin any of "
  401. "the library search paths. Verify your system is configured properly "
  402. "so the footprint libraries can be found." ), GetChars( tmp ) );
  403. DisplayError( aWindow, msg );
  404. return wxEmptyString;
  405. }
  406. if( !aKeyWord.IsEmpty() ) // Create a list of modules found by keyword.
  407. {
  408. for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
  409. {
  410. if( KeyWordOk( aKeyWord, MList.GetItem( ii ).m_KeyWord ) )
  411. {
  412. wxArrayString cols;
  413. cols.Add( MList.GetItem( ii ).GetFootprintName() );
  414. cols.Add( MList.GetItem( ii ).GetLibraryName() );
  415. rows.push_back( cols );
  416. }
  417. }
  418. }
  419. else if( !aMask.IsEmpty() ) // Create a list of modules found by pattern
  420. {
  421. for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
  422. {
  423. wxString& candidate = MList.GetItem( ii ).m_Module;
  424. if( WildCompareString( aMask, candidate, false ) )
  425. {
  426. wxArrayString cols;
  427. cols.Add( MList.GetItem( ii ).GetFootprintName() );
  428. cols.Add( MList.GetItem( ii ).GetLibraryName() );
  429. rows.push_back( cols );
  430. }
  431. }
  432. }
  433. else // Create the full list of modules
  434. {
  435. for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
  436. {
  437. wxArrayString cols;
  438. cols.Add( MList.GetItem( ii ).GetFootprintName() );
  439. cols.Add( MList.GetItem( ii ).GetLibraryName() );
  440. rows.push_back( cols );
  441. }
  442. }
  443. if( !rows.empty() )
  444. {
  445. wxArrayString headers;
  446. headers.Add( _( "Module" ) );
  447. headers.Add( _( "Library" ) );
  448. msg.Printf( _( "Modules [%d items]" ), (int) rows.size() );
  449. EDA_LIST_DIALOG dlg( aWindow, msg, headers, rows, OldName, DisplayCmpDoc );
  450. if( dlg.ShowModal() == wxID_OK )
  451. {
  452. CmpName = dlg.GetTextSelection();
  453. #if defined( USE_FP_LIB_TABLE )
  454. CmpName = dlg.GetTextSelection( 1 ) + wxT( ":" ) + CmpName;
  455. #endif
  456. SkipNextLeftButtonReleaseEvent();
  457. }
  458. else
  459. CmpName.Empty();
  460. }
  461. else
  462. {
  463. DisplayError( aWindow, _( "No footprint found." ) );
  464. CmpName.Empty();
  465. }
  466. if( CmpName != wxEmptyString )
  467. OldName = CmpName;
  468. wxLogDebug( wxT( "Footprint <%s> was selected." ), GetChars( CmpName ) );
  469. return CmpName;
  470. }
  471. static void DisplayCmpDoc( wxString& Name )
  472. {
  473. FOOTPRINT_INFO* module_info = MList.GetModuleInfo( Name );
  474. if( !module_info )
  475. {
  476. Name.Empty();
  477. return;
  478. }
  479. Name = _( "Description: " ) + module_info->m_Doc;
  480. Name += _( "\nKey words: " ) + module_info->m_KeyWord;
  481. }
  482. MODULE* FOOTPRINT_EDIT_FRAME::SelectFootprint( BOARD* aPcb )
  483. {
  484. MODULE* module;
  485. static wxString OldName; // Save name of last module selected.
  486. wxString CmpName, msg;
  487. wxArrayString listnames;
  488. module = aPcb->m_Modules;
  489. for( ; module != NULL; module = (MODULE*) module->Next() )
  490. listnames.Add( module->GetReference() );
  491. msg.Printf( _( "Modules [%d items]" ), listnames.GetCount() );
  492. wxArrayString headers;
  493. headers.Add( _( "Module" ) );
  494. std::vector<wxArrayString> itemsToDisplay;
  495. // Conversion from wxArrayString to vector of ArrayString
  496. for( unsigned i = 0; i < listnames.GetCount(); i++ )
  497. {
  498. wxArrayString item;
  499. item.Add( listnames[i] );
  500. itemsToDisplay.push_back( item );
  501. }
  502. EDA_LIST_DIALOG dlg( this, msg, headers, itemsToDisplay, wxEmptyString, NULL, SORT_LIST );
  503. if( dlg.ShowModal() == wxID_OK )
  504. CmpName = dlg.GetTextSelection();
  505. else
  506. return NULL;
  507. OldName = CmpName;
  508. module = aPcb->m_Modules;
  509. for( ; module != NULL; module = (MODULE*) module->Next() )
  510. {
  511. if( CmpName == module->GetReference() )
  512. break;
  513. }
  514. return module;
  515. }
  516. void FOOTPRINT_EDIT_FRAME::OnSaveLibraryAs( wxCommandEvent& aEvent )
  517. {
  518. wxString curLibPath = getLibPath();
  519. wxString dstLibPath = CreateNewLibrary();
  520. if( !dstLibPath )
  521. return; // user aborted in CreateNewLibrary()
  522. IO_MGR::PCB_FILE_T dstType = IO_MGR::GuessPluginTypeFromLibPath( dstLibPath );
  523. IO_MGR::PCB_FILE_T curType = IO_MGR::GuessPluginTypeFromLibPath( curLibPath );
  524. try
  525. {
  526. PLUGIN::RELEASER cur( IO_MGR::PluginFind( curType ) );
  527. PLUGIN::RELEASER dst( IO_MGR::PluginFind( dstType ) );
  528. wxArrayString mods = cur->FootprintEnumerate( curLibPath );
  529. for( unsigned i = 0; i < mods.size(); ++i )
  530. {
  531. std::auto_ptr<MODULE> m( cur->FootprintLoad( curLibPath, mods[i] ) );
  532. dst->FootprintSave( dstLibPath, m.get() );
  533. // m is deleted here by auto_ptr.
  534. }
  535. }
  536. catch( IO_ERROR ioe )
  537. {
  538. DisplayError( this, ioe.errorText );
  539. return;
  540. }
  541. wxString msg = wxString::Format(
  542. _( "Footprint library <%s> saved as <%s>." ),
  543. GetChars( curLibPath ), GetChars( dstLibPath ) );
  544. DisplayInfoMessage( this, msg );
  545. }