/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2023 Ethan Chien * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. * * 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 */ #include "panel_sync_sheet_pins.h" #include "sch_sheet_pin.h" #include "sheet_synchronization_model.h" #include "sheet_synchronization_item.h" #include "sync_sheet_pin_preference.h" #include "sheet_synchronization_agent.h" #include #include #include #include #include #include #include #include #include PANEL_SYNC_SHEET_PINS::PANEL_SYNC_SHEET_PINS( wxWindow* aParent, SCH_SHEET* aSheet, wxNotebook* aNoteBook, int aIndex, SHEET_SYNCHRONIZATION_AGENT& aAgent, const SCH_SHEET_PATH& aPath ) : PANEL_SYNC_SHEET_PINS_BASE( aParent ), m_sheet( aSheet ), m_noteBook( aNoteBook ), m_index( aIndex ), m_sheetFileName( aSheet->GetFileName() ), m_agent( aAgent ), m_path( std::move( aPath ) ) { m_btnUsePinAsTemplate->SetBitmap( KiBitmapBundle( BITMAPS::add_hierar_pin ) ); m_btnUseLabelAsTemplate->SetBitmap( KiBitmapBundle( BITMAPS::add_hierarchical_label ) ); m_btnUndo->SetBitmap( KiBitmapBundle( BITMAPS::left ) ); m_labelSheetName->SetLabel( aSheet->GetFileName() ); m_labelSymName->SetLabel( aSheet->GetShownName( true ) ); for( wxDataViewCtrl* view : { m_viewAssociated, m_viewSheetLabels, m_viewSheetPins } ) { for( int col : { SHEET_SYNCHRONIZATION_MODEL::NAME, SHEET_SYNCHRONIZATION_MODEL::SHAPE } ) { switch( col ) { case SHEET_SYNCHRONIZATION_MODEL::NAME: view->AppendIconTextColumn( SHEET_SYNCHRONIZATION_MODEL::GetColName( col ), col ); break; case SHEET_SYNCHRONIZATION_MODEL::SHAPE: view->AppendTextColumn( SHEET_SYNCHRONIZATION_MODEL::GetColName( col ), col ); break; } } } std::map view_idx = std::map{ { SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL, m_viewSheetLabels }, { SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN, m_viewSheetPins }, { SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED, m_viewAssociated }, }; for( auto& [idx, view] : view_idx ) { auto model = wxObjectDataPtr( new SHEET_SYNCHRONIZATION_MODEL( m_agent, m_sheet, m_path ) ); view->AssociateModel( model.get() ); m_models.try_emplace( idx, std::move( model ) ); } for( auto& [idx, view] : view_idx ) PostProcessModelSelection( idx, {} ); } void PANEL_SYNC_SHEET_PINS::UpdateForms() { SHEET_SYNCHRONIZATION_ITEM_LIST labels_list, pins_list, associated_list; auto labels_ori = m_sheet->GetScreen()->Items().OfType( SCH_HIER_LABEL_T ); std::vector pins_ori = m_sheet->GetPins(); auto check_matched = [&]( SCH_HIERLABEL* label ) { for( size_t i = 0; i < pins_ori.size(); i++ ) { SCH_SHEET_PIN* cur_pin = pins_ori[i]; if( label->GetText() == cur_pin->GetText() && label->GetShape() == cur_pin->GetShape() ) { associated_list.push_back( std::make_shared( label, cur_pin ) ); pins_ori.erase( pins_ori.begin() + i ); return; } } labels_list.push_back( std::make_shared( label, m_sheet ) ); }; for( const auto& item : labels_ori ) check_matched( static_cast( item ) ); for( const auto& pin : pins_ori ) pins_list.push_back( std::make_shared( static_cast( pin ), m_sheet ) ); m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->UpdateItems( std::move( labels_list ) ); m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->UpdateItems( std::move( pins_list ) ); m_models[SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED]->UpdateItems( std::move( associated_list ) ); UpdatePageImage(); } SHEET_SYNCHRONIZATION_MODEL_PTR PANEL_SYNC_SHEET_PINS::GetModel( int aKind ) const { return m_models.at( aKind ); } const wxString& PANEL_SYNC_SHEET_PINS::GetSheetFileName() const { return m_sheetFileName; } PANEL_SYNC_SHEET_PINS::~PANEL_SYNC_SHEET_PINS() { } bool PANEL_SYNC_SHEET_PINS::HasUndefinedSheetPing() const { return !m_models.at( SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL )->GetCount() && !m_models.at( SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN )->GetCount(); } void PANEL_SYNC_SHEET_PINS::OnBtnAddLabelsClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) if( auto idx = m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->GetSelectedIndex(); idx.has_value() ) { if( SHEET_SYNCHRONIZATION_ITE_PTR item = m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->GetSynchronizationItem( *idx ) ) { m_agent.PlaceHieraLable( m_sheet, m_path, static_cast( item->GetItem() ) ); } } } void PANEL_SYNC_SHEET_PINS::OnBtnAddSheetPinsClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) if( auto idx = m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->GetSelectedIndex(); idx.has_value() ) { if( SHEET_SYNCHRONIZATION_ITE_PTR item = m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->GetSynchronizationItem( *idx ) ) { m_agent.PlaceSheetPin( m_sheet, m_path, static_cast( item->GetItem() ) ); } } } void PANEL_SYNC_SHEET_PINS::GenericSync( SYNC_DIRECTION direction ) { wxDataViewItem labelIdx = m_viewSheetLabels->GetSelection(); wxDataViewItem pinIdx = m_viewSheetPins->GetSelection(); for( auto& idx : { labelIdx, pinIdx } ) { if( !idx.IsOk() ) return; } SHEET_SYNCHRONIZATION_ITE_PTR labelItem = m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->TakeItem( labelIdx ); SHEET_SYNCHRONIZATION_ITE_PTR pinItem = m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->TakeItem( pinIdx ); for( const auto& item : { labelItem, pinItem } ) { if( !item ) return; } auto label_ptr = std::static_pointer_cast( labelItem )->GetLabel(); auto pin_ptr = std::static_pointer_cast( pinItem )->GetPin(); switch( direction ) { case SYNC_DIRECTION::USE_LABEL_AS_TEMPLATE: m_agent.ModifyItem( *pinItem, [&]() { pin_ptr->SetText( label_ptr->GetText() ); pin_ptr->SetShape( label_ptr->GetShape() ); }, m_path ); break; case SYNC_DIRECTION::USE_PIN_AS_TEMPLATE: m_agent.ModifyItem( *labelItem, [&]() { label_ptr->SetText( pin_ptr->GetText() ); label_ptr->SetShape( pin_ptr->GetShape() ); }, m_path ); break; } m_models[SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED]->AppendItem( std::make_shared( label_ptr, pin_ptr ) ); UpdatePageImage(); for( auto idx : { SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL, SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN } ) { PostProcessModelSelection( idx, {} ); } m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->DoNotify(); } void PANEL_SYNC_SHEET_PINS::UpdatePageImage() const { m_noteBook->SetPageImage( m_index, HasUndefinedSheetPing() ? SYNC_SHEET_PIN_PREFERENCE::HAS_UNMATCHED : SYNC_SHEET_PIN_PREFERENCE::ALL_MATCHED ); } void PANEL_SYNC_SHEET_PINS::OnBtnUsePinAsTemplateClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) return GenericSync( SYNC_DIRECTION::USE_PIN_AS_TEMPLATE ); } void PANEL_SYNC_SHEET_PINS::OnBtnUseLabelAsTemplateClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) return GenericSync( SYNC_DIRECTION::USE_LABEL_AS_TEMPLATE ); } void PANEL_SYNC_SHEET_PINS::OnBtnRmPinsClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) wxDataViewItemArray array; m_viewSheetPins->GetSelections( array ); m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->RemoveItems( array ); PostProcessModelSelection( SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN, {} ); UpdatePageImage(); } void PANEL_SYNC_SHEET_PINS::OnBtnRmLabelsClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) wxDataViewItemArray array; m_viewSheetLabels->GetSelections( array ); m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->RemoveItems( array ); PostProcessModelSelection( SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL, {} ); UpdatePageImage(); } void PANEL_SYNC_SHEET_PINS::OnBtnUndoClicked( wxCommandEvent& aEvent ) { WXUNUSED( aEvent ) wxDataViewItemArray indexes; m_viewAssociated->GetSelections( indexes ); auto items = m_models[SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED]->TakeItems( indexes ); if( !items.size() ) return; for( auto& item : items ) { auto associated = std::static_pointer_cast( item ); m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->AppendItem( std::make_shared( associated->GetLabel(), m_sheet ) ); m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->AppendItem( std::make_shared( associated->GetPin(), m_sheet ) ); } PostProcessModelSelection( SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED, {} ); UpdatePageImage(); } void PANEL_SYNC_SHEET_PINS::PostProcessModelSelection( int aIdex, wxDataViewItem const& aItem ) { if( aItem.IsOk() ) m_models[aIdex]->OnRowSelected( m_models[aIdex]->GetRow( aItem ) ); else m_models[aIdex]->OnRowSelected( {} ); switch( aIdex ) { case SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN: { for( auto btn : { m_btnAddLabels, m_btnRmPins } ) btn->Enable( m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->HasSelectedIndex() ); break; } case SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL: { for( auto btn : { m_btnAddSheetPins, m_btnRmLabels } ) btn->Enable( m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->HasSelectedIndex() ); break; } case SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED: { m_btnUndo->Enable( m_models[SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED]->HasSelectedIndex() ); break; } default: break; } if( aIdex != SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED ) { for( auto btn : { m_btnUsePinAsTemplate, m_btnUseLabelAsTemplate } ) { btn->Enable( m_models[SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN]->HasSelectedIndex() && m_models[SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL]->HasSelectedIndex() ); } } } void PANEL_SYNC_SHEET_PINS::OnViewSheetLabelCellClicked( wxDataViewEvent& aEvent ) { PostProcessModelSelection( SHEET_SYNCHRONIZATION_MODEL::HIRE_LABEL, aEvent.GetItem() ); } void PANEL_SYNC_SHEET_PINS::OnViewSheetPinCellClicked( wxDataViewEvent& aEvent ) { PostProcessModelSelection( SHEET_SYNCHRONIZATION_MODEL::SHEET_PIN, aEvent.GetItem() ); } void PANEL_SYNC_SHEET_PINS::OnViewMatchedCellClicked( wxDataViewEvent& aEvent ) { PostProcessModelSelection( SHEET_SYNCHRONIZATION_MODEL::ASSOCIATED, aEvent.GetItem() ); }