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.

668 lines
20 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018-2021 KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <kiway.h>
  24. #include <kiway_player.h>
  25. #include <dialog_shim.h>
  26. #include <fields_grid_table.h>
  27. #include <sch_base_frame.h>
  28. #include <sch_field.h>
  29. #include <sch_validators.h>
  30. #include <validators.h>
  31. #include <symbol_library.h>
  32. #include <template_fieldnames.h>
  33. #include <widgets/grid_text_button_helpers.h>
  34. #include <wildcards_and_files_ext.h>
  35. #include <project/project_file.h>
  36. #include "eda_doc.h"
  37. #include <wx/settings.h>
  38. #include <kicad_string.h>
  39. enum
  40. {
  41. MYID_SELECT_FOOTPRINT = 991, // must be within GRID_TRICKS' enum range
  42. MYID_SHOW_DATASHEET
  43. };
  44. template <class T>
  45. FIELDS_GRID_TABLE<T>::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame,
  46. WX_GRID* aGrid, LIB_SYMBOL* aSymbol ) :
  47. m_frame( aFrame ),
  48. m_userUnits( aDialog->GetUserUnits() ),
  49. m_grid( aGrid ),
  50. m_parentType( SCH_SYMBOL_T ),
  51. m_mandatoryFieldCount( MANDATORY_FIELDS ),
  52. m_part( aSymbol ),
  53. m_fieldNameValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_NAME ),
  54. m_referenceValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), REFERENCE_FIELD ),
  55. m_valueValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), VALUE_FIELD ),
  56. m_libIdValidator(),
  57. m_urlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  58. m_nonUrlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  59. m_filepathValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), SHEETFILENAME )
  60. {
  61. initGrid( aDialog, aGrid );
  62. }
  63. template <class T>
  64. FIELDS_GRID_TABLE<T>::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame,
  65. WX_GRID* aGrid, SCH_SHEET* aSheet ) :
  66. m_frame( aFrame ),
  67. m_userUnits( aDialog->GetUserUnits() ),
  68. m_grid( aGrid ),
  69. m_parentType( SCH_SHEET_T ),
  70. m_mandatoryFieldCount( SHEET_MANDATORY_FIELDS ),
  71. m_part( nullptr ),
  72. m_fieldNameValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_NAME ),
  73. m_referenceValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), SHEETNAME_V ),
  74. m_valueValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), VALUE_FIELD ),
  75. m_libIdValidator(),
  76. m_urlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  77. m_nonUrlValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), FIELD_VALUE ),
  78. m_filepathValidator( aFrame->IsType( FRAME_SCH_SYMBOL_EDITOR ), SHEETFILENAME_V )
  79. {
  80. initGrid( aDialog, aGrid );
  81. }
  82. template <class T>
  83. void FIELDS_GRID_TABLE<T>::initGrid( DIALOG_SHIM* aDialog, WX_GRID* aGrid )
  84. {
  85. // Build the various grid cell attributes.
  86. // NOTE: validators and cellAttrs are member variables to get the destruction order
  87. // right. wxGrid is VERY cranky about this.
  88. m_readOnlyAttr = new wxGridCellAttr;
  89. m_readOnlyAttr->SetReadOnly( true );
  90. m_fieldNameAttr = new wxGridCellAttr;
  91. GRID_CELL_TEXT_EDITOR* nameEditor = new GRID_CELL_TEXT_EDITOR();
  92. nameEditor->SetValidator( m_fieldNameValidator );
  93. m_fieldNameAttr->SetEditor( nameEditor );
  94. m_referenceAttr = new wxGridCellAttr;
  95. GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
  96. referenceEditor->SetValidator( m_referenceValidator );
  97. m_referenceAttr->SetEditor( referenceEditor );
  98. m_valueAttr = new wxGridCellAttr;
  99. GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
  100. valueEditor->SetValidator( m_valueValidator );
  101. m_valueAttr->SetEditor( valueEditor );
  102. m_footprintAttr = new wxGridCellAttr;
  103. GRID_CELL_FOOTPRINT_ID_EDITOR* fpIdEditor = new GRID_CELL_FOOTPRINT_ID_EDITOR( aDialog );
  104. fpIdEditor->SetValidator( m_libIdValidator );
  105. m_footprintAttr->SetEditor( fpIdEditor );
  106. m_urlAttr = new wxGridCellAttr;
  107. GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( aDialog );
  108. urlEditor->SetValidator( m_urlValidator );
  109. m_urlAttr->SetEditor( urlEditor );
  110. m_nonUrlAttr = new wxGridCellAttr;
  111. GRID_CELL_TEXT_EDITOR* nonUrlEditor = new GRID_CELL_TEXT_EDITOR();
  112. nonUrlEditor->SetValidator( m_nonUrlValidator );
  113. m_nonUrlAttr->SetEditor( nonUrlEditor );
  114. m_curdir = m_frame->Prj().GetProjectPath();
  115. m_filepathAttr = new wxGridCellAttr;
  116. // Create a wild card using wxFileDialog syntax.
  117. wxString wildCard( _( "Schematic Files" ) );
  118. std::vector<std::string> exts;
  119. exts.push_back( KiCadSchematicFileExtension );
  120. wildCard += AddFileExtListToFilter( exts );
  121. auto filepathEditor = new GRID_CELL_PATH_EDITOR( aDialog, aGrid, &m_curdir, wildCard );
  122. filepathEditor->SetValidator( m_filepathValidator );
  123. m_filepathAttr->SetEditor( filepathEditor );
  124. m_boolAttr = new wxGridCellAttr;
  125. m_boolAttr->SetRenderer( new wxGridCellBoolRenderer() );
  126. m_boolAttr->SetEditor( new wxGridCellBoolEditor() );
  127. m_boolAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  128. wxArrayString vAlignNames;
  129. vAlignNames.Add( _( "Top" ) );
  130. vAlignNames.Add( _( "Center" ) );
  131. vAlignNames.Add( _( "Bottom" ) );
  132. m_vAlignAttr = new wxGridCellAttr;
  133. m_vAlignAttr->SetEditor( new wxGridCellChoiceEditor( vAlignNames ) );
  134. m_vAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  135. wxArrayString hAlignNames;
  136. hAlignNames.Add( _( "Left" ) );
  137. hAlignNames.Add(_( "Center" ) );
  138. hAlignNames.Add(_( "Right" ) );
  139. m_hAlignAttr = new wxGridCellAttr;
  140. m_hAlignAttr->SetEditor( new wxGridCellChoiceEditor( hAlignNames ) );
  141. m_hAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  142. wxArrayString orientationNames;
  143. orientationNames.Add( _( "Horizontal" ) );
  144. orientationNames.Add(_( "Vertical" ) );
  145. m_orientationAttr = new wxGridCellAttr;
  146. m_orientationAttr->SetEditor( new wxGridCellChoiceEditor( orientationNames ) );
  147. m_orientationAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  148. }
  149. template <class T>
  150. FIELDS_GRID_TABLE<T>::~FIELDS_GRID_TABLE()
  151. {
  152. m_readOnlyAttr->DecRef();
  153. m_fieldNameAttr->DecRef();
  154. m_boolAttr->DecRef();
  155. m_referenceAttr->DecRef();
  156. m_valueAttr->DecRef();
  157. m_footprintAttr->DecRef();
  158. m_urlAttr->DecRef();
  159. m_nonUrlAttr->DecRef();
  160. m_filepathAttr->DecRef();
  161. m_vAlignAttr->DecRef();
  162. m_hAlignAttr->DecRef();
  163. m_orientationAttr->DecRef();
  164. }
  165. template <class T>
  166. wxString FIELDS_GRID_TABLE<T>::GetColLabelValue( int aCol )
  167. {
  168. switch( aCol )
  169. {
  170. case FDC_NAME: return _( "Name" );
  171. case FDC_VALUE: return _( "Value" );
  172. case FDC_SHOWN: return _( "Show" );
  173. case FDC_H_ALIGN: return _( "H Align" );
  174. case FDC_V_ALIGN: return _( "V Align" );
  175. case FDC_ITALIC: return _( "Italic" );
  176. case FDC_BOLD: return _( "Bold" );
  177. case FDC_TEXT_SIZE: return _( "Text Size" );
  178. case FDC_ORIENTATION: return _( "Orientation" );
  179. case FDC_POSX: return _( "X Position" );
  180. case FDC_POSY: return _( "Y Position" );
  181. default: wxFAIL; return wxEmptyString;
  182. }
  183. }
  184. template <class T>
  185. bool FIELDS_GRID_TABLE<T>::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
  186. {
  187. switch( aCol )
  188. {
  189. case FDC_NAME:
  190. case FDC_VALUE:
  191. case FDC_H_ALIGN:
  192. case FDC_V_ALIGN:
  193. case FDC_TEXT_SIZE:
  194. case FDC_ORIENTATION:
  195. case FDC_POSX:
  196. case FDC_POSY:
  197. return aTypeName == wxGRID_VALUE_STRING;
  198. case FDC_SHOWN:
  199. case FDC_ITALIC:
  200. case FDC_BOLD:
  201. return aTypeName == wxGRID_VALUE_BOOL;
  202. default:
  203. wxFAIL;
  204. return false;
  205. }
  206. }
  207. template <class T>
  208. bool FIELDS_GRID_TABLE<T>::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
  209. {
  210. return CanGetValueAs( aRow, aCol, aTypeName );
  211. }
  212. template <class T>
  213. wxGridCellAttr* FIELDS_GRID_TABLE<T>::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind )
  214. {
  215. wxGridCellAttr* tmp;
  216. switch( aCol )
  217. {
  218. case FDC_NAME:
  219. if( aRow < m_mandatoryFieldCount )
  220. {
  221. tmp = m_fieldNameAttr->Clone();
  222. tmp->SetReadOnly( true );
  223. return tmp;
  224. }
  225. else
  226. {
  227. m_fieldNameAttr->IncRef();
  228. return m_fieldNameAttr;
  229. }
  230. case FDC_VALUE:
  231. if( m_parentType == SCH_SYMBOL_T && aRow == REFERENCE_FIELD )
  232. {
  233. m_referenceAttr->IncRef();
  234. return m_referenceAttr;
  235. }
  236. else if( m_parentType == SCH_SYMBOL_T && aRow == VALUE_FIELD )
  237. {
  238. // For power symbols, the value is not editable, because value and pin name must
  239. // be the same and can be edited only in library editor.
  240. if( ( m_part && m_part->IsPower() && !m_frame->IsType( FRAME_SCH_SYMBOL_EDITOR ) ) )
  241. {
  242. tmp = m_readOnlyAttr->Clone();
  243. tmp->SetReadOnly( true );
  244. tmp->SetTextColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
  245. return tmp;
  246. }
  247. else
  248. {
  249. m_valueAttr->IncRef();
  250. return m_valueAttr;
  251. }
  252. }
  253. else if( m_parentType == SCH_SYMBOL_T && aRow == FOOTPRINT_FIELD )
  254. {
  255. m_footprintAttr->IncRef();
  256. return m_footprintAttr;
  257. }
  258. else if( m_parentType == SCH_SYMBOL_T && aRow == DATASHEET_FIELD )
  259. {
  260. m_urlAttr->IncRef();
  261. return m_urlAttr;
  262. }
  263. else if( m_parentType == SCH_SHEET_T && aRow == SHEETNAME )
  264. {
  265. m_referenceAttr->IncRef();
  266. return m_referenceAttr;
  267. }
  268. else if( m_parentType == SCH_SHEET_T && aRow == SHEETFILENAME )
  269. {
  270. m_filepathAttr->IncRef();
  271. return m_filepathAttr;
  272. }
  273. else
  274. {
  275. wxString fn = GetValue( aRow, FDC_NAME );
  276. SCHEMATIC_SETTINGS* settings = m_frame->Prj().GetProjectFile().m_SchematicSettings;
  277. const TEMPLATE_FIELDNAME* templateFn =
  278. settings ? settings->m_TemplateFieldNames.GetFieldName( fn ) : nullptr;
  279. if( templateFn && templateFn->m_URL )
  280. {
  281. m_urlAttr->IncRef();
  282. return m_urlAttr;
  283. }
  284. else
  285. {
  286. m_nonUrlAttr->IncRef();
  287. return m_nonUrlAttr;
  288. }
  289. }
  290. return nullptr;
  291. case FDC_TEXT_SIZE:
  292. case FDC_POSX:
  293. case FDC_POSY:
  294. return nullptr;
  295. case FDC_H_ALIGN:
  296. m_hAlignAttr->IncRef();
  297. return m_hAlignAttr;
  298. case FDC_V_ALIGN:
  299. m_vAlignAttr->IncRef();
  300. return m_vAlignAttr;
  301. case FDC_ORIENTATION:
  302. m_orientationAttr->IncRef();
  303. return m_orientationAttr;
  304. case FDC_SHOWN:
  305. case FDC_ITALIC:
  306. case FDC_BOLD:
  307. m_boolAttr->IncRef();
  308. return m_boolAttr;
  309. default:
  310. wxFAIL;
  311. return nullptr;
  312. }
  313. }
  314. template <class T>
  315. wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
  316. {
  317. wxCHECK( aRow < GetNumberRows(), wxEmptyString );
  318. const T& field = this->at( (size_t) aRow );
  319. switch( aCol )
  320. {
  321. case FDC_NAME:
  322. // Use default field name for mandatory fields, because they are translated
  323. // according to the current locale
  324. if( aRow < m_mandatoryFieldCount )
  325. {
  326. if( m_parentType == SCH_SYMBOL_T )
  327. return TEMPLATE_FIELDNAME::GetDefaultFieldName( aRow );
  328. else if( m_parentType == SCH_SHEET_T )
  329. return SCH_SHEET::GetDefaultFieldName( aRow );
  330. }
  331. return field.GetName( false );
  332. case FDC_VALUE:
  333. return UnescapeString( field.GetText() );
  334. case FDC_SHOWN:
  335. return StringFromBool( field.IsVisible() );
  336. case FDC_H_ALIGN:
  337. switch ( field.GetHorizJustify() )
  338. {
  339. case GR_TEXT_HJUSTIFY_LEFT: return _( "Left" );
  340. case GR_TEXT_HJUSTIFY_CENTER: return _( "Center" );
  341. case GR_TEXT_HJUSTIFY_RIGHT: return _( "Right" );
  342. }
  343. break;
  344. case FDC_V_ALIGN:
  345. switch ( field.GetVertJustify() )
  346. {
  347. case GR_TEXT_VJUSTIFY_TOP: return _( "Top" );
  348. case GR_TEXT_VJUSTIFY_CENTER: return _( "Center" );
  349. case GR_TEXT_VJUSTIFY_BOTTOM: return _( "Bottom" );
  350. }
  351. break;
  352. case FDC_ITALIC:
  353. return StringFromBool( field.IsItalic() );
  354. case FDC_BOLD:
  355. return StringFromBool( field.IsBold() );
  356. case FDC_TEXT_SIZE:
  357. return StringFromValue( m_userUnits, field.GetTextSize().GetHeight() );
  358. case FDC_ORIENTATION:
  359. switch ( (int) field.GetTextAngle() )
  360. {
  361. case TEXT_ANGLE_HORIZ: return _( "Horizontal" );
  362. case TEXT_ANGLE_VERT: return _( "Vertical" );
  363. }
  364. break;
  365. case FDC_POSX:
  366. return StringFromValue( m_userUnits, field.GetTextPos().x );
  367. case FDC_POSY:
  368. return StringFromValue( m_userUnits, field.GetTextPos().y );
  369. default:
  370. // we can't assert here because wxWidgets sometimes calls this without checking
  371. // the column type when trying to see if there's an overflow
  372. break;
  373. }
  374. return wxT( "bad wxWidgets!" );
  375. }
  376. template <class T>
  377. bool FIELDS_GRID_TABLE<T>::GetValueAsBool( int aRow, int aCol )
  378. {
  379. wxCHECK( aRow < GetNumberRows(), false );
  380. const T& field = this->at( (size_t) aRow );
  381. switch( aCol )
  382. {
  383. case FDC_SHOWN: return field.IsVisible();
  384. case FDC_ITALIC: return field.IsItalic();
  385. case FDC_BOLD: return field.IsBold();
  386. default:
  387. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  388. return false;
  389. }
  390. }
  391. template <class T>
  392. void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue )
  393. {
  394. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  395. T& field = this->at( (size_t) aRow );
  396. wxPoint pos;
  397. switch( aCol )
  398. {
  399. case FDC_NAME:
  400. field.SetName( aValue );
  401. break;
  402. case FDC_VALUE:
  403. {
  404. wxString value( aValue );
  405. if( m_parentType == SCH_SHEET_T && aRow == SHEETFILENAME )
  406. {
  407. wxFileName fn( value );
  408. // It's annoying to throw up nag dialogs when the extension isn't right. Just
  409. // fix it.
  410. if( fn.GetExt().CmpNoCase( KiCadSchematicFileExtension ) != 0 )
  411. {
  412. fn.SetExt( KiCadSchematicFileExtension );
  413. value = fn.GetFullPath();
  414. }
  415. }
  416. else if( m_parentType == SCH_SYMBOL_T && aRow == VALUE_FIELD )
  417. {
  418. value = EscapeString( value, CTX_LIBID );
  419. }
  420. field.SetText( value );
  421. }
  422. break;
  423. case FDC_SHOWN:
  424. field.SetVisible( BoolFromString( aValue ) );
  425. break;
  426. case FDC_H_ALIGN:
  427. if( aValue == _( "Left" ) )
  428. field.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  429. else if( aValue == _( "Center" ) )
  430. field.SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
  431. else if( aValue == _( "Right" ) )
  432. field.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  433. else
  434. wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + aValue );
  435. break;
  436. case FDC_V_ALIGN:
  437. if( aValue == _( "Top" ) )
  438. field.SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  439. else if( aValue == _( "Center" ) )
  440. field.SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  441. else if( aValue == _( "Bottom" ) )
  442. field.SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  443. else
  444. wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + aValue);
  445. break;
  446. case FDC_ITALIC:
  447. field.SetItalic( BoolFromString( aValue ) );
  448. break;
  449. case FDC_BOLD:
  450. field.SetBold( BoolFromString( aValue ) );
  451. break;
  452. case FDC_TEXT_SIZE:
  453. field.SetTextSize( wxSize( ValueFromString( m_userUnits, aValue ),
  454. ValueFromString( m_userUnits, aValue ) ) );
  455. break;
  456. case FDC_ORIENTATION:
  457. if( aValue == _( "Horizontal" ) )
  458. field.SetTextAngle( TEXT_ANGLE_HORIZ );
  459. else if( aValue == _( "Vertical" ) )
  460. field.SetTextAngle( TEXT_ANGLE_VERT );
  461. else
  462. wxFAIL_MSG( wxT( "unknown orientation: " ) + aValue );
  463. break;
  464. case FDC_POSX:
  465. case FDC_POSY:
  466. pos = field.GetTextPos();
  467. if( aCol == FDC_POSX )
  468. pos.x = ValueFromString( m_userUnits, aValue );
  469. else
  470. pos.y = ValueFromString( m_userUnits, aValue );
  471. field.SetTextPos( pos );
  472. break;
  473. default:
  474. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
  475. break;
  476. }
  477. GetView()->Refresh();
  478. }
  479. template <class T>
  480. void FIELDS_GRID_TABLE<T>::SetValueAsBool( int aRow, int aCol, bool aValue )
  481. {
  482. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  483. T& field = this->at( (size_t) aRow );
  484. switch( aCol )
  485. {
  486. case FDC_SHOWN:
  487. field.SetVisible( aValue );
  488. break;
  489. case FDC_ITALIC:
  490. field.SetItalic( aValue );
  491. break;
  492. case FDC_BOLD:
  493. field.SetBold( aValue );
  494. break;
  495. default:
  496. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  497. break;
  498. }
  499. }
  500. // Explicit Instantiations
  501. template class FIELDS_GRID_TABLE<SCH_FIELD>;
  502. template class FIELDS_GRID_TABLE<LIB_FIELD>;
  503. void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu )
  504. {
  505. if( m_grid->GetGridCursorRow() == FOOTPRINT_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE )
  506. {
  507. menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
  508. _( "Browse for footprint" ) );
  509. menu.AppendSeparator();
  510. }
  511. else if( m_grid->GetGridCursorRow() == DATASHEET_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE )
  512. {
  513. menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
  514. _( "Show datasheet in browser" ) );
  515. menu.AppendSeparator();
  516. }
  517. GRID_TRICKS::showPopupMenu( menu );
  518. }
  519. void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
  520. {
  521. if( event.GetId() == MYID_SELECT_FOOTPRINT )
  522. {
  523. // pick a footprint using the footprint picker.
  524. wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE );
  525. KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true, m_dlg );
  526. if( frame->ShowModal( &fpid, m_dlg ) )
  527. m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid );
  528. frame->Destroy();
  529. }
  530. else if (event.GetId() == MYID_SHOW_DATASHEET )
  531. {
  532. wxString datasheet_uri = m_grid->GetCellValue( DATASHEET_FIELD, FDC_VALUE );
  533. GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj() );
  534. }
  535. else
  536. {
  537. GRID_TRICKS::doPopupSelection( event );
  538. }
  539. }
  540. template <class T>
  541. wxString FIELDS_GRID_TABLE<T>::StringFromBool( bool aValue ) const
  542. {
  543. if( aValue )
  544. return wxT( "1" );
  545. else
  546. return wxT( "0" );
  547. }
  548. template <class T>
  549. bool FIELDS_GRID_TABLE<T>::BoolFromString( wxString aValue ) const
  550. {
  551. if( aValue == "1" )
  552. {
  553. return true;
  554. }
  555. else if( aValue == "0" )
  556. {
  557. return false;
  558. }
  559. else
  560. {
  561. wxFAIL_MSG( wxString::Format( "string \"%s\" can't be converted to boolean "
  562. "correctly, it will have been perceived as FALSE", aValue ) );
  563. return false;
  564. }
  565. }