From 3c71e7ab09add58a12643421ff28d91e52152097 Mon Sep 17 00:00:00 2001 From: Jeff Young <jeff@rokeby.ie> Date: Mon, 17 Feb 2025 12:13:28 +0000 Subject: [PATCH] Auto-recognize URLs in SCH_FIELD and PCB_FIELD grids. Fixes https://gitlab.com/kicad/code/kicad/-/issues/17066 Fixes https://gitlab.com/kicad/code/kicad/-/issues/17745 --- .../dialogs/dialog_lib_symbol_properties.cpp | 5 ---- .../dialogs/dialog_symbol_fields_table.cpp | 24 ++++++++-------- eeschema/eeschema_jobs_handler.cpp | 2 +- eeschema/fields_data_model.cpp | 23 +++++++++++++++ eeschema/fields_data_model.h | 28 ++++++++++++++++--- eeschema/fields_grid_table.cpp | 2 +- eeschema/sch_field.h | 6 +++- pcbnew/pcb_field.cpp | 7 +++++ pcbnew/pcb_field.h | 2 ++ pcbnew/pcb_fields_grid_table.cpp | 2 +- 10 files changed, 77 insertions(+), 24 deletions(-) diff --git a/eeschema/dialogs/dialog_lib_symbol_properties.cpp b/eeschema/dialogs/dialog_lib_symbol_properties.cpp index c4775ae73f..001c636af0 100644 --- a/eeschema/dialogs/dialog_lib_symbol_properties.cpp +++ b/eeschema/dialogs/dialog_lib_symbol_properties.cpp @@ -87,11 +87,6 @@ DIALOG_LIB_SYMBOL_PROPERTIES::DIALOG_LIB_SYMBOL_PROPERTIES( SYMBOL_EDIT_FRAME* a SYMBOL_EDITOR_SETTINGS* cfg = m_Parent->GetSettings(); m_grid->ShowHideColumns( cfg->m_EditSymbolVisibleColumns ); - wxGridCellAttr* attr = new wxGridCellAttr; - attr->SetEditor( new GRID_CELL_URL_EDITOR( this, PROJECT_SCH::SchSearchS( &Prj() ), - m_embeddedFiles->GetLocalFiles() ) ); - m_grid->SetAttr( DATASHEET_FIELD, FDC_VALUE, attr ); - m_SymbolNameCtrl->SetValidator( FIELD_VALIDATOR( VALUE_FIELD ) ); // Configure button logos diff --git a/eeschema/dialogs/dialog_symbol_fields_table.cpp b/eeschema/dialogs/dialog_symbol_fields_table.cpp index 75a692c7b3..bf3f29bdcb 100644 --- a/eeschema/dialogs/dialog_symbol_fields_table.cpp +++ b/eeschema/dialogs/dialog_symbol_fields_table.cpp @@ -221,7 +221,11 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent, m_fieldsCtrl->SetIndent( 0 ); m_filter->SetDescriptiveText( _( "Filter" ) ); - m_dataModel = new FIELDS_EDITOR_GRID_DATA_MODEL( m_symbolsList ); + + wxGridCellAttr* attr = new wxGridCellAttr; + attr->SetEditor( new GRID_CELL_URL_EDITOR( this, PROJECT_SCH::SchSearchS( &Prj() ), + &m_parent->Schematic() ) ); + m_dataModel = new FIELDS_EDITOR_GRID_DATA_MODEL( m_symbolsList, attr ); LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel @@ -294,9 +298,7 @@ DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent, BOM_FIELD field; field.name = fieldName; field.show = !fieldName.StartsWith( wxT( "__" ), &field.name ); - field.groupBy = std::find( m_job->m_fieldsGroupBy.begin(), m_job->m_fieldsGroupBy.end(), - field.name ) - != m_job->m_fieldsGroupBy.end(); + field.groupBy = alg::contains( m_job->m_fieldsGroupBy, field.name ); if( ( m_job->m_fieldsLabels.size() > i ) && !m_job->m_fieldsLabels[i].IsEmpty() ) field.label = m_job->m_fieldsLabels[i]; @@ -413,43 +415,43 @@ void DIALOG_SYMBOL_FIELDS_TABLE::SetupColumnProperties( int aCol ) if( m_dataModel->ColIsReference( aCol ) ) { attr->SetReadOnly(); - m_grid->SetColAttr( aCol, attr ); + m_dataModel->SetColAttr( attr, aCol ); } else if( m_dataModel->GetColFieldName( aCol ) == GetCanonicalFieldName( FOOTPRINT_FIELD ) ) { attr->SetEditor( new GRID_CELL_FPID_EDITOR( this, wxEmptyString ) ); - m_grid->SetColAttr( aCol, attr ); + m_dataModel->SetColAttr( attr, aCol ); } else if( m_dataModel->GetColFieldName( aCol ) == GetCanonicalFieldName( DATASHEET_FIELD ) ) { // set datasheet column viewer button attr->SetEditor( new GRID_CELL_URL_EDITOR( this, PROJECT_SCH::SchSearchS( &Prj() ), &m_parent->Schematic() ) ); - m_grid->SetColAttr( aCol, attr ); + m_dataModel->SetColAttr( attr, aCol ); } else if( m_dataModel->ColIsQuantity( aCol ) || m_dataModel->ColIsItemNumber( aCol ) ) { attr->SetReadOnly(); - m_grid->SetColAttr( aCol, attr ); attr->SetAlignment( wxALIGN_RIGHT, wxALIGN_CENTER ); attr->SetRenderer( new wxGridCellNumberRenderer() ); + m_dataModel->SetColAttr( attr, aCol ); } else if( m_dataModel->ColIsAttribute( aCol ) ) { attr->SetAlignment( wxALIGN_CENTER, wxALIGN_CENTER ); attr->SetRenderer( new wxGridCellBoolRenderer() ); attr->SetReadOnly(); // not really; we delegate interactivity to GRID_TRICKS - m_grid->SetColAttr( aCol, attr ); + m_dataModel->SetColAttr( attr, aCol ); } else if( IsTextVar( m_dataModel->GetColFieldName( aCol ) ) ) { attr->SetReadOnly(); - m_grid->SetColAttr( aCol, attr ); + m_dataModel->SetColAttr( attr, aCol ); } else { attr->SetEditor( m_grid->GetDefaultEditor() ); - m_grid->SetColAttr( aCol, attr ); + m_dataModel->SetColAttr( attr, aCol ); } } diff --git a/eeschema/eeschema_jobs_handler.cpp b/eeschema/eeschema_jobs_handler.cpp index 32b54240a8..f95b05bfb7 100644 --- a/eeschema/eeschema_jobs_handler.cpp +++ b/eeschema/eeschema_jobs_handler.cpp @@ -530,7 +530,7 @@ int EESCHEMA_JOBS_HANDLER::JobExportBom( JOB* aJob ) m_reporter->Report( _( "Warning: duplicate sheet names.\n" ), RPT_SEVERITY_WARNING ); // Build our data model - FIELDS_EDITOR_GRID_DATA_MODEL dataModel( referenceList ); + FIELDS_EDITOR_GRID_DATA_MODEL dataModel( referenceList, nullptr ); // Mandatory fields + quantity virtual field first for( int fieldId : MANDATORY_FIELDS ) diff --git a/eeschema/fields_data_model.cpp b/eeschema/fields_data_model.cpp index a4d6ea3a05..98bccaa58c 100644 --- a/eeschema/fields_data_model.cpp +++ b/eeschema/fields_data_model.cpp @@ -175,6 +175,29 @@ wxString FIELDS_EDITOR_GRID_DATA_MODEL::GetValue( int aRow, int aCol ) } +wxGridCellAttr* FIELDS_EDITOR_GRID_DATA_MODEL::GetAttr( int aRow, int aCol, + wxGridCellAttr::wxAttrKind aKind ) +{ + if( GetColFieldName( aCol ) == GetCanonicalFieldName( DATASHEET_FIELD ) + || IsURL( GetValue( m_rows[aRow], aCol ) ) ) + { + if( m_urlEditor ) + { + m_urlEditor->IncRef(); + return enhanceAttr( m_urlEditor, aRow, aCol, aKind ); + } + } + + if( m_colAttrs[aCol] ) + { + m_colAttrs[aCol]->IncRef(); + return enhanceAttr( m_colAttrs[aCol], aRow, aCol, aKind ); + } + + return nullptr; +} + + wxString FIELDS_EDITOR_GRID_DATA_MODEL::GetValue( const DATA_MODEL_ROW& group, int aCol, const wxString& refDelimiter, const wxString& refRangeDelimiter, diff --git a/eeschema/fields_data_model.h b/eeschema/fields_data_model.h index 7f7d5d6883..0c771c2466 100644 --- a/eeschema/fields_data_model.h +++ b/eeschema/fields_data_model.h @@ -1,7 +1,6 @@ /* * This program source code file is part of KiCad, a free EDA CAD application. * - * Copyright (C) 2023 <author> * Copyright The KiCad Developers, see AUTHORS.txt for contributors. * * This program is free software: you can redistribute it and/or modify it @@ -19,6 +18,7 @@ */ #include <sch_reference_list.h> #include <wx/grid.h> +#include <widgets/wx_grid.h> // The field name in the data model (translated) #define DISPLAY_NAME_COLUMN 0 @@ -70,7 +70,7 @@ struct DATA_MODEL_COL }; -class FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase +class FIELDS_EDITOR_GRID_DATA_MODEL : public WX_GRID_TABLE_BASE { public: enum SCOPE : int @@ -80,7 +80,7 @@ public: SCOPE_SHEET_RECURSIVE = 2 }; - FIELDS_EDITOR_GRID_DATA_MODEL( SCH_REFERENCE_LIST& aSymbolsList ) : + FIELDS_EDITOR_GRID_DATA_MODEL( SCH_REFERENCE_LIST& aSymbolsList, wxGridCellAttr* aURLEditor ) : m_symbolsList( aSymbolsList ), m_edited( false ), m_sortColumn( 0 ), @@ -89,11 +89,21 @@ public: m_groupingEnabled( false ), m_excludeDNP( false ), m_includeExcluded( false ), - m_rebuildsEnabled( true ) + m_rebuildsEnabled( true ), + m_urlEditor( aURLEditor ) { m_symbolsList.SplitReferences(); } + ~FIELDS_EDITOR_GRID_DATA_MODEL() override + { + if( m_urlEditor ) + m_urlEditor->DecRef(); + + for( const auto& [col, attr] : m_colAttrs ) + wxSafeDecRef( attr ); + } + static const wxString QUANTITY_VARIABLE; static const wxString ITEM_NUMBER_VARIABLE; @@ -154,6 +164,8 @@ public: } wxString GetValue( int aRow, int aCol ) override; + wxGridCellAttr* GetAttr( int aRow, int aCol, wxGridCellAttr::wxAttrKind aKind ) override; + wxString GetValue( const DATA_MODEL_ROW& group, int aCol, const wxString& refDelimiter = wxT( ", " ), const wxString& refRangDelimiter = wxT( "-" ), @@ -265,6 +277,11 @@ public: void RemoveSymbol( const SCH_SYMBOL& aSymbol ); void UpdateReferences( const SCH_REFERENCE_LIST& aRefs ); + void SetColAttr( wxGridCellAttr* aAttr, int aCol ) override + { + wxSafeDecRef( m_colAttrs[aCol] ); + m_colAttrs[aCol] = aAttr; + } private: static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup, @@ -304,6 +321,9 @@ protected: bool m_includeExcluded; bool m_rebuildsEnabled; + wxGridCellAttr* m_urlEditor; + std::map<int, wxGridCellAttr*> m_colAttrs; + std::vector<DATA_MODEL_COL> m_cols; std::vector<DATA_MODEL_ROW> m_rows; diff --git a/eeschema/fields_grid_table.cpp b/eeschema/fields_grid_table.cpp index a0fc125f70..6ae35c8448 100644 --- a/eeschema/fields_grid_table.cpp +++ b/eeschema/fields_grid_table.cpp @@ -604,7 +604,7 @@ wxGridCellAttr* FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, wxGridCellAttr:: const TEMPLATE_FIELDNAME* templateFn = settings ? settings->m_TemplateFieldNames.GetFieldName( fn ) : nullptr; - if( templateFn && templateFn->m_URL ) + if( ( templateFn && templateFn->m_URL ) || field.IsHypertext() ) { m_urlAttr->IncRef(); return enhanceAttr( m_urlAttr, aRow, aCol, aKind ); diff --git a/eeschema/sch_field.h b/eeschema/sch_field.h index 1cf2c24188..f1ea8e04f3 100644 --- a/eeschema/sch_field.h +++ b/eeschema/sch_field.h @@ -31,6 +31,7 @@ #include <sch_item.h> #include <template_fieldnames.h> #include <general.h> +#include <string_utils.h> #include "scintilla_tricks.h" class SCH_EDIT_FRAME; @@ -103,7 +104,10 @@ public: bool IsHypertext() const override { - return GetCanonicalName() == wxT( "Intersheetrefs" ); + if( GetCanonicalName() == wxT( "Intersheetrefs" ) ) + return true; + + return IsURL( GetShownText( false ) ); } void DoHypertextAction( EDA_DRAW_FRAME* aFrame ) const override; diff --git a/pcbnew/pcb_field.cpp b/pcbnew/pcb_field.cpp index c5b3703e86..31aba4ddba 100644 --- a/pcbnew/pcb_field.cpp +++ b/pcbnew/pcb_field.cpp @@ -28,6 +28,7 @@ #include <i18n_utility.h> #include <pcb_painter.h> #include <api/board/board_types.pb.h> +#include <string_utils.h> PCB_FIELD::PCB_FIELD( FOOTPRINT* aParent, int aFieldId, const wxString& aName ) : @@ -142,6 +143,12 @@ bool PCB_FIELD::IsMandatory() const } +bool PCB_FIELD::IsHypertext() const +{ + return IsURL( GetShownText( false ) ); +} + + wxString PCB_FIELD::GetTextTypeDescription() const { if( IsMandatory() ) diff --git a/pcbnew/pcb_field.h b/pcbnew/pcb_field.h index b6dcdb08eb..9d536a09cd 100644 --- a/pcbnew/pcb_field.h +++ b/pcbnew/pcb_field.h @@ -72,6 +72,8 @@ public: bool IsMandatory() const; + bool IsHypertext() const; + wxString GetTextTypeDescription() const override; wxString GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFull ) const override; diff --git a/pcbnew/pcb_fields_grid_table.cpp b/pcbnew/pcb_fields_grid_table.cpp index 1915783609..9151b481af 100644 --- a/pcbnew/pcb_fields_grid_table.cpp +++ b/pcbnew/pcb_fields_grid_table.cpp @@ -223,7 +223,7 @@ wxGridCellAttr* PCB_FIELDS_GRID_TABLE::GetAttr( int aRow, int aCol, m_valueAttr->IncRef(); return enhanceAttr( m_valueAttr, aRow, aCol, aKind ); } - else if( field.GetId() == DATASHEET_FIELD ) + else if( field.GetId() == DATASHEET_FIELD || field.IsHypertext() ) { m_urlAttr->IncRef(); return enhanceAttr( m_urlAttr, aRow, aCol, aKind );