← Back to team overview

kicad-developers team mailing list archive

Re: [PATCH] Board statistics dialog

 

Hi Ian,
Sorry for delay, also I added feature to save statistics in txt file, as Dino suggested.

>Понедельник, 22 июля 2019, 23:57 +03:00 от Ian McInerney <ian.s.mcinerney@xxxxxxxx>:
>
>Alexander,
>
>Instead of declaring the 2 static variables separately, I would suggest creating a struct for the settings then store that as the static variable. For an example of this see the dialog_create_array.cpp file. This way if any new options must be added in the future, they can just be added to the struct very easily.
>
>-Ian
>On Mon, Jul 22, 2019 at 9:39 PM Alexander Shuklin < jasuramme@xxxxxxx > wrote:
>>Damn ><,
>>don't use last patch, please.
>>It doesn't count total vias amount. Use this one.
>>
>>
>>>Понедельник, 22 июля 2019, 22:14 +03:00 от Alexander Shuklin < jasuramme@xxxxxxx >:
>>>
>>>Hi,
>>>thanks for sharing experience, as I never used that translations or wxWidgets before. And I have no idea where else could I get that information. ))
>>>So, there's the patch with vias information and some tiny improvements. 
>>>
>>>
>>>>Понедельник, 22 июля 2019, 13:34 +03:00 от Ian McInerney < ian.s.mcinerney@xxxxxxxx >:
>>>>
>>>>
>>>>
>>>>On Mon, Jul 22, 2019 at 11:03 AM Dino Ghilardi < dino.ghilardi@xxxxxxxx > wrote:
>>>>>Hi Alexander,
>>>>>
>>>>>One possible solution for the translation could be put the ":" in a 
>>>>>different column of the table and right-align the field description text 
>>>>>(so all the colons will be aligned). A rapid google search shown that in 
>>>>>French and Vietnamese there should be a space before the colon, while in 
>>>>>the rest of the world there is not, so having the translation for the 
>>>>>":" word seems to make sense. Also another question arises: Is there 
>>>>>some language in which the colon should be another character before the 
>>>>>word? (I'm thinking about spanish where the question mark upside-down 
>>>>>appears before a question...)? ...conclusion: keeping "Height:" and 
>>>>>"Height" as two different words seem to be the solution that gives 
>>>>>maximum flexibility to translators.
>>>>>
>>>>
>>>>This actually doesn't give them as much flexibility. When translations are done, they need to examine the entire string that needs translating, so the ":" character should be included in the string. Separating out the two portions is the equivalent of saying that every lanugage will follow the same compositional rules.
>>>>  
>>>>>Another possible solution (probably better then the one above since it 
>>>>>just removes the problem) is to remove the ":" and have the cell borders 
>>>>>in a different color, just like the tables in the "board setup" dialog 
>>>>>(so that you can also take a look at that code to solve also the color 
>>>>>problem seeing how it was solved there). The advantage of this approach 
>>>>>is also having a more consistent "look" through all the dialogs.
>>>>>
>>>>>
>>>>>
>>>>>P.S. (a little bit off-topic):
>>>>>If you move the statistic window and check/uncheck one of the checkboxes 
>>>>>("subctract holes...." or "Exclude components...") the window "jumps" to 
>>>>>the center of the screen (its default position on open): do you have 
>>>>>also this behaviour or it is just on my debian-linux with gtk3?
>>>>>
>>>>>
>>>>>Cheers,
>>>>>Dino.
>>>>>
>>>>>On 22/07/19 10:13, Alexander Shuklin wrote:
>>>>>> Hi!
>>>>>> I'll have a look to add vias count to dialog.
>>>>>> There's some questions:
>>>>>> 
>>>>>> 1)I don't have too much experience with wxdialogs. There was commit on 
>>>>>> master, which says:
>>>>>>  >> remove settings for fg/bg color: the result is unpredictable: was 
>>>>>> black texts on black background on my computer.
>>>>>> And now I have all tables with data just in white boxes. Is it how it 
>>>>>> meant to be, or just some misbehavior on different systems? I use 
>>>>>> archlinux x64 OS.
>>>>>> there's screenshot in attachment
>>>>>> 
>>>>>> 2) Can we use something like _( "Height" ) + ":" for translation, not _( 
>>>>>> "Height:" )? As far as I understand, now we will need to have 2 
>>>>>> translations, first for "Height" and second for "Height:" but that's 
>>>>>> basically same word.
>>>>>> 
>>>>>>     Воскресенье, 21 июля 2019, 23:42 +03:00 от Dino Ghilardi
>>>>>>     < dino.ghilardi@xxxxxxxx >:
>>>>>> 
>>>>>>     Makes sense.
>>>>>>     Instead of a generic "via count" a more complete table similar to the
>>>>>>     one generated in the drill report file could be useful, but may be it
>>>>>>     can became quite long if a lot of different drill sizes are used (ok,
>>>>>>     scrollbars are made to handle that).
>>>>>>     Also having "vias", "blind vias" and "microvias" count man make sense
>>>>>>     (or at least having something like "microvias used: yes/no"), just to
>>>>>>     have in board statistics the information about the need of an advanced
>>>>>>     pcb manufacturing process.
>>>>>> 
>>>>>> 
>>>>>>     Cheers,
>>>>>>     Dino.
>>>>>> 
>>>>>> 
>>>>>>     On 21/07/19 20:54, Mark Roszko wrote:
>>>>>>      > > Since making every hole in the pcb costs time,  manufacturers
>>>>>>      > calculate the price of the PCB using also that number.
>>>>>>      >
>>>>>>      > A long time ago, holes cost alot. These days if your manufacturer is
>>>>>>      > charging alot per hole, you should run far away. Usually
>>>>>>     manufactuers
>>>>>>      > include 20k-40k holes in the base price per panel before they start
>>>>>>      > charging you tiny penny amounts for more in some increments of
>>>>>>      > thousands. The CNC machines these days as blazing fast at making the
>>>>>>      > holes required and they charge more for the drill bit being worn
>>>>>>     down
>>>>>>      > than the time.
>>>>>>      >
>>>>>>      > What does actually cost money is via type and size. Blind vias make
>>>>>>      > layer stackups a pain in the butt and micro vias needing lasers.
>>>>>>      > And also going below some via size can significantly add cost
>>>>>>     even if
>>>>>>      > not at microvia size because it requires different machines with
>>>>>>     more
>>>>>>      > precision and smaller drill bits.
>>>>>>      >
>>>>>>      >
>>>>>>      > If anything I would say to break down the statistics based on via
>>>>>>     type.
>>>>>>      >
>>>>>>      > On Sun, Jul 21, 2019 at 1:55 PM Dino Ghilardi
>>>>>>     < dino.ghilardi@xxxxxxxx <mailto: dino.ghilardi@xxxxxxxx >
>>>>>>      > <mailto: dino.ghilardi@xxxxxxxx >> wrote:
>>>>>>      >
>>>>>>      > I just tried the board statistics dialog and looks good, I like it.
>>>>>>      >
>>>>>>      > A thing I'd like to have to make it better is adding the number
>>>>>>     of vias
>>>>>>      > to the statistics: Since making every hole in the pcb costs time,
>>>>>>      > manufacturers calculate the price of the PCB using also that number.
>>>>>>      >
>>>>>>      > Also the option to save or print a text with the statistics report
>>>>>>      > would
>>>>>>      > be nice.
>>>>>>      >
>>>>>>      >
>>>>>>      > Cheers,
>>>>>>      > Dino.
>>>>>>      >
>>>>>> 
>>>>>>     _______________________________________________
>>>>>>     Mailing list:  https://launchpad.net/~kicad-developers
>>>>>>     Post to :  kicad-developers@xxxxxxxxxxxxxxxxxxx
>>>>>>     <mailto: kicad-developers@xxxxxxxxxxxxxxxxxxx >
>>>>>>     Unsubscribe :  https://launchpad.net/~kicad-developers
>>>>>>     More help :  https://help.launchpad.net/ListHelp
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> -- 
>>>>>> Alexander Shuklin
>>>>>
>>>>>
>>>>>_______________________________________________
>>>>>Mailing list:  https://launchpad.net/~kicad-developers
>>>>>Post to     :  kicad-developers@xxxxxxxxxxxxxxxxxxx
>>>>>Unsubscribe :  https://launchpad.net/~kicad-developers
>>>>>More help   :  https://help.launchpad.net/ListHelp
>>>
>>>
>>>-- 
>>>Alexander Shuklin
>>
>>
>>-- 
>>Alexander Shuklin


-- 
Alexander Shuklin
From f85dd5c77503b94982c6807eb35f125d7d99ca14 Mon Sep 17 00:00:00 2001
From: Alexander <alexandr.shuklin@biovitrum.ru>
Date: Mon, 22 Jul 2019 22:04:09 +0300
Subject: [PATCH] DIALOG_BOARD_STATISTICS modifications and fixes - added vias
 information to dialog - added "save txt report" feature - some code cleanup
 and readability fixes - fixed issue with dialog moving when checkbox clicked
 - now dialog saves checkboxes state
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="------------2.22.0"

This is a multi-part message in MIME format.
--------------2.22.0
Content-Type: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding: 8bit

---
 pcbnew/dialogs/dialog_board_statistics.cpp    | 294 ++++++++++++---
 pcbnew/dialogs/dialog_board_statistics.h      |  35 +-
 .../dialogs/dialog_board_statistics_base.cpp  | 304 +++++++++-------
 .../dialogs/dialog_board_statistics_base.fbp  | 342 +++++++++++++++---
 pcbnew/dialogs/dialog_board_statistics_base.h |  42 ++-
 5 files changed, 770 insertions(+), 247 deletions(-)


--------------2.22.0
Content-Type: text/x-patch; name="0001-DIALOG_BOARD_STATISTICS-modifications-and-fixes.patch"
Content-Transfer-Encoding: 8bit
Content-Disposition: attachment; filename="0001-DIALOG_BOARD_STATISTICS-modifications-and-fixes.patch"

diff --git a/pcbnew/dialogs/dialog_board_statistics.cpp b/pcbnew/dialogs/dialog_board_statistics.cpp
index 0a50da31d..f8b7d9cb2 100644
--- a/pcbnew/dialogs/dialog_board_statistics.cpp
+++ b/pcbnew/dialogs/dialog_board_statistics.cpp
@@ -25,45 +25,61 @@
 
 #include "dialog_board_statistics.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;
+    wxString saveReportFolder;
+    wxString saveReportName;
+};
+
+static DIALOG_BOARD_STATISTICS_SAVED_STATE s_savedDialogState;
+
 DIALOG_BOARD_STATISTICS::DIALOG_BOARD_STATISTICS( PCB_EDIT_FRAME* aParentFrame )
         : DIALOG_BOARD_STATISTICS_BASE( aParentFrame )
 {
     m_parentFrame = aParentFrame;
 
-    // Remove wxgrid's selection boxes
-    m_gridComponents->SetCellHighlightPenWidth( 0 );
-    m_gridPads->SetCellHighlightPenWidth( 0 );
-    m_gridBoard->SetCellHighlightPenWidth( 0 );
-    m_gridComponents->SetColMinimalAcceptableWidth( 80 );
-    m_gridPads->SetColMinimalAcceptableWidth( 80 );
-    m_gridBoard->SetColMinimalAcceptableWidth( 80 );
+    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( 0, COL_FRONT_SIDE, _( "Front Side" ) );
-    m_gridComponents->SetCellFont( 0, COL_FRONT_SIDE, headingFont );
-    m_gridComponents->SetCellValue( 0, COL_BOTTOM_SIDE, _( "Bottom Side" ) );
-    m_gridComponents->SetCellFont( 0, COL_BOTTOM_SIDE, headingFont );
-    m_gridComponents->SetCellValue( 0, COL_TOTAL, _( "Total" ) );
-    m_gridComponents->SetCellFont( 0, COL_TOTAL, headingFont );
-
-    m_gridComponents->SetCellAlignment( 0, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridComponents->SetCellAlignment( 1, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridComponents->SetCellAlignment( 2, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridComponents->SetCellAlignment( 3, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridComponents->SetCellAlignment( 4, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-
-    m_gridPads->SetCellAlignment( 0, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridPads->SetCellAlignment( 1, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridPads->SetCellAlignment( 2, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridPads->SetCellAlignment( 3, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
-    m_gridPads->SetCellAlignment( 4, 0, wxALIGN_LEFT, wxALIGN_CENTRE );
+    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, _( "Bottom 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 );
@@ -71,6 +87,27 @@ DIALOG_BOARD_STATISTICS::DIALOG_BOARD_STATISTICS( PCB_EDIT_FRAME* aParentFrame )
     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 )
+    {
+        fn.SetName( fn.GetName() + "_report" );
+        fn.SetExt( "txt" );
+        s_savedDialogState.saveReportName = fn.GetFullName();
+        s_savedDialogState.saveReportFolder = wxPathOnly( Prj().GetProjectFullName() );
+        s_savedDialogState.saveReportInitialized = true;
+    }
 }
 
 void DIALOG_BOARD_STATISTICS::refreshItemsTypes()
@@ -89,8 +126,13 @@ void DIALOG_BOARD_STATISTICS::refreshItemsTypes()
     m_padsTypes.push_back( padsType_t( PAD_ATTRIB_CONN, _( "Connector:" ) ) );
     m_padsTypes.push_back( padsType_t( PAD_ATTRIB_HOLE_NOT_PLATED, _( "NPTH:" ) ) );
 
+    m_viasTypes.clear();
+    m_viasTypes.push_back( viasType_t( VIA_THROUGH, _( "Through hole:" ) ) );
+    m_viasTypes.push_back( viasType_t( VIA_BLIND_BURIED, _( "Blind/buried:" ) ) );
+    m_viasTypes.push_back( viasType_t( VIA_MICROVIA, _( "Micro via:" ) ) );
+
     // If there not enough rows in grids, append some
-    size_t appendRows = m_componentsTypes.size() + 2 - m_gridComponents->GetNumberRows();
+    int appendRows = m_componentsTypes.size() + 2 - m_gridComponents->GetNumberRows();
 
     if( appendRows > 0 )
         m_gridComponents->AppendRows( appendRows );
@@ -99,6 +141,10 @@ void DIALOG_BOARD_STATISTICS::refreshItemsTypes()
 
     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()
@@ -115,6 +161,7 @@ void DIALOG_BOARD_STATISTICS::getDataFromPCB()
 {
     auto board = m_parentFrame->GetBoard();
 
+    // Get modules and pads count
     for( MODULE* module : board->Modules() )
     {
         auto& pads = module->Pads();
@@ -150,6 +197,29 @@ void DIALOG_BOARD_STATISTICS::getDataFromPCB()
         }
     }
 
+    // Get vias count
+    VIA* via;
+    for( auto& track : board->Tracks() )
+    {
+        if( track->Type() == PCB_VIA_T )
+        {
+            via = dynamic_cast<VIA*>( track );
+
+            // We have to check if cast was successful
+            if( via )
+            {
+                for( auto& type : m_viasTypes )
+                {
+                    if( via->GetViaType() == type.attribute )
+                    {
+                        type.qty++;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+
     bool           boundingBoxCreated = false; //flag if bounding box initialized
     BOX2I          bbox;
     SHAPE_POLY_SET polySet;
@@ -189,6 +259,11 @@ void DIALOG_BOARD_STATISTICS::getDataFromPCB()
                 }
             }
 
+            if( GetUserUnits() == INCHES )
+                m_boardArea /= ( IU_PER_MILS * IU_PER_MILS * 1000000 );
+            else
+                m_boardArea /= ( IU_PER_MM * IU_PER_MM );
+
             if( boundingBoxCreated )
             {
                 bbox.Merge( outline.BBox() );
@@ -210,13 +285,28 @@ void DIALOG_BOARD_STATISTICS::updateWidets()
     int currentRow = 0;
     for( auto& type : m_padsTypes )
     {
-        m_gridPads->SetCellValue( currentRow, 0, type.title );
-        m_gridPads->SetCellValue( currentRow, 1, wxString::Format( wxT( "%i " ), type.qty ) );
+        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, 0, _( "Total" ) );
-    m_gridPads->SetCellValue( currentRow, 1, wxString::Format( wxT( "%i " ), totalPads ) );
+    m_gridPads->SetCellValue( currentRow, COL_LABEL, _( "Total:" ) );
+    m_gridPads->SetCellValue( currentRow, COL_AMOUNT, wxString::Format( wxT( "%i " ), totalPads ) );
+
+    int totalVias = 0;
+    currentRow = 0;
+    for( auto& type : m_viasTypes )
+    {
+        m_gridVias->SetCellValue( currentRow, COL_LABEL, type.title );
+        m_gridVias->SetCellValue(
+                currentRow, COL_AMOUNT, wxString::Format( wxT( "%i " ), type.qty ) );
+        totalVias += type.qty;
+        currentRow++;
+    }
+    m_gridVias->SetCellValue( currentRow, COL_LABEL, _( "Total:" ) );
+    m_gridVias->SetCellValue( currentRow, COL_AMOUNT, wxString::Format( wxT( "%i " ), totalVias ) );
+
 
     int totalFront = 0;
     int totalBack = 0;
@@ -225,7 +315,7 @@ void DIALOG_BOARD_STATISTICS::updateWidets()
     currentRow = 1;
     for( auto& type : m_componentsTypes )
     {
-        m_gridComponents->SetCellValue( currentRow, 0, type.title );
+        m_gridComponents->SetCellValue( currentRow, COL_LABEL, type.title );
         m_gridComponents->SetCellValue(
                 currentRow, COL_FRONT_SIDE, wxString::Format( wxT( "%i " ), type.frontSideQty ) );
         m_gridComponents->SetCellValue(
@@ -236,7 +326,7 @@ void DIALOG_BOARD_STATISTICS::updateWidets()
         totalBack += type.backSideQty;
         currentRow++;
     }
-    m_gridComponents->SetCellValue( currentRow, 0, _( "Total" ) );
+    m_gridComponents->SetCellValue( currentRow, COL_LABEL, _( "Total:" ) );
     m_gridComponents->SetCellValue( currentRow, COL_FRONT_SIDE,
                                     wxString::Format( wxT( "%i " ), totalFront ) );
     m_gridComponents->SetCellValue( currentRow, COL_BOTTOM_SIDE, wxString::Format( wxT( "%i " ), totalBack ) );
@@ -245,34 +335,152 @@ void DIALOG_BOARD_STATISTICS::updateWidets()
 
     if( m_hasOutline )
     {
-        m_gridBoard->SetCellValue( 0, 1,
+        m_gridBoard->SetCellValue( ROW_BOARD_WIDTH, COL_AMOUNT,
                 MessageTextFromValue( m_parentFrame->GetUserUnits(), m_boardWidth, false ) + " " );
-        m_gridBoard->SetCellValue( 1, 1,
+        m_gridBoard->SetCellValue( ROW_BOARD_HEIGHT, COL_AMOUNT,
                 MessageTextFromValue( m_parentFrame->GetUserUnits(), m_boardHeight, false ) + " " );
-        if( GetUserUnits() == INCHES )
-            m_boardArea /= ( IU_PER_MILS * IU_PER_MILS * 1000000 );
-        else
-            m_boardArea /= ( IU_PER_MM * IU_PER_MM );
-        m_gridBoard->SetCellValue( 2, 1,
+        m_gridBoard->SetCellValue( ROW_BOARD_AREA, COL_AMOUNT,
                 wxString::Format( wxT( "%.3f %s²" ), m_boardArea,
                         GetAbbreviatedUnitsLabel( GetUserUnits(), false ) ) );
     }
     else
     {
-        m_gridBoard->SetCellValue( 0, 1, _( "unknown" ) );
-        m_gridBoard->SetCellValue( 1, 1, _( "unknown" ) );
-        m_gridBoard->SetCellValue( 2, 1, _( "unknown" ) );
+        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" ) );
     }
 
     m_gridComponents->AutoSize();
     m_gridPads->AutoSize();
     m_gridBoard->AutoSize();
+    m_gridVias->AutoSize();
 }
 
 // If any checkbox clicked, we have to refresh dialog data
 void DIALOG_BOARD_STATISTICS::checkboxClicked( wxCommandEvent& event )
 {
-    TransferDataToWindow();
+    s_savedDialogState.excludeNoPins = m_checkBoxExcludeComponentsNoPins->GetValue();
+    s_savedDialogState.subtractHoles = m_checkBoxSubtractHoles->GetValue();
+    refreshItemsTypes();
+    getDataFromPCB();
+    updateWidets();
+    Layout();
+    Fit();
+}
+
+void DIALOG_BOARD_STATISTICS::saveReportClicked( wxCommandEvent& event )
+{
+    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, _( "text files (*.txt)|*.txt" ),
+            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(), wxT( "wt" ) );
+
+    if( outFile == NULL )
+    {
+        msg.Printf( _( "Unable to create file \"%s\"" ), GetChars( saveFileDialog.GetPath() ) );
+        DisplayErrorMessage( this, msg );
+        return;
+    }
+    msg << _( "PCB statistics report\n" );
+    msg << _( "Date: " ) << wxDateTime::Now().Format() << "\n";
+    msg << _( "Project: " ) << Prj().GetProjectName() << "\n";
+    msg << _( "Board name: " ) << boardName << "\n";
+
+    msg << "\n";
+    msg << "Board\n";
+
+    if( m_hasOutline )
+    {
+        msg << _( "Width: " )
+            << MessageTextFromValue( m_parentFrame->GetUserUnits(), m_boardWidth, false ) << "\n";
+        msg << _( "Height: " )
+            << MessageTextFromValue( m_parentFrame->GetUserUnits(), m_boardHeight, false ) << "\n";
+        msg << _( "Area: " )
+            << wxString::Format( wxT( "%.3f %s²" ), m_boardArea,
+                       GetAbbreviatedUnitsLabel( GetUserUnits(), false ) )
+            << "\n";
+    }
+    else
+    {
+        msg << _( "Width: " ) << _( "unknown" ) << "\n";
+        msg << _( "Height: " ) << _( "unknown" ) << "\n";
+        msg << _( "Area: " ) << _( "unknown" ) << "\n";
+    }
+
+    msg << "\n";
+    msg << "Pads\n";
+    for( auto& type : m_padsTypes )
+        msg << type.title << " " << type.qty << "\n";
+
+    msg << "\n";
+    msg << "Vias\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
+    size_t   colsWidth[4];
+    wxString columns[4] = { "", _( "Front Side" ), _( "Back Side" ), _( "Total" ) };
+    wxString tmp;
+    for( int i = 0; i < 4; i++ )
+    {
+        colsWidth[i] = columns[i].size();
+    }
+    int frontTotal = 0;
+    int backTotal = 0;
+    for( auto& type : m_componentsTypes )
+    {
+        // Get maximum width for left label column
+        colsWidth[0] = std::max( type.title.size(), colsWidth[0] );
+        frontTotal += type.frontSideQty;
+        backTotal += type.backSideQty;
+    }
+
+    // Get maximum width for other columns
+    tmp.Printf( "%d", frontTotal );
+    colsWidth[1] = std::max( tmp.size(), colsWidth[1] );
+    tmp.Printf( "%d", backTotal );
+    colsWidth[2] = std::max( tmp.size(), colsWidth[2] );
+    tmp.Printf( "%d", frontTotal + backTotal );
+    colsWidth[3] = std::max( tmp.size(), colsWidth[3] );
+
+    //Write components amount to file
+    msg << "\n";
+    msg << _( "Components\n" );
+    tmp.Printf( "%-*s | %*s | %*s | %*s |\n", colsWidth[0], columns[0], colsWidth[1], columns[1],
+            colsWidth[2], columns[2], colsWidth[3], columns[3] );
+    msg += tmp;
+    for( auto& type : m_componentsTypes )
+    {
+        tmp.Printf( "%-*s | %*d | %*d | %*d |\n", colsWidth[0], type.title, colsWidth[1],
+                type.frontSideQty, colsWidth[2], type.backSideQty, colsWidth[3],
+                type.backSideQty + type.frontSideQty );
+        msg += tmp;
+    }
+    tmp.Printf( "%-*s | %*d | %*d | %*d |\n", colsWidth[0], _( "Total:" ), colsWidth[1], frontTotal,
+            colsWidth[2], backTotal, colsWidth[3], frontTotal + backTotal );
+    msg += tmp;
+
+    int success = fprintf( outFile, "%s", TO_UTF8( msg ) );
+    if( success < 0 )
+    {
+        msg.Printf( _( "Error writing to file \"%s\"" ), GetChars( saveFileDialog.GetPath() ) );
+        DisplayErrorMessage( this, msg );
+    }
+    fclose( outFile );
 }
 
 DIALOG_BOARD_STATISTICS::~DIALOG_BOARD_STATISTICS()
diff --git a/pcbnew/dialogs/dialog_board_statistics.h b/pcbnew/dialogs/dialog_board_statistics.h
index 5f26cd280..66dc16e6b 100644
--- a/pcbnew/dialogs/dialog_board_statistics.h
+++ b/pcbnew/dialogs/dialog_board_statistics.h
@@ -30,11 +30,14 @@
 #include <base_units.h>
 #include <class_board.h>
 #include <class_drawsegment.h>
+#include <class_track.h>
+#include <confirm.h>
 #include <dialog_board_statistics_base.h>
 #include <pad_shapes.h>
 #include <pcb_base_frame.h>
 #include <pcb_edit_frame.h>
-
+#include <project.h>
+#include <wx/datetime.h>
 
 /**
  * Class DIALOG_BOARD_STATISTIC
@@ -45,23 +48,25 @@ class DIALOG_BOARD_STATISTICS : public DIALOG_BOARD_STATISTICS_BASE
 {
 public:
     /**
-     * Struct holds information about pad type (such as SMD, THT, NPH
-     * and so on), which will be shown in the dialog. Also holds quantity
-     * of pads
+     * Struct to hold type information, which will be shown in dialog.
      */
-    struct padsType_t
+    template <typename T>
+    struct typeContainer_t
     {
-        padsType_t( PAD_ATTR_T aAttribute, wxString aTitle )
+        typeContainer_t<T>( T aAttribute, wxString aTitle )
                 : attribute( aAttribute ),
                   title( aTitle ),
                   qty( 0 )
         {
         }
-        PAD_ATTR_T attribute;
+        T          attribute;
         wxString   title;
         int        qty;
     };
 
+    using padsType_t = typeContainer_t<PAD_ATTR_T>;
+    using viasType_t = typeContainer_t<VIATYPE_T>;
+
     /**
      * Struct holds information about component type (such as SMD, THT,
      * Virtual and so on), which will be shown in the dialog. Holds both
@@ -84,6 +89,7 @@ public:
 
     using componentsTypeList_t = std::deque<componentsType_t>;
     using padsTypeList_t = std::deque<padsType_t>;
+    using viasTypeList_t = std::deque<viasType_t>;
 
     DIALOG_BOARD_STATISTICS( PCB_EDIT_FRAME* aParentFrame );
     ~DIALOG_BOARD_STATISTICS();
@@ -92,15 +98,13 @@ public:
     bool TransferDataToWindow() override;
 
     ///> Function to fill up all items types to be shown in the dialog.
-    void inline refreshItemsTypes();
+    void refreshItemsTypes();
 
     ///> Gets data from board
-    void inline getDataFromPCB();
+    void getDataFromPCB();
 
     ///> Applies data to dialog widgets
-    void inline updateWidets();
-
-    void checkboxClicked( wxCommandEvent& event ) override;
+    void updateWidets();
 
 private:
     PCB_EDIT_FRAME* m_parentFrame;
@@ -116,6 +120,13 @@ private:
 
     ///> Holds all pads types to be shown in the dialog
     padsTypeList_t  m_padsTypes;
+
+    ///> Holds all vias types to be shown in the dialog
+    viasTypeList_t m_viasTypes;
+
+    ///> Save board statistics to a file
+    void saveReportClicked( wxCommandEvent& event ) override;
+    void checkboxClicked( wxCommandEvent& event ) override;
 };
 
 #endif // __DIALOG_BOARD_STATISTICS_H
diff --git a/pcbnew/dialogs/dialog_board_statistics_base.cpp b/pcbnew/dialogs/dialog_board_statistics_base.cpp
index 791fd8999..b5a5c5cec 100644
--- a/pcbnew/dialogs/dialog_board_statistics_base.cpp
+++ b/pcbnew/dialogs/dialog_board_statistics_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jul 10 2019)
+// C++ code generated with wxFormBuilder (version Jun 25 2019)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO *NOT* EDIT THIS FILE!
@@ -11,183 +11,237 @@
 
 DIALOG_BOARD_STATISTICS_BASE::DIALOG_BOARD_STATISTICS_BASE( 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( wxDefaultSize, wxDefaultSize );
+    this->SetSizeHints( wxDefaultSize, wxDefaultSize );
 
-	wxBoxSizer* bMainBoxSizer;
-	bMainBoxSizer = new wxBoxSizer( wxVERTICAL );
+    wxBoxSizer* bMainBoxSizer;
+    bMainBoxSizer = new wxBoxSizer( wxVERTICAL );
 
-	wxGridBagSizer* gbContentsSizer;
-	gbContentsSizer = new wxGridBagSizer( 10, 20 );
-	gbContentsSizer->SetFlexibleDirection( wxBOTH );
-	gbContentsSizer->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_SPECIFIED );
+    wxFlexGridSizer* fgSizerContents;
+    fgSizerContents = new wxFlexGridSizer( 0, 2, 0, 0 );
+    fgSizerContents->AddGrowableCol( 0 );
+    fgSizerContents->AddGrowableCol( 1 );
+    fgSizerContents->AddGrowableRow( 0 );
+    fgSizerContents->AddGrowableRow( 1 );
+    fgSizerContents->SetFlexibleDirection( wxBOTH );
+    fgSizerContents->SetNonFlexibleGrowMode( wxFLEX_GROWMODE_ALL );
 
-	wxBoxSizer* bSizer2;
-	bSizer2 = new wxBoxSizer( wxVERTICAL );
+    wxBoxSizer* bSizerComponents;
+    bSizerComponents = new wxBoxSizer( wxVERTICAL );
 
-	wxStaticText* componentsLabel;
-	componentsLabel = new wxStaticText( this, wxID_ANY, _("Components"), wxDefaultPosition, wxDefaultSize, 0 );
-	componentsLabel->Wrap( -1 );
-	bSizer2->Add( componentsLabel, 0, wxALL, 5 );
+    wxStaticText* componentsLabel;
+    componentsLabel = new wxStaticText( this, wxID_ANY, _("Components"), wxDefaultPosition, wxDefaultSize, 0 );
+    componentsLabel->Wrap( -1 );
+    bSizerComponents->Add( componentsLabel, 0, wxALL, 5 );
 
-	m_gridComponents = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
+    m_gridComponents = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
 
-	// Grid
-	m_gridComponents->CreateGrid( 5, 4 );
-	m_gridComponents->EnableEditing( false );
-	m_gridComponents->EnableGridLines( false );
-	m_gridComponents->EnableDragGridSize( false );
-	m_gridComponents->SetMargins( 0, 0 );
+    // Grid
+    m_gridComponents->CreateGrid( 5, 4 );
+    m_gridComponents->EnableEditing( false );
+    m_gridComponents->EnableGridLines( false );
+    m_gridComponents->EnableDragGridSize( false );
+    m_gridComponents->SetMargins( 0, 0 );
 
-	// Columns
-	m_gridComponents->EnableDragColMove( false );
-	m_gridComponents->EnableDragColSize( true );
-	m_gridComponents->SetColLabelSize( 0 );
-	m_gridComponents->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
+    // Columns
+    m_gridComponents->EnableDragColMove( false );
+    m_gridComponents->EnableDragColSize( true );
+    m_gridComponents->SetColLabelSize( 0 );
+    m_gridComponents->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
-	// Rows
-	m_gridComponents->EnableDragRowSize( true );
-	m_gridComponents->SetRowLabelSize( 0 );
-	m_gridComponents->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
+    // Rows
+    m_gridComponents->EnableDragRowSize( true );
+    m_gridComponents->SetRowLabelSize( 0 );
+    m_gridComponents->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
-	// Label Appearance
-	m_gridComponents->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
+    // Label Appearance
+    m_gridComponents->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 
-	// Cell Defaults
-	m_gridComponents->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
-	bSizer2->Add( m_gridComponents, 0, wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+    // Cell Defaults
+    m_gridComponents->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
+    m_gridComponents->SetMaxSize( wxSize( -1,300 ) );
 
+    bSizerComponents->Add( m_gridComponents, 1, wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
 
-	gbContentsSizer->Add( bSizer2, wxGBPosition( 0, 0 ), wxGBSpan( 2, 1 ), wxEXPAND, 5 );
 
-	wxBoxSizer* bSizerPads;
-	bSizerPads = new wxBoxSizer( wxVERTICAL );
+    fgSizerContents->Add( bSizerComponents, 1, wxEXPAND, 5 );
 
-	wxStaticText* padsLabel;
-	padsLabel = new wxStaticText( this, wxID_ANY, _("Pads"), wxDefaultPosition, wxDefaultSize, 0 );
-	padsLabel->Wrap( -1 );
-	bSizerPads->Add( padsLabel, 0, wxALL, 5 );
+    wxBoxSizer* bSizerPads;
+    bSizerPads = new wxBoxSizer( wxVERTICAL );
 
-	m_gridPads = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
+    wxStaticText* padsLabel;
+    padsLabel = new wxStaticText( this, wxID_ANY, _("Pads"), wxDefaultPosition, wxDefaultSize, 0 );
+    padsLabel->Wrap( -1 );
+    bSizerPads->Add( padsLabel, 0, wxALL, 5 );
 
-	// Grid
-	m_gridPads->CreateGrid( 5, 2 );
-	m_gridPads->EnableEditing( false );
-	m_gridPads->EnableGridLines( false );
-	m_gridPads->EnableDragGridSize( false );
-	m_gridPads->SetMargins( 0, 0 );
+    m_gridPads = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
 
-	// Columns
-	m_gridPads->EnableDragColMove( false );
-	m_gridPads->EnableDragColSize( true );
-	m_gridPads->SetColLabelSize( 0 );
-	m_gridPads->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
+    // Grid
+    m_gridPads->CreateGrid( 5, 2 );
+    m_gridPads->EnableEditing( false );
+    m_gridPads->EnableGridLines( false );
+    m_gridPads->EnableDragGridSize( false );
+    m_gridPads->SetMargins( 0, 0 );
 
-	// Rows
-	m_gridPads->EnableDragRowSize( true );
-	m_gridPads->SetRowLabelSize( 0 );
-	m_gridPads->SetRowLabelAlignment( wxALIGN_RIGHT, wxALIGN_CENTER );
+    // Columns
+    m_gridPads->EnableDragColMove( false );
+    m_gridPads->EnableDragColSize( true );
+    m_gridPads->SetColLabelSize( 0 );
+    m_gridPads->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
-	// Label Appearance
-	m_gridPads->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
+    // Rows
+    m_gridPads->EnableDragRowSize( true );
+    m_gridPads->SetRowLabelSize( 0 );
+    m_gridPads->SetRowLabelAlignment( wxALIGN_RIGHT, wxALIGN_CENTER );
 
-	// Cell Defaults
-	m_gridPads->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
-	m_gridPads->SetMaxSize( wxSize( -1,300 ) );
+    // Label Appearance
+    m_gridPads->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 
-	bSizerPads->Add( m_gridPads, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+    // Cell Defaults
+    m_gridPads->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
+    m_gridPads->SetMaxSize( wxSize( -1,300 ) );
 
+    bSizerPads->Add( m_gridPads, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
 
-	gbContentsSizer->Add( bSizerPads, wxGBPosition( 0, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
 
-	wxBoxSizer* bSizerBrdSize;
-	bSizerBrdSize = new wxBoxSizer( wxVERTICAL );
+    fgSizerContents->Add( bSizerPads, 1, wxEXPAND, 5 );
 
-	wxStaticText* boardLabel;
-	boardLabel = new wxStaticText( this, wxID_ANY, _("Board Size"), wxDefaultPosition, wxDefaultSize, 0 );
-	boardLabel->Wrap( -1 );
-	bSizerBrdSize->Add( boardLabel, 0, wxALL, 5 );
+    wxBoxSizer* bSizerBrdSize;
+    bSizerBrdSize = new wxBoxSizer( wxVERTICAL );
 
-	m_gridBoard = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
+    wxStaticText* boardLabel;
+    boardLabel = new wxStaticText( this, wxID_ANY, _("Board Size"), wxDefaultPosition, wxDefaultSize, 0 );
+    boardLabel->Wrap( -1 );
+    bSizerBrdSize->Add( boardLabel, 0, wxALL, 5 );
 
-	// Grid
-	m_gridBoard->CreateGrid( 3, 2 );
-	m_gridBoard->EnableEditing( false );
-	m_gridBoard->EnableGridLines( false );
-	m_gridBoard->EnableDragGridSize( false );
-	m_gridBoard->SetMargins( 0, 0 );
+    m_gridBoard = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
 
-	// Columns
-	m_gridBoard->EnableDragColMove( false );
-	m_gridBoard->EnableDragColSize( true );
-	m_gridBoard->SetColLabelSize( 0 );
-	m_gridBoard->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
+    // Grid
+    m_gridBoard->CreateGrid( 3, 2 );
+    m_gridBoard->EnableEditing( false );
+    m_gridBoard->EnableGridLines( false );
+    m_gridBoard->EnableDragGridSize( false );
+    m_gridBoard->SetMargins( 0, 0 );
 
-	// Rows
-	m_gridBoard->EnableDragRowSize( true );
-	m_gridBoard->SetRowLabelSize( 0 );
-	m_gridBoard->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
+    // Columns
+    m_gridBoard->EnableDragColMove( false );
+    m_gridBoard->EnableDragColSize( true );
+    m_gridBoard->SetColLabelSize( 0 );
+    m_gridBoard->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
-	// Label Appearance
-	m_gridBoard->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
+    // Rows
+    m_gridBoard->EnableDragRowSize( true );
+    m_gridBoard->SetRowLabelSize( 0 );
+    m_gridBoard->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
-	// Cell Defaults
-	m_gridBoard->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
-	m_gridBoard->SetMaxSize( wxSize( -1,300 ) );
+    // Label Appearance
+    m_gridBoard->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 
-	bSizerBrdSize->Add( m_gridBoard, 0, wxBOTTOM|wxRIGHT|wxLEFT, 5 );
+    // Cell Defaults
+    m_gridBoard->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
+    m_gridBoard->SetMaxSize( wxSize( -1,300 ) );
 
+    bSizerBrdSize->Add( m_gridBoard, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
 
-	gbContentsSizer->Add( bSizerBrdSize, wxGBPosition( 1, 1 ), wxGBSpan( 1, 1 ), wxEXPAND, 5 );
 
+    fgSizerContents->Add( bSizerBrdSize, 1, wxEXPAND, 5 );
 
-	gbContentsSizer->AddGrowableCol( 0 );
-	gbContentsSizer->AddGrowableCol( 1 );
-	gbContentsSizer->AddGrowableRow( 0 );
-	gbContentsSizer->AddGrowableRow( 1 );
+    wxBoxSizer* bSizerVias;
+    bSizerVias = new wxBoxSizer( wxVERTICAL );
 
-	bMainBoxSizer->Add( gbContentsSizer, 1, wxEXPAND|wxALL, 10 );
+    viasLabel = new wxStaticText( this, wxID_ANY, _("Vias"), wxDefaultPosition, wxDefaultSize, 0 );
+    viasLabel->Wrap( -1 );
+    bSizerVias->Add( viasLabel, 0, wxALL, 5 );
 
-	m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
-	bMainBoxSizer->Add( m_staticline1, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 10 );
+    m_gridVias = new wxGrid( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxVSCROLL );
 
-	wxGridSizer* gOptionsSizer;
-	gOptionsSizer = new wxGridSizer( 0, 2, 0, 0 );
+    // Grid
+    m_gridVias->CreateGrid( 4, 2 );
+    m_gridVias->EnableEditing( false );
+    m_gridVias->EnableGridLines( false );
+    m_gridVias->EnableDragGridSize( false );
+    m_gridVias->SetMargins( 0, 0 );
 
-	m_checkBoxSubtractHoles = new wxCheckBox( this, wxID_ANY, _("Subtract holes from board area"), wxDefaultPosition, wxDefaultSize, 0 );
-	gOptionsSizer->Add( m_checkBoxSubtractHoles, 0, wxALL|wxEXPAND, 5 );
+    // Columns
+    m_gridVias->EnableDragColMove( false );
+    m_gridVias->EnableDragColSize( true );
+    m_gridVias->SetColLabelSize( 0 );
+    m_gridVias->SetColLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
-	m_checkBoxExcludeComponentsNoPins = new wxCheckBox( this, wxID_ANY, _("Exclude components with no pins"), wxDefaultPosition, wxDefaultSize, 0 );
-	gOptionsSizer->Add( m_checkBoxExcludeComponentsNoPins, 0, wxALL|wxEXPAND, 5 );
+    // Rows
+    m_gridVias->EnableDragRowSize( true );
+    m_gridVias->SetRowLabelSize( 0 );
+    m_gridVias->SetRowLabelAlignment( wxALIGN_CENTER, wxALIGN_CENTER );
 
+    // Label Appearance
+    m_gridVias->SetLabelFont( wxFont( wxNORMAL_FONT->GetPointSize(), wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL, false, wxEmptyString ) );
 
-	bMainBoxSizer->Add( gOptionsSizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
+    // Cell Defaults
+    m_gridVias->SetDefaultCellAlignment( wxALIGN_CENTER, wxALIGN_TOP );
+    m_gridVias->SetMaxSize( wxSize( -1,300 ) );
 
-	m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
-	bMainBoxSizer->Add( m_staticline2, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
+    bSizerVias->Add( m_gridVias, 1, wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT, 5 );
 
-	m_sdbControlSizer = new wxStdDialogButtonSizer();
-	m_sdbControlSizerOK = new wxButton( this, wxID_OK );
-	m_sdbControlSizer->AddButton( m_sdbControlSizerOK );
-	m_sdbControlSizer->Realize();
 
-	bMainBoxSizer->Add( m_sdbControlSizer, 0, wxALIGN_RIGHT|wxBOTTOM|wxLEFT|wxRIGHT|wxTOP, 5 );
+    fgSizerContents->Add( bSizerVias, 1, wxEXPAND, 5 );
 
 
-	this->SetSizer( bMainBoxSizer );
-	this->Layout();
-	bMainBoxSizer->Fit( this );
+    bMainBoxSizer->Add( fgSizerContents, 1, wxEXPAND|wxLEFT|wxRIGHT, 10 );
 
-	this->Centre( wxBOTH );
+    m_staticline1 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+    bMainBoxSizer->Add( m_staticline1, 0, wxEXPAND|wxBOTTOM|wxRIGHT|wxLEFT, 10 );
 
-	// Connect Events
-	m_checkBoxSubtractHoles->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
-	m_checkBoxExcludeComponentsNoPins->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
+    wxGridSizer* gOptionsSizer;
+    gOptionsSizer = new wxGridSizer( 0, 2, 0, 0 );
+
+    m_checkBoxSubtractHoles = new wxCheckBox( this, wxID_ANY, _("Subtract holes from board area"), wxDefaultPosition, wxDefaultSize, 0 );
+    gOptionsSizer->Add( m_checkBoxSubtractHoles, 0, wxALL|wxEXPAND, 5 );
+
+    m_checkBoxExcludeComponentsNoPins = new wxCheckBox( this, wxID_ANY, _("Exclude components with no pins"), wxDefaultPosition, wxDefaultSize, 0 );
+    gOptionsSizer->Add( m_checkBoxExcludeComponentsNoPins, 0, wxALL|wxEXPAND, 5 );
+
+
+    bMainBoxSizer->Add( gOptionsSizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 10 );
+
+    m_staticline2 = new wxStaticLine( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
+    bMainBoxSizer->Add( m_staticline2, 0, wxEXPAND|wxTOP|wxRIGHT|wxLEFT, 10 );
+
+    wxBoxSizer* bSizer6;
+    bSizer6 = new wxBoxSizer( wxHORIZONTAL );
+
+
+    bSizer6->Add( 0, 0, 1, wxEXPAND, 5 );
+
+    m_buttonSaveReport = new wxButton( this, wxID_ANY, _("Save report"), wxDefaultPosition, wxDefaultSize, 0 );
+    bSizer6->Add( m_buttonSaveReport, 0, wxALL, 5 );
+
+    m_sdbControlSizer = new wxStdDialogButtonSizer();
+    m_sdbControlSizerOK = new wxButton( this, wxID_OK );
+    m_sdbControlSizer->AddButton( m_sdbControlSizerOK );
+    m_sdbControlSizer->Realize();
+
+    bSizer6->Add( m_sdbControlSizer, 0, wxALIGN_RIGHT|wxBOTTOM|wxLEFT|wxRIGHT|wxTOP, 5 );
+
+
+    bMainBoxSizer->Add( bSizer6, 0, wxEXPAND, 5 );
+
+
+    this->SetSizer( bMainBoxSizer );
+    this->Layout();
+    bMainBoxSizer->Fit( this );
+
+    this->Centre( wxBOTH );
+
+    // Connect Events
+    m_checkBoxSubtractHoles->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
+    m_checkBoxExcludeComponentsNoPins->Connect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
+    m_buttonSaveReport->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::saveReportClicked ), NULL, this );
 }
 
 DIALOG_BOARD_STATISTICS_BASE::~DIALOG_BOARD_STATISTICS_BASE()
 {
-	// Disconnect Events
-	m_checkBoxSubtractHoles->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
-	m_checkBoxExcludeComponentsNoPins->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
+    // Disconnect Events
+    m_checkBoxSubtractHoles->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
+    m_checkBoxExcludeComponentsNoPins->Disconnect( wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::checkboxClicked ), NULL, this );
+    m_buttonSaveReport->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( DIALOG_BOARD_STATISTICS_BASE::saveReportClicked ), NULL, this );
 
 }
diff --git a/pcbnew/dialogs/dialog_board_statistics_base.fbp b/pcbnew/dialogs/dialog_board_statistics_base.fbp
index 8184de0ba..e8b4979c9 100644
--- a/pcbnew/dialogs/dialog_board_statistics_base.fbp
+++ b/pcbnew/dialogs/dialog_board_statistics_base.fbp
@@ -14,7 +14,6 @@
         <property name="file">dialog_board_statistics_base</property>
         <property name="first_id">1000</property>
         <property name="help_provider">none</property>
-        <property name="image_path_wrapper_function_name"></property>
         <property name="indent_with_spaces"></property>
         <property name="internationalize">1</property>
         <property name="name">DIALOG_BOARD_STATISTCS_BASE</property>
@@ -26,7 +25,6 @@
         <property name="skip_php_events">1</property>
         <property name="skip_python_events">1</property>
         <property name="ui_table">UI</property>
-        <property name="use_array_enum">0</property>
         <property name="use_enum">0</property>
         <property name="use_microsoft_bom">0</property>
         <object class="Dialog" expanded="1">
@@ -62,29 +60,27 @@
                 <property name="permission">none</property>
                 <object class="sizeritem" expanded="1">
                     <property name="border">10</property>
-                    <property name="flag">wxEXPAND|wxALL</property>
+                    <property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
                     <property name="proportion">1</property>
-                    <object class="wxGridBagSizer" expanded="1">
-                        <property name="empty_cell_size"></property>
+                    <object class="wxFlexGridSizer" expanded="1">
+                        <property name="cols">2</property>
                         <property name="flexible_direction">wxBOTH</property>
                         <property name="growablecols">0,1</property>
                         <property name="growablerows">0,1</property>
-                        <property name="hgap">20</property>
+                        <property name="hgap">0</property>
                         <property name="minimum_size"></property>
-                        <property name="name">gbContentsSizer</property>
-                        <property name="non_flexible_grow_mode">wxFLEX_GROWMODE_SPECIFIED</property>
+                        <property name="name">fgSizerContents</property>
+                        <property name="non_flexible_grow_mode">wxFLEX_GROWMODE_ALL</property>
                         <property name="permission">none</property>
-                        <property name="vgap">10</property>
-                        <object class="gbsizeritem" expanded="1">
+                        <property name="rows">0</property>
+                        <property name="vgap">0</property>
+                        <object class="sizeritem" expanded="1">
                             <property name="border">5</property>
-                            <property name="colspan">1</property>
-                            <property name="column">0</property>
                             <property name="flag">wxEXPAND</property>
-                            <property name="row">0</property>
-                            <property name="rowspan">2</property>
+                            <property name="proportion">1</property>
                             <object class="wxBoxSizer" expanded="1">
                                 <property name="minimum_size"></property>
-                                <property name="name">bSizer2</property>
+                                <property name="name">bSizerComponents</property>
                                 <property name="orient">wxVERTICAL</property>
                                 <property name="permission">none</property>
                                 <object class="sizeritem" expanded="1">
@@ -150,8 +146,8 @@
                                 </object>
                                 <object class="sizeritem" expanded="1">
                                     <property name="border">5</property>
-                                    <property name="flag">wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxRIGHT|wxLEFT</property>
-                                    <property name="proportion">0</property>
+                                    <property name="flag">wxALIGN_CENTER|wxALIGN_CENTER_HORIZONTAL|wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property>
+                                    <property name="proportion">1</property>
                                     <object class="wxGrid" expanded="1">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
@@ -207,7 +203,7 @@
                                         <property name="margin_width">0</property>
                                         <property name="max_size"></property>
                                         <property name="maximize_button">0</property>
-                                        <property name="maximum_size">-1,-1</property>
+                                        <property name="maximum_size">-1,300</property>
                                         <property name="min_size"></property>
                                         <property name="minimize_button">0</property>
                                         <property name="minimum_size"></property>
@@ -238,13 +234,10 @@
                                 </object>
                             </object>
                         </object>
-                        <object class="gbsizeritem" expanded="1">
+                        <object class="sizeritem" expanded="1">
                             <property name="border">5</property>
-                            <property name="colspan">1</property>
-                            <property name="column">1</property>
                             <property name="flag">wxEXPAND</property>
-                            <property name="row">0</property>
-                            <property name="rowspan">1</property>
+                            <property name="proportion">1</property>
                             <object class="wxBoxSizer" expanded="1">
                                 <property name="minimum_size"></property>
                                 <property name="name">bSizerPads</property>
@@ -313,8 +306,8 @@
                                 </object>
                                 <object class="sizeritem" expanded="1">
                                     <property name="border">5</property>
-                                    <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
-                                    <property name="proportion">0</property>
+                                    <property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property>
+                                    <property name="proportion">1</property>
                                     <object class="wxGrid" expanded="1">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
@@ -401,13 +394,10 @@
                                 </object>
                             </object>
                         </object>
-                        <object class="gbsizeritem" expanded="1">
+                        <object class="sizeritem" expanded="1">
                             <property name="border">5</property>
-                            <property name="colspan">1</property>
-                            <property name="column">1</property>
                             <property name="flag">wxEXPAND</property>
-                            <property name="row">1</property>
-                            <property name="rowspan">1</property>
+                            <property name="proportion">1</property>
                             <object class="wxBoxSizer" expanded="1">
                                 <property name="minimum_size"></property>
                                 <property name="name">bSizerBrdSize</property>
@@ -476,8 +466,8 @@
                                 </object>
                                 <object class="sizeritem" expanded="1">
                                     <property name="border">5</property>
-                                    <property name="flag">wxBOTTOM|wxRIGHT|wxLEFT</property>
-                                    <property name="proportion">0</property>
+                                    <property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property>
+                                    <property name="proportion">1</property>
                                     <object class="wxGrid" expanded="1">
                                         <property name="BottomDockable">1</property>
                                         <property name="LeftDockable">1</property>
@@ -564,6 +554,166 @@
                                 </object>
                             </object>
                         </object>
+                        <object class="sizeritem" expanded="1">
+                            <property name="border">5</property>
+                            <property name="flag">wxEXPAND</property>
+                            <property name="proportion">1</property>
+                            <object class="wxBoxSizer" expanded="1">
+                                <property name="minimum_size"></property>
+                                <property name="name">bSizerVias</property>
+                                <property name="orient">wxVERTICAL</property>
+                                <property name="permission">none</property>
+                                <object class="sizeritem" expanded="1">
+                                    <property name="border">5</property>
+                                    <property name="flag">wxALL</property>
+                                    <property name="proportion">0</property>
+                                    <object class="wxStaticText" expanded="1">
+                                        <property name="BottomDockable">1</property>
+                                        <property name="LeftDockable">1</property>
+                                        <property name="RightDockable">1</property>
+                                        <property name="TopDockable">1</property>
+                                        <property name="aui_layer"></property>
+                                        <property name="aui_name"></property>
+                                        <property name="aui_position"></property>
+                                        <property name="aui_row"></property>
+                                        <property name="best_size"></property>
+                                        <property name="bg"></property>
+                                        <property name="caption"></property>
+                                        <property name="caption_visible">1</property>
+                                        <property name="center_pane">0</property>
+                                        <property name="close_button">1</property>
+                                        <property name="context_help"></property>
+                                        <property name="context_menu">1</property>
+                                        <property name="default_pane">0</property>
+                                        <property name="dock">Dock</property>
+                                        <property name="dock_fixed">0</property>
+                                        <property name="docking">Left</property>
+                                        <property name="enabled">1</property>
+                                        <property name="fg"></property>
+                                        <property name="floatable">1</property>
+                                        <property name="font"></property>
+                                        <property name="gripper">0</property>
+                                        <property name="hidden">0</property>
+                                        <property name="id">wxID_ANY</property>
+                                        <property name="label">Vias</property>
+                                        <property name="markup">0</property>
+                                        <property name="max_size"></property>
+                                        <property name="maximize_button">0</property>
+                                        <property name="maximum_size"></property>
+                                        <property name="min_size"></property>
+                                        <property name="minimize_button">0</property>
+                                        <property name="minimum_size"></property>
+                                        <property name="moveable">1</property>
+                                        <property name="name">viasLabel</property>
+                                        <property name="pane_border">1</property>
+                                        <property name="pane_position"></property>
+                                        <property name="pane_size"></property>
+                                        <property name="permission">protected</property>
+                                        <property name="pin_button">1</property>
+                                        <property name="pos"></property>
+                                        <property name="resize">Resizable</property>
+                                        <property name="show">1</property>
+                                        <property name="size"></property>
+                                        <property name="style"></property>
+                                        <property name="subclass">; ; forward_declare</property>
+                                        <property name="toolbar_pane">0</property>
+                                        <property name="tooltip"></property>
+                                        <property name="window_extra_style"></property>
+                                        <property name="window_name"></property>
+                                        <property name="window_style"></property>
+                                        <property name="wrap">-1</property>
+                                    </object>
+                                </object>
+                                <object class="sizeritem" expanded="1">
+                                    <property name="border">5</property>
+                                    <property name="flag">wxBOTTOM|wxEXPAND|wxLEFT|wxRIGHT</property>
+                                    <property name="proportion">1</property>
+                                    <object class="wxGrid" expanded="1">
+                                        <property name="BottomDockable">1</property>
+                                        <property name="LeftDockable">1</property>
+                                        <property name="RightDockable">1</property>
+                                        <property name="TopDockable">1</property>
+                                        <property name="aui_layer"></property>
+                                        <property name="aui_name"></property>
+                                        <property name="aui_position"></property>
+                                        <property name="aui_row"></property>
+                                        <property name="autosize_cols">0</property>
+                                        <property name="autosize_rows">0</property>
+                                        <property name="best_size"></property>
+                                        <property name="bg"></property>
+                                        <property name="caption"></property>
+                                        <property name="caption_visible">1</property>
+                                        <property name="cell_bg"></property>
+                                        <property name="cell_font"></property>
+                                        <property name="cell_horiz_alignment">wxALIGN_CENTER</property>
+                                        <property name="cell_text"></property>
+                                        <property name="cell_vert_alignment">wxALIGN_TOP</property>
+                                        <property name="center_pane">0</property>
+                                        <property name="close_button">1</property>
+                                        <property name="col_label_horiz_alignment">wxALIGN_CENTER</property>
+                                        <property name="col_label_size">0</property>
+                                        <property name="col_label_values"></property>
+                                        <property name="col_label_vert_alignment">wxALIGN_CENTER</property>
+                                        <property name="cols">2</property>
+                                        <property name="column_sizes"></property>
+                                        <property name="context_help"></property>
+                                        <property name="context_menu">1</property>
+                                        <property name="default_pane">0</property>
+                                        <property name="dock">Dock</property>
+                                        <property name="dock_fixed">0</property>
+                                        <property name="docking">Left</property>
+                                        <property name="drag_col_move">0</property>
+                                        <property name="drag_col_size">1</property>
+                                        <property name="drag_grid_size">0</property>
+                                        <property name="drag_row_size">1</property>
+                                        <property name="editing">0</property>
+                                        <property name="enabled">1</property>
+                                        <property name="fg"></property>
+                                        <property name="floatable">1</property>
+                                        <property name="font"></property>
+                                        <property name="grid_line_color"></property>
+                                        <property name="grid_lines">0</property>
+                                        <property name="gripper">0</property>
+                                        <property name="hidden">0</property>
+                                        <property name="id">wxID_ANY</property>
+                                        <property name="label_bg"></property>
+                                        <property name="label_font">,90,90,-1,70,0</property>
+                                        <property name="label_text"></property>
+                                        <property name="margin_height">0</property>
+                                        <property name="margin_width">0</property>
+                                        <property name="max_size"></property>
+                                        <property name="maximize_button">0</property>
+                                        <property name="maximum_size">-1,300</property>
+                                        <property name="min_size"></property>
+                                        <property name="minimize_button">0</property>
+                                        <property name="minimum_size"></property>
+                                        <property name="moveable">1</property>
+                                        <property name="name">m_gridVias</property>
+                                        <property name="pane_border">1</property>
+                                        <property name="pane_position"></property>
+                                        <property name="pane_size"></property>
+                                        <property name="permission">protected</property>
+                                        <property name="pin_button">1</property>
+                                        <property name="pos"></property>
+                                        <property name="resize">Resizable</property>
+                                        <property name="row_label_horiz_alignment">wxALIGN_CENTER</property>
+                                        <property name="row_label_size">0</property>
+                                        <property name="row_label_values"></property>
+                                        <property name="row_label_vert_alignment">wxALIGN_CENTER</property>
+                                        <property name="row_sizes"></property>
+                                        <property name="rows">4</property>
+                                        <property name="show">1</property>
+                                        <property name="size"></property>
+                                        <property name="subclass">; ; forward_declare</property>
+                                        <property name="toolbar_pane">0</property>
+                                        <property name="tooltip"></property>
+                                        <property name="window_extra_style"></property>
+                                        <property name="window_name"></property>
+                                        <property name="window_style">wxVSCROLL</property>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
                     </object>
                 </object>
                 <object class="sizeritem" expanded="1">
@@ -628,7 +778,7 @@
                     <property name="border">10</property>
                     <property name="flag">wxEXPAND|wxLEFT|wxRIGHT</property>
                     <property name="proportion">0</property>
-                    <object class="wxGridSizer" expanded="1">
+                    <object class="wxGridSizer" expanded="0">
                         <property name="cols">2</property>
                         <property name="hgap">0</property>
                         <property name="minimum_size"></property>
@@ -636,11 +786,11 @@
                         <property name="permission">none</property>
                         <property name="rows">0</property>
                         <property name="vgap">0</property>
-                        <object class="sizeritem" expanded="1">
+                        <object class="sizeritem" expanded="0">
                             <property name="border">5</property>
                             <property name="flag">wxALL|wxEXPAND</property>
                             <property name="proportion">0</property>
-                            <object class="wxCheckBox" expanded="1">
+                            <object class="wxCheckBox" expanded="0">
                                 <property name="BottomDockable">1</property>
                                 <property name="LeftDockable">1</property>
                                 <property name="RightDockable">1</property>
@@ -701,11 +851,11 @@
                                 <event name="OnCheckBox">checkboxClicked</event>
                             </object>
                         </object>
-                        <object class="sizeritem" expanded="1">
+                        <object class="sizeritem" expanded="0">
                             <property name="border">5</property>
                             <property name="flag">wxALL|wxEXPAND</property>
                             <property name="proportion">0</property>
-                            <object class="wxCheckBox" expanded="1">
+                            <object class="wxCheckBox" expanded="0">
                                 <property name="BottomDockable">1</property>
                                 <property name="LeftDockable">1</property>
                                 <property name="RightDockable">1</property>
@@ -828,20 +978,114 @@
                 </object>
                 <object class="sizeritem" expanded="1">
                     <property name="border">5</property>
-                    <property name="flag">wxALIGN_RIGHT|wxBOTTOM|wxLEFT|wxRIGHT|wxTOP</property>
+                    <property name="flag">wxEXPAND</property>
                     <property name="proportion">0</property>
-                    <object class="wxStdDialogButtonSizer" expanded="1">
-                        <property name="Apply">0</property>
-                        <property name="Cancel">0</property>
-                        <property name="ContextHelp">0</property>
-                        <property name="Help">0</property>
-                        <property name="No">0</property>
-                        <property name="OK">1</property>
-                        <property name="Save">0</property>
-                        <property name="Yes">0</property>
+                    <object class="wxBoxSizer" expanded="1">
                         <property name="minimum_size"></property>
-                        <property name="name">m_sdbControlSizer</property>
-                        <property name="permission">protected</property>
+                        <property name="name">bSizer6</property>
+                        <property name="orient">wxHORIZONTAL</property>
+                        <property name="permission">none</property>
+                        <object class="sizeritem" expanded="1">
+                            <property name="border">5</property>
+                            <property name="flag">wxEXPAND</property>
+                            <property name="proportion">1</property>
+                            <object class="spacer" expanded="1">
+                                <property name="height">0</property>
+                                <property name="permission">protected</property>
+                                <property name="width">0</property>
+                            </object>
+                        </object>
+                        <object class="sizeritem" expanded="1">
+                            <property name="border">5</property>
+                            <property name="flag">wxALL</property>
+                            <property name="proportion">0</property>
+                            <object class="wxButton" expanded="1">
+                                <property name="BottomDockable">1</property>
+                                <property name="LeftDockable">1</property>
+                                <property name="RightDockable">1</property>
+                                <property name="TopDockable">1</property>
+                                <property name="aui_layer"></property>
+                                <property name="aui_name"></property>
+                                <property name="aui_position"></property>
+                                <property name="aui_row"></property>
+                                <property name="best_size"></property>
+                                <property name="bg"></property>
+                                <property name="bitmap"></property>
+                                <property name="caption"></property>
+                                <property name="caption_visible">1</property>
+                                <property name="center_pane">0</property>
+                                <property name="close_button">1</property>
+                                <property name="context_help"></property>
+                                <property name="context_menu">1</property>
+                                <property name="current"></property>
+                                <property name="default">0</property>
+                                <property name="default_pane">0</property>
+                                <property name="disabled"></property>
+                                <property name="dock">Dock</property>
+                                <property name="dock_fixed">0</property>
+                                <property name="docking">Left</property>
+                                <property name="enabled">1</property>
+                                <property name="fg"></property>
+                                <property name="floatable">1</property>
+                                <property name="focus"></property>
+                                <property name="font"></property>
+                                <property name="gripper">0</property>
+                                <property name="hidden">0</property>
+                                <property name="id">wxID_ANY</property>
+                                <property name="label">Save report</property>
+                                <property name="margins"></property>
+                                <property name="markup">0</property>
+                                <property name="max_size"></property>
+                                <property name="maximize_button">0</property>
+                                <property name="maximum_size"></property>
+                                <property name="min_size"></property>
+                                <property name="minimize_button">0</property>
+                                <property name="minimum_size"></property>
+                                <property name="moveable">1</property>
+                                <property name="name">m_buttonSaveReport</property>
+                                <property name="pane_border">1</property>
+                                <property name="pane_position"></property>
+                                <property name="pane_size"></property>
+                                <property name="permission">protected</property>
+                                <property name="pin_button">1</property>
+                                <property name="pos"></property>
+                                <property name="position"></property>
+                                <property name="pressed"></property>
+                                <property name="resize">Resizable</property>
+                                <property name="show">1</property>
+                                <property name="size"></property>
+                                <property name="style"></property>
+                                <property name="subclass">; ; forward_declare</property>
+                                <property name="toolbar_pane">0</property>
+                                <property name="tooltip"></property>
+                                <property name="validator_data_type"></property>
+                                <property name="validator_style">wxFILTER_NONE</property>
+                                <property name="validator_type">wxDefaultValidator</property>
+                                <property name="validator_variable"></property>
+                                <property name="window_extra_style"></property>
+                                <property name="window_name"></property>
+                                <property name="window_style"></property>
+                                <event name="OnButtonClick">saveReportClicked</event>
+                            </object>
+                        </object>
+                        <object class="sizeritem" expanded="1">
+                            <property name="border">5</property>
+                            <property name="flag">wxALIGN_RIGHT|wxBOTTOM|wxLEFT|wxRIGHT|wxTOP</property>
+                            <property name="proportion">0</property>
+                            <object class="wxStdDialogButtonSizer" expanded="1">
+                                <property name="Apply">0</property>
+                                <property name="Cancel">0</property>
+                                <property name="ContextHelp">0</property>
+                                <property name="Help">0</property>
+                                <property name="No">0</property>
+                                <property name="OK">1</property>
+                                <property name="Save">0</property>
+                                <property name="Yes">0</property>
+                                <property name="minimum_size"></property>
+                                <property name="name">m_sdbControlSizer</property>
+                                <property name="permission">protected</property>
+                            </object>
+                        </object>
                     </object>
                 </object>
             </object>
diff --git a/pcbnew/dialogs/dialog_board_statistics_base.h b/pcbnew/dialogs/dialog_board_statistics_base.h
index 4b31a4006..8ca408951 100644
--- a/pcbnew/dialogs/dialog_board_statistics_base.h
+++ b/pcbnew/dialogs/dialog_board_statistics_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Jul 10 2019)
+// C++ code generated with wxFormBuilder (version Jun 25 2019)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO *NOT* EDIT THIS FILE!
@@ -19,9 +19,11 @@
 #include <wx/settings.h>
 #include <wx/grid.h>
 #include <wx/sizer.h>
-#include <wx/gbsizer.h>
 #include <wx/statline.h>
 #include <wx/checkbox.h>
+#include <wx/bitmap.h>
+#include <wx/image.h>
+#include <wx/icon.h>
 #include <wx/button.h>
 #include <wx/dialog.h>
 
@@ -33,27 +35,31 @@
 ///////////////////////////////////////////////////////////////////////////////
 class DIALOG_BOARD_STATISTICS_BASE : public DIALOG_SHIM
 {
-	private:
+    private:
 
-	protected:
-		wxGrid* m_gridComponents;
-		wxGrid* m_gridPads;
-		wxGrid* m_gridBoard;
-		wxStaticLine* m_staticline1;
-		wxCheckBox* m_checkBoxSubtractHoles;
-		wxCheckBox* m_checkBoxExcludeComponentsNoPins;
-		wxStaticLine* m_staticline2;
-		wxStdDialogButtonSizer* m_sdbControlSizer;
-		wxButton* m_sdbControlSizerOK;
+    protected:
+        wxGrid* m_gridComponents;
+        wxGrid* m_gridPads;
+        wxGrid* m_gridBoard;
+        wxStaticText* viasLabel;
+        wxGrid* m_gridVias;
+        wxStaticLine* m_staticline1;
+        wxCheckBox* m_checkBoxSubtractHoles;
+        wxCheckBox* m_checkBoxExcludeComponentsNoPins;
+        wxStaticLine* m_staticline2;
+        wxButton* m_buttonSaveReport;
+        wxStdDialogButtonSizer* m_sdbControlSizer;
+        wxButton* m_sdbControlSizerOK;
 
-		// Virtual event handlers, overide them in your derived class
-		virtual void checkboxClicked( wxCommandEvent& event ) { event.Skip(); }
+        // Virtual event handlers, overide them in your derived class
+        virtual void checkboxClicked( wxCommandEvent& event ) { event.Skip(); }
+        virtual void saveReportClicked( wxCommandEvent& event ) { event.Skip(); }
 
 
-	public:
+    public:
 
-		DIALOG_BOARD_STATISTICS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Board Statistics"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
-		~DIALOG_BOARD_STATISTICS_BASE();
+        DIALOG_BOARD_STATISTICS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("Board Statistics"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE );
+        ~DIALOG_BOARD_STATISTICS_BASE();
 
 };
 

--------------2.22.0--



Follow ups

References