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.

1125 lines
33 KiB

2 years ago
2 years ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
3 years ago
3 years ago
2 years ago
2 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The 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 <embedded_files.h>
  24. #include <kiway.h>
  25. #include <kiway_player.h>
  26. #include <dialog_shim.h>
  27. #include <fields_grid_table.h>
  28. #include <sch_base_frame.h>
  29. #include <sch_field.h>
  30. #include <sch_label.h>
  31. #include <sch_validators.h>
  32. #include <validators.h>
  33. #include <sch_edit_frame.h>
  34. #include <symbol_library.h>
  35. #include <schematic.h>
  36. #include <template_fieldnames.h>
  37. #include <widgets/grid_text_button_helpers.h>
  38. #include <wildcards_and_files_ext.h>
  39. #include <project/project_file.h>
  40. #include <project/net_settings.h>
  41. #include "eda_doc.h"
  42. #include "widgets/grid_color_swatch_helpers.h"
  43. #include "font/fontconfig.h"
  44. #include "font/kicad_font_name.h"
  45. #include "widgets/grid_text_helpers.h"
  46. #include <wx/settings.h>
  47. #include <string_utils.h>
  48. #include <widgets/grid_combobox.h>
  49. #include <pgm_base.h>
  50. #include <project_sch.h>
  51. enum
  52. {
  53. MYID_SELECT_FOOTPRINT = GRIDTRICKS_FIRST_CLIENT_ID,
  54. MYID_SHOW_DATASHEET
  55. };
  56. #define DEFAULT_FONT_NAME _( "Default Font" )
  57. static wxString netList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH& aSheetPath )
  58. {
  59. wxCHECK( aSymbol && aSymbol->GetLibSymbolRef(), wxEmptyString );
  60. /*
  61. * Symbol netlist format:
  62. * pinNumber pinName <tab> pinNumber pinName...
  63. * fpFilter fpFilter...
  64. */
  65. wxString netlist;
  66. // We need the list of pins of the lib symbol, not just the pins of the current
  67. // sch symbol, that can be just an unit of a multi-unit symbol, to be able to
  68. // select/filter right footprints
  69. wxArrayString pins;
  70. const std::unique_ptr< LIB_SYMBOL >& lib_symbol = aSymbol->GetLibSymbolRef();
  71. if( lib_symbol )
  72. {
  73. for( SCH_PIN* pin : lib_symbol->GetPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
  74. pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
  75. }
  76. if( !pins.IsEmpty() )
  77. netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
  78. netlist << wxS( "\r" );
  79. wxArrayString fpFilters = aSymbol->GetLibSymbolRef()->GetFPFilters();
  80. if( !fpFilters.IsEmpty() )
  81. netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
  82. netlist << wxS( "\r" );
  83. return netlist;
  84. }
  85. static wxString netList( LIB_SYMBOL* aSymbol )
  86. {
  87. /*
  88. * Symbol netlist format:
  89. * pinNumber pinName <tab> pinNumber pinName...
  90. * fpFilter fpFilter...
  91. */
  92. wxString netlist;
  93. wxArrayString pins;
  94. for( SCH_PIN* pin : aSymbol->GetPins( 0 /* all units */, 1 /* single bodyStyle */ ) )
  95. pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() );
  96. if( !pins.IsEmpty() )
  97. netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE );
  98. netlist << wxS( "\r" );
  99. wxArrayString fpFilters = aSymbol->GetFPFilters();
  100. if( !fpFilters.IsEmpty() )
  101. netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE );
  102. netlist << wxS( "\r" );
  103. return netlist;
  104. }
  105. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame, WX_GRID* aGrid,
  106. LIB_SYMBOL* aSymbol, std::vector<EMBEDDED_FILES*> aFilesStack ) :
  107. m_frame( aFrame ),
  108. m_dialog( aDialog ),
  109. m_parentType( SCH_SYMBOL_T ),
  110. m_part( aSymbol ),
  111. m_filesStack( aFilesStack ),
  112. m_symbolNetlist( netList( aSymbol ) ),
  113. m_fieldNameValidator( FIELD_T::USER ),
  114. m_referenceValidator( FIELD_T::REFERENCE ),
  115. m_valueValidator( FIELD_T::VALUE ),
  116. m_urlValidator( FIELD_T::USER ),
  117. m_nonUrlValidator( FIELD_T::USER ),
  118. m_filepathValidator( FIELD_T::SHEET_FILENAME )
  119. {
  120. initGrid( aGrid );
  121. }
  122. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid,
  123. SCH_SYMBOL* aSymbol ) :
  124. m_frame( aFrame ),
  125. m_dialog( aDialog ),
  126. m_parentType( SCH_SYMBOL_T ),
  127. m_part( aSymbol->GetLibSymbolRef().get() ),
  128. m_symbolNetlist( netList( aSymbol, aFrame->GetCurrentSheet() ) ),
  129. m_fieldNameValidator( FIELD_T::USER ),
  130. m_referenceValidator( FIELD_T::REFERENCE ),
  131. m_valueValidator( FIELD_T::VALUE ),
  132. m_urlValidator( FIELD_T::USER ),
  133. m_nonUrlValidator( FIELD_T::USER ),
  134. m_filepathValidator( FIELD_T::SHEET_FILENAME )
  135. {
  136. m_filesStack.push_back( aSymbol->Schematic() );
  137. if( m_part )
  138. m_filesStack.push_back( m_part );
  139. initGrid( aGrid );
  140. }
  141. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid,
  142. SCH_SHEET* aSheet ) :
  143. m_frame( aFrame ),
  144. m_dialog( aDialog ),
  145. m_parentType( SCH_SHEET_T ),
  146. m_part( nullptr ),
  147. m_fieldNameValidator( FIELD_T::USER ),
  148. m_referenceValidator( FIELD_T::SHEET_NAME ),
  149. m_valueValidator( FIELD_T::VALUE ),
  150. m_urlValidator( FIELD_T::USER ),
  151. m_nonUrlValidator( FIELD_T::USER ),
  152. m_filepathValidator( FIELD_T::SHEET_FILENAME )
  153. {
  154. m_filesStack.push_back( aSheet->Schematic() );
  155. initGrid( aGrid );
  156. }
  157. FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid,
  158. SCH_LABEL_BASE* aLabel ) :
  159. m_frame( aFrame ),
  160. m_dialog( aDialog ),
  161. m_parentType( SCH_LABEL_LOCATE_ANY_T ),
  162. m_part( nullptr ),
  163. m_fieldNameValidator( FIELD_T::USER ),
  164. m_referenceValidator( FIELD_T::USER ),
  165. m_valueValidator( FIELD_T::USER ),
  166. m_urlValidator( FIELD_T::USER ),
  167. m_nonUrlValidator( FIELD_T::USER ),
  168. m_filepathValidator( FIELD_T::USER )
  169. {
  170. m_filesStack.push_back( aLabel->Schematic() );
  171. initGrid( aGrid );
  172. }
  173. int FIELDS_GRID_TABLE::GetMandatoryRowCount() const
  174. {
  175. int mandatoryRows = 0;
  176. for( const SCH_FIELD& field : *this )
  177. {
  178. if( field.IsMandatory() )
  179. mandatoryRows++;
  180. }
  181. return mandatoryRows;
  182. }
  183. void FIELDS_GRID_TABLE::initGrid( WX_GRID* aGrid )
  184. {
  185. // Build the various grid cell attributes.
  186. // NOTE: validators and cellAttrs are member variables to get the destruction order
  187. // right. wxGrid is VERY cranky about this.
  188. m_readOnlyAttr = new wxGridCellAttr;
  189. m_readOnlyAttr->SetReadOnly( true );
  190. m_fieldNameAttr = new wxGridCellAttr;
  191. GRID_CELL_TEXT_EDITOR* nameEditor = new GRID_CELL_TEXT_EDITOR();
  192. nameEditor->SetValidator( m_fieldNameValidator );
  193. m_fieldNameAttr->SetEditor( nameEditor );
  194. m_referenceAttr = new wxGridCellAttr;
  195. GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR();
  196. referenceEditor->SetValidator( m_referenceValidator );
  197. m_referenceAttr->SetEditor( referenceEditor );
  198. m_valueAttr = new wxGridCellAttr;
  199. if( m_parentType == LIB_SYMBOL_T )
  200. {
  201. GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR();
  202. valueEditor->SetValidator( m_valueValidator );
  203. m_valueAttr->SetEditor( valueEditor );
  204. }
  205. else
  206. {
  207. GRID_CELL_STC_EDITOR* valueEditor = new GRID_CELL_STC_EDITOR( true,
  208. [this]( wxStyledTextEvent& aEvent, SCINTILLA_TRICKS* aScintillaTricks )
  209. {
  210. SCH_FIELD* valueField = this->GetField( FIELD_T::VALUE );
  211. valueField->OnScintillaCharAdded( aScintillaTricks, aEvent );
  212. } );
  213. m_valueAttr->SetEditor( valueEditor );
  214. }
  215. m_footprintAttr = new wxGridCellAttr;
  216. GRID_CELL_FPID_EDITOR* fpIdEditor = new GRID_CELL_FPID_EDITOR( m_dialog, m_symbolNetlist );
  217. fpIdEditor->SetValidator( m_nonUrlValidator );
  218. m_footprintAttr->SetEditor( fpIdEditor );
  219. m_urlAttr = new wxGridCellAttr;
  220. SEARCH_STACK* prjSearchStack = PROJECT_SCH::SchSearchS( &m_frame->Prj() );
  221. GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( m_dialog, prjSearchStack, m_filesStack );
  222. urlEditor->SetValidator( m_urlValidator );
  223. m_urlAttr->SetEditor( urlEditor );
  224. m_nonUrlAttr = new wxGridCellAttr;
  225. GRID_CELL_TEXT_EDITOR* nonUrlEditor = new GRID_CELL_TEXT_EDITOR();
  226. nonUrlEditor->SetValidator( m_nonUrlValidator );
  227. m_nonUrlAttr->SetEditor( nonUrlEditor );
  228. m_curdir = m_frame->Prj().GetProjectPath();
  229. m_filepathAttr = new wxGridCellAttr;
  230. // Create a wild card using wxFileDialog syntax.
  231. wxString wildCard( _( "Schematic Files" ) );
  232. std::vector<std::string> exts;
  233. exts.push_back( FILEEXT::KiCadSchematicFileExtension );
  234. wildCard += AddFileExtListToFilter( exts );
  235. auto filepathEditor = new GRID_CELL_PATH_EDITOR( m_dialog, aGrid, &m_curdir, wildCard );
  236. filepathEditor->SetValidator( m_filepathValidator );
  237. m_filepathAttr->SetEditor( filepathEditor );
  238. m_boolAttr = new wxGridCellAttr;
  239. m_boolAttr->SetRenderer( new wxGridCellBoolRenderer() );
  240. m_boolAttr->SetEditor( new wxGridCellBoolEditor() );
  241. m_boolAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  242. wxArrayString vAlignNames;
  243. vAlignNames.Add( _( "Top" ) );
  244. vAlignNames.Add( _( "Center" ) );
  245. vAlignNames.Add( _( "Bottom" ) );
  246. m_vAlignAttr = new wxGridCellAttr;
  247. m_vAlignAttr->SetEditor( new wxGridCellChoiceEditor( vAlignNames ) );
  248. m_vAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  249. wxArrayString hAlignNames;
  250. hAlignNames.Add( _( "Left" ) );
  251. hAlignNames.Add(_( "Center" ) );
  252. hAlignNames.Add(_( "Right" ) );
  253. m_hAlignAttr = new wxGridCellAttr;
  254. m_hAlignAttr->SetEditor( new wxGridCellChoiceEditor( hAlignNames ) );
  255. m_hAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  256. wxArrayString orientationNames;
  257. orientationNames.Add( _( "Horizontal" ) );
  258. orientationNames.Add(_( "Vertical" ) );
  259. m_orientationAttr = new wxGridCellAttr;
  260. m_orientationAttr->SetEditor( new wxGridCellChoiceEditor( orientationNames ) );
  261. m_orientationAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
  262. SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame );
  263. wxArrayString existingNetclasses;
  264. wxArrayString fonts;
  265. std::vector<std::string> fontNames;
  266. if( editFrame )
  267. {
  268. // Load the combobox with existing existingNetclassNames
  269. PROJECT_FILE& projectFile = editFrame->Prj().GetProjectFile();
  270. const std::shared_ptr<NET_SETTINGS>& settings = projectFile.NetSettings();
  271. existingNetclasses.push_back( settings->GetDefaultNetclass()->GetName() );
  272. for( const auto& [name, netclass] : settings->GetNetclasses() )
  273. existingNetclasses.push_back( name );
  274. // We don't need to re-cache the embedded fonts when looking at symbols in the schematic
  275. // editor because the fonts are all available in the schematic.
  276. const std::vector<wxString>* fontFiles = nullptr;
  277. if( m_frame->GetScreen() && m_frame->GetScreen()->Schematic() )
  278. fontFiles = m_frame->GetScreen()->Schematic()->GetEmbeddedFiles()->GetFontFiles();
  279. Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ),
  280. fontFiles, false );
  281. }
  282. else
  283. {
  284. const std::vector<wxString>* fontFiles = m_part->GetEmbeddedFiles()->UpdateFontFiles();
  285. // If there are font files embedded, we want to re-cache our fonts for each symbol that
  286. // we are looking at in the symbol editor.
  287. Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ),
  288. fontFiles, !fontFiles->empty() );
  289. }
  290. m_netclassAttr = new wxGridCellAttr;
  291. m_netclassAttr->SetEditor( new GRID_CELL_COMBOBOX( existingNetclasses ) );
  292. for( const std::string& name : fontNames )
  293. fonts.Add( wxString( name ) );
  294. fonts.Sort();
  295. fonts.Insert( KICAD_FONT_NAME, 0 );
  296. fonts.Insert( DEFAULT_FONT_NAME, 0 );
  297. m_fontAttr = new wxGridCellAttr;
  298. m_fontAttr->SetEditor( new GRID_CELL_COMBOBOX( fonts ) );
  299. m_colorAttr = new wxGridCellAttr;
  300. m_colorAttr->SetRenderer( new GRID_CELL_COLOR_RENDERER( m_dialog ) );
  301. m_colorAttr->SetEditor( new GRID_CELL_COLOR_SELECTOR( m_dialog, aGrid ) );
  302. m_eval = std::make_unique<NUMERIC_EVALUATOR>( m_frame->GetUserUnits() );
  303. m_frame->Bind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this );
  304. }
  305. FIELDS_GRID_TABLE::~FIELDS_GRID_TABLE()
  306. {
  307. m_readOnlyAttr->DecRef();
  308. m_fieldNameAttr->DecRef();
  309. m_boolAttr->DecRef();
  310. m_referenceAttr->DecRef();
  311. m_valueAttr->DecRef();
  312. m_footprintAttr->DecRef();
  313. m_urlAttr->DecRef();
  314. m_nonUrlAttr->DecRef();
  315. m_filepathAttr->DecRef();
  316. m_vAlignAttr->DecRef();
  317. m_hAlignAttr->DecRef();
  318. m_orientationAttr->DecRef();
  319. m_netclassAttr->DecRef();
  320. m_fontAttr->DecRef();
  321. m_colorAttr->DecRef();
  322. m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this );
  323. }
  324. void FIELDS_GRID_TABLE::onUnitsChanged( wxCommandEvent& aEvent )
  325. {
  326. if( GetView() )
  327. GetView()->ForceRefresh();
  328. aEvent.Skip();
  329. }
  330. int FIELDS_GRID_TABLE::getColumnCount() const
  331. {
  332. if( m_frame->GetFrameType() == FRAME_SCH
  333. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  334. {
  335. return FDC_SCH_EDIT_COUNT;
  336. }
  337. else
  338. {
  339. return FDC_SYMBOL_EDITOR_COUNT;
  340. }
  341. }
  342. int FIELDS_GRID_TABLE::getVisibleRowCount() const
  343. {
  344. if( m_frame->GetFrameType() == FRAME_SCH
  345. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  346. {
  347. int visibleRows = 0;
  348. for( const SCH_FIELD& field : *this )
  349. {
  350. if( !field.IsPrivate() )
  351. visibleRows++;
  352. }
  353. return visibleRows;
  354. }
  355. return (int) this->size();
  356. }
  357. SCH_FIELD& FIELDS_GRID_TABLE::getField( int aRow )
  358. {
  359. if( m_frame->GetFrameType() == FRAME_SCH
  360. || m_frame->GetFrameType() == FRAME_SCH_VIEWER )
  361. {
  362. int visibleRow = 0;
  363. for( SCH_FIELD& field : *this )
  364. {
  365. if( field.IsPrivate() )
  366. continue;
  367. if( visibleRow == aRow )
  368. return field;
  369. ++visibleRow;
  370. }
  371. wxFAIL_MSG( wxT( "Row index off end of visible row count" ) );
  372. }
  373. return this->at( aRow );
  374. }
  375. wxString FIELDS_GRID_TABLE::GetColLabelValue( int aCol )
  376. {
  377. switch( aCol )
  378. {
  379. case FDC_NAME: return _( "Name" );
  380. case FDC_VALUE: return _( "Value" );
  381. case FDC_SHOWN: return _( "Show" );
  382. case FDC_SHOW_NAME: return _( "Show Name" );
  383. case FDC_H_ALIGN: return _( "H Align" );
  384. case FDC_V_ALIGN: return _( "V Align" );
  385. case FDC_ITALIC: return _( "Italic" );
  386. case FDC_BOLD: return _( "Bold" );
  387. case FDC_TEXT_SIZE: return _( "Text Size" );
  388. case FDC_ORIENTATION: return _( "Orientation" );
  389. case FDC_POSX: return _( "X Position" );
  390. case FDC_POSY: return _( "Y Position" );
  391. case FDC_FONT: return _( "Font" );
  392. case FDC_COLOR: return _( "Color" );
  393. case FDC_ALLOW_AUTOPLACE: return _( "Allow Autoplacement" );
  394. case FDC_PRIVATE: return _( "Private" );
  395. default: wxFAIL; return wxEmptyString;
  396. }
  397. }
  398. bool FIELDS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName )
  399. {
  400. switch( aCol )
  401. {
  402. case FDC_NAME:
  403. case FDC_VALUE:
  404. case FDC_H_ALIGN:
  405. case FDC_V_ALIGN:
  406. case FDC_TEXT_SIZE:
  407. case FDC_ORIENTATION:
  408. case FDC_POSX:
  409. case FDC_POSY:
  410. case FDC_FONT:
  411. case FDC_COLOR:
  412. return aTypeName == wxGRID_VALUE_STRING;
  413. case FDC_SHOWN:
  414. case FDC_SHOW_NAME:
  415. case FDC_ITALIC:
  416. case FDC_BOLD:
  417. case FDC_ALLOW_AUTOPLACE:
  418. case FDC_PRIVATE:
  419. return aTypeName == wxGRID_VALUE_BOOL;
  420. default:
  421. wxFAIL;
  422. return false;
  423. }
  424. }
  425. bool FIELDS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName )
  426. {
  427. return CanGetValueAs( aRow, aCol, aTypeName );
  428. }
  429. wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind )
  430. {
  431. wxCHECK( aRow < GetNumberRows(), nullptr );
  432. const SCH_FIELD& field = getField( aRow );
  433. wxGridCellAttr* tmp;
  434. switch( aCol )
  435. {
  436. case FDC_NAME:
  437. if( field.IsMandatory() )
  438. {
  439. tmp = m_fieldNameAttr->Clone();
  440. tmp->SetReadOnly( true );
  441. return enhanceAttr( tmp, aRow, aCol, aKind );
  442. }
  443. else
  444. {
  445. m_fieldNameAttr->IncRef();
  446. return enhanceAttr( m_fieldNameAttr, aRow, aCol, aKind );
  447. }
  448. case FDC_VALUE:
  449. if( field.GetId() == FIELD_T::REFERENCE )
  450. {
  451. m_referenceAttr->IncRef();
  452. return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
  453. }
  454. else if( field.GetId() == FIELD_T::VALUE )
  455. {
  456. m_valueAttr->IncRef();
  457. return enhanceAttr( m_valueAttr, aRow, aCol, aKind );
  458. }
  459. else if( field.GetId() == FIELD_T::FOOTPRINT )
  460. {
  461. // Power symbols have do not appear in the board, so don't allow
  462. // a footprint (m_part can be nullptr when loading a old schematic
  463. // (for instance Kicad 4) with libraries missing)
  464. if( m_part && m_part->IsPower() )
  465. {
  466. m_readOnlyAttr->IncRef();
  467. return enhanceAttr( m_readOnlyAttr, aRow, aCol, aKind );
  468. }
  469. else
  470. {
  471. m_footprintAttr->IncRef();
  472. return enhanceAttr( m_footprintAttr, aRow, aCol, aKind );
  473. }
  474. }
  475. else if( field.GetId() == FIELD_T::DATASHEET )
  476. {
  477. m_urlAttr->IncRef();
  478. return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
  479. }
  480. else if( field.GetId() == FIELD_T::SHEET_NAME )
  481. {
  482. m_referenceAttr->IncRef();
  483. return enhanceAttr( m_referenceAttr, aRow, aCol, aKind );
  484. }
  485. else if( field.GetId() == FIELD_T::SHEET_FILENAME )
  486. {
  487. m_filepathAttr->IncRef();
  488. return enhanceAttr( m_filepathAttr, aRow, aCol, aKind );
  489. }
  490. else if( ( m_parentType == SCH_LABEL_LOCATE_ANY_T )
  491. && field.GetCanonicalName() == wxT( "Netclass" ) )
  492. {
  493. m_netclassAttr->IncRef();
  494. return enhanceAttr( m_netclassAttr, aRow, aCol, aKind );
  495. }
  496. else
  497. {
  498. wxString fn = GetValue( aRow, FDC_NAME );
  499. SCHEMATIC_SETTINGS* settings = m_frame->Prj().GetProjectFile().m_SchematicSettings;
  500. const TEMPLATE_FIELDNAME* templateFn =
  501. settings ? settings->m_TemplateFieldNames.GetFieldName( fn ) : nullptr;
  502. if( ( templateFn && templateFn->m_URL ) || field.IsHypertext() )
  503. {
  504. m_urlAttr->IncRef();
  505. return enhanceAttr( m_urlAttr, aRow, aCol, aKind );
  506. }
  507. else
  508. {
  509. m_nonUrlAttr->IncRef();
  510. return enhanceAttr( m_nonUrlAttr, aRow, aCol, aKind );
  511. }
  512. }
  513. case FDC_TEXT_SIZE:
  514. case FDC_POSX:
  515. case FDC_POSY:
  516. return enhanceAttr( nullptr, aRow, aCol, aKind );
  517. case FDC_H_ALIGN:
  518. m_hAlignAttr->IncRef();
  519. return enhanceAttr( m_hAlignAttr, aRow, aCol, aKind );
  520. case FDC_V_ALIGN:
  521. m_vAlignAttr->IncRef();
  522. return enhanceAttr( m_vAlignAttr, aRow, aCol, aKind );
  523. case FDC_ORIENTATION:
  524. m_orientationAttr->IncRef();
  525. return enhanceAttr( m_orientationAttr, aRow, aCol, aKind );
  526. case FDC_SHOWN:
  527. case FDC_SHOW_NAME:
  528. case FDC_ITALIC:
  529. case FDC_BOLD:
  530. case FDC_ALLOW_AUTOPLACE:
  531. case FDC_PRIVATE:
  532. m_boolAttr->IncRef();
  533. return enhanceAttr( m_boolAttr, aRow, aCol, aKind );
  534. case FDC_FONT:
  535. m_fontAttr->IncRef();
  536. return enhanceAttr( m_fontAttr, aRow, aCol, aKind );
  537. case FDC_COLOR:
  538. m_colorAttr->IncRef();
  539. return enhanceAttr( m_colorAttr, aRow, aCol, aKind );
  540. default:
  541. wxFAIL;
  542. return enhanceAttr( nullptr, aRow, aCol, aKind );
  543. }
  544. }
  545. wxString FIELDS_GRID_TABLE::GetValue( int aRow, int aCol )
  546. {
  547. wxCHECK( aRow < GetNumberRows(), wxEmptyString );
  548. wxGrid* grid = GetView();
  549. const SCH_FIELD& field = getField( aRow );
  550. if( grid->GetGridCursorRow() == aRow && grid->GetGridCursorCol() == aCol
  551. && grid->IsCellEditControlShown() )
  552. {
  553. auto it = m_evalOriginal.find( { aRow, aCol } );
  554. if( it != m_evalOriginal.end() )
  555. return it->second;
  556. }
  557. switch( aCol )
  558. {
  559. case FDC_NAME:
  560. // Use default field names for mandatory and system fields because they are translated
  561. // according to the current locale
  562. if( m_parentType == SCH_LABEL_LOCATE_ANY_T )
  563. {
  564. return SCH_LABEL_BASE::GetDefaultFieldName( field.GetCanonicalName(), false );
  565. }
  566. else
  567. {
  568. if( field.IsMandatory() )
  569. return GetDefaultFieldName( field.GetId(), DO_TRANSLATE );
  570. else
  571. return field.GetName( false );
  572. }
  573. case FDC_VALUE:
  574. return EscapeString( UnescapeString( field.GetText() ), CTX_LINE );
  575. case FDC_SHOWN:
  576. return StringFromBool( field.IsVisible() );
  577. case FDC_SHOW_NAME:
  578. return StringFromBool( field.IsNameShown() );
  579. case FDC_H_ALIGN:
  580. switch ( field.GetEffectiveHorizJustify() )
  581. {
  582. case GR_TEXT_H_ALIGN_LEFT: return _( "Left" );
  583. case GR_TEXT_H_ALIGN_CENTER: return _( "Center" );
  584. case GR_TEXT_H_ALIGN_RIGHT: return _( "Right" );
  585. case GR_TEXT_H_ALIGN_INDETERMINATE: return INDETERMINATE_STATE;
  586. }
  587. break;
  588. case FDC_V_ALIGN:
  589. switch ( field.GetEffectiveVertJustify() )
  590. {
  591. case GR_TEXT_V_ALIGN_TOP: return _( "Top" );
  592. case GR_TEXT_V_ALIGN_CENTER: return _( "Center" );
  593. case GR_TEXT_V_ALIGN_BOTTOM: return _( "Bottom" );
  594. case GR_TEXT_V_ALIGN_INDETERMINATE: return INDETERMINATE_STATE;
  595. }
  596. break;
  597. case FDC_ITALIC:
  598. return StringFromBool( field.IsItalic() );
  599. case FDC_BOLD:
  600. return StringFromBool( field.IsBold() );
  601. case FDC_TEXT_SIZE:
  602. return m_frame->StringFromValue( field.GetTextHeight(), true );
  603. case FDC_ORIENTATION:
  604. if( field.GetTextAngle().IsHorizontal() )
  605. return _( "Horizontal" );
  606. else
  607. return _( "Vertical" );
  608. case FDC_POSX:
  609. return m_frame->StringFromValue( field.GetTextPos().x, true );
  610. case FDC_POSY:
  611. return m_frame->StringFromValue( field.GetTextPos().y, true );
  612. case FDC_FONT:
  613. if( field.GetFont() )
  614. return field.GetFont()->GetName();
  615. else
  616. return DEFAULT_FONT_NAME;
  617. case FDC_COLOR:
  618. return field.GetTextColor().ToCSSString();
  619. case FDC_ALLOW_AUTOPLACE:
  620. return StringFromBool( field.CanAutoplace() );
  621. case FDC_PRIVATE:
  622. return StringFromBool( field.IsPrivate() );
  623. default:
  624. // we can't assert here because wxWidgets sometimes calls this without checking
  625. // the column type when trying to see if there's an overflow
  626. break;
  627. }
  628. return wxT( "bad wxWidgets!" );
  629. }
  630. bool FIELDS_GRID_TABLE::GetValueAsBool( int aRow, int aCol )
  631. {
  632. wxCHECK( aRow < GetNumberRows(), false );
  633. const SCH_FIELD& field = getField( aRow );
  634. switch( aCol )
  635. {
  636. case FDC_SHOWN: return field.IsVisible();
  637. case FDC_SHOW_NAME: return field.IsNameShown();
  638. case FDC_ITALIC: return field.IsItalic();
  639. case FDC_BOLD: return field.IsBold();
  640. case FDC_ALLOW_AUTOPLACE: return field.CanAutoplace();
  641. case FDC_PRIVATE: return field.IsPrivate();
  642. default:
  643. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  644. return false;
  645. }
  646. }
  647. void FIELDS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue )
  648. {
  649. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  650. SCH_FIELD& field = getField( aRow );
  651. VECTOR2I pos;
  652. wxString value = aValue;
  653. switch( aCol )
  654. {
  655. case FDC_TEXT_SIZE:
  656. case FDC_POSX:
  657. case FDC_POSY:
  658. m_eval->SetDefaultUnits( m_frame->GetUserUnits() );
  659. if( m_eval->Process( value ) )
  660. {
  661. m_evalOriginal[ { aRow, aCol } ] = value;
  662. value = m_eval->Result();
  663. }
  664. break;
  665. default:
  666. break;
  667. }
  668. switch( aCol )
  669. {
  670. case FDC_NAME:
  671. field.SetName( value );
  672. break;
  673. case FDC_VALUE:
  674. {
  675. if( m_parentType == SCH_SHEET_T && field.GetId() == FIELD_T::SHEET_FILENAME )
  676. {
  677. value = EnsureFileExtension( value, FILEEXT::KiCadSchematicFileExtension );
  678. }
  679. else if( m_parentType == LIB_SYMBOL_T && field.GetId() == FIELD_T::VALUE )
  680. {
  681. value = EscapeString( value, CTX_LIBID );
  682. }
  683. field.SetText( UnescapeString( value ) );
  684. break;
  685. }
  686. case FDC_SHOWN:
  687. field.SetVisible( BoolFromString( value ) );
  688. break;
  689. case FDC_SHOW_NAME:
  690. field.SetNameShown( BoolFromString( value ) );
  691. break;
  692. case FDC_H_ALIGN:
  693. {
  694. GR_TEXT_H_ALIGN_T horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
  695. if( value == _( "Left" ) )
  696. horizontalJustification = GR_TEXT_H_ALIGN_LEFT;
  697. else if( value == _( "Center" ) )
  698. horizontalJustification = GR_TEXT_H_ALIGN_CENTER;
  699. else if( value == _( "Right" ) )
  700. horizontalJustification = GR_TEXT_H_ALIGN_RIGHT;
  701. else
  702. wxFAIL_MSG( wxT( "unknown horizontal alignment: " ) + value );
  703. // Note that we must set justifications before we can ask if they're flipped. If the old
  704. // justification is center then it won't know (whereas if the new justification is center
  705. // the we don't care).
  706. field.SetHorizJustify( horizontalJustification );
  707. if( field.IsHorizJustifyFlipped() )
  708. field.SetHorizJustify( EDA_TEXT::MapHorizJustify( - horizontalJustification ) );
  709. break;
  710. }
  711. case FDC_V_ALIGN:
  712. {
  713. GR_TEXT_V_ALIGN_T verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
  714. if( value == _( "Top" ) )
  715. verticalJustification = GR_TEXT_V_ALIGN_TOP;
  716. else if( value == _( "Center" ) )
  717. verticalJustification = GR_TEXT_V_ALIGN_CENTER;
  718. else if( value == _( "Bottom" ) )
  719. verticalJustification = GR_TEXT_V_ALIGN_BOTTOM;
  720. else
  721. wxFAIL_MSG( wxT( "unknown vertical alignment: " ) + value);
  722. // Note that we must set justifications before we can ask if they're flipped. If the old
  723. // justification is center then it won't know (whereas if the new justification is center
  724. // the we don't care).
  725. field.SetVertJustify( verticalJustification );
  726. if( field.IsVertJustifyFlipped() )
  727. field.SetVertJustify( EDA_TEXT::MapVertJustify( -verticalJustification ) );
  728. break;
  729. }
  730. case FDC_ITALIC:
  731. field.SetItalic( BoolFromString( value ) );
  732. break;
  733. case FDC_BOLD:
  734. field.SetBold( BoolFromString( value ) );
  735. break;
  736. case FDC_TEXT_SIZE:
  737. field.SetTextSize( VECTOR2I( m_frame->ValueFromString( value ),
  738. m_frame->ValueFromString( value ) ) );
  739. break;
  740. case FDC_ORIENTATION:
  741. if( value == _( "Horizontal" ) )
  742. field.SetTextAngle( ANGLE_HORIZONTAL );
  743. else if( value == _( "Vertical" ) )
  744. field.SetTextAngle( ANGLE_VERTICAL );
  745. else
  746. wxFAIL_MSG( wxT( "unknown orientation: " ) + value );
  747. break;
  748. case FDC_POSX:
  749. case FDC_POSY:
  750. pos = field.GetTextPos();
  751. if( aCol == FDC_POSX )
  752. pos.x = m_frame->ValueFromString( value );
  753. else
  754. pos.y = m_frame->ValueFromString( value );
  755. field.SetTextPos( pos );
  756. break;
  757. case FDC_FONT:
  758. if( value == DEFAULT_FONT_NAME )
  759. field.SetFont( nullptr );
  760. else if( value == KICAD_FONT_NAME )
  761. field.SetFont( KIFONT::FONT::GetFont( wxEmptyString, field.IsBold(),
  762. field.IsItalic() ) );
  763. else
  764. field.SetFont( KIFONT::FONT::GetFont( aValue, field.IsBold(), field.IsItalic() ) );
  765. break;
  766. case FDC_COLOR:
  767. field.SetTextColor( wxColor( value ) );
  768. break;
  769. case FDC_ALLOW_AUTOPLACE:
  770. field.SetCanAutoplace( BoolFromString( value ) );
  771. break;
  772. case FDC_PRIVATE:
  773. field.SetPrivate( BoolFromString( value ) );
  774. break;
  775. default:
  776. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) );
  777. break;
  778. }
  779. m_dialog->OnModify();
  780. GetView()->Refresh();
  781. }
  782. void FIELDS_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue )
  783. {
  784. wxCHECK( aRow < GetNumberRows(), /*void*/ );
  785. SCH_FIELD& field = getField( aRow );
  786. switch( aCol )
  787. {
  788. case FDC_SHOWN:
  789. field.SetVisible( aValue );
  790. break;
  791. case FDC_SHOW_NAME:
  792. field.SetNameShown( aValue );
  793. break;
  794. case FDC_ITALIC:
  795. field.SetItalic( aValue );
  796. break;
  797. case FDC_BOLD:
  798. field.SetBold( aValue );
  799. break;
  800. case FDC_ALLOW_AUTOPLACE:
  801. field.SetCanAutoplace( aValue );
  802. break;
  803. case FDC_PRIVATE:
  804. field.SetPrivate( aValue );
  805. break;
  806. default:
  807. wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) );
  808. break;
  809. }
  810. m_dialog->OnModify();
  811. }
  812. wxString FIELDS_GRID_TABLE::StringFromBool( bool aValue ) const
  813. {
  814. if( aValue )
  815. return wxT( "1" );
  816. else
  817. return wxT( "0" );
  818. }
  819. bool FIELDS_GRID_TABLE::BoolFromString( const wxString& aValue ) const
  820. {
  821. if( aValue == wxS( "1" ) )
  822. {
  823. return true;
  824. }
  825. else if( aValue == wxS( "0" ) )
  826. {
  827. return false;
  828. }
  829. else
  830. {
  831. wxFAIL_MSG( wxString::Format( "string '%s' can't be converted to boolean correctly and "
  832. "will be perceived as FALSE", aValue ) );
  833. return false;
  834. }
  835. }
  836. SCH_FIELD* FIELDS_GRID_TABLE::GetField( FIELD_T aFieldId )
  837. {
  838. for( SCH_FIELD& field : *this )
  839. {
  840. if( field.GetId() == aFieldId )
  841. return &field;
  842. }
  843. return nullptr;
  844. }
  845. int FIELDS_GRID_TABLE::GetFieldRow( FIELD_T aFieldId )
  846. {
  847. for( int ii = 0; ii < (int) this->size(); ++ii )
  848. {
  849. if( this->at( ii ).GetId() == aFieldId )
  850. return ii;
  851. }
  852. return -1;
  853. }
  854. void FIELDS_GRID_TABLE::DetachFields()
  855. {
  856. for( SCH_FIELD& field : *this )
  857. field.SetParent( nullptr );
  858. }
  859. int FIELDS_GRID_TRICKS::getFieldRow( FIELD_T aFieldId )
  860. {
  861. return static_cast<FIELDS_GRID_TABLE*>( m_grid->GetTable() )->GetFieldRow( aFieldId );
  862. }
  863. void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent )
  864. {
  865. if( m_grid->GetGridCursorRow() == getFieldRow( FIELD_T::FOOTPRINT )
  866. && m_grid->GetGridCursorCol() == FDC_VALUE
  867. && !m_grid->IsReadOnly( getFieldRow( FIELD_T::FOOTPRINT ), FDC_VALUE ) )
  868. {
  869. menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
  870. _( "Browse for footprint" ) );
  871. menu.AppendSeparator();
  872. }
  873. else if( m_grid->GetGridCursorRow() == getFieldRow( FIELD_T::DATASHEET )
  874. && m_grid->GetGridCursorCol() == FDC_VALUE
  875. && !m_grid->IsReadOnly( getFieldRow( FIELD_T::DATASHEET ), FDC_VALUE ) )
  876. {
  877. menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
  878. _( "Show datasheet in browser" ) );
  879. menu.AppendSeparator();
  880. }
  881. GRID_TRICKS::showPopupMenu( menu, aEvent );
  882. }
  883. void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event )
  884. {
  885. if( event.GetId() == MYID_SELECT_FOOTPRINT )
  886. {
  887. // pick a footprint using the footprint picker.
  888. wxString fpid = m_grid->GetCellValue( getFieldRow( FIELD_T::FOOTPRINT ), FDC_VALUE );
  889. if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) )
  890. {
  891. if( frame->ShowModal( &fpid, m_dlg ) )
  892. m_grid->SetCellValue( getFieldRow( FIELD_T::FOOTPRINT ), FDC_VALUE, fpid );
  893. frame->Destroy();
  894. }
  895. }
  896. else if (event.GetId() == MYID_SHOW_DATASHEET )
  897. {
  898. wxString datasheet_uri = m_grid->GetCellValue( getFieldRow( FIELD_T::DATASHEET ), FDC_VALUE );
  899. GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj(), PROJECT_SCH::SchSearchS( &m_dlg->Prj() ),
  900. m_filesStack );
  901. }
  902. else
  903. {
  904. GRID_TRICKS::doPopupSelection( event );
  905. }
  906. }