KiCad PCB EDA Suite
Loading...
Searching...
No Matches
dialog_resolve_field_case_conflicts.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 modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * 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, see <https://www.gnu.org/licenses/>.
18 */
19
21
22#include <sch_edit_frame.h>
23#include <sch_symbol.h>
24#include <sch_commit.h>
25#include <wx/grid.h>
26
27#include "grid_tricks.h"
28
29
31 std::vector<FIELD_CASE_CONFLICT> conflicts ) :
33 m_frame( aFrame ),
34 m_conflicts( std::move( conflicts ) ),
35 m_rowAction( m_conflicts.size(), 0 )
36{
37 m_grid->SetSelectionMode( wxGrid::wxGridSelectRows );
38
39 m_headerLabel->SetLabel( wxString::Format( _( "%zu symbols have user fields whose names differ only in case. "
40 "Choose how to resolve each before opening the table." ),
41 m_conflicts.size() ) );
42
43 m_grid->PushEventHandler( new GRID_TRICKS( m_grid ) );
44 m_grid->SetupColumnAutosizer( 3 );
45
47
48 SetupStandardButtons( { { wxID_OK, _( "Apply and Continue" ) },
49 { wxID_CANCEL, _( "Cancel" ) } } );
50
52}
53
54
56{
57 // destroy GRID_TRICKS before m_conflictsGrid.
58 m_grid->PopEventHandler( true );
59}
60
61
63{
64 m_grid->BeginBatch();
65 m_grid->ClearRows();
66 m_grid->AppendRows( static_cast<int>( m_conflicts.size() ) );
67
68 auto formatValue =
69 []( const wxString& aValue )
70 {
71 return aValue.IsEmpty() ? wxString( _( "(empty)" ) ) : aValue;
72 };
73
74 for( int i = 0; i < (int) m_conflicts.size(); ++i )
75 {
76 const FIELD_CASE_CONFLICT& c = m_conflicts[i];
77
78 m_grid->SetCellValue( i, 0, c.reference );
79 m_grid->SetCellValue( i, 1, c.sheetPath.PathHumanReadable( false ) );
80
81 wxString fieldsLabel = c.variants[0].first;
82 wxString valuesLabel = formatValue( c.variants[0].second );
83
84 for( size_t ii = 1; ii < c.variants.size(); ++ii )
85 {
86 fieldsLabel += '\n' + c.variants[ii].first;
87 valuesLabel += '\n' + formatValue( c.variants[ii].second );
88 }
89
90 m_grid->SetCellValue( i, 2, fieldsLabel );
91 m_grid->SetCellValue( i, 3, valuesLabel );
92
93 wxArrayString choices;
94 choices.Add( wxString::Format( _( "Keep '%s'" ), c.variants[0].first ) );
95
96 for( size_t ii = 1; ii < c.variants.size(); ++ii )
97 choices.Add( wxString::Format( _( "Keep '%s'" ), c.variants[ii].first ) );
98
99 choices.Add( _( "Join values" ) );
100
101 m_grid->SetCellEditor( i, 4, new wxGridCellChoiceEditor( choices, false ) );
102 m_grid->SetCellValue( i, 4, choices[0] );
103 }
104
105 m_grid->AutoSizeRows();
106 m_grid->EndBatch();
107}
108
109
110std::vector<int>
112{
113 std::vector<int> siblings;
114
115 if( aRow < 0 || static_cast<size_t>( aRow ) >= m_conflicts.size() )
116 return siblings;
117
118 const wxString& key = m_conflicts[aRow].caseFoldedKey;
119
120 for( size_t i = 0; i < m_conflicts.size(); ++i )
121 {
122 if( static_cast<int>( i ) != aRow && m_conflicts[i].caseFoldedKey.IsSameAs( key, false ) )
123 siblings.push_back( static_cast<int>( i ) );
124 }
125
126 return siblings;
127}
128
129
131{
132 int row = event.GetRow();
133 int col = event.GetCol();
134
135 if( col != 4 || row < 0 || static_cast<size_t>( row ) >= m_conflicts.size() )
136 {
137 event.Skip();
138 return;
139 }
140
141 m_rowAction[row] = -1; // join values
142
143 for( int ii = 0; ii < (int) m_conflicts[row].variants.size(); ++ii )
144 {
145 if( m_grid->GetCellValue( row, 4 ).Contains( m_conflicts[row].variants[ii].first ) )
146 {
147 m_rowAction[row] = ii;
148 break;
149 }
150 }
151
152 if( m_bulkApplyCheckbox->IsChecked() )
153 {
154 for( int sibling : findSiblingRows( row ) )
155 {
156 m_rowAction[sibling] = m_rowAction[row];
157 m_grid->SetCellValue( sibling, 4, m_grid->GetCellValue( row, 4 ) );
158 }
159 }
160
161 event.Skip();
162}
163
164
166{
168 EndModal( wxID_OK );
169}
170
171
173{
174 SCH_COMMIT commit( m_frame );
175 wxString sep = m_separatorCtrl->GetValue();
176
177 for( size_t row = 0; row < m_conflicts.size(); ++row )
178 {
180 SCH_SYMBOL* sym = c.symbol;
181 int action = m_rowAction[row];
182
183 commit.Modify( sym, c.sheetPath.LastScreen() );
184
185 wxString value;
186
187 if( action < 0 ) // join
188 {
189 value = c.variants[0].second;
190
191 for( const auto& [fieldName, fieldValue] : c.variants )
192 {
193 if( !value.IsEmpty() && !fieldValue.IsEmpty() )
194 value += sep;
195
196 value += fieldValue;
197 }
198
199 action = 0; // apply result to first field
200 }
201 else
202 {
203 if( action < (int) c.variants.size() )
204 value = c.variants[action].second;
205
206 for( const auto& [fieldName, fieldValue] : c.variants )
207 {
208 if( value.IsEmpty() )
209 value = fieldValue;
210 }
211 }
212
213 for( int jj = 0; jj < (int) c.variants.size(); ++jj )
214 {
215 if( jj == action )
216 {
217 if( SCH_FIELD* field = sym->GetField( c.variants[jj].first ) )
218 field->SetText( value );
219 }
220 else
221 {
222 sym->RemoveField( c.variants[jj].first );
223 }
224 }
225 }
226
227 commit.Push( _( "Resolve Duplicate Field Names" ) );
228}
COMMIT & Modify(EDA_ITEM *aItem, BASE_SCREEN *aScreen=nullptr, RECURSE_MODE aRecurse=RECURSE_MODE::NO_RECURSE)
Modify a given item in the model.
Definition commit.h:102
DIALOG_RESOLVE_FIELD_CASE_CONFLICTS_BASE(wxWindow *parent, wxWindowID id=wxID_ANY, const wxString &title=_("Resolve Field Name Conflicts"), const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER)
DIALOG_RESOLVE_FIELD_CASE_CONFLICTS(wxWindow *aParent, SCH_EDIT_FRAME *aFrame, std::vector< FIELD_CASE_CONFLICT > conflicts)
void onApplyAndContinue(wxCommandEvent &event) override
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...
Add mouse and command handling (such as cut, copy, and paste) to a WX_GRID instance.
Definition grid_tricks.h:57
Commit for the schematic and symbol editors.
Definition sch_commit.h:54
void Push(const wxString &aMessage=wxEmptyString, int aCommitFlags=0) override
Execute the changes.
Schematic editor (Eeschema) main window.
SCH_SCREEN * LastScreen()
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false, bool aEscapeSheetNames=false) const
Return the sheet path in a human readable form made from the sheet names.
Schematic symbol object.
Definition sch_symbol.h:75
void RemoveField(const wxString &aFieldName)
Remove a user field from the symbol.
SCH_FIELD * GetField(FIELD_T aFieldType)
Return a mandatory field in this symbol.
#define _(s)
STL namespace.
std::vector< std::pair< wxString, wxString > > variants