31#include <wx/bmpbuttn.h>
32#include <wx/stattext.h>
35static constexpr const wxChar*
TRACE_COND = wxT(
"KI_TRACE_DRC_RULE_EDITOR" );
39 bool aTwoObjectConstraint ) :
45 wxLogTrace(
TRACE_COND, wxS(
"[DRC_RE_CONDITION_GROUP_PANEL] ctor START" ) );
49 wxString labelText = aTwoObjectConstraint ?
_(
"Where conditions match:" )
50 :
_(
"Where object matches:" );
51 m_labelText =
new wxStaticText(
this, wxID_ANY, labelText );
56 m_addBtn->SetToolTip(
_(
"Add another condition" ) );
74 wxLogTrace(
TRACE_COND, wxS(
"[ParseCondition] expr='%s'" ), aConditionExpr );
83 if( aConditionExpr.IsEmpty() )
85 wxLogTrace(
TRACE_COND, wxS(
"[ParseCondition] empty expression, setting to ANY" ) );
96 std::vector<std::pair<BOOL_OPERATOR, wxString>> parts;
100 wxLogTrace(
TRACE_COND, wxS(
"[ParseCondition] tokenize failed, using single custom row" ) );
106 m_conditions[0].panel->ParseExpression( aConditionExpr );
111 wxLogTrace(
TRACE_COND, wxS(
"[ParseCondition] tokenized into %zu parts" ), parts.size() );
114 for(
size_t i = 0; i < parts.size(); ++i )
116 wxLogTrace(
TRACE_COND, wxS(
"[ParseCondition] part[%zu] op=%d expr='%s'" ),
117 i,
static_cast<int>( parts[i].first ), parts[i].second );
124 m_conditions[0].panel->ParseExpression( parts[i].second );
129 m_conditions.back().panel->ParseExpression( parts[i].second );
132 m_conditions.back().operatorChoice->SetSelection(
static_cast<int>( parts[i].first ) );
140 wxLogTrace(
TRACE_COND, wxS(
"[ParseCondition] done, HasCustomQuerySelected=%d" ),
151 wxString rowExpr =
m_conditions[i].panel->BuildExpression();
153 if( rowExpr.IsEmpty() )
178 bool hasCustom =
m_conditions[i].panel->HasCustomQuerySelected();
180 wxLogTrace(
TRACE_COND, wxS(
"[HasCustomQuerySelected] row[%zu] type=%d hasCustom=%d" ),
181 i,
static_cast<int>(
m_conditions[i].panel->GetConditionType() ), hasCustom ? 1 : 0 );
198 entry.
rowSizer =
new wxBoxSizer( wxHORIZONTAL );
203 wxArrayString operators;
204 operators.Add(
_(
"AND" ) );
205 operators.Add(
_(
"OR" ) );
206 operators.Add(
_(
"AND NOT" ) );
207 operators.Add(
_(
"OR NOT" ) );
209 entry.
operatorChoice =
new wxChoice(
this, wxID_ANY, wxDefaultPosition, wxDefaultSize, operators );
215 opChoice->Bind( wxEVT_CHOICE,
216 [
this, opChoice]( wxCommandEvent& )
234 wxLogTrace(
TRACE_COND, wxS(
"[addConditionRow] creating row panel" ) );
236 wxLogTrace(
TRACE_COND, wxS(
"[addConditionRow] adding row panel to rowSizer" ) );
265 if( wxWindow* parent = GetParent() )
272 if( aIndex < 0 || aIndex >=
static_cast<int>(
m_conditions.size() ) )
287 entry.
panel->Destroy();
295 int newIndex =
static_cast<int>( i );
309 if( wxWindow* parent = GetParent() )
342 entry.panel->ShowDeleteButton( showDelete );
347 const wxString& aExpr, std::vector<std::pair<BOOL_OPERATOR, wxString>>& aParts )
349 wxString remaining = aExpr;
353 while( !remaining.IsEmpty() )
355 remaining.Trim(
false );
357 if( remaining.IsEmpty() )
363 if( remaining.StartsWith(
"&&" ) )
365 remaining = remaining.Mid( 2 ).Trim(
false );
367 if( remaining.StartsWith(
"!" ) )
370 remaining = remaining.Mid( 1 ).Trim(
false );
377 else if( remaining.StartsWith(
"||" ) )
379 remaining = remaining.Mid( 2 ).Trim(
false );
381 if( remaining.StartsWith(
"!" ) )
384 remaining = remaining.Mid( 1 ).Trim(
false );
400 bool inQuote =
false;
403 for(
size_t i = 0; i < remaining.length(); ++i )
405 wxChar c = remaining[i];
407 if( c ==
'\\' && i + 1 < remaining.length() )
428 if( depth == 0 && i + 1 < remaining.length() )
430 if( remaining.Mid( i, 2 ) ==
"&&" || remaining.Mid( i, 2 ) ==
"||" )
439 end = remaining.length();
441 wxString part = remaining.Left(
end ).Trim(
true ).Trim(
false );
442 aParts.push_back( { nextOp, part } );
444 remaining = remaining.Mid(
end );
448 return !aParts.empty();
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
Information pertinent to a Pcbnew printed circuit board.
std::vector< CONDITION_ENTRY > m_conditions
bool HasCustomQuerySelected() const
wxStaticText * m_labelText
std::function< void()> m_changeCallback
void onAddClicked(wxCommandEvent &aEvent)
bool tokenizeCondition(const wxString &aExpr, std::vector< std::pair< BOOL_OPERATOR, wxString > > &aParts)
Tokenize a condition expression by boolean operators.
void ParseCondition(const wxString &aConditionExpr)
Parse a condition string and populate the UI.
DRC_RE_CONDITION_GROUP_PANEL(wxWindow *aParent, BOARD *aBoard, bool aTwoObjectConstraint)
wxBitmapButton * m_addBtn
void addConditionRow(BOOL_OPERATOR aOp=BOOL_OPERATOR::AND)
void removeConditionRow(int aIndex)
wxString BuildCondition() const
Build a condition string from the current UI state.
bool m_twoObjectConstraint
void updateDeleteButtonVisibility()
A single condition row in the condition group panel.
void SetDeleteCallback(std::function< void()> aCallback)
void SetChangeCallback(std::function< void()> aCallback)
static constexpr const wxChar * TRACE_COND
DRC_RE_CONDITION_ROW_PANEL * panel
wxChoice * operatorChoice
wxString result
Test unit parsing edge cases and error handling.