void SetHtmlDesc()
    {
        wxString raw_desc;

        if( m_part->IsRoot() )
        {
            raw_desc = m_part->GetDescription();
        }
        else
        {
            LIB_PART* root = m_part->GetPart();

            for( size_t i = 0; i < root->GetAliasCount(); ++i )
            {
                LIB_ALIAS* alias = root->GetAlias( i );

                if( alias && !alias->GetDescription().empty() )
                {
                    raw_desc = alias->GetDescription();
                    break;
                }
            }
        }

        m_html.Replace( "__DESC__", wxString::Format( DescFormat, EscapedHTML( raw_desc ) ) );
    }
void LIB_EDIT_FRAME::OnViewEntryDoc( wxCommandEvent& event )
{
    LIB_PART* part = GetCurPart();

    if( !part )
        return;

    wxString filename;

    if( part->GetAliasCount() > 1 )
    {
        ACTION_MENU  popup;
        wxString     msg;
        int          id = 0;

        for( LIB_ALIAS* alias : part->GetAliases() )
        {
            msg.Printf( wxT( "%s (%s)" ), alias->GetName(), alias->GetDocFileName() );
            popup.Append( id++, msg );
        }

        PopupMenu( &popup );

        if( popup.GetSelected() >= 0 )
            filename = part->GetAlias( (unsigned) popup.GetSelected() )->GetDocFileName();
    }
    else
        filename = part->GetAlias( 0 )->GetDocFileName();

    if( !filename.IsEmpty() && filename != wxT( "~" ) )
    {
        SEARCH_STACK* lib_search = Prj().SchSearchS();

        GetAssociatedDocument( this, filename, lib_search );
    }
}
void LIB_EDIT_FRAME::DisplayCmpDoc()
{
    LIB_ALIAS*      alias;
    PART_LIB*    lib = GetCurLib();
    LIB_PART*       part = GetCurPart();

    ClearMsgPanel();

    if( !lib || !part )
        return;

    wxString msg = part->GetName();

    AppendMsgPanel( _( "Name" ), msg, BLUE, 8 );

    if( m_aliasName == part->GetName() )
        msg = _( "None" );
    else
        msg = m_aliasName;

    alias = part->GetAlias( m_aliasName );

    wxCHECK_RET( alias != NULL, "Alias not found in component." );

    AppendMsgPanel( _( "Alias" ), msg, RED, 8 );

    static wxChar UnitLetter[] = wxT( "?ABCDEFGHIJKLMNOPQRSTUVWXYZ" );
    msg = UnitLetter[m_unit];

    AppendMsgPanel( _( "Unit" ), msg, BROWN, 8 );

    if( m_convert > 1 )
        msg = _( "Convert" );
    else
        msg = _( "Normal" );

    AppendMsgPanel( _( "Body" ), msg, GREEN, 8 );

    if( part->IsPower() )
        msg = _( "Power Symbol" );
    else
        msg = _( "Part" );

    AppendMsgPanel( _( "Type" ), msg, MAGENTA, 8 );
    AppendMsgPanel( _( "Description" ), alias->GetDescription(), CYAN, 8 );
    AppendMsgPanel( _( "Key words" ), alias->GetKeyWords(), DARKDARKGRAY );
    AppendMsgPanel( _( "Datasheet" ), alias->GetDocFileName(), DARKDARKGRAY );
}
void LIB_EDIT_FRAME::OnUpdateViewDoc( wxUpdateUIEvent& event )
{
    bool enable = false;

    PART_LIB*    lib  = GetCurLib();
    LIB_PART*       part = GetCurPart();

    if( part && lib )
    {
        LIB_ALIAS* alias = part->GetAlias( m_aliasName );

        wxCHECK_RET( alias != NULL, wxT( "Alias <" ) + m_aliasName + wxT( "> not found." ) );

        enable = !alias->GetDocFileName().IsEmpty();
    }

    event.Enable( enable );
}
void LIB_EDIT_FRAME::OnViewEntryDoc( wxCommandEvent& event )
{
    LIB_PART* part = GetCurPart();

    if( !part )
        return;

    wxString    fileName;
    LIB_ALIAS*  alias = part->GetAlias( m_aliasName );

    wxCHECK_RET( alias != NULL, wxT( "Alias not found." ) );

    fileName = alias->GetDocFileName();

    if( !fileName.IsEmpty() )
    {
        SEARCH_STACK* lib_search = Prj().SchSearchS();

        GetAssociatedDocument( this, fileName, lib_search );
    }
}
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::CopyDocFromRootToAlias( wxCommandEvent& event )
{
    if( m_Parent == NULL )
        return;

    LIB_ALIAS* parent_alias;
    LIB_PART*      component = m_Parent->GetCurPart();

    if( component == NULL )
        return;

    // search for the main alias: this is the first alias in alias list
    // something like the main component
    parent_alias = component->GetAlias( 0 );

    if( parent_alias == NULL )  // Should never occur (bug)
        return;

    m_DocCtrl->SetValue( parent_alias->GetDescription() );
    m_DocfileCtrl->SetValue( parent_alias->GetDocFileName() );
    m_KeywordsCtrl->SetValue( parent_alias->GetKeyWords() );
}
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::InitPanelDoc()
{
    LIB_ALIAS* alias;
    LIB_PART*      component = m_Parent->GetCurPart();

    if( component == NULL )
        return;

    wxString aliasname = m_Parent->GetAliasName();

    if( aliasname.IsEmpty() )
        return;

    alias = component->GetAlias( aliasname );

    if( alias != NULL )
    {
        m_DocCtrl->SetValue( alias->GetDescription() );
        m_KeywordsCtrl->SetValue( alias->GetKeyWords() );
        m_DocfileCtrl->SetValue( alias->GetDocFileName() );
    }
}
void DIALOG_EDIT_LIBENTRY_FIELDS_IN_LIB::OnOKButtonClick( wxCommandEvent& event )
{
    if( !copyPanelToSelectedField() )
        return;

    // test if reference prefix is acceptable
    if( !SCH_COMPONENT::IsReferenceStringValid( m_FieldsBuf[REFERENCE].GetText() ) )
    {
        DisplayError( NULL, _( "Illegal reference prefix. A reference must start by a letter" ) );
        return;
    }

    /* Note: this code is now (2010-dec-04) not used, because the value field is no more editable
     * because changing the value is equivalent to create a new component or alias.
     * This is now handled in libedit main frame, and no more in this dialog
     * but this code is not removed, just in case
     */
    /* If a new name entered in the VALUE field, that it not an existing alias name
     * or root alias of the component */
    wxString newvalue = m_FieldsBuf[VALUE].GetText();

    if( m_libEntry->HasAlias( newvalue ) && !m_libEntry->GetAlias( newvalue )->IsRoot() )
    {
        wxString msg = wxString::Format(
            _( "A new name is entered for this component\n"
               "An alias %s already exists!\n"
               "Cannot update this component" ),
            GetChars( newvalue )
            );
        DisplayError( this, msg );
        return;
    }
    /* End unused code */

    // save old cmp in undo list
    m_parent->SaveCopyInUndoList( m_libEntry );

    // delete any fields with no name or no value before we copy all of m_FieldsBuf
    // back into the component
    for( unsigned i = MANDATORY_FIELDS; i < m_FieldsBuf.size(); )
    {
        if( m_FieldsBuf[i].GetName().IsEmpty() || m_FieldsBuf[i].GetText().IsEmpty() )
        {
            m_FieldsBuf.erase( m_FieldsBuf.begin() + i );
            continue;
        }

        ++i;
    }

#if defined(DEBUG)
    for( unsigned i = 0;  i<m_FieldsBuf.size();  ++i )
    {
        printf( "save[%u].name:'%s' value:'%s'\n", i,
                TO_UTF8( m_FieldsBuf[i].GetName() ),
                TO_UTF8( m_FieldsBuf[i].GetText() ) );
    }
#endif

    // copy all the fields back, fully replacing any previous fields
    m_libEntry->SetFields( m_FieldsBuf );

    // We need to keep the name and the value the same at the moment!
    SetName( m_libEntry->GetValueField().GetText() );

    m_parent->OnModify();

    EndQuasiModal( wxID_OK );
}
XNODE* NETLIST_EXPORTER_GENERIC::makeLibParts()
{
    XNODE*      xlibparts = node( wxT( "libparts" ) );   // auto_ptr
    wxString    sLibpart  = wxT( "libpart" );
    wxString    sLib      = wxT( "lib" );
    wxString    sPart     = wxT( "part" );
    wxString    sAliases  = wxT( "aliases" );
    wxString    sAlias    = wxT( "alias" );
    wxString    sPins     = wxT( "pins" );      // key for library component pins list
    wxString    sPin      = wxT( "pin" );       // key for one library component pin descr
    wxString    sPinNum   = wxT( "num" );       // key for one library component pin num
    wxString    sPinName  = wxT( "name" );      // key for one library component pin name
    wxString    sPinType  = wxT( "type" );      // key for one library component pin electrical type
    wxString    sName     = wxT( "name" );
    wxString    sField    = wxT( "field" );
    wxString    sFields   = wxT( "fields" );
    wxString    sDescr    = wxT( "description" );
    wxString    sDocs     = wxT( "docs" );
    wxString    sFprints  = wxT( "footprints" );
    wxString    sFp       = wxT( "fp" );

    LIB_PINS    pinList;
    LIB_FIELDS  fieldList;

    m_Libraries.clear();

    for( std::set<LIB_PART*>::iterator it = m_LibParts.begin(); it!=m_LibParts.end();  ++it )
    {
        LIB_PART* lcomp = *it;
        PART_LIB* library = lcomp->GetLib();

        m_Libraries.insert( library );  // inserts component's library if unique

        XNODE* xlibpart;
        xlibparts->AddChild( xlibpart = node( sLibpart ) );
        xlibpart->AddAttribute( sLib, library->GetLogicalName() );
        xlibpart->AddAttribute( sPart, lcomp->GetName()  );

        if( lcomp->GetAliasCount() )
        {
            wxArrayString aliases = lcomp->GetAliasNames( false );
            if( aliases.GetCount() )
            {
                XNODE* xaliases = node( sAliases );
                xlibpart->AddChild( xaliases );
                for( unsigned i=0;  i<aliases.GetCount();  ++i )
                {
                    xaliases->AddChild( node( sAlias, aliases[i] ) );
                }
            }
        }

        //----- show the important properties -------------------------
        if( !lcomp->GetAlias( 0 )->GetDescription().IsEmpty() )
            xlibpart->AddChild( node( sDescr, lcomp->GetAlias( 0 )->GetDescription() ) );

        if( !lcomp->GetAlias( 0 )->GetDocFileName().IsEmpty() )
            xlibpart->AddChild( node( sDocs,  lcomp->GetAlias( 0 )->GetDocFileName() ) );

        // Write the footprint list
        if( lcomp->GetFootPrints().GetCount() )
        {
            XNODE*  xfootprints;
            xlibpart->AddChild( xfootprints = node( sFprints ) );

            for( unsigned i=0; i<lcomp->GetFootPrints().GetCount(); ++i )
            {
                xfootprints->AddChild( node( sFp, lcomp->GetFootPrints()[i] ) );
            }
        }

        //----- show the fields here ----------------------------------
        fieldList.clear();
        lcomp->GetFields( fieldList );

        XNODE*     xfields;
        xlibpart->AddChild( xfields = node( sFields ) );

        for( unsigned i=0;  i<fieldList.size();  ++i )
        {
            if( !fieldList[i].GetText().IsEmpty() )
            {
                XNODE*     xfield;
                xfields->AddChild( xfield = node( sField, fieldList[i].GetText() ) );
                xfield->AddAttribute( sName, fieldList[i].GetName(false) );
            }
        }

        //----- show the pins here ------------------------------------
        pinList.clear();
        lcomp->GetPins( pinList, 0, 0 );

        /* we must erase redundant Pins references in pinList
         * These redundant pins exist because some pins
         * are found more than one time when a component has
         * multiple parts per package or has 2 representations (DeMorgan conversion)
         * For instance, a 74ls00 has DeMorgan conversion, with different pin shapes,
         * and therefore each pin  appears 2 times in the list.
         * Common pins (VCC, GND) can also be found more than once.
         */
        sort( pinList.begin(), pinList.end(), sortPinsByNumber );
        for( int ii = 0; ii < (int)pinList.size()-1; ii++ )
        {
            if( pinList[ii]->GetNumber() == pinList[ii+1]->GetNumber() )
            {   // 2 pins have the same number, remove the redundant pin at index i+1
                pinList.erase(pinList.begin() + ii + 1);
                ii--;
            }
        }

        if( pinList.size() )
        {
            XNODE*     pins;

            xlibpart->AddChild( pins = node( sPins ) );
            for( unsigned i=0; i<pinList.size();  ++i )
            {
                XNODE*     pin;

                pins->AddChild( pin = node( sPin ) );
                pin->AddAttribute( sPinNum, pinList[i]->GetNumberString() );
                pin->AddAttribute( sPinName, pinList[i]->GetName() );
                pin->AddAttribute( sPinType, pinList[i]->GetCanonicalElectricalTypeName() );

                // caution: construction work site here, drive slowly
            }
        }
    }

    return xlibparts;
}
LIB_EDIT_FRAME::LIB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
    SCH_BASE_FRAME( aKiway, aParent, FRAME_SCH_LIB_EDITOR, _( "Library Editor" ),
        wxDefaultPosition, wxDefaultSize, KICAD_DEFAULT_DRAWFRAME_STYLE, LIB_EDIT_FRAME_NAME )
{
    m_showAxis   = true;            // true to draw axis
    SetShowDeMorgan( false );
    m_drawSpecificConvert = true;
    m_drawSpecificUnit    = false;
    m_hotkeysDescrList    = g_Libedit_Hokeys_Descr;
    m_editPinsPerPartOrConvert = false;
    m_repeatPinStep = DEFAULT_REPEAT_OFFSET_PIN;

    m_my_part = NULL;
    m_tempCopyComponent = NULL;

    // Delayed initialization
    if( m_textSize == -1 )
        m_textSize = GetDefaultTextSize();

    // Initialize grid id to the default value 50 mils:
    m_LastGridSizeId = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000;

    wxIcon icon;
    icon.CopyFromBitmap( KiBitmap( libedit_icon_xpm ) );
    SetIcon( icon );

    LoadSettings( config() );

    SetScreen( new SCH_SCREEN( aKiway ) );
    GetScreen()->m_Center = true;
    GetScreen()->SetMaxUndoItems( m_UndoRedoCountMax );

    SetCrossHairPosition( wxPoint( 0, 0 ) );

    // Ensure m_LastGridSizeId is an offset inside the allowed schematic range
    if( m_LastGridSizeId < ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000 )
        m_LastGridSizeId = ID_POPUP_GRID_LEVEL_50 - ID_POPUP_GRID_LEVEL_1000;

    if( m_LastGridSizeId > ID_POPUP_GRID_LEVEL_1 - ID_POPUP_GRID_LEVEL_1000 )
        m_LastGridSizeId = ID_POPUP_GRID_LEVEL_1 - ID_POPUP_GRID_LEVEL_1000;

    SetSize( m_FramePos.x, m_FramePos.y, m_FrameSize.x, m_FrameSize.y );

    GetScreen()->SetGrid( ID_POPUP_GRID_LEVEL_1000 + m_LastGridSizeId  );

    if( m_canvas )
        m_canvas->SetEnableBlockCommands( true );

    ReCreateMenuBar();
    ReCreateHToolbar();
    ReCreateVToolbar();

    // Ensure the current alias name is valid if a part is loaded
    // Sometimes it is not valid. This is the case
    // when a part value (the part lib name), or the alias list was modified
    // during a previous session and the modifications not saved in lib.
    // Reopen libedit in a new session gives a non valid m_aliasName
    // because the curr part is reloaded from the library (and this is the unmodified part)
    // and the old alias name (from the previous edition) can be invalid
    LIB_PART* part = GetCurPart();

    if( part == NULL )
        m_aliasName.Empty();
    else if( m_aliasName != part->GetName() )
    {
        LIB_ALIAS* alias = part->GetAlias( m_aliasName );

        if( !alias )
            m_aliasName = part->GetName();
    }


    CreateOptionToolbar();
    DisplayLibInfos();
    DisplayCmpDoc();
    UpdateAliasSelectList();
    UpdatePartSelectList();

    m_auimgr.SetManagedWindow( this );

    EDA_PANEINFO horiz;
    horiz.HorizontalToolbarPane();

    EDA_PANEINFO vert;
    vert.VerticalToolbarPane();

    EDA_PANEINFO mesg;
    mesg.MessageToolbarPane();

    m_auimgr.AddPane( m_mainToolBar,
                      wxAuiPaneInfo( horiz ).Name( wxT( "m_mainToolBar" ) ).Top().Row( 0 ) );

    m_auimgr.AddPane( m_drawToolBar,
                      wxAuiPaneInfo( vert ).Name( wxT( "m_VToolBar" ) ).Right() );

    m_auimgr.AddPane( m_optionsToolBar,
                      wxAuiPaneInfo( vert ).Name( wxT( "m_optionsToolBar" ) ).Left() );

    m_auimgr.AddPane( m_canvas,
                      wxAuiPaneInfo().Name( wxT( "DrawFrame" ) ).CentrePane() );

    m_auimgr.AddPane( m_messagePanel,
                      wxAuiPaneInfo( mesg ).Name( wxT( "MsgPanel" ) ).Bottom().Layer(10) );

    m_auimgr.Update();

    Raise();
    Show( true );

    wxCommandEvent evt( wxEVT_COMMAND_MENU_SELECTED, ID_ZOOM_PAGE );
    wxPostEvent( this, evt );
}
void DIALOG_EDIT_COMPONENT_IN_LIBRARY::OnOkClick( wxCommandEvent& event )
{
    /* Update the doc, keyword and doc filename strings */
    LIB_ALIAS* alias;
    LIB_PART*      component = m_Parent->GetCurPart();

    if( component == NULL )
    {
        EndModal( wxID_CANCEL );
        return;
    }

    m_Parent->SaveCopyInUndoList( component );

    alias = component->GetAlias( m_Parent->GetAliasName() );

    wxCHECK_RET( alias != NULL,
                 wxT( "Alias \"" ) + m_Parent->GetAliasName() + wxT( "\" of component \"" ) +
                 component->GetName() + wxT( "\" does not exist." ) );

    alias->SetDescription( m_DocCtrl->GetValue() );
    alias->SetKeyWords( m_KeywordsCtrl->GetValue() );
    alias->SetDocFileName( m_DocfileCtrl->GetValue() );

    component->SetAliases( m_PartAliasListCtrl->GetStrings() );

    int unitCount = m_SelNumberOfUnits->GetValue();
    ChangeNbUnitsPerPackage( unitCount );

    if( m_AsConvertButt->GetValue() )
    {
        if( !m_Parent->GetShowDeMorgan() )
        {
            m_Parent->SetShowDeMorgan( true );
            SetUnsetConvert();
        }
    }
    else
    {
        if( m_Parent->GetShowDeMorgan() )
        {
            m_Parent->SetShowDeMorgan( false );
            SetUnsetConvert();
        }
    }

    component->SetShowPinNumbers( m_ShowPinNumButt->GetValue() );
    component->SetShowPinNames( m_ShowPinNameButt->GetValue() );

    if( m_PinsNameInsideButt->GetValue() == false )
        component->SetPinNameOffset( 0 );       // pin text outside the body (name is on the pin)
    else
    {
        component->SetPinNameOffset( m_SetSkew->GetValue() );
        // Ensure component->m_TextInside != 0, because the meaning is "text outside".
        if( component->GetPinNameOffset() == 0 )
            component->SetPinNameOffset( 20 );  // give a reasonnable value
    }

    if( m_OptionPower->GetValue() == true )
        component->SetPower();
    else
        component->SetNormal();

    /* Set the option "Units locked".
     *  Obviously, cannot be true if there is only one part */
    component->LockUnits( m_OptionPartsLocked->GetValue() );

    if( component->GetUnitCount() <= 1 )
        component->LockUnits( false );

    /* Update the footprint filter list */
    component->GetFootPrints().Clear();
    component->GetFootPrints() = m_FootprintFilterListBox->GetStrings();

    EndModal( wxID_OK );
}