mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-09-14 18:23:15 +02:00
Move IPC2581 output to REPORTER
Adds a wx_reporter_panel to the 2581 output window, shunt messages through the reporter instance Fixes https://gitlab.com/kicad/code/kicad/-/issues/16314
This commit is contained in:
parent
c2f503774b
commit
44228bd580
@ -20,9 +20,11 @@
|
||||
#include "dialogs/dialog_export_2581.h"
|
||||
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/filedlg.h>
|
||||
#include <wx/filefn.h>
|
||||
|
||||
#include <board.h>
|
||||
#include <footprint.h>
|
||||
@ -32,10 +34,14 @@
|
||||
#include <pgm_base.h>
|
||||
#include <project.h>
|
||||
#include <project/project_file.h>
|
||||
#include <pcb_io/pcb_io_mgr.h>
|
||||
#include <widgets/wx_html_report_panel.h>
|
||||
#include <widgets/wx_progress_reporters.h>
|
||||
#include <settings/settings_manager.h>
|
||||
#include <string_utils.h>
|
||||
#include <widgets/std_bitmap_button.h>
|
||||
#include <jobs/job_export_pcb_ipc2581.h>
|
||||
#include <wx_filename.h>
|
||||
|
||||
|
||||
|
||||
@ -213,6 +219,88 @@ void DIALOG_EXPORT_2581::onDistPNChange( wxCommandEvent& event )
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_EXPORT_2581::onOKClick( wxCommandEvent& event )
|
||||
{
|
||||
if( m_job )
|
||||
{
|
||||
if( TransferDataFromWindow() )
|
||||
EndModal( wxID_OK );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if( !TransferDataFromWindow() )
|
||||
return;
|
||||
|
||||
m_messagesPanel->Clear();
|
||||
|
||||
REPORTER& reporter = m_messagesPanel->Reporter();
|
||||
|
||||
wxFileName pcbFileName = GetOutputPath();
|
||||
WX_FILENAME::ResolvePossibleSymlinks( pcbFileName );
|
||||
|
||||
if( pcbFileName.GetName().empty() )
|
||||
{
|
||||
reporter.Report( _( "The board must be saved before generating IPC-2581 file." ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
if( !m_parent->IsWritable( pcbFileName ) )
|
||||
{
|
||||
reporter.Report( wxString::Format( _( "Insufficient permissions to write file '%s'." ),
|
||||
pcbFileName.GetFullPath() ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
|
||||
|
||||
WX_PROGRESS_REPORTER progress( this, _( "Generate IPC-2581 File" ), 5, PR_CAN_ABORT );
|
||||
|
||||
std::map<std::string, UTF8> props;
|
||||
|
||||
props[ "units" ] = TO_UTF8( GetUnitsString() );
|
||||
props[ "sigfig" ] = TO_UTF8( GetPrecision() );
|
||||
props[ "version" ] = TO_UTF8( wxString( GetVersion() ) );
|
||||
props[ "OEMRef" ] = TO_UTF8( GetOEM() );
|
||||
props[ "mpn" ] = TO_UTF8( GetMPN() );
|
||||
props[ "mfg" ] = TO_UTF8( GetMfg() );
|
||||
props[ "dist" ] = TO_UTF8( GetDist() );
|
||||
props[ "distpn" ] = TO_UTF8( GetDistPN() );
|
||||
|
||||
try
|
||||
{
|
||||
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( PCB_IO_MGR::IPC2581 ) );
|
||||
pi->SetProgressReporter( &progress );
|
||||
pi->SetReporter( &reporter );
|
||||
pi->SaveBoard( tempFile, m_parent->GetBoard(), &props );
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
reporter.Report( wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
|
||||
pcbFileName.GetFullPath(), ioe.What() ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
|
||||
wxRemoveFile( tempFile );
|
||||
return;
|
||||
}
|
||||
|
||||
if( wxFileExists( pcbFileName.GetFullPath() ) )
|
||||
wxRemoveFile( pcbFileName.GetFullPath() );
|
||||
|
||||
if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
|
||||
{
|
||||
reporter.Report( wxString::Format( _( "Failed to create file '%s'." ), pcbFileName.GetFullPath() ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
wxRemoveFile( tempFile );
|
||||
return;
|
||||
}
|
||||
|
||||
reporter.Report( _( "IPC-2581 file generated successfully." ), RPT_SEVERITY_ACTION );
|
||||
}
|
||||
|
||||
|
||||
void DIALOG_EXPORT_2581::init()
|
||||
{
|
||||
m_textDistributor->SetSize( m_choiceDistPN->GetSize() );
|
||||
|
@ -1700,6 +1700,17 @@
|
||||
</object>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
|
||||
<property name="proportion">1</property>
|
||||
<object class="wxPanel" expanded="false">
|
||||
<property name="minimum_size">-300,150</property>
|
||||
<property name="name">m_messagesPanel</property>
|
||||
<property name="permission">protected</property>
|
||||
<property name="subclass">WX_HTML_REPORT_PANEL; widgets/wx_html_report_panel.h; forward_declare</property>
|
||||
</object>
|
||||
</object>
|
||||
<object class="sizeritem" expanded="true">
|
||||
<property name="border">5</property>
|
||||
<property name="flag">wxALL|wxEXPAND</property>
|
||||
|
@ -103,6 +103,7 @@ private:
|
||||
void onCompressCheck( wxCommandEvent& event ) override;
|
||||
void onMfgPNChange( wxCommandEvent& event ) override;
|
||||
void onDistPNChange( wxCommandEvent& event ) override;
|
||||
void onOKClick( wxCommandEvent& event ) override;
|
||||
|
||||
void init();
|
||||
|
||||
|
@ -1,11 +1,12 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
|
||||
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "widgets/std_bitmap_button.h"
|
||||
#include "widgets/wx_html_report_panel.h"
|
||||
|
||||
#include "dialog_export_2581_base.h"
|
||||
|
||||
@ -185,6 +186,11 @@ DIALOG_EXPORT_2581_BASE::DIALOG_EXPORT_2581_BASE( wxWindow* parent, wxWindowID i
|
||||
|
||||
bMainSizer->Add( bSizerMiddle, 0, wxEXPAND|wxBOTTOM, 5 );
|
||||
|
||||
m_messagesPanel = new WX_HTML_REPORT_PANEL( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
|
||||
m_messagesPanel->SetMinSize( wxSize( -300,150 ) );
|
||||
|
||||
bMainSizer->Add( m_messagesPanel, 1, wxEXPAND|wxLEFT|wxRIGHT, 5 );
|
||||
|
||||
m_stdButtons = new wxStdDialogButtonSizer();
|
||||
m_stdButtonsOK = new wxButton( this, wxID_OK );
|
||||
m_stdButtons->AddButton( m_stdButtonsOK );
|
||||
|
@ -1,5 +1,5 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6)
|
||||
// C++ code generated with wxFormBuilder (version 4.2.1-0-g80c4cb6a-dirty)
|
||||
// http://www.wxformbuilder.org/
|
||||
//
|
||||
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
@ -11,6 +11,7 @@
|
||||
#include <wx/xrc/xmlres.h>
|
||||
#include <wx/intl.h>
|
||||
class STD_BITMAP_BUTTON;
|
||||
class WX_HTML_REPORT_PANEL;
|
||||
|
||||
#include "dialog_shim.h"
|
||||
#include <wx/string.h>
|
||||
@ -31,6 +32,7 @@ class STD_BITMAP_BUTTON;
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/checkbox.h>
|
||||
#include <wx/gbsizer.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/dialog.h>
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -68,6 +70,7 @@ class DIALOG_EXPORT_2581_BASE : public DIALOG_SHIM
|
||||
wxChoice* m_choiceDistPN;
|
||||
wxStaticText* m_staticText9;
|
||||
wxTextCtrl* m_textDistributor;
|
||||
WX_HTML_REPORT_PANEL* m_messagesPanel;
|
||||
wxStdDialogButtonSizer* m_stdButtons;
|
||||
wxButton* m_stdButtonsOK;
|
||||
wxButton* m_stdButtonsCancel;
|
||||
|
126
pcbnew/files.cpp
126
pcbnew/files.cpp
@ -1284,131 +1284,7 @@ int BOARD_EDITOR_CONTROL::GenIPC2581File( const TOOL_EVENT& aEvent )
|
||||
{
|
||||
DIALOG_EXPORT_2581 dlg( m_frame );
|
||||
|
||||
if( dlg.ShowModal() != wxID_OK )
|
||||
return 0;
|
||||
|
||||
wxFileName pcbFileName = dlg.GetOutputPath();
|
||||
|
||||
// Write through symlinks, don't replace them
|
||||
WX_FILENAME::ResolvePossibleSymlinks( pcbFileName );
|
||||
|
||||
if( pcbFileName.GetName().empty() )
|
||||
{
|
||||
DisplayError( m_frame, _( "The board must be saved before generating IPC-2581 file." ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( !m_frame->IsWritable( pcbFileName ) )
|
||||
{
|
||||
DisplayError( m_frame, wxString::Format( _( "Insufficient permissions to write file '%s'." ),
|
||||
pcbFileName.GetFullPath() ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
wxString tempFile = wxFileName::CreateTempFileName( wxS( "pcbnew_ipc" ) );
|
||||
wxString upperTxt;
|
||||
wxString lowerTxt;
|
||||
WX_PROGRESS_REPORTER reporter( m_frame, _( "Generate IPC-2581 File" ), 5, PR_CAN_ABORT );
|
||||
std::map<std::string, UTF8> props;
|
||||
|
||||
props["units"] = dlg.GetUnitsString();
|
||||
props["sigfig"] = dlg.GetPrecision();
|
||||
props["version"] = dlg.GetVersion();
|
||||
props["OEMRef"] = dlg.GetOEM();
|
||||
props["mpn"] = dlg.GetMPN();
|
||||
props["mfg"] = dlg.GetMfg();
|
||||
props["dist"] = dlg.GetDist();
|
||||
props["distpn"] = dlg.GetDistPN();
|
||||
|
||||
auto saveFile =
|
||||
[&]() -> bool
|
||||
{
|
||||
try
|
||||
{
|
||||
IO_RELEASER<PCB_IO> pi( PCB_IO_MGR::PluginFind( PCB_IO_MGR::IPC2581 ) );
|
||||
pi->SetProgressReporter( &reporter );
|
||||
pi->SaveBoard( tempFile, m_frame->GetBoard(), &props );
|
||||
return true;
|
||||
}
|
||||
catch( const IO_ERROR& ioe )
|
||||
{
|
||||
DisplayError( m_frame, wxString::Format( _( "Error generating IPC-2581 file '%s'.\n%s" ),
|
||||
pcbFileName.GetFullPath(),
|
||||
ioe.What() ) );
|
||||
|
||||
lowerTxt.Printf( _( "Failed to create temporary file '%s'." ), tempFile );
|
||||
|
||||
m_frame->SetMsgPanel( upperTxt, lowerTxt );
|
||||
|
||||
// In case we started a file but didn't fully write it, clean up
|
||||
wxRemoveFile( tempFile );
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
thread_pool& tp = GetKiCadThreadPool();
|
||||
auto ret = tp.submit( saveFile );
|
||||
|
||||
|
||||
std::future_status status = ret.wait_for( std::chrono::milliseconds( 250 ) );
|
||||
|
||||
while( status != std::future_status::ready )
|
||||
{
|
||||
reporter.KeepRefreshing();
|
||||
status = ret.wait_for( std::chrono::milliseconds( 250 ) );
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if( !ret.get() )
|
||||
return 0;
|
||||
}
|
||||
catch( const std::exception& e )
|
||||
{
|
||||
wxLogError( "Exception in IPC-2581 generation: %s", e.what() );
|
||||
m_frame->GetScreen()->SetContentModified( false );
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Preserve the permissions of the current file
|
||||
KIPLATFORM::IO::DuplicatePermissions( pcbFileName.GetFullPath(), tempFile );
|
||||
|
||||
if( dlg.GetCompress() )
|
||||
{
|
||||
wxFileName tempfn = pcbFileName;
|
||||
tempfn.SetExt( FILEEXT::Ipc2581FileExtension );
|
||||
wxFileName zipfn = tempFile;
|
||||
zipfn.SetExt( "zip" );
|
||||
|
||||
{
|
||||
wxFFileOutputStream fnout( zipfn.GetFullPath() );
|
||||
wxZipOutputStream zip( fnout );
|
||||
wxFFileInputStream fnin( tempFile );
|
||||
|
||||
zip.PutNextEntry( tempfn.GetFullName() );
|
||||
fnin.Read( zip );
|
||||
}
|
||||
|
||||
wxRemoveFile( tempFile );
|
||||
tempFile = zipfn.GetFullPath();
|
||||
}
|
||||
|
||||
// If save succeeded, replace the original with what we just wrote
|
||||
if( !wxRenameFile( tempFile, pcbFileName.GetFullPath() ) )
|
||||
{
|
||||
DisplayError( m_frame, wxString::Format( _( "Error generating IPC-2581 file '%s'.\n"
|
||||
"Failed to rename temporary file '%s." ),
|
||||
pcbFileName.GetFullPath(),
|
||||
tempFile ) );
|
||||
|
||||
lowerTxt.Printf( _( "Failed to rename temporary file '%s'." ),
|
||||
tempFile );
|
||||
|
||||
m_frame->SetMsgPanel( upperTxt, lowerTxt );
|
||||
}
|
||||
|
||||
m_frame->GetScreen()->SetContentModified( false );
|
||||
dlg.ShowModal();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -923,7 +923,7 @@ void PCB_IO_IPC2581::addShape( wxXmlNode* aContentNode, const PAD& aPad, PCB_LAY
|
||||
break;
|
||||
}
|
||||
default:
|
||||
wxLogError( "Unknown pad type" );
|
||||
Report( _( "Pad has unsupported type; it was skipped." ), RPT_SEVERITY_WARNING );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1256,8 +1256,9 @@ wxXmlNode* PCB_IO_IPC2581::generateBOMSection( wxXmlNode* aEcadNode )
|
||||
|
||||
if( iter == m_footprint_dict.end() )
|
||||
{
|
||||
wxLogError( "Footprint %s not found in dictionary",
|
||||
fp->GetFPID().GetLibItemName().wx_str() );
|
||||
Report( wxString::Format( _( "Footprint %s not found in dictionary; BOM data may be incomplete." ),
|
||||
fp->GetFPID().GetLibItemName().wx_str() ),
|
||||
RPT_SEVERITY_WARNING );
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1271,8 +1272,9 @@ wxXmlNode* PCB_IO_IPC2581::generateBOMSection( wxXmlNode* aEcadNode )
|
||||
}
|
||||
else
|
||||
{
|
||||
wxLogError( "Footprint %s not found in OEMRef dictionary",
|
||||
fp->GetFPID().GetLibItemName().wx_str() );
|
||||
Report( wxString::Format( _( "Component \"%s\" missing OEM reference; BOM entry will be skipped." ),
|
||||
fp->GetFPID().GetLibItemName().wx_str() ),
|
||||
RPT_SEVERITY_WARNING );
|
||||
}
|
||||
|
||||
entry->m_OEMDesignRef = genString( entry->m_OEMDesignRef, "REF" );
|
||||
@ -2253,7 +2255,7 @@ void PCB_IO_IPC2581::generateProfile( wxXmlNode* aStepNode )
|
||||
|
||||
if( ! m_board->GetBoardPolygonOutlines( board_outline ) )
|
||||
{
|
||||
wxLogError( "Failed to get board outline" );
|
||||
Report( _( "Board outline is invalid or missing. Please run DRC." ), RPT_SEVERITY_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2614,7 +2616,8 @@ void PCB_IO_IPC2581::generateComponents( wxXmlNode* aStepNode )
|
||||
}
|
||||
|
||||
if( !m_OEMRef_dict.emplace( fp, name ).second )
|
||||
wxLogError( "Duplicate footprint pointers. Please report this bug." );
|
||||
Report( _( "Duplicate footprint pointers encountered; IPC-2581 output may be incorrect." ),
|
||||
RPT_SEVERITY_ERROR );
|
||||
|
||||
addAttribute( componentNode, "part", genString( name, "REF" ) );
|
||||
addAttribute( componentNode, "layerRef", m_layer_name_map[fp->GetLayer()] );
|
||||
@ -2814,7 +2817,8 @@ void PCB_IO_IPC2581::generateLayerSetDrill( wxXmlNode* aLayerNode )
|
||||
|
||||
if( it == m_padstack_dict.end() )
|
||||
{
|
||||
wxLogError( "Failed to find padstack for via" );
|
||||
Report( _( "Via uses unsupported padstack; omitted from drill data." ),
|
||||
RPT_SEVERITY_WARNING );
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2839,7 +2843,8 @@ void PCB_IO_IPC2581::generateLayerSetDrill( wxXmlNode* aLayerNode )
|
||||
|
||||
if( it == m_padstack_dict.end() )
|
||||
{
|
||||
wxLogError( "Failed to find padstack for pad" );
|
||||
Report( _( "Pad uses unsupported padstack; hole was omitted from drill data." ),
|
||||
RPT_SEVERITY_WARNING );
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -2899,6 +2904,8 @@ void PCB_IO_IPC2581::generateLayerSetNet( wxXmlNode* aLayerNode, PCB_LAYER_ID aL
|
||||
wxXmlNode* teardropLayerSetNode = nullptr;
|
||||
wxXmlNode* teardropFeatureSetNode = nullptr;
|
||||
|
||||
bool teardrop_warning = false;
|
||||
|
||||
if( BOARD_CONNECTED_ITEM* item = dynamic_cast<BOARD_CONNECTED_ITEM*>( *it );
|
||||
IsCopperLayer( aLayer ) && item )
|
||||
{
|
||||
@ -2954,7 +2961,9 @@ void PCB_IO_IPC2581::generateLayerSetNet( wxXmlNode* aLayerNode, PCB_LAYER_ID aL
|
||||
{
|
||||
wxXmlNode* zoneFeatureNode = specialNode;
|
||||
|
||||
if( zone->IsTeardropArea() && m_version > 'B' )
|
||||
if( zone->IsTeardropArea() )
|
||||
{
|
||||
if( m_version > 'B' )
|
||||
{
|
||||
if( !teardropFeatureSetNode )
|
||||
{
|
||||
@ -2974,6 +2983,13 @@ void PCB_IO_IPC2581::generateLayerSetNet( wxXmlNode* aLayerNode, PCB_LAYER_ID aL
|
||||
|
||||
zoneFeatureNode = teardropFeatureSetNode;
|
||||
}
|
||||
else if( !teardrop_warning )
|
||||
{
|
||||
Report( _( "Teardrops are not supported in IPC-2581 revision B; they were exported as zones." ),
|
||||
RPT_SEVERITY_WARNING );
|
||||
teardrop_warning = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( FOOTPRINT* fp = zone->GetParentFootprint() )
|
||||
@ -3448,7 +3464,7 @@ void PCB_IO_IPC2581::SaveBoard( const wxString& aFileName, BOARD* aBoard,
|
||||
|
||||
if( !m_xml_doc->Save( out_stream ) )
|
||||
{
|
||||
wxLogError( _( "Failed to save file to buffer" ) );
|
||||
Report( _( "Failed to save IPC-2581 data to buffer." ), RPT_SEVERITY_ERROR );
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user