43#include <wx/stc/stc.h>
62 m_propertyGrid->SetDefaultCellAlignment( wxALIGN_LEFT, wxALIGN_CENTER );
67 [
this]( wxKeyEvent& aEvent )
72 [
this]( wxStyledTextEvent& aEvent )
92 SetMinSize( wxSize( 350, 400 ) );
125 if( IsShown() &&
m_notebook->GetSelection() == 0 )
132 if( aValue.CheckType<
int>() )
133 return wxVariant( aValue.As<
int>() );
134 else if( aValue.CheckType<
long>() )
135 return wxVariant( aValue.As<
long>() );
136 else if( aValue.CheckType<
long long>() )
138 return wxVariant(
static_cast<double>( aValue.As<
long long>() ) );
139 else if( aValue.CheckType<
double>() )
140 return wxVariant( aValue.As<
double>() );
141 else if( aValue.CheckType<
bool>() )
142 return wxVariant( aValue.As<
bool>() );
143 else if( aValue.CheckType<wxString>() )
144 return wxVariant( aValue.As<wxString>() );
148 if( aValue.GetAs( &strVal ) )
149 return wxVariant( strVal );
160 const wxString& propName = aProperty->
Name();
161 wxString variantName;
166 if( !variantName.IsEmpty() )
168 if( propName ==
_HKI(
"Do not Populate" ) )
170 else if( propName ==
_HKI(
"Exclude From Bill of Materials" ) )
172 else if( propName ==
_HKI(
"Exclude From Position Files" ) )
177 wxAny anyValue = aItem->
Get( aProperty );
179 if( anyValue.IsNull() )
188wxVariant getFootprintFieldValue(
FOOTPRINT* aFootprint,
const wxString& aFieldName )
195 wxString variantName;
200 if( !variantName.IsEmpty() )
209 return wxVariant( field->
GetText() );
213std::set<wxString> getCommonFootprintFieldNames(
const PCB_SELECTION& aSelection )
215 std::set<wxString> commonFieldNames;
216 bool firstFootprint =
true;
224 std::set<wxString> fieldNames;
234 commonFieldNames = std::move( fieldNames );
235 firstFootprint =
false;
239 std::erase_if( commonFieldNames,
240 [&](
const wxString& aName )
242 return !fieldNames.count( aName );
247 return commonFieldNames;
253 if( aValue.IsNull() )
254 return wxEmptyString;
257 return aValue.GetString();
259 wxVariant valueCopy = aValue;
260 wxPGProperty* pgProperty =
nullptr;
266 const wxPGChoices& canonicalLayers = aProperty->
Choices();
267 wxArrayString boardLayerNames;
268 wxArrayInt boardLayerIDs;
270 for(
int ii = 0; ii < (int) canonicalLayers.GetCount(); ++ii )
272 int layer = canonicalLayers.GetValue( ii );
275 boardLayerIDs.push_back( layer );
279 layerProp->SetLabel( wxGetTranslation( aProperty->
Name() ) );
280 layerProp->SetName( aProperty->
Name() );
281 layerProp->SetHelpString( wxGetTranslation( aProperty->
Name() ) );
282 layerProp->SetClientData(
const_cast<PROPERTY_BASE*
>( aProperty ) );
283 pgProperty = layerProp;
292 wxString formatted = pgProperty->ValueToString( valueCopy, 0 );
295 if( !formatted.IsEmpty() )
299 return aValue.GetString();
303wxString normalizeFormattedValueForExpression(
PROPERTY_BASE* aProperty,
const wxString& aValue )
305 wxString normalized = aValue;
312 normalized.Replace( wxT(
" " ), wxEmptyString );
313 normalized.Replace( wxT(
"mils" ), wxT(
"mil" ) );
318 normalized.Replace( wxT(
"°" ), wxT(
"deg" ) );
319 normalized.Replace( wxT(
" " ), wxEmptyString );
329bool isExprIdentChar( wxChar aCh )
331 return wxIsalnum( aCh ) || aCh == wxT(
'_' );
335std::set<wxString> getQueryableFootprintFieldNames(
const std::vector<PROPERTY_ROW_DATA>& aRows )
337 std::set<wxString> fieldNames = {
_HKI(
"Reference" ),
_HKI(
"Value" ),
_HKI(
"Datasheet" ),
338 _HKI(
"Description" ) };
342 if( row.property ==
nullptr )
343 fieldNames.insert( row.propertyName );
350bool matchAliasAt(
const wxString& aExpression,
size_t aPos,
const wxString& aAlias )
352 if( aPos + aAlias.length() > aExpression.length() )
355 if( aExpression.Mid( aPos, aAlias.length() ) != aAlias )
358 if( aPos > 0 && isExprIdentChar( aExpression[aPos - 1] ) )
361 size_t end = aPos + aAlias.length();
363 if(
end < aExpression.length() && isExprIdentChar( aExpression[
end] ) )
370wxString normalizeQueryFieldAliases(
const wxString& aExpression,
const std::vector<PROPERTY_ROW_DATA>& aRows )
378 std::vector<FIELD_ALIAS> aliases;
380 for(
const wxString& fieldName : getQueryableFootprintFieldNames( aRows ) )
382 wxString exprName = fieldName;
383 exprName.Replace( wxT(
" " ), wxT(
"_" ) );
385 wxString escapedFieldName = fieldName;
386 escapedFieldName.Replace( wxT(
"'" ), wxT(
"\\'" ) );
389 { wxT(
"A." ) + exprName, wxString::Format( wxT(
"A.getField('%s')" ), escapedFieldName ) } );
392 std::sort( aliases.begin(), aliases.end(),
393 [](
const FIELD_ALIAS& aLhs,
const FIELD_ALIAS& aRhs )
395 return aLhs.from.length() > aRhs.from.length();
399 bool inString =
false;
401 for(
size_t i = 0; i < aExpression.length(); )
403 wxChar ch = aExpression[i];
405 if( ch == wxT(
'\'' ) && ( i == 0 || aExpression[i - 1] != wxT(
'\\' ) ) )
407 inString = !inString;
415 bool replaced =
false;
417 for(
const FIELD_ALIAS& alias : aliases )
419 if( matchAliasAt( aExpression, i, alias.from ) )
421 normalized += alias.to;
422 i += alias.from.length();
440bool queryUsesUnsupportedPairwiseSyntax(
const wxString& aExpression )
442 bool inString =
false;
444 for(
size_t i = 0; i < aExpression.length(); ++i )
446 wxChar ch = aExpression[i];
448 if( ch == wxT(
'\'' ) && ( i == 0 || aExpression[i - 1] != wxT(
'\\' ) ) )
450 inString = !inString;
454 if( !inString && i + 2 <= aExpression.length() && aExpression.Mid( i, 2 ) == wxT(
"B." )
455 && ( i == 0 || !isExprIdentChar( aExpression[i - 1] ) ) )
465bool isVisibleInFindByProperties(
const wxString& aName,
const PROPERTY_BASE* aProperty )
486 if( selection.Empty() )
493 std::map<wxString, PROPERTY_MATCH_MODE> savedModes;
498 savedModes[row.propertyName] = row.matchMode;
504 if( selection.Size() == 1 )
505 m_statusLabel->SetLabel( selection.Front()->GetFriendlyName() );
507 m_statusLabel->SetLabel( wxString::Format(
_(
"%d objects selected" ), selection.Size() ) );
514 std::map<wxString, PROPERTY_BASE*> commonProps;
518 commonProps.emplace( prop->Name(), prop );
522 for(
auto propIt = commonProps.begin(); propIt != commonProps.end(); )
525 propIt = commonProps.erase( propIt );
531 for(
auto& [
name, property] : commonProps )
533 if( !isVisibleInFindByProperties(
name, property ) )
536 bool available =
true;
557 bool different =
false;
593 row.
displayValue = different ? wxString( wxT(
"<...>" ) )
599 for(
const wxString& fieldName : getCommonFootprintFieldNames( selection ) )
601 if( commonProps.count( fieldName ) )
611 bool different =
false;
612 bool available =
true;
616 wxVariant value = getFootprintFieldValue(
static_cast<FOOTPRINT*
>( item ), fieldName );
640 row.
displayValue = different ? wxString( wxT(
"<...>" ) )
660 m_propertyGrid->SetCellTextColour( i, 2, wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT ) );
664 wxString choices[] = {
_(
"Ignored" ),
_(
"Matching" ),
_(
"Different" ) };
665 m_propertyGrid->SetCellEditor( i, 2,
new wxGridCellChoiceEditor( 3, choices ) );
666 m_propertyGrid->SetCellRenderer( i, 2,
new wxGridCellStringRenderer() );
678 int col1Width = totalWidth - col0Width - col2Width;
683 bool anyActive =
false;
703 if( aEvent.GetCol() == 2 && aEvent.GetRow() >= 0 && aEvent.GetRow() < (
int)
m_propertyRows.size()
706 m_propertyGrid->SetGridCursor( aEvent.GetRow(), aEvent.GetCol() );
718 int row = aEvent.GetRow();
719 int col = aEvent.GetCol();
730 if( val ==
_(
"Matching" ) )
732 else if( val ==
_(
"Different" ) )
739 bool anyActive =
false;
759 int col1Width = totalWidth - col0Width - col2Width;
796 std::vector<BOARD_ITEM*> items;
802 items.push_back( track );
806 items.push_back( fp );
808 for(
PAD*
pad : fp->Pads() )
809 items.push_back(
pad );
811 for(
PCB_FIELD* field : fp->GetFields() )
812 items.push_back( field );
815 items.push_back( gi );
817 for(
ZONE* zone : fp->Zones() )
818 items.push_back( zone );
822 items.push_back( item );
825 items.push_back( zone );
848 if( row.property ==
nullptr )
853 itemValue = getFootprintFieldValue(
static_cast<FOOTPRINT*
>( aItem ), row.propertyName );
868 if( itemValue.IsNull() )
871 bool valuesEqual = ( itemValue == row.rawValue );
891 if( !aMatchList.empty() )
894 if(
m_zoomToFit->IsChecked() && !aMatchList.empty() )
897 m_frame->GetCanvas()->ForceRefresh();
899 aStatusLabel->SetLabel( wxString::Format(
_(
"%zu items matched" ), aMatchList.size() ) );
911 matchList.push_back( item );
920 wxString expression =
m_queryEditor->GetText().Trim().Trim(
false );
922 if( expression.IsEmpty() )
925 wxString normalizedExpression = normalizeQueryFieldAliases( expression,
m_propertyRows );
927 if( queryUsesUnsupportedPairwiseSyntax( normalizedExpression ) )
929 wxString error =
_(
"B. expressions are not supported." );
932 wxMessageBox( error,
_(
"Expression Error" ), wxOK | wxICON_ERROR,
this );
943 [&](
const wxString& aMessage,
int aOffset )
945 errors += aMessage + wxT(
"\n" );
948 bool ok = compiler.
Compile( normalizedExpression.ToUTF8().data(), &ucode, &preflightContext );
953 wxMessageBox( errors,
_(
"Expression Error" ), wxOK | wxICON_ERROR,
this );
964 bool matched =
false;
965 LSET itemLayers = item->GetLayerSet();
982 matchList.push_back( item );
991 wxString
result = aPropName;
992 result.Replace( wxT(
" " ), wxT(
"_" ) );
999 if( aValue.GetType() == wxT(
"bool" ) )
1000 return aValue.GetBool() ? wxT(
"true" ) : wxT(
"false" );
1004 wxString val = formatFindByPropertiesDisplayValue(
m_frame, aProp, aValue );
1006 val.Replace( wxT(
"'" ), wxT(
"\\'" ) );
1008 return wxString::Format( wxT(
"'%s'" ), val );
1020 return normalizeFormattedValueForExpression( aProp,
1021 formatFindByPropertiesDisplayValue(
m_frame, aProp, aValue ) );
1027 if( aValue.GetType() == wxT(
"double" ) || aValue.GetType() == wxT(
"long" ) )
1028 return aValue.GetString();
1030 wxString val = aProp ? formatFindByPropertiesDisplayValue(
m_frame, aProp, aValue ) : aValue.GetString();
1032 val.Replace( wxT(
"'" ), wxT(
"\\'" ) );
1034 return wxString::Format( wxT(
"'%s'" ), val );
1040 wxArrayString conditions;
1052 if( row.property ==
nullptr )
1054 lhs = wxString::Format( wxT(
"A.getField(%s)" ),
1065 conditions.Add( wxString::Format( wxT(
"%s %s %s" ), lhs, op, value ) );
1070 for(
size_t i = 0; i < conditions.size(); i++ )
1086 if( !expr.IsEmpty() )
1096 wxString expression =
m_queryEditor->GetText().Trim().Trim(
false );
1098 if( expression.IsEmpty() )
1104 wxString normalizedExpression = normalizeQueryFieldAliases( expression,
m_propertyRows );
1106 if( queryUsesUnsupportedPairwiseSyntax( normalizedExpression ) )
1118 [&](
const wxString& aMessage,
int aOffset )
1120 errors += aMessage + wxT(
"\n" );
1123 bool ok = compiler.
Compile( normalizedExpression.ToUTF8().data(), &ucode, &preflightContext );
1136 if( sel != wxNOT_FOUND )
1154 if( aQuery.IsEmpty() )
1161 queries.erase( std::remove( queries.begin(), queries.end(), aQuery ), queries.end() );
1164 queries.insert( queries.begin(), aQuery );
1167 if( queries.size() > 10 )
1168 queries.resize( 10 );
1183 if( event.GetSelection() == 0 )
1197 wxString prev2 =
m_queryEditor->GetTextRange( pos - 2, pos );
1199 if( prev2 == wxT(
"A." ) )
1202 wxArrayString tokens;
1203 std::set<wxString> seen;
1214 wxString
name = prop->Name();
1216 if( !isVisibleInFindByProperties(
name, prop ) )
1219 name.Replace( wxT(
" " ), wxT(
"_" ) );
1221 if( seen.insert(
name ).second )
1226 for(
const wxString& fieldName : getQueryableFootprintFieldNames(
m_propertyRows ) )
1228 wxString exprName = fieldName;
1229 exprName.Replace( wxT(
" " ), wxT(
"_" ) );
1231 if( seen.insert( exprName ).second )
1232 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