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.
		
		
		
		
		
			
		
			
				
					
					
						
							1101 lines
						
					
					
						
							33 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							1101 lines
						
					
					
						
							33 KiB
						
					
					
				| /* | |
|  * This program source code file is part of KiCad, a free EDA CAD application. | |
|  * | |
|  * Copyright The KiCad Developers, see AUTHORS.txt for contributors. | |
|  * | |
|  * This program is free software; you can redistribute it and/or | |
|  * modify it under the terms of the GNU General Public License | |
|  * as published by the Free Software Foundation; either version 2 | |
|  * of the License, or (at your option) any later version. | |
|  * | |
|  * This program is distributed in the hope that it will be useful, | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | |
|  * GNU General Public License for more details. | |
|  * | |
|  * You should have received a copy of the GNU General Public License | |
|  * along with this program; if not, you may find one here: | |
|  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html | |
|  * or you may search the http://www.gnu.org website for the version 2 license, | |
|  * or you may write to the Free Software Foundation, Inc., | |
|  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA | |
|  */ | |
| 
 | |
| #include <embedded_files.h> | |
| #include <kiway.h> | |
| #include <kiway_player.h> | |
| #include <dialog_shim.h> | |
| #include <fields_grid_table.h> | |
| #include <sch_base_frame.h> | |
| #include <sch_field.h> | |
| #include <sch_label.h> | |
| #include <sch_validators.h> | |
| #include <validators.h> | |
| #include <sch_edit_frame.h> | |
| #include <symbol_library.h> | |
| #include <schematic.h> | |
| #include <template_fieldnames.h> | |
| #include <widgets/grid_text_button_helpers.h> | |
| #include <wildcards_and_files_ext.h> | |
| #include <project/project_file.h> | |
| #include <project/net_settings.h> | |
| #include "eda_doc.h" | |
| #include "widgets/grid_color_swatch_helpers.h" | |
| #include "font/fontconfig.h" | |
| #include "font/kicad_font_name.h" | |
| #include "widgets/grid_text_helpers.h" | |
| #include <wx/settings.h> | |
| #include <string_utils.h> | |
| #include <widgets/grid_combobox.h> | |
| #include <pgm_base.h> | |
| #include <project_sch.h> | |
|  | |
| 
 | |
| enum | |
| { | |
|     MYID_SELECT_FOOTPRINT = GRIDTRICKS_FIRST_CLIENT_ID, | |
|     MYID_SHOW_DATASHEET | |
| }; | |
| 
 | |
| 
 | |
| #define DEFAULT_FONT_NAME _( "Default Font" ) | |
|  | |
| 
 | |
| static wxString netList( SCH_SYMBOL* aSymbol, SCH_SHEET_PATH& aSheetPath ) | |
| { | |
|     /* | |
|      * Symbol netlist format: | |
|      *   pinNumber pinName <tab> pinNumber pinName... | |
|      *   fpFilter fpFilter... | |
|      */ | |
|     wxString netlist; | |
| 
 | |
|     // We need the list of pins of the lib symbol, not just the pins of the current | |
|     // sch symbol, that can be just an unit of a multi-unit symbol, to be able to | |
|     // select/filter right footprints | |
|     wxArrayString pins; | |
| 
 | |
|     const std::unique_ptr< LIB_SYMBOL >& lib_symbol = aSymbol->GetLibSymbolRef(); | |
| 
 | |
|     if( lib_symbol ) | |
|     { | |
|         for( SCH_PIN* pin : lib_symbol->GetPins( 0 /* all units */, 1 /* single bodyStyle */ ) ) | |
|             pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() ); | |
|     } | |
| 
 | |
|     if( !pins.IsEmpty() ) | |
|         netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE ); | |
| 
 | |
|     netlist << wxS( "\r" ); | |
| 
 | |
|     if( lib_symbol ) | |
|     { | |
|         wxArrayString fpFilters = lib_symbol->GetFPFilters(); | |
| 
 | |
|         if( !fpFilters.IsEmpty() ) | |
|             netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE ); | |
|     } | |
| 
 | |
|     netlist << wxS( "\r" ); | |
| 
 | |
|     return netlist; | |
| } | |
| 
 | |
| 
 | |
| static wxString netList( LIB_SYMBOL* aSymbol ) | |
| { | |
|     /* | |
|      * Symbol netlist format: | |
|      *   pinNumber pinName <tab> pinNumber pinName... | |
|      *   fpFilter fpFilter... | |
|      */ | |
|     wxString      netlist; | |
|     wxArrayString pins; | |
| 
 | |
|     for( SCH_PIN* pin : aSymbol->GetPins( 0 /* all units */, 1 /* single bodyStyle */ ) ) | |
|         pins.push_back( pin->GetNumber() + ' ' + pin->GetShownName() ); | |
| 
 | |
|     if( !pins.IsEmpty() ) | |
|         netlist << EscapeString( wxJoin( pins, '\t' ), CTX_LINE ); | |
| 
 | |
|     netlist << wxS( "\r" ); | |
| 
 | |
|     wxArrayString fpFilters = aSymbol->GetFPFilters(); | |
| 
 | |
|     if( !fpFilters.IsEmpty() ) | |
|         netlist << EscapeString( wxJoin( fpFilters, ' ' ), CTX_LINE ); | |
| 
 | |
|     netlist << wxS( "\r" ); | |
| 
 | |
|     return netlist; | |
| } | |
| 
 | |
| 
 | |
| FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_BASE_FRAME* aFrame, WX_GRID* aGrid, | |
|                                       LIB_SYMBOL* aSymbol, std::vector<EMBEDDED_FILES*> aFilesStack ) : | |
|         m_frame( aFrame ), | |
|         m_dialog( aDialog ), | |
|         m_parentType( SCH_SYMBOL_T ), | |
|         m_part( aSymbol ), | |
|         m_filesStack( aFilesStack ), | |
|         m_symbolNetlist( netList( aSymbol ) ), | |
|         m_fieldNameValidator( FIELD_NAME ), | |
|         m_referenceValidator( REFERENCE_FIELD ), | |
|         m_valueValidator( VALUE_FIELD ), | |
|         m_urlValidator( FIELD_VALUE ), | |
|         m_nonUrlValidator( FIELD_VALUE ), | |
|         m_filepathValidator( SHEETFILENAME ) | |
| { | |
|     initGrid( aGrid ); | |
| } | |
| 
 | |
| 
 | |
| FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid, | |
|                                       SCH_SYMBOL* aSymbol ) : | |
|         m_frame( aFrame ), | |
|         m_dialog( aDialog ), | |
|         m_parentType( SCH_SYMBOL_T ), | |
|         m_part( aSymbol->GetLibSymbolRef().get() ), | |
|         m_symbolNetlist( netList( aSymbol, aFrame->GetCurrentSheet() ) ), | |
|         m_fieldNameValidator( FIELD_NAME ), | |
|         m_referenceValidator( REFERENCE_FIELD ), | |
|         m_valueValidator( VALUE_FIELD ), | |
|         m_urlValidator( FIELD_VALUE ), | |
|         m_nonUrlValidator( FIELD_VALUE ), | |
|         m_filepathValidator( SHEETFILENAME ) | |
| { | |
|     m_filesStack.push_back( aSymbol->Schematic() ); | |
| 
 | |
|     if( m_part ) | |
|         m_filesStack.push_back( m_part ); | |
| 
 | |
|     initGrid( aGrid ); | |
| } | |
| 
 | |
| 
 | |
| FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid, | |
|                                       SCH_SHEET* aSheet ) : | |
|         m_frame( aFrame ), | |
|         m_dialog( aDialog ), | |
|         m_parentType( SCH_SHEET_T ), | |
|         m_part( nullptr ), | |
|         m_fieldNameValidator( FIELD_NAME ), | |
|         m_referenceValidator( SHEETNAME_V ), | |
|         m_valueValidator( VALUE_FIELD ), | |
|         m_urlValidator( FIELD_VALUE ), | |
|         m_nonUrlValidator( FIELD_VALUE ), | |
|         m_filepathValidator( SHEETFILENAME_V ) | |
| { | |
|     m_filesStack.push_back( aSheet->Schematic() ); | |
| 
 | |
|     initGrid( aGrid ); | |
| } | |
| 
 | |
| 
 | |
| FIELDS_GRID_TABLE::FIELDS_GRID_TABLE( DIALOG_SHIM* aDialog, SCH_EDIT_FRAME* aFrame, WX_GRID* aGrid, | |
|                                       SCH_LABEL_BASE* aLabel ) : | |
|         m_frame( aFrame ), | |
|         m_dialog( aDialog ), | |
|         m_parentType( SCH_LABEL_LOCATE_ANY_T ), | |
|         m_part( nullptr ), | |
|         m_fieldNameValidator( FIELD_NAME ), | |
|         m_referenceValidator( 0 ), | |
|         m_valueValidator( 0 ), | |
|         m_urlValidator( FIELD_VALUE ), | |
|         m_nonUrlValidator( FIELD_VALUE ), | |
|         m_filepathValidator( 0 ) | |
| { | |
|     m_filesStack.push_back( aLabel->Schematic() ); | |
| 
 | |
|     initGrid( aGrid ); | |
| } | |
| 
 | |
| 
 | |
| int FIELDS_GRID_TABLE::GetMandatoryRowCount() const | |
| { | |
|     int mandatoryRows = 0; | |
| 
 | |
|     for( const SCH_FIELD& field : *this ) | |
|     { | |
|         if( field.IsMandatory() ) | |
|             mandatoryRows++; | |
|     } | |
| 
 | |
|     return mandatoryRows; | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TABLE::initGrid( WX_GRID* aGrid ) | |
| { | |
|     // Build the various grid cell attributes. | |
|     // NOTE: validators and cellAttrs are member variables to get the destruction order | |
|     // right.  wxGrid is VERY cranky about this. | |
|  | |
|     m_readOnlyAttr = new wxGridCellAttr; | |
|     m_readOnlyAttr->SetReadOnly( true ); | |
| 
 | |
|     m_fieldNameAttr = new wxGridCellAttr; | |
|     GRID_CELL_TEXT_EDITOR* nameEditor = new GRID_CELL_TEXT_EDITOR(); | |
|     nameEditor->SetValidator( m_fieldNameValidator ); | |
|     m_fieldNameAttr->SetEditor( nameEditor ); | |
| 
 | |
|     m_referenceAttr = new wxGridCellAttr; | |
|     GRID_CELL_TEXT_EDITOR* referenceEditor = new GRID_CELL_TEXT_EDITOR(); | |
|     referenceEditor->SetValidator( m_referenceValidator ); | |
|     m_referenceAttr->SetEditor( referenceEditor ); | |
| 
 | |
|     m_valueAttr = new wxGridCellAttr; | |
| 
 | |
|     if( m_parentType == LIB_SYMBOL_T ) | |
|     { | |
|         GRID_CELL_TEXT_EDITOR* valueEditor = new GRID_CELL_TEXT_EDITOR(); | |
|         valueEditor->SetValidator( m_valueValidator ); | |
|         m_valueAttr->SetEditor( valueEditor ); | |
|     } | |
|     else | |
|     { | |
|         GRID_CELL_STC_EDITOR* valueEditor = new GRID_CELL_STC_EDITOR( true, true, | |
|                 [this]( wxStyledTextEvent& aEvent, SCINTILLA_TRICKS* aScintillaTricks ) | |
|                 { | |
|                     SCH_FIELD& valueField = static_cast<SCH_FIELD&>( this->at( VALUE_FIELD ) ); | |
|                     valueField.OnScintillaCharAdded( aScintillaTricks, aEvent ); | |
|                 } ); | |
| 
 | |
|         m_valueAttr->SetEditor( valueEditor ); | |
|     } | |
| 
 | |
|     m_footprintAttr = new wxGridCellAttr; | |
|     GRID_CELL_FPID_EDITOR* fpIdEditor = new GRID_CELL_FPID_EDITOR( m_dialog, m_symbolNetlist ); | |
|     fpIdEditor->SetValidator( m_nonUrlValidator ); | |
|     m_footprintAttr->SetEditor( fpIdEditor ); | |
| 
 | |
|     m_urlAttr = new wxGridCellAttr; | |
|     SEARCH_STACK* prjSearchStack = PROJECT_SCH::SchSearchS( &m_frame->Prj() ); | |
|     GRID_CELL_URL_EDITOR* urlEditor = new GRID_CELL_URL_EDITOR( m_dialog, prjSearchStack, m_filesStack ); | |
|     urlEditor->SetValidator( m_urlValidator ); | |
|     m_urlAttr->SetEditor( urlEditor ); | |
| 
 | |
|     m_nonUrlAttr = new wxGridCellAttr; | |
|     GRID_CELL_TEXT_EDITOR* nonUrlEditor = new GRID_CELL_TEXT_EDITOR(); | |
|     nonUrlEditor->SetValidator( m_nonUrlValidator ); | |
|     m_nonUrlAttr->SetEditor( nonUrlEditor ); | |
| 
 | |
|     m_curdir = m_frame->Prj().GetProjectPath(); | |
|     m_filepathAttr = new wxGridCellAttr; | |
| 
 | |
|     // Create a wild card using wxFileDialog syntax. | |
|     wxString wildCard( _( "Schematic Files" ) ); | |
|     std::vector<std::string> exts; | |
|     exts.push_back( FILEEXT::KiCadSchematicFileExtension ); | |
|     wildCard += AddFileExtListToFilter( exts ); | |
| 
 | |
|     auto filepathEditor = new GRID_CELL_PATH_EDITOR( m_dialog, aGrid, &m_curdir, wildCard ); | |
|     filepathEditor->SetValidator( m_filepathValidator ); | |
|     m_filepathAttr->SetEditor( filepathEditor ); | |
| 
 | |
|     m_boolAttr = new wxGridCellAttr; | |
|     m_boolAttr->SetRenderer( new wxGridCellBoolRenderer() ); | |
|     m_boolAttr->SetEditor( new wxGridCellBoolEditor() ); | |
|     m_boolAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); | |
| 
 | |
|     wxArrayString vAlignNames; | |
|     vAlignNames.Add( _( "Top" ) ); | |
|     vAlignNames.Add( _( "Center" ) ); | |
|     vAlignNames.Add( _( "Bottom" ) ); | |
|     m_vAlignAttr = new wxGridCellAttr; | |
|     m_vAlignAttr->SetEditor( new wxGridCellChoiceEditor( vAlignNames ) ); | |
|     m_vAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); | |
| 
 | |
|     wxArrayString hAlignNames; | |
|     hAlignNames.Add( _( "Left" ) ); | |
|     hAlignNames.Add(_( "Center" ) ); | |
|     hAlignNames.Add(_( "Right" ) ); | |
|     m_hAlignAttr = new wxGridCellAttr; | |
|     m_hAlignAttr->SetEditor( new wxGridCellChoiceEditor( hAlignNames ) ); | |
|     m_hAlignAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); | |
| 
 | |
|     wxArrayString orientationNames; | |
|     orientationNames.Add( _( "Horizontal" ) ); | |
|     orientationNames.Add(_( "Vertical" ) ); | |
|     m_orientationAttr = new wxGridCellAttr; | |
|     m_orientationAttr->SetEditor( new wxGridCellChoiceEditor( orientationNames ) ); | |
|     m_orientationAttr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); | |
| 
 | |
|     SCH_EDIT_FRAME* editFrame = dynamic_cast<SCH_EDIT_FRAME*>( m_frame ); | |
|     wxArrayString   existingNetclasses; | |
| 
 | |
|     wxArrayString            fonts; | |
|     std::vector<std::string> fontNames; | |
| 
 | |
|     if( editFrame ) | |
|     { | |
|         // Load the combobox with existing existingNetclassNames | |
|         PROJECT_FILE&                        projectFile = editFrame->Prj().GetProjectFile(); | |
|         const std::shared_ptr<NET_SETTINGS>& settings = projectFile.NetSettings(); | |
| 
 | |
|         existingNetclasses.push_back( settings->GetDefaultNetclass()->GetName() ); | |
| 
 | |
|         for( const auto& [name, netclass] : settings->GetNetclasses() ) | |
|             existingNetclasses.push_back( name ); | |
| 
 | |
|         // We don't need to re-cache the embedded fonts when looking at symbols in the schematic | |
|         // editor because the fonts are all available in the schematic. | |
|         const std::vector<wxString>* fontFiles = nullptr; | |
| 
 | |
|         if( m_frame->GetScreen() && m_frame->GetScreen()->Schematic() ) | |
|             fontFiles = m_frame->GetScreen()->Schematic()->GetEmbeddedFiles()->GetFontFiles(); | |
| 
 | |
|         Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ), | |
|                                  fontFiles, false ); | |
|     } | |
|     else | |
|     { | |
|         const std::vector<wxString>* fontFiles = m_part->GetEmbeddedFiles()->UpdateFontFiles(); | |
| 
 | |
|         // If there are font files embedded, we want to re-cache our fonts for each symbol that | |
|         // we are looking at in the symbol editor. | |
|         Fontconfig()->ListFonts( fontNames, std::string( Pgm().GetLanguageTag().utf8_str() ), | |
|                                  fontFiles, !fontFiles->empty() ); | |
|     } | |
| 
 | |
|     m_netclassAttr = new wxGridCellAttr; | |
|     m_netclassAttr->SetEditor( new GRID_CELL_COMBOBOX( existingNetclasses ) ); | |
| 
 | |
|     for( const std::string& name : fontNames ) | |
|         fonts.Add( wxString( name ) ); | |
| 
 | |
|     fonts.Sort(); | |
|     fonts.Insert( KICAD_FONT_NAME, 0 ); | |
|     fonts.Insert( DEFAULT_FONT_NAME, 0 ); | |
| 
 | |
|     m_fontAttr = new wxGridCellAttr; | |
|     m_fontAttr->SetEditor( new GRID_CELL_COMBOBOX( fonts ) ); | |
| 
 | |
|     m_colorAttr = new wxGridCellAttr; | |
|     m_colorAttr->SetRenderer( new GRID_CELL_COLOR_RENDERER( m_dialog ) ); | |
|     m_colorAttr->SetEditor( new GRID_CELL_COLOR_SELECTOR( m_dialog, aGrid ) ); | |
| 
 | |
|     m_eval = std::make_unique<NUMERIC_EVALUATOR>( m_frame->GetUserUnits() ); | |
| 
 | |
|     m_frame->Bind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this ); | |
| } | |
| 
 | |
| 
 | |
| FIELDS_GRID_TABLE::~FIELDS_GRID_TABLE() | |
| { | |
|     m_readOnlyAttr->DecRef(); | |
|     m_fieldNameAttr->DecRef(); | |
|     m_boolAttr->DecRef(); | |
|     m_referenceAttr->DecRef(); | |
|     m_valueAttr->DecRef(); | |
|     m_footprintAttr->DecRef(); | |
|     m_urlAttr->DecRef(); | |
|     m_nonUrlAttr->DecRef(); | |
|     m_filepathAttr->DecRef(); | |
|     m_vAlignAttr->DecRef(); | |
|     m_hAlignAttr->DecRef(); | |
|     m_orientationAttr->DecRef(); | |
|     m_netclassAttr->DecRef(); | |
|     m_fontAttr->DecRef(); | |
|     m_colorAttr->DecRef(); | |
| 
 | |
|     m_frame->Unbind( EDA_EVT_UNITS_CHANGED, &FIELDS_GRID_TABLE::onUnitsChanged, this ); | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TABLE::onUnitsChanged( wxCommandEvent& aEvent ) | |
| { | |
|     if( GetView() ) | |
|         GetView()->ForceRefresh(); | |
| 
 | |
|     aEvent.Skip(); | |
| } | |
| 
 | |
| 
 | |
| int FIELDS_GRID_TABLE::getColumnCount() const | |
| { | |
|     if( m_frame->GetFrameType() == FRAME_SCH | |
|         || m_frame->GetFrameType() == FRAME_SCH_VIEWER ) | |
|     { | |
|         return FDC_SCH_EDIT_COUNT; | |
|     } | |
|     else | |
|     { | |
|         return FDC_SYMBOL_EDITOR_COUNT; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| int FIELDS_GRID_TABLE::getVisibleRowCount() const | |
| { | |
|     if( m_frame->GetFrameType() == FRAME_SCH | |
|         || m_frame->GetFrameType() == FRAME_SCH_VIEWER ) | |
|     { | |
|         int visibleRows = 0; | |
| 
 | |
|         for( const SCH_FIELD& field : *this ) | |
|         { | |
|             if( !field.IsPrivate() ) | |
|                 visibleRows++; | |
|         } | |
| 
 | |
|         return visibleRows; | |
|     } | |
| 
 | |
|     return (int) this->size(); | |
| } | |
| 
 | |
| 
 | |
| SCH_FIELD& FIELDS_GRID_TABLE::getField( int aRow ) | |
| { | |
|     if( m_frame->GetFrameType() == FRAME_SCH | |
|         || m_frame->GetFrameType() == FRAME_SCH_VIEWER ) | |
|     { | |
|         int visibleRow = 0; | |
| 
 | |
|         for( SCH_FIELD& field : *this ) | |
|         { | |
|             if( field.IsPrivate() ) | |
|                 continue; | |
| 
 | |
|             if( visibleRow == aRow ) | |
|                 return field; | |
| 
 | |
|             ++visibleRow; | |
|         } | |
| 
 | |
|         wxFAIL_MSG( wxT( "Row index off end of visible row count" ) ); | |
|     } | |
| 
 | |
|     return this->at( aRow ); | |
| } | |
| 
 | |
| 
 | |
| wxString FIELDS_GRID_TABLE::GetColLabelValue( int aCol ) | |
| { | |
|     switch( aCol ) | |
|     { | |
|     case FDC_NAME:            return _( "Name" ); | |
|     case FDC_VALUE:           return _( "Value" ); | |
|     case FDC_SHOWN:           return _( "Show" ); | |
|     case FDC_SHOW_NAME:       return _( "Show Name" ); | |
|     case FDC_H_ALIGN:         return _( "H Align" ); | |
|     case FDC_V_ALIGN:         return _( "V Align" ); | |
|     case FDC_ITALIC:          return _( "Italic" ); | |
|     case FDC_BOLD:            return _( "Bold" ); | |
|     case FDC_TEXT_SIZE:       return _( "Text Size" ); | |
|     case FDC_ORIENTATION:     return _( "Orientation" ); | |
|     case FDC_POSX:            return _( "X Position" ); | |
|     case FDC_POSY:            return _( "Y Position" ); | |
|     case FDC_FONT:            return _( "Font" ); | |
|     case FDC_COLOR:           return _( "Color" ); | |
|     case FDC_ALLOW_AUTOPLACE: return _( "Allow Autoplacement" ); | |
|     case FDC_PRIVATE:         return _( "Private" ); | |
|     default:      wxFAIL;     return wxEmptyString; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| bool FIELDS_GRID_TABLE::CanGetValueAs( int aRow, int aCol, const wxString& aTypeName ) | |
| { | |
|     switch( aCol ) | |
|     { | |
|     case FDC_NAME: | |
|     case FDC_VALUE: | |
|     case FDC_H_ALIGN: | |
|     case FDC_V_ALIGN: | |
|     case FDC_TEXT_SIZE: | |
|     case FDC_ORIENTATION: | |
|     case FDC_POSX: | |
|     case FDC_POSY: | |
|     case FDC_FONT: | |
|     case FDC_COLOR: | |
|         return aTypeName == wxGRID_VALUE_STRING; | |
| 
 | |
|     case FDC_SHOWN: | |
|     case FDC_SHOW_NAME: | |
|     case FDC_ITALIC: | |
|     case FDC_BOLD: | |
|     case FDC_ALLOW_AUTOPLACE: | |
|     case FDC_PRIVATE: | |
|         return aTypeName == wxGRID_VALUE_BOOL; | |
| 
 | |
|     default: | |
|         wxFAIL; | |
|         return false; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| bool FIELDS_GRID_TABLE::CanSetValueAs( int aRow, int aCol, const wxString& aTypeName ) | |
| { | |
|     return CanGetValueAs( aRow, aCol, aTypeName ); | |
| } | |
| 
 | |
| 
 | |
| wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind  ) | |
| { | |
|     wxCHECK( aRow < GetNumberRows(), nullptr ); | |
| 
 | |
|     const SCH_FIELD& field = getField( aRow ); | |
|     wxGridCellAttr*  tmp; | |
| 
 | |
|     switch( aCol ) | |
|     { | |
|     case FDC_NAME: | |
|         if( field.IsMandatory() ) | |
|         { | |
|             tmp = m_fieldNameAttr->Clone(); | |
|             tmp->SetReadOnly( true ); | |
|             return enhanceAttr( tmp, aRow, aCol, aKind ); | |
|         } | |
|         else | |
|         { | |
|             m_fieldNameAttr->IncRef(); | |
|             return enhanceAttr( m_fieldNameAttr, aRow, aCol, aKind ); | |
|         } | |
| 
 | |
|     case FDC_VALUE: | |
|         if( m_parentType == SCH_SYMBOL_T && field.GetId() == REFERENCE_FIELD ) | |
|         { | |
|             m_referenceAttr->IncRef(); | |
|             return enhanceAttr( m_referenceAttr, aRow, aCol, aKind ); | |
|         } | |
|         else if( m_parentType == SCH_SYMBOL_T && field.GetId() == VALUE_FIELD ) | |
|         { | |
|             m_valueAttr->IncRef(); | |
|             return enhanceAttr( m_valueAttr, aRow, aCol, aKind ); | |
|         } | |
|         else if( m_parentType == SCH_SYMBOL_T && field.GetId() == FOOTPRINT_FIELD ) | |
|         { | |
|             // Power symbols have do not appear in the board, so don't allow | |
|             // a footprint (m_part can be nullptr when loading a old schematic | |
|             // (for instance Kicad 4) with libraries missing) | |
|             if( m_part && m_part->IsPower() ) | |
|             { | |
|                 m_readOnlyAttr->IncRef(); | |
|                 return enhanceAttr( m_readOnlyAttr, aRow, aCol, aKind ); | |
|             } | |
|             else | |
|             { | |
|                 m_footprintAttr->IncRef(); | |
|                 return enhanceAttr( m_footprintAttr, aRow, aCol, aKind ); | |
|             } | |
|         } | |
|         else if( m_parentType == SCH_SYMBOL_T && field.GetId() == DATASHEET_FIELD ) | |
|         { | |
|             m_urlAttr->IncRef(); | |
|             return enhanceAttr( m_urlAttr, aRow, aCol, aKind ); | |
|         } | |
|         else if( m_parentType == SCH_SHEET_T && field.GetId() == SHEETNAME ) | |
|         { | |
|             m_referenceAttr->IncRef(); | |
|             return enhanceAttr( m_referenceAttr, aRow, aCol, aKind ); | |
|         } | |
|         else if( m_parentType == SCH_SHEET_T && field.GetId() == SHEETFILENAME ) | |
|         { | |
|             m_filepathAttr->IncRef(); | |
|             return enhanceAttr( m_filepathAttr, aRow, aCol, aKind ); | |
|         } | |
|         else if( ( m_parentType == SCH_LABEL_LOCATE_ANY_T ) | |
|                 && field.GetCanonicalName() == wxT( "Netclass" ) ) | |
|         { | |
|             m_netclassAttr->IncRef(); | |
|             return enhanceAttr( m_netclassAttr, aRow, aCol, aKind ); | |
|         } | |
|         else | |
|         { | |
|             wxString fn = GetValue( aRow, FDC_NAME ); | |
| 
 | |
|             SCHEMATIC_SETTINGS* settings = m_frame->Prj().GetProjectFile().m_SchematicSettings; | |
| 
 | |
|             const TEMPLATE_FIELDNAME* templateFn = | |
|                     settings ? settings->m_TemplateFieldNames.GetFieldName( fn ) : nullptr; | |
| 
 | |
|             if( ( templateFn && templateFn->m_URL ) || field.IsHypertext() ) | |
|             { | |
|                 m_urlAttr->IncRef(); | |
|                 return enhanceAttr( m_urlAttr, aRow, aCol, aKind ); | |
|             } | |
|             else | |
|             { | |
|                 m_nonUrlAttr->IncRef(); | |
|                 return enhanceAttr( m_nonUrlAttr, aRow, aCol, aKind ); | |
|             } | |
|         } | |
| 
 | |
|     case FDC_TEXT_SIZE: | |
|     case FDC_POSX: | |
|     case FDC_POSY: | |
|         return enhanceAttr( nullptr, aRow, aCol, aKind ); | |
| 
 | |
|     case FDC_H_ALIGN: | |
|         m_hAlignAttr->IncRef(); | |
|         return enhanceAttr( m_hAlignAttr, aRow, aCol, aKind ); | |
| 
 | |
|     case FDC_V_ALIGN: | |
|         m_vAlignAttr->IncRef(); | |
|         return enhanceAttr( m_vAlignAttr, aRow, aCol, aKind ); | |
| 
 | |
|     case FDC_ORIENTATION: | |
|         m_orientationAttr->IncRef(); | |
|         return enhanceAttr( m_orientationAttr, aRow, aCol, aKind ); | |
| 
 | |
|     case FDC_SHOWN: | |
|     case FDC_SHOW_NAME: | |
|     case FDC_ITALIC: | |
|     case FDC_BOLD: | |
|     case FDC_ALLOW_AUTOPLACE: | |
|     case FDC_PRIVATE: | |
|         m_boolAttr->IncRef(); | |
|         return enhanceAttr( m_boolAttr, aRow, aCol, aKind ); | |
| 
 | |
|     case FDC_FONT: | |
|         m_fontAttr->IncRef(); | |
|         return enhanceAttr( m_fontAttr, aRow, aCol, aKind ); | |
| 
 | |
|     case FDC_COLOR: | |
|         m_colorAttr->IncRef(); | |
|         return enhanceAttr( m_colorAttr, aRow, aCol, aKind ); | |
| 
 | |
|     default: | |
|         wxFAIL; | |
|         return enhanceAttr( nullptr, aRow, aCol, aKind ); | |
|     } | |
| } | |
| 
 | |
| 
 | |
| wxString FIELDS_GRID_TABLE::GetValue( int aRow, int aCol ) | |
| { | |
|     wxCHECK( aRow < GetNumberRows(), wxEmptyString ); | |
| 
 | |
|     wxGrid*          grid = GetView(); | |
|     const SCH_FIELD& field = getField( aRow ); | |
| 
 | |
|     if( grid->GetGridCursorRow() == aRow && grid->GetGridCursorCol() == aCol | |
|             && grid->IsCellEditControlShown() ) | |
|     { | |
|         auto it = m_evalOriginal.find( { aRow, aCol } ); | |
| 
 | |
|         if( it != m_evalOriginal.end() ) | |
|             return it->second; | |
|     } | |
| 
 | |
|     switch( aCol ) | |
|     { | |
|     case FDC_NAME: | |
|         // Use default field names for mandatory and system fields because they are translated | |
|         // according to the current locale | |
|         if( m_parentType == SCH_SYMBOL_T || m_parentType == LIB_SYMBOL_T ) | |
|         { | |
|             if( field.IsMandatory() ) | |
|                 return GetDefaultFieldName( aRow, DO_TRANSLATE ); | |
|             else | |
|                 return field.GetName( false ); | |
|         } | |
|         else if( m_parentType == SCH_SHEET_T ) | |
|         { | |
|             if( field.IsMandatory() ) | |
|                 return SCH_SHEET::GetDefaultFieldName( field.GetId(), DO_TRANSLATE ); | |
|             else | |
|                 return field.GetName( false ); | |
|         } | |
|         else if( m_parentType == SCH_LABEL_LOCATE_ANY_T ) | |
|         { | |
|             return SCH_LABEL_BASE::GetDefaultFieldName( field.GetCanonicalName(), false ); | |
|         } | |
|         else | |
|         { | |
|             wxFAIL_MSG( wxS( "Unhandled field owner type." ) ); | |
|             return field.GetName( false ); | |
|         } | |
| 
 | |
|     case FDC_VALUE: | |
|         return EscapeString( UnescapeString( field.GetText() ), CTX_LINE ); | |
| 
 | |
|     case FDC_SHOWN: | |
|         return StringFromBool( field.IsVisible() ); | |
| 
 | |
|     case FDC_SHOW_NAME: | |
|         return StringFromBool( field.IsNameShown() ); | |
| 
 | |
|     case FDC_H_ALIGN: | |
|         switch ( field.GetEffectiveHorizJustify() ) | |
|         { | |
|         case GR_TEXT_H_ALIGN_LEFT:          return _( "Left" ); | |
|         case GR_TEXT_H_ALIGN_CENTER:        return _( "Center" ); | |
|         case GR_TEXT_H_ALIGN_RIGHT:         return _( "Right" ); | |
|         case GR_TEXT_H_ALIGN_INDETERMINATE: return INDETERMINATE_STATE; | |
|         } | |
| 
 | |
|         break; | |
| 
 | |
|     case FDC_V_ALIGN: | |
|         switch ( field.GetEffectiveVertJustify() ) | |
|         { | |
|         case GR_TEXT_V_ALIGN_TOP:           return _( "Top" ); | |
|         case GR_TEXT_V_ALIGN_CENTER:        return _( "Center" ); | |
|         case GR_TEXT_V_ALIGN_BOTTOM:        return _( "Bottom" ); | |
|         case GR_TEXT_V_ALIGN_INDETERMINATE: return INDETERMINATE_STATE; | |
|         } | |
| 
 | |
|         break; | |
| 
 | |
|     case FDC_ITALIC: | |
|         return StringFromBool( field.IsItalic() ); | |
| 
 | |
|     case FDC_BOLD: | |
|         return StringFromBool( field.IsBold() ); | |
| 
 | |
|     case FDC_TEXT_SIZE: | |
|         return m_frame->StringFromValue( field.GetTextHeight(), true ); | |
| 
 | |
|     case FDC_ORIENTATION: | |
|         if( field.GetTextAngle().IsHorizontal() ) | |
|             return _( "Horizontal" ); | |
|         else | |
|             return _( "Vertical" ); | |
| 
 | |
|     case FDC_POSX: | |
|         return m_frame->StringFromValue( field.GetTextPos().x, true ); | |
| 
 | |
|     case FDC_POSY: | |
|         return m_frame->StringFromValue( field.GetTextPos().y, true ); | |
| 
 | |
|     case FDC_FONT: | |
|         if( field.GetFont() ) | |
|             return field.GetFont()->GetName(); | |
|         else | |
|             return DEFAULT_FONT_NAME; | |
| 
 | |
|     case FDC_COLOR: | |
|         return field.GetTextColor().ToCSSString(); | |
| 
 | |
|     case FDC_ALLOW_AUTOPLACE: | |
|         return StringFromBool( field.CanAutoplace() ); | |
| 
 | |
|     case FDC_PRIVATE: | |
|         return StringFromBool( field.IsPrivate() ); | |
| 
 | |
|     default: | |
|         // we can't assert here because wxWidgets sometimes calls this without checking | |
|         // the column type when trying to see if there's an overflow | |
|         break; | |
|     } | |
| 
 | |
|     return wxT( "bad wxWidgets!" ); | |
| } | |
| 
 | |
| 
 | |
| bool FIELDS_GRID_TABLE::GetValueAsBool( int aRow, int aCol ) | |
| { | |
|     wxCHECK( aRow < GetNumberRows(), false ); | |
|     const SCH_FIELD& field = getField( aRow ); | |
| 
 | |
|     switch( aCol ) | |
|     { | |
|     case FDC_SHOWN:           return field.IsVisible(); | |
|     case FDC_SHOW_NAME:       return field.IsNameShown(); | |
|     case FDC_ITALIC:          return field.IsItalic(); | |
|     case FDC_BOLD:            return field.IsBold(); | |
|     case FDC_ALLOW_AUTOPLACE: return field.CanAutoplace(); | |
|     case FDC_PRIVATE:         return field.IsPrivate(); | |
|     default: | |
|         wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) ); | |
|         return false; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TABLE::SetValue( int aRow, int aCol, const wxString &aValue ) | |
| { | |
|     wxCHECK( aRow < GetNumberRows(), /*void*/ ); | |
|     SCH_FIELD& field = getField( aRow ); | |
|     VECTOR2I   pos; | |
|     wxString   value = aValue; | |
| 
 | |
|     switch( aCol ) | |
|     { | |
|     case FDC_TEXT_SIZE: | |
|     case FDC_POSX: | |
|     case FDC_POSY: | |
|         m_eval->SetDefaultUnits( m_frame->GetUserUnits() ); | |
| 
 | |
|         if( m_eval->Process( value ) ) | |
|         { | |
|             m_evalOriginal[ { aRow, aCol } ] = value; | |
|             value = m_eval->Result(); | |
|         } | |
| 
 | |
|         break; | |
| 
 | |
|     default: | |
|         break; | |
|     } | |
| 
 | |
|     switch( aCol ) | |
|     { | |
|     case FDC_NAME: | |
|         field.SetName( value ); | |
|         break; | |
| 
 | |
|     case FDC_VALUE: | |
|     { | |
|         if( m_parentType == SCH_SHEET_T && field.GetId() == SHEETFILENAME ) | |
|         { | |
|             value = EnsureFileExtension( value, FILEEXT::KiCadSchematicFileExtension ); | |
|         } | |
|         else if( m_parentType == LIB_SYMBOL_T && field.GetId() == VALUE_FIELD ) | |
|         { | |
|             value = EscapeString( value, CTX_LIBID ); | |
|         } | |
| 
 | |
|         field.SetText( UnescapeString( value ) ); | |
|         break; | |
|     } | |
| 
 | |
|     case FDC_SHOWN: | |
|         field.SetVisible( BoolFromString( value ) ); | |
|         break; | |
| 
 | |
|     case FDC_SHOW_NAME: | |
|         field.SetNameShown( BoolFromString( value ) ); | |
|         break; | |
| 
 | |
|     case FDC_H_ALIGN: | |
|     { | |
|         GR_TEXT_H_ALIGN_T horizontalJustification = GR_TEXT_H_ALIGN_CENTER; | |
| 
 | |
|         if( value == _( "Left" ) ) | |
|             horizontalJustification = GR_TEXT_H_ALIGN_LEFT; | |
|         else if( value == _( "Center" ) ) | |
|             horizontalJustification = GR_TEXT_H_ALIGN_CENTER; | |
|         else if( value == _( "Right" ) ) | |
|             horizontalJustification = GR_TEXT_H_ALIGN_RIGHT; | |
| 
 | |
|         // Note that we must set justifications before we can ask if they're flipped.  If the old | |
|         // justification is center then it won't know (whereas if the new justification is center | |
|         // the we don't care). | |
|         field.SetHorizJustify( horizontalJustification ); | |
| 
 | |
|         if( field.IsHorizJustifyFlipped() ) | |
|             field.SetHorizJustify( EDA_TEXT::MapHorizJustify( - horizontalJustification ) ); | |
| 
 | |
|         break; | |
|     } | |
| 
 | |
|     case FDC_V_ALIGN: | |
|     { | |
|         GR_TEXT_V_ALIGN_T verticalJustification = GR_TEXT_V_ALIGN_BOTTOM; | |
| 
 | |
|         if( value == _( "Top" ) ) | |
|             verticalJustification = GR_TEXT_V_ALIGN_TOP; | |
|         else if( value == _( "Center" ) ) | |
|             verticalJustification = GR_TEXT_V_ALIGN_CENTER; | |
|         else if( value == _( "Bottom" ) ) | |
|             verticalJustification = GR_TEXT_V_ALIGN_BOTTOM; | |
| 
 | |
|         // Note that we must set justifications before we can ask if they're flipped.  If the old | |
|         // justification is center then it won't know (whereas if the new justification is center | |
|         // the we don't care). | |
|         field.SetVertJustify( verticalJustification ); | |
| 
 | |
|         if( field.IsVertJustifyFlipped() ) | |
|             field.SetVertJustify( EDA_TEXT::MapVertJustify( -verticalJustification ) ); | |
| 
 | |
|         break; | |
|     } | |
| 
 | |
|     case FDC_ITALIC: | |
|         field.SetItalic( BoolFromString( value ) ); | |
|         break; | |
| 
 | |
|     case FDC_BOLD: | |
|         field.SetBold( BoolFromString( value ) ); | |
|         break; | |
| 
 | |
|     case FDC_TEXT_SIZE: | |
|         field.SetTextSize( VECTOR2I( m_frame->ValueFromString( value ), | |
|                                      m_frame->ValueFromString( value ) ) ); | |
|         break; | |
| 
 | |
|     case FDC_ORIENTATION: | |
|         if( value == _( "Horizontal" ) ) | |
|             field.SetTextAngle( ANGLE_HORIZONTAL ); | |
|         else if( value == _( "Vertical" ) ) | |
|             field.SetTextAngle( ANGLE_VERTICAL ); | |
|         else | |
|             wxFAIL_MSG( wxT( "unknown orientation: " ) + value ); | |
| 
 | |
|         break; | |
| 
 | |
|     case FDC_POSX: | |
|     case FDC_POSY: | |
|         pos = field.GetTextPos(); | |
| 
 | |
|         if( aCol == FDC_POSX ) | |
|             pos.x = m_frame->ValueFromString( value ); | |
|         else | |
|             pos.y = m_frame->ValueFromString( value ); | |
| 
 | |
|         field.SetTextPos( pos ); | |
|         break; | |
| 
 | |
|     case FDC_FONT: | |
|         if( value == DEFAULT_FONT_NAME ) | |
|             field.SetFont( nullptr ); | |
|         else if( value == KICAD_FONT_NAME ) | |
|             field.SetFont( KIFONT::FONT::GetFont( wxEmptyString, field.IsBold(), field.IsItalic() ) ); | |
|         else | |
|             field.SetFont( KIFONT::FONT::GetFont( aValue, field.IsBold(), field.IsItalic() ) ); | |
| 
 | |
|         break; | |
| 
 | |
|     case FDC_COLOR: | |
|         field.SetTextColor( wxColor( value ) ); | |
|         break; | |
| 
 | |
|     case FDC_ALLOW_AUTOPLACE: | |
|         field.SetCanAutoplace( BoolFromString( value ) ); | |
|         break; | |
| 
 | |
|     case FDC_PRIVATE: | |
|         field.SetPrivate( BoolFromString( value ) ); | |
|         break; | |
| 
 | |
|     default: | |
|         wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a string value" ), aCol ) ); | |
|         break; | |
|     } | |
| 
 | |
|     m_dialog->OnModify(); | |
| 
 | |
|     GetView()->Refresh(); | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TABLE::SetValueAsBool( int aRow, int aCol, bool aValue ) | |
| { | |
|     wxCHECK( aRow < GetNumberRows(), /*void*/ ); | |
|     SCH_FIELD& field = getField( aRow ); | |
| 
 | |
|     switch( aCol ) | |
|     { | |
|     case FDC_SHOWN: | |
|         field.SetVisible( aValue ); | |
|         break; | |
| 
 | |
|     case FDC_SHOW_NAME: | |
|         field.SetNameShown( aValue ); | |
|         break; | |
| 
 | |
|     case FDC_ITALIC: | |
|         field.SetItalic( aValue ); | |
|         break; | |
| 
 | |
|     case FDC_BOLD: | |
|         field.SetBold( aValue ); | |
|         break; | |
| 
 | |
|     case FDC_ALLOW_AUTOPLACE: | |
|         field.SetCanAutoplace( aValue ); | |
|         break; | |
| 
 | |
|     case FDC_PRIVATE: | |
|         field.SetPrivate( aValue ); | |
|         break; | |
| 
 | |
|     default: | |
|         wxFAIL_MSG( wxString::Format( wxT( "column %d doesn't hold a bool value" ), aCol ) ); | |
|         break; | |
|     } | |
| 
 | |
|     m_dialog->OnModify(); | |
| } | |
| 
 | |
| 
 | |
| wxString FIELDS_GRID_TABLE::StringFromBool( bool aValue ) const | |
| { | |
|     if( aValue ) | |
|         return wxT( "1" ); | |
|     else | |
|         return wxT( "0" ); | |
| } | |
| 
 | |
| 
 | |
| bool FIELDS_GRID_TABLE::BoolFromString( const wxString& aValue ) const | |
| { | |
|     if( aValue == wxS( "1" ) ) | |
|     { | |
|         return true; | |
|     } | |
|     else if( aValue == wxS( "0" ) ) | |
|     { | |
|         return false; | |
|     } | |
|     else | |
|     { | |
|         wxFAIL_MSG( wxString::Format( "string '%s' can't be converted to boolean correctly and " | |
|                                       "will be perceived as FALSE", aValue ) ); | |
|         return false; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TABLE::DetachFields() | |
| { | |
|     for( SCH_FIELD& field : *this ) | |
|         field.SetParent( nullptr ); | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TRICKS::showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) | |
| { | |
|     if( m_grid->GetGridCursorRow() == FOOTPRINT_FIELD && m_grid->GetGridCursorCol() == FDC_VALUE | |
|         && !m_grid->IsReadOnly( FOOTPRINT_FIELD, FDC_VALUE ) ) | |
|     { | |
|         menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ), | |
|                      _( "Browse for footprint" ) ); | |
|         menu.AppendSeparator(); | |
|     } | |
|     else if( m_grid->GetGridCursorRow() == DATASHEET_FIELD | |
|            && m_grid->GetGridCursorCol() == FDC_VALUE ) | |
|     { | |
|         menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ), | |
|                      _( "Show datasheet in browser" ) ); | |
|         menu.AppendSeparator(); | |
|     } | |
| 
 | |
|     GRID_TRICKS::showPopupMenu( menu, aEvent ); | |
| } | |
| 
 | |
| 
 | |
| void FIELDS_GRID_TRICKS::doPopupSelection( wxCommandEvent& event ) | |
| { | |
|     if( event.GetId() == MYID_SELECT_FOOTPRINT ) | |
|     { | |
|         // pick a footprint using the footprint picker. | |
|         wxString fpid = m_grid->GetCellValue( FOOTPRINT_FIELD, FDC_VALUE ); | |
| 
 | |
|         if( KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_CHOOSER, true, m_dlg ) ) | |
|         { | |
|             if( frame->ShowModal( &fpid, m_dlg ) ) | |
|                 m_grid->SetCellValue( FOOTPRINT_FIELD, FDC_VALUE, fpid ); | |
| 
 | |
|             frame->Destroy(); | |
|         } | |
|     } | |
|     else if (event.GetId() == MYID_SHOW_DATASHEET ) | |
|     { | |
|         wxString datasheet_uri = m_grid->GetCellValue( DATASHEET_FIELD, FDC_VALUE ); | |
| 
 | |
|         GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj(), PROJECT_SCH::SchSearchS( &m_dlg->Prj() ), | |
|                                m_filesStack ); | |
|     } | |
|     else | |
|     { | |
|         GRID_TRICKS::doPopupSelection( event ); | |
|     } | |
| } | |
| 
 | |
| 
 |