22#include <wx/settings.h> 
   39                                                   bool aAddedByUser, 
bool aIsCheckbox )
 
   45    m_cols.push_back( { aFieldName, aLabel, aAddedByUser, 
false, 
false, aIsCheckbox } );
 
 
   53                                                                    const wxString&   aFieldName )
 
   74    else if( aFieldName == wxS( 
"Keywords" ) )
 
 
  103    const wxString fieldName = 
m_cols[aCol].m_fieldName;
 
  107        std::map<wxString, LIB_DATA_ELEMENT>& fieldStore = 
m_dataStore[symbol->m_Uuid];
 
  108        auto it = fieldStore.find( fieldName );
 
  110        if( it != fieldStore.end() )
 
  112            it->second.m_currentData = wxEmptyString;
 
  113            it->second.m_currentlyEmpty = 
true;
 
  114            it->second.m_isModified = 
true;
 
  115            fieldStore.erase( it );
 
 
  129        if( 
auto node = 
m_dataStore[symbol->m_Uuid].extract( 
m_cols[aCol].m_fieldName ) )
 
  131            node.key() = newName;
 
  132            node.mapped().m_isModified = 
true;
 
  133            m_dataStore[symbol->m_Uuid].insert( std::move( node ) );
 
  137    m_cols[aCol].m_fieldName = newName;
 
  138    m_cols[aCol].m_label = newName;
 
 
  145    for( 
size_t i = 0; i < 
m_cols.size(); i++ )
 
  147        if( 
m_cols[i].m_fieldName == aFieldName )
 
 
  157    size_t foundCount = 0;
 
  159    if( aNewOrder.size() > 
m_cols.size() )
 
  160        wxLogDebug( 
"New order contains more fields than existing columns." );
 
  162    for( 
const wxString& newField : aNewOrder )
 
  165        for( 
size_t i = 0; i < 
m_cols.size() && foundCount < 
m_cols.size(); i++ )
 
  167            if( 
m_cols[i].m_fieldName == newField )
 
  177            wxLogDebug( 
"Field '%s' not found in existing columns.", newField );
 
  180    if( foundCount != 
m_cols.size() && foundCount != aNewOrder.size() )
 
  182        wxLogDebug( 
"Not all fields in the new order were found in the existing columns." );
 
 
  190    for( 
int col = 0; col < aCol; ++col )
 
 
  209    std::set<wxString> mixedValues;
 
  212    wxCHECK( aCol >= 0 && aCol < (
int) 
m_cols.size(), fieldValue );
 
  225        if( listMixedValues )
 
  226            mixedValues.insert( refFieldValue );
 
  227        else if( ref == 
group.m_Refs.front() )
 
  228            fieldValue = refFieldValue;
 
  229        else if( fieldValue != refFieldValue )
 
  233    if( listMixedValues )
 
  235        fieldValue = wxEmptyString;
 
  237        for( 
const wxString& value : mixedValues )
 
  239            if( value.IsEmpty() )
 
  241            else if( fieldValue.IsEmpty() )
 
  244                fieldValue += 
"," + value;
 
 
  254    wxCHECK_RET( aCol >= 0 && aCol < (
int) 
m_cols.size(), wxS( 
"Invalid column number" ) );
 
 
  275    wxCHECK( aCol >= 0 && aCol < 
static_cast<int>( 
m_cols.size() ), 
false );
 
 
  282    wxCHECK( aCol >= 0 && aCol < 
static_cast<int>( 
m_cols.size() ), 
false );
 
  283    return m_cols[aCol].m_isCheckbox;
 
 
  289    wxGridCellAttr* attr = wxGridTableBase::GetAttr( aRow, aCol, aKind );
 
  297            wxGridCellAttr* newAttr = 
m_colAttrs[aCol]->Clone();
 
  300            if( attr->HasBackgroundColour() && !newAttr->HasBackgroundColour() )
 
  301                newAttr->SetBackgroundColour( attr->GetBackgroundColour() );
 
  302            if( attr->HasTextColour() && !newAttr->HasTextColour() )
 
  303                newAttr->SetTextColour( attr->GetTextColour() );
 
  304            if( attr->HasFont() && !newAttr->HasFont() )
 
  305                newAttr->SetFont( attr->GetFont() );
 
  317        attr = 
new wxGridCellAttr;
 
  320    bool rowModified = 
false;
 
  321    bool cellModified = 
false;
 
  322    bool cellEmpty = 
true;
 
  323    bool blankModified = 
false;
 
  325    const wxString& fieldName = 
m_cols[aCol].m_fieldName;
 
  341            blankModified = 
true;
 
  347                if( 
m_dataStore[ref->m_Uuid][col.m_fieldName].m_isModified )
 
  355        if( cellModified && rowModified && !cellEmpty )
 
  364        if( stripedRenderer )
 
  366            attr->SetRenderer( stripedRenderer );
 
  367            attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
 
  371                if( 
m_dataStore[ref->m_Uuid][fieldName].m_isModified )
 
  373                    m_dataStore[ref->m_Uuid][fieldName].m_isStriped = 
true;
 
  375                    if( 
m_dataStore[ref->m_Uuid][fieldName].m_currentlyEmpty )
 
  377                        if( 
m_dataStore[ref->m_Uuid][fieldName].m_originallyEmpty )
 
  379                            attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ) );
 
  381                        else if( 
m_dataStore[ref->m_Uuid][fieldName].m_originalData.empty() )
 
  383                            attr->SetBackgroundColour( wxColour( 180, 220, 180 ) );
 
  387                            attr->SetBackgroundColour( wxColour( 220, 180, 180 ) );
 
  390                    else if( 
m_dataStore[ref->m_Uuid][fieldName].m_currentData.IsEmpty() )
 
  392                        attr->SetBackgroundColour( wxColour( 180, 200, 180 ) );
 
  396                        attr->SetBackgroundColour( wxColour( 200, 180, 180 ) );
 
  404        bool wasStriped = 
false;
 
  408            if( 
m_dataStore[ref->m_Uuid][fieldName].m_isStriped )
 
  411                m_dataStore[ref->m_Uuid][fieldName].m_isStriped = 
false;
 
  417            attr = 
new wxGridCellAttr;
 
  420            attr->SetBackgroundColour( wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWFRAME ) );
 
  423            attr->SetBackgroundColour( wxColour( 192, 255, 192 ) );
 
  430        if( attr->HasFont() )
 
  431            font = attr->GetFont();
 
  433            font = GetView()->GetDefaultCellFont();
 
  440            attr->SetFont( font );
 
 
  450    wxCHECK_RET( aRow >= 0 && aRow < (
int) 
m_rows.size(), 
"Invalid Row Number" );
 
  451    wxCHECK_RET( aCol >= 0 && aCol < (
int) 
m_cols.size(), 
"Invalid Column Number" );
 
  454    const wxString& fieldName = 
m_cols[aCol].m_fieldName;
 
  456    std::map<wxString, LIB_DATA_ELEMENT>& parentFieldStore = 
m_dataStore[parentSymbol->
m_Uuid];
 
  459    wxString derivedSymbolFieldName = 
"__DERIVED_SYMBOL_" + fieldName + 
"__";
 
  469    wxLogTrace( 
traceLibFieldTable, 
"CreateDerivedSymbol: Parent symbol name='%s', UUID='%s'",
 
  471    wxLogTrace( 
traceLibFieldTable, 
"CreateDerivedSymbol: Stored creation request for symbol '%s' under parent UUID %s, special field '%s'",
 
  472                aNewSymbolName, parentSymbol->
m_Uuid.
AsString(), derivedSymbolFieldName );
 
 
  479    wxCHECK_RET( aRow >= 0 && aRow < (
int) 
m_rows.size(), 
"Invalid Row Number" );
 
  480    wxCHECK_RET( aCol >= 0 && aCol < (
int) 
m_cols.size(), 
"Invalid Column Number" );
 
  484    wxLogTrace( 
traceLibFieldTable, 
"CreateDerivedSymbolImmediate: Creating '%s' from parent '%s' immediately",
 
  485                aNewSymbolName, parentSymbol->
GetName() );
 
  488    KIID newDerivedSymbolUuid;
 
 
  501    wxLogTrace( 
traceLibFieldTable, 
"createActualDerivedSymbol: Creating '%s' from parent '%s', symbol list size before: %zu",
 
  508        if( sym->m_Uuid == aNewSymbolUuid )
 
  518        newSymbol->
SetName( aNewSymbolName );
 
  525        const_cast<KIID&
>( newSymbol->
m_Uuid ) = aNewSymbolUuid;
 
  528        wxLogTrace( 
traceLibFieldTable, 
"createActualDerivedSymbol: Added new symbol to list, size now: %zu",
 
  532        for( 
const auto& col : 
m_cols )
 
  537        wxLogTrace( 
traceLibFieldTable, 
"createActualDerivedSymbol: Initialized field data for new symbol" );
 
  544    wxLogTrace( 
traceLibFieldTable, 
"Created derived symbol '%s' for library '%s', total tracked: %zu",
 
 
  556        for( 
auto& [
name, element] : fieldStore )
 
  558            element.m_currentData = element.m_originalData;
 
  559            element.m_isModified = 
false;
 
  560            element.m_currentlyEmpty = 
false;
 
  566    for( 
const auto& [symId, fieldStore] : 
m_dataStore )
 
  568        for( 
const auto& [
name, element] : fieldStore )
 
  570            if( element.m_isModified )
 
 
  582    wxCHECK_RET( aCol >= 0 && aCol < (
int) 
m_cols.size(), wxS( 
"Invalid column number" ) );
 
  589        if( 
m_cols[aCol].m_fieldName == wxS( 
"Keywords" ) )
 
 
  614    if( lhGroup.
m_Refs.size() == 0 )
 
  616    else if( rhGroup.
m_Refs.size() == 0 )
 
  622            [ ascending ]( 
const wxString& a, 
const wxString& b )
 
  631    wxString lhs = dataModel->
GetValue( lhGroup, sortCol ).Trim( 
true ).Trim( 
false );
 
  632    wxString rhs = dataModel->
GetValue( rhGroup, sortCol ).Trim( 
true ).Trim( 
false );
 
  634    if( lhs == rhs && lhGroup.
m_Refs.size() > 1 && rhGroup.
m_Refs.size() > 1 )
 
  636        wxString lhRef = lhGroup.
m_Refs[1]->GetName();
 
  637        wxString rhRef = rhGroup.
m_Refs[1]->GetName();
 
  638        return local_cmp( lhRef, rhRef );
 
  642        return local_cmp( lhs, rhs );
 
 
  655        std::sort( row.m_Refs.begin(), row.m_Refs.end(),
 
  658                       wxString lhs_ref( lhs->GetRef( nullptr ) );
 
  659                       wxString rhs_ref( rhs->GetRef( nullptr ) );
 
  660                       return StrNumCmp( lhs_ref, rhs_ref, true ) < 0;
 
  667                   return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
 
  675        row.m_ItemNumber = itemNumber++;
 
 
  685    bool        matchFound = 
false;
 
  690    for( 
size_t i = 0; i < 
m_cols.size(); ++i )
 
 
  708                                                               const wxString&   aAttributeName )
 
  710    if( aAttributeName == wxS( 
"${DNP}" ) )
 
  711        return aSymbol->
GetDNP() ? wxS( 
"1" ) : wxS( 
"0" );
 
  713    if( aAttributeName == wxS( 
"${EXCLUDE_FROM_BOARD}" ) )
 
  716    if( aAttributeName == wxS( 
"${EXCLUDE_FROM_BOM}" ) )
 
  719    if( aAttributeName == wxS( 
"${EXCLUDE_FROM_SIM}" ) )
 
  722    if( aAttributeName == wxS( 
"Power" ) )
 
  723        return aSymbol->
IsPower() ? wxS( 
"1" ) : wxS( 
"0" );
 
  725    if( aAttributeName == wxS( 
"LocalPower" ) )
 
  726        return aSymbol->
IsLocalPower() ? wxS( 
"1" ) : wxS( 
"0" );
 
 
  733                                                           const wxString& aAttributeName,
 
  734                                                           const wxString& aValue )
 
  736    if( aAttributeName == wxS( 
"${DNP}" ) )
 
  737        aSymbol->
SetDNP( aValue == wxS( 
"1" ) );
 
  738    else if( aAttributeName == wxS( 
"${EXCLUDE_FROM_BOARD}" ) )
 
  740    else if( aAttributeName == wxS( 
"${EXCLUDE_FROM_BOM}" ) )
 
  742    else if( aAttributeName == wxS( 
"${EXCLUDE_FROM_SIM}" ) )
 
  744    else if( aAttributeName == wxS( 
"LocalPower" ) )
 
  747        if( aValue == wxS( 
"0" ) )
 
  752    else if( aAttributeName == wxS( 
"Power" ) )
 
  754        if( aValue == wxS( 
"0" ) )
 
  760        wxLogDebug( 
"Unknown attribute name: %s", aAttributeName );
 
 
  772        static_cast<WX_GRID*
>( GetView() )->CommitPendingChanges( 
true );
 
  774        wxGridTableMessage msg( 
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, 0, (
int) 
m_rows.size() );
 
  775        GetView()->ProcessTableMessage( msg );
 
  785                    ref->GetName(), ref->m_Uuid.AsString() );
 
  791            std::map<wxString, LIB_DATA_ELEMENT>& fieldStore = 
m_dataStore[ref->m_Uuid];
 
  795                auto it = fieldStore.find( col.m_fieldName );
 
  808        bool matchFound = 
false;
 
  826                row.m_Refs.push_back( ref );
 
  838        wxGridTableMessage msg( 
this, wxGRIDTABLE_NOTIFY_ROWS_APPENDED, (
int) 
m_rows.size() );
 
  839        GetView()->ProcessTableMessage( msg );
 
 
  849    std::vector<LIB_DATA_MODEL_ROW> children;
 
  853        bool matchFound = 
false;
 
  859    if( children.size() < 2 )
 
  862    std::sort( children.begin(), children.end(),
 
  865                   return cmp( lhs, rhs, this, m_sortColumn, m_sortAscending );
 
  869    m_rows.insert( 
m_rows.begin() + aRow + 1, children.begin(), children.end() );
 
  871    wxGridTableMessage msg( 
this, wxGRIDTABLE_NOTIFY_ROWS_INSERTED, aRow, (
int) children.size() );
 
  872    GetView()->ProcessTableMessage( msg );
 
 
  878    auto firstChild = 
m_rows.begin() + aRow + 1;
 
  879    auto afterLastChild = firstChild;
 
  882    while( afterLastChild != 
m_rows.end() && afterLastChild->m_Flag == 
CHILD_ITEM )
 
  889    m_rows.erase( firstChild, afterLastChild );
 
  891    wxGridTableMessage msg( 
this, wxGRIDTABLE_NOTIFY_ROWS_DELETED, aRow + 1, deleted );
 
  892    GetView()->ProcessTableMessage( msg );
 
 
  909    for( 
size_t i = 0; i < 
m_rows.size(); ++i )
 
 
  922    for( 
size_t i = 0; i < 
m_rows.size(); ++i )
 
 
  931                                                   std::function<
void()> postApplyHandler )
 
  935        std::map<wxString, LIB_DATA_ELEMENT>& fieldStore = 
m_dataStore[symbol->m_Uuid];
 
  937        for( 
auto& srcData : fieldStore )
 
  939            const wxString&   srcName = srcData.first;
 
  945                symbolChangeHandler( symbol );
 
  960            if( srcName.StartsWith( 
"__DERIVED_SYMBOL_" ) && srcName.EndsWith( 
"__" ) )
 
  963            if( srcName == wxS( 
"Keywords" ) )
 
  965                symbol->SetKeyWords( srcValue );
 
  973            SCH_FIELD* destField = symbol->GetField( srcName );
 
  974            bool       userAdded = ( col != -1 && 
m_cols[col].m_userAdded );
 
  977            bool createField = !destField && ( !srcValue.IsEmpty() || userAdded );
 
  981                const VECTOR2I symbolPos = symbol->GetPosition();
 
  984                symbol->AddField( destField );
 
  997                if( !srcValue.IsEmpty() )
 
 1006                destField->
SetText( srcValue );
 
 1015        std::vector<SCH_FIELD*> symbolFields;
 
 1016        symbol->GetFields( symbolFields );
 
 1021            if( field->IsMandatory() )
 
 1025            if( !fieldStore.contains( field->GetName() ) )
 
 1027                symbolChangeHandler( symbol );
 
 1028                symbol->RemoveField( field );
 
 1037        for( 
auto& [fieldName, element] : fieldStore )
 
 1039            if( element.m_createDerivedSymbol )
 
 1046                    KIID parentUuid( element.m_originalData );
 
 1050                        if( sym->m_Uuid == parentUuid )
 
 1067                        if( sym->GetName() == element.m_originalData )
 
 1077                    wxString actualDerivedName = element.m_derivedSymbolName;
 
 1080                    if( actualDerivedName == parentSymbol->
GetName() )
 
 1083                        actualDerivedName = parentSymbol->
GetName() + 
"_1";
 
 1087                        bool nameExists = 
true;
 
 1089                        while( nameExists && variant < 100 )
 
 1095                                if( sym->GetName() == actualDerivedName )
 
 1104                                actualDerivedName = parentSymbol->
GetName() + 
"_" + wxString::Format( 
"%d", variant );
 
 1111                    KIID newDerivedSymbolUuid;
 
 1116                element.m_createDerivedSymbol = 
false;
 
 1125    if( postApplyHandler )
 
 
 1149        return wxGRID_VALUE_BOOL;
 
 1151    return wxGridTableBase::GetTypeName( row, col );
 
 
 1157    wxCHECK( aCol >= 0 && aCol < (
int) 
m_cols.size(), 
nullptr );
 
 1159    const wxString& fieldName = 
m_cols[aCol].m_fieldName;
 
 1165        it->second->IncRef();
 
 1169    wxGridCellRenderer* stripedRenderer = 
nullptr;
 
 1174    stripedRenderer->IncRef();
 
 1178    stripedRenderer->IncRef();
 
 1179    return stripedRenderer;
 
 
 1186    wxCHECK( aCol >= 0 && aCol < (
int) 
m_cols.size(), 
false );
 
 
wxString AsString() const
 
void SetFieldsOrder(const std::vector< wxString > &aNewOrder)
 
wxGridCellRenderer * getStripedRenderer(int aCol) const
 
void SetValue(int aRow, int aCol, const wxString &aValue) override
 
wxString GetColFieldName(int aCol)
 
wxString getAttributeValue(const LIB_SYMBOL *, const wxString &aAttributeName)
 
std::vector< std::pair< LIB_SYMBOL *, wxString > > m_createdDerivedSymbols
 
static bool cmp(const LIB_DATA_MODEL_ROW &lhGroup, const LIB_DATA_MODEL_ROW &rhGroup, LIB_FIELDS_EDITOR_GRID_DATA_MODEL *dataModel, int sortCol, bool ascending)
 
std::map< KIID, std::map< wxString, LIB_DATA_ELEMENT > > m_dataStore
 
static const wxString ITEM_NUMBER_VARIABLE
 
std::map< wxString, wxGridCellRenderer * > m_stripedRenderers
 
wxGridCellAttr * GetAttr(int row, int col, wxGridCellAttr::wxAttrKind kind) override
 
static const wxString SYMBOL_NAME
 
void CreateDerivedSymbolImmediate(int aRow, int aCol, wxString &aNewSymbolName)
 
bool isStripeableField(int aCol)
 
wxString GetValue(int aRow, int aCol) override
 
void RemoveColumn(int aCol)
 
bool ColIsCheck(int aCol)
 
void createActualDerivedSymbol(const LIB_SYMBOL *aParentSymbol, const wxString &aNewSymbolName, const KIID &aNewSymbolUuid)
 
std::vector< LIB_DATA_MODEL_COL > m_cols
 
void AddColumn(const wxString &aFieldName, const wxString &aLabel, bool aAddedByUser, bool aIsCheckbox)
 
void ApplyData(std::function< void(LIB_SYMBOL *)> symbolChangeHandler, std::function< void()> postApplyHandler=nullptr)
 
void ExpandCollapseRow(int aRow)
 
std::vector< LIB_DATA_MODEL_ROW > m_rows
 
int GetFieldNameCol(const wxString &aFieldName)
 
void updateDataStoreSymbolField(const LIB_SYMBOL *aSymbol, const wxString &aFieldName)
 
void RenameColumn(int aCol, const wxString &newName)
 
std::vector< LIB_SYMBOL * > m_symbolsList
 
bool groupMatch(const LIB_SYMBOL *lhRef, const LIB_SYMBOL *rhRef)
 
int GetDataWidth(int aCol)
 
void CreateDerivedSymbol(int aRow, int aCol, wxString &aNewSymbolName)
 
void ClearCell(int aRow, int aCol)
 
void setAttributeValue(LIB_SYMBOL *aSymbol, const wxString &aAttributeName, const wxString &aValue)
 
void CollapseRow(int aRow)
 
wxString GetTypeName(int row, int col) override
 
LIB_FIELDS_EDITOR_GRID_DATA_MODEL()
 
bool IsExpanderColumn(int aCol) const override
 
bool ColIsSymbolName(int aCol)
 
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
 
Define a library symbol object.
 
const LIB_ID & GetLibId() const override
 
wxString GetKeyWords() const override
 
bool IsPower() const override
 
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
 
void SetParent(LIB_SYMBOL *aParent=nullptr)
 
wxString GetName() const override
 
SCH_FIELD & GetValueField()
Return reference to the value field.
 
bool IsLocalPower() const override
 
virtual void SetName(const wxString &aName)
 
void SetPosition(const VECTOR2I &aPosition) override
 
void SetText(const wxString &aText) override
 
void SetExcludedFromBoard(bool aExcludeFromBoard) override
Set or clear exclude from board netlist flag.
 
virtual bool GetDNP(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
Set or clear the 'Do Not Populate' flag.
 
bool GetExcludedFromBoard() const override
 
virtual void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
 
virtual bool GetExcludedFromBOM(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
 
virtual void SetDNP(bool aDNP, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
 
virtual bool GetExcludedFromSim(const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) const override
 
virtual void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
 
std::map< int, wxGridCellAttr * > m_colAttrs
 
bool IsGeneratedField(const wxString &aSource)
Returns true if the string is generated, e.g contains a single text var reference.
 
STRIPED_CELL_RENDERER< wxGridCellStringRenderer > STRIPED_STRING_RENDERER
 
const wxChar *const traceLibFieldTable
 
KICOMMON_API wxSize GetTextSize(const wxString &aSingleLine, wxWindow *aWindow)
Return the size of aSingleLine of text when it is rendered in aWindow using whatever font is currentl...
 
bool WildCompareString(const wxString &pattern, const wxString &string_to_tst, bool case_sensitive)
Compare a string against wild card (* and ?) pattern using the usual rules.
 
bool m_createDerivedSymbol
 
wxString m_derivedSymbolName
 
std::vector< const LIB_SYMBOL * > m_Refs
 
@ USER
The field ID hasn't been set yet; field is invalid.
 
@ FOOTPRINT
Field Name Module PCB, i.e. "16DIP300".
 
@ REFERENCE
Field Reference of part, i.e. "IC21".
 
@ VALUE
Field Value of part, i.e. "3.3K".
 
wxLogTrace helper definitions.
 
#define INDETERMINATE_STATE
Used for holding indeterminate values, such as with multiple selections holding different values or c...
 
VECTOR2< int32_t > VECTOR2I
 
@ GROUP_COLLAPSED_DURING_SORT