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.

736 lines
20 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2013 Jean-Pierre Charras, jp.charras at wanadoo.fr
  5. * Copyright (C) 2008-2013 Wayne Stambaugh <stambaughw@verizon.net>
  6. * Copyright (C) 2004-2013 KiCad Developers, see change_log.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 libedit.cpp
  27. * @brief Eeschema component library editor.
  28. */
  29. #include <fctsys.h>
  30. #include <gr_basic.h>
  31. #include <macros.h>
  32. #include <appl_wxstruct.h>
  33. #include <class_drawpanel.h>
  34. #include <confirm.h>
  35. #include <gestfich.h>
  36. #include <class_sch_screen.h>
  37. #include <eeschema_id.h>
  38. #include <general.h>
  39. #include <protos.h>
  40. #include <libeditframe.h>
  41. #include <class_library.h>
  42. #include <template_fieldnames.h>
  43. #include <wildcards_and_files_ext.h>
  44. #include <dialogs/dialog_lib_new_component.h>
  45. void LIB_EDIT_FRAME::DisplayLibInfos()
  46. {
  47. wxString msg = _( "Component Library Editor: " );
  48. EnsureActiveLibExists();
  49. if( m_library )
  50. {
  51. msg += m_library->GetFullFileName();
  52. if( m_library->IsReadOnly() )
  53. msg += _( " [Read Only]" );
  54. }
  55. else
  56. {
  57. msg += _( "no library selected" );
  58. }
  59. SetTitle( msg );
  60. }
  61. void LIB_EDIT_FRAME::SelectActiveLibrary( CMP_LIBRARY* aLibrary )
  62. {
  63. if( aLibrary == NULL )
  64. aLibrary = SelectLibraryFromList( this );
  65. if( aLibrary )
  66. {
  67. m_library = aLibrary;
  68. }
  69. DisplayLibInfos();
  70. }
  71. bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( LIB_ALIAS* aLibEntry, CMP_LIBRARY* aLibrary )
  72. {
  73. if( GetScreen()->IsModify()
  74. && !IsOK( this, _( "The current component is not saved.\n\nDiscard current changes?" ) ) )
  75. return false;
  76. SelectActiveLibrary( aLibrary );
  77. return LoadComponentFromCurrentLib( aLibEntry );
  78. }
  79. bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( LIB_ALIAS* aLibEntry )
  80. {
  81. if( !LoadOneLibraryPartAux( aLibEntry, m_library ) )
  82. return false;
  83. m_editPinsPerPartOrConvert = m_component->UnitsLocked() ? true : false;
  84. GetScreen()->ClearUndoRedoList();
  85. Zoom_Automatique( false );
  86. SetShowDeMorgan( m_component->HasConversion() );
  87. return true;
  88. }
  89. void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
  90. {
  91. wxString msg;
  92. wxString CmpName;
  93. LIB_ALIAS* libEntry = NULL;
  94. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  95. if( GetScreen()->IsModify()
  96. && !IsOK( this, _( "Current component is not saved.\n\nDiscard current changes?" ) ) )
  97. return;
  98. // No current lib, ask user for the library to use.
  99. if( m_library == NULL )
  100. {
  101. SelectActiveLibrary();
  102. if( m_library == NULL )
  103. return;
  104. }
  105. wxArrayString historyList;
  106. CmpName = SelectComponentFromLibrary( m_library->GetName(), historyList, true, NULL, NULL );
  107. if( CmpName.IsEmpty() )
  108. return;
  109. GetScreen()->ClrModify();
  110. m_lastDrawItem = m_drawItem = NULL;
  111. // Delete previous library component, if any
  112. if( m_component )
  113. {
  114. delete m_component;
  115. m_component = NULL;
  116. m_aliasName.Empty();
  117. }
  118. /* Load the new library component */
  119. libEntry = m_library->FindEntry( CmpName );
  120. CMP_LIBRARY* searchLib = m_library;
  121. if( libEntry == NULL )
  122. { // Not found in the active library: search inside the full list
  123. // (can happen when using Viewlib to load a component)
  124. libEntry = CMP_LIBRARY::FindLibraryEntry( CmpName );
  125. if( libEntry )
  126. {
  127. searchLib = libEntry->GetLibrary();
  128. // The entry to load is not in the active lib
  129. // Ask for a new active lib
  130. wxString msg;
  131. msg << _("The selected component is not in the active library");
  132. msg << wxT("\n\n");
  133. msg << _("Do you want to change the active library?");
  134. if( IsOK( this, msg ) )
  135. SelectActiveLibrary( searchLib );
  136. }
  137. }
  138. if( libEntry == NULL )
  139. {
  140. msg.Printf( _( "Component name %s not found in library %s" ),
  141. GetChars( CmpName ),
  142. GetChars( searchLib->GetName() ) );
  143. DisplayError( this, msg );
  144. return;
  145. }
  146. EXCHG( searchLib, m_library );
  147. LoadComponentFromCurrentLib( libEntry );
  148. EXCHG( searchLib, m_library );
  149. DisplayLibInfos();
  150. }
  151. bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, CMP_LIBRARY* aLibrary )
  152. {
  153. wxString msg, cmpName, rootName;
  154. LIB_COMPONENT* component;
  155. if( ( aEntry == NULL ) || ( aLibrary == NULL ) )
  156. return false;
  157. if( aEntry->GetName().IsEmpty() )
  158. {
  159. wxLogWarning( wxT( "Entry in library <%s> has empty name field." ),
  160. GetChars( aLibrary->GetName() ) );
  161. return false;
  162. }
  163. cmpName = m_aliasName = aEntry->GetName();
  164. LIB_ALIAS* alias = (LIB_ALIAS*) aEntry;
  165. component = alias->GetComponent();
  166. wxASSERT( component != NULL );
  167. wxLogDebug( wxT( "\"<%s>\" is alias of \"<%s>\"" ),
  168. GetChars( cmpName ),
  169. GetChars( component->GetName() ) );
  170. if( m_component )
  171. {
  172. delete m_component;
  173. m_aliasName.Empty();
  174. }
  175. m_component = new LIB_COMPONENT( *component );
  176. if( m_component == NULL )
  177. {
  178. msg.Printf( _( "Could not create copy of component <%s> in library <%s>." ),
  179. GetChars( aEntry->GetName() ),
  180. GetChars( aLibrary->GetName() ) );
  181. DisplayError( this, msg );
  182. return false;
  183. }
  184. m_aliasName = aEntry->GetName();
  185. m_unit = 1;
  186. m_convert = 1;
  187. m_showDeMorgan = false;
  188. if( m_component->HasConversion() )
  189. m_showDeMorgan = true;
  190. GetScreen()->ClrModify();
  191. DisplayLibInfos();
  192. UpdateAliasSelectList();
  193. UpdatePartSelectList();
  194. /* Display the document information based on the entry selected just in
  195. * case the entry is an alias. */
  196. DisplayCmpDoc();
  197. return true;
  198. }
  199. void LIB_EDIT_FRAME::RedrawComponent( wxDC* aDC, wxPoint aOffset )
  200. {
  201. if( m_component )
  202. {
  203. // display reference like in schematic (a reference U is shown U? or U?A)
  204. // although it is stored without ? and part id.
  205. // So temporary change the reference by a schematic like reference
  206. LIB_FIELD* field = m_component->GetField( REFERENCE );
  207. wxString fieldText = field->GetText();
  208. wxString fieldfullText = field->GetFullText( m_unit );
  209. field->EDA_TEXT::SetText( fieldfullText ); // change the field text string only
  210. m_component->Draw( m_canvas, aDC, aOffset, m_unit, m_convert, GR_DEFAULT_DRAWMODE );
  211. field->EDA_TEXT::SetText( fieldText ); // restore the field text string
  212. }
  213. }
  214. void LIB_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
  215. {
  216. if( GetScreen() == NULL )
  217. return;
  218. m_canvas->DrawBackGround( DC );
  219. RedrawComponent( DC, wxPoint( 0, 0 ) );
  220. if( m_canvas->IsMouseCaptured() )
  221. m_canvas->CallMouseCapture( DC, wxDefaultPosition, false );
  222. m_canvas->DrawCrossHair( DC );
  223. DisplayLibInfos();
  224. UpdateStatusBar();
  225. }
  226. void LIB_EDIT_FRAME::OnSaveActiveLibrary( wxCommandEvent& event )
  227. {
  228. bool newFile = false;
  229. if( event.GetId() == ID_LIBEDIT_SAVE_CURRENT_LIB_AS )
  230. newFile = true;
  231. this->SaveActiveLibrary( newFile );
  232. }
  233. bool LIB_EDIT_FRAME::SaveActiveLibrary( bool newFile )
  234. {
  235. wxFileName fn;
  236. wxString msg;
  237. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  238. if( m_library == NULL )
  239. {
  240. DisplayError( this, _( "No library specified." ) );
  241. return false;
  242. }
  243. if( GetScreen()->IsModify() )
  244. {
  245. if( IsOK( this, _( "Include last component changes?" ) ) )
  246. SaveOnePartInMemory();
  247. }
  248. if( newFile )
  249. { // Get a new name for the library
  250. wxString default_path = wxGetApp().ReturnLastVisitedLibraryPath();
  251. wxFileDialog dlg( this, _( "Component Library Name:" ), default_path,
  252. wxEmptyString, SchematicLibraryFileExtension,
  253. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  254. if( dlg.ShowModal() == wxID_CANCEL )
  255. return false;
  256. fn = dlg.GetPath();
  257. /* The GTK file chooser doesn't return the file extension added to
  258. * file name so add it here. */
  259. if( fn.GetExt().IsEmpty() )
  260. fn.SetExt( SchematicLibraryFileExtension );
  261. wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() );
  262. }
  263. else
  264. {
  265. fn = wxFileName( m_library->GetFullFileName() );
  266. msg.Printf( _( "Modify library file <%s> ?" ),
  267. GetChars( fn.GetFullPath() ) );
  268. if( !IsOK( this, msg ) )
  269. return false;
  270. }
  271. // Verify the user has write privileges before attempting to save the library file.
  272. if( !IsWritable( fn ) )
  273. return false;
  274. ClearMsgPanel();
  275. wxFileName libFileName = fn;
  276. wxFileName backupFileName = fn;
  277. // Rename the old .lib file to .bak.
  278. if( libFileName.FileExists() )
  279. {
  280. backupFileName.SetExt( wxT( "bak" ) );
  281. if( backupFileName.FileExists() )
  282. wxRemoveFile( backupFileName.GetFullPath() );
  283. if( !wxRenameFile( libFileName.GetFullPath(), backupFileName.GetFullPath() ) )
  284. {
  285. libFileName.MakeAbsolute();
  286. msg = wxT( "Failed to rename old component library file " ) +
  287. backupFileName.GetFullPath();
  288. DisplayError( this, msg );
  289. }
  290. }
  291. try
  292. {
  293. FILE_OUTPUTFORMATTER libFormatter( libFileName.GetFullPath() );
  294. if( !m_library->Save( libFormatter ) )
  295. {
  296. msg.Printf( _( "Error occurred while saving library file <%s>" ),
  297. GetChars( fn.GetFullPath() ) );
  298. AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
  299. DisplayError( this, msg );
  300. return false;
  301. }
  302. }
  303. catch( ... /* IO_ERROR ioe */ )
  304. {
  305. libFileName.MakeAbsolute();
  306. msg.Printf( _( "Failed to create component library file <%s>" ),
  307. GetChars( libFileName.GetFullPath() ) );
  308. DisplayError( this, msg );
  309. return false;
  310. }
  311. wxFileName docFileName = libFileName;
  312. docFileName.SetExt( DOC_EXT );
  313. // Rename .doc file to .bck.
  314. if( docFileName.FileExists() )
  315. {
  316. backupFileName.SetExt( wxT( "bck" ) );
  317. if( backupFileName.FileExists() )
  318. wxRemoveFile( backupFileName.GetFullPath() );
  319. if( !wxRenameFile( docFileName.GetFullPath(), backupFileName.GetFullPath() ) )
  320. {
  321. msg = wxT( "Failed to save old library document file " ) +
  322. backupFileName.GetFullPath();
  323. DisplayError( this, msg );
  324. }
  325. }
  326. try
  327. {
  328. FILE_OUTPUTFORMATTER docFormatter( docFileName.GetFullPath() );
  329. if( !m_library->SaveDocs( docFormatter ) )
  330. {
  331. msg.Printf( _( "Error occurred while saving library documentation file <%s>" ),
  332. GetChars( docFileName.GetFullPath() ) );
  333. AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
  334. DisplayError( this, msg );
  335. return false;
  336. }
  337. }
  338. catch( ... /* IO_ERROR ioe */ )
  339. {
  340. docFileName.MakeAbsolute();
  341. msg.Printf( _( "Failed to create component document library file <%s>" ),
  342. GetChars( docFileName.GetFullPath() ) );
  343. DisplayError( this, msg );
  344. return false;
  345. }
  346. msg.Printf( _( "Library file <%s> OK" ), GetChars( fn.GetFullName() ) );
  347. fn.SetExt( DOC_EXT );
  348. wxString msg1;
  349. msg1.Printf( _( "Documentation file <%s> OK" ), GetChars( fn.GetFullPath() ) );
  350. AppendMsgPanel( msg, msg1, BLUE );
  351. return true;
  352. }
  353. void LIB_EDIT_FRAME::DisplayCmpDoc()
  354. {
  355. wxString msg;
  356. LIB_ALIAS* alias;
  357. ClearMsgPanel();
  358. if( m_library == NULL || m_component == NULL )
  359. return;
  360. msg = m_component->GetName();
  361. AppendMsgPanel( _( "Name" ), msg, BLUE, 8 );
  362. if( m_aliasName == m_component->GetName() )
  363. msg = _( "None" );
  364. else
  365. msg = m_aliasName;
  366. alias = m_component->GetAlias( m_aliasName );
  367. wxCHECK_RET( alias != NULL, wxT( "Alias not found in component." ) );
  368. AppendMsgPanel( _( "Alias" ), msg, RED, 8 );
  369. static wxChar UnitLetter[] = wxT( "?ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
  370. msg = UnitLetter[m_unit];
  371. AppendMsgPanel( _( "Unit" ), msg, BROWN, 8 );
  372. if( m_convert > 1 )
  373. msg = _( "Convert" );
  374. else
  375. msg = _( "Normal" );
  376. AppendMsgPanel( _( "Body" ), msg, GREEN, 8 );
  377. if( m_component->IsPower() )
  378. msg = _( "Power Symbol" );
  379. else
  380. msg = _( "Component" );
  381. AppendMsgPanel( _( "Type" ), msg, MAGENTA, 8 );
  382. AppendMsgPanel( _( "Description" ), alias->GetDescription(), CYAN, 8 );
  383. AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY );
  384. AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY );
  385. }
  386. void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
  387. {
  388. wxString CmpName;
  389. LIB_ALIAS* LibEntry;
  390. wxArrayString ListNames;
  391. wxString msg;
  392. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  393. m_lastDrawItem = NULL;
  394. m_drawItem = NULL;
  395. if( m_library == NULL )
  396. {
  397. SelectActiveLibrary();
  398. if( m_library == NULL )
  399. {
  400. DisplayError( this, _( "Please select a component library." ) );
  401. return;
  402. }
  403. }
  404. m_library->GetEntryNames( ListNames );
  405. if( ListNames.IsEmpty() )
  406. {
  407. msg.Printf( _( "Component library <%s> is empty." ), GetChars( m_library->GetName() ) );
  408. wxMessageBox( msg, _( "Delete Entry Error" ), wxID_OK | wxICON_EXCLAMATION, this );
  409. return;
  410. }
  411. msg.Printf( _( "Select 1 of %d components to delete\nfrom library <%s>." ),
  412. ListNames.GetCount(),
  413. GetChars( m_library->GetName() ) );
  414. wxSingleChoiceDialog dlg( this, msg, _( "Delete Component" ), ListNames );
  415. if( dlg.ShowModal() == wxID_CANCEL || dlg.GetStringSelection().IsEmpty() )
  416. return;
  417. LibEntry = m_library->FindEntry( dlg.GetStringSelection() );
  418. if( LibEntry == NULL )
  419. {
  420. msg.Printf( _( "Entry <%s> not found in library <%s>." ),
  421. GetChars( dlg.GetStringSelection() ),
  422. GetChars( m_library->GetName() ) );
  423. DisplayError( this, msg );
  424. return;
  425. }
  426. msg.Printf( _( "Delete component %s from library %s?" ),
  427. GetChars( LibEntry->GetName() ),
  428. GetChars( m_library->GetName() ) );
  429. if( !IsOK( this, msg ) )
  430. return;
  431. if( m_component == NULL || !m_component->HasAlias( LibEntry->GetName() ) )
  432. {
  433. m_library->RemoveEntry( LibEntry );
  434. return;
  435. }
  436. /* If deleting the current entry or removing one of the aliases for
  437. * the current entry, sync the changes in the current entry as well.
  438. */
  439. if( GetScreen()->IsModify()
  440. && !IsOK( this, _( "The component being deleted has been modified. \
  441. All changes will be lost. Discard changes?" ) ) )
  442. return;
  443. LIB_ALIAS* nextEntry = m_library->RemoveEntry( LibEntry );
  444. if( nextEntry != NULL )
  445. {
  446. if( LoadOneLibraryPartAux( nextEntry, m_library ) )
  447. Zoom_Automatique( false );
  448. }
  449. else
  450. {
  451. delete m_component;
  452. m_component = NULL;
  453. m_aliasName.Empty();
  454. }
  455. m_canvas->Refresh();
  456. }
  457. void LIB_EDIT_FRAME::CreateNewLibraryPart( wxCommandEvent& event )
  458. {
  459. wxString name;
  460. if( m_component && GetScreen()->IsModify()
  461. && !IsOK( this, _( "All changes to the current component will be \
  462. lost!\n\nClear the current component from the screen?" ) ) )
  463. return;
  464. m_canvas->EndMouseCapture( ID_NO_TOOL_SELECTED, m_canvas->GetDefaultCursor() );
  465. m_drawItem = NULL;
  466. DIALOG_LIB_NEW_COMPONENT dlg( this );
  467. dlg.SetMinSize( dlg.GetSize() );
  468. if( dlg.ShowModal() == wxID_CANCEL )
  469. return;
  470. if( dlg.GetName().IsEmpty() )
  471. {
  472. wxMessageBox( _( "This new component has no name and cannot be created. Aborted" ) );
  473. return;
  474. }
  475. #ifndef KICAD_KEEPCASE
  476. name = dlg.GetName().MakeUpper();
  477. #else
  478. name = dlg.GetName();
  479. #endif
  480. name.Replace( wxT( " " ), wxT( "_" ) );
  481. /* Test if there a component with this name already. */
  482. if( m_library && m_library->FindEntry( name ) )
  483. {
  484. wxString msg;
  485. msg.Printf( _( "Component %s already exists in library %s" ),
  486. GetChars( name ),
  487. GetChars( m_library->GetName() ) );
  488. DisplayError( this, msg );
  489. return;
  490. }
  491. LIB_COMPONENT* component = new LIB_COMPONENT( name );
  492. component->GetReferenceField().SetText( dlg.GetReference() );
  493. component->SetPartCount( dlg.GetPartCount() );
  494. // Initialize component->m_TextInside member:
  495. // if 0, pin text is outside the body (on the pin)
  496. // if > 0, pin text is inside the body
  497. component->SetConversion( dlg.GetAlternateBodyStyle() );
  498. SetShowDeMorgan( dlg.GetAlternateBodyStyle() );
  499. if( dlg.GetPinNameInside() )
  500. {
  501. component->SetPinNameOffset( dlg.GetPinTextPosition() );
  502. if( component->GetPinNameOffset() == 0 )
  503. component->SetPinNameOffset( 1 );
  504. }
  505. else
  506. {
  507. component->SetPinNameOffset( 0 );
  508. }
  509. ( dlg.GetPowerSymbol() ) ? component->SetPower() : component->SetNormal();
  510. component->SetShowPinNumbers( dlg.GetShowPinNumber() );
  511. component->SetShowPinNames( dlg.GetShowPinName() );
  512. component->LockUnits( dlg.GetLockItems() );
  513. if( dlg.GetPartCount() < 2 )
  514. component->LockUnits( false );
  515. m_aliasName = component->GetName();
  516. if( m_component )
  517. {
  518. delete m_component;
  519. m_aliasName.Empty();
  520. }
  521. m_component = component;
  522. m_aliasName = m_component->GetName();
  523. m_unit = 1;
  524. m_convert = 1;
  525. DisplayLibInfos();
  526. DisplayCmpDoc();
  527. UpdateAliasSelectList();
  528. UpdatePartSelectList();
  529. m_editPinsPerPartOrConvert = m_component->UnitsLocked() ? true : false;
  530. m_lastDrawItem = NULL;
  531. GetScreen()->ClearUndoRedoList();
  532. OnModify();
  533. m_canvas->Refresh();
  534. m_mainToolBar->Refresh();
  535. }
  536. void LIB_EDIT_FRAME::SaveOnePartInMemory()
  537. {
  538. LIB_COMPONENT* oldComponent;
  539. LIB_COMPONENT* component;
  540. wxString msg;
  541. if( m_component == NULL )
  542. {
  543. DisplayError( this, _( "No component to save." ) );
  544. return;
  545. }
  546. if( m_library == NULL )
  547. SelectActiveLibrary();
  548. if( m_library == NULL )
  549. {
  550. DisplayError( this, _( "No library specified." ) );
  551. return;
  552. }
  553. GetScreen()->ClrModify();
  554. oldComponent = m_library->FindComponent( m_component->GetName() );
  555. if( oldComponent != NULL )
  556. {
  557. msg.Printf( _( "Component %s already exists. Change it?" ),
  558. GetChars( m_component->GetName() ) );
  559. if( !IsOK( this, msg ) )
  560. return;
  561. }
  562. m_drawItem = m_lastDrawItem = NULL;
  563. if( oldComponent != NULL )
  564. component = m_library->ReplaceComponent( oldComponent, m_component );
  565. else
  566. component = m_library->AddComponent( m_component );
  567. if( component == NULL )
  568. return;
  569. msg.Printf( _( "Component %s saved in library %s" ),
  570. GetChars( component->GetName() ),
  571. GetChars( m_library->GetName() ) );
  572. SetStatusText( msg );
  573. }