Add some defensive code to prevent re-entrant printing.

Fixes: lp:1765965
* https://bugs.launchpad.net/kicad/+bug/1765965
This commit is contained in:
Jeff Young 2019-08-13 17:59:43 +01:00
parent a33d67f6b4
commit c2d77a7300
5 changed files with 58 additions and 118 deletions

View File

@ -21,7 +21,7 @@
#include <confirm.h>
#include <eda_draw_frame.h>
#include <printout.h>
#include <enabler.h>
#include <pgm_base.h>
// Define min and max reasonable values for print scale
static constexpr double MIN_SCALE = 0.01;
@ -222,6 +222,12 @@ void DIALOG_PRINT_GENERIC::onPrintPreview( wxCommandEvent& event )
void DIALOG_PRINT_GENERIC::onPrintButtonClick( wxCommandEvent& event )
{
if( Pgm().m_Printing )
{
DisplayError( this, _( "Previous print job not yet complete." ) );
return;
}
m_settings->m_pageCount = 0; // it needs to be set by a derived dialog
saveSettings();
@ -237,19 +243,19 @@ void DIALOG_PRINT_GENERIC::onPrintButtonClick( wxCommandEvent& event )
wxPrinter printer( &printDialogData );
auto printout = std::unique_ptr<wxPrintout>( createPrintout( _( "Print" ) ) );
// Disable 'Print' button to prevent issuing another print
// command before the previous one is finished (causes problems on Windows)
ENABLER printBtnDisable( *m_sdbSizer1OK, false );
if( !printer.Print( this, printout.get(), true ) )
Pgm().m_Printing = true;
{
if( wxPrinter::GetLastError() == wxPRINTER_ERROR )
DisplayError( this, _( "There was a problem printing." ) );
}
else
{
*s_PrintData = printer.GetPrintDialogData().GetPrintData();
if( !printer.Print( this, printout.get(), true ) )
{
if( wxPrinter::GetLastError() == wxPRINTER_ERROR )
DisplayError( this, _( "There was a problem printing." ) );
}
else
{
*s_PrintData = printer.GetPrintDialogData().GetPrintData();
}
}
Pgm().m_Printing = false;
}

View File

@ -132,6 +132,7 @@ PGM_BASE::PGM_BASE()
{
m_pgm_checker = NULL;
m_locale = NULL;
m_Printing = false;
m_show_env_var_dialog = true;

View File

@ -2,7 +2,7 @@
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2015 Jean-Pierre Charras, jp.charras at wanadoo.fr
* Copyright (C) 2015-2018 KiCad Developers, see CHANGELOG.TXT for contributors.
* Copyright (C) 2015-2019 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
@ -25,38 +25,22 @@
#include <fctsys.h>
#include <pgm_base.h>
#include <gr_basic.h>
#include <sch_draw_panel.h>
#include <confirm.h>
#include <sch_screen.h>
#include <sch_edit_frame.h>
#include <base_units.h>
#include <general.h>
#include <eeschema_config.h>
#include <sch_sheet.h>
#include <sch_sheet_path.h>
#include <invoke_sch_dialog.h>
#include <dialog_print_using_printer_base.h>
/**
* Class DIALOG_PRINT_USING_PRINTER
* offers to print a schematic dialog.
*
* Derived from DIALOG_PRINT_USING_PRINTER_base created by wxFormBuilder
*/
class DIALOG_PRINT_USING_PRINTER : public DIALOG_PRINT_USING_PRINTER_BASE
{
public:
DIALOG_PRINT_USING_PRINTER( SCH_EDIT_FRAME* aParent );
~DIALOG_PRINT_USING_PRINTER() override;
SCH_EDIT_FRAME* GetParent() const
{
return ( SCH_EDIT_FRAME* ) wxWindow::GetParent();
}
private:
bool TransferDataToWindow() override;
bool TransferDataFromWindow() override;
@ -65,6 +49,8 @@ private:
void OnPrintPreview( wxCommandEvent& event ) override;
void GetPrintOptions();
SCH_EDIT_FRAME* m_parent;
};
@ -84,6 +70,7 @@ public:
wxASSERT( aParent != NULL );
m_parent = aParent;
}
bool OnPrintPage( int page ) override;
bool HasPage( int page ) override;
bool OnBeginDocument( int startPage, int endPage ) override;
@ -142,7 +129,8 @@ wxSize SCH_PREVIEW_FRAME::s_size;
DIALOG_PRINT_USING_PRINTER::DIALOG_PRINT_USING_PRINTER( SCH_EDIT_FRAME* aParent ) :
DIALOG_PRINT_USING_PRINTER_BASE( aParent )
DIALOG_PRINT_USING_PRINTER_BASE( aParent ),
m_parent( aParent )
{
wxASSERT( aParent != NULL );
@ -177,11 +165,9 @@ DIALOG_PRINT_USING_PRINTER::~DIALOG_PRINT_USING_PRINTER()
bool DIALOG_PRINT_USING_PRINTER::TransferDataToWindow()
{
SCH_EDIT_FRAME* parent = GetParent();
// Initialize page specific print setup dialog settings.
const PAGE_INFO& pageInfo = parent->GetScreen()->GetPageSettings();
wxPageSetupDialogData& pageSetupDialogData = parent->GetPageSetupData();
const PAGE_INFO& pageInfo = m_parent->GetScreen()->GetPageSettings();
wxPageSetupDialogData& pageSetupDialogData = m_parent->GetPageSetupData();
pageSetupDialogData.SetPaperId( pageInfo.GetPaperId() );
@ -203,10 +189,8 @@ bool DIALOG_PRINT_USING_PRINTER::TransferDataToWindow()
void DIALOG_PRINT_USING_PRINTER::GetPrintOptions()
{
SCH_EDIT_FRAME* parent = GetParent();
parent->SetPrintMonochrome( m_checkMonochrome->IsChecked() );
parent->SetPrintSheetReference( m_checkReference->IsChecked() );
m_parent->SetPrintMonochrome( m_checkMonochrome->IsChecked() );
m_parent->SetPrintSheetReference( m_checkReference->IsChecked() );
}
@ -214,13 +198,10 @@ void DIALOG_PRINT_USING_PRINTER::GetPrintOptions()
*/
void DIALOG_PRINT_USING_PRINTER::OnPageSetup( wxCommandEvent& event )
{
SCH_EDIT_FRAME* parent = GetParent();
wxPageSetupDialog pageSetupDialog( this, &parent->GetPageSetupData() );
wxPageSetupDialog pageSetupDialog( this, &m_parent->GetPageSetupData() );
pageSetupDialog.ShowModal();
parent->GetPageSetupData() = pageSetupDialog.GetPageSetupDialogData();
m_parent->GetPageSetupData() = pageSetupDialog.GetPageSetupDialogData();
}
@ -228,15 +209,13 @@ void DIALOG_PRINT_USING_PRINTER::OnPageSetup( wxCommandEvent& event )
*/
void DIALOG_PRINT_USING_PRINTER::OnPrintPreview( wxCommandEvent& event )
{
SCH_EDIT_FRAME* parent = GetParent();
GetPrintOptions();
// Pass two printout objects: for preview, and possible printing.
wxString title = _( "Preview" );
wxPrintPreview* preview = new wxPrintPreview( new SCH_PRINTOUT( parent, title ),
new SCH_PRINTOUT( parent, title ),
&parent->GetPageSetupData().GetPrintData() );
wxPrintPreview* preview = new wxPrintPreview( new SCH_PRINTOUT( m_parent, title ),
new SCH_PRINTOUT( m_parent, title ),
&m_parent->GetPageSetupData().GetPrintData() );
preview->SetZoom( 100 );
@ -245,7 +224,7 @@ void DIALOG_PRINT_USING_PRINTER::OnPrintPreview( wxCommandEvent& event )
// on first invocation in this runtime session, set to 2/3 size of my parent,
// but will be changed in Show() if not first time as will position.
frame->SetSize( (parent->GetSize() * 2) / 3 );
frame->SetSize( (m_parent->GetSize() * 2) / 3 );
frame->Center();
// On wxGTK, set the flag wxTOPLEVEL_EX_DIALOG is mandatory, if we want
@ -268,33 +247,36 @@ void DIALOG_PRINT_USING_PRINTER::OnPrintPreview( wxCommandEvent& event )
bool DIALOG_PRINT_USING_PRINTER::TransferDataFromWindow()
{
SCH_EDIT_FRAME* parent = GetParent();
if( Pgm().m_Printing )
{
DisplayError( this, _( "Previous print job not yet complete." ) );
return false;
}
GetPrintOptions();
wxPrintDialogData printDialogData( parent->GetPageSetupData().GetPrintData() );
wxPrintDialogData printDialogData( m_parent->GetPageSetupData().GetPrintData() );
printDialogData.SetMaxPage( g_RootSheet->CountSheets() );
if( g_RootSheet->CountSheets() > 1 )
printDialogData.EnablePageNumbers( true );
wxPrinter printer( &printDialogData );
SCH_PRINTOUT printout( parent, _( "Print Schematic" ) );
SCH_PRINTOUT printout( m_parent, _( "Print Schematic" ) );
// Disable 'Print' button to prevent issuing another print
// command before the previous one is finished (causes problems on Windows)
m_sdbSizer1OK->Enable( false );
if( !printer.Print( this, &printout, true ) )
Pgm().m_Printing = true;
{
if( wxPrinter::GetLastError() == wxPRINTER_ERROR )
wxMessageBox( _( "An error occurred attempting to print the schematic." ),
_( "Printing" ), wxOK );
}
else
{
parent->GetPageSetupData() = printer.GetPrintDialogData().GetPrintData();
if( !printer.Print( this, &printout, true ) )
{
if( wxPrinter::GetLastError() == wxPRINTER_ERROR )
DisplayError( this, _( "An error occurred attempting to print the schematic." ) );
}
else
{
m_parent->GetPageSetupData() = printer.GetPrintDialogData().GetPrintData();
}
}
Pgm().m_Printing = false;
return true;
}

View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2018 CERN
* Author: Maciej Suminski <maciej.suminski@cern.ch>
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef ENABLER_H
#define ENABLER_H
#include <wx/window.h>
/**
* Simple class to automatically enable/disable widgets.
*
* As long as an ENABLER object exists, the handled widget will be kept in the requested state.
*/
class ENABLER
{
public:
/**
* Constructor.
*
* @param aObject is the object to be temporarily enabled or disabled.
* @param aState is the requested temporary state (true for enabled, false for disabled).
*/
ENABLER( wxWindow& aObject, bool aState )
: m_object( aObject ), m_state( aState )
{
m_object.Enable( m_state );
}
~ENABLER()
{
m_object.Enable( !m_state );
}
private:
wxWindow& m_object;
bool m_state;
};
#endif /* ENABLER_H */

View File

@ -361,6 +361,11 @@ public:
*/
void SaveCommonSettings();
/**
* wxWidgets on MSW tends to crash if you spool up more than one print job at a time.
*/
bool m_Printing;
protected:
/**