47#include <wx/stc/stc.h>
66 m_propertyGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
71 [
this]( wxKeyEvent& aEvent )
76 [
this]( wxStyledTextEvent& aEvent )
96 SetMinSize( wxSize( 350, 400 ) );
129 if( IsShown() &&
m_notebook->GetSelection() == 0 )
136 if( aValue.CheckType<
int>() )
137 return wxVariant( aValue.As<
int>() );
138 else if( aValue.CheckType<
long>() )
139 return wxVariant( aValue.As<
long>() );
140 else if( aValue.CheckType<
long long>() )
142 return wxVariant(
static_cast<double>( aValue.As<
long long>() ) );
143 else if( aValue.CheckType<
double>() )
144 return wxVariant( aValue.As<
double>() );
145 else if( aValue.CheckType<
bool>() )
146 return wxVariant( aValue.As<
bool>() );
147 else if( aValue.CheckType<wxString>() )
148 return wxVariant( aValue.As<wxString>() );
152 if( aValue.GetAs( &strVal ) )
153 return wxVariant( strVal );
164 const wxString& propName = aProperty->
Name();
165 wxString variantName;
170 if( !variantName.IsEmpty() )
172 if( propName ==
_HKI(
"Do not Populate" ) )
174 else if( propName ==
_HKI(
"Exclude From Bill of Materials" ) )
176 else if( propName ==
_HKI(
"Exclude From Position Files" ) )
181 wxAny anyValue = aItem->
Get( aProperty );
183 if( anyValue.IsNull() )
192wxVariant getFootprintFieldValue(
FOOTPRINT* aFootprint,
const wxString& aFieldName )
199 wxString variantName;
204 if( !variantName.IsEmpty() )
213 return wxVariant( field->
GetText() );
217std::set<wxString> getCommonFootprintFieldNames(
const PCB_SELECTION& aSelection )
219 std::set<wxString> commonFieldNames;
220 bool firstFootprint =
true;
228 std::set<wxString> fieldNames;
238 commonFieldNames = std::move( fieldNames );
239 firstFootprint =
false;
243 std::erase_if( commonFieldNames,
244 [&](
const wxString& aName )
246 return !fieldNames.count( aName );
251 return commonFieldNames;
257 if( aValue.IsNull() )
258 return wxEmptyString;
261 return aValue.GetString();
263 wxVariant valueCopy = aValue;
264 wxPGProperty* pgProperty =
nullptr;
270 const wxPGChoices& canonicalLayers = aProperty->
Choices();
271 wxArrayString boardLayerNames;
272 wxArrayInt boardLayerIDs;
274 for(
int ii = 0; ii < (int) canonicalLayers.GetCount(); ++ii )
276 int layer = canonicalLayers.GetValue( ii );
279 boardLayerIDs.push_back( layer );
283 layerProp->SetLabel( wxGetTranslation( aProperty->
Name() ) );
284 layerProp->SetName( aProperty->
Name() );
285 layerProp->SetHelpString( wxGetTranslation( aProperty->
Name() ) );
286 layerProp->SetClientData(
const_cast<PROPERTY_BASE*
>( aProperty ) );
287 pgProperty = layerProp;
296 wxString formatted = pgProperty->ValueToString( valueCopy, 0 );
299 if( !formatted.IsEmpty() )
303 return aValue.GetString();
307wxString normalizeFormattedValueForExpression(
PROPERTY_BASE* aProperty,
const wxString& aValue )
309 wxString normalized = aValue;
316 normalized.Replace( wxT(
" " ), wxEmptyString );
317 normalized.Replace( wxT(
"mils" ), wxT(
"mil" ) );
322 normalized.Replace( wxT(
"°" ), wxT(
"deg" ) );
323 normalized.Replace( wxT(
" " ), wxEmptyString );
333bool isExprIdentChar( wxChar aCh )
335 return wxIsalnum( aCh ) || aCh == wxT(
'_' );
339std::set<wxString> getQueryableFootprintFieldNames(
const std::vector<PROPERTY_ROW_DATA>& aRows )
341 std::set<wxString> fieldNames = {
_HKI(
"Reference" ),
_HKI(
"Value" ),
_HKI(
"Datasheet" ),
342 _HKI(
"Description" ) };
346 if( row.property ==
nullptr )
347 fieldNames.insert( row.propertyName );
354bool matchAliasAt(
const wxString& aExpression,
size_t aPos,
const wxString& aAlias )
356 if( aPos + aAlias.length() > aExpression.length() )
359 if( aExpression.Mid( aPos, aAlias.length() ) != aAlias )
362 if( aPos > 0 && isExprIdentChar( aExpression[aPos - 1] ) )
365 size_t end = aPos + aAlias.length();
367 if(
end < aExpression.length() && isExprIdentChar( aExpression[
end] ) )
374wxString normalizeQueryFieldAliases(
const wxString& aExpression,
const std::vector<PROPERTY_ROW_DATA>& aRows )
382 std::vector<FIELD_ALIAS> aliases;
384 for(
const wxString& fieldName : getQueryableFootprintFieldNames( aRows ) )
386 wxString exprName = fieldName;
387 exprName.Replace( wxT(
" " ), wxT(
"_" ) );
389 wxString escapedFieldName = fieldName;
390 escapedFieldName.Replace( wxT(
"'" ), wxT(
"\\'" ) );
393 { wxT(
"A." ) + exprName, wxString::Format( wxT(
"A.getField('%s')" ), escapedFieldName ) } );
396 std::sort( aliases.begin(), aliases.end(),
397 [](
const FIELD_ALIAS& aLhs,
const FIELD_ALIAS& aRhs )
399 return aLhs.from.length() > aRhs.from.length();
403 bool inString =
false;
405 for(
size_t i = 0; i < aExpression.length(); )
407 wxChar ch = aExpression[i];
409 if( ch == wxT(
'\'' ) && ( i == 0 || aExpression[i - 1] != wxT(
'\\' ) ) )
411 inString = !inString;
419 bool replaced =
false;
421 for(
const FIELD_ALIAS& alias : aliases )
423 if( matchAliasAt( aExpression, i, alias.from ) )
425 normalized += alias.to;
426 i += alias.from.length();
444bool queryUsesUnsupportedPairwiseSyntax(
const wxString& aExpression )
446 bool inString =
false;
448 for(
size_t i = 0; i < aExpression.length(); ++i )
450 wxChar ch = aExpression[i];
452 if( ch == wxT(
'\'' ) && ( i == 0 || aExpression[i - 1] != wxT(
'\\' ) ) )
454 inString = !inString;
458 if( !inString && i + 2 <= aExpression.length() && aExpression.Mid( i, 2 ) == wxT(
"B." )
459 && ( i == 0 || !isExprIdentChar( aExpression[i - 1] ) ) )
469bool isVisibleInFindByProperties(
const wxString& aName,
const PROPERTY_BASE* aProperty )
490 if( selection.Empty() )
497 std::map<wxString, PROPERTY_MATCH_MODE> savedModes;
502 savedModes[row.propertyName] = row.matchMode;
508 if( selection.Size() == 1 )
509 m_statusLabel->SetLabel( selection.Front()->GetFriendlyName() );
511 m_statusLabel->SetLabel( wxString::Format(
_(
"%d objects selected" ), selection.Size() ) );
518 std::map<wxString, PROPERTY_BASE*> commonProps;
522 commonProps.emplace( prop->Name(), prop );
526 for(
auto propIt = commonProps.begin(); propIt != commonProps.end(); )
529 propIt = commonProps.erase( propIt );
535 for(
auto& [
name, property] : commonProps )
537 if( !isVisibleInFindByProperties(
name, property ) )
540 bool available =
true;
561 bool different =
false;
597 row.
displayValue = different ? wxString( wxT(
"<...>" ) )
603 for(
const wxString& fieldName : getCommonFootprintFieldNames( selection ) )
605 if( commonProps.count( fieldName ) )
615 bool different =
false;
616 bool available =
true;
620 wxVariant value = getFootprintFieldValue(
static_cast<FOOTPRINT*
>( item ), fieldName );
644 row.
displayValue = different ? wxString( wxT(
"<...>" ) )
664 m_propertyGrid->SetCellTextColour( i, 2, wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
668 wxString choices[] = {
_(
"Ignored" ),
_(
"Matching" ),
_(
"Different" ) };
669 m_propertyGrid->SetCellEditor( i, 2,
new wxGridCellChoiceEditor( 3, choices ) );
670 m_propertyGrid->SetCellRenderer( i, 2,
new wxGridCellStringRenderer() );
682 int col1Width = totalWidth - col0Width - col2Width;
687 bool anyActive =
false;
707 if( aEvent.GetCol() == 2 && aEvent.GetRow() >= 0 && aEvent.GetRow() < (
int)
m_propertyRows.size()
710 m_propertyGrid->SetGridCursor( aEvent.GetRow(), aEvent.GetCol() );
722 int row = aEvent.GetRow();
723 int col = aEvent.GetCol();
734 if( val ==
_(
"Matching" ) )
736 else if( val ==
_(
"Different" ) )
743 bool anyActive =
false;
763 int col1Width = totalWidth - col0Width - col2Width;
800 std::vector<BOARD_ITEM*> items;
806 items.push_back( track );
810 items.push_back( fp );
812 for(
PAD*
pad : fp->Pads() )
813 items.push_back(
pad );
815 for(
PCB_FIELD* field : fp->GetFields() )
816 items.push_back( field );
819 items.push_back( gi );
821 for(
ZONE* zone : fp->Zones() )
822 items.push_back( zone );
826 items.push_back( item );
829 items.push_back( zone );
852 if( row.property ==
nullptr )
857 itemValue = getFootprintFieldValue(
static_cast<FOOTPRINT*
>( aItem ), row.propertyName );
872 if( itemValue.IsNull() )
875 bool valuesEqual = ( itemValue == row.rawValue );
895 if( !aMatchList.empty() )
898 if(
m_zoomToFit->IsChecked() && !aMatchList.empty() )
901 aStatusLabel->SetLabel( wxString::Format(
_(
"%zu items matched" ), aMatchList.size() ) );
913 matchList.push_back( item );
922 wxString expression =
m_queryEditor->GetText().Trim().Trim(
false );
924 if( expression.IsEmpty() )
927 wxString normalizedExpression = normalizeQueryFieldAliases( expression,
m_propertyRows );
929 if( queryUsesUnsupportedPairwiseSyntax( normalizedExpression ) )
931 wxString error =
_(
"B. expressions are not supported." );
934 wxMessageBox( error,
_(
"Expression Error" ), wxOK | wxICON_ERROR,
this );
945 [&](
const wxString& aMessage,
int aOffset )
947 errors += aMessage + wxT(
"\n" );
950 bool ok = compiler.
Compile( normalizedExpression.ToUTF8().data(), &ucode, &preflightContext );
955 wxMessageBox( errors,
_(
"Expression Error" ), wxOK | wxICON_ERROR,
this );
966 bool matched =
false;
967 LSET itemLayers = item->GetLayerSet();
984 matchList.push_back( item );
993 wxString
result = aPropName;
994 result.Replace( wxT(
" " ), wxT(
"_" ) );
1001 if( aValue.GetType() == wxT(
"bool" ) )
1002 return aValue.GetBool() ? wxT(
"true" ) : wxT(
"false" );
1006 wxString val = formatFindByPropertiesDisplayValue(
m_frame, aProp, aValue );
1008 val.Replace( wxT(
"'" ), wxT(
"\\'" ) );
1010 return wxString::Format( wxT(
"'%s'" ), val );
1022 return normalizeFormattedValueForExpression( aProp,
1023 formatFindByPropertiesDisplayValue(
m_frame, aProp, aValue ) );
1029 if( aValue.GetType() == wxT(
"double" ) || aValue.GetType() == wxT(
"long" ) )
1030 return aValue.GetString();
1032 wxString val = aProp ? formatFindByPropertiesDisplayValue(
m_frame, aProp, aValue ) : aValue.GetString();
1034 val.Replace( wxT(
"'" ), wxT(
"\\'" ) );
1036 return wxString::Format( wxT(
"'%s'" ), val );
1042 wxArrayString conditions;
1054 if( row.property ==
nullptr )
1056 lhs = wxString::Format( wxT(
"A.getField(%s)" ),
1067 conditions.Add( wxString::Format( wxT(
"%s %s %s" ), lhs, op, value ) );
1072 for(
size_t i = 0; i < conditions.size(); i++ )
1088 if( !expr.IsEmpty() )
1098 wxString expression =
m_queryEditor->GetText().Trim().Trim(
false );
1100 if( expression.IsEmpty() )
1106 wxString normalizedExpression = normalizeQueryFieldAliases( expression,
m_propertyRows );
1108 if( queryUsesUnsupportedPairwiseSyntax( normalizedExpression ) )
1120 [&](
const wxString& aMessage,
int aOffset )
1122 errors += aMessage + wxT(
"\n" );
1125 bool ok = compiler.
Compile( normalizedExpression.ToUTF8().data(), &ucode, &preflightContext );
1138 if( sel != wxNOT_FOUND )
1156 if( aQuery.IsEmpty() )
1163 queries.erase( std::remove( queries.begin(), queries.end(), aQuery ), queries.end() );
1166 queries.insert( queries.begin(), aQuery );
1169 if( queries.size() > 10 )
1170 queries.resize( 10 );
1185 if( event.GetSelection() == 0 )
1199 wxString prev2 =
m_queryEditor->GetTextRange( pos - 2, pos );
1201 if( prev2 == wxT(
"A." ) )
1204 wxArrayString tokens;
1205 std::set<wxString> seen;
1216 wxString
name = prop->Name();
1218 if( !isVisibleInFindByProperties(
name, prop ) )
1221 name.Replace( wxT(
" " ), wxT(
"_" ) );
1223 if( seen.insert(
name ).second )
1228 for(
const wxString& fieldName : getQueryableFootprintFieldNames(
m_propertyRows ) )
1230 wxString exprName = fieldName;
1231 exprName.Replace( wxT(
" " ), wxT(
"_" ) );
1233 if( seen.insert( exprName ).second )
1234 tokens.Add( exprName );
static TOOL_ACTION zoomFitSelection
static TOOL_ACTION selectionClear
Clear the current selection.
static TOOL_ACTION selectItems
Select a list of items (specified as the event parameter)
A base class for any item which can be embedded within the BOARD container class, and therefore insta...
virtual const BOARD * GetBoard() const
Return the BOARD in which this BOARD_ITEM resides, or NULL if none.
const wxString GetLayerName(PCB_LAYER_ID aLayer) const
Return the name of a aLayer.
wxString GetCurrentVariant() const
wxStaticText * m_queryStatusLabel
DIALOG_FIND_BY_PROPERTIES_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Find by Properties"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
wxButton * m_createQueryBtn
wxButton * m_selectMatchingBtn
wxCheckBox * m_deselectNonMatching
wxComboBox * m_recentQueries
wxStaticText * m_statusLabel
wxStyledTextCtrl * m_queryEditor
bool Show(bool show=true) override
DIALOG_FIND_BY_PROPERTIES(PCB_EDIT_FRAME *aParent)
void selectMatchingFromQuery()
void onSelectMatchingClick(wxCommandEvent &event) override
void applyMatchResults(EDA_ITEMS &aMatchList, wxStaticText *aStatusLabel)
std::vector< PROPERTY_ROW_DATA > m_propertyRows
void onGridCellChanged(wxGridEvent &aEvent)
void saveRecentQuery(const wxString &aQuery)
~DIALOG_FIND_BY_PROPERTIES() override
wxString formatValueForExpression(PROPERTY_BASE *aProp, const wxVariant &aValue)
wxVariant getVariantAwareValue(EDA_ITEM *aItem, PROPERTY_BASE *aProperty)
void onNotebookPageChanged(wxNotebookEvent &event) override
std::set< size_t > m_selectedTypes
void OnBoardChanged(wxCommandEvent &event)
void onCheckSyntaxClick(wxCommandEvent &event) override
static wxVariant anyToVariant(const wxAny &aValue)
bool itemMatchesPropertyCriteria(BOARD_ITEM *aItem)
void OnSelectionChanged()
void updateMatchModeCell(int aRow)
void onScintillaCharAdded(wxStyledTextEvent &aEvent)
static wxString propNameToExprField(const wxString &aPropName)
void onRecentQuerySelected(wxCommandEvent &event) override
wxString generateExpressionFromProperties()
void rebuildPropertyGrid()
void OnCloseButtonClick(wxCommandEvent &event) override
SCINTILLA_TRICKS * m_scintillaTricks
void onGridCellClick(wxGridEvent &aEvent)
std::vector< BOARD_ITEM * > collectAllBoardItems()
void selectMatchingFromProperties()
void onGridSizeChanged(wxSizeEvent &aEvent)
void onCreateQueryClick(wxCommandEvent &event) override
bool Show(bool show) override
A base class for most all the KiCad significant classes used in schematics and boards.
KICAD_T Type() const
Returns the type of object.
virtual const wxString & GetText() const
Return the string associated with the text object.
wxAny Get(PROPERTY_BASE *aProperty) const
void SetErrorCallback(std::function< void(const wxString &aMessage, int aOffset)> aCallback)
bool Compile(const wxString &aString, UCODE *aCode, CONTEXT *aPreflightContext)
VALUE * Run(CONTEXT *ctx)
LSET is a set of PCB_LAYER_IDs.
LSEQ Seq(const LSEQ &aSequence) const
Return an LSEQ from the union of this LSET and a desired sequence.
void SetItems(BOARD_ITEM *a, BOARD_ITEM *b=nullptr)
The main frame for Pcbnew.
wxString GetCanonicalName() const
Get a non-language-specific name for a field which can be used for storage, variable look-up,...
The backing store for a PROJECT, in JSON format.
std::vector< wxString > m_FindByPropertiesQueries
Recent queries for Find by Properties dialog.
bool IsHiddenFromPropertiesManager() const
virtual size_t TypeHash() const =0
Return type-id of the property type.
bool IsHiddenFromDesignEditors() const
PROPERTY_DISPLAY Display() const
virtual bool HasChoices() const
Return true if this PROPERTY has a limited set of possible values.
const wxString & Name() const
virtual const wxPGChoices & Choices() const
Return a limited set of possible values (e.g.
Provide class metadata.Helper macro to map type hashes to names.
const std::vector< PROPERTY_BASE * > & GetProperties(TYPE_ID aType) const
Return all properties for a specific type.
static PROPERTY_MANAGER & Instance()
PROPERTY_BASE * GetProperty(TYPE_ID aType, const wxString &aProperty) const
Return a property for a specific type.
bool IsAvailableFor(TYPE_ID aItemClass, PROPERTY_BASE *aProp, INSPECTABLE *aItem)
Checks overriden availability and original availability of a property, returns false if the property ...
Add cut/copy/paste, dark theme, autocomplete and brace highlighting to a wxStyleTextCtrl instance.
Handle a list of polygons defining a copper zone.
PCB_LAYER_ID
A quick note on layer IDs:
PCB_LAYER_ID ToLAYER_ID(int aLayer)
wxPGProperty * PGPropertyFactory(const PROPERTY_BASE *aProperty, EDA_DRAW_FRAME *aFrame)
Customized abstract wxPGProperty class to handle coordinate/size units.
@ PT_DEGREE
Angle expressed in degrees.
@ PT_COORD
Coordinate expressed in distance units (mm/inch)
@ PT_DECIDEGREE
Angle expressed in decidegrees.
@ PT_SIZE
Size expressed in distance units (mm/inch)
@ PT_TIME
Time expressed in ps.
size_t TYPE_ID
Unique type identifier.
std::vector< EDA_ITEM * > EDA_ITEMS
std::vector< FAB_LAYER_COLOR > dummy
PROPERTY_MATCH_MODE matchMode
wxString result
Test unit parsing edge cases and error handling.
@ PCB_FOOTPRINT_T
class FOOTPRINT, a footprint