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.

600 lines
15 KiB

16 years ago
  1. /**
  2. * @file libedit.cpp
  3. * @brief Eeschema component library editor.
  4. */
  5. #include "fctsys.h"
  6. #include "gr_basic.h"
  7. #include "macros.h"
  8. #include "appl_wxstruct.h"
  9. #include "class_drawpanel.h"
  10. #include "confirm.h"
  11. #include "gestfich.h"
  12. #include "class_sch_screen.h"
  13. #include "eeschema_id.h"
  14. #include "general.h"
  15. #include "protos.h"
  16. #include "libeditframe.h"
  17. #include "class_library.h"
  18. #include "template_fieldnames.h"
  19. #include "dialogs/dialog_lib_new_component.h"
  20. void LIB_EDIT_FRAME::DisplayLibInfos()
  21. {
  22. wxString msg = _( "Component Library Editor: " );
  23. EnsureActiveLibExists();
  24. if( m_library )
  25. {
  26. msg += m_library->GetFullFileName();
  27. if( m_library->IsReadOnly() )
  28. msg += _( " [Read Only]" );
  29. }
  30. else
  31. {
  32. msg += _( "no library selected" );
  33. }
  34. SetTitle( msg );
  35. }
  36. void LIB_EDIT_FRAME::SelectActiveLibrary( CMP_LIBRARY* aLibrary )
  37. {
  38. if( aLibrary == NULL )
  39. aLibrary = SelectLibraryFromList( this );
  40. if( aLibrary )
  41. {
  42. m_library = aLibrary;
  43. }
  44. DisplayLibInfos();
  45. }
  46. bool LIB_EDIT_FRAME::LoadComponentAndSelectLib( LIB_ALIAS* aLibEntry, CMP_LIBRARY* aLibrary )
  47. {
  48. if( GetScreen()->IsModify()
  49. && !IsOK( this, _( "Current part not saved.\n\nDiscard current changes?" ) ) )
  50. return false;
  51. SelectActiveLibrary( aLibrary );
  52. return LoadComponentFromCurrentLib( aLibEntry );
  53. }
  54. bool LIB_EDIT_FRAME::LoadComponentFromCurrentLib( LIB_ALIAS* aLibEntry )
  55. {
  56. if( !LoadOneLibraryPartAux( aLibEntry, m_library ) )
  57. return false;
  58. g_EditPinByPinIsOn = m_component->UnitsLocked() ? true : false;
  59. m_HToolBar->ToggleTool( ID_LIBEDIT_EDIT_PIN_BY_PIN, g_EditPinByPinIsOn );
  60. GetScreen()->ClearUndoRedoList();
  61. Zoom_Automatique( false );
  62. DrawPanel->Refresh();
  63. SetShowDeMorgan( m_component->HasConversion() );
  64. m_HToolBar->Refresh();
  65. return true;
  66. }
  67. void LIB_EDIT_FRAME::LoadOneLibraryPart( wxCommandEvent& event )
  68. {
  69. int i;
  70. wxString msg;
  71. wxString CmpName;
  72. LIB_ALIAS* LibEntry = NULL;
  73. DrawPanel->EndMouseCapture( ID_NO_TOOL_SELECTED, DrawPanel->GetDefaultCursor() );
  74. if( GetScreen()->IsModify()
  75. && !IsOK( this, _( "Current part not saved.\n\nDiscard current changes?" ) ) )
  76. return;
  77. // No current lib, ask user for the library to use.
  78. if( m_library == NULL )
  79. {
  80. SelectActiveLibrary();
  81. if( m_library == NULL )
  82. return;
  83. }
  84. i = GetNameOfPartToLoad( this, m_library, CmpName );
  85. if( i == 0 )
  86. return;
  87. GetScreen()->ClrModify();
  88. m_lastDrawItem = m_drawItem = NULL;
  89. // Delete previous library component, if any
  90. if( m_component )
  91. {
  92. SAFE_DELETE( m_component );
  93. m_aliasName.Empty();
  94. }
  95. /* Load the new library component */
  96. LibEntry = m_library->FindEntry( CmpName );
  97. if( LibEntry == NULL )
  98. {
  99. msg.Printf( _( "Component name \"%s\" not found in library \"%s\"." ),
  100. GetChars( CmpName ),
  101. GetChars( m_library->GetName() ) );
  102. DisplayError( this, msg );
  103. return;
  104. }
  105. if( ! LoadComponentFromCurrentLib( LibEntry ) )
  106. return;
  107. }
  108. bool LIB_EDIT_FRAME::LoadOneLibraryPartAux( LIB_ALIAS* aEntry, CMP_LIBRARY* aLibrary )
  109. {
  110. wxString msg, cmpName, rootName;
  111. LIB_COMPONENT* component;
  112. if( ( aEntry == NULL ) || ( aLibrary == NULL ) )
  113. return false;
  114. if( aEntry->GetName().IsEmpty() )
  115. {
  116. wxLogWarning( wxT( "Entry in library <%s> has empty name field." ),
  117. GetChars( aLibrary->GetName() ) );
  118. return false;
  119. }
  120. cmpName = m_aliasName = aEntry->GetName();
  121. LIB_ALIAS* alias = (LIB_ALIAS*) aEntry;
  122. component = alias->GetComponent();
  123. wxASSERT( component != NULL );
  124. wxLogDebug( wxT( "\"<%s>\" is alias of \"<%s>\"" ),
  125. GetChars( cmpName ),
  126. GetChars( component->GetName() ) );
  127. if( m_component )
  128. {
  129. SAFE_DELETE( m_component );
  130. m_aliasName.Empty();
  131. }
  132. m_component = new LIB_COMPONENT( *component );
  133. if( m_component == NULL )
  134. {
  135. msg.Printf( _( "Could not create copy of part <%s> in library <%s>." ),
  136. GetChars( aEntry->GetName() ),
  137. GetChars( aLibrary->GetName() ) );
  138. DisplayError( this, msg );
  139. return false;
  140. }
  141. m_aliasName = aEntry->GetName();
  142. m_unit = 1;
  143. m_convert = 1;
  144. m_showDeMorgan = false;
  145. if( m_component->HasConversion() )
  146. m_showDeMorgan = true;
  147. GetScreen()->ClrModify();
  148. DisplayLibInfos();
  149. UpdateAliasSelectList();
  150. UpdatePartSelectList();
  151. /* Display the document information based on the entry selected just in
  152. * case the entry is an alias. */
  153. DisplayCmpDoc();
  154. return true;
  155. }
  156. void LIB_EDIT_FRAME::RedrawActiveWindow( wxDC* DC, bool EraseBg )
  157. {
  158. if( GetScreen() == NULL )
  159. return;
  160. DrawPanel->DrawBackGround( DC );
  161. if( m_component )
  162. {
  163. // display reference like in schematic (a reference U is shown U? or U?A)
  164. // although it is stored without ? and part id.
  165. // So temporary change the reference by a schematic like reference
  166. LIB_FIELD* Field = m_component->GetField( REFERENCE );
  167. wxString fieldText = Field->m_Text;
  168. wxString fieldfullText = Field->GetFullText( m_unit );
  169. Field->m_Text = fieldfullText;
  170. m_component->Draw( DrawPanel, DC, wxPoint( 0, 0 ), m_unit,
  171. m_convert, GR_DEFAULT_DRAWMODE );
  172. Field->m_Text = fieldText;
  173. }
  174. if( DrawPanel->IsMouseCaptured() )
  175. DrawPanel->m_mouseCaptureCallback( DrawPanel, DC, wxDefaultPosition, false );
  176. DrawPanel->DrawCrossHair( DC );
  177. DisplayLibInfos();
  178. UpdateStatusBar();
  179. }
  180. void LIB_EDIT_FRAME::SaveActiveLibrary( wxCommandEvent& event )
  181. {
  182. wxFileName fn;
  183. wxString msg;
  184. DrawPanel->EndMouseCapture( ID_NO_TOOL_SELECTED, DrawPanel->GetDefaultCursor() );
  185. if( m_library == NULL )
  186. {
  187. DisplayError( this, _( "No library specified." ) );
  188. return;
  189. }
  190. if( GetScreen()->IsModify() )
  191. {
  192. if( IsOK( this, _( "Include last component changes?" ) ) )
  193. SaveOnePartInMemory();
  194. }
  195. if( event.GetId() == ID_LIBEDIT_SAVE_CURRENT_LIB_AS )
  196. { // Get a new name for the library
  197. wxString default_path = wxGetApp().ReturnLastVisitedLibraryPath();
  198. wxFileDialog dlg( this, _( "Component Library Name:" ), default_path,
  199. wxEmptyString, CompLibFileWildcard,
  200. wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
  201. if( dlg.ShowModal() == wxID_CANCEL )
  202. return;
  203. fn = dlg.GetPath();
  204. /* The GTK file chooser doesn't return the file extension added to
  205. * file name so add it here. */
  206. if( fn.GetExt().IsEmpty() )
  207. fn.SetExt( CompLibFileExtension );
  208. wxGetApp().SaveLastVisitedLibraryPath( fn.GetPath() );
  209. }
  210. else
  211. {
  212. fn = wxFileName( m_library->GetFullFileName() );
  213. msg = _( "Modify library file \"" ) + fn.GetFullPath() + _( "\"?" );
  214. if( !IsOK( this, msg ) )
  215. return;
  216. }
  217. // Verify the user has write privileges before attempting to save the library file.
  218. if( !IsWritable( fn ) )
  219. return;
  220. bool success = m_library->Save( fn.GetFullPath(), true );
  221. ClearMsgPanel();
  222. if( !success )
  223. {
  224. msg = _( "Error while saving library file \"" ) + fn.GetFullPath() + _( "\"." );
  225. AppendMsgPanel( _( "*** ERROR: ***" ), msg, RED );
  226. DisplayError( this, msg );
  227. }
  228. else
  229. {
  230. msg = _( "Library file \"" ) + fn.GetFullName() + wxT( "\" Ok" );
  231. fn.SetExt( DOC_EXT );
  232. wxString msg1 = _( "Document file \"" ) + fn.GetFullPath() + wxT( "\" Ok" );
  233. AppendMsgPanel( msg, msg1, BLUE );
  234. }
  235. }
  236. void LIB_EDIT_FRAME::DisplayCmpDoc()
  237. {
  238. wxString msg;
  239. LIB_ALIAS* alias;
  240. ClearMsgPanel();
  241. if( m_library == NULL || m_component == NULL )
  242. return;
  243. msg = m_component->GetName();
  244. AppendMsgPanel( _( "Part" ), msg, BLUE, 8 );
  245. if( m_aliasName == m_component->GetName() )
  246. msg = _( "None" );
  247. else
  248. msg = m_aliasName;
  249. alias = m_component->GetAlias( m_aliasName );
  250. wxCHECK_RET( alias != NULL, wxT( "Alias not found in component." ) );
  251. AppendMsgPanel( _( "Alias" ), msg, RED, 8 );
  252. static wxChar UnitLetter[] = wxT( "?ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
  253. msg = UnitLetter[m_unit];
  254. AppendMsgPanel( _( "Unit" ), msg, BROWN, 8 );
  255. if( m_convert > 1 )
  256. msg = _( "Convert" );
  257. else
  258. msg = _( "Normal" );
  259. AppendMsgPanel( _( "Body" ), msg, GREEN, 8 );
  260. if( m_component->IsPower() )
  261. msg = _( "Power Symbol" );
  262. else
  263. msg = _( "Component" );
  264. AppendMsgPanel( _( "Type" ), msg, MAGENTA, 8 );
  265. AppendMsgPanel( _( "Description" ), alias->GetDescription(), CYAN, 8 );
  266. AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY );
  267. AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY );
  268. }
  269. void LIB_EDIT_FRAME::DeleteOnePart( wxCommandEvent& event )
  270. {
  271. wxString CmpName;
  272. LIB_ALIAS* LibEntry;
  273. wxArrayString ListNames;
  274. wxString msg;
  275. DrawPanel->EndMouseCapture( ID_NO_TOOL_SELECTED, DrawPanel->GetDefaultCursor() );
  276. m_lastDrawItem = NULL;
  277. m_drawItem = NULL;
  278. if( m_library == NULL )
  279. {
  280. SelectActiveLibrary();
  281. if( m_library == NULL )
  282. {
  283. DisplayError( this, _( "Please select a component library." ) );
  284. return;
  285. }
  286. }
  287. m_library->GetEntryNames( ListNames );
  288. if( ListNames.IsEmpty() )
  289. {
  290. msg.Printf( _( "Component library <%s> is empty." ), GetChars( m_library->GetName() ) );
  291. wxMessageBox( msg, _( "Delete Entry Error" ), wxID_OK | wxICON_EXCLAMATION, this );
  292. return;
  293. }
  294. msg.Printf( _( "Select 1 of %d components to delete\nfrom library <%s>." ),
  295. ListNames.GetCount(),
  296. GetChars( m_library->GetName() ) );
  297. wxSingleChoiceDialog dlg( this, msg, _( "Delete Component" ), ListNames );
  298. if( dlg.ShowModal() == wxID_CANCEL || dlg.GetStringSelection().IsEmpty() )
  299. return;
  300. LibEntry = m_library->FindEntry( dlg.GetStringSelection() );
  301. if( LibEntry == NULL )
  302. {
  303. msg.Printf( _( "Entry <%s> not found in library <%s>." ),
  304. GetChars( dlg.GetStringSelection() ),
  305. GetChars( m_library->GetName() ) );
  306. DisplayError( this, msg );
  307. return;
  308. }
  309. msg.Printf( _( "Delete component \"%s\" from library \"%s\"?" ),
  310. GetChars( LibEntry->GetName() ),
  311. GetChars( m_library->GetName() ) );
  312. if( !IsOK( this, msg ) )
  313. return;
  314. if( m_component == NULL || !m_component->HasAlias( LibEntry->GetName() ) )
  315. {
  316. m_library->RemoveEntry( LibEntry );
  317. return;
  318. }
  319. /* If deleting the current entry or removing one of the aliases for
  320. * the current entry, sync the changes in the current entry as well.
  321. */
  322. if( GetScreen()->IsModify()
  323. && !IsOK( this, _( "The component being deleted has been modified. \
  324. All changes will be lost. Discard changes?" ) ) )
  325. return;
  326. LIB_ALIAS* nextEntry = m_library->RemoveEntry( LibEntry );
  327. if( nextEntry != NULL )
  328. {
  329. if( LoadOneLibraryPartAux( nextEntry, m_library ) )
  330. Zoom_Automatique( false );
  331. }
  332. else
  333. {
  334. SAFE_DELETE( m_component );
  335. m_aliasName.Empty();
  336. }
  337. DrawPanel->Refresh();
  338. }
  339. void LIB_EDIT_FRAME::CreateNewLibraryPart( wxCommandEvent& event )
  340. {
  341. wxString name;
  342. if( m_component && GetScreen()->IsModify()
  343. && !IsOK( this, _( "All changes to the current component will be \
  344. lost!\n\nClear the current component from the screen?" ) ) )
  345. return;
  346. DrawPanel->EndMouseCapture( ID_NO_TOOL_SELECTED, DrawPanel->GetDefaultCursor() );
  347. m_drawItem = NULL;
  348. DIALOG_LIB_NEW_COMPONENT dlg( this );
  349. dlg.SetMinSize( dlg.GetSize() );
  350. if( dlg.ShowModal() == wxID_CANCEL )
  351. return;
  352. if( dlg.GetName().IsEmpty() )
  353. {
  354. wxMessageBox( _( "This new component has no name and cannot be created. Aborted" ) );
  355. return;
  356. }
  357. #ifndef KICAD_KEEPCASE
  358. name = dlg.GetName().MakeUpper();
  359. #else
  360. name = dlg.GetName();
  361. #endif
  362. name.Replace( wxT( " " ), wxT( "_" ) );
  363. /* Test if there a component with this name already. */
  364. if( m_library && m_library->FindEntry( name ) )
  365. {
  366. wxString msg;
  367. msg.Printf( _( "Component \"%s\" already exists in library \"%s\"." ),
  368. GetChars( name ),
  369. GetChars( m_library->GetName() ) );
  370. DisplayError( this, msg );
  371. return;
  372. }
  373. LIB_COMPONENT* component = new LIB_COMPONENT( name );
  374. component->GetReferenceField().m_Text = dlg.GetReference();
  375. component->SetPartCount( dlg.GetPartCount() );
  376. // Initialize component->m_TextInside member:
  377. // if 0, pin text is outside the body (on the pin)
  378. // if > 0, pin text is inside the body
  379. component->SetConversion( dlg.GetAlternateBodyStyle() );
  380. SetShowDeMorgan( dlg.GetAlternateBodyStyle() );
  381. if( dlg.GetPinNameInside() )
  382. {
  383. component->SetPinNameOffset( dlg.GetPinTextPosition() );
  384. if( component->GetPinNameOffset() == 0 )
  385. component->SetPinNameOffset( 1 );
  386. }
  387. else
  388. {
  389. component->SetPinNameOffset( 0 );
  390. }
  391. ( dlg.GetPowerSymbol() ) ? component->SetPower() : component->SetNormal();
  392. component->SetShowPinNumbers( dlg.GetShowPinNumber() );
  393. component->SetShowPinNames( dlg.GetShowPinName() );
  394. component->LockUnits( dlg.GetLockItems() );
  395. if( dlg.GetPartCount() < 2 )
  396. component->LockUnits( false );
  397. m_aliasName = component->GetName();
  398. if( m_component )
  399. {
  400. SAFE_DELETE( m_component );
  401. m_aliasName.Empty();
  402. }
  403. m_component = component;
  404. m_aliasName = m_component->GetName();
  405. m_unit = 1;
  406. m_convert = 1;
  407. DisplayLibInfos();
  408. DisplayCmpDoc();
  409. UpdateAliasSelectList();
  410. UpdatePartSelectList();
  411. g_EditPinByPinIsOn = m_component->UnitsLocked() ? true : false;
  412. m_HToolBar->ToggleTool( ID_LIBEDIT_EDIT_PIN_BY_PIN, g_EditPinByPinIsOn );
  413. m_lastDrawItem = NULL;
  414. GetScreen()->ClearUndoRedoList();
  415. OnModify();
  416. DrawPanel->Refresh();
  417. m_HToolBar->Refresh();
  418. }
  419. void LIB_EDIT_FRAME::SaveOnePartInMemory()
  420. {
  421. LIB_COMPONENT* oldComponent;
  422. LIB_COMPONENT* Component;
  423. wxString msg;
  424. if( m_component == NULL )
  425. {
  426. DisplayError( this, _( "No component to save." ) );
  427. return;
  428. }
  429. if( m_library == NULL )
  430. SelectActiveLibrary();
  431. if( m_library == NULL )
  432. {
  433. DisplayError( this, _( "No library specified." ) );
  434. return;
  435. }
  436. GetScreen()->ClrModify();
  437. oldComponent = m_library->FindComponent( m_component->GetName() );
  438. if( oldComponent != NULL )
  439. {
  440. msg.Printf( _( "Component \"%s\" already exists. Change it?" ),
  441. GetChars( m_component->GetName() ) );
  442. if( !IsOK( this, msg ) )
  443. return;
  444. }
  445. m_drawItem = m_lastDrawItem = NULL;
  446. if( oldComponent != NULL )
  447. Component = m_library->ReplaceComponent( oldComponent, m_component );
  448. else
  449. Component = m_library->AddComponent( m_component );
  450. if( Component == NULL )
  451. return;
  452. msg.Printf( _( "Component %s saved in library %s" ),
  453. GetChars( Component->GetName() ),
  454. GetChars( m_library->GetName() ) );
  455. SetStatusText( msg );
  456. }