2017-04-02 12:09:01 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2017 Oliver Walters
|
2023-02-09 20:13:05 +00:00
|
|
|
* Copyright (C) 2017-2023 KiCad Developers, see AUTHORS.txt for contributors.
|
2017-04-02 12:09:01 +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
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2018-03-07 12:48:08 +00:00
|
|
|
#include <base_units.h>
|
2018-04-17 10:34:48 +00:00
|
|
|
#include <bitmaps.h>
|
2021-06-15 13:24:55 +00:00
|
|
|
#include <symbol_library.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <confirm.h>
|
|
|
|
#include <eda_doc.h>
|
2022-09-12 22:38:36 +00:00
|
|
|
#include <wildcards_and_files_ext.h>
|
2023-02-09 20:13:05 +00:00
|
|
|
#include <schematic_settings.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <general.h>
|
2018-04-17 10:34:48 +00:00
|
|
|
#include <grid_tricks.h>
|
2021-07-29 09:56:22 +00:00
|
|
|
#include <string_utils.h>
|
2021-09-14 22:45:14 +00:00
|
|
|
#include <kiface_base.h>
|
2018-04-17 10:34:48 +00:00
|
|
|
#include <sch_edit_frame.h>
|
|
|
|
#include <sch_reference_list.h>
|
2020-05-13 02:00:37 +00:00
|
|
|
#include <schematic.h>
|
2019-07-17 20:21:22 +00:00
|
|
|
#include <tools/sch_editor_control.h>
|
2021-12-16 04:56:21 +00:00
|
|
|
#include <kiplatform/ui.h>
|
2018-07-20 22:26:37 +00:00
|
|
|
#include <widgets/grid_text_button_helpers.h>
|
2022-04-17 19:02:05 +00:00
|
|
|
#include <widgets/bitmap_button.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <widgets/wx_grid.h>
|
2023-02-06 21:05:53 +00:00
|
|
|
#include <wx/debug.h>
|
2022-05-09 13:41:00 +00:00
|
|
|
#include <wx/ffile.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <wx/grid.h>
|
2021-05-01 07:50:29 +00:00
|
|
|
#include <wx/textdlg.h>
|
2022-05-09 13:41:00 +00:00
|
|
|
#include <wx/filedlg.h>
|
2023-02-09 20:13:05 +00:00
|
|
|
#include <dialogs/eda_view_switcher.h>
|
2021-07-03 20:43:30 +00:00
|
|
|
#include "dialog_symbol_fields_table.h"
|
2023-02-09 20:13:05 +00:00
|
|
|
#include "eda_list_dialog.h"
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
// The field name in the data model (translated)
|
2020-10-28 10:22:52 +00:00
|
|
|
#define DISPLAY_NAME_COLUMN 0
|
2023-02-23 19:10:50 +00:00
|
|
|
// The field name's label for exporting (CSV, etc.)
|
|
|
|
#define LABEL_COLUMN 1
|
|
|
|
#define SHOW_FIELD_COLUMN 2
|
|
|
|
#define GROUP_BY_COLUMN 3
|
|
|
|
// The internal field name (untranslated)
|
|
|
|
#define FIELD_NAME_COLUMN 4
|
2020-10-28 10:22:52 +00:00
|
|
|
|
|
|
|
#ifdef __WXMAC__
|
|
|
|
#define COLUMN_MARGIN 5
|
|
|
|
#else
|
|
|
|
#define COLUMN_MARGIN 15
|
|
|
|
#endif
|
|
|
|
|
2018-07-20 22:26:37 +00:00
|
|
|
enum
|
|
|
|
{
|
2022-03-26 11:05:10 +00:00
|
|
|
MYID_SELECT_FOOTPRINT = GRIDTRICKS_FIRST_CLIENT_ID,
|
2018-07-20 22:26:37 +00:00
|
|
|
MYID_SHOW_DATASHEET
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-03-14 04:51:59 +00:00
|
|
|
class FIELDS_EDITOR_GRID_TRICKS : public GRID_TRICKS
|
|
|
|
{
|
|
|
|
public:
|
2019-03-04 11:02:12 +00:00
|
|
|
FIELDS_EDITOR_GRID_TRICKS( DIALOG_SHIM* aParent, WX_GRID* aGrid,
|
2018-07-20 22:26:37 +00:00
|
|
|
wxDataViewListCtrl* aFieldsCtrl ) :
|
2018-03-14 04:51:59 +00:00
|
|
|
GRID_TRICKS( aGrid ),
|
2018-07-20 22:26:37 +00:00
|
|
|
m_dlg( aParent ),
|
2018-03-14 04:51:59 +00:00
|
|
|
m_fieldsCtrl( aFieldsCtrl )
|
|
|
|
{}
|
|
|
|
|
|
|
|
protected:
|
2023-02-05 20:47:27 +00:00
|
|
|
void showPopupMenu( wxMenu& menu, wxGridEvent& aEvent ) override
|
2018-07-20 22:26:37 +00:00
|
|
|
{
|
2020-11-12 21:31:41 +00:00
|
|
|
if( m_grid->GetGridCursorCol() == FOOTPRINT_FIELD )
|
2018-07-20 22:26:37 +00:00
|
|
|
{
|
2019-06-17 19:05:11 +00:00
|
|
|
menu.Append( MYID_SELECT_FOOTPRINT, _( "Select Footprint..." ),
|
|
|
|
_( "Browse for footprint" ) );
|
2018-07-20 22:26:37 +00:00
|
|
|
menu.AppendSeparator();
|
|
|
|
}
|
2020-11-12 21:31:41 +00:00
|
|
|
else if( m_grid->GetGridCursorCol() == DATASHEET_FIELD )
|
2018-07-20 22:26:37 +00:00
|
|
|
{
|
2019-06-17 19:05:11 +00:00
|
|
|
menu.Append( MYID_SHOW_DATASHEET, _( "Show Datasheet" ),
|
|
|
|
_( "Show datasheet in browser" ) );
|
2018-07-20 22:26:37 +00:00
|
|
|
menu.AppendSeparator();
|
|
|
|
}
|
|
|
|
|
2023-02-05 20:47:27 +00:00
|
|
|
GRID_TRICKS::showPopupMenu( menu, aEvent );
|
2018-07-20 22:26:37 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 04:51:59 +00:00
|
|
|
void doPopupSelection( wxCommandEvent& event ) override
|
|
|
|
{
|
2018-07-20 22:26:37 +00:00
|
|
|
if( event.GetId() == MYID_SELECT_FOOTPRINT )
|
|
|
|
{
|
|
|
|
// pick a footprint using the footprint picker.
|
2021-07-16 20:13:26 +00:00
|
|
|
wxString fpid = m_grid->GetCellValue( m_grid->GetGridCursorRow(),
|
|
|
|
FOOTPRINT_FIELD );
|
|
|
|
KIWAY_PLAYER* frame = m_dlg->Kiway().Player( FRAME_FOOTPRINT_VIEWER_MODAL, true,
|
|
|
|
m_dlg );
|
2018-07-20 22:26:37 +00:00
|
|
|
|
|
|
|
if( frame->ShowModal( &fpid, m_dlg ) )
|
2020-11-12 21:31:41 +00:00
|
|
|
m_grid->SetCellValue( m_grid->GetGridCursorRow(), FOOTPRINT_FIELD, fpid );
|
2018-07-20 22:26:37 +00:00
|
|
|
|
|
|
|
frame->Destroy();
|
|
|
|
}
|
|
|
|
else if (event.GetId() == MYID_SHOW_DATASHEET )
|
|
|
|
{
|
2021-07-16 20:13:26 +00:00
|
|
|
wxString datasheet_uri = m_grid->GetCellValue( m_grid->GetGridCursorRow(),
|
|
|
|
DATASHEET_FIELD );
|
2022-05-11 01:28:48 +00:00
|
|
|
GetAssociatedDocument( m_dlg, datasheet_uri, &m_dlg->Prj(), m_dlg->Prj().SchSearchS() );
|
2018-07-20 22:26:37 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GRID_TRICKS::doPopupSelection( event );
|
|
|
|
}
|
2018-03-14 04:51:59 +00:00
|
|
|
|
|
|
|
if( event.GetId() >= GRIDTRICKS_FIRST_SHOWHIDE && event.GetId() < GRIDTRICKS_LAST_ID )
|
|
|
|
{
|
2020-11-12 21:31:41 +00:00
|
|
|
if( !m_grid->IsColShown( REFERENCE_FIELD ) )
|
2019-02-03 20:53:21 +00:00
|
|
|
{
|
|
|
|
DisplayError( m_dlg, _( "The Reference column cannot be hidden." ) );
|
|
|
|
|
2020-11-12 21:31:41 +00:00
|
|
|
m_grid->ShowCol( REFERENCE_FIELD );
|
2019-02-03 20:53:21 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 04:51:59 +00:00
|
|
|
// Refresh Show checkboxes from grid columns
|
|
|
|
for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
|
2019-02-03 20:53:21 +00:00
|
|
|
m_fieldsCtrl->SetToggleValue( m_grid->IsColShown( i ), i, 1 );
|
2018-03-14 04:51:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-20 22:26:37 +00:00
|
|
|
DIALOG_SHIM* m_dlg;
|
2018-03-14 04:51:59 +00:00
|
|
|
wxDataViewListCtrl* m_fieldsCtrl;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
enum GROUP_TYPE
|
|
|
|
{
|
|
|
|
GROUP_SINGLETON,
|
|
|
|
GROUP_COLLAPSED,
|
2018-05-13 11:06:46 +00:00
|
|
|
GROUP_COLLAPSED_DURING_SORT,
|
2018-05-12 22:04:11 +00:00
|
|
|
GROUP_EXPANDED,
|
|
|
|
CHILD_ITEM
|
|
|
|
};
|
|
|
|
|
2019-06-17 19:05:11 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
BOM_PRESET DIALOG_SYMBOL_FIELDS_TABLE::bomPresetGroupedByValue(
|
|
|
|
_HKI( "Grouped By Value" ),
|
|
|
|
std::map<std::string, bool>( {
|
|
|
|
std::pair<std::string, bool>( "Reference", true ),
|
|
|
|
std::pair<std::string, bool>( "Value", true ),
|
|
|
|
std::pair<std::string, bool>( "Datasheet", true ),
|
|
|
|
std::pair<std::string, bool>( "Footprint", true ),
|
|
|
|
std::pair<std::string, bool>( "Quantity", true ),
|
|
|
|
} ),
|
|
|
|
std::map<std::string, bool>( {
|
|
|
|
std::pair<std::string, bool>( "Reference", false ),
|
|
|
|
std::pair<std::string, bool>( "Value", true ),
|
|
|
|
std::pair<std::string, bool>( "Datasheet", false ),
|
|
|
|
std::pair<std::string, bool>( "Footprint", false ),
|
|
|
|
std::pair<std::string, bool>( "Quantity", false ),
|
|
|
|
} ),
|
|
|
|
std::map<std::string, int>(), std::map<std::string, bool>(), std::vector<wxString>(),
|
|
|
|
_HKI( "" ), true );
|
|
|
|
|
|
|
|
|
|
|
|
BOM_PRESET DIALOG_SYMBOL_FIELDS_TABLE::bomPresetGroupedByValueFootprint(
|
|
|
|
_HKI( "Grouped By Value and Footprint" ),
|
|
|
|
std::map<std::string, bool>( {
|
|
|
|
std::pair<std::string, bool>( "Reference", true ),
|
|
|
|
std::pair<std::string, bool>( "Value", true ),
|
|
|
|
std::pair<std::string, bool>( "Datasheet", true ),
|
|
|
|
std::pair<std::string, bool>( "Footprint", true ),
|
|
|
|
std::pair<std::string, bool>( "Quantity", true ),
|
|
|
|
} ),
|
|
|
|
std::map<std::string, bool>( {
|
|
|
|
std::pair<std::string, bool>( "Reference", false ),
|
|
|
|
std::pair<std::string, bool>( "Value", true ),
|
|
|
|
std::pair<std::string, bool>( "Datasheet", false ),
|
|
|
|
std::pair<std::string, bool>( "Footprint", true ),
|
|
|
|
std::pair<std::string, bool>( "Quantity", false ),
|
|
|
|
} ),
|
|
|
|
std::map<std::string, int>(), std::map<std::string, bool>(), std::vector<wxString>(),
|
|
|
|
_HKI( "" ), true );
|
|
|
|
|
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
struct DATA_MODEL_ROW
|
|
|
|
{
|
2020-01-09 22:55:46 +00:00
|
|
|
DATA_MODEL_ROW( const SCH_REFERENCE& aFirstReference, GROUP_TYPE aType )
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
|
|
|
m_Refs.push_back( aFirstReference );
|
|
|
|
m_Flag = aType;
|
|
|
|
}
|
|
|
|
|
|
|
|
GROUP_TYPE m_Flag;
|
|
|
|
std::vector<SCH_REFERENCE> m_Refs;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
struct DATA_MODEL_COL
|
|
|
|
{
|
|
|
|
wxString m_fieldName;
|
|
|
|
wxString m_label;
|
|
|
|
bool m_userAdded;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
class FIELDS_EDITOR_GRID_DATA_MODEL : public wxGridTableBase
|
|
|
|
{
|
|
|
|
protected:
|
|
|
|
// The data model is fundamentally m_componentRefs X m_fieldNames.
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-05-22 11:50:57 +00:00
|
|
|
SCH_EDIT_FRAME* m_frame;
|
2020-11-15 16:08:31 +00:00
|
|
|
SCH_REFERENCE_LIST m_symbolsList;
|
2018-06-05 19:59:58 +00:00
|
|
|
bool m_edited;
|
2018-05-13 11:06:46 +00:00
|
|
|
int m_sortColumn;
|
|
|
|
bool m_sortAscending;
|
2023-02-23 19:10:50 +00:00
|
|
|
std::vector<DATA_MODEL_COL> m_cols;
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// However, the grid view can vary in two ways:
|
|
|
|
// 1) the componentRefs can be grouped into fewer rows
|
|
|
|
// 2) some columns can be hidden
|
|
|
|
//
|
|
|
|
// We handle (1) here (ie: a table row maps to a group, and the table is rebuilt
|
|
|
|
// when the groupings change), and we let the wxGrid handle (2) (ie: the number
|
|
|
|
// of columns is constant but are hidden/shown by the wxGrid control).
|
2017-05-02 17:51:02 +00:00
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
std::vector< DATA_MODEL_ROW > m_rows;
|
2017-12-05 12:51:09 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// Data store
|
|
|
|
// A map of compID : fieldSet, where fieldSet is a map of fieldName : fieldValue
|
2020-02-21 22:20:42 +00:00
|
|
|
std::map< KIID, std::map<wxString, wxString> > m_dataStore;
|
2017-05-03 06:24:45 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
public:
|
2020-11-15 16:08:31 +00:00
|
|
|
FIELDS_EDITOR_GRID_DATA_MODEL( SCH_EDIT_FRAME* aFrame, SCH_REFERENCE_LIST& aSymbolsList ) :
|
2018-05-22 11:50:57 +00:00
|
|
|
m_frame( aFrame ),
|
2020-11-15 16:08:31 +00:00
|
|
|
m_symbolsList( aSymbolsList ),
|
2018-06-05 19:59:58 +00:00
|
|
|
m_edited( false ),
|
2019-01-12 01:27:08 +00:00
|
|
|
m_sortColumn( 0 ),
|
2018-06-04 17:48:17 +00:00
|
|
|
m_sortAscending( false )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
m_symbolsList.SplitReferences();
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2018-03-09 01:44:20 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
void AddColumn( const wxString& aFieldName, const wxString& aLabel, bool aAddedByUser )
|
2017-05-03 06:24:45 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
m_cols.push_back((struct DATA_MODEL_COL) {
|
|
|
|
.m_fieldName = aFieldName,
|
|
|
|
.m_label = aLabel,
|
|
|
|
.m_userAdded = aAddedByUser });
|
2022-09-12 22:38:36 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2021-06-10 14:10:55 +00:00
|
|
|
SCH_SYMBOL* symbol = m_symbolsList[ i ].GetSymbol();
|
2022-03-23 15:46:49 +00:00
|
|
|
|
|
|
|
wxCHECK( symbol && ( symbol->GetInstanceReferences().size() != 0 ), /* void */ );
|
|
|
|
|
|
|
|
wxString val = symbol->GetFieldText( aFieldName );
|
|
|
|
|
|
|
|
if( aFieldName == wxT( "Value" ) )
|
2022-11-25 14:25:39 +00:00
|
|
|
val = symbol->GetValueFieldText( true );
|
2022-03-23 15:46:49 +00:00
|
|
|
else if( aFieldName == wxT( "Footprint" ) )
|
2022-11-25 14:25:39 +00:00
|
|
|
val = symbol->GetFootprintFieldText( true );
|
2022-03-23 15:46:49 +00:00
|
|
|
|
|
|
|
m_dataStore[ symbol->m_Uuid ][ aFieldName ] = val;
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-05-03 06:24:45 +00:00
|
|
|
}
|
|
|
|
|
2022-04-12 20:13:26 +00:00
|
|
|
void RemoveColumn( int aCol )
|
|
|
|
{
|
|
|
|
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
|
|
|
{
|
|
|
|
SCH_SYMBOL* symbol = m_symbolsList[ i ].GetSymbol();
|
2023-02-23 19:10:50 +00:00
|
|
|
m_dataStore[symbol->m_Uuid].erase( m_cols[aCol].m_fieldName );
|
2022-04-12 20:13:26 +00:00
|
|
|
}
|
2023-02-23 19:10:50 +00:00
|
|
|
|
|
|
|
m_cols.erase( m_cols.begin() + aCol );
|
2022-04-12 20:13:26 +00:00
|
|
|
}
|
|
|
|
|
2023-01-27 14:18:32 +00:00
|
|
|
void RenameColumn( int aCol, const wxString& newName )
|
|
|
|
{
|
|
|
|
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
|
|
|
{
|
|
|
|
SCH_SYMBOL* symbol = m_symbolsList[i].GetSymbol();
|
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
auto node = m_dataStore[symbol->m_Uuid].extract( m_cols[aCol].m_fieldName );
|
2023-01-27 14:18:32 +00:00
|
|
|
node.key() = newName;
|
|
|
|
m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
|
|
|
|
}
|
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
m_cols[aCol].m_fieldName = newName;
|
2023-02-06 21:05:53 +00:00
|
|
|
}
|
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
void MoveColumn( int aCol, int aNewPos ) { std::swap( m_cols[aCol], m_cols[aNewPos] ); }
|
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
int GetNumberRows() override { return (int) m_rows.size(); }
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
int GetNumberCols() override { return (int) m_cols.size(); }
|
|
|
|
|
|
|
|
void SetColLabelValue( int aCol, const wxString& aLabel ) override
|
|
|
|
{
|
|
|
|
m_cols[aCol].m_label = aLabel;
|
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
wxString GetColLabelValue( int aCol ) override { return m_cols[aCol].m_label; }
|
2023-02-02 19:12:02 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
wxString GetColFieldName( int aCol ) { return m_cols[aCol].m_fieldName; }
|
2020-10-19 17:35:22 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
int GetFieldNameCol( wxString aFieldName )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
for( size_t i = 0; i < m_cols.size(); i++ )
|
2023-02-02 19:12:02 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
if( m_cols[i].m_fieldName == aFieldName )
|
2023-02-02 19:12:02 +00:00
|
|
|
return (int) i;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-05-08 10:41:46 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
const std::vector<wxString> GetFieldsOrder()
|
|
|
|
{
|
|
|
|
std::vector<wxString> fields;
|
|
|
|
|
|
|
|
for( auto col : m_cols )
|
|
|
|
{
|
|
|
|
fields.emplace_back( col.m_fieldName );
|
|
|
|
}
|
|
|
|
|
|
|
|
return fields;
|
|
|
|
}
|
2023-02-06 21:05:53 +00:00
|
|
|
|
|
|
|
void SetFieldsOrder( const std::vector<wxString>& aNewOrder )
|
|
|
|
{
|
|
|
|
size_t foundCount = 0;
|
|
|
|
|
|
|
|
for( const wxString& newField : aNewOrder )
|
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
for( size_t i = 0; i < m_cols.size(); i++ )
|
2023-02-06 21:05:53 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
if( m_cols[i].m_fieldName == newField )
|
2023-02-06 21:05:53 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
std::swap( m_cols[foundCount], m_cols[i] );
|
2023-02-06 21:05:53 +00:00
|
|
|
foundCount++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-02-02 19:12:02 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
bool IsEmptyCell( int aRow, int aCol ) override
|
|
|
|
{
|
|
|
|
return false; // don't allow adjacent cell overflow, even if we are actually empty
|
|
|
|
}
|
2017-05-08 10:41:46 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
wxString GetValue( int aRow, int aCol ) override
|
2017-05-08 10:41:46 +00:00
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
if( ColIsReference( aCol ) )
|
2018-05-13 11:06:46 +00:00
|
|
|
{
|
|
|
|
// Poor-man's tree controls
|
|
|
|
if( m_rows[ aRow ].m_Flag == GROUP_COLLAPSED )
|
|
|
|
return wxT( "> " ) + GetValue( m_rows[ aRow ], aCol );
|
|
|
|
else if (m_rows[ aRow ].m_Flag == GROUP_EXPANDED )
|
|
|
|
return wxT( "v " ) + GetValue( m_rows[ aRow ], aCol );
|
|
|
|
else if( m_rows[ aRow ].m_Flag == CHILD_ITEM )
|
|
|
|
return wxT( " " ) + GetValue( m_rows[ aRow ], aCol );
|
|
|
|
else
|
|
|
|
return wxT( " " ) + GetValue( m_rows[ aRow ], aCol );
|
|
|
|
}
|
|
|
|
else
|
2021-02-23 14:34:06 +00:00
|
|
|
{
|
2018-05-13 11:06:46 +00:00
|
|
|
return GetValue( m_rows[ aRow ], aCol );
|
2021-02-23 14:34:06 +00:00
|
|
|
}
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2022-05-09 13:41:00 +00:00
|
|
|
wxString GetRawValue( int aRow, int aCol )
|
|
|
|
{
|
|
|
|
return GetValue( m_rows[ aRow ], aCol );
|
|
|
|
}
|
|
|
|
|
|
|
|
GROUP_TYPE GetRowFlags( int aRow )
|
|
|
|
{
|
|
|
|
return m_rows[ aRow ].m_Flag;
|
|
|
|
}
|
|
|
|
|
2020-10-27 11:03:35 +00:00
|
|
|
std::vector<SCH_REFERENCE> GetRowReferences( int aRow ) const
|
2018-05-19 15:25:28 +00:00
|
|
|
{
|
2018-06-12 18:15:04 +00:00
|
|
|
wxCHECK( aRow < (int)m_rows.size(), std::vector<SCH_REFERENCE>() );
|
2018-05-19 15:25:28 +00:00
|
|
|
return m_rows[ aRow ].m_Refs;
|
|
|
|
}
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
bool ColIsReference( int aCol )
|
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
return ( aCol < (int) m_cols.size() ) && m_cols[aCol].m_fieldName == _( "Reference" );
|
2023-02-02 19:12:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ColIsQuantity( int aCol )
|
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
return ( aCol < (int) m_cols.size() ) && m_cols[aCol].m_fieldName == _( "Qty" );
|
2023-02-02 19:12:02 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 11:03:35 +00:00
|
|
|
wxString GetValue( const DATA_MODEL_ROW& group, int aCol )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2018-05-13 11:06:46 +00:00
|
|
|
std::vector<SCH_REFERENCE> references;
|
|
|
|
wxString fieldValue;
|
2017-05-08 10:41:46 +00:00
|
|
|
|
2022-04-12 20:13:26 +00:00
|
|
|
for( const SCH_REFERENCE& ref : group.m_Refs )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
if( ColIsReference( aCol ) || ColIsQuantity( aCol ) )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2018-05-13 11:06:46 +00:00
|
|
|
references.push_back( ref );
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
|
|
|
else // Other columns are either a single value or ROW_MULTI_ITEMS
|
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
const KIID& symbolID = ref.GetSymbol()->m_Uuid;
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2020-12-12 14:59:48 +00:00
|
|
|
if( !m_dataStore.count( symbolID )
|
2023-02-23 19:10:50 +00:00
|
|
|
|| !m_dataStore[symbolID].count( m_cols[aCol].m_fieldName ) )
|
2020-05-05 15:40:18 +00:00
|
|
|
{
|
|
|
|
return INDETERMINATE_STATE;
|
|
|
|
}
|
2019-01-12 01:27:08 +00:00
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
if( &ref == &group.m_Refs.front() )
|
2023-02-23 19:10:50 +00:00
|
|
|
fieldValue = m_dataStore[symbolID][m_cols[aCol].m_fieldName];
|
|
|
|
else if( fieldValue != m_dataStore[symbolID][m_cols[aCol].m_fieldName] )
|
2020-05-05 15:40:18 +00:00
|
|
|
return INDETERMINATE_STATE;
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-08 10:41:46 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
if( ColIsReference( aCol ) || ColIsQuantity( aCol ) )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
|
|
|
// Remove duplicates (other units of multi-unit parts)
|
2018-10-07 23:14:07 +00:00
|
|
|
std::sort( references.begin(), references.end(),
|
2020-12-12 14:59:48 +00:00
|
|
|
[]( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
|
|
|
|
{
|
2021-09-25 20:52:35 +00:00
|
|
|
wxString l_ref( l.GetRef() << l.GetRefNumber() );
|
|
|
|
wxString r_ref( r.GetRef() << r.GetRefNumber() );
|
2021-09-01 18:45:10 +00:00
|
|
|
return StrNumCmp( l_ref, r_ref, true ) < 0;
|
2020-12-12 14:59:48 +00:00
|
|
|
} );
|
2018-10-07 23:14:07 +00:00
|
|
|
|
2018-05-13 11:06:46 +00:00
|
|
|
auto logicalEnd = std::unique( references.begin(), references.end(),
|
2020-12-12 14:59:48 +00:00
|
|
|
[]( const SCH_REFERENCE& l, const SCH_REFERENCE& r ) -> bool
|
|
|
|
{
|
|
|
|
// If unannotated then we can't tell what units belong together
|
|
|
|
// so we have to leave them all
|
|
|
|
if( l.GetRefNumber() == wxT( "?" ) )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
wxString l_ref( l.GetRef() << l.GetRefNumber() );
|
|
|
|
wxString r_ref( r.GetRef() << r.GetRefNumber() );
|
|
|
|
return l_ref == r_ref;
|
|
|
|
} );
|
|
|
|
|
2018-05-13 11:06:46 +00:00
|
|
|
references.erase( logicalEnd, references.end() );
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
if( ColIsReference( aCol ) )
|
2018-05-13 11:06:46 +00:00
|
|
|
fieldValue = SCH_REFERENCE_LIST::Shorthand( references );
|
2023-02-02 19:12:02 +00:00
|
|
|
else if( ColIsQuantity( aCol ) )
|
2018-05-13 11:06:46 +00:00
|
|
|
fieldValue = wxString::Format( wxT( "%d" ), ( int )references.size() );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2018-10-19 11:28:34 +00:00
|
|
|
return fieldValue;
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void SetValue( int aRow, int aCol, const wxString &aValue ) override
|
2017-05-08 10:41:46 +00:00
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
if( ColIsReference( aCol ) || ColIsQuantity( aCol ) )
|
2018-04-17 10:34:48 +00:00
|
|
|
return; // Can't modify references or quantity
|
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
DATA_MODEL_ROW& rowGroup = m_rows[aRow];
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2022-04-12 20:13:26 +00:00
|
|
|
for( const SCH_REFERENCE& ref : rowGroup.m_Refs )
|
2023-02-23 19:10:50 +00:00
|
|
|
m_dataStore[ref.GetSymbol()->m_Uuid][m_cols[aCol].m_fieldName] = aValue;
|
2018-06-05 19:59:58 +00:00
|
|
|
|
|
|
|
m_edited = true;
|
2017-05-08 10:41:46 +00:00
|
|
|
}
|
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
static bool cmp( const DATA_MODEL_ROW& lhGroup, const DATA_MODEL_ROW& rhGroup,
|
2018-04-17 10:34:48 +00:00
|
|
|
FIELDS_EDITOR_GRID_DATA_MODEL* dataModel, int sortCol, bool ascending )
|
|
|
|
{
|
|
|
|
// Empty rows always go to the bottom, whether ascending or descending
|
2018-05-12 22:04:11 +00:00
|
|
|
if( lhGroup.m_Refs.size() == 0 )
|
2018-04-17 10:34:48 +00:00
|
|
|
return true;
|
2018-05-12 22:04:11 +00:00
|
|
|
else if( rhGroup.m_Refs.size() == 0 )
|
2018-04-17 10:34:48 +00:00
|
|
|
return false;
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2019-11-13 07:33:29 +00:00
|
|
|
// N.B. To meet the iterator sort conditions, we cannot simply invert the truth
|
|
|
|
// to get the opposite sort. i.e. ~(a<b) != (a>b)
|
2020-12-12 14:59:48 +00:00
|
|
|
auto local_cmp =
|
|
|
|
[ ascending ]( const auto a, const auto b )
|
|
|
|
{
|
|
|
|
if( ascending )
|
|
|
|
return a < b;
|
|
|
|
else
|
|
|
|
return a > b;
|
|
|
|
};
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2019-02-03 20:53:21 +00:00
|
|
|
// Primary sort key is sortCol; secondary is always REFERENCE (column 0)
|
2017-12-29 15:44:33 +00:00
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
wxString lhs = dataModel->GetValue( (DATA_MODEL_ROW&) lhGroup, sortCol );
|
|
|
|
wxString rhs = dataModel->GetValue( (DATA_MODEL_ROW&) rhGroup, sortCol );
|
2017-05-08 10:41:46 +00:00
|
|
|
|
2020-11-12 21:31:41 +00:00
|
|
|
if( lhs == rhs || sortCol == REFERENCE_FIELD )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2021-09-25 20:14:42 +00:00
|
|
|
wxString lhRef = lhGroup.m_Refs[ 0 ].GetRef() + lhGroup.m_Refs[ 0 ].GetRefNumber();
|
|
|
|
wxString rhRef = rhGroup.m_Refs[ 0 ].GetRef() + rhGroup.m_Refs[ 0 ].GetRefNumber();
|
2021-09-01 18:45:10 +00:00
|
|
|
return local_cmp( StrNumCmp( lhRef, rhRef, true ), 0 );
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
|
|
|
else
|
2020-12-12 14:59:48 +00:00
|
|
|
{
|
2019-11-13 07:33:29 +00:00
|
|
|
return local_cmp( ValueStringCompare( lhs, rhs ), 0 );
|
2020-12-12 14:59:48 +00:00
|
|
|
}
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
void Sort( int aColumn, bool ascending )
|
|
|
|
{
|
|
|
|
if( aColumn < 0 )
|
|
|
|
aColumn = 0;
|
|
|
|
|
2018-05-13 11:06:46 +00:00
|
|
|
m_sortColumn = aColumn;
|
|
|
|
m_sortAscending = ascending;
|
|
|
|
|
|
|
|
CollapseForSort();
|
2018-05-12 22:04:11 +00:00
|
|
|
|
2022-09-01 17:17:24 +00:00
|
|
|
// We're going to sort the rows based on their first reference, so the first reference
|
|
|
|
// had better be the lowest one.
|
|
|
|
for( DATA_MODEL_ROW& row : m_rows )
|
|
|
|
{
|
|
|
|
std::sort( row.m_Refs.begin(), row.m_Refs.end(),
|
|
|
|
[]( const SCH_REFERENCE& lhs, const SCH_REFERENCE& rhs )
|
|
|
|
{
|
|
|
|
wxString lhs_ref( lhs.GetRef() << lhs.GetRefNumber() );
|
|
|
|
wxString rhs_ref( rhs.GetRef() << rhs.GetRefNumber() );
|
|
|
|
return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
std::sort( m_rows.begin(), m_rows.end(),
|
2022-09-01 17:17:24 +00:00
|
|
|
[this]( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
|
2019-07-17 20:45:43 +00:00
|
|
|
{
|
|
|
|
return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
|
|
|
|
} );
|
2018-05-13 11:06:46 +00:00
|
|
|
|
|
|
|
ExpandAfterSort();
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
bool unitMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef )
|
2017-05-08 10:41:46 +00:00
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
// If items are unannotated then we can't tell if they're units of the same symbol or not
|
2018-05-13 20:47:47 +00:00
|
|
|
if( lhRef.GetRefNumber() == wxT( "?" ) )
|
2018-04-17 10:34:48 +00:00
|
|
|
return false;
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
return ( lhRef.GetRef() == rhRef.GetRef() && lhRef.GetRefNumber() == rhRef.GetRefNumber() );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool groupMatch( const SCH_REFERENCE& lhRef, const SCH_REFERENCE& rhRef,
|
|
|
|
wxDataViewListCtrl* fieldsCtrl )
|
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
bool matchFound = false;
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// First check the reference column. This can be done directly out of the
|
|
|
|
// SCH_REFERENCEs as the references can't be edited in the grid.
|
2020-11-12 21:31:41 +00:00
|
|
|
if( fieldsCtrl->GetToggleValue( REFERENCE_FIELD, GROUP_BY_COLUMN ) )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
|
|
|
// if we're grouping by reference, then only the prefix must match
|
|
|
|
if( lhRef.GetRef() != rhRef.GetRef() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
matchFound = true;
|
|
|
|
}
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
const KIID& lhRefID = lhRef.GetSymbol()->m_Uuid;
|
|
|
|
const KIID& rhRefID = rhRef.GetSymbol()->m_Uuid;
|
2018-04-17 10:34:48 +00:00
|
|
|
|
|
|
|
// Now check all the other columns. This must be done out of the dataStore
|
|
|
|
// for the refresh button to work after editing.
|
2020-11-12 21:31:41 +00:00
|
|
|
for( int i = REFERENCE_FIELD + 1; i < fieldsCtrl->GetItemCount(); ++i )
|
2017-05-08 10:41:46 +00:00
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
if( !fieldsCtrl->GetToggleValue( i, GROUP_BY_COLUMN ) )
|
|
|
|
continue;
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2023-02-07 15:04:44 +00:00
|
|
|
wxString fieldName = fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN );
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
if( m_dataStore[ lhRefID ][ fieldName ] != m_dataStore[ rhRefID ][ fieldName ] )
|
|
|
|
return false;
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
matchFound = true;
|
|
|
|
}
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
return matchFound;
|
2017-05-08 10:41:46 +00:00
|
|
|
}
|
2017-04-16 06:43:59 +00:00
|
|
|
|
2022-04-17 19:02:05 +00:00
|
|
|
void RebuildRows( wxSearchCtrl* aFilter, wxCheckBox* aGroupSymbolsBox,
|
|
|
|
wxDataViewListCtrl* aFieldsCtrl )
|
2017-05-08 10:41:46 +00:00
|
|
|
{
|
2022-04-17 19:02:05 +00:00
|
|
|
if( GetView() )
|
2018-04-17 19:23:26 +00:00
|
|
|
{
|
|
|
|
// Commit any pending in-place edits before the row gets moved out from under
|
|
|
|
// the editor.
|
2018-11-11 07:28:58 +00:00
|
|
|
static_cast<WX_GRID*>( GetView() )->CommitPendingChanges( true );
|
2018-04-17 19:23:26 +00:00
|
|
|
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, m_rows.size() );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
m_rows.clear();
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
SCH_REFERENCE ref = m_symbolsList[ i ];
|
2022-04-17 19:02:05 +00:00
|
|
|
|
|
|
|
if( !aFilter->GetValue().IsEmpty()
|
2022-04-19 18:19:47 +00:00
|
|
|
&& !WildCompareString( aFilter->GetValue(), ref.GetFullRef(), false ) )
|
2022-04-17 19:02:05 +00:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool matchFound = false;
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
// See if we already have a row which this symbol fits into
|
2020-12-12 14:59:48 +00:00
|
|
|
for( DATA_MODEL_ROW& row : m_rows )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2018-05-12 22:04:11 +00:00
|
|
|
// all group members must have identical refs so just use the first one
|
|
|
|
SCH_REFERENCE rowRef = row.m_Refs[ 0 ];
|
|
|
|
|
|
|
|
if( unitMatch( ref, rowRef ) )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
|
|
|
matchFound = true;
|
2018-05-12 22:04:11 +00:00
|
|
|
row.m_Refs.push_back( ref );
|
|
|
|
break;
|
|
|
|
}
|
2020-11-15 16:08:31 +00:00
|
|
|
else if ( aGroupSymbolsBox->GetValue() && groupMatch( ref, rowRef, aFieldsCtrl ) )
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
|
|
|
matchFound = true;
|
|
|
|
row.m_Refs.push_back( ref );
|
|
|
|
row.m_Flag = GROUP_COLLAPSED;
|
2018-04-17 10:34:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !matchFound )
|
2019-07-17 20:45:43 +00:00
|
|
|
m_rows.emplace_back( DATA_MODEL_ROW( ref, GROUP_SINGLETON ) );
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
|
|
|
|
2018-04-17 19:23:26 +00:00
|
|
|
if ( GetView() )
|
|
|
|
{
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, m_rows.size() );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
2017-05-08 10:41:46 +00:00
|
|
|
}
|
2017-04-18 14:10:17 +00:00
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
void ExpandRow( int aRow )
|
|
|
|
{
|
|
|
|
std::vector<DATA_MODEL_ROW> children;
|
|
|
|
|
2020-12-12 14:59:48 +00:00
|
|
|
for( SCH_REFERENCE& ref : m_rows[ aRow ].m_Refs )
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
|
|
|
bool matchFound = false;
|
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
// See if we already have a child group which this symbol fits into
|
2020-12-12 14:59:48 +00:00
|
|
|
for( DATA_MODEL_ROW& child : children )
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
|
|
|
// group members are by definition all matching, so just check
|
|
|
|
// against the first member
|
|
|
|
if( unitMatch( ref, child.m_Refs[ 0 ] ) )
|
|
|
|
{
|
|
|
|
matchFound = true;
|
|
|
|
child.m_Refs.push_back( ref );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( !matchFound )
|
2019-07-17 20:45:43 +00:00
|
|
|
children.emplace_back( DATA_MODEL_ROW( ref, CHILD_ITEM ) );
|
2018-05-12 22:04:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( children.size() < 2 )
|
|
|
|
return;
|
|
|
|
|
2018-05-13 11:06:46 +00:00
|
|
|
std::sort( children.begin(), children.end(),
|
|
|
|
[ this ] ( const DATA_MODEL_ROW& lhs, const DATA_MODEL_ROW& rhs ) -> bool
|
|
|
|
{
|
|
|
|
return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
|
|
|
|
} );
|
|
|
|
|
2018-05-12 22:04:11 +00:00
|
|
|
m_rows[ aRow ].m_Flag = GROUP_EXPANDED;
|
|
|
|
m_rows.insert( m_rows.begin() + aRow + 1, children.begin(), children.end() );
|
|
|
|
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, children.size() );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
void CollapseRow( int aRow )
|
|
|
|
{
|
|
|
|
auto firstChild = m_rows.begin() + aRow + 1;
|
|
|
|
auto afterLastChild = firstChild;
|
|
|
|
int deleted = 0;
|
|
|
|
|
|
|
|
while( afterLastChild != m_rows.end() && afterLastChild->m_Flag == CHILD_ITEM )
|
|
|
|
{
|
|
|
|
deleted++;
|
|
|
|
afterLastChild++;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_rows[ aRow ].m_Flag = GROUP_COLLAPSED;
|
|
|
|
m_rows.erase( firstChild, afterLastChild );
|
|
|
|
|
|
|
|
wxGridTableMessage msg( this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
|
|
|
|
GetView()->ProcessTableMessage( msg );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExpandCollapseRow( int aRow )
|
|
|
|
{
|
|
|
|
DATA_MODEL_ROW& group = m_rows[ aRow ];
|
|
|
|
|
|
|
|
if( group.m_Flag == GROUP_COLLAPSED )
|
|
|
|
ExpandRow( aRow );
|
|
|
|
else if( group.m_Flag == GROUP_EXPANDED )
|
|
|
|
CollapseRow( aRow );
|
|
|
|
}
|
|
|
|
|
2018-05-13 11:06:46 +00:00
|
|
|
void CollapseForSort()
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
2018-05-13 06:56:17 +00:00
|
|
|
for( size_t i = 0; i < m_rows.size(); ++i )
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
|
|
|
if( m_rows[ i ].m_Flag == GROUP_EXPANDED )
|
2018-05-13 11:06:46 +00:00
|
|
|
{
|
2018-05-12 22:04:11 +00:00
|
|
|
CollapseRow( i );
|
2018-05-13 11:06:46 +00:00
|
|
|
m_rows[ i ].m_Flag = GROUP_COLLAPSED_DURING_SORT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExpandAfterSort()
|
|
|
|
{
|
2018-05-16 16:14:06 +00:00
|
|
|
for( size_t i = 0; i < m_rows.size(); ++i )
|
2018-05-13 11:06:46 +00:00
|
|
|
{
|
|
|
|
if( m_rows[ i ].m_Flag == GROUP_COLLAPSED_DURING_SORT )
|
|
|
|
ExpandRow( i );
|
2018-05-12 22:04:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-22 11:50:57 +00:00
|
|
|
void ApplyData()
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2021-06-10 14:10:55 +00:00
|
|
|
SCH_SYMBOL& symbol = *m_symbolsList[ i ].GetSymbol();
|
|
|
|
SCH_SCREEN* screen = m_symbolsList[i].GetSheetPath().LastScreen();
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
m_frame->SaveCopyInUndoList( screen, &symbol, UNDO_REDO::CHANGED, true );
|
2017-05-08 10:41:46 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
const std::map<wxString, wxString>& fieldStore = m_dataStore[symbol.m_Uuid];
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2019-03-27 09:39:25 +00:00
|
|
|
for( const std::pair<wxString, wxString> srcData : fieldStore )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2022-04-12 20:13:26 +00:00
|
|
|
if( srcData.first == _( "Qty" ) )
|
|
|
|
continue;
|
|
|
|
|
2019-03-27 09:39:25 +00:00
|
|
|
const wxString& srcName = srcData.first;
|
|
|
|
const wxString& srcValue = srcData.second;
|
2020-11-15 16:08:31 +00:00
|
|
|
SCH_FIELD* destField = symbol.FindField( srcName );
|
2023-02-23 19:10:50 +00:00
|
|
|
int col = GetFieldNameCol( srcName );
|
|
|
|
bool userAdded = ( col != -1 && m_cols[col].m_userAdded );
|
2018-04-19 17:55:16 +00:00
|
|
|
|
2022-05-13 09:39:16 +00:00
|
|
|
// Add a not existing field if it has a value for this symbol
|
2023-02-23 19:10:50 +00:00
|
|
|
bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
|
2022-09-12 22:38:36 +00:00
|
|
|
|
2022-05-13 09:39:16 +00:00
|
|
|
if( createField )
|
2019-03-27 09:39:25 +00:00
|
|
|
{
|
2022-01-01 06:04:08 +00:00
|
|
|
const VECTOR2I symbolPos = symbol.GetPosition();
|
2020-11-15 16:08:31 +00:00
|
|
|
destField = symbol.AddField( SCH_FIELD( symbolPos, -1, &symbol, srcName ) );
|
2019-03-27 09:39:25 +00:00
|
|
|
}
|
2018-04-19 17:55:16 +00:00
|
|
|
|
2022-05-13 09:39:16 +00:00
|
|
|
if( !destField )
|
|
|
|
continue;
|
|
|
|
|
2022-04-12 20:13:26 +00:00
|
|
|
if( destField->GetId() == REFERENCE_FIELD )
|
2020-09-18 22:29:38 +00:00
|
|
|
{
|
2022-05-13 09:39:16 +00:00
|
|
|
// Reference is not editable from this dialog
|
2020-09-18 22:29:38 +00:00
|
|
|
}
|
2020-11-12 21:31:41 +00:00
|
|
|
else if( destField->GetId() == VALUE_FIELD )
|
2020-09-18 22:29:38 +00:00
|
|
|
{
|
|
|
|
// Value field cannot be empty
|
|
|
|
if( !srcValue.IsEmpty() )
|
2022-11-25 14:25:39 +00:00
|
|
|
symbol.SetValueFieldText( srcValue );
|
2020-09-18 22:29:38 +00:00
|
|
|
}
|
2020-11-12 21:31:41 +00:00
|
|
|
else if( destField->GetId() == FOOTPRINT_FIELD )
|
2020-09-18 22:29:38 +00:00
|
|
|
{
|
2022-11-25 14:25:39 +00:00
|
|
|
symbol.SetFootprintFieldText( srcValue );
|
2020-09-18 22:29:38 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
destField->SetText( srcValue );
|
|
|
|
}
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2022-04-12 20:13:26 +00:00
|
|
|
|
|
|
|
for( int ii = symbol.GetFields().size() - 1; ii >= MANDATORY_FIELDS; ii-- )
|
|
|
|
{
|
|
|
|
if( fieldStore.count( symbol.GetFields()[ii].GetName() ) == 0 )
|
|
|
|
symbol.GetFields().erase( symbol.GetFields().begin() + ii );
|
|
|
|
}
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2018-06-05 19:59:58 +00:00
|
|
|
|
|
|
|
m_edited = false;
|
|
|
|
}
|
|
|
|
|
2018-09-27 12:04:15 +00:00
|
|
|
int GetDataWidth( int aCol )
|
|
|
|
{
|
|
|
|
int width = 0;
|
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
if( ColIsReference( aCol ) )
|
2018-09-27 12:04:15 +00:00
|
|
|
{
|
2018-09-29 08:08:29 +00:00
|
|
|
for( int row = 0; row < GetNumberRows(); ++row )
|
2020-10-25 16:41:38 +00:00
|
|
|
width = std::max( width, KIUI::GetTextSize( GetValue( row, aCol ), GetView() ).x );
|
2018-09-27 12:04:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
wxString fieldName = GetColFieldName( aCol ); // symbol fieldName or Qty string
|
2018-09-29 08:08:29 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
for( unsigned symbolRef = 0; symbolRef < m_symbolsList.GetCount(); ++ symbolRef )
|
2018-09-27 12:04:15 +00:00
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
const KIID& symbolID = m_symbolsList[ symbolRef ].GetSymbol()->m_Uuid;
|
2023-02-02 19:12:02 +00:00
|
|
|
wxString text = m_dataStore[symbolID][fieldName];
|
2020-02-21 22:20:42 +00:00
|
|
|
|
2020-10-25 16:41:38 +00:00
|
|
|
width = std::max( width, KIUI::GetTextSize( text, GetView() ).x );
|
2018-09-27 12:04:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-06-05 19:59:58 +00:00
|
|
|
bool IsEdited()
|
|
|
|
{
|
|
|
|
return m_edited;
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
|
|
|
};
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
DIALOG_SYMBOL_FIELDS_TABLE::DIALOG_SYMBOL_FIELDS_TABLE( SCH_EDIT_FRAME* parent ) :
|
2023-02-09 20:13:05 +00:00
|
|
|
DIALOG_SYMBOL_FIELDS_TABLE_BASE( parent ), m_currentBomPreset( nullptr ),
|
|
|
|
m_lastSelectedBomPreset( nullptr ), m_parent( parent ),
|
|
|
|
m_schSettings( parent->Schematic().Settings() )
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2018-09-27 12:04:15 +00:00
|
|
|
wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
|
2022-07-08 17:16:14 +00:00
|
|
|
int nameColWidthMargin = 44;
|
2018-09-27 12:04:15 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
// Get all symbols from the list of schematic sheets
|
|
|
|
m_parent->Schematic().GetSheets().GetSymbols( m_symbolsList, false );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2022-04-17 19:02:05 +00:00
|
|
|
m_separator1->SetIsSeparator();
|
|
|
|
m_separator2->SetIsSeparator();
|
2021-03-08 02:59:07 +00:00
|
|
|
m_bRefresh->SetBitmap( KiBitmap( BITMAPS::small_refresh ) );
|
2023-02-28 17:16:36 +00:00
|
|
|
m_bRefreshPreview->SetBitmap( KiBitmap( BITMAPS::small_refresh ) );
|
|
|
|
m_browseButton->SetBitmap( KiBitmap( BITMAPS::small_folder ) );
|
|
|
|
|
|
|
|
m_addFieldButton->SetBitmap( KiBitmap( BITMAPS::small_plus ) );
|
|
|
|
m_removeFieldButton->SetBitmap( KiBitmap( BITMAPS::small_trash ) );
|
|
|
|
m_renameFieldButton->SetBitmap( KiBitmap( BITMAPS::small_edit ) );
|
|
|
|
|
|
|
|
m_removeFieldButton->Enable( false );
|
|
|
|
m_renameFieldButton->Enable( false );
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2021-02-23 14:34:06 +00:00
|
|
|
m_fieldsCtrl->AppendTextColumn( _( "Field" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldsCtrl->AppendTextColumn( _( "Label" ), wxDATAVIEW_CELL_EDITABLE, 0, wxALIGN_LEFT, 0 );
|
2020-12-12 14:59:48 +00:00
|
|
|
m_fieldsCtrl->AppendToggleColumn( _( "Show" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
|
|
|
|
wxALIGN_CENTER, 0 );
|
2019-06-17 19:05:11 +00:00
|
|
|
m_fieldsCtrl->AppendToggleColumn( _( "Group By" ), wxDATAVIEW_CELL_ACTIVATABLE, 0,
|
|
|
|
wxALIGN_CENTER, 0 );
|
2020-12-12 14:59:48 +00:00
|
|
|
|
|
|
|
// GTK asserts if the number of columns doesn't match the data, but we still don't want
|
|
|
|
// to display the canonical names. So we'll insert a column for them, but keep it 0 width.
|
|
|
|
m_fieldsCtrl->AppendTextColumn( _( "Name" ), wxDATAVIEW_CELL_INERT, 0, wxALIGN_LEFT, 0 );
|
2018-04-23 17:23:09 +00:00
|
|
|
|
2018-04-26 17:00:25 +00:00
|
|
|
// SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails here on GTK, so we calculate the title sizes and
|
|
|
|
// set the column widths ourselves.
|
2020-10-28 10:22:52 +00:00
|
|
|
wxDataViewColumn* column = m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN );
|
2020-10-25 16:41:38 +00:00
|
|
|
m_showColWidth = KIUI::GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
|
2020-10-28 10:22:52 +00:00
|
|
|
column->SetMinWidth( m_showColWidth );
|
2018-04-26 10:09:41 +00:00
|
|
|
|
|
|
|
column = m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN );
|
2020-10-25 16:41:38 +00:00
|
|
|
m_groupByColWidth = KIUI::GetTextSize( column->GetTitle(), m_fieldsCtrl ).x + COLUMN_MARGIN;
|
2020-10-28 10:22:52 +00:00
|
|
|
column->SetMinWidth( m_groupByColWidth );
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// The fact that we're a list should keep the control from reserving space for the
|
|
|
|
// expander buttons... but it doesn't. Fix by forcing the indent to 0.
|
|
|
|
m_fieldsCtrl->SetIndent( 0 );
|
|
|
|
|
2022-04-17 19:02:05 +00:00
|
|
|
m_filter->SetDescriptiveText( _( "Filter" ) );
|
2020-11-15 16:08:31 +00:00
|
|
|
m_dataModel = new FIELDS_EDITOR_GRID_DATA_MODEL( m_parent, m_symbolsList );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
|
|
|
LoadFieldNames(); // loads rows into m_fieldsCtrl and columns into m_dataModel
|
|
|
|
|
2018-04-26 10:09:41 +00:00
|
|
|
// Now that the fields are loaded we can set the initial location of the splitter
|
2018-04-26 17:00:25 +00:00
|
|
|
// based on the list width. Again, SetWidth( wxCOL_WIDTH_AUTOSIZE ) fails us on GTK.
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldNameColWidth = 0;
|
|
|
|
m_labelColWidth = 0;
|
2018-04-29 13:45:11 +00:00
|
|
|
|
|
|
|
for( int row = 0; row < m_fieldsCtrl->GetItemCount(); ++row )
|
2018-04-26 17:00:25 +00:00
|
|
|
{
|
2023-02-07 15:04:44 +00:00
|
|
|
const wxString& displayName = m_fieldsCtrl->GetTextValue( row, DISPLAY_NAME_COLUMN );
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldNameColWidth =
|
|
|
|
std::max( m_fieldNameColWidth, KIUI::GetTextSize( displayName, m_fieldsCtrl ).x );
|
|
|
|
|
|
|
|
const wxString& label = m_fieldsCtrl->GetTextValue( row, LABEL_COLUMN );
|
|
|
|
m_labelColWidth = std::max( m_labelColWidth, KIUI::GetTextSize( label, m_fieldsCtrl ).x );
|
2018-04-26 17:00:25 +00:00
|
|
|
}
|
2018-04-29 13:45:11 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldNameColWidth += nameColWidthMargin;
|
|
|
|
m_labelColWidth += nameColWidthMargin;
|
2022-07-08 17:16:14 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
int fieldsMinWidth = m_fieldNameColWidth + m_labelColWidth + m_groupByColWidth + m_showColWidth;
|
2020-10-28 10:22:52 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( m_fieldNameColWidth );
|
|
|
|
m_fieldsCtrl->GetColumn( LABEL_COLUMN )->SetWidth( m_labelColWidth );
|
2020-12-12 14:59:48 +00:00
|
|
|
|
|
|
|
// This is used for data only. Don't show it to the user.
|
2023-02-07 15:04:44 +00:00
|
|
|
m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetHidden( true );
|
2020-10-29 16:27:38 +00:00
|
|
|
|
|
|
|
m_splitterMainWindow->SetMinimumPaneSize( fieldsMinWidth );
|
|
|
|
m_splitterMainWindow->SetSashPosition( fieldsMinWidth + 40 );
|
2018-04-26 10:09:41 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
m_cbBomPresets->SetToolTip( wxString::Format(
|
|
|
|
_( "Save and restore layer visibility combinations.\n"
|
|
|
|
"Use %s+Tab to activate selector.\n"
|
|
|
|
"Successive Tabs while holding %s down will "
|
|
|
|
"cycle through presets in the popup." ),
|
|
|
|
KeyNameFromKeyCode( PRESET_SWITCH_KEY ), KeyNameFromKeyCode( PRESET_SWITCH_KEY ) ) );
|
|
|
|
|
2022-04-17 19:02:05 +00:00
|
|
|
m_dataModel->RebuildRows( m_filter, m_groupSymbolsBox, m_fieldsCtrl );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2022-07-08 17:16:14 +00:00
|
|
|
m_grid->UseNativeColHeader( true );
|
2018-04-17 10:34:48 +00:00
|
|
|
m_grid->SetTable( m_dataModel, true );
|
|
|
|
|
2020-04-21 15:15:04 +00:00
|
|
|
// must be done after SetTable(), which appears to re-set it
|
2021-02-03 03:32:20 +00:00
|
|
|
m_grid->SetSelectionMode( wxGrid::wxGridSelectCells );
|
2020-04-21 15:15:04 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// add Cut, Copy, and Paste to wxGrid
|
2023-02-23 19:10:50 +00:00
|
|
|
m_grid->PushEventHandler( new FIELDS_EDITOR_GRID_TRICKS( this, m_grid, m_fieldsCtrl ) );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2018-07-20 22:26:37 +00:00
|
|
|
// give a bit more room for comboboxes
|
|
|
|
m_grid->SetDefaultRowSize( m_grid->GetDefaultRowSize() + 4 );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
// Load our BOM view presets
|
|
|
|
SetUserBomPresets( m_schSettings.m_BomPresets );
|
|
|
|
ApplyBomPreset( m_schSettings.m_BomSettings );
|
|
|
|
syncBomPresetSelection();
|
|
|
|
|
2023-02-06 21:05:53 +00:00
|
|
|
SetupColumnProperties();
|
|
|
|
|
|
|
|
m_grid->SelectRow( 0 );
|
|
|
|
m_grid->SetGridCursor( 0, 1 );
|
|
|
|
SetInitialFocus( m_grid );
|
|
|
|
|
|
|
|
SetupStandardButtons();
|
|
|
|
|
|
|
|
finishDialogSettings();
|
|
|
|
SetSize( defaultDlgSize );
|
|
|
|
Center();
|
|
|
|
|
|
|
|
// Connect Events
|
|
|
|
m_grid->Connect( wxEVT_GRID_COL_SORT,
|
|
|
|
wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr, this );
|
|
|
|
m_grid->Connect( wxEVT_GRID_COL_MOVE,
|
|
|
|
wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColMove ), nullptr, this );
|
2023-02-09 20:13:05 +00:00
|
|
|
m_cbBomPresets->Bind( wxEVT_CHOICE, &DIALOG_SYMBOL_FIELDS_TABLE::onBomPresetChanged, this );
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldsCtrl->Bind( wxEVT_DATAVIEW_ITEM_VALUE_CHANGED,
|
|
|
|
&DIALOG_SYMBOL_FIELDS_TABLE::OnColLabelChange, this );
|
2023-02-06 21:05:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::SetupColumnProperties()
|
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
wxSize defaultDlgSize = ConvertDialogToPixels( wxSize( 600, 300 ) );
|
2019-06-17 19:05:11 +00:00
|
|
|
|
2023-01-30 17:16:33 +00:00
|
|
|
// Restore column sorting order and widths
|
2023-02-02 19:12:02 +00:00
|
|
|
m_grid->AutoSizeColumns( false );
|
2023-01-30 17:16:33 +00:00
|
|
|
int sortCol = 0;
|
|
|
|
bool sortAscending = true;
|
|
|
|
|
2023-02-06 21:05:53 +00:00
|
|
|
|
2020-04-21 15:15:04 +00:00
|
|
|
for( int col = 0; col < m_grid->GetNumberCols(); ++col )
|
2018-09-27 12:04:15 +00:00
|
|
|
{
|
2023-02-06 21:05:53 +00:00
|
|
|
wxGridCellAttr* attr = new wxGridCellAttr;
|
|
|
|
attr->SetReadOnly( false );
|
|
|
|
|
|
|
|
// Set some column types to specific editors
|
|
|
|
if( m_dataModel->GetColFieldName( col ) == _( "Reference" ) )
|
|
|
|
{
|
|
|
|
attr->SetReadOnly();
|
|
|
|
m_grid->SetColAttr( col, attr );
|
|
|
|
}
|
|
|
|
else if( m_dataModel->GetColFieldName( col ) == _( "Footprint" ) )
|
|
|
|
{
|
|
|
|
attr->SetEditor( new GRID_CELL_FPID_EDITOR( this, wxEmptyString ) );
|
|
|
|
m_grid->SetColAttr( col, attr );
|
|
|
|
}
|
|
|
|
else if( m_dataModel->GetColFieldName( col ) == _( "Datasheet" ) )
|
|
|
|
{
|
|
|
|
// set datasheet column viewer button
|
|
|
|
attr->SetEditor( new GRID_CELL_URL_EDITOR( this, Prj().SchSearchS() ) );
|
|
|
|
m_grid->SetColAttr( col, attr );
|
|
|
|
}
|
|
|
|
else if( m_dataModel->GetColFieldName( col ) == _( "Qty" ) )
|
|
|
|
{
|
|
|
|
attr->SetReadOnly();
|
|
|
|
m_grid->SetColAttr( col, attr );
|
|
|
|
m_grid->SetColFormatNumber( col );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
attr->SetEditor( m_grid->GetDefaultEditor() );
|
|
|
|
m_grid->SetColAttr( col, attr );
|
|
|
|
m_grid->SetColFormatCustom( col, wxGRID_VALUE_STRING );
|
|
|
|
}
|
|
|
|
|
2018-10-05 12:54:15 +00:00
|
|
|
// Columns are hidden by setting their width to 0 so if we resize them they will
|
|
|
|
// become unhidden.
|
|
|
|
if( m_grid->IsColShown( col ) )
|
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
std::string key( m_dataModel->GetColFieldName( col ).ToUTF8() );
|
2018-09-27 12:04:15 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
if( m_schSettings.m_BomSettings.column_widths.count( key ) )
|
2020-04-21 15:15:04 +00:00
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
int width = m_schSettings.m_BomSettings.column_widths.at( key );
|
2020-04-21 15:15:04 +00:00
|
|
|
m_grid->SetColSize( col, width );
|
|
|
|
}
|
2018-10-05 12:54:15 +00:00
|
|
|
else
|
2020-04-21 15:15:04 +00:00
|
|
|
{
|
|
|
|
int textWidth = m_dataModel->GetDataWidth( col ) + COLUMN_MARGIN;
|
|
|
|
int maxWidth = defaultDlgSize.x / 3;
|
|
|
|
|
|
|
|
if( col == m_grid->GetNumberCols() - 1 )
|
2023-03-03 18:25:25 +00:00
|
|
|
m_grid->SetColSize( col, Clamp( 50, textWidth, maxWidth ) );
|
2020-04-21 15:15:04 +00:00
|
|
|
else
|
2023-03-03 18:25:25 +00:00
|
|
|
m_grid->SetColSize( col, Clamp( 100, textWidth, maxWidth ) );
|
2020-04-21 15:15:04 +00:00
|
|
|
}
|
2023-01-30 17:16:33 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
if( m_schSettings.m_BomSettings.column_sorts.count( key ) )
|
2023-01-30 17:16:33 +00:00
|
|
|
{
|
|
|
|
sortCol = col;
|
2023-02-09 20:13:05 +00:00
|
|
|
sortAscending = m_schSettings.m_BomSettings.column_sorts[key];
|
2023-01-30 17:16:33 +00:00
|
|
|
}
|
2018-10-05 12:54:15 +00:00
|
|
|
}
|
2018-09-27 12:04:15 +00:00
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2023-02-06 21:05:53 +00:00
|
|
|
// sync m_grid's column visibilities to Show checkboxes in m_fieldsCtrl
|
|
|
|
for( int i = 0; i < m_fieldsCtrl->GetItemCount(); ++i )
|
2023-01-30 17:16:33 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
int col = m_dataModel->GetFieldNameCol( m_fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ) );
|
|
|
|
|
|
|
|
if( col == -1 )
|
|
|
|
continue;
|
2023-01-30 17:16:33 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
if( m_fieldsCtrl->GetToggleValue( i, SHOW_FIELD_COLUMN ) )
|
|
|
|
m_grid->ShowCol( col );
|
2023-02-06 21:05:53 +00:00
|
|
|
else
|
2023-02-23 19:10:50 +00:00
|
|
|
m_grid->HideCol( col );
|
2023-01-30 17:16:33 +00:00
|
|
|
}
|
|
|
|
|
2023-02-06 21:05:53 +00:00
|
|
|
m_dataModel->Sort( sortCol, sortAscending );
|
|
|
|
m_grid->SetSortingColumn( sortCol, sortAscending );
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
DIALOG_SYMBOL_FIELDS_TABLE::~DIALOG_SYMBOL_FIELDS_TABLE()
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
// Disconnect Events
|
2019-06-17 19:05:11 +00:00
|
|
|
m_grid->Disconnect( wxEVT_GRID_COL_SORT,
|
2021-07-16 20:13:26 +00:00
|
|
|
wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColSort ), nullptr,
|
|
|
|
this );
|
2023-01-30 17:16:33 +00:00
|
|
|
m_grid->Disconnect( wxEVT_GRID_COL_SORT,
|
|
|
|
wxGridEventHandler( DIALOG_SYMBOL_FIELDS_TABLE::OnColMove ), nullptr,
|
|
|
|
this );
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// Delete the GRID_TRICKS.
|
|
|
|
m_grid->PopEventHandler( true );
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// we gave ownership of m_dataModel to the wxGrid...
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
bool DIALOG_SYMBOL_FIELDS_TABLE::TransferDataToWindow()
|
2020-01-09 00:57:39 +00:00
|
|
|
{
|
|
|
|
if( !wxDialog::TransferDataFromWindow() )
|
|
|
|
return false;
|
|
|
|
|
|
|
|
TOOL_MANAGER* toolMgr = m_parent->GetToolManager();
|
|
|
|
EE_SELECTION_TOOL* selectionTool = toolMgr->GetTool<EE_SELECTION_TOOL>();
|
|
|
|
EE_SELECTION& selection = selectionTool->GetSelection();
|
2021-06-10 14:10:55 +00:00
|
|
|
SCH_SYMBOL* symbol = nullptr;
|
2020-01-09 00:57:39 +00:00
|
|
|
|
|
|
|
if( selection.GetSize() == 1 )
|
|
|
|
{
|
|
|
|
EDA_ITEM* item = selection.Front();
|
|
|
|
|
2021-06-10 14:10:55 +00:00
|
|
|
if( item->Type() == SCH_SYMBOL_T )
|
|
|
|
symbol = (SCH_SYMBOL*) item;
|
|
|
|
else if( item->GetParent() && item->GetParent()->Type() == SCH_SYMBOL_T )
|
|
|
|
symbol = (SCH_SYMBOL*) item->GetParent();
|
2020-01-09 00:57:39 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
if( symbol )
|
2020-01-09 00:57:39 +00:00
|
|
|
{
|
|
|
|
for( int row = 0; row < m_dataModel->GetNumberRows(); ++row )
|
|
|
|
{
|
|
|
|
std::vector<SCH_REFERENCE> references = m_dataModel->GetRowReferences( row );
|
|
|
|
bool found = false;
|
|
|
|
|
2020-01-09 22:55:46 +00:00
|
|
|
for( const SCH_REFERENCE& ref : references )
|
2020-01-09 00:57:39 +00:00
|
|
|
{
|
2020-11-15 16:08:31 +00:00
|
|
|
if( ref.GetSymbol() == symbol )
|
2020-01-09 00:57:39 +00:00
|
|
|
{
|
|
|
|
found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if( found )
|
|
|
|
{
|
|
|
|
m_grid->GoToCell( row, 1 );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
bool DIALOG_SYMBOL_FIELDS_TABLE::TransferDataFromWindow()
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2018-08-19 16:10:14 +00:00
|
|
|
if( !m_grid->CommitPendingChanges() )
|
|
|
|
return false;
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
if( !wxDialog::TransferDataFromWindow() )
|
|
|
|
return false;
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
SCH_SHEET_PATH currentSheet = m_parent->GetCurrentSheet();
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-05-22 11:50:57 +00:00
|
|
|
m_dataModel->ApplyData();
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
// Reset the view to where we left the user
|
|
|
|
m_parent->SetCurrentSheet( currentSheet );
|
2020-05-09 19:02:54 +00:00
|
|
|
m_parent->SyncView();
|
2018-04-17 10:34:48 +00:00
|
|
|
m_parent->Refresh();
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2020-05-09 19:02:54 +00:00
|
|
|
m_parent->OnModify();
|
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
return true;
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::AddField( const wxString& aFieldName,
|
|
|
|
const wxString& aLabelValue,
|
2022-09-12 22:38:36 +00:00
|
|
|
bool defaultShow, bool defaultSortBy, bool addedByUser )
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
m_dataModel->AddColumn( aFieldName, aLabelValue, addedByUser );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2018-05-22 11:50:57 +00:00
|
|
|
wxVector<wxVariant> fieldsCtrlRow;
|
2023-02-09 20:13:05 +00:00
|
|
|
bool show = defaultShow;
|
|
|
|
bool sort_by = defaultSortBy;
|
2020-01-13 01:44:19 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
std::string key( aFieldName.ToUTF8() );
|
2020-01-13 01:44:19 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
if( m_schSettings.m_BomSettings.fields_show.count( key ) )
|
|
|
|
show = m_schSettings.m_BomSettings.fields_show.at( key );
|
2020-01-13 01:44:19 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
if( m_schSettings.m_BomSettings.fields_group_by.count( key ) )
|
|
|
|
sort_by = m_schSettings.m_BomSettings.fields_group_by.at( key );
|
2018-05-19 15:47:39 +00:00
|
|
|
|
2020-04-21 21:19:15 +00:00
|
|
|
// Don't change these to emplace_back: some versions of wxWidgets don't support it
|
2023-02-02 19:12:02 +00:00
|
|
|
fieldsCtrlRow.push_back( wxVariant( aFieldName ) );
|
2023-02-23 19:10:50 +00:00
|
|
|
fieldsCtrlRow.push_back( wxVariant( aLabelValue ) );
|
2020-04-21 21:19:15 +00:00
|
|
|
fieldsCtrlRow.push_back( wxVariant( show ) );
|
|
|
|
fieldsCtrlRow.push_back( wxVariant( sort_by ) );
|
2023-02-23 19:10:50 +00:00
|
|
|
fieldsCtrlRow.push_back( wxVariant( aFieldName ) );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2018-05-22 11:50:57 +00:00
|
|
|
m_fieldsCtrl->AppendItem( fieldsCtrlRow );
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::LoadFieldNames()
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2018-05-19 15:47:39 +00:00
|
|
|
std::set<wxString> userFieldNames;
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
for( unsigned i = 0; i < m_symbolsList.GetCount(); ++i )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2021-06-10 14:10:55 +00:00
|
|
|
SCH_SYMBOL* symbol = m_symbolsList[ i ].GetSymbol();
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2020-11-15 16:08:31 +00:00
|
|
|
for( int j = MANDATORY_FIELDS; j < symbol->GetFieldCount(); ++j )
|
2021-02-28 13:28:23 +00:00
|
|
|
userFieldNames.insert( symbol->GetFields()[j].GetName() );
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2019-02-03 20:53:21 +00:00
|
|
|
|
2020-10-19 17:35:22 +00:00
|
|
|
AddField( _( "Reference" ), wxT( "Reference" ), true, true );
|
|
|
|
AddField( _( "Value" ), wxT( "Value" ), true, true );
|
|
|
|
AddField( _( "Footprint" ), wxT( "Footprint" ), true, true );
|
|
|
|
AddField( _( "Datasheet" ), wxT( "Datasheet" ), true, false );
|
2023-02-23 19:10:50 +00:00
|
|
|
AddField( _( "Quantity" ), wxT( "Qty" ), true, false );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2019-07-17 20:45:43 +00:00
|
|
|
for( const wxString& fieldName : userFieldNames )
|
2020-10-19 17:35:22 +00:00
|
|
|
AddField( fieldName, fieldName, true, false );
|
2018-05-19 15:47:39 +00:00
|
|
|
|
2018-07-07 02:36:31 +00:00
|
|
|
// Add any templateFieldNames which aren't already present in the userFieldNames
|
2020-08-30 17:57:10 +00:00
|
|
|
for( const TEMPLATE_FIELDNAME& templateFieldname :
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_TemplateFieldNames.GetTemplateFieldNames() )
|
2020-02-16 12:51:44 +00:00
|
|
|
{
|
2020-08-30 17:57:10 +00:00
|
|
|
if( userFieldNames.count( templateFieldname.m_Name ) == 0 )
|
2020-10-19 17:35:22 +00:00
|
|
|
AddField( templateFieldname.m_Name, templateFieldname.m_Name, false, false );
|
2020-02-16 12:51:44 +00:00
|
|
|
}
|
2023-02-06 21:05:53 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
m_dataModel->SetFieldsOrder( m_schSettings.m_BomSettings.column_order );
|
2018-04-17 10:34:48 +00:00
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnAddField( wxCommandEvent& event )
|
2018-05-23 12:12:01 +00:00
|
|
|
{
|
|
|
|
wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Add Field" ) );
|
|
|
|
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
|
|
return;
|
|
|
|
|
|
|
|
wxString fieldName = dlg.GetValue();
|
|
|
|
|
|
|
|
if( fieldName.IsEmpty() )
|
|
|
|
{
|
|
|
|
DisplayError( this, _( "Field must have a name." ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
|
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
if( fieldName == m_dataModel->GetColFieldName( i ) )
|
2018-05-23 12:12:01 +00:00
|
|
|
{
|
2021-11-04 00:02:14 +00:00
|
|
|
DisplayError( this, wxString::Format( _( "Field name '%s' already in use." ),
|
2019-06-17 19:05:11 +00:00
|
|
|
fieldName ) );
|
2018-05-23 12:12:01 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-13 01:44:19 +00:00
|
|
|
std::string key( fieldName.ToUTF8() );
|
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
m_parent->Schematic().Settings().m_BomSettings.fields_show[key] = true;
|
2022-09-12 22:38:36 +00:00
|
|
|
AddField( fieldName, fieldName, true, false, true );
|
2018-05-23 12:12:01 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_APPENDED, 1 );
|
2018-05-23 12:12:01 +00:00
|
|
|
m_grid->ProcessTableMessage( msg );
|
2019-02-03 20:53:21 +00:00
|
|
|
|
2023-02-02 19:12:02 +00:00
|
|
|
wxGridCellAttr* attr = new wxGridCellAttr;
|
2019-02-03 20:53:21 +00:00
|
|
|
m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
|
2023-02-02 19:12:02 +00:00
|
|
|
m_grid->SetColFormatCustom( m_dataModel->GetColsCount() - 1, wxGRID_VALUE_STRING );
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2018-05-23 12:12:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-12 20:13:26 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnRemoveField( wxCommandEvent& event )
|
|
|
|
{
|
2022-09-11 12:28:53 +00:00
|
|
|
int col = -1;
|
|
|
|
int row = m_fieldsCtrl->GetSelectedRow();
|
2022-04-12 20:13:26 +00:00
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
// Should never occur: "Remove Field..." button should be disabled if invalid selection
|
|
|
|
// via OnFieldsCtrlSelectionChanged()
|
2023-01-17 04:14:38 +00:00
|
|
|
wxCHECK_RET( row != -1, wxS( "Some user defined field must be selected first" ) );
|
|
|
|
wxCHECK_RET( row >= MANDATORY_FIELDS, wxS( "Mandatory fields cannot be removed" ) );
|
2022-04-12 20:13:26 +00:00
|
|
|
|
2023-02-07 15:04:44 +00:00
|
|
|
wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
|
|
|
|
wxString displayName = m_fieldsCtrl->GetTextValue( row, DISPLAY_NAME_COLUMN );
|
2022-04-12 20:13:26 +00:00
|
|
|
|
2023-02-07 15:04:44 +00:00
|
|
|
wxString confirm_msg =
|
|
|
|
wxString::Format( _( "Are you sure you want to remove the field '%s'?" ), displayName );
|
2022-11-25 15:17:20 +00:00
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
if( !IsOK( this, confirm_msg ) )
|
|
|
|
return;
|
2022-04-12 20:13:26 +00:00
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
|
2022-04-12 20:13:26 +00:00
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
if( fieldName == m_dataModel->GetColFieldName( i ) )
|
2022-09-24 01:44:15 +00:00
|
|
|
col = i;
|
2022-04-12 20:13:26 +00:00
|
|
|
}
|
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
m_fieldsCtrl->DeleteItem( row );
|
|
|
|
m_dataModel->RemoveColumn( col );
|
2022-04-12 20:13:26 +00:00
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
// Make selection and update the state of "Remove field..." button via OnFieldsCtrlSelectionChanged()
|
|
|
|
// Safe to decrement row index because we always have mandatory fields
|
|
|
|
m_fieldsCtrl->SelectRow( --row );
|
|
|
|
|
|
|
|
if( row < MANDATORY_FIELDS )
|
2023-01-27 14:18:32 +00:00
|
|
|
{
|
|
|
|
m_removeFieldButton->Enable( false );
|
|
|
|
m_renameFieldButton->Enable( false );
|
|
|
|
}
|
2022-09-11 12:28:53 +00:00
|
|
|
|
|
|
|
wxGridTableMessage msg( m_dataModel, wxGRIDTABLE_NOTIFY_COLS_DELETED,
|
2022-04-12 20:13:26 +00:00
|
|
|
m_fieldsCtrl->GetItemCount(), 1 );
|
2022-11-25 15:17:20 +00:00
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
m_grid->ProcessTableMessage( msg );
|
2022-04-12 20:13:26 +00:00
|
|
|
|
|
|
|
// set up attributes on the new quantities column
|
|
|
|
wxGridCellAttr* attr = new wxGridCellAttr;
|
|
|
|
attr->SetReadOnly();
|
|
|
|
|
|
|
|
m_grid->SetColAttr( m_dataModel->GetColsCount() - 1, attr );
|
|
|
|
m_grid->SetColFormatNumber( m_dataModel->GetColsCount() - 1 );
|
|
|
|
m_grid->SetColSize( m_dataModel->GetColsCount() - 1, 50 );
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2022-04-12 20:13:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-01-27 14:18:32 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnRenameField( wxCommandEvent& event )
|
|
|
|
{
|
|
|
|
int col = -1;
|
|
|
|
int row = m_fieldsCtrl->GetSelectedRow();
|
|
|
|
|
|
|
|
// Should never occur: "Rename Field..." button should be disabled if invalid selection
|
|
|
|
// via OnFieldsCtrlSelectionChanged()
|
|
|
|
wxCHECK_RET( row != -1, wxS( "Some user defined field must be selected first" ) );
|
|
|
|
wxCHECK_RET( row >= MANDATORY_FIELDS, wxS( "Mandatory fields cannot be renamed" ) );
|
|
|
|
|
|
|
|
wxString fieldName = m_fieldsCtrl->GetTextValue( row, 0 );
|
|
|
|
|
|
|
|
|
|
|
|
wxTextEntryDialog dlg( this, _( "New field name:" ), _( "Rename Field" ) );
|
|
|
|
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
|
|
return;
|
|
|
|
|
|
|
|
wxString newFieldName = dlg.GetValue();
|
|
|
|
|
|
|
|
if( fieldName.IsEmpty() )
|
|
|
|
{
|
|
|
|
DisplayError( this, _( "Field must have a name." ) );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( int i = 0; i < m_dataModel->GetNumberCols(); ++i )
|
|
|
|
{
|
2023-02-02 19:12:02 +00:00
|
|
|
if( fieldName == m_dataModel->GetColFieldName( i ) )
|
2023-01-27 14:18:32 +00:00
|
|
|
{
|
|
|
|
if( col == -1 )
|
|
|
|
{
|
|
|
|
col = i;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
wxString confirm_msg = wxString::Format(
|
|
|
|
_( "Field name %s already exists. Cannot rename over existing field." ),
|
|
|
|
fieldName );
|
|
|
|
DisplayError( this, confirm_msg );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_dataModel->RenameColumn( col, newFieldName );
|
|
|
|
m_fieldsCtrl->SetTextValue( newFieldName, col, 0 );
|
|
|
|
|
|
|
|
std::string oldKey( fieldName.ToUTF8() );
|
|
|
|
std::string newKey( newFieldName.ToUTF8() );
|
|
|
|
|
|
|
|
//In-place rename map key
|
2023-02-09 20:13:05 +00:00
|
|
|
auto node = m_schSettings.m_BomSettings.fields_show.extract( oldKey );
|
2023-01-27 14:18:32 +00:00
|
|
|
node.key() = newKey;
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.fields_show.insert( std::move( node ) );
|
2023-01-27 14:18:32 +00:00
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
syncBomPresetSelection();
|
2023-01-27 14:18:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-04-17 19:02:05 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterText( wxCommandEvent& aEvent )
|
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.filter_string = m_filter->GetValue();
|
2022-04-17 19:02:05 +00:00
|
|
|
m_dataModel->RebuildRows( m_filter, m_groupSymbolsBox, m_fieldsCtrl );
|
|
|
|
m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
|
|
|
|
m_grid->ForceRefresh();
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2022-04-17 19:02:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnFilterMouseMoved( wxMouseEvent& aEvent )
|
|
|
|
{
|
|
|
|
wxPoint pos = aEvent.GetPosition();
|
|
|
|
wxRect ctrlRect = m_filter->GetScreenRect();
|
|
|
|
int buttonWidth = ctrlRect.GetHeight(); // Presume buttons are square
|
|
|
|
|
|
|
|
if( m_filter->IsSearchButtonVisible() && pos.x < buttonWidth )
|
|
|
|
SetCursor( wxCURSOR_ARROW );
|
|
|
|
else if( m_filter->IsCancelButtonVisible() && pos.x > ctrlRect.GetWidth() - buttonWidth )
|
|
|
|
SetCursor( wxCURSOR_ARROW );
|
|
|
|
else
|
|
|
|
SetCursor( wxCURSOR_IBEAM );
|
|
|
|
}
|
|
|
|
|
2022-09-11 12:28:53 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnFieldsCtrlSelectionChanged( wxDataViewEvent& event )
|
|
|
|
{
|
|
|
|
int row = m_fieldsCtrl->GetSelectedRow();
|
|
|
|
|
|
|
|
if( row >= MANDATORY_FIELDS )
|
2023-01-27 14:18:32 +00:00
|
|
|
{
|
2022-09-11 12:28:53 +00:00
|
|
|
m_removeFieldButton->Enable( true );
|
2023-01-27 14:18:32 +00:00
|
|
|
m_renameFieldButton->Enable( true );
|
|
|
|
}
|
2022-09-11 12:28:53 +00:00
|
|
|
else
|
2023-01-27 14:18:32 +00:00
|
|
|
{
|
2022-09-11 12:28:53 +00:00
|
|
|
m_removeFieldButton->Enable( false );
|
2023-01-27 14:18:32 +00:00
|
|
|
m_renameFieldButton->Enable( false );
|
|
|
|
}
|
2022-09-11 12:28:53 +00:00
|
|
|
}
|
2022-04-17 19:02:05 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnColumnItemToggled( wxDataViewEvent& event )
|
2018-04-17 10:34:48 +00:00
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
wxDataViewItem item = event.GetItem();
|
|
|
|
int row = m_fieldsCtrl->ItemToRow( item );
|
|
|
|
int col = event.GetColumn();
|
2017-04-02 12:09:01 +00:00
|
|
|
|
|
|
|
switch ( col )
|
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
case SHOW_FIELD_COLUMN:
|
2018-05-19 15:47:39 +00:00
|
|
|
{
|
|
|
|
bool value = m_fieldsCtrl->GetToggleValue( row, col );
|
2019-02-03 20:53:21 +00:00
|
|
|
|
2023-02-07 15:04:44 +00:00
|
|
|
std::string fieldName( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ).ToUTF8() );
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.fields_show[fieldName] = value;
|
2018-05-19 15:47:39 +00:00
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
int dataCol = m_dataModel->GetFieldNameCol( fieldName );
|
|
|
|
|
|
|
|
if( dataCol != -1 )
|
|
|
|
{
|
|
|
|
if( value )
|
|
|
|
m_grid->ShowCol( dataCol );
|
|
|
|
else
|
|
|
|
m_grid->HideCol( dataCol );
|
|
|
|
}
|
2021-02-23 14:34:06 +00:00
|
|
|
|
2017-04-02 12:09:01 +00:00
|
|
|
break;
|
2018-05-19 15:47:39 +00:00
|
|
|
}
|
2017-11-03 08:41:48 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
case GROUP_BY_COLUMN:
|
2018-05-19 15:47:39 +00:00
|
|
|
{
|
|
|
|
bool value = m_fieldsCtrl->GetToggleValue( row, col );
|
2023-02-02 19:12:02 +00:00
|
|
|
|
|
|
|
if( m_dataModel->ColIsQuantity( row ) && value )
|
|
|
|
{
|
|
|
|
DisplayError( this, _( "The Quantity column cannot be grouped by." ) );
|
|
|
|
|
|
|
|
value = false;
|
|
|
|
m_fieldsCtrl->SetToggleValue( value, row, col );
|
|
|
|
}
|
|
|
|
|
2023-02-07 15:04:44 +00:00
|
|
|
std::string fieldName( m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN ).ToUTF8() );
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.fields_group_by[fieldName] = value;
|
2020-01-13 01:44:19 +00:00
|
|
|
|
2022-04-17 19:02:05 +00:00
|
|
|
m_dataModel->RebuildRows( m_filter, m_groupSymbolsBox, m_fieldsCtrl );
|
2018-04-17 10:34:48 +00:00
|
|
|
m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
|
2018-05-19 15:47:39 +00:00
|
|
|
m_grid->ForceRefresh();
|
2017-05-08 10:41:46 +00:00
|
|
|
break;
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
2021-02-23 14:34:06 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2018-05-19 15:47:39 +00:00
|
|
|
}
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnGroupSymbolsToggled( wxCommandEvent& event )
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.group_symbols = m_groupSymbolsBox->GetValue();
|
2022-04-17 19:02:05 +00:00
|
|
|
m_dataModel->RebuildRows( m_filter, m_groupSymbolsBox, m_fieldsCtrl );
|
2018-04-17 10:34:48 +00:00
|
|
|
m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
|
|
|
|
m_grid->ForceRefresh();
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2017-04-18 09:25:02 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnColSort( wxGridEvent& aEvent )
|
2017-04-18 09:25:02 +00:00
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
int sortCol = aEvent.GetCol();
|
|
|
|
std::string key( m_dataModel->GetColFieldName( sortCol ).ToUTF8() );
|
|
|
|
bool ascending;
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2020-12-12 14:59:48 +00:00
|
|
|
// This is bonkers, but wxWidgets doesn't tell us ascending/descending in the event, and
|
|
|
|
// if we ask it will give us pre-event info.
|
2018-04-17 10:34:48 +00:00
|
|
|
if( m_grid->IsSortingBy( sortCol ) )
|
2020-12-12 14:59:48 +00:00
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
// same column; invert ascending
|
|
|
|
ascending = !m_grid->IsSortOrderAscending();
|
2020-12-12 14:59:48 +00:00
|
|
|
}
|
2018-04-17 10:34:48 +00:00
|
|
|
else
|
2020-12-12 14:59:48 +00:00
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
// different column; start with ascending
|
|
|
|
ascending = true;
|
2020-12-12 14:59:48 +00:00
|
|
|
}
|
2017-04-02 12:09:01 +00:00
|
|
|
|
2023-01-30 17:16:33 +00:00
|
|
|
// We only support sorting on one column at this time
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.column_sorts.clear();
|
|
|
|
m_schSettings.m_BomSettings.column_sorts[key] = ascending;
|
2023-01-30 17:16:33 +00:00
|
|
|
|
2018-04-17 10:34:48 +00:00
|
|
|
m_dataModel->Sort( sortCol, ascending );
|
2019-11-13 07:33:29 +00:00
|
|
|
m_grid->ForceRefresh();
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2023-01-30 17:16:33 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnColMove( wxGridEvent& aEvent )
|
|
|
|
{
|
2023-02-06 21:05:53 +00:00
|
|
|
int origPos = aEvent.GetCol();
|
|
|
|
|
2023-01-30 17:16:33 +00:00
|
|
|
CallAfter(
|
2023-02-06 21:05:53 +00:00
|
|
|
[origPos, this]()
|
2023-01-30 17:16:33 +00:00
|
|
|
{
|
2023-02-06 21:05:53 +00:00
|
|
|
int newPos = m_grid->GetColPos( origPos );
|
|
|
|
|
|
|
|
m_dataModel->MoveColumn( origPos, newPos );
|
|
|
|
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.column_order = m_dataModel->GetFieldsOrder();
|
2023-02-06 21:05:53 +00:00
|
|
|
|
|
|
|
// "Unmove" the column since we've moved the column internally
|
|
|
|
m_grid->ResetColPos();
|
|
|
|
|
|
|
|
// We need to reset all the column attr's to the correct column order
|
|
|
|
SetupColumnProperties();
|
2023-01-30 17:16:33 +00:00
|
|
|
|
2023-02-06 21:05:53 +00:00
|
|
|
m_grid->ForceRefresh();
|
2023-01-30 17:16:33 +00:00
|
|
|
} );
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
syncBomPresetSelection();
|
2023-01-30 17:16:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-02-23 19:10:50 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnColLabelChange( wxDataViewEvent& aEvent )
|
|
|
|
{
|
|
|
|
wxDataViewItem item = aEvent.GetItem();
|
|
|
|
int row = m_fieldsCtrl->ItemToRow( item );
|
|
|
|
wxString label = m_fieldsCtrl->GetTextValue( row, LABEL_COLUMN );
|
|
|
|
wxString fieldName = m_fieldsCtrl->GetTextValue( row, FIELD_NAME_COLUMN );
|
|
|
|
int col = m_dataModel->GetFieldNameCol( fieldName );
|
|
|
|
|
|
|
|
if( col != -1 )
|
|
|
|
m_dataModel->SetColLabelValue( col, label );
|
|
|
|
|
|
|
|
syncBomPresetSelection();
|
|
|
|
|
|
|
|
aEvent.Skip();
|
|
|
|
|
|
|
|
m_grid->ForceRefresh();
|
|
|
|
}
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnTableValueChanged( wxGridEvent& aEvent )
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2018-04-17 10:34:48 +00:00
|
|
|
m_grid->ForceRefresh();
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-06-07 16:43:28 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnTableColSize( wxGridSizeEvent& aEvent )
|
2020-04-21 15:15:04 +00:00
|
|
|
{
|
2023-02-09 20:13:05 +00:00
|
|
|
int col = aEvent.GetRowOrCol();
|
|
|
|
std::string key( m_dataModel->GetColFieldName( col ).ToUTF8() );
|
2020-04-21 15:15:04 +00:00
|
|
|
|
|
|
|
if( m_grid->GetColSize( col ) )
|
2023-02-09 20:13:05 +00:00
|
|
|
m_schSettings.m_BomSettings.column_widths[key] = m_grid->GetColSize( col );
|
2020-04-21 15:15:04 +00:00
|
|
|
|
|
|
|
aEvent.Skip();
|
2023-02-23 19:10:50 +00:00
|
|
|
|
|
|
|
m_grid->ForceRefresh();
|
2020-04-21 15:15:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnRegroupSymbols( wxCommandEvent& aEvent )
|
2017-04-02 12:09:01 +00:00
|
|
|
{
|
2022-04-17 19:02:05 +00:00
|
|
|
m_dataModel->RebuildRows( m_filter, m_groupSymbolsBox, m_fieldsCtrl );
|
2018-04-17 10:34:48 +00:00
|
|
|
m_dataModel->Sort( m_grid->GetSortingColumn(), m_grid->IsSortOrderAscending() );
|
|
|
|
m_grid->ForceRefresh();
|
2017-04-02 12:09:01 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 08:41:48 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnTableCellClick( wxGridEvent& event )
|
2018-05-12 22:04:11 +00:00
|
|
|
{
|
2023-02-06 21:05:53 +00:00
|
|
|
if( m_dataModel->ColIsReference( event.GetCol() ) )
|
2018-05-19 15:25:28 +00:00
|
|
|
{
|
2019-01-16 13:16:23 +00:00
|
|
|
m_grid->ClearSelection();
|
|
|
|
m_grid->SetGridCursor( event.GetRow(), event.GetCol() );
|
|
|
|
|
2018-05-19 15:25:28 +00:00
|
|
|
m_dataModel->ExpandCollapseRow( event.GetRow() );
|
|
|
|
}
|
2018-05-12 22:04:11 +00:00
|
|
|
else
|
2018-05-19 15:25:28 +00:00
|
|
|
{
|
2018-05-12 22:04:11 +00:00
|
|
|
event.Skip();
|
2018-05-19 15:25:28 +00:00
|
|
|
}
|
2018-05-12 22:04:11 +00:00
|
|
|
}
|
|
|
|
|
2023-01-29 11:51:21 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnTableRangeSelected( wxGridRangeSelectEvent& event )
|
|
|
|
{
|
|
|
|
wxGridCellCoordsArray selectedCells = m_grid->GetSelectedCells();
|
|
|
|
|
2023-01-30 14:29:47 +00:00
|
|
|
if( selectedCells.GetCount() == 1 )
|
|
|
|
{
|
2023-01-29 11:51:21 +00:00
|
|
|
int row = selectedCells[0].GetRow();
|
2023-01-30 14:40:48 +00:00
|
|
|
int flag = m_dataModel->GetRowFlags( row );
|
|
|
|
std::vector<SCH_REFERENCE> refs = m_dataModel->GetRowReferences( row );
|
2023-01-29 11:51:21 +00:00
|
|
|
|
2023-01-30 14:40:48 +00:00
|
|
|
// Focus Eeschema view on the symbol selected in the dialog
|
|
|
|
// TODO: Highlight or select more than one unit
|
|
|
|
if( ( flag == GROUP_SINGLETON || flag == CHILD_ITEM ) && refs.size() >= 1 )
|
2023-01-29 11:51:21 +00:00
|
|
|
{
|
2023-01-30 14:40:48 +00:00
|
|
|
SCH_EDITOR_CONTROL* editor = m_parent->GetToolManager()->GetTool<SCH_EDITOR_CONTROL>();
|
2023-01-29 11:51:21 +00:00
|
|
|
|
2023-01-30 14:40:48 +00:00
|
|
|
std::sort( refs.begin(), refs.end(),
|
|
|
|
[]( const SCH_REFERENCE& a, const SCH_REFERENCE& b )
|
|
|
|
{
|
|
|
|
return a.GetUnit() < b.GetUnit();
|
|
|
|
} );
|
2023-01-29 11:51:21 +00:00
|
|
|
|
2023-01-30 14:40:48 +00:00
|
|
|
// search and highlight the symbol found by its full path.
|
|
|
|
// It allows select of not yet annotated or duplicaded symbols
|
|
|
|
wxString symbol_path = refs[0].GetFullPath();
|
|
|
|
// wxString reference = refs[0].GetRef() + refs[0].GetRefNumber(); // Not used
|
|
|
|
editor->FindSymbolAndItem( &symbol_path, nullptr, true, HIGHLIGHT_SYMBOL, wxEmptyString );
|
2023-01-29 11:51:21 +00:00
|
|
|
}
|
2023-01-30 14:40:48 +00:00
|
|
|
|
|
|
|
return;
|
2023-01-29 11:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
event.Skip();
|
|
|
|
}
|
2018-05-12 22:04:11 +00:00
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnTableItemContextMenu( wxGridEvent& event )
|
2017-04-25 02:55:49 +00:00
|
|
|
{
|
2019-06-17 19:02:48 +00:00
|
|
|
// TODO: Option to select footprint if FOOTPRINT column selected
|
2017-04-25 02:55:49 +00:00
|
|
|
|
|
|
|
event.Skip();
|
|
|
|
}
|
2017-06-07 16:43:28 +00:00
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnSizeFieldList( wxSizeEvent& event )
|
2017-04-25 02:55:49 +00:00
|
|
|
{
|
2023-02-23 19:10:50 +00:00
|
|
|
m_labelColWidth = KIPLATFORM::UI::GetUnobscuredSize( m_fieldsCtrl ).x;
|
|
|
|
m_labelColWidth -= m_fieldNameColWidth + m_showColWidth + m_groupByColWidth;
|
2022-07-08 17:16:14 +00:00
|
|
|
#ifdef __WXMAC__
|
2022-11-14 18:46:39 +00:00
|
|
|
// TODO: something in wxWidgets 3.1.x pads checkbox columns with extra space. (It used to
|
|
|
|
// also be that the width of the column would get set too wide (to 30), but that's patched in
|
|
|
|
// our local wxWidgets fork.)
|
2023-02-23 19:10:50 +00:00
|
|
|
m_labelColWidth -= 30;
|
2022-07-08 17:16:14 +00:00
|
|
|
#endif
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2018-05-04 14:43:59 +00:00
|
|
|
// GTK loses its head and messes these up when resizing the splitter bar:
|
2020-10-28 10:22:52 +00:00
|
|
|
m_fieldsCtrl->GetColumn( SHOW_FIELD_COLUMN )->SetWidth( m_showColWidth );
|
|
|
|
m_fieldsCtrl->GetColumn( GROUP_BY_COLUMN )->SetWidth( m_groupByColWidth );
|
2018-04-17 10:34:48 +00:00
|
|
|
|
2023-02-07 15:04:44 +00:00
|
|
|
m_fieldsCtrl->GetColumn( FIELD_NAME_COLUMN )->SetHidden( true );
|
2023-02-23 19:10:50 +00:00
|
|
|
m_fieldsCtrl->GetColumn( DISPLAY_NAME_COLUMN )->SetWidth( m_fieldNameColWidth );
|
|
|
|
m_fieldsCtrl->GetColumn( LABEL_COLUMN )->SetWidth( m_labelColWidth );
|
2017-04-25 02:55:49 +00:00
|
|
|
|
2021-12-15 04:35:44 +00:00
|
|
|
m_fieldsCtrl->Refresh(); // To refresh checkboxes on Windows.
|
|
|
|
|
2017-04-25 02:55:49 +00:00
|
|
|
event.Skip();
|
|
|
|
}
|
2018-04-19 22:13:19 +00:00
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnSaveAndContinue( wxCommandEvent& aEvent )
|
2018-04-19 22:13:19 +00:00
|
|
|
{
|
|
|
|
if( TransferDataFromWindow() )
|
2018-08-01 23:06:12 +00:00
|
|
|
m_parent->SaveProject();
|
2018-04-19 22:13:19 +00:00
|
|
|
}
|
2018-06-05 19:59:58 +00:00
|
|
|
|
|
|
|
|
2022-05-09 13:41:00 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnExport( wxCommandEvent& aEvent )
|
|
|
|
{
|
2022-07-07 18:22:30 +00:00
|
|
|
int last_col = m_grid->GetNumberCols() - 1;
|
|
|
|
|
2022-05-09 13:41:00 +00:00
|
|
|
if( m_dataModel->IsEdited() )
|
|
|
|
if( OKOrCancelDialog( nullptr, _( "Unsaved data" ),
|
|
|
|
_( "Changes are unsaved. Export unsaved data?" ), "", _( "OK" ),
|
|
|
|
_( "Cancel" ) )
|
|
|
|
== wxID_CANCEL )
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate the netlist filename
|
|
|
|
wxFileName fn = m_parent->Schematic().GetFileName();
|
|
|
|
fn.SetExt( CsvFileExtension );
|
|
|
|
|
|
|
|
wxFileDialog saveDlg( this, _( "Save as CSV" ), wxPathOnly( Prj().GetProjectFullName() ),
|
|
|
|
fn.GetFullName(), CsvFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
|
|
|
|
|
|
|
|
if( saveDlg.ShowModal() == wxID_CANCEL )
|
|
|
|
return;
|
|
|
|
|
|
|
|
wxFFile out( saveDlg.GetPath(), "wb" );
|
|
|
|
|
|
|
|
if( !out.IsOpened() )
|
|
|
|
return;
|
|
|
|
|
2022-07-07 18:22:30 +00:00
|
|
|
// Find the location for the line terminator
|
2022-07-08 07:48:34 +00:00
|
|
|
for( int col = m_grid->GetNumberCols() - 1; col >=0 ; --col )
|
2022-07-07 18:22:30 +00:00
|
|
|
{
|
|
|
|
if( m_grid->IsColShown( col ) )
|
|
|
|
{
|
|
|
|
last_col = col;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-09 13:41:00 +00:00
|
|
|
// Column names
|
|
|
|
for( int col = 0; col < m_grid->GetNumberCols(); col++ )
|
|
|
|
{
|
|
|
|
if( !m_grid->IsColShown( col ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
wxString escapedValue = m_grid->GetColLabelValue( col );
|
2023-01-17 04:14:38 +00:00
|
|
|
escapedValue.Replace( wxS( "\"" ), wxS( "\"\"" ) );
|
2022-05-09 13:41:00 +00:00
|
|
|
|
2023-01-17 04:14:38 +00:00
|
|
|
wxString format = col == last_col ? wxS( "\"%s\"\r\n" ) : wxS( "\"%s\"," );
|
2022-05-09 13:41:00 +00:00
|
|
|
|
|
|
|
out.Write( wxString::Format( format, escapedValue ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Data rows
|
|
|
|
for( int row = 0; row < m_grid->GetNumberRows(); row++ )
|
|
|
|
{
|
|
|
|
// Don't output child rows
|
|
|
|
if( m_dataModel->GetRowFlags( row ) == CHILD_ITEM )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for( int col = 0; col < m_grid->GetNumberCols(); col++ )
|
|
|
|
{
|
|
|
|
if( !m_grid->IsColShown( col ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Get the unanottated version of the field, e.g. no "> " or "v " by
|
|
|
|
wxString escapedValue = m_dataModel->GetRawValue( row, col );
|
2023-01-17 04:14:38 +00:00
|
|
|
escapedValue.Replace( wxS( "\"" ), wxS( "\"\"" ) );
|
2022-05-09 13:41:00 +00:00
|
|
|
|
2023-01-17 04:14:38 +00:00
|
|
|
wxString format = col == last_col ? wxS( "\"%s\"\r\n" ) : wxS( "\"%s\"," );
|
2022-05-09 13:41:00 +00:00
|
|
|
|
|
|
|
out.Write( wxString::Format( format, escapedValue ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnCancel( wxCommandEvent& event )
|
2018-06-05 19:59:58 +00:00
|
|
|
{
|
|
|
|
Close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-07-03 20:43:30 +00:00
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::OnClose( wxCloseEvent& event )
|
2018-06-05 19:59:58 +00:00
|
|
|
{
|
2018-08-19 16:10:14 +00:00
|
|
|
// This is a cancel, so commit quietly as we're going to throw the results away anyway.
|
|
|
|
m_grid->CommitPendingChanges( true );
|
2018-06-05 19:59:58 +00:00
|
|
|
|
|
|
|
if( m_dataModel->IsEdited() )
|
|
|
|
{
|
2020-08-10 20:48:26 +00:00
|
|
|
if( !HandleUnsavedChanges( this, _( "Save changes?" ),
|
2021-10-01 20:49:14 +00:00
|
|
|
[&]() -> bool
|
2020-12-12 14:59:48 +00:00
|
|
|
{
|
|
|
|
return TransferDataFromWindow();
|
|
|
|
} ) )
|
2018-06-05 19:59:58 +00:00
|
|
|
{
|
|
|
|
event.Veto();
|
2018-08-11 20:46:03 +00:00
|
|
|
return;
|
2018-06-05 19:59:58 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-11 20:46:03 +00:00
|
|
|
|
|
|
|
event.Skip();
|
2018-06-05 19:59:58 +00:00
|
|
|
}
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
|
|
|
|
std::vector<BOM_PRESET> DIALOG_SYMBOL_FIELDS_TABLE::GetUserBomPresets() const
|
|
|
|
{
|
|
|
|
std::vector<BOM_PRESET> ret;
|
|
|
|
|
|
|
|
for( const std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
|
|
|
|
{
|
|
|
|
if( !pair.second.readOnly )
|
|
|
|
ret.emplace_back( pair.second );
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::SetUserBomPresets( std::vector<BOM_PRESET>& aPresetList )
|
|
|
|
{
|
|
|
|
// Reset to defaults
|
|
|
|
loadDefaultBomPresets();
|
|
|
|
|
|
|
|
for( const BOM_PRESET& preset : aPresetList )
|
|
|
|
{
|
|
|
|
if( m_bomPresets.count( preset.name ) )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
m_bomPresets[preset.name] = preset;
|
|
|
|
|
|
|
|
m_bomPresetMRU.Add( preset.name );
|
|
|
|
}
|
|
|
|
|
|
|
|
rebuildBomPresetsWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::ApplyBomPreset( const wxString& aPresetName )
|
|
|
|
{
|
|
|
|
updateBomPresetSelection( aPresetName );
|
|
|
|
|
|
|
|
wxCommandEvent dummy;
|
|
|
|
onBomPresetChanged( dummy );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::ApplyBomPreset( const BOM_PRESET& aPreset )
|
|
|
|
{
|
|
|
|
if( m_bomPresets.count( aPreset.name ) )
|
|
|
|
m_currentBomPreset = &m_bomPresets[aPreset.name];
|
|
|
|
else
|
|
|
|
m_currentBomPreset = nullptr;
|
|
|
|
|
|
|
|
m_lastSelectedBomPreset =
|
|
|
|
( m_currentBomPreset && !m_currentBomPreset->readOnly ) ? m_currentBomPreset : nullptr;
|
|
|
|
|
|
|
|
updateBomPresetSelection( aPreset.name );
|
|
|
|
doApplyBomPreset( aPreset );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::loadDefaultBomPresets()
|
|
|
|
{
|
|
|
|
m_bomPresets.clear();
|
|
|
|
m_bomPresetMRU.clear();
|
|
|
|
|
|
|
|
// Load the read-only defaults
|
|
|
|
for( const BOM_PRESET& preset : { bomPresetGroupedByValue, bomPresetGroupedByValueFootprint } )
|
|
|
|
{
|
|
|
|
m_bomPresets[preset.name] = preset;
|
|
|
|
m_bomPresets[preset.name].readOnly = true;
|
|
|
|
|
|
|
|
m_bomPresetMRU.Add( preset.name );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::rebuildBomPresetsWidget()
|
|
|
|
{
|
|
|
|
m_bomPresetsLabel->SetLabel(
|
|
|
|
wxString::Format( _( "Presets (%s+Tab):" ), KeyNameFromKeyCode( PRESET_SWITCH_KEY ) ) );
|
|
|
|
m_cbBomPresets->Clear();
|
|
|
|
|
|
|
|
// Build the layers preset list.
|
|
|
|
// By default, the presetAllLayers will be selected
|
|
|
|
int idx = 0;
|
|
|
|
int default_idx = 0;
|
|
|
|
|
|
|
|
for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
|
|
|
|
{
|
|
|
|
m_cbBomPresets->Append( wxGetTranslation( pair.first ),
|
|
|
|
static_cast<void*>( &pair.second ) );
|
|
|
|
|
|
|
|
if( pair.first == bomPresetGroupedByValueFootprint.name )
|
|
|
|
default_idx = idx;
|
|
|
|
|
|
|
|
idx++;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cbBomPresets->Append( wxT( "---" ) );
|
|
|
|
m_cbBomPresets->Append( _( "Save preset..." ) );
|
|
|
|
m_cbBomPresets->Append( _( "Delete preset..." ) );
|
|
|
|
|
|
|
|
// At least the built-in presets should always be present
|
|
|
|
wxASSERT( !m_bomPresets.empty() );
|
|
|
|
|
|
|
|
// Default preset: all Boms
|
|
|
|
m_cbBomPresets->SetSelection( default_idx );
|
|
|
|
m_currentBomPreset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( default_idx ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::syncBomPresetSelection()
|
|
|
|
{
|
|
|
|
BOM_PRESET& current = m_parent->Schematic().Settings().m_BomSettings;
|
|
|
|
|
|
|
|
auto it = std::find_if( m_bomPresets.begin(), m_bomPresets.end(),
|
|
|
|
[&]( const std::pair<const wxString, BOM_PRESET>& aPair )
|
|
|
|
{
|
|
|
|
return ( aPair.second.fields_show == current.fields_show
|
|
|
|
&& aPair.second.fields_group_by == current.fields_group_by
|
|
|
|
&& aPair.second.column_sorts == current.column_sorts
|
|
|
|
&& aPair.second.column_order == current.column_order
|
|
|
|
&& aPair.second.filter_string == current.filter_string
|
|
|
|
&& aPair.second.group_symbols == current.group_symbols );
|
|
|
|
} );
|
|
|
|
|
|
|
|
if( it != m_bomPresets.end() )
|
|
|
|
{
|
|
|
|
// Select the right m_cbBomPresets item.
|
|
|
|
// but these items are translated if they are predefined items.
|
|
|
|
bool do_translate = it->second.readOnly;
|
|
|
|
wxString text = do_translate ? wxGetTranslation( it->first ) : it->first;
|
|
|
|
|
|
|
|
m_cbBomPresets->SetStringSelection( text );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 ); // separator
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentBomPreset = static_cast<BOM_PRESET*>(
|
|
|
|
m_cbBomPresets->GetClientData( m_cbBomPresets->GetSelection() ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::updateBomPresetSelection( const wxString& aName )
|
|
|
|
{
|
|
|
|
// look at m_userBomPresets to know if aName is a read only preset, or a user preset.
|
|
|
|
// Read only presets have translated names in UI, so we have to use
|
|
|
|
// a translated name in UI selection.
|
|
|
|
// But for a user preset name we should search for aName (not translated)
|
|
|
|
wxString ui_label = aName;
|
|
|
|
|
|
|
|
for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
|
|
|
|
{
|
|
|
|
if( pair.first != aName )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if( pair.second.readOnly == true )
|
|
|
|
ui_label = wxGetTranslation( aName );
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int idx = m_cbBomPresets->FindString( ui_label );
|
|
|
|
|
|
|
|
if( idx >= 0 && m_cbBomPresets->GetSelection() != idx )
|
|
|
|
{
|
|
|
|
m_cbBomPresets->SetSelection( idx );
|
|
|
|
m_currentBomPreset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( idx ) );
|
|
|
|
}
|
|
|
|
else if( idx < 0 )
|
|
|
|
{
|
|
|
|
m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 ); // separator
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::onBomPresetChanged( wxCommandEvent& aEvent )
|
|
|
|
{
|
|
|
|
int count = m_cbBomPresets->GetCount();
|
|
|
|
int index = m_cbBomPresets->GetSelection();
|
|
|
|
|
|
|
|
auto resetSelection =
|
|
|
|
[&]()
|
|
|
|
{
|
|
|
|
if( m_currentBomPreset )
|
|
|
|
m_cbBomPresets->SetStringSelection( m_currentBomPreset->name );
|
|
|
|
else
|
|
|
|
m_cbBomPresets->SetSelection( m_cbBomPresets->GetCount() - 3 );
|
|
|
|
};
|
|
|
|
|
|
|
|
if( index == count - 3 )
|
|
|
|
{
|
|
|
|
// Separator: reject the selection
|
|
|
|
resetSelection();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if( index == count - 2 )
|
|
|
|
{
|
|
|
|
// Save current state to new preset
|
|
|
|
wxString name;
|
|
|
|
|
|
|
|
if( m_lastSelectedBomPreset )
|
|
|
|
name = m_lastSelectedBomPreset->name;
|
|
|
|
|
|
|
|
wxTextEntryDialog dlg( this, _( "BOM preset name:" ), _( "Save BOM Preset" ), name );
|
|
|
|
|
|
|
|
if( dlg.ShowModal() != wxID_OK )
|
|
|
|
{
|
|
|
|
resetSelection();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
name = dlg.GetValue();
|
|
|
|
bool exists = m_bomPresets.count( name );
|
|
|
|
|
|
|
|
if( !exists )
|
|
|
|
{
|
|
|
|
m_bomPresets[name] = BOM_PRESET( name, m_schSettings.m_BomSettings.fields_show,
|
|
|
|
m_schSettings.m_BomSettings.fields_group_by,
|
|
|
|
m_schSettings.m_BomSettings.column_widths,
|
|
|
|
m_schSettings.m_BomSettings.column_sorts,
|
|
|
|
m_schSettings.m_BomSettings.column_order,
|
|
|
|
m_schSettings.m_BomSettings.filter_string,
|
|
|
|
m_schSettings.m_BomSettings.group_symbols );
|
|
|
|
}
|
|
|
|
|
|
|
|
BOM_PRESET* preset = &m_bomPresets[name];
|
|
|
|
m_currentBomPreset = preset;
|
|
|
|
|
|
|
|
if( !exists )
|
|
|
|
{
|
|
|
|
index = m_cbBomPresets->Insert( name, index - 1, static_cast<void*>( preset ) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
preset->fields_show = m_schSettings.m_BomSettings.fields_show;
|
|
|
|
preset->fields_group_by = m_schSettings.m_BomSettings.fields_group_by;
|
|
|
|
preset->column_widths = m_schSettings.m_BomSettings.column_widths;
|
|
|
|
preset->column_sorts = m_schSettings.m_BomSettings.column_sorts;
|
|
|
|
preset->column_order = m_schSettings.m_BomSettings.column_order;
|
|
|
|
preset->filter_string = m_schSettings.m_BomSettings.filter_string;
|
|
|
|
preset->group_symbols = m_schSettings.m_BomSettings.group_symbols;
|
|
|
|
|
|
|
|
index = m_cbBomPresets->FindString( name );
|
|
|
|
m_bomPresetMRU.Remove( name );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cbBomPresets->SetSelection( index );
|
|
|
|
m_bomPresetMRU.Insert( name, 0 );
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if( index == count - 1 )
|
|
|
|
{
|
|
|
|
// Delete a preset
|
|
|
|
wxArrayString headers;
|
|
|
|
std::vector<wxArrayString> items;
|
|
|
|
|
|
|
|
headers.Add( _( "Presets" ) );
|
|
|
|
|
|
|
|
for( std::pair<const wxString, BOM_PRESET>& pair : m_bomPresets )
|
|
|
|
{
|
|
|
|
if( !pair.second.readOnly )
|
|
|
|
{
|
|
|
|
wxArrayString item;
|
|
|
|
item.Add( pair.first );
|
|
|
|
items.emplace_back( item );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EDA_LIST_DIALOG dlg( this, _( "Delete Preset" ), headers, items );
|
|
|
|
dlg.SetListLabel( _( "Select preset:" ) );
|
|
|
|
|
|
|
|
if( dlg.ShowModal() == wxID_OK )
|
|
|
|
{
|
|
|
|
wxString presetName = dlg.GetTextSelection();
|
|
|
|
int idx = m_cbBomPresets->FindString( presetName );
|
|
|
|
|
|
|
|
if( idx != wxNOT_FOUND )
|
|
|
|
{
|
|
|
|
m_bomPresets.erase( presetName );
|
|
|
|
|
|
|
|
m_cbBomPresets->Delete( idx );
|
|
|
|
m_currentBomPreset = nullptr;
|
|
|
|
|
|
|
|
m_bomPresetMRU.Remove( presetName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resetSelection();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOM_PRESET* preset = static_cast<BOM_PRESET*>( m_cbBomPresets->GetClientData( index ) );
|
|
|
|
m_currentBomPreset = preset;
|
|
|
|
|
|
|
|
m_lastSelectedBomPreset = ( !preset || preset->readOnly ) ? nullptr : preset;
|
|
|
|
|
|
|
|
if( preset )
|
|
|
|
{
|
|
|
|
doApplyBomPreset( *preset );
|
|
|
|
syncBomPresetSelection();
|
|
|
|
m_currentBomPreset = preset;
|
|
|
|
|
|
|
|
if( !m_currentBomPreset->name.IsEmpty() )
|
|
|
|
{
|
|
|
|
m_bomPresetMRU.Remove( preset->name );
|
|
|
|
m_bomPresetMRU.Insert( preset->name, 0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void DIALOG_SYMBOL_FIELDS_TABLE::doApplyBomPreset( const BOM_PRESET& aPreset )
|
|
|
|
{
|
|
|
|
// Set a good default sort
|
|
|
|
m_dataModel->Sort( m_dataModel->GetFieldNameCol( _( "Reference" ) ), false );
|
|
|
|
|
|
|
|
for( int i = 0; i < m_fieldsCtrl->GetItemCount(); i++ )
|
|
|
|
{
|
|
|
|
const std::string fieldName( m_fieldsCtrl->GetTextValue( i, FIELD_NAME_COLUMN ).ToUTF8() );
|
|
|
|
int col = m_dataModel->GetFieldNameCol( fieldName );
|
|
|
|
|
|
|
|
if( col == -1 )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
bool show = aPreset.fields_show.count( fieldName ) && aPreset.fields_show.at( fieldName );
|
|
|
|
bool groupBy = aPreset.fields_group_by.count( fieldName )
|
|
|
|
&& aPreset.fields_group_by.at( fieldName );
|
|
|
|
int width = aPreset.column_widths.count( fieldName ) ? aPreset.column_widths.at( fieldName )
|
|
|
|
: -1;
|
|
|
|
|
|
|
|
m_fieldsCtrl->SetToggleValue( show, i, SHOW_FIELD_COLUMN );
|
|
|
|
|
|
|
|
if( show )
|
|
|
|
m_grid->ShowCol( col );
|
|
|
|
else
|
|
|
|
m_grid->HideCol( col );
|
|
|
|
|
|
|
|
m_fieldsCtrl->SetToggleValue( groupBy, i, GROUP_BY_COLUMN );
|
|
|
|
|
|
|
|
if( aPreset.column_sorts.count( fieldName ) )
|
2023-02-23 19:10:50 +00:00
|
|
|
m_dataModel->Sort( col, false );
|
2023-02-09 20:13:05 +00:00
|
|
|
|
|
|
|
if( width != -1 )
|
|
|
|
m_grid->SetColSize( col, width );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_dataModel->SetFieldsOrder( aPreset.column_order );
|
|
|
|
SetupColumnProperties();
|
|
|
|
|
|
|
|
m_filter->ChangeValue( aPreset.filter_string );
|
|
|
|
m_groupSymbolsBox->SetValue( aPreset.group_symbols );
|
|
|
|
|
|
|
|
m_schSettings.m_BomSettings.fields_show = aPreset.fields_show;
|
|
|
|
m_schSettings.m_BomSettings.fields_group_by = aPreset.fields_group_by;
|
|
|
|
m_schSettings.m_BomSettings.column_widths = aPreset.column_widths;
|
|
|
|
m_schSettings.m_BomSettings.column_sorts = aPreset.column_sorts;
|
|
|
|
m_schSettings.m_BomSettings.column_order = aPreset.column_order;
|
|
|
|
m_schSettings.m_BomSettings.filter_string = aPreset.filter_string;
|
|
|
|
m_schSettings.m_BomSettings.group_symbols = aPreset.group_symbols;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool DIALOG_SYMBOL_FIELDS_TABLE::TryBefore( wxEvent& aEvent )
|
|
|
|
{
|
|
|
|
static bool s_presetSwitcherShown = false;
|
|
|
|
|
|
|
|
// wxWidgets generates no key events for the tab key when the ctrl key is held down. One
|
|
|
|
// way around this is to look at all events and inspect the keyboard state of the tab key.
|
|
|
|
// However, this runs into issues on some linux VMs where querying the keyboard state is
|
|
|
|
// very slow. Fortunately we only use ctrl-tab on Mac, so we implement this lovely hack:
|
|
|
|
#ifdef __WXMAC__
|
|
|
|
if( wxGetKeyState( WXK_TAB ) )
|
|
|
|
#else
|
|
|
|
if( ( aEvent.GetEventType() == wxEVT_CHAR || aEvent.GetEventType() == wxEVT_CHAR_HOOK )
|
|
|
|
&& static_cast<wxKeyEvent&>( aEvent ).GetKeyCode() == WXK_TAB )
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
if( !s_presetSwitcherShown && wxGetKeyState( PRESET_SWITCH_KEY ) )
|
|
|
|
{
|
|
|
|
if( this->IsActive() )
|
|
|
|
{
|
|
|
|
if( m_bomPresetMRU.size() > 0 )
|
|
|
|
{
|
|
|
|
EDA_VIEW_SWITCHER switcher( this, m_bomPresetMRU, PRESET_SWITCH_KEY );
|
|
|
|
|
|
|
|
s_presetSwitcherShown = true;
|
|
|
|
switcher.ShowModal();
|
|
|
|
s_presetSwitcherShown = false;
|
|
|
|
|
|
|
|
int idx = switcher.GetSelection();
|
|
|
|
|
|
|
|
if( idx >= 0 && idx < (int) m_bomPresetMRU.size() )
|
|
|
|
ApplyBomPreset( m_bomPresetMRU[idx] );
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DIALOG_SYMBOL_FIELDS_TABLE_BASE::TryBefore( aEvent );
|
|
|
|
}
|