KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_assign_netclass.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
25
26#include <wx/regex.h>
27
29#include <project.h>
32#include <eda_base_frame.h>
33#include <string_utils.h>
34
35
36wxString UpgradeGlobStarToRegex( const wxString& aPattern )
37{
38 // Match a '*' that is NOT preceded by '.'
39 // (needs lookbehind, so no std::regex)
40 static const wxRegEx globStarPattern( wxT( R"((?<!\.)\*)" ) );
41
42 wxString result = aPattern;
43 globStarPattern.ReplaceAll( &result, ".*" );
44 return result;
45}
46
47
48static wxString GetStringCommonPrefix( const wxArrayString& aSet )
49{
50 if( aSet.empty() )
51 return wxEmptyString;
52
53 wxString commonPrefix = *aSet.begin();
54
55 for( const wxString& str : aSet )
56 {
57 const size_t minLength = std::min( commonPrefix.size(), str.size() );
58 size_t matchUntil = 0;
59 while( matchUntil < minLength && commonPrefix[matchUntil] == str[matchUntil] )
60 {
61 ++matchUntil;
62 }
63
64 commonPrefix = commonPrefix.substr( 0, matchUntil );
65
66 // If the common prefix is empty, we can stop early
67 // as there is no common prefix.
68 if( commonPrefix.empty() )
69 break;
70 }
71
72 return commonPrefix;
73}
74
75
90static wxString GetNetclassPatternForSet( const std::set<wxString>& aNetNames )
91{
92 if( aNetNames.empty() )
93 return wxEmptyString;
94
95 if( aNetNames.size() == 1 )
96 {
97 return *aNetNames.begin();
98 }
99
100 wxArrayString netNames;
101 for( const wxString& netName : aNetNames )
102 {
103 // If the net name contains a '*' (e..g it was a bus prefix),
104 // we CAN use it in a pipe-separated regex pattern, but it has to be
105 // upgraded from a glob star to a regex star.
106 netNames.Add( UpgradeGlobStarToRegex( netName ) );
107 }
108
109 // Sort the net names to have a consistent order.
111
112 // Get the common prefix of all net names.
113 const wxString commonPrefix = GetStringCommonPrefix( netNames );
114
115 if( !commonPrefix.IsEmpty() && commonPrefix != wxT( "/" ) )
116 {
117 // If the common prefix is not empty, we can use it to simplify the pattern.
118 // This only works for one prefix, but with tries or similar, we can find
119 // multiple prefixes if that's something we want to do.
120
121 wxArrayString netTails;
122
123 for( const wxString& netName : netNames )
124 {
125 // Add the tail of the net name after the common prefix.
126 netTails.Add( netName.Mid( commonPrefix.size() ) );
127 }
128
129 return commonPrefix + + wxT("(") + wxJoin( netTails, wxT( '|' ) ) + wxT(")");
130 }
131
132 // No better ideas, just a straight pipe-separated list of net names.
133 return wxJoin( netNames, wxT( '|' ) );
134}
135
136
138 const std::set<wxString>& aNetNames,
139 const std::set<wxString> aCandidateNetNames,
140 const std::function<void( const std::vector<wxString>& )>& aPreviewer ) :
142 m_frame( aParent ),
143 m_selectedNetNames( aNetNames ),
144 m_netCandidates( aCandidateNetNames ),
145 m_previewer( aPreviewer )
146{
147 m_matchingNets->SetFont( KIUI::GetInfoFont( this ) );
148 m_info->SetFont( KIUI::GetInfoFont( this ).Italic() );
149
150 // @translate the string below.
151 if( aParent->GetFrameType() == FRAME_PCB_EDITOR )
152 m_info->SetLabel( wxT( "Note: complete netclass assignments can be edited in Board "
153 "Setup > Project." ) );
154
156
158}
159
160
162{
163 if( !wxWindow::TransferDataToWindow() )
164 return false;
165
166 std::shared_ptr<NET_SETTINGS>& netSettings = m_frame->Prj().GetProjectFile().m_NetSettings;
167
169
170 for( const auto& [name, netclass] : netSettings->GetNetclasses() )
171 m_netclassCtrl->Append( name );
172
173 if( m_netclassCtrl->GetCount() > 1 )
174 m_netclassCtrl->SetSelection( 1 ); // First non-Default netclass
175 else
176 m_netclassCtrl->SetSelection( 0 ); // Default netclass
177
178 const wxString initialNetclassPattern = GetNetclassPatternForSet( m_selectedNetNames );
179 m_patternCtrl->SetValue( initialNetclassPattern );
180
181 return true;
182}
183
184
186{
187 std::shared_ptr<NET_SETTINGS>& netSettings = m_frame->Prj().GetProjectFile().m_NetSettings;
188
189 if( m_patternCtrl->GetValue().IsEmpty() )
190 return true;
191
192 netSettings->SetNetclassPatternAssignment( m_patternCtrl->GetValue(),
193 m_netclassCtrl->GetStringSelection() );
194
195 return true;
196}
197
198
199void DIALOG_ASSIGN_NETCLASS::onPatternText( wxCommandEvent& aEvent )
200{
201 wxString pattern = m_patternCtrl->GetValue();
202
203 if( pattern != m_lastPattern )
204 {
205 m_matchingNets->Clear();
206
207 std::vector<wxString> matchingNetNames;
208
209 if( !pattern.IsEmpty() )
210 {
211 EDA_COMBINED_MATCHER matcher( pattern, CTX_NETCLASS );
212
213 m_matchingNets->Report( _( "<b>Currently matching nets:</b>" ) );
214
215 for( const wxString& net : m_netCandidates )
216 {
217 if( matcher.StartsWith( net ) )
218 {
219 m_matchingNets->Report( net );
220 matchingNetNames.push_back( net );
221 }
222 }
223 }
224
225 m_matchingNets->Flush();
226
227 m_previewer( matchingNetNames );
228 m_lastPattern = pattern;
229 }
230}
const char * name
DIALOG_ASSIGN_NETCLASS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Add Netclass Assignment"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE)
void onPatternText(wxCommandEvent &aEvent) override
const std::set< wxString > m_selectedNetNames
std::function< void(const std::vector< wxString > &)> m_previewer
DIALOG_ASSIGN_NETCLASS(EDA_BASE_FRAME *aParent, const std::set< wxString > &aNetNames, const std::set< wxString > aCandidateNetNames, const std::function< void(const std::vector< wxString > &)> &aPreviewer)
std::set< wxString > m_netCandidates
void SetupStandardButtons(std::map< int, wxString > aLabels={})
void finishDialogSettings()
In all dialogs, we must call the same functions to fix minimal dlg size, the default position and per...
The base frame for deriving all KiCad main window classes.
FRAME_T GetFrameType() const
bool StartsWith(const wxString &aTerm)
static const char Default[]
the name of the default NETCLASS
Definition netclass.h:47
static wxString GetStringCommonPrefix(const wxArrayString &aSet)
static wxString GetNetclassPatternForSet(const std::set< wxString > &aNetNames)
Propose a netclass pattern for a set of net names.
wxString UpgradeGlobStarToRegex(const wxString &aPattern)
#define _(s)
Base window classes and related definitions.
@ CTX_NETCLASS
@ FRAME_PCB_EDITOR
Definition frame_type.h:42
KICOMMON_API wxFont GetInfoFont(wxWindow *aWindow)
void StrNumSort(T &aList, CASE_SENSITIVITY aCaseSensitivity)
Sort a container of wxString objects, in place, using the StrNumCmp() function.
wxString result
Test unit parsing edge cases and error handling.