From 1b4ec6ccb5bb88c732f391a19a12b5c5933058cf Mon Sep 17 00:00:00 2001
From: Ian McInerney <ian.s.mcinerney@ieee.org>
Date: Sun, 30 Aug 2020 00:19:05 +0100
Subject: [PATCH] Display symbol libraries that couldn't be loaded as disabled
 text

Fixes https://gitlab.com/kicad/code/kicad/issues/5092
---
 common/lib_tree_model_adapter.cpp             | 12 +++++-----
 eeschema/libedit/lib_manager.cpp              |  8 +++++++
 eeschema/libedit/lib_manager.h                |  5 ++++
 eeschema/symbol_lib_table.cpp                 | 13 +++++++++++
 eeschema/symbol_lib_table.h                   |  9 ++++++++
 .../symbol_tree_synchronizing_adapter.cpp     | 23 +++++++++++++++----
 include/lib_table_base.h                      | 21 +++++++++++++----
 7 files changed, 77 insertions(+), 14 deletions(-)

diff --git a/common/lib_tree_model_adapter.cpp b/common/lib_tree_model_adapter.cpp
index 1ddeaaca63..da4a58e48a 100644
--- a/common/lib_tree_model_adapter.cpp
+++ b/common/lib_tree_model_adapter.cpp
@@ -385,7 +385,7 @@ wxDataViewItem LIB_TREE_MODEL_ADAPTER::FindItem( const LIB_ID& aLibId )
 unsigned int LIB_TREE_MODEL_ADAPTER::GetChildren( wxDataViewItem const&   aItem,
                                                   wxDataViewItemArray&    aChildren ) const
 {
-    auto node = ( aItem.IsOk() ? ToNode( aItem ) : &m_tree );
+    const LIB_TREE_NODE* node = ( aItem.IsOk() ? ToNode( aItem ) : &m_tree );
 
     if( node->m_Type != LIB_TREE_NODE::TYPE::LIBID
             || ( m_show_units && node->m_Type == LIB_TREE_NODE::TYPE::LIBID ) )
@@ -430,7 +430,7 @@ bool LIB_TREE_MODEL_ADAPTER::HasContainerColumns( wxDataViewItem const& aItem )
 
 bool LIB_TREE_MODEL_ADAPTER::IsContainer( wxDataViewItem const& aItem ) const
 {
-    auto node = ToNode( aItem );
+    LIB_TREE_NODE* node = ToNode( aItem );
     return node ? node->m_Children.size() : true;
 }
 
@@ -440,8 +440,8 @@ wxDataViewItem LIB_TREE_MODEL_ADAPTER::GetParent( wxDataViewItem const& aItem )
     if( m_freeze )
         return ToItem( nullptr );
 
-    auto node = ToNode( aItem );
-    auto parent = node ? node->m_Parent : nullptr;
+    LIB_TREE_NODE* node   = ToNode( aItem );
+    LIB_TREE_NODE* parent = node ? node->m_Parent : nullptr;
 
     // wxDataViewModel has no root node, but rather top-level elements have
     // an invalid (null) parent.
@@ -462,7 +462,7 @@ void LIB_TREE_MODEL_ADAPTER::GetValue( wxVariant&              aVariant,
         return;
     }
 
-    auto node = ToNode( aItem );
+    LIB_TREE_NODE* node = ToNode( aItem );
     wxASSERT( node );
 
     switch( aCol )
@@ -485,7 +485,7 @@ bool LIB_TREE_MODEL_ADAPTER::GetAttr( wxDataViewItem const&   aItem,
     if( IsFrozen() )
         return false;
 
-    auto node = ToNode( aItem );
+    LIB_TREE_NODE* node = ToNode( aItem );
     wxASSERT( node );
 
     if( node->m_Type != LIB_TREE_NODE::LIBID )
diff --git a/eeschema/libedit/lib_manager.cpp b/eeschema/libedit/lib_manager.cpp
index 75ba441d79..0992915ed4 100644
--- a/eeschema/libedit/lib_manager.cpp
+++ b/eeschema/libedit/lib_manager.cpp
@@ -286,6 +286,14 @@ bool LIB_MANAGER::IsLibraryReadOnly( const wxString& aLibrary ) const
 }
 
 
+bool LIB_MANAGER::IsLibraryLoaded( const wxString& aLibrary ) const
+{
+    wxCHECK( LibraryExists( aLibrary ), false );
+
+    return symTable()->IsSymbolLibLoaded( aLibrary );
+}
+
+
 std::list<LIB_PART*> LIB_MANAGER::GetAliases( const wxString& aLibrary ) const
 {
     std::list<LIB_PART*> ret;
diff --git a/eeschema/libedit/lib_manager.h b/eeschema/libedit/lib_manager.h
index fc58f61b4d..17a8c5ecbe 100644
--- a/eeschema/libedit/lib_manager.h
+++ b/eeschema/libedit/lib_manager.h
@@ -197,6 +197,11 @@ public:
      */
     bool LibraryExists( const wxString& aLibrary, bool aCheckEnabled = false ) const;
 
+    /**
+     * Returns true if the library was successfully loaded
+     */
+    bool IsLibraryLoaded( const wxString& aLibrary ) const;
+
     /**
      * Returns true if library has unsaved modifications.
      */
diff --git a/eeschema/symbol_lib_table.cpp b/eeschema/symbol_lib_table.cpp
index b6c40ae117..3003062ff1 100644
--- a/eeschema/symbol_lib_table.cpp
+++ b/eeschema/symbol_lib_table.cpp
@@ -78,7 +78,9 @@ bool SYMBOL_LIB_TABLE_ROW::Refresh()
         wxArrayString dummyList;
 
         plugin.set( SCH_IO_MGR::FindPlugin( type ) );
+        SetLoaded( false );
         plugin->EnumerateSymbolLib( dummyList, GetFullURI( true ), GetProperties() );
+        SetLoaded( true );
         return true;
     }
 
@@ -290,7 +292,9 @@ void SYMBOL_LIB_TABLE::EnumerateSymbolLib( const wxString& aNickname, wxArrayStr
     if( aPowerSymbolsOnly )
         row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
 
+    row->SetLoaded( false );
     row->plugin->EnumerateSymbolLib( aAliasNames, row->GetFullURI( true ), row->GetProperties() );
+    row->SetLoaded( true );
 
     if( aPowerSymbolsOnly )
         row->SetOptions( options );
@@ -326,7 +330,9 @@ void SYMBOL_LIB_TABLE::LoadSymbolLib( std::vector<LIB_PART*>& aSymbolList,
     if( aPowerSymbolsOnly )
         row->SetOptions( row->GetOptions() + " " + PropPowerSymsOnly );
 
+    row->SetLoaded( false );
     row->plugin->EnumerateSymbolLib( aSymbolList, row->GetFullURI( true ), row->GetProperties() );
+    row->SetLoaded( true );
 
     if( aPowerSymbolsOnly )
         row->SetOptions( options );
@@ -417,6 +423,13 @@ bool SYMBOL_LIB_TABLE::IsSymbolLibWritable( const wxString& aNickname )
     return row->plugin->IsSymbolLibWritable( row->GetFullURI( true ) );
 }
 
+bool SYMBOL_LIB_TABLE::IsSymbolLibLoaded( const wxString& aNickname )
+{
+    const SYMBOL_LIB_TABLE_ROW* row = FindRow( aNickname );
+    wxCHECK( row, false );
+    return row->GetIsLoaded();
+}
+
 
 void SYMBOL_LIB_TABLE::DeleteSymbolLib( const wxString& aNickname )
 {
diff --git a/eeschema/symbol_lib_table.h b/eeschema/symbol_lib_table.h
index 09a1d59ed7..573144a88c 100644
--- a/eeschema/symbol_lib_table.h
+++ b/eeschema/symbol_lib_table.h
@@ -240,6 +240,15 @@ public:
      */
     bool IsSymbolLibWritable( const wxString& aNickname );
 
+    /**
+     * Return true if the library given by @a aNickname was successfully loaded.
+     *
+     * @param aNickname is the library nickname in the symbol library table.
+     *
+     * @throw IO_ERROR if no library at @a aNickname exists.
+     */
+    bool IsSymbolLibLoaded( const wxString& aNickname );
+
     void DeleteSymbolLib( const wxString& aNickname );
 
     void CreateSymbolLib( const wxString& aNickname );
diff --git a/eeschema/symbol_tree_synchronizing_adapter.cpp b/eeschema/symbol_tree_synchronizing_adapter.cpp
index 3fe648936b..7f8cbbf821 100644
--- a/eeschema/symbol_tree_synchronizing_adapter.cpp
+++ b/eeschema/symbol_tree_synchronizing_adapter.cpp
@@ -241,6 +241,14 @@ void SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetValue( wxVariant& aVariant, wxDataVie
             node->m_Desc = m_frame->GetCurPart()->GetDescription();
 
         aVariant = node->m_Desc;
+
+        // Annotate that the library failed to load in the description column
+        if( node->m_Type == LIB_TREE_NODE::LIB )
+        {
+            if( !m_libMgr->IsLibraryLoaded( node->m_Name ) )
+                aVariant = _( "(failed to load) " ) + aVariant.GetString();
+        }
+
         break;
 
     default:    // column == -1 is used for default Compare function
@@ -256,13 +264,20 @@ bool SYMBOL_TREE_SYNCHRONIZING_ADAPTER::GetAttr( wxDataViewItem const& aItem, un
     if( IsFrozen() )
         return false;
 
-    // change attributes only for the name field
-    if( aCol != 0 )
-        return false;
-
     LIB_TREE_NODE* node = ToNode( aItem );
     wxCHECK( node, false );
 
+    // Mark both columns of unloaded libraries using grey text color (to look disabled)
+    if( node->m_Type == LIB_TREE_NODE::LIB && !m_libMgr->IsLibraryLoaded( node->m_Name ) )
+    {
+        aAttr.SetColour( wxSystemSettings::GetColour( wxSYS_COLOUR_GRAYTEXT  ) );
+        return true;
+    }
+
+    // The remaining attributes are only for the name column
+    if( aCol != 0 )
+        return false;
+
     switch( node->m_Type )
     {
     case LIB_TREE_NODE::LIB:
diff --git a/include/lib_table_base.h b/include/lib_table_base.h
index 0c02b85a2e..d1fce8bda5 100644
--- a/include/lib_table_base.h
+++ b/include/lib_table_base.h
@@ -77,7 +77,8 @@ public:
                    const wxString& aDescr = wxEmptyString ) :
         nickName( aNick ),
         description( aDescr ),
-        enabled( true )
+        enabled( true ),
+        m_loaded( false )
     {
         properties.reset();
         SetOptions( aOptions );
@@ -86,18 +87,28 @@ public:
 
     bool operator==( const LIB_TABLE_ROW& r ) const;
 
-    bool operator!=( const LIB_TABLE_ROW& r ) const   { return !( *this == r ); }
+    bool operator!=( const LIB_TABLE_ROW& r ) const { return !( *this == r ); }
 
     /**
      * @return the logical name of this library table row.
      */
-    const wxString& GetNickName() const         { return nickName; }
+    const wxString& GetNickName() const { return nickName; }
 
     /**
      * Change the logical name of this library, useful for an editor.
      */
     void SetNickName( const wxString& aNickName ) { nickName = aNickName; }
 
+    /**
+     * @return true if the library was loaded without error
+     */
+    bool GetIsLoaded() const { return m_loaded; }
+
+    /**
+     * Mark the row as being a loaded library
+     */
+    void SetLoaded( bool aLoaded ) { m_loaded = aLoaded; };
+
     /**
      * @return the enabled status of this library row
      */
@@ -183,7 +194,8 @@ protected:
 #endif
         options( aRow.options ),
         description( aRow.description ),
-        enabled( aRow.enabled )
+        enabled( aRow.enabled ),
+        m_loaded( aRow.m_loaded )
     {
         if( aRow.properties )
             properties = std::make_unique<PROPERTIES>( *aRow.properties.get() );
@@ -209,6 +221,7 @@ private:
     wxString          description;
 
     bool              enabled = true;     ///< Whether the LIB_TABLE_ROW is enabled
+    bool              m_loaded;           ///< Whether the LIB_TABLE_ROW is loaded
 
     std::unique_ptr< PROPERTIES > properties;
 };