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.

558 lines
16 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2018 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 <class_library.h>
  32. #include <template_fieldnames.h>
  33. #include <widgets/grid_icon_text_helpers.h>
  34. #include <widgets/grid_text_button_helpers.h>
  35. #include "eda_doc.h"
  36. enum
  37. {
  38. MYID_SELECT_FOOTPRINT = 991, // must be within GRID_TRICKS' enum range
  39. MYID_SHOW_DATASHEET
  40. };
  41. template <class T>
  42. FIELDS_GRID_TABLE<T>::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame,
  43. LIB_PART* aPart ) :
  44. m_frame( aFrame ),
  45. m_userUnits( aDialog->GetUserUnits() ),
  46. m_part( aPart ),
  47. m_fieldNameValidator( aFrame->IsType( FRAME_SCH_LIB_EDITOR ), FIELD_NAME ),
  48. m_referenceValidator( aFrame->IsType( FRAME_SCH_LIB_EDITOR ), REFERENCE ),
  49. m_valueValidator( aFrame->IsType( FRAME_SCH_LIB_EDITOR ), VALUE )
  50. {
  51. // Build the various grid cell attributes.
  52. m_readOnlyAttr = new wxGridCellAttr;
  53. m_readOnlyAttr->SetReadOnly( true );
  54. m_fieldNameAttr = new wxGridCellAttr;
  55. GRID_CELL_TEXT_EDITOR* nameEditor = new GRID_CELL_TEXT_EDITOR();
  56. nameEditor->SetValidator( m_fieldNameValidator );
  57. m_fieldNameAttr->SetEditor( nameEditor );
  58. m_referenceAttr = new wxGridCellAttr;
  59. GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
  60. referenceEditor->SetValidator( m_referenceValidator );
  61. m_referenceAttr->SetEditor( referenceEditor );
  62. m_valueAttr = new wxGridCellAttr;
  63. GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
  64. valueEditor->SetValidator( m_valueValidator );
  65. m_valueAttr->SetEditor( valueEditor );
  66. m_footprintAttr = new wxGridCellAttr;
  67. m_footprintAttr->SetEditor( new GRID_CELL_FOOTPRINT_ID_EDITOR( aDialog ) );
  68. m_urlAttr = new wxGridCellAttr;
  69. m_urlAttr->SetEditor( new GRID_CELL_URL_EDITOR( aDialog ) );
  70. m_boolAttr = new wxGridCellAttr;
  71. m_boolAttr->SetRenderer( new wxGridCellBoolRenderer() );
  72. m_boolAttr->SetEditor( new wxGridCellBoolEditor() );
  73. m_boolAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  74. wxArrayString vAlignNames;
  75. vAlignNames.Add( _( "Top" ) );
  76. vAlignNames.Add( _( "Center" ) );
  77. vAlignNames.Add( _( "Bottom" ) );
  78. m_vAlignAttr = new wxGridCellAttr;
  79. m_vAlignAttr->SetEditor( new wxGridCellChoiceEditor( vAlignNames ) );
  80. m_vAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  81. wxArrayString hAlignNames;
  82. hAlignNames.Add( _( "Left" ) );
  83. hAlignNames.Add(_( "Center" ) );
  84. hAlignNames.Add(_( "Right" ) );
  85. m_hAlignAttr = new wxGridCellAttr;
  86. m_hAlignAttr->SetEditor( new wxGridCellChoiceEditor( hAlignNames ) );
  87. m_hAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  88. wxArrayString orientationNames;
  89. orientationNames.Add( _( "Horizontal" ) );
  90. orientationNames.Add(_( "Vertical" ) );
  91. m_orientationAttr = new wxGridCellAttr;
  92. m_orientationAttr->SetEditor( new wxGridCellChoiceEditor( orientationNames ) );
  93. m_orientationAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_BOTTOM );
  94. }
  95. template <class T>
  96. FIELDS_GRID_TABLE<T>::~FIELDS_GRID_TABLE()
  97. {
  98. m_readOnlyAttr->DecRef();
  99. m_fieldNameAttr->DecRef();
  100. m_boolAttr->DecRef();
  101. m_referenceAttr->DecRef();
  102. m_valueAttr->DecRef();
  103. m_footprintAttr->DecRef();
  104. m_urlAttr->DecRef();
  105. m_vAlignAttr->DecRef();
  106. m_hAlignAttr->DecRef();
  107. m_orientationAttr->DecRef();
  108. }
  109. template <class T>
  110. wxString FIELDS_GRID_TABLE<T>::GetColLabelValue( int aCol )
  111. {
  112. switch( aCol )
  113. {
  114. case FDC_NAME: return _( "Name" );
  115. case FDC_VALUE: return _( "Value" );
  116. case FDC_SHOWN: return _( "Show" );
  117. case FDC_H_ALIGN: return _( "H Align" );
  118. case FDC_V_ALIGN: return _( "V Align" );
  119. case FDC_ITALIC: return _( "Italic" );
  120. case FDC_BOLD: return _( "Bold" );
  121. case FDC_TEXT_SIZE: return _( "Text Size" );
  122. case FDC_ORIENTATION: return _( "Orientation" );
  123. case FDC_POSX: return _( "X Position" );
  124. case FDC_POSY: return _( "Y Position" );
  125. default: wxFAIL; return wxEmptyString;
  126. }
  127. }
  128. template <class T>
  129. bool FIELDS_GRID_TABLE<T>::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
  130. {
  131. switch( aCol )
  132. {
  133. case FDC_NAME:
  134. case FDC_VALUE:
  135. case FDC_H_ALIGN:
  136. case FDC_V_ALIGN:
  137. case FDC_TEXT_SIZE:
  138. case FDC_ORIENTATION:
  139. case FDC_POSX:
  140. case FDC_POSY:
  141. return aTypeName == wxGRID_VALUE_STRING;
  142. case FDC_SHOWN:
  143. case FDC_ITALIC:
  144. case FDC_BOLD:
  145. return aTypeName == wxGRID_VALUE_BOOL;
  146. default:
  147. wxFAIL;
  148. return false;
  149. }
  150. }
  151. template <class T>
  152. bool FIELDS_GRID_TABLE<T>::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
  153. {
  154. return CanGetValueAs( aRow, aCol, aTypeName );
  155. }
  156. template <class T>
  157. wxGridCellAttr* FIELDS_GRID_TABLE<T>::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind )
  158. {
  159. switch( aCol )
  160. {
  161. case FDC_NAME:
  162. if( aRow < MANDATORY_FIELDS )
  163. {
  164. m_readOnlyAttr->IncRef();
  165. return m_readOnlyAttr;
  166. }
  167. else
  168. {
  169. m_fieldNameAttr->IncRef();
  170. return m_fieldNameAttr;
  171. }
  172. case FDC_VALUE:
  173. if( aRow == REFERENCE )
  174. {
  175. m_referenceAttr->IncRef();
  176. return m_referenceAttr;
  177. }
  178. else if( aRow == VALUE )
  179. {
  180. // For power symbols, the value is not editable, because value and pin name must
  181. // be the same and can be edited only in library editor.
  182. if( m_part && m_part->IsPower() && ! m_frame->IsType( FRAME_SCH_LIB_EDITOR ) )
  183. {
  184. m_readOnlyAttr->IncRef();
  185. return m_readOnlyAttr;
  186. }
  187. else
  188. {
  189. m_valueAttr->IncRef();
  190. return m_valueAttr;
  191. }
  192. }
  193. else if( aRow == FOOTPRINT )
  194. {
  195. m_footprintAttr->IncRef();
  196. return m_footprintAttr;
  197. }
  198. else if( aRow == DATASHEET )
  199. {
  200. m_urlAttr->IncRef();
  201. return m_urlAttr;
  202. }
  203. else
  204. {
  205. wxString fieldname = GetValue( aRow, FDC_NAME );
  206. const TEMPLATE_FIELDNAME* templateFn = m_frame->GetTemplateFieldName( fieldname );
  207. if( templateFn && templateFn->m_URL )
  208. {
  209. m_urlAttr->IncRef();
  210. return m_urlAttr;
  211. }
  212. }
  213. return nullptr;
  214. case FDC_TEXT_SIZE:
  215. case FDC_POSX:
  216. case FDC_POSY:
  217. return nullptr;
  218. case FDC_H_ALIGN:
  219. m_hAlignAttr->IncRef();
  220. return m_hAlignAttr;
  221. case FDC_V_ALIGN:
  222. m_vAlignAttr->IncRef();
  223. return m_vAlignAttr;
  224. case FDC_ORIENTATION:
  225. m_orientationAttr->IncRef();
  226. return m_orientationAttr;
  227. case FDC_SHOWN:
  228. case FDC_ITALIC:
  229. case FDC_BOLD:
  230. m_boolAttr->IncRef();
  231. return m_boolAttr;
  232. default:
  233. wxFAIL;
  234. return nullptr;
  235. }
  236. }
  237. template <class T>
  238. wxString FIELDS_GRID_TABLE<T>::GetValue( int aRow, int aCol )
  239. {
  240. wxCHECK( aRow < GetNumberRows(), wxEmptyString );
  241. const T& field = this->at( (size_t) aRow );
  242. switch( aCol )
  243. {
  244. case FDC_NAME:
  245. // Use default field name for mandatory fields, because they are transalted
  246. // according to the current locale
  247. if( aRow < MANDATORY_FIELDS )
  248. return TEMPLATE_FIELDNAME::GetDefaultFieldName( aRow );
  249. else
  250. return field.GetName( false );
  251. case FDC_VALUE:
  252. return field.GetText();
  253. case FDC_SHOWN:
  254. return StringFromBool( field.IsVisible() );
  255. case FDC_H_ALIGN:
  256. switch ( field.GetHorizJustify() )
  257. {
  258. case GR_TEXT_HJUSTIFY_LEFT:
  259. return _( "Left" );
  260. case GR_TEXT_HJUSTIFY_CENTER:
  261. return _( "Center" );
  262. case GR_TEXT_HJUSTIFY_RIGHT:
  263. return _( "Right" );
  264. }
  265. break;
  266. case FDC_V_ALIGN:
  267. switch ( field.GetVertJustify() )
  268. {
  269. case GR_TEXT_VJUSTIFY_TOP:
  270. return _( "Top" );
  271. case GR_TEXT_VJUSTIFY_CENTER:
  272. return _( "Center" );
  273. case GR_TEXT_VJUSTIFY_BOTTOM:
  274. return _( "Bottom" );
  275. }
  276. break;
  277. case FDC_ITALIC:
  278. return StringFromBool( field.IsItalic() );
  279. case FDC_BOLD:
  280. return StringFromBool( field.IsBold() );
  281. case FDC_TEXT_SIZE:
  282. return StringFromValue( m_userUnits, field.GetTextSize().GetHeight(), true, true );
  283. case FDC_ORIENTATION:
  284. switch ( (int) field.GetTextAngle() )
  285. {
  286. case TEXT_ANGLE_HORIZ:
  287. return _( "Horizontal" );
  288. case TEXT_ANGLE_VERT:
  289. return _( "Vertical" );
  290. }
  291. break;
  292. case FDC_POSX:
  293. return StringFromValue( m_userUnits, field.GetTextPos().x, true );
  294. case FDC_POSY:
  295. return StringFromValue( m_userUnits, field.GetTextPos().y, true );
  296. default:
  297. // we can't assert here because wxWidgets sometimes calls this without checking
  298. // the column type when trying to see if there's an overflow
  299. break;
  300. }
  301. return wxT( "bad wxWidgets!" );
  302. }
  303. template <class T>
  304. bool FIELDS_GRID_TABLE<T>::GetValueAsBool( int aRow, int aCol )
  305. {
  306. wxCHECK( aRow < GetNumberRows(), false );
  307. const T& field = this->at( (size_t) aRow );
  308. switch( aCol )
  309. {
  310. case FDC_SHOWN: return field.IsVisible();
  311. case FDC_ITALIC: return field.IsItalic();
  312. case FDC_BOLD: return field.IsBold();
  313. default:
  314. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  315. return false;
  316. }
  317. }
  318. template <class T>
  319. void FIELDS_GRID_TABLE<T>::SetValue( int aRow, int aCol, const wxString &aValue )
  320. {
  321. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  322. T& field = this->at( (size_t) aRow );
  323. wxPoint pos;
  324. switch( aCol )
  325. {
  326. case FDC_NAME:
  327. field.SetName( aValue );
  328. break;
  329. case FDC_VALUE:
  330. field.SetText( aValue );
  331. break;
  332. case FDC_SHOWN:
  333. field.SetVisible( BoolFromString( aValue ) );
  334. break;
  335. case FDC_H_ALIGN:
  336. if( aValue == _( "Left" ) )
  337. field.SetHorizJustify( GR_TEXT_HJUSTIFY_LEFT );
  338. else if( aValue == _( "Center" ) )
  339. field.SetHorizJustify( GR_TEXT_HJUSTIFY_CENTER );
  340. else if( aValue == _( "Right" ) )
  341. field.SetHorizJustify( GR_TEXT_HJUSTIFY_RIGHT );
  342. else
  343. wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + aValue );
  344. break;
  345. case FDC_V_ALIGN:
  346. if( aValue == _( "Top" ) )
  347. field.SetVertJustify( GR_TEXT_VJUSTIFY_TOP );
  348. else if( aValue == _( "Center" ) )
  349. field.SetVertJustify( GR_TEXT_VJUSTIFY_CENTER );
  350. else if( aValue == _( "Bottom" ) )
  351. field.SetVertJustify( GR_TEXT_VJUSTIFY_BOTTOM );
  352. else
  353. wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + aValue);
  354. break;
  355. case FDC_ITALIC:
  356. field.SetItalic( BoolFromString( aValue ) );
  357. break;
  358. case FDC_BOLD:
  359. field.SetBold( BoolFromString( aValue ) );
  360. break;
  361. case FDC_TEXT_SIZE:
  362. field.SetTextSize( wxSize( ValueFromString( m_userUnits, aValue ),
  363. ValueFromString( m_userUnits, aValue ) ) );
  364. break;
  365. case FDC_ORIENTATION:
  366. if( aValue == _( "Horizontal" ) )
  367. field.SetTextAngle( TEXT_ANGLE_HORIZ );
  368. else if( aValue == _( "Vertical" ) )
  369. field.SetTextAngle( TEXT_ANGLE_VERT );
  370. else
  371. wxFAIL_MSG( wxT( "unknown orientation: " ) + aValue );
  372. break;
  373. case FDC_POSX:
  374. case FDC_POSY:
  375. pos = field.GetTextPos();
  376. if( aCol == FDC_POSX )
  377. pos.x = ValueFromString( m_userUnits, aValue );
  378. else
  379. pos.y = ValueFromString( m_userUnits, aValue );
  380. field.SetTextPos( pos );
  381. break;
  382. default:
  383. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
  384. break;
  385. }
  386. GetView()->Refresh();
  387. }
  388. template <class T>
  389. void FIELDS_GRID_TABLE<T>::SetValueAsBool( int aRow, int aCol, bool aValue )
  390. {
  391. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  392. T& field = this->at( (size_t) aRow );
  393. switch( aCol )
  394. {
  395. case FDC_SHOWN:
  396. field.SetVisible( aValue );
  397. break;
  398. case FDC_ITALIC:
  399. field.SetItalic( aValue );
  400. break;
  401. case FDC_BOLD:
  402. field.SetBold( aValue );
  403. break;
  404. default:
  405. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  406. break;
  407. }
  408. }
  409. // Explicit Instantiations
  410. template class FIELDS_GRID_TABLE<SCH_FIELD>;
  411. template class FIELDS_GRID_TABLE<LIB_FIELD>;
  412. void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu )
  413. {
  414. if( m_grid->GetGridCursorRow() == FOOTPRINT && m_grid->GetGridCursorCol() == FDC_VALUE )
  415. {
  416. menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ), _( "Browse for footprint" ) );
  417. menu.AppendSeparator();
  418. }
  419. else if( m_grid->GetGridCursorRow() == DATASHEET && m_grid->GetGridCursorCol() == FDC_VALUE )
  420. {
  421. menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ), _( "Show datasheet in browser" ) );
  422. menu.AppendSeparator();
  423. }
  424. GRID_TRICKS::showPopupMenu( menu );
  425. }
  426. void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
  427. {
  428. if( event.GetId() == MYID_SELECT_FOOTPRINT )
  429. {
  430. // pick a footprint using the footprint picker.
  431. wxString fpid = m_grid->GetCellValue( FOOTPRINT, FDC_VALUE );
  432. KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_PCB_MODULE_VIEWER_MODAL, true, m_dlg );
  433. if( frame->ShowModal( &fpid, m_dlg ) )
  434. m_grid->SetCellValue( FOOTPRINT, FDC_VALUE, fpid );
  435. frame->Destroy();
  436. }
  437. else if (event.GetId() == MYID_SHOW_DATASHEET )
  438. {
  439. wxString datasheet_uri = m_grid->GetCellValue( DATASHEET, FDC_VALUE );
  440. GetAssociatedDocument( m_dlg, datasheet_uri );
  441. }
  442. else
  443. {
  444. GRID_TRICKS::doPopupSelection( event );
  445. }
  446. }
  447. template <class T>
  448. wxString FIELDS_GRID_TABLE<T>::StringFromBool( bool aValue )
  449. {
  450. if( aValue )
  451. return wxT( "1" );
  452. else
  453. return wxT( "0" );
  454. }
  455. template <class T>
  456. bool FIELDS_GRID_TABLE<T>::BoolFromString( wxString aValue )
  457. {
  458. if( aValue == wxT( "1" ) )
  459. {
  460. return true;
  461. }
  462. else if( aValue == wxT( "0" ) )
  463. {
  464. return false;
  465. }
  466. else
  467. {
  468. wxFAIL_MSG( wxString::Format( wxT( "string \"%s\" can't be converted to boolean correctly, it will have been perceived as FALSE" ), aValue ) );
  469. return false;
  470. }
  471. }