Commit dba4fcce authored by Dick Hollenbeck's avatar Dick Hollenbeck

*) Change FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE*, const wxString*)

   To use multiple working threads.  This entailed adding KiCad typedefs:
*) Add typedefs for MUTEX and MUTLOCK which mask the actual choices for the project.
*) Add FOOTPRINT_LIST::DisplayErrors( wxWindow* ) which is a single strategy for
   showing aggregated load errors.  Although what's there is only scaffolding
   and needs a volunteer who knows HTML pretty well.
*) Ensure all callers of ReadFootprintFiles() use the new DisplayErrors() function.   
*) Push utf8.cpp and utf8.h into common library for open use.
parent 7717aa92
......@@ -141,6 +141,7 @@ set(COMMON_SRCS
selcolor.cpp
string.cpp
trigo.cpp
utf8.cpp
wildcards_and_files_ext.cpp
worksheet.cpp
wxwineda.cpp
......
......@@ -102,10 +102,10 @@ void DisplayInfoMessage( wxWindow* parent, const wxString& text, int displaytime
void DisplayHtmlInfoMessage( wxWindow* parent, const wxString& title,
const wxString& text, const wxSize& size )
{
HTML_MESSAGE_BOX *dlg = new HTML_MESSAGE_BOX(parent,title, wxDefaultPosition, size );
dlg->AddHTML_Text( text );
dlg->ShowModal();
dlg->Destroy();
HTML_MESSAGE_BOX dlg( parent, title, wxDefaultPosition, size );
dlg.AddHTML_Text( text );
dlg.ShowModal();
}
......
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 8 2012)
// C++ code generated with wxFormBuilder (version Nov 5 2013)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
......@@ -21,7 +21,7 @@ DIALOG_DISPLAY_HTML_TEXT_BASE::DIALOG_DISPLAY_HTML_TEXT_BASE( wxWindow* parent,
m_buttonClose = new wxButton( this, wxID_CANCEL, _("Close"), wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT );
m_buttonClose->SetDefault();
bMainSizer->Add( m_buttonClose, 0, wxALIGN_RIGHT|wxRIGHT|wxLEFT, 5 );
bMainSizer->Add( m_buttonClose, 0, wxALIGN_RIGHT|wxALL, 10 );
this->SetSizer( bMainSizer );
......
......@@ -20,8 +20,10 @@
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
......@@ -42,7 +44,7 @@
<property name="minimum_size">400,120</property>
<property name="name">DIALOG_DISPLAY_HTML_TEXT_BASE</property>
<property name="pos"></property>
<property name="size">431,120</property>
<property name="size">465,202</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title"></property>
......@@ -176,8 +178,8 @@
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_RIGHT|wxRIGHT|wxLEFT</property>
<property name="border">10</property>
<property name="flag">wxALIGN_RIGHT|wxALL</property>
<property name="proportion">0</property>
<object class="wxButton" expanded="1">
<property name="BottomDockable">1</property>
......
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Oct 8 2012)
// C++ code generated with wxFormBuilder (version Nov 5 2013)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
......@@ -45,7 +45,7 @@ class DIALOG_DISPLAY_HTML_TEXT_BASE : public DIALOG_SHIM
public:
wxHtmlWindow* m_htmlWindow;
DIALOG_DISPLAY_HTML_TEXT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 431,120 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
DIALOG_DISPLAY_HTML_TEXT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 465,202 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_DISPLAY_HTML_TEXT_BASE();
};
......
......@@ -27,10 +27,14 @@
*/
#define USE_WORKER_THREADS 1 // 1:yes, 0:no. use worker thread to load libraries
/*
* Functions to read footprint libraries and fill m_footprints by available footprints names
* and their documentation (comments and keywords)
*/
#include <fctsys.h>
#include <common.h>
#include <macros.h>
......@@ -40,9 +44,47 @@
#include <io_mgr.h>
#include <fp_lib_table.h>
#include <fpid.h>
#include <class_module.h>
#if defined(USE_FP_LIB_TABLE)
#include <boost/thread.hpp>
#endif
/*
wxString ToHTML( const IO_ERROR** aList, int aCount )
{
wxString msg = wxT( "<table>" );
msg += "
for( int i=0; i<aCount; ++i )
{
wxArrayString* sl = wxStringSplit( aList, wxChar( '\n' ) );
delete sl;
}
wxString msg = wxT( "<ul>" );
for ( unsigned ii = 0; ii < strings_list->GetCount(); ii++ )
{
msg += wxT( "<li>" );
msg += strings_list->Item( ii ) + wxT( "</li>" );
}
msg += wxT( "</ul>" );
m_htmlWindow->AppendToPage( msg );
delete strings_list;
}
*/
#if !defined( USE_FP_LIB_TABLE )
bool FOOTPRINT_LIST::ReadFootprintFiles( wxArrayString& aFootprintLibNames )
......@@ -50,9 +92,9 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( wxArrayString& aFootprintLibNames )
bool retv = true;
// Clear data before reading files
m_filesNotFound.Empty();
m_filesInvalid.Empty();
m_List.clear();
m_error_count = 0;
m_errors.clear();
m_list.clear();
// try
{
......@@ -80,13 +122,6 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( wxArrayString& aFootprintLibNames )
wxLogDebug( wxT( "Path <%s> -> <%s>." ), GetChars( aFootprintLibNames[ii] ),
GetChars( filename.GetFullPath() ) );
if( !filename.IsOk() || !filename.FileExists() )
{
m_filesNotFound << aFootprintLibNames[ii] << wxT( "\n" );
retv = false;
continue;
}
try
{
wxArrayString fpnames = pi->FootprintEnumerate( filename.GetFullPath() );
......@@ -111,37 +146,133 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( wxArrayString& aFootprintLibNames )
AddItem( fpinfo );
}
}
catch( IO_ERROR ioe )
catch( const PARSE_ERROR& pe )
{
m_filesInvalid << ioe.errorText << wxT( "\n" );
m_errors.push_back( new PARSE_ERROR( pe ) );
retv = false;
}
catch( const IO_ERROR& ioe )
{
m_errors.push_back( new IO_ERROR( ioe ) );
retv = false;
}
}
}
/* caller should catch this, UI seems not wanted here.
catch( IO_ERROR ioe )
catch( const IO_ERROR& ioe )
{
DisplayError( NULL, ioe.errorText );
return false;
}
*/
m_List.sort();
m_list.sort();
return retv;
}
#else
#else // yes USE_FP_LIB_TABLE, by all means:
#if USE_WORKER_THREADS //---------------------------------------------------------------------
#define USE_WORKER_THREADS 1 // 1:yes, 0:no. use worker threads to load libraries
#define JOBZ 6 // no. libraries per worker thread. It takes about
// a second to load a GITHUB library, so assigning
// this no. libraries to each thread should give a little
// over this no. seconds total time if the original delay
// were caused by latencies alone.
// (If https://github.com does not mind.)
#define NTOLERABLE_ERRORS 4 // max errors before aborting, although threads
// in progress will still pile on for a bit. e.g. if 9 threads
// expect 9 greater than this.
void FOOTPRINT_LIST::loader_job( const wxString* aNicknameList, int aJobZ )
{
//DBG(printf( "%s: first:'%s' count:%d\n", __func__, (char*) TO_UTF8( *aNicknameList ), aJobZ );)
for( int i=0; i<aJobZ; ++i )
{
if( m_error_count >= NTOLERABLE_ERRORS )
break;
const wxString& nickname = aNicknameList[i];
try
{
wxArrayString fpnames = m_lib_table->FootprintEnumerate( nickname );
for( unsigned ni=0; ni<fpnames.GetCount(); ++ni )
{
std::auto_ptr<MODULE> m( m_lib_table->FootprintLoad( nickname, fpnames[ni] ) );
FOOTPRINT_INFO* fpinfo = new FOOTPRINT_INFO();
fpinfo->SetNickname( nickname );
fpinfo->m_Module = fpnames[ni];
fpinfo->m_padCount = m->GetPadCount( MODULE::DO_NOT_INCLUDE_NPTH );
fpinfo->m_KeyWord = m->GetKeywords();
fpinfo->m_Doc = m->GetDescription();
AddItem( fpinfo );
}
}
catch( const PARSE_ERROR& pe )
{
// push_back is not thread safe, use the lock the MUTEX.
MUTLOCK lock( m_errors_lock );
++m_error_count; // modify only under lock
m_errors.push_back( new IO_ERROR( pe ) );
}
catch( const IO_ERROR& ioe )
{
MUTLOCK lock( m_errors_lock );
++m_error_count;
m_errors.push_back( new IO_ERROR( ioe ) );
}
// Catch anything unexpected and map it into the expected.
// Likely even more important since this function runs on GUI-less
// worker threads.
catch( const std::exception& se )
{
// this is a round about way to do this, but who knows what THROW_IO_ERROR()
// may be tricked out to do someday, keep it in the game.
try
{
THROW_IO_ERROR( se.what() );
}
catch( const IO_ERROR& ioe )
{
MUTLOCK lock( m_errors_lock );
++m_error_count;
m_errors.push_back( new IO_ERROR( ioe ) );
}
}
}
}
#endif // USE_WORKER_THREADS ---------------------------------------------------
bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname )
{
bool retv = true;
m_lib_table = aTable;
// Clear data before reading files
m_filesNotFound.Empty();
m_filesInvalid.Empty();
m_List.clear();
m_error_count = 0;
m_errors.clear();
m_list.clear();
std::vector< wxString > nicknames;
......@@ -149,8 +280,68 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* a
// do all of them
nicknames = aTable->GetLogicalLibs();
else
// single footprint
nicknames.push_back( *aNickname );
#if USE_WORKER_THREADS
// Something which will not invoke a thread copy constructor, one of many ways obviously:
typedef boost::ptr_vector< boost::thread > MYTHREADS;
MYTHREADS threads;
// Give each thread JOBZ nicknames to process. The last portion of, or if the entire
// size() is small, I'll do myself.
for( unsigned i=0; i<nicknames.size(); )
{
if( m_error_count >= NTOLERABLE_ERRORS )
{
// abort the remaining nicknames.
retv = false;
break;
}
int jobz = JOBZ;
if( i + jobz >= nicknames.size() )
{
jobz = nicknames.size() - i;
// Only a little bit to do, I'll do it myself, on current thread.
// This is the path for a single footprint also.
loader_job( &nicknames[i], jobz );
}
else
{
// Delegate the job to a worker thread created here.
threads.push_back( new boost::thread( &FOOTPRINT_LIST::loader_job,
this, &nicknames[i], jobz ) );
}
i += jobz;
}
// Wait for all the worder threads to complete, it does not matter in what order
// we wait for them as long as a full sweep is made. Think of the great race,
// everyone must finish.
for( unsigned i=0; i<threads.size(); ++i )
{
threads[i].join();
}
m_list.sort();
// The result of this function can be a blend of successes and failures, whose
// mix is given by the Count()s of the two lists. The return value indicates whether
// an abort occurred, even true does not necessarily mean full success, although
// false definitely means failure.
return retv;
#else
bool retv = true;
for( unsigned ii = 0; ii < nicknames.size(); ii++ )
{
const wxString& nickname = nicknames[ii];
......@@ -178,23 +369,44 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* a
AddItem( fpinfo );
}
}
catch( IO_ERROR ioe )
catch( const PARSE_ERROR& pe )
{
m_filesInvalid << ioe.errorText << wxT( "\n" );
m_errors.push_back( new IO_ERROR( pe ) );
retv = false;
}
catch( const IO_ERROR& ioe )
{
m_errors.push_back( new IO_ERROR( ioe ) );
retv = false;
}
}
m_List.sort();
m_list.sort();
return retv;
#endif
}
#endif // USE_FP_LIB_TABLE
FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString& aFootprintName )
void FOOTPRINT_LIST::AddItem( FOOTPRINT_INFO* aItem )
{
#if defined( USE_FP_LIB_TABLE )
// m_list is not thread safe, and this function is called from
// worker threads, lock m_list.
MUTLOCK lock( m_list_lock );
#endif
m_list.push_back( aItem );
}
const FOOTPRINT_INFO* FOOTPRINT_LIST::GetModuleInfo( const wxString& aFootprintName )
{
BOOST_FOREACH( FOOTPRINT_INFO& footprint, m_List )
BOOST_FOREACH( const FOOTPRINT_INFO& footprint, m_list )
{
#if defined( USE_FP_LIB_TABLE )
FPID fpid;
......@@ -243,3 +455,45 @@ bool FOOTPRINT_INFO::InLibrary( const wxString& aLibrary ) const
return filename.GetFullPath() == m_lib_path;
#endif
}
#include <confirm.h> // until scaffolding goes.
void FOOTPRINT_LIST::DisplayErrors( wxTopLevelWindow* aWindow )
{
#if 1
// scaffolding until a better one is written, hopefully below.
DBG(printf( "m_error_count:%d\n", m_error_count );)
wxString msg = _( "Errors were encountered loading footprints" );
msg += wxT( '\n' );
for( unsigned i = 0; i<m_errors.size(); ++i )
{
msg += m_errors[i].errorText;
msg += wxT( '\n' );
}
DisplayError( aWindow, msg );
#else // real evolving deal:
// @todo: go to a more HTML !<table>! ? centric output, possibly with
// recommendations for remedy of errors. Add numeric error codes
// to PARSE_ERROR, and switch on them for remedies, etc. Full
// access is provided to everything in every exception!
HTML_MESSAGE_BOX dlg( aWindow, _( "Load Error" ) );
dlg.MessageSet( _( "Errors were encountered loading footprints" ) );
wxString msg = my html wizardry.
dlg.AddHTML_Text( msg );
dlg.ShowModal();
#endif
}
......@@ -637,13 +637,34 @@ const FP_LIB_TABLE::ROW* FP_LIB_TABLE::FindRow( const wxString& aNickname )
}
// wxGetenv( wchar_t* ) is not re-entrant on linux.
// Put a lock on multithreaded use of wxGetenv( wchar_t* ), called from wxEpandEnvVars(),
// needed by bool ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname = NULL );
#if 1
#include <ki_mutex.h>
const wxString FP_LIB_TABLE::ExpandSubstitutions( const wxString& aString )
{
static MUTEX getenv_mutex;
MUTLOCK lock( getenv_mutex );
// We reserve the right to do this another way, by providing our own member
// function.
return wxExpandEnvVars( aString );
}
#else
const wxString FP_LIB_TABLE::ExpandSubstitutions( const wxString& aString )
{
// We reserve the right to do this another way, by providing our own member
// function.
return wxExpandEnvVars( aString );
}
#endif
bool FP_LIB_TABLE::IsEmpty( bool aIncludeFallback )
{
......
#include <fctsys.h>
#include <html_messagebox.h>
#include <macros.h>
#include <common.h>
HTML_MESSAGE_BOX::HTML_MESSAGE_BOX( wxWindow* parent, const wxString & aTitle,
wxPoint aPos, wxSize aSize)
: DIALOG_DISPLAY_HTML_TEXT_BASE( parent, wxID_ANY, aTitle, aPos, aSize )
HTML_MESSAGE_BOX::HTML_MESSAGE_BOX( wxWindow* parent, const wxString& aTitle,
wxPoint aPos, wxSize aSize) :
DIALOG_DISPLAY_HTML_TEXT_BASE( parent, wxID_ANY, aTitle, aPos, aSize )
{
ListClear();
Center();
}
void HTML_MESSAGE_BOX::OnCloseButtonClick( wxCommandEvent& event )
{
EndModal(0);
EndModal( 0 );
}
void HTML_MESSAGE_BOX::ListClear(void)
void HTML_MESSAGE_BOX::ListClear()
{
m_htmlWindow->SetPage(wxEmptyString);
m_htmlWindow->SetPage( wxEmptyString );
}
/**
* Function ListSet
* Add a list of items.
* @param aList = a string containing items. Items are separated by '\n'
*/
void HTML_MESSAGE_BOX::ListSet(const wxString &aList)
void HTML_MESSAGE_BOX::ListSet( const wxString& aList )
{
wxArrayString* wxStringSplit( wxString txt, wxChar splitter );
// wxArrayString* wxStringSplit( wxString txt, wxChar splitter );
wxArrayString* strings_list = wxStringSplit( aList, wxChar( '\n' ) );
wxArrayString* strings_list = wxStringSplit( aList, wxChar('\n') );
wxString msg = wxT("<ul>");
for ( unsigned ii = 0; ii < strings_list->GetCount(); ii ++ )
wxString msg = wxT( "<ul>" );
for ( unsigned ii = 0; ii < strings_list->GetCount(); ii++ )
{
msg += wxT("<li>");
msg += strings_list->Item(ii) + wxT("</li>");
msg += wxT( "<li>" );
msg += strings_list->Item( ii ) + wxT( "</li>" );
}
msg += wxT("</ul>");
msg += wxT( "</ul>" );
m_htmlWindow->AppendToPage( msg );
delete strings_list;
}
/**
* Function ListSet
* Add a list of items.
* @param aList = a wxArrayString containing items
*/
void HTML_MESSAGE_BOX::ListSet(const wxArrayString &aList)
void HTML_MESSAGE_BOX::ListSet( const wxArrayString& aList )
{
wxString msg = wxT("<ul>");
for ( unsigned ii = 0; ii < aList.GetCount(); ii ++ )
wxString msg = wxT( "<ul>" );
for( unsigned ii = 0; ii < aList.GetCount(); ii++ )
{
msg += wxT("<li>");
msg += aList.Item(ii) + wxT("</li>");
msg += wxT( "<li>" );
msg += aList.Item( ii ) + wxT( "</li>" );
}
msg += wxT("</ul>");
msg += wxT( "</ul>" );
m_htmlWindow->AppendToPage( msg );
}
/**
* Function MessageSet
* Add a message (in bold) to message list.
* @param message = the message
*/
void HTML_MESSAGE_BOX::MessageSet(const wxString &message)
void HTML_MESSAGE_BOX::MessageSet( const wxString& message )
{
wxString message_value;
message_value.Printf(wxT("<b>%s</b><br>"), GetChars( message ) );
wxString message_value = wxString::Format(
wxT( "<b>%s</b><br>" ), GetChars( message ) );
m_htmlWindow->AppendToPage( message_value );
}
/**
* Function AddHTML_Text
* Add a text to message list.
* @param message = the text to add
*/
void HTML_MESSAGE_BOX::AddHTML_Text(const wxString &message)
void HTML_MESSAGE_BOX::AddHTML_Text( const wxString& message )
{
m_htmlWindow->AppendToPage( message );
}
......
#include <stdio.h>
#include <string>
#include <wx/string.h>
#include <assert.h>
/**
* Class UTF8
* is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special
* conversion support to and from wxString, and has iteration over unicode characters.
*
* <p>I've been careful to supply only conversion facilities and not try
* and duplicate wxString() with many member functions. In the end it is
* to be a std::string. There are multiple ways to create text into a std::string
* without the need of too many member functions:
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* <ul>
* <li>richio.h's StrPrintf()</li>
* <li>std::ostringstream.</li>
* </ul>
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* <p>Because this class used no virtuals, it should be possible to cast any
* std::string into a UTF8 using this kind of cast: (UTF8 &) without construction
* or copying being the effect of the cast. Be sure the source std::string holds
* UTF8 encoded text before you do that.
* 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.
*
* @author Dick Hollenbeck
*/
class UTF8 : public std::string
{
public:
UTF8( const wxString& o );
/// This is the only constructor for which you could end up with
/// non-UTF8 encoding, but that would be your fault.
UTF8( const char* txt ) :
std::string( txt )
{
}
/// For use with _() function on wx 2.8:
UTF8( const wchar_t* txt );
explicit UTF8( const std::string& o ) :
std::string( o )
{
}
UTF8() :
std::string()
{
}
UTF8& operator=( const wxString& o );
UTF8& operator=( const std::string& o )
{
std::string::operator=( o );
return *this;
}
operator wxString () const;
/// This one is not in std::string, and one wonders why... might be a solid
/// enough reason to remove it still.
operator char* () const
{
return (char*) c_str();
}
/**
* Function uni_forward
* advances over a single UTF8 encoded multibyte character, capturing the
* unicode character as it goes, and returning the number of bytes consumed.
* 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.
*
* @param aSequence is the UTF8 byte sequence, must be aligned on start of character.
* @param aResult is where to put the unicode character, and may be NULL if no interest.
* @return int - the count of bytes consumed.
*/
static int uni_forward( const unsigned char* aSequence, unsigned* aResult = NULL );
/**
* class uni_iter
* is a non-muting iterator that walks through unicode code points in the UTF8 encoded
* string. The normal ++(), ++(int), ->(), and *() operators are all supported
* for read only access and they return an unsigned holding the unicode character
* appropriate for the respective operator.
* 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
*/
class uni_iter
{
friend class UTF8;
const unsigned char* it;
// private constructor.
uni_iter( const char* start ) :
it( (const unsigned char*) start )
{
// for the human: assert( sizeof(unsigned) >= 4 );
}
public:
uni_iter( const uni_iter& o )
{
it = o.it;
}
/// pre-increment and return uni_iter at new position
const uni_iter& operator++()
{
it += uni_forward( it );
return *this;
}
/// post-increment and return uni_iter at initial position
uni_iter operator++( int )
{
uni_iter ret = *this;
it += uni_forward( it );
return ret;
}
/*
/// return unicode at current position
unsigned operator->() const
{
unsigned result;
// grab the result, do not advance
uni_forward( it, &result );
return result;
}
*/
/// return unicode at current position
unsigned operator*() const
{
unsigned result;
// grab the result, do not advance
uni_forward( it, &result );
return result;
}
bool operator==( const uni_iter& other ) const { return it == other.it; }
bool operator!=( const uni_iter& other ) const { return it != other.it; }
/// Since the ++ operators advance more than one byte, this is your best
/// loop termination test, < end(), not == end().
bool operator< ( const uni_iter& other ) const { return it < other.it; }
bool operator<=( const uni_iter& other ) const { return it <= other.it; }
bool operator> ( const uni_iter& other ) const { return it > other.it; }
bool operator>=( const uni_iter& other ) const { return it >= other.it; }
};
/**
* Function ubegin
* returns a @a uni_iter initialized to the start of "this" UTF8 byte sequence.
*/
uni_iter ubegin() const
{
return uni_iter( data() );
}
/**
* Function uend
* returns a @a uni_iter initialized to the end of "this" UTF8 byte sequence.
*/
uni_iter uend() const
{
return uni_iter( data() + size() );
}
};
wxString wxFunctionTaking_wxString( const wxString& wx )
{
printf( "%s:'%s'\n", __func__, (char*) UTF8( wx ) );
printf( "%s:'%s'\n", __func__, (const char*) UTF8( wx ) );
printf( "%s:'%s'\n", __func__, UTF8( wx ).c_str() );
return wx;
}
int main()
{
std::string str = "input";
UTF8 u0 = L"wide string";
UTF8 u1 = "initial";
wxString wx = wxT( "input2" );
printf( "u0:'%s'\n", u0.c_str() );
printf( "u1:'%s'\n", u1.c_str() );
u1 = str;
wxString wx2 = u1;
// force a std::string into a UTF8, then into a wxString, then copy construct:
wxString wx3 = (UTF8&) u1;
UTF8 u2 = wx2;
u2 += 'X';
printf( "u2:'%s'\n", u2.c_str() );
// key accomplishments here:
// 1) passing a UTF8 to a function which normally takes a wxString.
// 2) return a wxString back into a UTF8.
UTF8 result = wxFunctionTaking_wxString( u2 );
printf( "result:'%s'\n", result.c_str() );
// test the unicode iterator:
for( UTF8::uni_iter it = u2.ubegin(); it < u2.uend(); )
{
// test post-increment:
printf( " _%c_", *it++ );
// after UTF8::uni_forward() is implemented, %c is no longer useable.
// printf( " _%02x_", *it++ );
}
printf( "\n" );
UTF8::uni_iter it = u2.ubegin();
UTF8::uni_iter it2 = it++;
printf( "post_inc:'%c' should be 'i'\n", *it2 );
it2 = ++it;
printf( "pre_inc:'%c' should be 'p'\n", *it2 );
printf( "u[1]:'%c' should be 'n'\n", u2[1] );
#include <utf8.h>
return 0;
}
/* THROW_IO_ERROR needs this, but it will soon be including this file, so until some
factoring of THROW_IO_ERROR into a separate header, defer and use the asserts.
#include <richio.h>
*/
#include <assert.h>
/*
These to go into a library *.cpp, they are not inlined so that significant
code space is saved by encapsulating the creation of intermediate objects
and referencing wxConvUTF8.
These are not inlined so that code space is saved by encapsulating the
creation of intermediate objects and referencing wxConvUTF8.
*/
......@@ -405,3 +185,76 @@ UTF8::UTF8( const wchar_t* txt ) :
resize( sz );
}
#if 0 // some unit tests:
#include <stdio.h>
wxString wxFunctionTaking_wxString( const wxString& wx )
{
printf( "%s:'%s'\n", __func__, (char*) UTF8( wx ) );
printf( "%s:'%s'\n", __func__, (const char*) UTF8( wx ) );
printf( "%s:'%s'\n", __func__, UTF8( wx ).c_str() );
return wx;
}
int main()
{
std::string str = "input";
UTF8 u0 = L"wide string";
UTF8 u1 = "initial";
wxString wx = wxT( "input2" );
printf( "u0:'%s'\n", u0.c_str() );
printf( "u1:'%s'\n", u1.c_str() );
u1 = str;
wxString wx2 = u1;
// force a std::string into a UTF8, then into a wxString, then copy construct:
wxString wx3 = (UTF8&) u1;
UTF8 u2 = wx2;
u2 += 'X';
printf( "u2:'%s'\n", u2.c_str() );
// key accomplishments here:
// 1) passing a UTF8 to a function which normally takes a wxString.
// 2) return a wxString back into a UTF8.
UTF8 result = wxFunctionTaking_wxString( u2 );
printf( "result:'%s'\n", result.c_str() );
// test the unicode iterator:
for( UTF8::uni_iter it = u2.ubegin(); it < u2.uend(); )
{
// test post-increment:
printf( " _%c_", *it++ );
// after UTF8::uni_forward() is implemented, %c is no longer useable.
// printf( " _%02x_", *it++ );
}
printf( "\n" );
UTF8::uni_iter it = u2.ubegin();
UTF8::uni_iter it2 = it++;
printf( "post_inc:'%c' should be 'i'\n", *it2 );
it2 = ++it;
printf( "pre_inc:'%c' should be 'p'\n", *it2 );
printf( "u[1]:'%c' should be 'n'\n", u2[1] );
return 0;
}
#endif
......@@ -176,7 +176,7 @@ void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event )
/* filter alias so one can use multiple aliases (for polar and nonpolar caps for
* example) */
FOOTPRINT_INFO *module = m_footprints.GetModuleInfo( alias.m_FootprintName );
const FOOTPRINT_INFO *module = m_footprints.GetModuleInfo( alias.m_FootprintName );
if( module )
{
......@@ -210,7 +210,7 @@ void CVPCB_MAINFRAME::AssocieModule( wxCommandEvent& event )
{
/* we do not need to analyse wildcards: single footprint do not contain them */
/* and if there are wildcards it just will not match any */
FOOTPRINT_INFO *module = m_footprints.GetModuleInfo( component->GetFootprintFilters()[0] );
const FOOTPRINT_INFO* module = m_footprints.GetModuleInfo( component->GetFootprintFilters()[0] );
if( module )
{
......
......@@ -558,9 +558,9 @@ void DISPLAY_FOOTPRINTS_FRAME::InitDisplay()
msg.Printf( _( "Footprint: %s" ), GetChars( footprintName ) );
SetTitle( msg );
FOOTPRINT_INFO* module_info = parentframe->m_footprints.GetModuleInfo( footprintName );
const FOOTPRINT_INFO* module_info = parentframe->m_footprints.GetModuleInfo( footprintName );
const wxChar *libname;
const wxChar* libname;
if( module_info )
libname = GetChars( module_info->GetNickname() );
......
......@@ -704,7 +704,8 @@ void CVPCB_MAINFRAME::DisplayStatus()
else
{
wxString footprintName = m_FootprintList->GetSelectedFootprint();
FOOTPRINT_INFO* module = m_footprints.GetModuleInfo( footprintName );
const FOOTPRINT_INFO* module = m_footprints.GetModuleInfo( footprintName );
if( module ) // can be NULL if no netlist loaded
{
......@@ -716,7 +717,6 @@ void CVPCB_MAINFRAME::DisplayStatus()
}
}
msg.Empty();
if( m_FootprintList )
......@@ -769,26 +769,9 @@ bool CVPCB_MAINFRAME::LoadFootprintFiles()
m_footprints.ReadFootprintFiles( m_footprintLibTable );
#endif
// Display error messages, if any.
if( !m_footprints.m_filesNotFound.IsEmpty() || !m_footprints.m_filesInvalid.IsEmpty() )
if( m_footprints.GetErrorCount() )
{
HTML_MESSAGE_BOX dialog( this, _( "Load Error" ) );
if( !m_footprints.m_filesNotFound.IsEmpty() )
{
wxString message = _( "Some files could not be found!" );
dialog.MessageSet( message );
dialog.ListSet( m_footprints.m_filesNotFound );
}
// Display if there are invalid files.
if( !m_footprints.m_filesInvalid.IsEmpty() )
{
dialog.MessageSet( _( "Some files are invalid!" ) );
dialog.ListSet( m_footprints.m_filesInvalid );
}
dialog.ShowModal();
m_footprints.DisplayErrors( this );
}
return true;
......
......@@ -33,10 +33,15 @@
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/foreach.hpp>
#if defined( USE_FP_LIB_TABLE )
#include <ki_mutex.h>
#endif
#include <kicad_string.h>
class FP_LIB_TABLE;
class wxTopLevelWindow;
/*
......@@ -106,64 +111,103 @@ inline bool operator<( const FOOTPRINT_INFO& item1, const FOOTPRINT_INFO& item2
}
/**
* Class FOOTPRINT_LIST
* holds a list of FOOTPRINT_INFO objects, along with a list of IO_ERRORs or
* PARSE_ERRORs that were thrown acquiring the FOOTPRINT_INFOs.
*/
class FOOTPRINT_LIST
{
public:
boost::ptr_vector< FOOTPRINT_INFO > m_List;
wxString m_filesNotFound;
wxString m_filesInvalid;
FP_LIB_TABLE* m_lib_table; ///< no ownership
volatile int m_error_count; ///< thread safe to read.
typedef boost::ptr_vector< FOOTPRINT_INFO > FPILIST;
typedef boost::ptr_vector< IO_ERROR > ERRLIST;
FPILIST m_list;
ERRLIST m_errors; ///< some can be PARSE_ERRORs also
#if defined( USE_FP_LIB_TABLE )
MUTEX m_errors_lock;
MUTEX m_list_lock;
#endif
/**
* Function loader_job
* loads footprints from @a aNicknameList and calls AddItem() on to help fill
* m_list.
*
* @param aNicknameList is a wxString[] holding libraries to load all footprints from.
* @param aJobZ is the size of the job, i.e. the count of nicknames.
*/
void loader_job( const wxString* aNicknameList, int aJobZ );
public:
FOOTPRINT_LIST() :
m_lib_table( 0 ),
m_error_count( 0 )
{
}
/**
* Function GetCount
* @return the number of items stored in list
*/
unsigned GetCount() const { return m_List.size(); }
unsigned GetCount() const { return m_list.size(); }
/// Was forced to add this by modview_frame.cpp
const FPILIST& GetList() const { return m_list; }
/**
* Function GetModuleInfo
* @return the item stored in list if found
* @param aFootprintName = the name of item
* @param aFootprintName = the footprint name inside the FOOTPRINT_INFO of interest.
* @return const FOOTPRINT_INF* - the item stored in list if found
*/
FOOTPRINT_INFO* GetModuleInfo( const wxString & aFootprintName );
const FOOTPRINT_INFO* GetModuleInfo( const wxString& aFootprintName );
/**
* Function GetItem
* @return the aIdx item in list
* @param aIdx = index of the given item
* @return the aIdx item in list
*/
FOOTPRINT_INFO & GetItem( unsigned aIdx )
{
return m_List[aIdx];
}
const FOOTPRINT_INFO& GetItem( unsigned aIdx ) const { return m_list[aIdx]; }
/**
* Function AddItem
* add aItem in list
* @param aItem = item to add
*/
void AddItem( FOOTPRINT_INFO* aItem )
{
m_List.push_back( aItem );
}
void AddItem( FOOTPRINT_INFO* aItem );
unsigned GetErrorCount() const { return m_errors.size(); }
const IO_ERROR* GetError( unsigned aIdx ) const { return &m_errors[aIdx]; }
#if !defined( USE_FP_LIB_TABLE )
/**
* Function ReadFootprintFiles
*
* @param aFootprintsLibNames = an array string giving the list of libraries to load
*/
bool ReadFootprintFiles( wxArrayString& aFootprintsLibNames );
#endif
/**
* Function ReadFootprintFiles
* reads all the footprints provided by the combination of aTable and aNickname.
*
* @param aTable defines all the libraries.
* @param aNickname is the library to read from, or if NULL means read all
* footprints from all known libraries.
* footprints from all known libraries in aTable.
* @return bool - true if it ran to completion, else false if it aborted after
* some number of errors. If true, it does not mean there were no errors, check
* GetErrorCount() for that, should be zero to indicate success.
*/
bool ReadFootprintFiles( FP_LIB_TABLE* aTable, const wxString* aNickname = NULL );
void DisplayErrors( wxTopLevelWindow* aCaller = NULL );
};
#endif // FOOTPRINT_INFO_H_
#ifndef _html_messagebox_
#define _html_messagebox_
/**
@file
Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
......@@ -8,7 +9,10 @@ Subclass of DIALOG_DISPLAY_HTML_TEXT_BASE, which is generated by wxFormBuilder.
#include <../common/dialogs/dialog_display_info_HTML_base.h>
/** Implementing HTML_MESSAGE_BOX */
/**
* Class HTML_MESSAGE_BOX
*/
class HTML_MESSAGE_BOX : public DIALOG_DISPLAY_HTML_TEXT_BASE
{
protected:
......@@ -16,8 +20,10 @@ protected:
void OnCloseButtonClick( wxCommandEvent& event );
public:
/** Constructor */
HTML_MESSAGE_BOX( wxWindow* parent, const wxString & aTitle,
/**
* Constructor
*/
HTML_MESSAGE_BOX( wxWindow* parent, const wxString& aTitle,
wxPoint aPos = wxDefaultPosition,
wxSize aSize = wxSize( 450,250 ) );
......@@ -26,28 +32,30 @@ public:
* Add a list of items.
* @param aList = a string containing items. Items are separated by '\n'
*/
void ListSet(const wxString &aList);
void ListSet( const wxString& aList );
/**
* Function ListSet
* Add a list of items.
* @param aList = a wxArrayString containing items.
*/
void ListSet(const wxArrayString &aList);
void ListSet( const wxArrayString& aList );
void ListClear();
/**
* Function MessageSet
* Add a message (in bold) to message list.
* adds a message (in bold) to message list.
* @param message = the message
*/
void MessageSet(const wxString &message);
void MessageSet( const wxString& message );
/**
* Function AddHTML_Text
* Add a html text (without any change) to message list.
* adds html text (without any change) to message list.
* @param message = the text to add
*/
void AddHTML_Text(const wxString &message);
void AddHTML_Text( const wxString& message );
};
#endif // _html_messagebox_
#ifndef KI_MUTEX_H_
#define KI_MUTEX_H_
/// Establish KiCad MUTEX choices here in this file:
/// typedef MUTEX and typedef MUTLOCK.
///
/// Using an unnamed resource is easier, providing a textual name for a
/// constructor is cumbersome, so we make choice on that criteria mostly:
#if 0
// This is a fine choice between the two, but requires linking to ${Boost_LIBRARIES}
// which currently only happens when GITHUB_PLUGIN goes into pcbnew or _pcbnew.
// cvpcb is left out. Changing the 4 CMakeLists.txts fixes all this easily.
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
typedef boost::interprocess::interprocess_mutex MUTEX;
typedef boost::interprocess::scoped_lock<MUTEX> MUTLOCK;
#else
#include <wx/thread.h>
typedef wxMutex MUTEX;
typedef wxMutexLocker MUTLOCK;
#endif
#endif // KI_MUTEX_H_
......@@ -93,7 +93,7 @@ std::string
/**
* Struct IO_ERROR
* is a class used to hold an error message and may be used to throw exceptions
* is a class used to hold an error message and may be used when throwing exceptions
* containing meaningful error messages.
* @author Dick Hollenbeck
*/
......@@ -148,7 +148,9 @@ struct IO_ERROR // : std::exception
IO_ERROR() {}
~IO_ERROR() throw ( /*none*/ ){}
// Destructor is virtual because PARSE_ERROR is derived from it and
// boost::ptr_vector lists consisting of both will need a virtual destructor.
virtual ~IO_ERROR() throw ( /*none*/ ){}
};
......
#ifndef UTF8_H_
#define UTF8_H_
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
* Copyright (C) 2013 KiCad Developers, see CHANGELOG.TXT for contributors.
*
* 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
*/
#include <string>
#include <wx/string.h>
/**
* Class UTF8
* is an 8 bit std::string that is assuredly encoded in UTF8, and supplies special
* conversion support to and from wxString, and has iteration over unicode characters.
*
* <p>I've been careful to supply only conversion facilities and not try
* and duplicate wxString() with many member functions. In the end it is
* to be a std::string. There are multiple ways to create text into a std::string
* without the need of too many member functions:
*
* <ul>
* <li>richio.h's StrPrintf()</li>
* <li>std::ostringstream.</li>
* </ul>
*
* <p>Because this class used no virtuals, it should be possible to cast any
* std::string into a UTF8 using this kind of cast: (UTF8 &) without construction
* or copying being the effect of the cast. Be sure the source std::string holds
* UTF8 encoded text before you do that.
*
* @author Dick Hollenbeck
*/
class UTF8 : public std::string
{
public:
UTF8( const wxString& o );
/// This is the only constructor for which you could end up with
/// non-UTF8 encoding, but that would be your fault.
UTF8( const char* txt ) :
std::string( txt )
{
}
/// For use with _() function on wx 2.8:
UTF8( const wchar_t* txt );
explicit UTF8( const std::string& o ) :
std::string( o )
{
}
UTF8() :
std::string()
{
}
UTF8& operator=( const wxString& o );
UTF8& operator=( const std::string& o )
{
std::string::operator=( o );
return *this;
}
operator wxString () const;
/// This one is not in std::string, and one wonders why... might be a solid
/// enough reason to remove it still.
operator char* () const
{
return (char*) c_str();
}
/**
* Function uni_forward
* advances over a single UTF8 encoded multibyte character, capturing the
* unicode character as it goes, and returning the number of bytes consumed.
*
* @param aSequence is the UTF8 byte sequence, must be aligned on start of character.
* @param aResult is where to put the unicode character, and may be NULL if no interest.
* @return int - the count of bytes consumed.
*/
static int uni_forward( const unsigned char* aSequence, unsigned* aResult = NULL );
/**
* class uni_iter
* is a non-muting iterator that walks through unicode code points in the UTF8 encoded
* string. The normal ++(), ++(int), ->(), and *() operators are all supported
* for read only access and they return an unsigned holding the unicode character
* appropriate for the respective operator.
*/
class uni_iter
{
friend class UTF8;
const unsigned char* it;
// private constructor.
uni_iter( const char* start ) :
it( (const unsigned char*) start )
{
// for the human: assert( sizeof(unsigned) >= 4 );
}
public:
uni_iter( const uni_iter& o )
{
it = o.it;
}
/// pre-increment and return uni_iter at new position
const uni_iter& operator++()
{
it += uni_forward( it );
return *this;
}
/// post-increment and return uni_iter at initial position
uni_iter operator++( int )
{
uni_iter ret = *this;
it += uni_forward( it );
return ret;
}
/*
/// return unicode at current position
unsigned operator->() const
{
unsigned result;
// grab the result, do not advance
uni_forward( it, &result );
return result;
}
*/
/// return unicode at current position
unsigned operator*() const
{
unsigned result;
// grab the result, do not advance
uni_forward( it, &result );
return result;
}
bool operator==( const uni_iter& other ) const { return it == other.it; }
bool operator!=( const uni_iter& other ) const { return it != other.it; }
/// Since the ++ operators advance more than one byte, this is your best
/// loop termination test, < end(), not == end().
bool operator< ( const uni_iter& other ) const { return it < other.it; }
bool operator<=( const uni_iter& other ) const { return it <= other.it; }
bool operator> ( const uni_iter& other ) const { return it > other.it; }
bool operator>=( const uni_iter& other ) const { return it >= other.it; }
};
/**
* Function ubegin
* returns a @a uni_iter initialized to the start of "this" UTF8 byte sequence.
*/
uni_iter ubegin() const
{
return uni_iter( data() );
}
/**
* Function uend
* returns a @a uni_iter initialized to the end of "this" UTF8 byte sequence.
*/
uni_iter uend() const
{
return uni_iter( data() + size() );
}
};
#endif // UTF8_H__
......@@ -38,10 +38,10 @@ double UNIT_SELECTOR_LEN::GetUnitScale()
}
UNIT_SELECTOR_FREQUENCY::UNIT_SELECTOR_FREQUENCY(wxWindow *parent, wxWindowID id,
UNIT_SELECTOR_FREQUENCY::UNIT_SELECTOR_FREQUENCY( wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size,
const wxArrayString& choices, long style )
: UNIT_SELECTOR( parent, id, pos, size, choices, style )
const wxArrayString& choices, long style ):
UNIT_SELECTOR( parent, id, pos, size, choices, style )
{
Append( _("GHz") );
Append( _("MHz") );
......@@ -58,19 +58,19 @@ double UNIT_SELECTOR_FREQUENCY::GetUnitScale()
{
switch( GetCurrentSelection() )
{
case 0: return UNIT_GHZ; break;
case 1: return UNIT_MHZ; break;
case 2: return UNIT_KHZ; break;
case 3: return 1.0; break;
case 0: return UNIT_GHZ;
case 1: return UNIT_MHZ;
case 2: return UNIT_KHZ;
case 3: return 1.0;
}
return 1.0;
}
UNIT_SELECTOR_ANGLE::UNIT_SELECTOR_ANGLE(wxWindow *parent, wxWindowID id,
UNIT_SELECTOR_ANGLE::UNIT_SELECTOR_ANGLE( wxWindow *parent, wxWindowID id,
const wxPoint& pos, const wxSize& size,
const wxArrayString& choices, long style )
: UNIT_SELECTOR( parent, id, pos, size, choices, style )
const wxArrayString& choices, long style ) :
UNIT_SELECTOR( parent, id, pos, size, choices, style )
{
Append( _("Radian") );
Append( _("Degree") );
......
......@@ -537,18 +537,11 @@ wxString PCB_BASE_FRAME::SelectFootprint( EDA_DRAW_FRAME* aWindow,
wxASSERT( aTable != NULL );
if( !MList.ReadFootprintFiles( aTable, !aLibraryName ? NULL : &aLibraryName ) )
{
msg.Format( _( "Error occurred attempting to load footprint library '%s':\n\n" ),
GetChars( aLibraryName ) );
if( !MList.m_filesNotFound.IsEmpty() )
msg += _( "Files not found:\n\n" ) + MList.m_filesNotFound;
if( !MList.m_filesInvalid.IsEmpty() )
msg += _("\n\nFile load errors:\n\n" ) + MList.m_filesInvalid;
MList.ReadFootprintFiles( aTable, !aLibraryName ? NULL : &aLibraryName );
DisplayError( this, msg );
if( MList.GetErrorCount() )
{
MList.DisplayErrors( this );
return wxEmptyString;
}
......@@ -587,7 +580,7 @@ wxString PCB_BASE_FRAME::SelectFootprint( EDA_DRAW_FRAME* aWindow,
{
for( unsigned ii = 0; ii < MList.GetCount(); ii++ )
{
wxString& candidate = MList.GetItem( ii ).m_Module;
const wxString& candidate = MList.GetItem( ii ).m_Module;
if( WildCompareString( aMask, candidate, false ) )
{
......@@ -648,18 +641,18 @@ wxString PCB_BASE_FRAME::SelectFootprint( EDA_DRAW_FRAME* aWindow,
}
static void DisplayCmpDoc( wxString& Name )
static void DisplayCmpDoc( wxString& aName )
{
FOOTPRINT_INFO* module_info = MList.GetModuleInfo( Name );
const FOOTPRINT_INFO* module_info = MList.GetModuleInfo( aName );
if( !module_info )
{
Name.Empty();
aName.Empty();
return;
}
Name = _( "Description: " ) + module_info->m_Doc;
Name += _( "\nKey words: " ) + module_info->m_KeyWord;
aName = _( "Description: " ) + module_info->m_Doc;
aName += _( "\nKey words: " ) + module_info->m_KeyWord;
}
......
......@@ -385,43 +385,29 @@ void FOOTPRINT_VIEWER_FRAME::ReCreateFootprintList()
return;
}
bool libLoaded = false;
FOOTPRINT_LIST fp_info_list;
wxArrayString libsList;
#if !defined( USE_FP_LIB_TABLE )
libsList.Add( m_libraryName );
libLoaded = fp_info_list.ReadFootprintFiles( libsList );
fp_info_list.ReadFootprintFiles( libsList );
#else
libLoaded = fp_info_list.ReadFootprintFiles( m_footprintLibTable, &m_libraryName );
fp_info_list.ReadFootprintFiles( m_footprintLibTable, &m_libraryName );
#endif
if( !libLoaded )
if( fp_info_list.GetErrorCount() )
{
m_footprintName = wxEmptyString;
m_libraryName = wxEmptyString;
wxString msg;
msg.Format( _( "Error occurred attempting to load footprint library <%s>:\n\n" ),
GetChars( m_libraryName ) );
if( !fp_info_list.m_filesNotFound.IsEmpty() )
msg += _( "Files not found:\n\n" ) + fp_info_list.m_filesNotFound;
if( !fp_info_list.m_filesInvalid.IsEmpty() )
msg += _( "\n\nFile load errors:\n\n" ) + fp_info_list.m_filesInvalid;
DisplayError( this, msg );
fp_info_list.DisplayErrors( this );
return;
}
wxArrayString fpList;
BOOST_FOREACH( FOOTPRINT_INFO& footprint, fp_info_list.m_List )
BOOST_FOREACH( const FOOTPRINT_INFO& footprint, fp_info_list.GetList() )
{
fpList.Add( footprint.m_Module );
}
......@@ -538,23 +524,23 @@ void FOOTPRINT_VIEWER_FRAME::ExportSelectedFootprint( wxCommandEvent& event )
void FOOTPRINT_VIEWER_FRAME::LoadSettings( )
{
wxConfig* cfg ;
EDA_DRAW_FRAME::LoadSettings();
wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath );
cfg = wxGetApp().GetSettings();
// wxConfig* cfg =
wxGetApp().GetSettings();
}
void FOOTPRINT_VIEWER_FRAME::SaveSettings()
{
wxConfig* cfg;
EDA_DRAW_FRAME::SaveSettings();
wxConfigPathChanger cpc( wxGetApp().GetSettings(), m_configPath );
cfg = wxGetApp().GetSettings();
// wxConfig* cfg =
wxGetApp().GetSettings();
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment