|
|
/*
* This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2019 Alexander Shuklin, jasuramme@gmail.com * Copyright (C) 2019 KiCad Developers, see AUTHORS.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 "dialog_board_statistics.h"
#include "base_units.h"
#include <macros.h>
#include <wildcards_and_files_ext.h>
#include <wx/filedlg.h>
#define COL_LABEL 0
#define COL_AMOUNT 1
// Defines for components view
#define ROW_LABEL 0
#define COL_FRONT_SIDE 1
#define COL_BOTTOM_SIDE 2
#define COL_TOTAL 3
// Defines for board view
#define ROW_BOARD_WIDTH 0
#define ROW_BOARD_HEIGHT 1
#define ROW_BOARD_AREA 2
/**
* Struct containing the dialog last saved state */struct DIALOG_BOARD_STATISTICS_SAVED_STATE{ DIALOG_BOARD_STATISTICS_SAVED_STATE() : excludeNoPins( false ), subtractHoles( false ), saveReportInitialized(false) { }
// Flags to remember last checkboxes state
bool excludeNoPins; bool subtractHoles;
// Variables to save last report file name and folder
bool saveReportInitialized; // true after the 3 next string are initialized
wxString saveReportFolder; // last report folder
wxString saveReportName; // last report filename
wxString m_project; // name of the project used to create the last report
// used to reinit last state after a project change
};
static DIALOG_BOARD_STATISTICS_SAVED_STATE s_savedDialogState;
DIALOG_BOARD_STATISTICS::DIALOG_BOARD_STATISTICS( PCB_EDIT_FRAME* aParentFrame ) : DIALOG_BOARD_STATISTICS_BASE( aParentFrame ), m_boardWidth( 0 ), m_boardHeight( 0 ), m_boardArea( 0.0 ), m_hasOutline( false ){ m_parentFrame = aParentFrame;
m_gridDrills->UseNativeColHeader(); m_gridDrills->Connect( wxEVT_GRID_COL_SORT, wxGridEventHandler( DIALOG_BOARD_STATISTICS::drillGridSort ), NULL, this );
m_checkBoxExcludeComponentsNoPins->SetValue( s_savedDialogState.excludeNoPins ); m_checkBoxSubtractHoles->SetValue( s_savedDialogState.subtractHoles );
// Make labels for grids
wxFont headingFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); headingFont.SetSymbolicSize( wxFONTSIZE_SMALL ); m_gridComponents->SetCellValue( ROW_LABEL, COL_FRONT_SIDE, _( "Front Side" ) ); m_gridComponents->SetCellFont( ROW_LABEL, COL_FRONT_SIDE, headingFont ); m_gridComponents->SetCellValue( ROW_LABEL, COL_BOTTOM_SIDE, _( "Back Side" ) ); m_gridComponents->SetCellFont( ROW_LABEL, COL_BOTTOM_SIDE, headingFont ); m_gridComponents->SetCellValue( ROW_LABEL, COL_TOTAL, _( "Total" ) ); m_gridComponents->SetCellFont( ROW_LABEL, COL_TOTAL, headingFont );
m_gridBoard->SetCellValue( 0, 0, _( "Width:" ) ); m_gridBoard->SetCellAlignment( 0, 0, wxALIGN_LEFT, wxALIGN_CENTRE ); m_gridBoard->SetCellValue( 1, 0, _( "Height:" ) ); m_gridBoard->SetCellAlignment( 1, 0, wxALIGN_LEFT, wxALIGN_CENTRE ); m_gridBoard->SetCellValue( 2, 0, _( "Area:" ) ); m_gridBoard->SetCellAlignment( 2, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
wxGrid* grids[] = { m_gridComponents, m_gridPads, m_gridVias, m_gridBoard }; for( auto& grid : grids ) { // Remove wxgrid's selection boxes
grid->SetCellHighlightPenWidth( 0 ); grid->SetColMinimalAcceptableWidth( 80 ); for( int i = 0; i < grid->GetNumberRows(); i++ ) grid->SetCellAlignment( i, COL_LABEL, wxALIGN_LEFT, wxALIGN_CENTRE ); }
wxFileName fn = m_parentFrame->GetBoard()->GetFileName();
if( !s_savedDialogState.saveReportInitialized || s_savedDialogState.m_project != Prj().GetProjectFullName() ) { fn.SetName( fn.GetName() + "_report" ); fn.SetExt( "txt" ); s_savedDialogState.saveReportName = fn.GetFullName(); s_savedDialogState.saveReportFolder = wxPathOnly( Prj().GetProjectFullName() ); s_savedDialogState.m_project = Prj().GetProjectFullName(); s_savedDialogState.saveReportInitialized = true; }
// The wxStdDialogButtonSizer wxID_CANCLE button is in fact a close button
// Nothing to cancel:
m_sdbControlSizerCancel->SetLabel( _( "Close" ) );}
void DIALOG_BOARD_STATISTICS::refreshItemsTypes(){ m_componentsTypes.clear();
// If you need some more types to be shown, simply add them to the
// corresponding list
m_componentsTypes.push_back( componentsType_t( FP_THROUGH_HOLE, _( "THT:" ) ) ); m_componentsTypes.push_back( componentsType_t( FP_SMD, _( "SMD:" ) ) );
m_padsTypes.clear(); m_padsTypes.push_back( padsType_t( PAD_ATTRIB::PTH, _( "Through hole:" ) ) ); m_padsTypes.push_back( padsType_t( PAD_ATTRIB::SMD, _( "SMD:" ) ) ); m_padsTypes.push_back( padsType_t( PAD_ATTRIB::CONN, _( "Connector:" ) ) ); m_padsTypes.push_back( padsType_t( PAD_ATTRIB::NPTH, _( "NPTH:" ) ) );
m_viasTypes.clear(); m_viasTypes.push_back( viasType_t( VIATYPE::THROUGH, _( "Through vias:" ) ) ); m_viasTypes.push_back( viasType_t( VIATYPE::BLIND_BURIED, _( "Blind/buried:" ) ) ); m_viasTypes.push_back( viasType_t( VIATYPE::MICROVIA, _( "Micro vias:" ) ) );
// If there not enough rows in grids, append some
int appendRows = m_componentsTypes.size() + 2 - m_gridComponents->GetNumberRows();
if( appendRows > 0 ) m_gridComponents->AppendRows( appendRows );
appendRows = m_padsTypes.size() + 1 - m_gridPads->GetNumberRows();
if( appendRows > 0 ) m_gridPads->AppendRows( appendRows );
appendRows = m_viasTypes.size() + 1 - m_gridVias->GetNumberRows();
if( appendRows ) m_gridVias->AppendRows( appendRows );}
bool DIALOG_BOARD_STATISTICS::TransferDataToWindow(){ refreshItemsTypes(); getDataFromPCB(); updateWidets(); Layout(); drillsPanel->Layout(); finishDialogSettings(); return true;}
void DIALOG_BOARD_STATISTICS::getDataFromPCB(){ BOARD* board = m_parentFrame->GetBoard();
// Get footprints and pads count
for( FOOTPRINT* footprint : board->Footprints() ) { // Do not proceed footprints with no pads if checkbox checked
if( m_checkBoxExcludeComponentsNoPins->GetValue() && ! footprint->Pads().size() ) continue;
// Go through components types list
for( auto& type : m_componentsTypes ) { if(( footprint->GetAttributes() & type.attribute ) > 0 ) { if( footprint->IsFlipped() ) type.backSideQty++; else type.frontSideQty++; break; } }
for( PAD* pad : footprint->Pads() ) { // Go through pads types list
for( auto& type : m_padsTypes ) { if( pad->GetAttribute() == type.attribute ) { type.qty++; break; } }
if( pad->GetDrillSize().x > 0 && pad->GetDrillSize().y > 0 ) { PCB_LAYER_ID top, bottom;
if( pad->GetLayerSet().CuStack().empty() ) { // The pad is not on any copper layer
top = UNDEFINED_LAYER; bottom = UNDEFINED_LAYER; } else { top = pad->GetLayerSet().CuStack().front(); bottom = pad->GetLayerSet().CuStack().back(); }
drillType_t drill( pad->GetDrillSize().x, pad->GetDrillSize().y, pad->GetDrillShape(), pad->GetAttribute() != PAD_ATTRIB::NPTH, true, top, bottom );
auto it = m_drillTypes.begin();
for( ; it != m_drillTypes.end(); ++it ) { if( *it == drill ) { it->qty++; break; } }
if( it == m_drillTypes.end() ) { drill.qty = 1; m_drillTypes.push_back( drill ); m_gridDrills->InsertRows(); } } } }
// Get via counts
for( TRACK* track : board->Tracks() ) { if( VIA* via = dyn_cast<VIA*>( track ) ) { for( auto& type : m_viasTypes ) { if( via->GetViaType() == type.attribute ) { type.qty++; break; } }
drillType_t drill( via->GetDrillValue(), via->GetDrillValue(), PAD_DRILL_SHAPE_CIRCLE, true, false, via->TopLayer(), via->BottomLayer() );
auto it = m_drillTypes.begin();
for( ; it != m_drillTypes.end(); ++it ) { if( *it == drill ) { it->qty++; break; } }
if( it == m_drillTypes.end() ) { drill.qty = 1; m_drillTypes.push_back( drill ); m_gridDrills->InsertRows(); } } }
sort( m_drillTypes.begin(), m_drillTypes.end(), drillType_t::COMPARE( drillType_t::COL_COUNT, false ) );
bool boundingBoxCreated = false; //flag if bounding box initialized
BOX2I bbox; SHAPE_POLY_SET polySet; m_hasOutline = board->GetBoardPolygonOutlines( polySet );
// If board has no Edge Cuts lines, board->GetBoardPolygonOutlines will
// return small rectangle, so we double check that
bool edgeCutsExists = false;
for( BOARD_ITEM* drawing : board->Drawings() ) { if( drawing->GetLayer() == Edge_Cuts ) { edgeCutsExists = true; break; } }
if( !edgeCutsExists ) m_hasOutline = false;
if( m_hasOutline ) { m_boardArea = 0.0;
for( int i = 0; i < polySet.OutlineCount(); i++ ) { SHAPE_LINE_CHAIN& outline = polySet.Outline( i ); m_boardArea += std::fabs( outline.Area() );
// If checkbox "subtract holes" is checked
if( m_checkBoxSubtractHoles->GetValue() ) { for( int j = 0; j < polySet.HoleCount( i ); j++ ) m_boardArea -= std::fabs( polySet.Hole( i, j ).Area() ); }
if( boundingBoxCreated ) { bbox.Merge( outline.BBox() ); } else { bbox = outline.BBox(); boundingBoxCreated = true; } }
m_boardWidth = bbox.GetWidth(); m_boardHeight = bbox.GetHeight(); }}
void DIALOG_BOARD_STATISTICS::updateWidets(){ int totalPads = 0; int currentRow = 0;
for( const auto& type : m_padsTypes ) { m_gridPads->SetCellValue( currentRow, COL_LABEL, type.title ); m_gridPads->SetCellValue( currentRow, COL_AMOUNT, wxString::Format( wxT( "%i " ), type.qty ) ); totalPads += type.qty; currentRow++; }
m_gridPads->SetCellValue( currentRow, COL_LABEL, _( "Total:" ) ); m_gridPads->SetCellValue( currentRow, COL_AMOUNT, wxString::Format( "%i ", totalPads ) );
int totalVias = 0; currentRow = 0;
for( const auto& type : m_viasTypes ) { m_gridVias->SetCellValue( currentRow, COL_LABEL, type.title ); m_gridVias->SetCellValue( currentRow, COL_AMOUNT, wxString::Format( "%i ", type.qty ) ); totalVias += type.qty; currentRow++; }
m_gridVias->SetCellValue( currentRow, COL_LABEL, _( "Total:" ) ); m_gridVias->SetCellValue( currentRow, COL_AMOUNT, wxString::Format( "%i ", totalVias ) );
int totalFront = 0; int totalBack = 0;
// We don't use row 0, as there labels are
currentRow = 1;
for( const auto& type : m_componentsTypes ) { m_gridComponents->SetCellValue( currentRow, COL_LABEL, type.title ); m_gridComponents->SetCellValue( currentRow, COL_FRONT_SIDE, wxString::Format( "%i ", type.frontSideQty ) ); m_gridComponents->SetCellValue( currentRow, COL_BOTTOM_SIDE, wxString::Format( "%i ", type.backSideQty ) ); m_gridComponents->SetCellValue( currentRow, 3, wxString::Format( wxT( "%i " ), type.frontSideQty + type.backSideQty ) ); totalFront += type.frontSideQty; totalBack += type.backSideQty; currentRow++; }
m_gridComponents->SetCellValue( currentRow, COL_LABEL, _( "Total:" ) ); m_gridComponents->SetCellValue( currentRow, COL_FRONT_SIDE, wxString::Format( "%i ", totalFront ) ); m_gridComponents->SetCellValue( currentRow, COL_BOTTOM_SIDE, wxString::Format( "%i ", totalBack ) ); m_gridComponents->SetCellValue( currentRow, COL_TOTAL, wxString::Format( "%i ", totalFront + totalBack ) );
if( m_hasOutline ) { m_gridBoard->SetCellValue( ROW_BOARD_WIDTH, COL_AMOUNT, MessageTextFromValue( GetUserUnits(), m_boardWidth ) + " " ); m_gridBoard->SetCellValue( ROW_BOARD_HEIGHT, COL_AMOUNT, MessageTextFromValue( GetUserUnits(), m_boardHeight ) + " " ); m_gridBoard->SetCellValue( ROW_BOARD_AREA, COL_AMOUNT, MessageTextFromValue( GetUserUnits(), m_boardArea, true, EDA_DATA_TYPE::AREA ) ); } else { m_gridBoard->SetCellValue( ROW_BOARD_WIDTH, COL_AMOUNT, _( "unknown" ) ); m_gridBoard->SetCellValue( ROW_BOARD_HEIGHT, COL_AMOUNT, _( "unknown" ) ); m_gridBoard->SetCellValue( ROW_BOARD_AREA, COL_AMOUNT, _( "unknown" ) ); }
updateDrillGrid();
m_gridComponents->AutoSize(); m_gridPads->AutoSize(); m_gridBoard->AutoSize(); m_gridVias->AutoSize(); m_gridDrills->AutoSize();
adjustDrillGridColumns();}
void DIALOG_BOARD_STATISTICS::updateDrillGrid(){ BOARD* board = m_parentFrame->GetBoard(); int currentRow = 0;
for( const auto& type : m_drillTypes ) { wxString shapeStr; wxString startLayerStr; wxString stopLayerStr;
switch( type.shape ) { case PAD_DRILL_SHAPE_CIRCLE: shapeStr = _( "Round" ); break; case PAD_DRILL_SHAPE_OBLONG: shapeStr = _( "Slot" ); break; default: shapeStr = _( "???" ); break; }
if( type.startLayer == UNDEFINED_LAYER ) startLayerStr = _( "N/A" ); else startLayerStr = board->GetLayerName( type.startLayer );
if( type.stopLayer == UNDEFINED_LAYER ) stopLayerStr = _( "N/A" ); else stopLayerStr = board->GetLayerName( type.stopLayer );
m_gridDrills->SetCellValue( currentRow, drillType_t::COL_COUNT, wxString::Format( "%i", type.qty ) ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_SHAPE, shapeStr ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_X_SIZE, MessageTextFromValue( GetUserUnits(), type.xSize ) ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_Y_SIZE, MessageTextFromValue( GetUserUnits(), type.ySize ) ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_PLATED, type.isPlated ? _( "PTH" ) : _( "NPTH" ) ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_VIA_PAD, type.isPad ? _( "Pad" ) : _( "Via" ) ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_START_LAYER, startLayerStr ); m_gridDrills->SetCellValue( currentRow, drillType_t::COL_STOP_LAYER, stopLayerStr );
currentRow++; }}
void DIALOG_BOARD_STATISTICS::printGridToStringAsTable( wxGrid* aGrid, wxString& aStr, bool aUseRowLabels, bool aUseColLabels, bool aUseFirstColAsLabel ){ std::vector<int> widths( aGrid->GetNumberCols(), 0 ); int rowLabelsWidth = 0;
// Determine column widths.
if( aUseColLabels ) { for( int col = 0; col < aGrid->GetNumberCols(); col++ ) widths[col] = aGrid->GetColLabelValue( col ).length(); }
for( int row = 0; row < aGrid->GetNumberRows(); row++ ) { rowLabelsWidth = std::max<int>( rowLabelsWidth, aGrid->GetRowLabelValue( row ).length() );
for( int col = 0; col < aGrid->GetNumberCols(); col++ ) widths[col] = std::max<int>( widths[col], aGrid->GetCellValue( row, col ).length() ); }
// Print the cells.
wxString tmp;
// Print column labels.
aStr << "|";
if( aUseRowLabels ) { aStr.Append( ' ', rowLabelsWidth ); aStr << " |"; }
for( int col = 0; col < aGrid->GetNumberCols(); col++ ) { if( aUseColLabels ) tmp.Printf( " %*s |", widths[col], aGrid->GetColLabelValue( col ) ); else tmp.Printf( " %*s |", widths[col], aGrid->GetCellValue( 0, col ) ); aStr << tmp; }
aStr << "\n";
// Print column label horizontal separators.
aStr << "|";
if( aUseRowLabels ) { aStr.Append( '-', rowLabelsWidth ); aStr << "-|"; }
for( int col = 0; col < aGrid->GetNumberCols(); col++ ) { aStr << "-"; aStr.Append( '-', widths[col] ); aStr << "-|"; }
aStr << "\n";
// Print regular cells.
int firstRow = 0, firstCol = 0;
if( !aUseColLabels ) firstRow = 1;
if( !aUseRowLabels && aUseFirstColAsLabel ) firstCol = 1;
for( int row = firstRow; row < aGrid->GetNumberRows(); row++ ) { if( aUseRowLabels ) tmp.Printf( "|%-*s |", rowLabelsWidth, aGrid->GetRowLabelValue( row ) ); else if( aUseFirstColAsLabel ) tmp.Printf( "|%-*s |", widths[0], aGrid->GetCellValue( row, 0 ) ); else tmp.Printf( "|" ); aStr << tmp;
for( int col = firstCol; col < aGrid->GetNumberCols(); col++ ) { tmp.Printf( " %*s |", widths[col], aGrid->GetCellValue( row, col ) ); aStr << tmp; } aStr << "\n"; }}
void DIALOG_BOARD_STATISTICS::adjustDrillGridColumns(){ int newTotalWidth = m_gridDrills->GetClientSize().GetWidth(); int curTotalWidth = 0;
// Find the total current width
for( int i = 0; i < m_gridDrills->GetNumberCols(); i++ ) { if( i != drillType_t::COL_START_LAYER && i != drillType_t::COL_STOP_LAYER ) curTotalWidth += m_gridDrills->GetColSize( i ); }
// Resize the last two columns to fill all available space
int remainingWidth = newTotalWidth - curTotalWidth;
m_gridDrills->SetColSize( drillType_t::COL_START_LAYER, remainingWidth / 2 ); m_gridDrills->SetColSize( drillType_t::COL_STOP_LAYER, remainingWidth - remainingWidth / 2 );
m_gridDrills->Refresh();}
// If any checkbox clicked, we have to refresh dialog data
void DIALOG_BOARD_STATISTICS::checkboxClicked( wxCommandEvent& aEvent ){ s_savedDialogState.excludeNoPins = m_checkBoxExcludeComponentsNoPins->GetValue(); s_savedDialogState.subtractHoles = m_checkBoxSubtractHoles->GetValue(); refreshItemsTypes(); getDataFromPCB(); updateWidets(); Layout(); drillsPanel->Layout();}
void DIALOG_BOARD_STATISTICS::saveReportClicked( wxCommandEvent& aEvent ){ FILE* outFile; wxString msg; wxString boardName;
wxFileName fn = m_parentFrame->GetBoard()->GetFileName(); boardName = fn.GetName(); wxFileDialog saveFileDialog( this, _( "Save Report File" ), s_savedDialogState.saveReportFolder, s_savedDialogState.saveReportName, TextFileWildcard(), wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
if( saveFileDialog.ShowModal() == wxID_CANCEL ) return;
s_savedDialogState.saveReportFolder = wxPathOnly( saveFileDialog.GetPath() ); s_savedDialogState.saveReportName = saveFileDialog.GetFilename();
outFile = wxFopen( saveFileDialog.GetPath(), "wt" );
if( outFile == NULL ) { msg.Printf( _( "Unable to create file \"%s\"" ), saveFileDialog.GetPath() ); DisplayErrorMessage( this, msg ); return; }
msg << _( "PCB statistics report\n=====================" ) << "\n"; msg << wxS( "- " ) << _( "Date" ) << wxS( ": " ) << wxDateTime::Now().Format() << "\n"; msg << wxS( "- " ) << _( "Project" ) << wxS( ": " )<< Prj().GetProjectName() << "\n"; msg << wxS( "- " ) << _( "Board name" ) << wxS( ": " )<< boardName << "\n";
msg << "\n"; msg << _( "Board" ) << "\n-----\n";
if( m_hasOutline ) { msg << wxS( "- " ) << _( "Width" ) << wxS( ": " ) << MessageTextFromValue( GetUserUnits(), m_boardWidth ) << "\n"; msg << wxS( "- " ) << _( "Height" ) << wxS( ": " )<< MessageTextFromValue( GetUserUnits(), m_boardHeight ) << "\n"; msg << wxS( "- " ) << _( "Area" ) + wxS( ": " ) << MessageTextFromValue( GetUserUnits(), m_boardArea, true, EDA_DATA_TYPE::AREA ); msg << "\n"; } else { msg << wxS( "- " ) << _( "Width" ) << wxS( ": " ) << _( "unknown" ) << "\n"; msg << wxS( "- " ) << _( "Height" ) << wxS( ": " ) << _( "unknown" ) << "\n"; msg << wxS( "- " ) << _( "Area" ) << wxS( ": " ) << _( "unknown" ) << "\n"; }
msg << "\n"; msg << _( "Pads" ) << "\n----\n";
for( auto& type : m_padsTypes ) msg << "- " << type.title << " " << type.qty << "\n";
msg << "\n"; msg << _( "Vias" ) << "\n----\n";
for( auto& type : m_viasTypes ) msg << "- " << type.title << " " << type.qty << "\n";
// We will save data about components in the table.
// We have to calculate column widths
std::vector<int> widths; std::vector<wxString> labels{ "", _( "Front Side" ), _( "Back Side" ), _( "Total" ) }; wxString tmp;
widths.reserve( labels.size() ); for( const auto& label : labels ) widths.push_back( label.size() );
int frontTotal = 0; int backTotal = 0;
for( const auto& type : m_componentsTypes ) { // Get maximum width for left label column
widths[0] = std::max<int>( type.title.size(), widths[0] ); frontTotal += type.frontSideQty; backTotal += type.backSideQty; }
// Get maximum width for other columns
tmp.Printf( "%i", frontTotal ); widths[1] = std::max<int>( tmp.size(), widths[1] ); tmp.Printf( "%i", backTotal ); widths[2] = std::max<int>( tmp.size(), widths[2] ); tmp.Printf( "%i", frontTotal + backTotal ); widths[3] = std::max<int>( tmp.size(), widths[3] );
//Write components amount to file
msg << "\n"; msg << _( "Components" ) << "\n----------\n"; msg << "\n";
printGridToStringAsTable( m_gridComponents, msg, false, false, true );
msg << "\n"; msg << _( "Drill holes" ) << "\n-----------\n"; msg << "\n";
printGridToStringAsTable( m_gridDrills, msg, false, true, false );
if( fprintf( outFile, "%s", TO_UTF8( msg ) ) < 0 ) { msg.Printf( _( "Error writing to file \"%s\"" ), saveFileDialog.GetPath() ); DisplayErrorMessage( this, msg ); }
fclose( outFile );}
void DIALOG_BOARD_STATISTICS::drillGridSize( wxSizeEvent& aEvent ){ aEvent.Skip(); adjustDrillGridColumns();}
void DIALOG_BOARD_STATISTICS::drillGridSort( wxGridEvent& aEvent ){ drillType_t::COL_ID colId = static_cast<drillType_t::COL_ID>( aEvent.GetCol() ); bool ascending = !( m_gridDrills->IsSortingBy( colId ) && m_gridDrills->IsSortOrderAscending() );
sort( m_drillTypes.begin(), m_drillTypes.end(), drillType_t::COMPARE( colId, ascending ) );
updateDrillGrid();}
DIALOG_BOARD_STATISTICS::~DIALOG_BOARD_STATISTICS(){}
|