/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2015-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 #include #include #include #include #include #include #include #include #include #include #include #include class DIALOG_RESCUE_EACH: public DIALOG_RESCUE_EACH_BASE { public: /** * This dialog asks the user which rescuable, cached parts he wants to rescue. * * Any rejects will be pruned from aCandidates. * * @param aParent - the SCH_EDIT_FRAME calling this * @param aRescuer - the active RESCUER instance * @param aCurrentSheet the current sheet in the schematic editor frame * @param aGalBackEndType the current GAL type used to render symbols * @param aAskShowAgain - if true, a "Never Show Again" button will be included */ DIALOG_RESCUE_EACH( wxWindow* aParent, RESCUER& aRescuer, SCH_SHEET_PATH* aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType, bool aAskShowAgain ); ~DIALOG_RESCUE_EACH(); private: SYMBOL_PREVIEW_WIDGET* m_previewNewWidget; SYMBOL_PREVIEW_WIDGET* m_previewOldWidget; RESCUER* m_Rescuer; SCH_SHEET_PATH* m_currentSheet; bool m_AskShowAgain; bool TransferDataToWindow() override; bool TransferDataFromWindow() override; void PopulateConflictList(); void PopulateInstanceList(); void OnConflictSelect( wxDataViewEvent& aEvent ) override; void OnNeverShowClick( wxCommandEvent& aEvent ) override; void OnCancelClick( wxCommandEvent& aEvent ) override; // Display the 2 items (old in cache and new in library) corresponding to the // selected conflict in m_ListOfConflicts void displayItemsInConflict(); }; DIALOG_RESCUE_EACH::DIALOG_RESCUE_EACH( wxWindow* aParent, RESCUER& aRescuer, SCH_SHEET_PATH* aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType, bool aAskShowAgain ) : DIALOG_RESCUE_EACH_BASE( aParent ), m_Rescuer( &aRescuer ), m_currentSheet( aCurrentSheet ), m_AskShowAgain( aAskShowAgain ) { wxASSERT( aCurrentSheet ); m_previewOldWidget = new SYMBOL_PREVIEW_WIDGET( m_previewOldPanel, &Kiway(), false, aGalBackEndType ); m_SizerOldPanel->Add( m_previewOldWidget, 1, wxEXPAND | wxALL, 5 ); m_previewNewWidget = new SYMBOL_PREVIEW_WIDGET( m_previewNewPanel, &Kiway(), false, aGalBackEndType ); m_SizerNewPanel->Add( m_previewNewWidget, 1, wxEXPAND | wxALL, 5 ); // Set the info message, customized to include the proper suffix. wxString info = _( "This schematic was made using older symbol libraries which may break the " "schematic. Some symbols may need to be linked to a different symbol name. " "Some symbols may need to be \"rescued\" (copied and renamed) into a new library.\n\n" "The following changes are recommended to update the project." ); m_htmlPrompt->AppendToPage( info ); // wxDataViewListCtrl seems to do a poor job of laying itself out so help it along here. wxString header = _( "Accept" ); wxFont font = m_ListOfConflicts->GetFont(); font.MakeBold(); wxClientDC dc( this ); dc.SetFont( font ); int width = dc.GetTextExtent( header ).GetWidth() * 1.25; m_ListOfConflicts->AppendToggleColumn( header, wxDATAVIEW_CELL_ACTIVATABLE, width, wxALIGN_CENTER ); header = _( "Symbol Name" ); width = dc.GetTextExtent( header ).GetWidth() * 2; m_ListOfConflicts->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width ); header = _( "Action Taken" ); width = dc.GetTextExtent( header ).GetWidth() * 10; m_ListOfConflicts->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width ); header = _( "Reference" ); width = dc.GetTextExtent( header ).GetWidth() * 2; m_ListOfInstances->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width ); header = _( "Value" ); width = dc.GetTextExtent( header ).GetWidth() * 10; m_ListOfInstances->AppendTextColumn( header, wxDATAVIEW_CELL_INERT, width ); m_previewOldWidget->SetLayoutDirection( wxLayout_LeftToRight ); m_previewNewWidget->SetLayoutDirection( wxLayout_LeftToRight ); // Make sure the HTML window is large enough. Some fun size juggling and // fudge factors here but it does seem to work pretty reliably. wxSize info_size = m_htmlPrompt->GetTextExtent( info ); wxSize prompt_size = m_htmlPrompt->GetSize(); wxSize font_size = m_htmlPrompt->GetTextExtent( "X" ); int approx_info_height = ( 2 * info_size.x / prompt_size.x ) * font_size.y; m_htmlPrompt->SetSizeHints( 2 * prompt_size.x / 3, approx_info_height ); SetupStandardButtons(); m_stdButtonsOK->SetLabel( _( "Rescue Symbols" ) ); m_stdButtonsCancel->SetLabel( _( "Skip Symbol Rescue" ) ); m_stdButtons->Layout(); GetSizer()->SetSizeHints( this ); Layout(); Center(); } DIALOG_RESCUE_EACH::~DIALOG_RESCUE_EACH() { } bool DIALOG_RESCUE_EACH::TransferDataToWindow() { if( !wxDialog::TransferDataToWindow() ) return false; PopulateConflictList(); PopulateInstanceList(); if( !m_AskShowAgain ) m_btnNeverShowAgain->Hide(); return true; } void DIALOG_RESCUE_EACH::PopulateConflictList() { wxVector data; for( RESCUE_CANDIDATE& each_candidate : m_Rescuer->m_all_candidates ) { data.clear(); data.push_back( wxVariant( true ) ); data.push_back( each_candidate.GetRequestedName() ); data.push_back( each_candidate.GetActionDescription() ); m_ListOfConflicts->AppendItem( data ); } if( !m_Rescuer->m_all_candidates.empty() ) { // Select the first choice m_ListOfConflicts->SelectRow( 0 ); // Ensure this choice is displayed: displayItemsInConflict(); } } void DIALOG_RESCUE_EACH::PopulateInstanceList() { m_ListOfInstances->DeleteAllItems(); int row = m_ListOfConflicts->GetSelectedRow(); if( row == wxNOT_FOUND ) row = 0; RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row]; wxVector data; int count = 0; for( SCH_SYMBOL* eachSymbol : *m_Rescuer->GetSymbols() ) { if( eachSymbol->GetLibId().Format() != UTF8( selected_part.GetRequestedName() ) ) continue; SCH_FIELD* valueField = eachSymbol->GetField( VALUE_FIELD ); data.clear(); data.push_back( eachSymbol->GetRef( m_currentSheet ) ); data.push_back( valueField ? valueField->GetText() : wxString( wxT( "" ) ) ); m_ListOfInstances->AppendItem( data ); count++; } wxString msg = wxString::Format( _( "Instances of this symbol (%d items):" ), count ); m_titleInstances->SetLabelText( msg ); } void DIALOG_RESCUE_EACH::displayItemsInConflict() { int row = m_ListOfConflicts->GetSelectedRow(); if( row < 0 ) { m_previewOldWidget->DisplayPart( nullptr, 0 ); m_previewNewWidget->DisplayPart( nullptr, 0 ); } else { RESCUE_CANDIDATE& selected_part = m_Rescuer->m_all_candidates[row]; m_previewOldWidget->DisplayPart( selected_part.GetCacheCandidate(), selected_part.GetUnit(), selected_part.GetConvert() ); m_previewNewWidget->DisplayPart( selected_part.GetLibCandidate(), selected_part.GetUnit(), selected_part.GetConvert() ); } } void DIALOG_RESCUE_EACH::OnConflictSelect( wxDataViewEvent& aEvent ) { // wxformbuilder connects this event to the _dialog_, not the data view. // Make sure the correct item triggered it, otherwise we trigger recursively // and get a stack overflow. if( aEvent.GetEventObject() != m_ListOfConflicts ) return; PopulateInstanceList(); displayItemsInConflict(); } bool DIALOG_RESCUE_EACH::TransferDataFromWindow() { if( !wxDialog::TransferDataFromWindow() ) return false; for( size_t index = 0; index < m_Rescuer->GetCandidateCount(); ++index ) { wxVariant val; m_ListOfConflicts->GetValue( val, index, 0 ); bool rescue_part = val.GetBool(); if( rescue_part ) m_Rescuer->m_chosen_candidates.push_back( &m_Rescuer->m_all_candidates[index] ); } return true; } void DIALOG_RESCUE_EACH::OnNeverShowClick( wxCommandEvent& aEvent ) { wxMessageDialog dlg( GetParent(), _( "Stop showing this tool?\n" "No changes will be made.\n\n" "This setting can be changed from the \"Preferences\" dialog,\n" "and the tool can be activated manually from the \"Tools\" menu." ), _( "Rescue Symbols" ), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION ); int resp = dlg.ShowModal (); if( resp == wxID_YES ) { auto cfg = dynamic_cast( Kiface().KifaceSettings() ); if( cfg ) cfg->m_RescueNeverShow = true; m_Rescuer->m_chosen_candidates.clear(); Close(); } } void DIALOG_RESCUE_EACH::OnCancelClick( wxCommandEvent& aEvent ) { m_Rescuer->m_chosen_candidates.clear(); DIALOG_RESCUE_EACH_BASE::OnCancelClick( aEvent ); } int InvokeDialogRescueEach( wxWindow* aParent, RESCUER& aRescuer, SCH_SHEET_PATH* aCurrentSheet, EDA_DRAW_PANEL_GAL::GAL_TYPE aGalBackEndType, bool aAskShowAgain ) { DIALOG_RESCUE_EACH dlg( aParent, aRescuer, aCurrentSheet, aGalBackEndType, aAskShowAgain ); return dlg.ShowQuasiModal(); }