From e6a8294c5672fabbd0002b18ff364c3dcfd74d4c Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 7 Jan 2017 20:43:39 +0100 Subject: [PATCH] dialog_footprint_wizard_list: add button to show the trace of errors when python scripts wizards failed to load. --- .../dialogs/dialog_footprint_wizard_list.cpp | 39 ++- pcbnew/dialogs/dialog_footprint_wizard_list.h | 1 + .../dialog_footprint_wizard_list_base.cpp | 35 ++- .../dialog_footprint_wizard_list_base.fbp | 276 +++++++++++++++++- .../dialog_footprint_wizard_list_base.h | 23 +- pcbnew/swig/python_scripting.cpp | 5 + pcbnew/swig/python_scripting.h | 8 + scripting/kicadplugins.i | 11 +- 8 files changed, 393 insertions(+), 5 deletions(-) diff --git a/pcbnew/dialogs/dialog_footprint_wizard_list.cpp b/pcbnew/dialogs/dialog_footprint_wizard_list.cpp index e2c2a40f62..5e95586637 100644 --- a/pcbnew/dialogs/dialog_footprint_wizard_list.cpp +++ b/pcbnew/dialogs/dialog_footprint_wizard_list.cpp @@ -108,7 +108,10 @@ DIALOG_FOOTPRINT_WIZARD_LIST::DIALOG_FOOTPRINT_WIZARD_LIST( wxWindow* aParent ) // Display info about scripts: unloadable scripts (due to syntax errors is python source) pcbnewGetUnloadableScriptNames( message ); if( message.IsEmpty() ) + { m_tcNotLoaded->SetValue( _( "All footprint generator scripts were loaded" ) ); + m_buttonShowTrace->Show( false ); + } else m_tcNotLoaded->SetValue( message ); @@ -132,7 +135,7 @@ void DIALOG_FOOTPRINT_WIZARD_LIST::OnCellFpGeneratorClick( wxGridEvent& event ) int click_row = event.GetRow(); m_footprintWizard = FOOTPRINT_WIZARDS::GetWizard( click_row ); m_footprintGeneratorsGrid->SelectRow( event.GetRow(), false ); - // Move the grid cursor, mainly for aesthetic reasons: + // Move the grid cursor to the active line, mainly for aesthetic reasons: m_footprintGeneratorsGrid->GoToCell( event.GetRow(), FP_GEN_ROW_NUMBER ); } @@ -142,6 +145,40 @@ void DIALOG_FOOTPRINT_WIZARD_LIST::OnCellFpGeneratorDoubleClick( wxGridEvent& ev EndModal( wxID_OK ); } +void DIALOG_FOOTPRINT_WIZARD_LIST::onShowTrace( wxCommandEvent& event ) +{ + wxString trace; + pcbnewGetWizardsBackTrace( trace ); + + // Filter message before displaying them + // a trace starts by "Traceback" and is followed by 2 useless lines + // for our purpose + wxArrayString traces; + wxStringSplit( trace, traces, '\n' ); + + // Build the filtered message (remove useless lines) + trace.Clear(); + + for( unsigned ii = 0; ii < traces.Count(); ++ii ) + { + if( traces[ii].Contains( "Traceback" ) ) + { + ii += 2; // Skip this line and next lines which are related to pcbnew.py module + + if( !trace.IsEmpty() ) // Add separator for the next trace block + trace << "\n**********************************\n"; + } + else + trace += traces[ii] + "\n"; + } + + // Now display the filtered trace in our dialog + // (a simple wxMessageBox is really not suitable for long messages) + DIALOG_FOOTPRINT_WIZARD_LOG logWindow( this ); + logWindow.m_Message->SetValue( trace ); + logWindow.ShowModal(); +} + FOOTPRINT_WIZARD* DIALOG_FOOTPRINT_WIZARD_LIST::GetWizard() { diff --git a/pcbnew/dialogs/dialog_footprint_wizard_list.h b/pcbnew/dialogs/dialog_footprint_wizard_list.h index eccfb78f8a..d8d411f986 100644 --- a/pcbnew/dialogs/dialog_footprint_wizard_list.h +++ b/pcbnew/dialogs/dialog_footprint_wizard_list.h @@ -43,6 +43,7 @@ public: private: void OnCellFpGeneratorClick( wxGridEvent& event ) override; void OnCellFpGeneratorDoubleClick( wxGridEvent& event ) override; + void onShowTrace( wxCommandEvent& event ) override; }; #endif // _DIALOG_FOOTPRINT_WIZARD_LIST_H_ diff --git a/pcbnew/dialogs/dialog_footprint_wizard_list_base.cpp b/pcbnew/dialogs/dialog_footprint_wizard_list_base.cpp index e0f19706b1..efdf3035bc 100644 --- a/pcbnew/dialogs/dialog_footprint_wizard_list_base.cpp +++ b/pcbnew/dialogs/dialog_footprint_wizard_list_base.cpp @@ -83,6 +83,9 @@ DIALOG_FOOTPRINT_WIZARD_LIST_BASE::DIALOG_FOOTPRINT_WIZARD_LIST_BASE( wxWindow* m_bsizerPanelInfo->Add( m_tcNotLoaded, 1, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + m_buttonShowTrace = new wxButton( m_panelInfo, wxID_ANY, _("Show Trace"), wxDefaultPosition, wxDefaultSize, 0 ); + m_bsizerPanelInfo->Add( m_buttonShowTrace, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 ); + m_panelInfo->SetSizer( m_bsizerPanelInfo ); m_panelInfo->Layout(); @@ -101,7 +104,7 @@ DIALOG_FOOTPRINT_WIZARD_LIST_BASE::DIALOG_FOOTPRINT_WIZARD_LIST_BASE( wxWindow* m_sdbSizer->AddButton( m_sdbSizerCancel ); m_sdbSizer->Realize(); - bSizerMain->Add( m_sdbSizer, 0, wxEXPAND|wxALL, 5 ); + bSizerMain->Add( m_sdbSizer, 0, wxALL|wxALIGN_RIGHT, 5 ); this->SetSizer( bSizerMain ); @@ -112,6 +115,7 @@ DIALOG_FOOTPRINT_WIZARD_LIST_BASE::DIALOG_FOOTPRINT_WIZARD_LIST_BASE( wxWindow* // Connect Events m_footprintGeneratorsGrid->Connect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FOOTPRINT_WIZARD_LIST_BASE::OnCellFpGeneratorClick ), NULL, this ); m_footprintGeneratorsGrid->Connect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FOOTPRINT_WIZARD_LIST_BASE::OnCellFpGeneratorDoubleClick ), NULL, this ); + m_buttonShowTrace->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_WIZARD_LIST_BASE::onShowTrace ), NULL, this ); } DIALOG_FOOTPRINT_WIZARD_LIST_BASE::~DIALOG_FOOTPRINT_WIZARD_LIST_BASE() @@ -119,5 +123,34 @@ DIALOG_FOOTPRINT_WIZARD_LIST_BASE::~DIALOG_FOOTPRINT_WIZARD_LIST_BASE() // Disconnect Events m_footprintGeneratorsGrid->Disconnect( wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler( DIALOG_FOOTPRINT_WIZARD_LIST_BASE::OnCellFpGeneratorClick ), NULL, this ); m_footprintGeneratorsGrid->Disconnect( wxEVT_GRID_CELL_LEFT_DCLICK, wxGridEventHandler( DIALOG_FOOTPRINT_WIZARD_LIST_BASE::OnCellFpGeneratorDoubleClick ), NULL, this ); + m_buttonShowTrace->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_FOOTPRINT_WIZARD_LIST_BASE::onShowTrace ), NULL, this ); } + +DIALOG_FOOTPRINT_WIZARD_LOG::DIALOG_FOOTPRINT_WIZARD_LOG( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style ) +{ + this->SetSizeHints( wxSize( 600,350 ), wxDefaultSize ); + + wxBoxSizer* bSizerMain; + bSizerMain = new wxBoxSizer( wxVERTICAL ); + + m_Message = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY ); + bSizerMain->Add( m_Message, 1, wxALL|wxEXPAND, 5 ); + + m_sdbSizer = new wxStdDialogButtonSizer(); + m_sdbSizerOK = new wxButton( this, wxID_OK ); + m_sdbSizer->AddButton( m_sdbSizerOK ); + m_sdbSizer->Realize(); + + bSizerMain->Add( m_sdbSizer, 0, wxALIGN_RIGHT|wxALL, 5 ); + + + this->SetSizer( bSizerMain ); + this->Layout(); + + this->Centre( wxBOTH ); +} + +DIALOG_FOOTPRINT_WIZARD_LOG::~DIALOG_FOOTPRINT_WIZARD_LOG() +{ +} diff --git a/pcbnew/dialogs/dialog_footprint_wizard_list_base.fbp b/pcbnew/dialogs/dialog_footprint_wizard_list_base.fbp index 0104a1a5f9..093631e7ff 100644 --- a/pcbnew/dialogs/dialog_footprint_wizard_list_base.fbp +++ b/pcbnew/dialogs/dialog_footprint_wizard_list_base.fbp @@ -835,6 +835,94 @@ + + 5 + wxBOTTOM|wxRIGHT|wxLEFT + 0 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + Show Trace + + 0 + + + 0 + + 1 + m_buttonShowTrace + 1 + + + protected + 1 + + Resizable + 1 + + + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + onShowTrace + + + + + + + + + + + + + + + + + + + + + + + + + @@ -923,7 +1011,7 @@ 5 - wxEXPAND|wxALL + wxALL|wxALIGN_RIGHT 0 0 @@ -949,5 +1037,191 @@ + + 0 + wxAUI_MGR_DEFAULT + + wxBOTH + + 1 + 1 + impl_virtual + + + + 0 + wxID_ANY + + 600,350 + DIALOG_FOOTPRINT_WIZARD_LOG + + 646,361 + wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER + DIALOG_SHIM; dialog_shim.h + Traceback of errors in not loadable python scripts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + bSizerMain + wxVERTICAL + none + + 5 + wxALL|wxEXPAND + 1 + + 1 + 1 + 1 + 1 + + + + + + + + 1 + 0 + 1 + + 1 + 0 + Dock + 0 + Left + 1 + + 1 + + 0 + 0 + wxID_ANY + + 0 + + 0 + + 0 + -1,-1 + 1 + m_Message + 1 + + + public + 1 + + Resizable + 1 + + wxTE_MULTILINE|wxTE_READONLY + + 0 + + + wxFILTER_NONE + wxDefaultValidator + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + wxALIGN_RIGHT|wxALL + 0 + + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + + m_sdbSizer + protected + + + + + + + + + + + + diff --git a/pcbnew/dialogs/dialog_footprint_wizard_list_base.h b/pcbnew/dialogs/dialog_footprint_wizard_list_base.h index 791c7d4e63..0ec920b42e 100644 --- a/pcbnew/dialogs/dialog_footprint_wizard_list_base.h +++ b/pcbnew/dialogs/dialog_footprint_wizard_list_base.h @@ -27,9 +27,9 @@ class DIALOG_SHIM; #include #include #include +#include #include #include -#include #include /////////////////////////////////////////////////////////////////////////// @@ -51,6 +51,7 @@ class DIALOG_FOOTPRINT_WIZARD_LIST_BASE : public DIALOG_SHIM wxTextCtrl* m_tcSearchPaths; wxStaticText* m_staticText11; wxTextCtrl* m_tcNotLoaded; + wxButton* m_buttonShowTrace; wxStaticLine* m_staticline; wxStdDialogButtonSizer* m_sdbSizer; wxButton* m_sdbSizerOK; @@ -59,6 +60,7 @@ class DIALOG_FOOTPRINT_WIZARD_LIST_BASE : public DIALOG_SHIM // Virtual event handlers, overide them in your derived class virtual void OnCellFpGeneratorClick( wxGridEvent& event ) { event.Skip(); } virtual void OnCellFpGeneratorDoubleClick( wxGridEvent& event ) { event.Skip(); } + virtual void onShowTrace( wxCommandEvent& event ) { event.Skip(); } public: @@ -68,4 +70,23 @@ class DIALOG_FOOTPRINT_WIZARD_LIST_BASE : public DIALOG_SHIM }; +/////////////////////////////////////////////////////////////////////////////// +/// Class DIALOG_FOOTPRINT_WIZARD_LOG +/////////////////////////////////////////////////////////////////////////////// +class DIALOG_FOOTPRINT_WIZARD_LOG : public DIALOG_SHIM +{ + private: + + protected: + wxStdDialogButtonSizer* m_sdbSizer; + wxButton* m_sdbSizerOK; + + public: + wxTextCtrl* m_Message; + + DIALOG_FOOTPRINT_WIZARD_LOG( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Traceback of errors in not loadable python scripts"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 646,361 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER ); + ~DIALOG_FOOTPRINT_WIZARD_LOG(); + +}; + #endif //__DIALOG_FOOTPRINT_WIZARD_LIST_BASE_H__ diff --git a/pcbnew/swig/python_scripting.cpp b/pcbnew/swig/python_scripting.cpp index 3c574266c9..2bc4e7779d 100644 --- a/pcbnew/swig/python_scripting.cpp +++ b/pcbnew/swig/python_scripting.cpp @@ -258,6 +258,11 @@ void pcbnewGetScriptsSearchPaths( wxString& aNames ) pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetWizardsSearchPaths", aNames ); } +void pcbnewGetWizardsBackTrace( wxString& aNames ) +{ + pcbnewRunPythonMethodWithReturnedString( "pcbnew.GetWizardsBackTrace", aNames ); +} + void pcbnewFinishPythonScripting() { diff --git a/pcbnew/swig/python_scripting.h b/pcbnew/swig/python_scripting.h index 42fbf57e92..861d166855 100644 --- a/pcbnew/swig/python_scripting.h +++ b/pcbnew/swig/python_scripting.h @@ -64,6 +64,14 @@ void pcbnewGetUnloadableScriptNames( wxString& aNames ); * @param aNames is a wxString which will contain the paths (separated by '\n') */ void pcbnewGetScriptsSearchPaths( wxString& aNames ); + +/** + * Function pcbnewGetWizardsBackTrace + * returns the backtrace of errors (if any) when wizard python scripts are loaded + * @param aNames is a wxString which will contain the trace + */ +void pcbnewGetWizardsBackTrace( wxString& aNames ); + #ifdef KICAD_SCRIPTING_WXPYTHON void RedirectStdio(); diff --git a/scripting/kicadplugins.i b/scripting/kicadplugins.i index 5380f543f1..324f92550c 100644 --- a/scripting/kicadplugins.i +++ b/scripting/kicadplugins.i @@ -65,16 +65,21 @@ NOT_LOADED_WIZARDS="" """ PLUGIN_DIRECTORIES_SEARCH="" +""" the trace of errors during execution of footprint wizards scripts +""" +FULL_BACK_TRACE="" def GetUnLoadableWizards(): global NOT_LOADED_WIZARDS return NOT_LOADED_WIZARDS - def GetWizardsSearchPaths(): global PLUGIN_DIRECTORIES_SEARCH return PLUGIN_DIRECTORIES_SEARCH +def GetWizardsBackTrace(): + global FULL_BACK_TRACE + return FULL_BACK_TRACE def ReloadPlugin(name): if not KICAD_PLUGINS.has_key(name): @@ -132,6 +137,7 @@ def LoadPlugins(bundlepath=None): """ import os import sys + import traceback import pcbnew kicad_path = os.environ.get('KICAD_PATH') @@ -162,6 +168,8 @@ def LoadPlugins(bundlepath=None): PLUGIN_DIRECTORIES_SEARCH += "\n" PLUGIN_DIRECTORIES_SEARCH += plugins_dir + global FULL_BACK_TRACE + FULL_BACK_TRACE="" failed_wizards_list="" for plugins_dir in plugin_directories: @@ -191,6 +199,7 @@ def LoadPlugins(bundlepath=None): if failed_wizards_list != "" : failed_wizards_list += "\n" failed_wizards_list += module_filename + FULL_BACK_TRACE += traceback.format_exc(sys.exc_info()) pass global NOT_LOADED_WIZARDS