2011-12-08 21:05:43 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
2015-02-21 09:46:44 +00:00
|
|
|
* Copyright (C) 2004 Jean-Pierre Charras, jp.charras at wanadoo.fr
|
2017-09-20 12:44:52 +00:00
|
|
|
* Copyright (C) 2008 Wayne Stambaugh <stambaughw@gmail.com>
|
2024-01-06 12:56:16 +00:00
|
|
|
* Copyright (C) 2004-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
2011-12-08 21:05:43 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
2017-02-20 12:20:39 +00:00
|
|
|
#include <bitmaps.h>
|
2018-01-30 10:49:51 +00:00
|
|
|
#include <sch_edit_frame.h>
|
2012-01-23 04:33:36 +00:00
|
|
|
#include <sch_sheet.h>
|
|
|
|
#include <sch_sheet_path.h>
|
2024-04-24 12:36:34 +00:00
|
|
|
#include <sch_commit.h>
|
2020-05-13 02:00:37 +00:00
|
|
|
#include <schematic.h>
|
2019-04-14 00:44:05 +00:00
|
|
|
#include <tool/tool_manager.h>
|
2019-05-10 17:19:48 +00:00
|
|
|
#include <tools/ee_actions.h>
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
#include <hierarchy_pane.h>
|
2021-09-14 22:45:14 +00:00
|
|
|
#include <kiface_base.h>
|
2022-06-02 21:56:17 +00:00
|
|
|
#include <eeschema_settings.h>
|
2017-09-20 12:44:52 +00:00
|
|
|
|
2020-11-29 00:10:17 +00:00
|
|
|
#include <wx/object.h>
|
2022-09-27 11:31:47 +00:00
|
|
|
#include <wx/generic/textdlgg.h>
|
|
|
|
#include <wx/menu.h>
|
2016-11-16 10:07:02 +00:00
|
|
|
|
2017-09-20 12:44:52 +00:00
|
|
|
/**
|
|
|
|
* Store an SCH_SHEET_PATH of each sheet in hierarchy.
|
|
|
|
*/
|
2022-09-26 20:31:26 +00:00
|
|
|
class TREE_ITEM_DATA : public wxTreeItemData
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
|
|
|
public:
|
2009-12-02 21:44:03 +00:00
|
|
|
SCH_SHEET_PATH m_SheetPath;
|
2015-02-28 16:56:09 +00:00
|
|
|
|
2024-04-24 12:36:34 +00:00
|
|
|
TREE_ITEM_DATA( SCH_SHEET_PATH& sheet ) : wxTreeItemData(), m_SheetPath( sheet ) {}
|
2007-06-05 12:10:51 +00:00
|
|
|
};
|
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
|
2020-11-29 00:10:17 +00:00
|
|
|
// Need to use wxRTTI macros in order for OnCompareItems to work properly
|
|
|
|
// See: https://docs.wxwidgets.org/3.1/classwx_tree_ctrl.html#ab90a465793c291ca7aa827a576b7d146
|
|
|
|
wxIMPLEMENT_ABSTRACT_CLASS( HIERARCHY_TREE, wxTreeCtrl );
|
|
|
|
|
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
int HIERARCHY_TREE::OnCompareItems( const wxTreeItemId& item1, const wxTreeItemId& item2 )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2022-09-26 20:31:26 +00:00
|
|
|
SCH_SHEET_PATH* item1Path = &static_cast<TREE_ITEM_DATA*>( GetItemData( item1 ) )->m_SheetPath;
|
|
|
|
SCH_SHEET_PATH* item2Path = &static_cast<TREE_ITEM_DATA*>( GetItemData( item2 ) )->m_SheetPath;
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
return item1Path->ComparePageNum( *item2Path );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
HIERARCHY_PANE::HIERARCHY_PANE( SCH_EDIT_FRAME* aParent ) :
|
2022-09-26 20:31:26 +00:00
|
|
|
WX_PANEL( aParent )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2022-06-02 21:56:17 +00:00
|
|
|
wxASSERT( dynamic_cast<SCH_EDIT_FRAME*>( aParent ) );
|
2017-12-04 11:45:54 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
m_frame = aParent;
|
2012-07-10 12:26:26 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
wxBoxSizer* sizer = new wxBoxSizer( wxVERTICAL );
|
|
|
|
SetSizer( sizer );
|
|
|
|
m_tree = new HIERARCHY_TREE( this );
|
2012-07-10 12:26:26 +00:00
|
|
|
|
2024-03-05 13:38:46 +00:00
|
|
|
#ifdef __WXMAC__
|
|
|
|
// HiDPI-aware API; will be generally available in wxWidgets 3.4
|
|
|
|
wxVector<wxBitmapBundle> images;
|
|
|
|
images.push_back( KiBitmapBundle( BITMAPS::tree_nosel ) );
|
|
|
|
images.push_back( KiBitmapBundle( BITMAPS::tree_sel ) );
|
|
|
|
m_tree->SetImages( images );
|
|
|
|
#else
|
2022-06-02 21:56:17 +00:00
|
|
|
// Make an image list containing small icons
|
|
|
|
// All icons are expected having the same size.
|
|
|
|
wxBitmap tree_nosel_bm( KiBitmap( BITMAPS::tree_nosel ) );
|
2022-09-26 20:31:26 +00:00
|
|
|
wxImageList* imageList = new wxImageList( tree_nosel_bm.GetWidth(), tree_nosel_bm.GetHeight(),
|
|
|
|
true, 2 );
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
imageList->Add( tree_nosel_bm );
|
|
|
|
imageList->Add( KiBitmap( BITMAPS::tree_sel ) );
|
2008-07-31 15:30:57 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
m_tree->AssignImageList( imageList );
|
2024-03-05 13:38:46 +00:00
|
|
|
#endif
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2024-01-28 21:20:01 +00:00
|
|
|
sizer->Add( m_tree, 1, wxEXPAND, wxBORDER_NONE );
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2022-07-09 22:30:52 +00:00
|
|
|
m_events_bound = false;
|
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
UpdateHierarchyTree();
|
2022-07-09 22:30:52 +00:00
|
|
|
|
|
|
|
// Enable selection events
|
2022-12-12 11:46:20 +00:00
|
|
|
Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
|
|
|
Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onTreeItemRightClick, this );
|
|
|
|
Bind( wxEVT_CHAR_HOOK, &HIERARCHY_PANE::onCharHook, this );
|
2024-04-24 12:36:34 +00:00
|
|
|
m_tree->Bind( wxEVT_TREE_END_LABEL_EDIT, &HIERARCHY_PANE::onTreeEditFinished, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
m_tree->Bind( wxEVT_RIGHT_UP, &HIERARCHY_PANE::onRightClick, this );
|
2022-07-09 22:30:52 +00:00
|
|
|
m_events_bound = true;
|
2017-12-10 12:22:43 +00:00
|
|
|
}
|
|
|
|
|
2008-07-31 15:30:57 +00:00
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
HIERARCHY_PANE::~HIERARCHY_PANE()
|
2020-09-21 18:16:32 +00:00
|
|
|
{
|
2022-12-12 11:46:20 +00:00
|
|
|
Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
|
|
|
Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onTreeItemRightClick, this );
|
|
|
|
Unbind( wxEVT_CHAR_HOOK, &HIERARCHY_PANE::onCharHook, this );
|
2024-04-24 12:36:34 +00:00
|
|
|
m_tree->Unbind( wxEVT_TREE_END_LABEL_EDIT, &HIERARCHY_PANE::onTreeEditFinished, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
m_tree->Unbind( wxEVT_RIGHT_UP, &HIERARCHY_PANE::onRightClick, this );
|
2020-09-21 18:16:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
void HIERARCHY_PANE::buildHierarchyTree( SCH_SHEET_PATH* aList, const wxTreeItemId& aParent )
|
2017-12-10 12:22:43 +00:00
|
|
|
{
|
2020-05-03 14:52:31 +00:00
|
|
|
std::vector<SCH_ITEM*> sheetChildren;
|
|
|
|
aList->LastScreen()->GetSheets( &sheetChildren );
|
|
|
|
|
|
|
|
for( SCH_ITEM* aItem : sheetChildren )
|
2008-07-31 15:30:57 +00:00
|
|
|
{
|
2019-06-25 23:39:58 +00:00
|
|
|
SCH_SHEET* sheet = static_cast<SCH_SHEET*>( aItem );
|
2020-11-29 00:10:17 +00:00
|
|
|
aList->push_back( sheet );
|
|
|
|
|
2024-04-24 12:36:34 +00:00
|
|
|
wxString sheetNameBase = sheet->GetFields()[SHEETNAME].GetShownText( false );
|
|
|
|
wxString sheetName = formatPageString( sheetNameBase, aList->GetPageNumber() );
|
|
|
|
wxString sheetNumber = aList->GetPageNumber();
|
2022-06-02 21:56:17 +00:00
|
|
|
wxTreeItemId child = m_tree->AppendItem( aParent, sheetName, 0, 1 );
|
2022-09-26 20:31:26 +00:00
|
|
|
m_tree->SetItemData( child, new TREE_ITEM_DATA( *aList ) );
|
2019-06-25 23:39:58 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
buildHierarchyTree( aList, child );
|
|
|
|
aList->pop_back();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tree->SortChildren( aParent );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
void HIERARCHY_PANE::UpdateHierarchySelection()
|
2022-06-02 21:56:17 +00:00
|
|
|
{
|
2022-07-09 22:30:52 +00:00
|
|
|
bool eventsWereBound = m_events_bound;
|
|
|
|
|
|
|
|
if( eventsWereBound )
|
|
|
|
{
|
|
|
|
// Disable selection events
|
2022-12-12 11:46:20 +00:00
|
|
|
Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
|
|
|
Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onTreeItemRightClick, this );
|
2022-07-09 22:30:52 +00:00
|
|
|
|
|
|
|
m_events_bound = false;
|
|
|
|
}
|
|
|
|
|
2022-10-24 22:00:10 +00:00
|
|
|
std::function<void( const wxTreeItemId& )> recursiveDescent =
|
2022-10-24 21:38:53 +00:00
|
|
|
[&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
|
2022-06-02 21:56:17 +00:00
|
|
|
|
2022-10-24 21:38:53 +00:00
|
|
|
TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
|
2022-09-26 20:31:26 +00:00
|
|
|
|
2022-10-24 21:38:53 +00:00
|
|
|
if( itemData->m_SheetPath == m_frame->GetCurrentSheet() )
|
2022-10-24 22:00:10 +00:00
|
|
|
{
|
2024-01-06 17:25:16 +00:00
|
|
|
wxTreeItemId parent = m_tree->GetItemParent( id );
|
|
|
|
|
|
|
|
if( parent.IsOk() && !m_tree->IsExpanded( parent ) )
|
|
|
|
m_tree->Expand( parent );
|
|
|
|
|
|
|
|
if( !m_tree->IsVisible( id ) )
|
|
|
|
m_tree->EnsureVisible( id );
|
|
|
|
|
2022-10-24 22:00:10 +00:00
|
|
|
m_tree->SetItemBold( id, true );
|
2024-01-06 17:25:16 +00:00
|
|
|
m_tree->SetFocusedItem( id );
|
2022-10-24 22:00:10 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_tree->SetItemBold( id, false );
|
|
|
|
}
|
|
|
|
|
2022-10-24 21:38:53 +00:00
|
|
|
wxTreeItemIdValue cookie;
|
|
|
|
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
2022-09-26 20:31:26 +00:00
|
|
|
|
2022-10-24 21:38:53 +00:00
|
|
|
while( child.IsOk() )
|
|
|
|
{
|
2022-10-24 22:00:10 +00:00
|
|
|
recursiveDescent( child );
|
2022-10-24 21:38:53 +00:00
|
|
|
child = m_tree->GetNextChild( id, cookie );
|
|
|
|
}
|
|
|
|
};
|
2020-09-21 18:16:32 +00:00
|
|
|
|
2022-10-24 22:00:10 +00:00
|
|
|
recursiveDescent( m_tree->GetRootItem() );
|
|
|
|
|
2022-07-09 22:30:52 +00:00
|
|
|
if( eventsWereBound )
|
|
|
|
{
|
|
|
|
// Enable selection events
|
2022-12-12 11:46:20 +00:00
|
|
|
Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
|
|
|
Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onTreeItemRightClick, this );
|
2022-07-09 22:30:52 +00:00
|
|
|
|
|
|
|
m_events_bound = true;
|
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
void HIERARCHY_PANE::UpdateHierarchyTree()
|
2019-10-24 17:07:01 +00:00
|
|
|
{
|
2020-01-08 14:01:22 +00:00
|
|
|
Freeze();
|
|
|
|
|
2022-07-09 22:30:52 +00:00
|
|
|
bool eventsWereBound = m_events_bound;
|
|
|
|
|
|
|
|
if( eventsWereBound )
|
|
|
|
{
|
|
|
|
// Disable selection events
|
2022-12-12 11:46:20 +00:00
|
|
|
Unbind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
|
|
|
Unbind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
Unbind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onTreeItemRightClick, this );
|
2022-07-09 22:30:52 +00:00
|
|
|
|
|
|
|
m_events_bound = false;
|
|
|
|
}
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2024-03-17 13:02:07 +00:00
|
|
|
std::set<SCH_SHEET_PATH> expandedNodes;
|
|
|
|
|
|
|
|
std::function<void( const wxTreeItemId& )> getExpandedNodes =
|
|
|
|
[&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
|
|
|
|
|
|
|
|
TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
|
|
|
|
|
|
|
|
if( m_tree->IsExpanded( id ) )
|
|
|
|
expandedNodes.emplace( itemData->m_SheetPath );
|
|
|
|
|
|
|
|
wxTreeItemIdValue cookie;
|
|
|
|
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
|
|
|
|
|
|
|
while( child.IsOk() )
|
|
|
|
{
|
|
|
|
getExpandedNodes( child );
|
|
|
|
child = m_tree->GetNextChild( id, cookie );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
if( !m_tree->IsEmpty() )
|
|
|
|
getExpandedNodes( m_tree->GetRootItem() );
|
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
m_list.clear();
|
|
|
|
m_list.push_back( &m_frame->Schematic().Root() );
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
m_tree->DeleteAllItems();
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
wxTreeItemId root = m_tree->AddRoot( getRootString(), 0, 1 );
|
2022-09-26 20:31:26 +00:00
|
|
|
m_tree->SetItemData( root, new TREE_ITEM_DATA( m_list ) );
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
buildHierarchyTree( &m_list, root );
|
|
|
|
UpdateHierarchySelection();
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2024-03-17 13:02:07 +00:00
|
|
|
if( !expandedNodes.empty() )
|
|
|
|
{
|
|
|
|
std::function<void( const wxTreeItemId& )> expandNodes =
|
|
|
|
[&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
|
|
|
|
|
|
|
|
TREE_ITEM_DATA* itemData =
|
|
|
|
static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
|
|
|
|
|
|
|
|
if( expandedNodes.find( itemData->m_SheetPath ) != expandedNodes.end() )
|
|
|
|
m_tree->Expand( id );
|
|
|
|
|
|
|
|
wxTreeItemIdValue cookie;
|
|
|
|
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
|
|
|
|
|
|
|
while( child.IsOk() )
|
|
|
|
{
|
|
|
|
expandNodes( child );
|
|
|
|
child = m_tree->GetNextChild( id, cookie );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
expandNodes( m_tree->GetRootItem() );
|
|
|
|
}
|
|
|
|
else if( m_tree->ItemHasChildren( root ) )
|
|
|
|
{
|
2024-01-06 12:56:16 +00:00
|
|
|
m_tree->Expand( root );
|
2024-03-17 13:02:07 +00:00
|
|
|
}
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-07-09 22:30:52 +00:00
|
|
|
if( eventsWereBound )
|
|
|
|
{
|
|
|
|
// Enable selection events
|
2022-12-12 11:46:20 +00:00
|
|
|
Bind( wxEVT_TREE_ITEM_ACTIVATED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
|
|
|
Bind( wxEVT_TREE_SEL_CHANGED, &HIERARCHY_PANE::onSelectSheetPath, this );
|
2024-01-28 21:20:01 +00:00
|
|
|
Bind( wxEVT_TREE_ITEM_RIGHT_CLICK, &HIERARCHY_PANE::onTreeItemRightClick, this );
|
2022-07-09 22:30:52 +00:00
|
|
|
|
|
|
|
m_events_bound = true;
|
|
|
|
}
|
2020-01-08 14:01:22 +00:00
|
|
|
|
|
|
|
Thaw();
|
2019-10-24 17:07:01 +00:00
|
|
|
}
|
2007-06-05 12:10:51 +00:00
|
|
|
|
2020-11-29 00:10:17 +00:00
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
void HIERARCHY_PANE::onSelectSheetPath( wxTreeEvent& aEvent )
|
2007-06-05 12:10:51 +00:00
|
|
|
{
|
2022-06-02 21:56:17 +00:00
|
|
|
wxTreeItemId itemSel = m_tree->GetSelection();
|
2024-01-20 19:25:03 +00:00
|
|
|
|
|
|
|
if( !itemSel.IsOk() )
|
|
|
|
return;
|
|
|
|
|
2022-09-26 20:31:26 +00:00
|
|
|
TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( itemSel ) );
|
2020-04-12 23:09:17 +00:00
|
|
|
|
2024-01-20 19:25:03 +00:00
|
|
|
if( !itemData )
|
|
|
|
return;
|
|
|
|
|
2022-06-02 21:56:17 +00:00
|
|
|
SetCursor( wxCURSOR_ARROWWAIT );
|
2023-06-26 22:16:51 +00:00
|
|
|
m_frame->GetToolManager()->RunAction<SCH_SHEET_PATH*>( EE_ACTIONS::changeSheet,
|
2022-12-15 00:15:40 +00:00
|
|
|
&itemData->m_SheetPath );
|
2022-06-02 21:56:17 +00:00
|
|
|
SetCursor( wxCURSOR_ARROW );
|
2007-06-05 12:10:51 +00:00
|
|
|
}
|
|
|
|
|
2024-01-25 17:20:43 +00:00
|
|
|
void HIERARCHY_PANE::UpdateLabelsHierarchyTree()
|
|
|
|
{
|
|
|
|
// Update the labels of the hierarchical tree of the schematic.
|
|
|
|
// Must be called only for an up to date tree, to update displayed labels after
|
|
|
|
// a sheet name or a sheet number change.
|
|
|
|
|
|
|
|
std::function<void( const wxTreeItemId& )> updateLabel =
|
|
|
|
[&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
|
2024-04-24 12:36:34 +00:00
|
|
|
SCH_SHEET* sheet = itemData->m_SheetPath.Last();
|
|
|
|
wxString sheetNameLabel =
|
2024-03-17 13:02:07 +00:00
|
|
|
formatPageString( sheet->GetFields()[SHEETNAME].GetShownText( false ),
|
|
|
|
itemData->m_SheetPath.GetPageNumber() );
|
|
|
|
|
2024-01-25 17:20:43 +00:00
|
|
|
if( m_tree->GetItemText( id ) != sheetNameLabel )
|
|
|
|
m_tree->SetItemText( id, sheetNameLabel );
|
|
|
|
};
|
|
|
|
|
|
|
|
wxTreeItemId rootId = m_tree->GetRootItem();
|
|
|
|
updateLabel( rootId );
|
|
|
|
|
|
|
|
std::function<void( const wxTreeItemId& )> recursiveDescent =
|
|
|
|
[&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
|
|
|
|
wxTreeItemIdValue cookie;
|
|
|
|
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
|
|
|
|
|
|
|
while( child.IsOk() )
|
|
|
|
{
|
|
|
|
updateLabel( child );
|
|
|
|
recursiveDescent( child );
|
|
|
|
child = m_tree->GetNextChild( id, cookie );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
recursiveDescent( rootId );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-28 21:20:01 +00:00
|
|
|
void HIERARCHY_PANE::onTreeItemRightClick( wxTreeEvent& aEvent )
|
2022-09-26 20:57:32 +00:00
|
|
|
{
|
2024-01-28 21:20:01 +00:00
|
|
|
onRightClick( aEvent.GetItem() );
|
|
|
|
}
|
2022-12-12 10:42:51 +00:00
|
|
|
|
|
|
|
|
2024-01-28 21:20:01 +00:00
|
|
|
void HIERARCHY_PANE::onRightClick( wxMouseEvent& aEvent )
|
|
|
|
{
|
|
|
|
onRightClick( wxTreeItemId() );
|
|
|
|
}
|
2022-12-12 10:42:51 +00:00
|
|
|
|
|
|
|
|
2024-01-28 21:20:01 +00:00
|
|
|
void HIERARCHY_PANE::onRightClick( wxTreeItemId aItem )
|
|
|
|
{
|
|
|
|
wxMenu ctxMenu;
|
|
|
|
TREE_ITEM_DATA* itemData = nullptr;
|
|
|
|
|
|
|
|
if( !aItem.IsOk() )
|
|
|
|
aItem = m_tree->GetSelection();
|
|
|
|
|
|
|
|
if( aItem.IsOk() )
|
|
|
|
itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( aItem ) );
|
|
|
|
|
|
|
|
if( itemData )
|
|
|
|
{
|
2024-04-24 12:36:34 +00:00
|
|
|
ctxMenu.Append( EDIT_PAGE_NUMBER, _( "Edit Page Number" ) );
|
|
|
|
// The root item cannot be renamed
|
|
|
|
if( m_tree->GetRootItem() != aItem.GetID() )
|
|
|
|
{
|
|
|
|
ctxMenu.Append( RENAME, _( "Rename" ), _( "Change name of this sheet" ) );
|
|
|
|
}
|
|
|
|
|
2024-01-28 21:20:01 +00:00
|
|
|
ctxMenu.AppendSeparator();
|
|
|
|
}
|
2024-04-24 12:36:34 +00:00
|
|
|
ctxMenu.Append( EXPAND_ALL, ACTIONS::expandAll.GetMenuItem() );
|
|
|
|
ctxMenu.Append( COLLAPSE_ALL, ACTIONS::collapseAll.GetMenuItem() );
|
2022-09-26 20:57:32 +00:00
|
|
|
|
|
|
|
|
2024-04-24 12:36:34 +00:00
|
|
|
int selected = GetPopupMenuSelectionFromUser( ctxMenu );
|
|
|
|
|
|
|
|
switch( selected )
|
2024-01-28 21:20:01 +00:00
|
|
|
{
|
2024-04-24 12:36:34 +00:00
|
|
|
case EDIT_PAGE_NUMBER:
|
2022-09-26 20:57:32 +00:00
|
|
|
{
|
|
|
|
wxString msg;
|
2022-12-12 11:00:18 +00:00
|
|
|
wxString sheetPath = itemData->m_SheetPath.PathHumanReadable( false, true );
|
2022-09-26 20:57:32 +00:00
|
|
|
wxString pageNumber = itemData->m_SheetPath.GetPageNumber();
|
|
|
|
|
2022-12-12 10:42:51 +00:00
|
|
|
msg.Printf( _( "Enter page number for sheet path %s" ),
|
2022-12-12 11:00:18 +00:00
|
|
|
( sheetPath.Length() > 20 ) ? wxS( " \n" ) + sheetPath + wxT( ": " )
|
|
|
|
: sheetPath + wxT( ": " ) );
|
2022-09-26 20:57:32 +00:00
|
|
|
|
|
|
|
wxTextEntryDialog dlg( m_frame, msg, _( "Edit Sheet Page Number" ), pageNumber );
|
|
|
|
|
|
|
|
dlg.SetTextValidator( wxFILTER_ALPHANUMERIC ); // No white space.
|
|
|
|
|
|
|
|
if( dlg.ShowModal() == wxID_OK && dlg.GetValue() != itemData->m_SheetPath.GetPageNumber() )
|
|
|
|
{
|
2023-03-03 00:22:05 +00:00
|
|
|
SCH_SHEET_PATH parentPath = itemData->m_SheetPath;
|
|
|
|
parentPath.pop_back();
|
|
|
|
|
|
|
|
m_frame->SaveCopyInUndoList( parentPath.LastScreen(), itemData->m_SheetPath.Last(),
|
|
|
|
UNDO_REDO::CHANGED, false );
|
2022-09-26 20:57:32 +00:00
|
|
|
|
|
|
|
itemData->m_SheetPath.SetPageNumber( dlg.GetValue() );
|
|
|
|
|
|
|
|
if( itemData->m_SheetPath == m_frame->GetCurrentSheet() )
|
|
|
|
{
|
|
|
|
m_frame->GetScreen()->SetPageNumber( dlg.GetValue() );
|
|
|
|
m_frame->OnPageSettingsChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_frame->OnModify();
|
2024-01-25 17:20:43 +00:00
|
|
|
|
|
|
|
UpdateLabelsHierarchyTree();
|
2022-09-26 20:57:32 +00:00
|
|
|
}
|
2024-01-28 21:20:01 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
2024-04-24 12:36:34 +00:00
|
|
|
case EXPAND_ALL:
|
2024-01-28 21:20:01 +00:00
|
|
|
m_tree->ExpandAll();
|
|
|
|
break;
|
2024-04-24 12:36:34 +00:00
|
|
|
case COLLAPSE_ALL:
|
2024-01-28 21:20:01 +00:00
|
|
|
m_tree->CollapseAll();
|
|
|
|
break;
|
2024-04-24 12:36:34 +00:00
|
|
|
case RENAME:
|
|
|
|
m_tree->SetItemText( aItem, itemData->m_SheetPath.Last()->GetName() );
|
|
|
|
m_tree->EditLabel( aItem );
|
|
|
|
setIdenticalSheetsHighlighted( itemData->m_SheetPath );
|
|
|
|
break;
|
2024-01-28 21:20:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-04-24 12:36:34 +00:00
|
|
|
void HIERARCHY_PANE::onTreeEditFinished( wxTreeEvent& event )
|
|
|
|
{
|
|
|
|
TREE_ITEM_DATA* data = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( event.GetItem() ) );
|
|
|
|
wxString newName = event.GetLabel();
|
|
|
|
|
|
|
|
if( !newName.IsEmpty() )
|
|
|
|
{
|
|
|
|
// The editor holds only the page name as a text, while normally
|
|
|
|
// the tree items displaying it suffixed with the page number
|
|
|
|
if( data->m_SheetPath.Last()->GetName() != newName )
|
|
|
|
{
|
|
|
|
const SCH_SHEET* parentSheet =
|
|
|
|
data->m_SheetPath.GetSheet( data->m_SheetPath.size() - 2 );
|
|
|
|
|
|
|
|
if( parentSheet )
|
|
|
|
{
|
|
|
|
SCH_COMMIT commit( m_frame );
|
|
|
|
commit.Modify( &data->m_SheetPath.Last()->GetFields()[SHEETNAME],
|
|
|
|
parentSheet->GetScreen() );
|
|
|
|
|
|
|
|
data->m_SheetPath.Last()->SetName( newName );
|
|
|
|
|
|
|
|
renameIdenticalSheets( data->m_SheetPath, newName, &commit );
|
|
|
|
|
|
|
|
if( !commit.Empty() )
|
|
|
|
commit.Push( _( "Renaming sheet" ) );
|
|
|
|
|
|
|
|
if( data->m_SheetPath == m_frame->GetCurrentSheet() )
|
|
|
|
{
|
|
|
|
m_frame->OnPageSettingsChange();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tree->SetItemText( event.GetItem(), formatPageString( data->m_SheetPath.Last()->GetName(),
|
|
|
|
data->m_SheetPath.GetPageNumber() ) );
|
|
|
|
setIdenticalSheetsHighlighted( data->m_SheetPath, false );
|
|
|
|
// The event needs to be rejected otherwise the SetItemText call above
|
|
|
|
// will be ineffective (the treeview item will hold the editor's content)
|
|
|
|
event.Veto();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-28 21:20:01 +00:00
|
|
|
void HIERARCHY_PANE::onCharHook( wxKeyEvent& aKeyStroke )
|
|
|
|
{
|
|
|
|
int hotkey = aKeyStroke.GetKeyCode();
|
|
|
|
|
|
|
|
if( aKeyStroke.GetModifiers() & wxMOD_CONTROL )
|
|
|
|
hotkey += MD_CTRL;
|
|
|
|
|
|
|
|
if( aKeyStroke.GetModifiers() & wxMOD_ALT )
|
|
|
|
hotkey += MD_ALT;
|
|
|
|
|
|
|
|
if( aKeyStroke.GetModifiers() & wxMOD_SHIFT )
|
|
|
|
hotkey += MD_SHIFT;
|
|
|
|
|
|
|
|
if( hotkey == ACTIONS::expandAll.GetHotKey()
|
|
|
|
|| hotkey == ACTIONS::expandAll.GetHotKeyAlt() )
|
|
|
|
{
|
|
|
|
m_tree->ExpandAll();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if( hotkey == ACTIONS::collapseAll.GetHotKey()
|
|
|
|
|| hotkey == ACTIONS::collapseAll.GetHotKeyAlt() )
|
|
|
|
{
|
|
|
|
m_tree->CollapseAll();
|
|
|
|
return;
|
2022-09-26 20:57:32 +00:00
|
|
|
}
|
2024-04-24 12:36:34 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
aKeyStroke.Skip();
|
|
|
|
}
|
2022-09-26 20:57:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
wxString HIERARCHY_PANE::getRootString()
|
2020-11-29 00:10:17 +00:00
|
|
|
{
|
2022-06-02 21:56:17 +00:00
|
|
|
SCH_SHEET* rootSheet = &m_frame->Schematic().Root();
|
2020-11-29 00:10:17 +00:00
|
|
|
SCH_SHEET_PATH rootPath;
|
|
|
|
rootPath.push_back( rootSheet );
|
|
|
|
|
2023-11-27 18:44:49 +00:00
|
|
|
return formatPageString( rootSheet->GetShownName( false ), rootPath.GetPageNumber() );
|
2020-11-29 00:10:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-12-12 11:46:20 +00:00
|
|
|
wxString HIERARCHY_PANE::formatPageString( const wxString& aName, const wxString& aPage )
|
2020-11-29 00:10:17 +00:00
|
|
|
{
|
|
|
|
return aName + wxT( " " ) + wxString::Format( _( "(page %s)" ), aPage );
|
|
|
|
}
|
2024-04-24 12:36:34 +00:00
|
|
|
|
|
|
|
void HIERARCHY_PANE::setIdenticalSheetsHighlighted( const SCH_SHEET_PATH& path, bool highLighted )
|
|
|
|
{
|
|
|
|
std::function<void( const wxTreeItemId& )> recursiveDescent = [&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
|
|
|
|
|
|
|
|
TREE_ITEM_DATA* itemData = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
|
|
|
|
|
|
|
|
if( itemData->m_SheetPath.Cmp( path ) != 0 && itemData->m_SheetPath.Last() == path.Last() )
|
|
|
|
{
|
|
|
|
wxFont font = m_tree->GetItemFont( id );
|
|
|
|
font.SetUnderlined( highLighted );
|
|
|
|
m_tree->SetItemFont( id, font );
|
|
|
|
}
|
|
|
|
|
|
|
|
wxTreeItemIdValue cookie;
|
|
|
|
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
|
|
|
|
|
|
|
while( child.IsOk() )
|
|
|
|
{
|
|
|
|
recursiveDescent( child );
|
|
|
|
child = m_tree->GetNextChild( id, cookie );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
recursiveDescent( m_tree->GetRootItem() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void HIERARCHY_PANE::renameIdenticalSheets( const SCH_SHEET_PATH& renamedSheet,
|
|
|
|
const wxString newName, SCH_COMMIT* commit )
|
|
|
|
{
|
|
|
|
std::function<void( const wxTreeItemId& )> recursiveDescent = [&]( const wxTreeItemId& id )
|
|
|
|
{
|
|
|
|
wxCHECK_RET( id.IsOk(), wxT( "Invalid tree item" ) );
|
|
|
|
|
|
|
|
TREE_ITEM_DATA* data = static_cast<TREE_ITEM_DATA*>( m_tree->GetItemData( id ) );
|
|
|
|
|
|
|
|
const SCH_SHEET* parentSheet = data->m_SheetPath.GetSheet( data->m_SheetPath.size() - 2 );
|
|
|
|
|
|
|
|
if( parentSheet && data->m_SheetPath.Cmp( renamedSheet ) != 0
|
|
|
|
&& data->m_SheetPath.Last() == renamedSheet.Last() )
|
|
|
|
{
|
|
|
|
commit->Modify( &data->m_SheetPath.Last()->GetFields()[SHEETNAME],
|
|
|
|
parentSheet->GetScreen() );
|
|
|
|
|
|
|
|
data->m_SheetPath.Last()->SetName( newName );
|
|
|
|
|
|
|
|
if( data->m_SheetPath == m_frame->GetCurrentSheet() )
|
|
|
|
{
|
|
|
|
m_frame->OnPageSettingsChange();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_tree->SetItemText( id, formatPageString( data->m_SheetPath.Last()->GetName(),
|
|
|
|
data->m_SheetPath.GetPageNumber() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
wxTreeItemIdValue cookie;
|
|
|
|
wxTreeItemId child = m_tree->GetFirstChild( id, cookie );
|
|
|
|
|
|
|
|
while( child.IsOk() )
|
|
|
|
{
|
|
|
|
recursiveDescent( child );
|
|
|
|
child = m_tree->GetNextChild( id, cookie );
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
recursiveDescent( m_tree->GetRootItem() );
|
|
|
|
}
|