KiCad PCB EDA Suite
Loading...
Searching...
No Matches
hierarchy_pane.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 (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
5 * Copyright (C) 2008 Wayne Stambaugh <[email protected]>
6 * Copyright (C) 2004-2022 KiCad Developers, see AUTHORS.txt for contributors.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, you may find one here:
20 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21 * or you may search the http://www.gnu.org website for the version 2 license,
22 * or you may write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24 */
25
26#include <bitmaps.h>
27#include <sch_edit_frame.h>
28#include <sch_sheet.h>
29#include <sch_sheet_path.h>
30#include <schematic.h>
31#include <tool/tool_manager.h>
32#include <tools/ee_actions.h>
33
34#include <hierarchy_pane.h>
35#include <kiface_base.h>
36#include <eeschema_settings.h>
37
38#include <wx/object.h>
39#include <wx/generic/textdlgg.h>
40#include <wx/menu.h>
41
45class TREE_ITEM_DATA : public wxTreeItemData
46{
47public:
49
51 wxTreeItemData()
52 {
53 m_SheetPath = sheet;
54 }
55};
56
57
58// Need to use wxRTTI macros in order for OnCompareItems to work properly
59// See: https://docs.wxwidgets.org/3.1/classwx_tree_ctrl.html#ab90a465793c291ca7aa827a576b7d146
61
62
63int HIERARCHY_TREE::OnCompareItems( const wxTreeItemId& item1, const wxTreeItemId& item2 )
64{
65 SCH_SHEET_PATH* item1Path = &static_cast<TREE_ITEM_DATA*>( GetItemData( item1 ) )->m_SheetPath;
66 SCH_SHEET_PATH* item2Path = &static_cast<TREE_ITEM_DATA*>( GetItemData( item2 ) )->m_SheetPath;
67
68 return item1Path->ComparePageNum( *item2Path );
69}
70
71
73 WX_PANEL( aParent )
74{
75 wxASSERT( dynamic_cast<SCH_EDIT_FRAME*>( aParent ) );
76
77 m_frame = aParent;
78
79 wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
80 SetSizer( sizer );
81 m_tree = new HIERARCHY_TREE( this );
82
83 // Make an image list containing small icons
84 // All icons are expected having the same size.
85 wxBitmap tree_nosel_bm( KiBitmap( BITMAPS::tree_nosel ) );
86 wxImageList* imageList = new wxImageList( tree_nosel_bm.GetWidth(), tree_nosel_bm.GetHeight(),
87 true, 2 );
88
89 imageList->Add( tree_nosel_bm );
90 imageList->Add( KiBitmap( BITMAPS::tree_sel ) );
91
92 m_tree->AssignImageList( imageList );
93
94 sizer->Add( m_tree, 1, wxEXPAND, wxBORDER_NONE, 0 );
95
96 m_events_bound = false;
97
99
100 // Enable selection events
101 Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
102 Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
103 Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onRightClick, this );
104
105 m_events_bound = true;
106}
107
108
110{
111 Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
112 Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
113 Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onRightClick, this );
114}
115
116
117void HIERARCHY_PANE::buildHierarchyTree( SCH_SHEET_PATH* aList, const wxTreeItemId& aParent )
118{
119 std::vector<SCH_ITEM*> sheetChildren;
120 aList->LastScreen()->GetSheets( &sheetChildren );
121
122 for( SCH_ITEM* aItem : sheetChildren )
123 {
124 SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
125 aList->push_back( sheet );
126
127 wxString sheetName = formatPageString( sheet->GetFields()[SHEETNAME].GetShownText( false ),
128 aList->GetPageNumber() );
129 wxTreeItemId child = m_tree->AppendItem( aParent, sheetName, 0, 1 );
130 m_tree->SetItemData( child, new TREE_ITEM_DATA( *aList ) );
131
132 buildHierarchyTree( aList, child );
133 aList->pop_back();
134 }
135
136 m_tree->SortChildren( aParent );
137}
138
139
141{
142 bool eventsWereBound = m_events_bound;
143
144 if( eventsWereBound )
145 {
146 // Disable selection events
147 Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
148 Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
149 Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onRightClick, this );
150
151 m_events_bound = false;
152 }
153
154 bool sheetSelected = false;
155
156 std::function<void( const wxTreeItemId& )> recursiveDescent =
157 [&]( const wxTreeItemId& id )
158 {
159 wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
160
161 TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
162
163 if( itemData->m_SheetPath == m_frame->GetCurrentSheet() )
164 {
165 m_tree->EnsureVisible( id );
166 m_tree->SetItemBold( id, true );
167 }
168 else
169 {
170 m_tree->SetItemBold( id, false );
171 }
172
173 if( itemData->m_SheetPath.Last()->IsSelected() )
174 {
175 m_tree->EnsureVisible( id );
176 m_tree->SelectItem( id );
177 sheetSelected = true;
178 }
179
180 wxTreeItemIdValue cookie;
181 wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
182
183 while( child.IsOk() )
184 {
185 recursiveDescent( child );
186 child = m_tree->GetNextChild( id, cookie );
187 }
188 };
189
190 recursiveDescent( m_tree->GetRootItem() );
191
192 if( !sheetSelected && m_tree->GetSelection() )
193 m_tree->SelectItem( m_tree->GetSelection(), false );
194
195 if( eventsWereBound )
196 {
197 // Enable selection events
198 Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
199 Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
200 Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onRightClick, this );
201
202 m_events_bound = true;
203 }
204}
205
206
208{
209 Freeze();
210
211 bool eventsWereBound = m_events_bound;
212
213 if( eventsWereBound )
214 {
215 // Disable selection events
216 Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
217 Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
218 Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onRightClick, this );
219
220 m_events_bound = false;
221 }
222
223 m_list.clear();
225
226 m_tree->DeleteAllItems();
227
228 wxTreeItemId root = m_tree->AddRoot( getRootString(), 0, 1 );
229 m_tree->SetItemData( root, new TREE_ITEM_DATA( m_list ) );
230
231 buildHierarchyTree( &m_list, root );
233
234 m_tree->ExpandAll();
235
236 if( eventsWereBound )
237 {
238 // Enable selection events
239 Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
240 Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
241 Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onRightClick, this );
242
243 m_events_bound = true;
244 }
245
246 Thaw();
247}
248
249
250void HIERARCHY_PANE::onSelectSheetPath( wxTreeEvent& aEvent )
251{
252 wxTreeItemId itemSel = m_tree->GetSelection();
253 TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( itemSel ) );
254
255 SetCursor( wxCURSOR_ARROWWAIT );
257 &itemData->m_SheetPath );
258 SetCursor( wxCURSOR_ARROW );
259}
260
261
262void HIERARCHY_PANE::onRightClick( wxTreeEvent& aEvent )
263{
264 wxTreeItemId itemSel = m_tree->GetFocusedItem();
265
266 if( !itemSel.IsOk() )
267 return;
268
269 TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( itemSel ) );
270
271 if( !itemData )
272 return;
273
274 wxMenu ctxMenu;
275
276 ctxMenu.Append( 1, _( "Edit Page Number" ) );
277
278 if( GetPopupMenuSelectionFromUser( ctxMenu ) == 1 )
279 {
280 wxString msg;
281 wxString sheetPath = itemData->m_SheetPath.PathHumanReadable( false, true );
282 wxString pageNumber = itemData->m_SheetPath.GetPageNumber();
283
284 msg.Printf( _( "Enter page number for sheet path %s" ),
285 ( sheetPath.Length() > 20 ) ? wxS( " \n" ) + sheetPath + wxT( ": " )
286 : sheetPath + wxT( ": " ) );
287
288 wxTextEntryDialog dlg( m_frame, msg, _( "Edit Sheet Page Number" ), pageNumber );
289
290 dlg.SetTextValidator( wxFILTER_ALPHANUMERIC ); // No white space.
291
292 if( dlg.ShowModal() == wxID_OK && dlg.GetValue() != itemData->m_SheetPath.GetPageNumber() )
293 {
294 SCH_SHEET_PATH parentPath = itemData->m_SheetPath;
295 parentPath.pop_back();
296
297 m_frame->SaveCopyInUndoList( parentPath.LastScreen(), itemData->m_SheetPath.Last(),
298 UNDO_REDO::CHANGED, false );
299
300 itemData->m_SheetPath.SetPageNumber( dlg.GetValue() );
301
302 if( itemData->m_SheetPath == m_frame->GetCurrentSheet() )
303 {
304 m_frame->GetScreen()->SetPageNumber( dlg.GetValue() );
306 }
307
308 m_frame->OnModify();
309 }
310 }
311}
312
313
315{
316 SCH_SHEET* rootSheet = &m_frame->Schematic().Root();
317 SCH_SHEET_PATH rootPath;
318 rootPath.push_back( rootSheet );
319
320 return formatPageString ( _( "Root" ), rootPath.GetPageNumber() );
321}
322
323
324wxString HIERARCHY_PANE::formatPageString( const wxString& aName, const wxString& aPage )
325{
326 return aName + wxT( " " ) + wxString::Format( _( "(page %s)" ), aPage );
327}
wxBitmap KiBitmap(BITMAPS aBitmap, int aHeightTag)
Construct a wxBitmap from an image identifier Returns the image from the active theme if the image ha...
Definition: bitmap.cpp:106
void SetPageNumber(const wxString &aPageNumber)
Definition: base_screen.h:79
bool IsSelected() const
Definition: eda_item.h:106
static TOOL_ACTION changeSheet
Definition: ee_actions.h:213
SCH_EDIT_FRAME * m_frame
HIERARCHY_TREE * m_tree
void onSelectSheetPath(wxTreeEvent &aEvent)
Open the selected sheet and display the corresponding screen when a tree item is selected.
wxString formatPageString(const wxString &aName, const wxString &aPage)
wxString getRootString()
SCH_SHEET_PATH m_list
void UpdateHierarchySelection()
Updates the tree's selection to match current page.
HIERARCHY_PANE(SCH_EDIT_FRAME *aParent)
void UpdateHierarchyTree()
Update the hierarchical tree of the schematic.
void buildHierarchyTree(SCH_SHEET_PATH *aList, const wxTreeItemId &aParent)
Create the hierarchical tree of the schematic.
void onRightClick(wxTreeEvent &aEvent)
Handle a right-click in the tree.
Navigation hierarchy tree control.
int OnCompareItems(const wxTreeItemId &item1, const wxTreeItemId &item2) override
SCH_SHEET & Root() const
Definition: schematic.h:105
Schematic editor (Eeschema) main window.
void OnModify() override
Must be called after a schematic change in order to set the "modify" flag and update other data struc...
SCH_SCREEN * GetScreen() const override
Return a pointer to a BASE_SCREEN or one of its derivatives.
void SaveCopyInUndoList(SCH_SCREEN *aScreen, SCH_ITEM *aItemToCopy, UNDO_REDO aTypeCommand, bool aAppend, bool aDirtyConnectivity=true)
Create a copy of the current schematic item, and put it in the undo list.
SCH_SHEET_PATH & GetCurrentSheet() const
SCHEMATIC & Schematic() const
void OnPageSettingsChange() override
Called when modifying the page settings.
Base class for any item which can be embedded within the SCHEMATIC container class,...
Definition: sch_item.h:150
void GetSheets(std::vector< SCH_ITEM * > *aItems) const
Similar to Items().OfType( SCH_SHEET_T ), but return the sheets in a deterministic order (L-R,...
Handle access to a stack of flattened SCH_SHEET objects by way of a path for creating a flattened sch...
int ComparePageNum(const SCH_SHEET_PATH &aSheetPathToTest) const
Compare sheets by their page number.
wxString PathHumanReadable(bool aUseShortRootName=true, bool aStripTrailingSeparator=false) const
Return the sheet path in a human readable form made from the sheet names.
SCH_SCREEN * LastScreen()
wxString GetPageNumber() const
void SetPageNumber(const wxString &aPageNumber)
Set the sheet instance user definable page number.
SCH_SHEET * Last() const
Return a pointer to the last SCH_SHEET of the list.
void push_back(SCH_SHEET *aSheet)
Forwarded method from std::vector.
void clear()
Forwarded method from std::vector.
void pop_back()
Forwarded method from std::vector.
Sheet symbol placed in a schematic, and is the entry point for a sub schematic.
Definition: sch_sheet.h:57
std::vector< SCH_FIELD > & GetFields()
Definition: sch_sheet.h:93
TOOL_MANAGER * GetToolManager() const
Return the MVC controller.
Definition: tools_holder.h:55
bool RunAction(const std::string &aActionName, T aParam)
Run the specified action immediately, pausing the current action to run the new one.
Definition: tool_manager.h:145
Store an SCH_SHEET_PATH of each sheet in hierarchy.
SCH_SHEET_PATH m_SheetPath
TREE_ITEM_DATA(SCH_SHEET_PATH &sheet)
static void recursiveDescent(wxSizer *aSizer, std::map< int, wxString > &aLabels)
#define _(s)
wxIMPLEMENT_ABSTRACT_CLASS(HIERARCHY_TREE, wxTreeCtrl)
@ SHEETNAME
Definition: sch_sheet.h:45
Definition of the SCH_SHEET_PATH and SCH_SHEET_LIST classes for Eeschema.