KiCad PCB EDA Suite
Loading...
Searching...
No Matches
lib_fields_data_model.h
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 (C) 2024 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 along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <sch_reference_list.h>
23#include <wx/grid.h>
24#include <wx/arrstr.h>
26#include <fields_data_model.h>
27
28
30{
31 LIB_DATA_MODEL_ROW( const LIB_SYMBOL* aFirstReference, GROUP_TYPE aType ) :
32 m_ItemNumber( 0 ),
33 m_Flag( aType ),
34 m_Refs( { aFirstReference } )
35 {
36 }
37
40 std::vector<const LIB_SYMBOL*> m_Refs;
41};
42
43
45{
46 wxString m_fieldName;
47 wxString m_label;
49 bool m_show;
50 bool m_group;
52};
53
54
56{
58 {
59 m_originalData = wxEmptyString;
60 m_currentData = wxEmptyString;
61 m_originallyEmpty = false;
62 m_currentlyEmpty = false;
63 m_isModified = false;
64 m_isStriped = false;
66 m_derivedSymbolName = wxEmptyString;
67 }
68
70 wxString m_currentData;
77};
78
79
81{
82public:
84 m_edited( false ),
85 m_sortColumn( 0 ),
86 m_sortAscending( false ),
87 m_filter( wxEmptyString ),
88 m_groupingEnabled( false ),
90 {
91 }
92
94 {
95 for( auto& pair : m_stripedRenderers )
96 pair.second->DecRef();
97
98 m_stripedRenderers.clear();
99 }
100
101 static const wxString QUANTITY_VARIABLE;
102 static const wxString ITEM_NUMBER_VARIABLE;
103
104 void CreateDerivedSymbol( int aRow, int aCol, wxString& aNewSymbolName );
105 void CreateDerivedSymbolImmediate( int aRow, int aCol, wxString& aNewSymbolName );
106
107 void AddColumn( const wxString& aFieldName, const wxString& aLabel, bool aAddedByUser, bool aIsCheckbox );
108 void RemoveColumn( int aCol );
109 void RenameColumn( int aCol, const wxString& newName );
110
111 void MoveColumn( int aCol, int aNewPos )
112 {
113 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
114
115 if( aCol == aNewPos )
116 {
117 return;
118 }
119 else if( aCol < aNewPos )
120 {
121 std::rotate( std::begin( m_cols ) + aCol, std::begin( m_cols ) + aCol + 1,
122 std::begin( m_cols ) + aNewPos + 1 );
123 }
124 else
125 {
126 std::rotate( std::begin( m_cols ) + aNewPos, std::begin( m_cols ) + aCol,
127 std::begin( m_cols ) + aCol + 1 );
128 }
129 }
130
131 int GetNumberRows() override { return (int) m_rows.size(); }
132 int GetNumberCols() override { return (int) m_cols.size(); }
133
134 void SetColLabelValue( int aCol, const wxString& aLabel ) override
135 {
136 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
137 m_cols[aCol].m_label = aLabel;
138 }
139
140 wxString GetColLabelValue( int aCol ) override
141 {
142 wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
143 return m_cols[aCol].m_label;
144 }
145
146 wxString GetColFieldName( int aCol )
147 {
148 wxCHECK( aCol >= 0 && aCol < (int) m_cols.size(), wxString() );
149 return m_cols[aCol].m_fieldName;
150 }
151
152 int GetFieldNameCol( const wxString& aFieldName );
153
154 void SetFieldsOrder( const std::vector<wxString>& aNewOrder );
155
156 bool IsEmptyCell( int aRow, int aCol ) override
157 {
158 return false; // don't allow adjacent cell overflow, even if we are actually empty
159 }
160
161 wxString GetValue( int aRow, int aCol ) override;
162 wxString GetTypeName( int row, int col ) override;
163 wxString GetValue( const LIB_DATA_MODEL_ROW& group, int aCol );
164 void SetValue( int aRow, int aCol, const wxString& aValue ) override;
165
166 wxGridCellAttr* GetAttr( int row, int col, wxGridCellAttr::wxAttrKind kind ) override;
167 void RevertRow( int aRow );
168 void ClearCell( int aRow, int aCol );
169
170 bool ColIsValue( int aCol );
171 bool ColIsCheck( int aCol );
172
173 void SetSorting( int aCol, bool ascending )
174 {
175 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
176 m_sortColumn = aCol;
177 m_sortAscending = ascending;
178 }
179
180 int GetSortCol() { return m_sortColumn; }
181 bool GetSortAsc() { return m_sortAscending; }
182 const LIB_SYMBOL* GetSymbolForRow( int aRow )
183 {
184 wxCHECK( aRow >= 0 && aRow < (int) m_rows.size(), nullptr );
185 return m_rows[aRow].m_Refs[0];
186 }
187
188 void GetSymbolNames( wxArrayString& aList )
189 {
190 aList.Clear();
191
192 for( const LIB_SYMBOL* symbol : m_symbolsList )
193 aList.Add( symbol->GetName() );
194 }
195
196 void SetSymbols( const std::vector<LIB_SYMBOL*>& aSymbolsList ) { m_symbolsList = aSymbolsList; }
197 void RebuildRows();
198
199 void ExpandRow( int aRow );
200 void CollapseRow( int aRow );
201 void ExpandCollapseRow( int aRow );
202 void CollapseForSort();
203 void ExpandAfterSort();
204
205 void ApplyData( std::function<void( LIB_SYMBOL* )> symbolChangeHandler,
206 std::function<void()> postApplyHandler = nullptr );
207
209 std::vector<std::pair<LIB_SYMBOL*, wxString>> GetAndClearCreatedDerivedSymbols()
210 {
211 auto result = std::move( m_createdDerivedSymbols );
213 return result;
214 }
215
216 bool IsEdited() { return m_edited; }
217
218 int GetDataWidth( int aCol );
219
220 void SetFilter( const wxString& aFilter ) { m_filter = aFilter; }
221 const wxString& GetFilter() { return m_filter; }
222
225
226 void SetGroupColumn( int aCol, bool group )
227 {
228 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
229 m_cols[aCol].m_group = group;
230 }
231
232 bool GetGroupColumn( int aCol )
233 {
234 wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
235 return m_cols[aCol].m_group;
236 }
237
238 void SetShowColumn( int aCol, bool show )
239 {
240 wxCHECK_RET( aCol >= 0 && aCol < (int) m_cols.size(), "Invalid Column Number" );
241 m_cols[aCol].m_show = show;
242 }
243
244 bool GetShowColumn( int aCol )
245 {
246 wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
247 return m_cols[aCol].m_show;
248 }
249
250 bool IsRowEditable( int aRow )
251 {
252 wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
253 return m_rows[aRow].m_Flag == GROUP_SINGLETON || m_rows[aRow].m_Flag == GROUP_SINGLETON;
254 }
255
256 bool IsCellEdited( int aRow, int aCol )
257 {
258 wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
259 wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
260 return m_dataStore[m_rows[aRow].m_Refs[0]->m_Uuid][m_cols[aCol].m_fieldName].m_isModified;
261 }
262
263 bool IsCellClear( int aRow, int aCol )
264 {
265 wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
266 wxCHECK_MSG( aCol >= 0 && aCol < (int) m_cols.size(), false, "Invalid Column Number" );
267 return m_dataStore[m_rows[aRow].m_Refs[0]->m_Uuid][m_cols[aCol].m_fieldName].m_currentlyEmpty;
268 }
269
270 bool IsRowSingleSymbol( int aRow )
271 {
272 wxCHECK_MSG( aRow >= 0 && aRow < (int) m_rows.size(), false, "Invalid Row Number" );
273 return m_rows[aRow].m_Flag == GROUP_SINGLETON || m_rows[aRow].m_Flag == CHILD_ITEM;
274 }
275
276private:
277 static bool cmp( const LIB_DATA_MODEL_ROW& lhGroup, const LIB_DATA_MODEL_ROW& rhGroup,
278 LIB_FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending );
279
280 bool groupMatch( const LIB_SYMBOL* lhRef, const LIB_SYMBOL* rhRef );
281 wxString getAttributeValue( const LIB_SYMBOL*, const wxString& aAttributeName );
282 void setAttributeValue( LIB_SYMBOL* aSymbol, const wxString& aAttributeName, const wxString& aValue );
283
284 void createActualDerivedSymbol( const LIB_SYMBOL* aParentSymbol, const wxString& aNewSymbolName,
285 const KIID& aNewSymbolUuid );
286
287 void Sort();
288
289 void updateDataStoreSymbolField( const LIB_SYMBOL* aSymbol, const wxString& aFieldName );
290
291 bool isStripeableField( int aCol );
292 wxGridCellRenderer* getStripedRenderer( int aCol ) const;
293
294protected:
295 std::vector<LIB_SYMBOL*> m_symbolsList;
299 wxString m_filter;
301
302 std::vector<LIB_DATA_MODEL_COL> m_cols;
303 std::vector<LIB_DATA_MODEL_ROW> m_rows;
304
305 // Data store
306 // The data model is fundamentally symbols X fieldNames.
307 // A map of symbolID : fieldSet, where fieldSet is a map of fieldName : LIB_DATA_ELEMENT
308 std::map<KIID, std::map<wxString, LIB_DATA_ELEMENT>> m_dataStore;
309
310 // Track newly created derived symbols for library manager integration
311 std::vector<std::pair<LIB_SYMBOL*, wxString>> m_createdDerivedSymbols; // symbol, library name
312
313 // stripe bitmap support
315 mutable std::map<wxString, wxGridCellRenderer*> m_stripedRenderers;
316};
Definition kiid.h:49
wxString GetColLabelValue(int aCol) override
void SetFieldsOrder(const std::vector< wxString > &aNewOrder)
wxGridCellRenderer * getStripedRenderer(int aCol) const
void SetValue(int aRow, int aCol, const wxString &aValue) override
void GetSymbolNames(wxArrayString &aList)
wxString getAttributeValue(const LIB_SYMBOL *, const wxString &aAttributeName)
std::vector< std::pair< LIB_SYMBOL *, wxString > > m_createdDerivedSymbols
static bool cmp(const LIB_DATA_MODEL_ROW &lhGroup, const LIB_DATA_MODEL_ROW &rhGroup, LIB_FIELDS_EDITOR_GRID_DATA_MODEL *dataModel, int sortCol, bool ascending)
std::map< KIID, std::map< wxString, LIB_DATA_ELEMENT > > m_dataStore
void MoveColumn(int aCol, int aNewPos)
std::map< wxString, wxGridCellRenderer * > m_stripedRenderers
wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) override
void SetGroupColumn(int aCol, bool group)
void CreateDerivedSymbolImmediate(int aRow, int aCol, wxString &aNewSymbolName)
wxString GetValue(int aRow, int aCol) override
void createActualDerivedSymbol(const LIB_SYMBOL *aParentSymbol, const wxString &aNewSymbolName, const KIID &aNewSymbolUuid)
std::vector< LIB_DATA_MODEL_COL > m_cols
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser, bool aIsCheckbox)
void ApplyData(std::function< void(LIB_SYMBOL *)> symbolChangeHandler, std::function< void()> postApplyHandler=nullptr)
std::vector< LIB_DATA_MODEL_ROW > m_rows
int GetFieldNameCol(const wxString &aFieldName)
void updateDataStoreSymbolField(const LIB_SYMBOL *aSymbol, const wxString &aFieldName)
void RenameColumn(int aCol, const wxString &newName)
std::vector< LIB_SYMBOL * > m_symbolsList
void SetColLabelValue(int aCol, const wxString &aLabel) override
STRIPED_STRING_RENDERER * m_stripedStringRenderer
bool groupMatch(const LIB_SYMBOL *lhRef, const LIB_SYMBOL *rhRef)
void SetSorting(int aCol, bool ascending)
void CreateDerivedSymbol(int aRow, int aCol, wxString &aNewSymbolName)
void setAttributeValue(LIB_SYMBOL *aSymbol, const wxString &aAttributeName, const wxString &aValue)
std::vector< std::pair< LIB_SYMBOL *, wxString > > GetAndClearCreatedDerivedSymbols()
Get and clear the list of newly created derived symbols for library manager processing.
void SetFilter(const wxString &aFilter)
wxString GetTypeName(int row, int col) override
const LIB_SYMBOL * GetSymbolForRow(int aRow)
void SetShowColumn(int aCol, bool show)
void SetSymbols(const std::vector< LIB_SYMBOL * > &aSymbolsList)
bool IsEmptyCell(int aRow, int aCol) override
Define a library symbol object.
Definition lib_symbol.h:85
@ GROUP_SINGLETON
@ CHILD_ITEM
STRIPED_CELL_RENDERER< wxGridCellStringRenderer > STRIPED_STRING_RENDERER
LIB_DATA_MODEL_ROW(const LIB_SYMBOL *aFirstReference, GROUP_TYPE aType)
std::vector< const LIB_SYMBOL * > m_Refs
wxString result
Test unit parsing edge cases and error handling.