280 lines
8.8 KiB
C++
280 lines
8.8 KiB
C++
/*
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
*
|
|
* Copyright (C) 2017 CERN
|
|
* Copyright (C) 2020 KiCad Developers, see AUTHORS.txt for contributors.
|
|
*
|
|
* @author Maciej Suminski <maciej.suminski@cern.ch>
|
|
*
|
|
* 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 3
|
|
* 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:
|
|
* https://www.gnu.org/licenses/gpl-3.0.html
|
|
* or you may search the http://www.gnu.org website for the version 3 license,
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include "dialog_update_fields.h"
|
|
|
|
#include <sch_edit_frame.h>
|
|
#include <sch_component.h>
|
|
#include <schematic.h>
|
|
#include <class_libentry.h>
|
|
#include <algorithm>
|
|
|
|
|
|
int InvokeDialogUpdateFields( SCH_EDIT_FRAME* aCaller, SCH_COMPONENT* aSpecificComponent,
|
|
bool aCreateUndoEntry )
|
|
{
|
|
DIALOG_UPDATE_FIELDS dlg( aCaller, aSpecificComponent, aCreateUndoEntry );
|
|
return dlg.ShowQuasiModal();
|
|
}
|
|
|
|
|
|
DIALOG_UPDATE_FIELDS::DIALOG_UPDATE_FIELDS( SCH_EDIT_FRAME* aParent,
|
|
SCH_COMPONENT* aSpecificComponent,
|
|
bool aCreateUndoEntry ) :
|
|
DIALOG_UPDATE_FIELDS_BASE( aParent ),
|
|
m_frame( aParent ),
|
|
m_createUndo( aCreateUndoEntry )
|
|
{
|
|
if( aSpecificComponent )
|
|
{
|
|
m_components.emplace_back( aParent->GetScreen(), aSpecificComponent );
|
|
}
|
|
else
|
|
{
|
|
for( SCH_SHEET_PATH& path : aParent->Schematic().GetSheets() )
|
|
{
|
|
SCH_SCREEN* screen = path.LastScreen();
|
|
|
|
for( SCH_ITEM* item : screen->Items().OfType( SCH_COMPONENT_T ) )
|
|
m_components.emplace_back( screen, static_cast<SCH_COMPONENT*>( item ) );
|
|
}
|
|
}
|
|
|
|
m_sdbSizerOK->SetDefault();
|
|
}
|
|
|
|
|
|
bool DIALOG_UPDATE_FIELDS::TransferDataFromWindow()
|
|
{
|
|
if( !wxDialog::TransferDataFromWindow() )
|
|
return false;
|
|
|
|
if( m_components.empty() )
|
|
return true; // nothing to process
|
|
|
|
// Create the set of fields to be updated
|
|
m_updateFields.clear();
|
|
|
|
for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
|
|
{
|
|
if( m_fieldsBox->IsChecked( i ) )
|
|
m_updateFields.insert( m_fieldsBox->GetString( i ) );
|
|
}
|
|
|
|
|
|
// Undo buffer entry
|
|
if( m_createUndo )
|
|
{
|
|
PICKED_ITEMS_LIST itemsList;
|
|
|
|
for( std::pair<SCH_SCREEN*, SCH_COMPONENT*>& component : m_components )
|
|
itemsList.PushItem( ITEM_PICKER( component.first, component.second, UR_CHANGED ) );
|
|
|
|
m_frame->SaveCopyInUndoList( itemsList, UR_CHANGED, true );
|
|
}
|
|
|
|
|
|
// Do it!
|
|
for( std::pair<SCH_SCREEN*, SCH_COMPONENT*>& component : m_components )
|
|
updateFields( component.second );
|
|
|
|
m_frame->SyncView();
|
|
m_frame->GetCanvas()->Refresh();
|
|
m_frame->OnModify();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool DIALOG_UPDATE_FIELDS::TransferDataToWindow()
|
|
{
|
|
if( !wxDialog::TransferDataToWindow() || !m_components.size() )
|
|
return false;
|
|
|
|
// Collect all user field names from library parts of components that are going to be updated
|
|
{
|
|
for( std::pair<SCH_SCREEN*, SCH_COMPONENT*>& component : m_components )
|
|
{
|
|
const std::unique_ptr< LIB_PART >& part = component.second->GetPartRef();
|
|
|
|
if( !part )
|
|
continue;
|
|
|
|
const auto& drawItems = part->GetDrawItems();
|
|
|
|
for( auto it = drawItems.begin( LIB_FIELD_T ); it != drawItems.end( LIB_FIELD_T ); ++it )
|
|
{
|
|
const LIB_FIELD* field = static_cast<const LIB_FIELD*>( &( *it ) );
|
|
|
|
if( field->GetId() >= MANDATORY_FIELDS )
|
|
m_updateFields.insert( field->GetName() );
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the listbox widget
|
|
m_fieldsBox->Clear();
|
|
|
|
for( int i = 0; i < MANDATORY_FIELDS; ++i )
|
|
{
|
|
m_fieldsBox->Append( m_components.front().second->GetField( i )->GetName() );
|
|
|
|
if( i != REFERENCE && i != VALUE )
|
|
m_fieldsBox->Check( i, true );
|
|
}
|
|
|
|
for( const wxString& fieldName : m_updateFields )
|
|
{
|
|
int idx = m_fieldsBox->Append( fieldName );
|
|
m_fieldsBox->Check( idx, true );
|
|
}
|
|
|
|
// Now all widgets have the size fixed, call FinishDialogSettings
|
|
FinishDialogSettings();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void DIALOG_UPDATE_FIELDS::updateFields( SCH_COMPONENT* aComponent )
|
|
{
|
|
SCH_FIELDS newFields;
|
|
|
|
std::unique_ptr< LIB_PART >& libPart = aComponent->GetPartRef();
|
|
|
|
if( !libPart ) // the symbol is not found in lib: cannot update fields
|
|
return;
|
|
|
|
LIB_PART* alias = m_frame->GetLibPart( aComponent->GetLibId() );
|
|
|
|
for( const SCH_FIELD& existingField : aComponent->GetFields() )
|
|
{
|
|
if( existingField.GetId() >= 0 && existingField.GetId() < MANDATORY_FIELDS )
|
|
{
|
|
newFields.push_back( existingField );
|
|
continue;
|
|
}
|
|
|
|
// If requested, transfer only fields that occur also in the original library part
|
|
if( m_removeExtraBox->IsChecked() && !libPart->FindField( existingField.GetName() ) )
|
|
continue;
|
|
|
|
newFields.push_back( existingField );
|
|
}
|
|
|
|
// Update the requested fields
|
|
for( const wxString& fieldName : m_updateFields )
|
|
{
|
|
LIB_FIELD* libField = libPart->FindField( fieldName );
|
|
|
|
if( !libField )
|
|
continue;
|
|
|
|
auto it = std::find_if( newFields.begin(), newFields.end(),
|
|
[&] ( const SCH_FIELD& f )
|
|
{
|
|
return f.GetName() == fieldName;
|
|
} );
|
|
|
|
if( it != newFields.end() )
|
|
{
|
|
SCH_FIELD* newField = &*it;
|
|
wxString fieldValue = libField->GetText();
|
|
|
|
if( alias )
|
|
{
|
|
if( fieldName == TEMPLATE_FIELDNAME::GetDefaultFieldName( VALUE ) )
|
|
fieldValue = alias->GetName();
|
|
else if( fieldName == TEMPLATE_FIELDNAME::GetDefaultFieldName( DATASHEET ) )
|
|
fieldValue = alias->GetDatasheetField().GetText();
|
|
}
|
|
|
|
if( fieldValue.IsEmpty() )
|
|
{
|
|
// If the library field is empty an update would clear an existing entry.
|
|
// Check if this is the desired behavior.
|
|
if( m_resetEmpty->IsChecked() )
|
|
newField->SetText( wxEmptyString );
|
|
}
|
|
else
|
|
{
|
|
newField->SetText( fieldValue );
|
|
}
|
|
|
|
if( m_resetVisibility->IsChecked() )
|
|
{
|
|
newField->SetVisible( libField->IsVisible() );
|
|
}
|
|
|
|
if( m_resetPosition->IsChecked() )
|
|
{
|
|
newField->SetTextAngle( libField->GetTextAngle() );
|
|
|
|
// Schematic fields are schematic-relative; symbol editor fields are component-relative
|
|
if( m_createUndo )
|
|
newField->SetTextPos( libField->GetTextPos() + aComponent->GetPosition() );
|
|
else
|
|
newField->SetTextPos( libField->GetTextPos() );
|
|
}
|
|
|
|
if( m_resetSizeAndStyle->IsChecked() )
|
|
{
|
|
newField->SetHorizJustify( libField->GetHorizJustify() );
|
|
newField->SetVertJustify( libField->GetVertJustify() );
|
|
newField->SetTextSize( libField->GetTextSize() );
|
|
newField->SetItalic( libField->IsItalic() );
|
|
newField->SetBold( libField->IsBold() );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Missing field, it has to be added to the component
|
|
SCH_FIELD newField( wxPoint( 0, 0 ), newFields.size(), aComponent, fieldName );
|
|
|
|
newField.ImportValues( *libField );
|
|
newField.SetText( libField->GetText() );
|
|
|
|
// Schematic fields are schematic-relative; symbol editor fields are component-relative
|
|
if( m_createUndo )
|
|
newField.SetTextPos( libField->GetTextPos() + aComponent->GetPosition() );
|
|
else
|
|
newField.SetTextPos( libField->GetTextPos() );
|
|
|
|
newFields.push_back( newField );
|
|
}
|
|
}
|
|
|
|
// Apply changes & clean-up
|
|
aComponent->SetFields( newFields );
|
|
}
|
|
|
|
|
|
void DIALOG_UPDATE_FIELDS::checkAll( bool aCheck )
|
|
{
|
|
for( unsigned i = 0; i < m_fieldsBox->GetCount(); ++i )
|
|
m_fieldsBox->Check( i, aCheck );
|
|
}
|