1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2017 Chris Pavlina <pavlina.chris@gmail.com>
5  * Copyright (C) 2017-2021 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software: you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the
9  * Free Software Foundation, either version 3 of the License, or (at your
10  * option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include <generate_alias_info.h>
22 #include <string_utils.h>
23 #include <template_fieldnames.h>
24 #include <lib_symbol.h>
25 #include <symbol_lib_table.h>
26 #include <wx/log.h>
27 
28 static const wxString DescriptionFormat =
29     "<b>__NAME__</b>"
30     "__ALIASOF__"
31     "__DESC__"
32     "__KEY__"
33     "<hr><table border=0>"
34     "__FIELDS__"
35     "</table>";
36 
37 static const wxString AliasOfFormat =   "<br><i>" + _( "Alias of" ) + " %s (%s)</i>";
38 static const wxString DescFormat =      "<br>%s";
39 static const wxString KeywordsFormat =  "<br>" + _( "Keywords" ) + ": %s";
40 static const wxString FieldFormat =
41     "<tr>"
42     "   <td><b>__NAME__</b></td>"
43     "   <td>__VALUE__</td>"
44     "</tr>";
45 static const wxString DatasheetLinkFormat = "<a href=\"__HREF__\">__TEXT__</a>";
46 
47 
48 class FOOTPRINT_INFO_GENERATOR
49 {
50     wxString m_html;
51     SYMBOL_LIB_TABLE* m_sym_lib_table;
52     LIB_ID const m_lib_id;
53     LIB_SYMBOL* m_symbol;
54     int m_unit;
55 
56 public:
FOOTPRINT_INFO_GENERATOR(SYMBOL_LIB_TABLE * aSymbolLibTable,LIB_ID const & aLibId,int aUnit)57     FOOTPRINT_INFO_GENERATOR( SYMBOL_LIB_TABLE* aSymbolLibTable, LIB_ID const& aLibId, int aUnit )
58         : m_html( DescriptionFormat ),
59           m_sym_lib_table( aSymbolLibTable ),
60           m_lib_id( aLibId ),
61           m_symbol( nullptr ),
62           m_unit( aUnit )
63     { }
64 
65     /**
66      * Generate the HTML internally.
67      */
GenerateHtml()68     void GenerateHtml()
69     {
70         wxCHECK_RET( m_sym_lib_table, "Symbol library table pointer is not valid" );
71 
72         if( !m_lib_id.IsValid() )
73             return;
74 
75         try
76         {
77             m_symbol = m_sym_lib_table->LoadSymbol( m_lib_id );
78         }
79         catch( const IO_ERROR& ioe )
80         {
81             wxLogError( _( "Error loading symbol %s from library '%s'." ) + wxS( "\n%s" ),
82                         m_lib_id.GetLibItemName().wx_str(),
83                         m_lib_id.GetLibNickname().wx_str(),
84                         ioe.What() );
85             return;
86         }
87 
88         if( m_symbol )
89         {
90             SetHtmlName();
91             SetHtmlAliasOf();
92             SetHtmlDesc();
93             SetHtmlKeywords();
94             SetHtmlFieldTable();
95         }
96     }
97 
98     /**
99      * Return the generated HTML.
100      */
GetHtml() const101     wxString GetHtml() const
102     {
103         return m_html;
104     }
105 
106 protected:
SetHtmlName()107     void SetHtmlName()
108     {
109         m_html.Replace( "__NAME__", EscapeHTML( UnescapeString( m_symbol->GetName() ) ) );
110     }
111 
112 
SetHtmlAliasOf()113     void SetHtmlAliasOf()
114     {
115         if( m_symbol->IsRoot() )
116         {
117             m_html.Replace( "__ALIASOF__", wxEmptyString );
118         }
119         else
120         {
121             wxString root_name = _( "Unknown" );
122             wxString root_desc = "";
123 
124             std::shared_ptr< LIB_SYMBOL > parent = m_symbol->GetParent().lock();
125 
126             if( parent )
127             {
128                 root_name = parent->GetName();
129                 root_desc = parent->GetDescription();
130             }
131 
132             m_html.Replace( "__ALIASOF__", wxString::Format(  AliasOfFormat,
133                                                               EscapeHTML( UnescapeString( root_name ) ),
134                                                               EscapeHTML( root_desc ) ) );
135         }
136     }
137 
138 
SetHtmlDesc()139     void SetHtmlDesc()
140     {
141         wxString raw_desc = m_symbol->GetDescription();
142 
143         m_html.Replace( "__DESC__", wxString::Format( DescFormat, EscapeHTML( raw_desc ) ) );
144     }
145 
146 
SetHtmlKeywords()147     void SetHtmlKeywords()
148     {
149         wxString keywords = m_symbol->GetKeyWords();
150 
151         if( keywords.empty() )
152             m_html.Replace( "__KEY__", wxEmptyString );
153         else
154             m_html.Replace( "__KEY__", wxString::Format( KeywordsFormat, EscapeHTML( keywords ) ) );
155     }
156 
157 
GetHtmlFieldRow(const LIB_FIELD & aField) const158     wxString GetHtmlFieldRow( const LIB_FIELD& aField ) const
159     {
160         wxString name = aField.GetCanonicalName();
161         wxString text = aField.GetFullText( m_unit > 0 ? m_unit : 1 );
162         wxString fieldhtml = FieldFormat;
163 
164         fieldhtml.Replace( "__NAME__", EscapeHTML( name ) );
165 
166         switch( aField.GetId() )
167         {
168         case DATASHEET_FIELD:
169             text = m_symbol->GetDatasheetField().GetText();
170 
171             if( text.IsEmpty() || text == wxT( "~" ) )
172             {
173                 fieldhtml.Replace( "__VALUE__", text );
174             }
175             else
176             {
177                 wxString datasheetlink = DatasheetLinkFormat;
178                 datasheetlink.Replace( "__HREF__", EscapeHTML( text ) );
179 
180                 if( text.Length() > 75 )
181                     text = text.Left( 72 ) + wxT( "..." );
182 
183                 datasheetlink.Replace( "__TEXT__", EscapeHTML( text ) );
184 
185                 fieldhtml.Replace( "__VALUE__", datasheetlink );
186             }
187 
188             break;
189 
190         case VALUE_FIELD:
191             // showing the value just repeats the name, so that's not much use...
192             return wxEmptyString;
193 
194         default:
195             fieldhtml.Replace( "__VALUE__", EscapeHTML( text ) );
196         }
197 
198         return fieldhtml;
199     }
200 
201 
SetHtmlFieldTable()202     void SetHtmlFieldTable()
203     {
204         wxString                fieldtable;
205         std::vector<LIB_FIELD*> fields;
206 
207         m_symbol->GetFields( fields );
208 
209         for( const LIB_FIELD* field: fields )
210             fieldtable += GetHtmlFieldRow( *field );
211 
212         if( m_symbol->IsAlias() )
213         {
214             std::shared_ptr<LIB_SYMBOL> parent = m_symbol->GetParent().lock();
215 
216             // Append all of the unique parent fields if this is an alias.
217             if( parent )
218             {
219                 std::vector<LIB_FIELD*> parentFields;
220 
221                 parent->GetFields( parentFields );
222 
223                 for( const LIB_FIELD* parentField : parentFields )
224                 {
225                     if( m_symbol->FindField( parentField->GetCanonicalName() ) )
226                         continue;
227 
228                     fieldtable += GetHtmlFieldRow( *parentField );
229                 }
230             }
231         }
232 
233         m_html.Replace( "__FIELDS__", fieldtable );
234     }
235 };
236 
237 
GenerateAliasInfo(SYMBOL_LIB_TABLE * aSymLibTable,LIB_ID const & aLibId,int aUnit)238 wxString GenerateAliasInfo( SYMBOL_LIB_TABLE* aSymLibTable, LIB_ID const& aLibId, int aUnit )
239 {
240     FOOTPRINT_INFO_GENERATOR gen( aSymLibTable, aLibId, aUnit );
241     gen.GenerateHtml();
242     return gen.GetHtml();
243 }
244