← Back to team overview

kicad-developers team mailing list archive

Re: [FEATURE] Component table viewer

 

Wayne,

I have reattached all patches including a new one which does the following:

a) Removes BOM export
b) Removes Save/Cancel dialog as per JP's request
c) Fixes speed issue as per JP's request
d) Small bugfix

These should apply directly to latest master branch.

Cheers

On Tue, Apr 25, 2017 at 12:43 AM, Wayne Stambaugh <stambaughw@xxxxxxxxx>
wrote:

> Oliver,
>
> Thank you for your understanding on this issue.  Once you include the
> patch to remove the BOM code, I will merge this into the master branch.
>
> Cheers,
>
> Wayne
>
> On 4/23/2017 5:41 PM, Oliver Walters wrote:
> > Wayne,
> >
> > I tend to agree actually, as I have been developing this the less I
> > think having a BoM export is appropriate:
> >
> > 1. Separation of tasks - it's simpler and cleaner just as an editing
> table
> > 2. Python (etc) is way better at data manipulation
> > 3. External scripts are by design much more flexible.
> >
> > I have some ideas for improving BOM output but I am now thinking they
> > would be best served not integrated here.
> >
> > I will remove the buttons and leave those thoughts for another
> conversation.
> >
> > Oliver
> >
> > On 24 Apr 2017 01:47, "Wayne Stambaugh" <stambaughw@xxxxxxxxx
> > <mailto:stambaughw@xxxxxxxxx>> wrote:
> >
> >     Oliver,
> >
> >     I finally got a chance to test your patch set and was a bit surprised
> >     what I saw after following the conversation on the mailing list.  I
> was
> >     under the impression that this was a generic component properties
> >     editing grid not a BOM tool which is what it really is.  I like the
> idea
> >     of being able to edit component fields in table form.  I'm less
> thrilled
> >     about the BOM export options.  For those of you who haven't been
> around
> >     very long, Eeschema used to have a BOM dialog.  It didn't allow for
> >     editing field values but it contained options for various BOM output
> >     types.  Initially this dialog was simple and contained only a few BOM
> >     output types and options.  Of course everyone has their own idea of
> how
> >     a BOM should be formatted so gradually over time, the BOM dialog and
> the
> >     underlying BOM output code became a huge mess.  It was finally
> decided
> >     that the design was no longer maintainable and removed.  It was
> replaced
> >     by the current system along with samples that provided all of the
> same
> >     BOM output options from the old BOM dialog.  Except for the field
> >     editing grid, your dialog and BOM code looks a lot like the original
> BOM
> >     dialog.  I can see the same thing happening all over again.  Why no
> use
> >     the existing BOM generation code in your dialog rather than
> re-implement
> >     code that does the exact same thing?  I'm not opposed to field
> editing
> >     part of the dialog, but I see the BOM output part heading the same
> >     direction as the old BOM dialog.
> >
> >     On 4/20/2017 1:59 AM, Oliver Walters wrote:
> >     > Wayne,
> >     >
> >     > Is the behaviour I have implemented acceptable?
> >     >
> >     > Regards,
> >     > Oliver
> >     >
> >     > On Wed, Apr 19, 2017 at 12:13 AM, Oliver Walters
> >     > <oliver.henry.walters@xxxxxxxxx
> >     <mailto:oliver.henry.walters@xxxxxxxxx>
> >     <mailto:oliver.henry.walters@xxxxxxxxx
> >     <mailto:oliver.henry.walters@xxxxxxxxx>>>
> >     > wrote:
> >     >
> >     >     Wayne,
> >     >
> >     >     I have now fixed this such that UNDO actions are pushed to the
> >     UNDO
> >     >     stack for the associated sheet. All UNDO actions for a given
> sheet
> >     >     are grouped so a single Ctrl-Z will undo all components
> changed in
> >     >     the table (for the given sheet).
> >     >
> >     >     Please find patch _007 attached (must be appli ed atop all
> >     previous
> >     >     patches).
> >     >
> >     >     Let me know if you see any other pressing issues.
> >     >
> >     >     Regards,
> >     >     Oliver
> >     >
> >     >     On Tue, Apr 18, 2017 at 6:30 AM, Wayne Stambaugh
> >     >     <stambaughw@xxxxxxxxx <mailto:stambaughw@xxxxxxxxx>
> >     <mailto:stambaughw@xxxxxxxxx <mailto:stambaughw@xxxxxxxxx>>> wrote:
> >     >
> >     >         On 4/17/2017 4:18 PM, Oliver Walters wrote:
> >     >         > So how do we proceed here? Is there a 'global' undo
> >     stack? If not:
> >     >
> >     >         Unfortunately there is no global undo stack.  Undo stacks
> are
> >     >         maintained
> >     >         for each unique SCH_SCREEN (schematic file) object.
> >     >
> >     >         >
> >     >         > A) don't allow changes made in the component table
> >     viewer to be undone
> >     >         > B) Make an undo entry for each sheet that has changed
> >     symbols
> >     >         >
> >     >         > A) is easier but the user would need to
> >     quit-without-save to undo changes
> >     >
> >     >         This is less than desirable
> >     >
> >     >         >
> >     >         > B) is more difficult and doesn't solve the undo
> >     operations getting out
> >     >         > of order either, as the user could inject another
> >     operation on a given
> >     >         > sheet.
> >     >
> >     >         This would be my preference.  Out of order operations are
> >     already an
> >     >         issue so this solution doesn't make that issue any worse.
> >     >         Undo/redo is
> >     >         only available for the current sheet so the user would
> have to
> >     >         change
> >     >         sheets in order to undo anything changed in the component
> >     >         properties table.
> >     >
> >     >         >
> >     >         > Suggestions?
> >     >         >
> >     >         > On 18 Apr 2017 01:26, "Wayne Stambaugh"
> >     <stambaughw@xxxxxxxxx <mailto:stambaughw@xxxxxxxxx>
> >     <mailto:stambaughw@xxxxxxxxx <mailto:stambaughw@xxxxxxxxx>>
> >     >         > <mailto:stambaughw@xxxxxxxxx
> >     <mailto:stambaughw@xxxxxxxxx> <mailto:stambaughw@xxxxxxxxx
> >     <mailto:stambaughw@xxxxxxxxx>>>> wrote:
> >     >         >
> >     >         >     On 4/17/2017 10:21 AM, jp charras wrote:
> >     >         >     > Le 17/04/2017 à 04:11, Oliver Walters a écrit :
> >     >         >     >> JP, others,
> >     >         >     >>
> >     >         >     >> After further investigation, I have worked out
> >     why the components
> >     >         >     with duplicated references were
> >     >         >     >> displaying incorrectly.
> >     >         >     >>
> >     >         >     >> Patch_004 is attached, Thomas can you confirm
> >     that it fixes the
> >     >         >     display for you?
> >     >         >     >>
> >     >         >     >> Kind Regards,
> >     >         >     >> Oliver
> >     >         >     >>
> >     >         >     >> On Mon, Apr 17, 2017 at 7:53 AM, Oliver Walters
> >     >         >     <oliver.henry.walters@xxxxxxxxx
> >     <mailto:oliver.henry.walters@xxxxxxxxx>
> >     >         <mailto:oliver.henry.walters@xxxxxxxxx
> >     <mailto:oliver.henry.walters@xxxxxxxxx>>
> >     >         <mailto:oliver.henry.walters@xxxxxxxxx
> >     <mailto:oliver.henry.walters@xxxxxxxxx>
> >     >         <mailto:oliver.henry.walters@xxxxxxxxx
> >     <mailto:oliver.henry.walters@xxxxxxxxx>>>
> >     >         >     >
> >     >         >     > Good work, Oliver!
> >     >         >     >
> >     >         >     > I found 2 issues (tested on W7)
> >     >         >     >
> >     >         >     > 1 - m_reloadTableButton is not correctly
> >     enabled/disabled.
> >     >         >     > This is due to the way events are managed, and
> this is
> >     >         OS dependent.
> >     >         >     > To avoid this issue, enable/disable it inside a
> >     >         wxUpdateUIEvent
> >     >         >     attached to this button.
> >     >         >     >
> >     >         >     > 2 - ESC key and ENTER keys do not dismiss the
> dialog.
> >     >         >     > This is due to the fact you do not have a
> >     >         wxStdDialogButtonSizer,
> >     >         >     and no OK and Cancel button.
> >     >         >     > Please, add it and use the OK button (as usual in a
> >     >         dialog) to
> >     >         >     transfer changes to schematic (do not
> >     >         >     > use a wxCloseEvent to manage that), and obviously
> >     Cancel
> >     >         just
> >     >         >     closes the dialog.
> >     >         >     > To do this transfer, just  override
> >     >         TransferDataFromWindow(), that
> >     >         >     is called by wxWidgets when
> >     >         >     > closing a dialog by the OK button.
> >     >         >     >
> >     >         >     > About other things, undo/redo lists should manage
> only
> >     >         changes
> >     >         >     made inside the corresponding sheet,
> >     >         >     > not in other sheets, to avoid inconsistencies and
> >     >         therefore crashes.
> >     >         >     >
> >     >         >
> >     >         >     This is one of the reasons I've been reluctant to
> accept
> >     >         code that
> >     >         >     attempts to change the state of a SCH_SCREEN object
> >     other
> >     >         than the
> >     >         >     current SCH_SCREEN object.  It exposes a known flaw
> >     in our
> >     >         schematic
> >     >         >     undo/redo design and I have yet to see anyone update
> the
> >     >         undo/redo
> >     >         >     SCH_SCREEN stacks correctly.  I see the potential for
> >     >         serious issues if
> >     >         >     you do not keep the undo/redo stacks properly synced.
> >     >         Once you allow
> >     >         >     the modification of information in the SCH_SCREEN
> object
> >     >         other than the
> >     >         >     current one, you need to update the undo/redo stack
> for
> >     >         the appropriate
> >     >         >     SCH_SCREEN object.  Otherwise, you wont be able to
> undo
> >     >         all of the
> >     >         >     changes correctly.
> >     >         >
> >     >         >     _______________________________________________
> >     >         >     Mailing list:
> >     https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     >         <https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>>
> >     >         >     <https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     >         <https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>>>
> >     >         >     Post to     : kicad-developers@xxxxxxxxxxxxxxxxxxx
> >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx>
> >     >         <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx
> >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx>>
> >     >         >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx
> >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx>
> >     >         <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx
> >     <mailto:kicad-developers@xxxxxxxxxxxxxxxxxxx>>>
> >     >         >     Unsubscribe :
> >     https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     >         <https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>>
> >     >         >     <https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>
> >     >         <https://launchpad.net/~kicad-developers
> >     <https://launchpad.net/~kicad-developers>>>
> >     >         >     More help   : https://help.launchpad.net/ListHelp
> >     <https://help.launchpad.net/ListHelp>
> >     >         <https://help.launchpad.net/ListHelp
> >     <https://help.launchpad.net/ListHelp>>
> >     >         >     <https://help.launchpad.net/ListHelp
> >     <https://help.launchpad.net/ListHelp>
> >     >         <https://help.launchpad.net/ListHelp
> >     <https://help.launchpad.net/ListHelp>>>
> >     >         >
> >     >
> >     >
> >     >
> >
> >
>
From f7316d631e93df54e62fa4d75475f4e6043b777e Mon Sep 17 00:00:00 2001
From: Oliver <oliver.henry.walters@xxxxxxxxx>
Date: Sun, 2 Apr 2017 22:09:01 +1000
Subject: [PATCH 1/8] Added component table dialog

- Allows grouping of matched components
- Bulk edit of components in a spreadsheet window
- User can choose to save / undo changes
- All changes are pushed to the undo stack in a single operation
- Export table to HTML / CSV output
---
 bitmaps_png/CMakeLists.txt                  |    1 +
 bitmaps_png/cpp_26/spreadsheet.cpp          |   45 +
 bitmaps_png/sources/spreadsheet.svg         |  440 +++++++++
 common/dialog_shim.cpp                      |    3 +-
 common/wildcards_and_files_ext.cpp          |    1 +
 eeschema/CMakeLists.txt                     |    5 +
 eeschema/bom_exporter.cpp                   |  420 ++++++++
 eeschema/bom_exporter.h                     |  123 +++
 eeschema/bom_table_column.cpp               |  136 +++
 eeschema/bom_table_column.h                 |  147 +++
 eeschema/bom_table_model.cpp                | 1404 +++++++++++++++++++++++++++
 eeschema/bom_table_model.h                  |  282 ++++++
 eeschema/dialogs/dialog_bom_editor.cpp      |  439 +++++++++
 eeschema/dialogs/dialog_bom_editor.h        |   83 ++
 eeschema/dialogs/dialog_bom_editor_base.cpp |  150 +++
 eeschema/dialogs/dialog_bom_editor_base.fbp | 1202 +++++++++++++++++++++++
 eeschema/dialogs/dialog_bom_editor_base.h   |  101 ++
 eeschema/invoke_sch_dialog.h                |    3 +
 eeschema/menubar.cpp                        |    7 +
 eeschema/sch_component.cpp                  |   68 ++
 eeschema/sch_component.h                    |   12 +
 eeschema/schframe.cpp                       |   11 +
 eeschema/schframe.h                         |    1 +
 eeschema/tool_sch.cpp                       |    5 +-
 include/bitmaps.h                           |    1 +
 include/id.h                                |    1 +
 include/wildcards_and_files_ext.h           |    1 +
 27 files changed, 5090 insertions(+), 2 deletions(-)
 create mode 100644 bitmaps_png/cpp_26/spreadsheet.cpp
 create mode 100644 bitmaps_png/sources/spreadsheet.svg
 create mode 100644 eeschema/bom_exporter.cpp
 create mode 100644 eeschema/bom_exporter.h
 create mode 100644 eeschema/bom_table_column.cpp
 create mode 100644 eeschema/bom_table_column.h
 create mode 100644 eeschema/bom_table_model.cpp
 create mode 100644 eeschema/bom_table_model.h
 create mode 100644 eeschema/dialogs/dialog_bom_editor.cpp
 create mode 100644 eeschema/dialogs/dialog_bom_editor.h
 create mode 100644 eeschema/dialogs/dialog_bom_editor_base.cpp
 create mode 100644 eeschema/dialogs/dialog_bom_editor_base.fbp
 create mode 100644 eeschema/dialogs/dialog_bom_editor_base.h

diff --git a/bitmaps_png/CMakeLists.txt b/bitmaps_png/CMakeLists.txt
index 80bdcea..02c6c06 100644
--- a/bitmaps_png/CMakeLists.txt
+++ b/bitmaps_png/CMakeLists.txt
@@ -531,6 +531,7 @@ set( BMAPS_MID
     show_no_layers
     show_no_copper_layers
     show_all_copper_layers
+    spreadsheet
     svg_file
     swap_layer
     text_sketch
diff --git a/bitmaps_png/cpp_26/spreadsheet.cpp b/bitmaps_png/cpp_26/spreadsheet.cpp
new file mode 100644
index 0000000..fb71a5f
--- /dev/null
+++ b/bitmaps_png/cpp_26/spreadsheet.cpp
@@ -0,0 +1,45 @@
+
+/* Do not modify this file, it was automatically generated by the
+ * PNG2cpp CMake script, using a *.png file as input.
+ */
+
+#include <bitmaps.h>
+
+static const unsigned char png[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52,
+ 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x1a, 0x08, 0x06, 0x00, 0x00, 0x00, 0xa9, 0x4a, 0x4c,
+ 0xce, 0x00, 0x00, 0x01, 0xbd, 0x49, 0x44, 0x41, 0x54, 0x48, 0xc7, 0x63, 0x60, 0xa0, 0x17, 0x10,
+ 0x92, 0x90, 0x08, 0xe3, 0xd5, 0x32, 0x7b, 0xcd, 0xa7, 0x6b, 0xfd, 0x9e, 0x47, 0xdd, 0xe4, 0x23,
+ 0x8f, 0x86, 0xc9, 0x47, 0x10, 0x1b, 0x19, 0x73, 0xab, 0xe8, 0x7d, 0x22, 0x46, 0x8c, 0x57, 0xc3,
+ 0xf4, 0x23, 0xc8, 0x0c, 0x14, 0x31, 0x4d, 0xb3, 0xd7, 0x82, 0x32, 0x4a, 0x51, 0x0c, 0xc2, 0xb2,
+ 0x4a, 0x77, 0x18, 0x5a, 0xf6, 0xff, 0x67, 0x68, 0x3d, 0xf0, 0x9f, 0x21, 0xa9, 0xef, 0x3f, 0x43,
+ 0x72, 0x3f, 0x84, 0x8d, 0x8c, 0x1d, 0x62, 0x89, 0x13, 0x4b, 0x9d, 0xf4, 0x9f, 0x21, 0xa1, 0x1b,
+ 0x55, 0x0c, 0x68, 0x36, 0xaf, 0x9a, 0xc1, 0x13, 0x06, 0x61, 0x79, 0xd5, 0xfb, 0x70, 0x41, 0x5a,
+ 0x58, 0x04, 0xc4, 0x7c, 0x1a, 0x26, 0xcf, 0xe9, 0x67, 0x11, 0x9f, 0xb8, 0xf4, 0x33, 0xb0, 0x26,
+ 0x10, 0xd6, 0x77, 0xfd, 0xaf, 0xe7, 0xec, 0xfb, 0xdf, 0x39, 0x26, 0x03, 0x05, 0x2b, 0xe8, 0x18,
+ 0x11, 0x25, 0x66, 0xec, 0xe6, 0xff, 0xdf, 0xc0, 0xc9, 0x1b, 0x43, 0x9c, 0x4f, 0x4c, 0xfa, 0x29,
+ 0x86, 0x8f, 0x16, 0x2e, 0x5f, 0xf5, 0xff, 0xd9, 0xb3, 0x67, 0x28, 0x38, 0x3f, 0x3f, 0x9f, 0x28,
+ 0xb1, 0xf5, 0xeb, 0xd7, 0xff, 0x5f, 0xb6, 0x6c, 0x19, 0x86, 0xb8, 0x84, 0x84, 0xc4, 0xcd, 0x61,
+ 0x68, 0x91, 0x90, 0x9c, 0xd2, 0x03, 0x86, 0x8a, 0x75, 0xff, 0xc1, 0x38, 0xa2, 0xe1, 0xff, 0xa4,
+ 0xe9, 0xb3, 0xfe, 0x5f, 0xb8, 0x70, 0x01, 0x05, 0xa7, 0xa4, 0xa4, 0x10, 0x25, 0x36, 0x6f, 0xde,
+ 0xbc, 0xff, 0xd3, 0xa6, 0x4d, 0xc3, 0x10, 0x17, 0x13, 0x13, 0xbb, 0xc5, 0x20, 0x20, 0x21, 0xfb,
+ 0x94, 0xc1, 0x37, 0xff, 0x3f, 0x18, 0x5b, 0x06, 0xfd, 0x8f, 0x4d, 0x48, 0xfa, 0xdf, 0xda, 0xda,
+ 0x8a, 0x82, 0x1d, 0x1c, 0x1c, 0x88, 0x12, 0x4b, 0x4d, 0x4d, 0xfd, 0x9f, 0x90, 0x90, 0x80, 0x21,
+ 0x2e, 0x24, 0x24, 0xf4, 0x60, 0x34, 0x31, 0x90, 0x6f, 0x91, 0x80, 0xa4, 0xdc, 0x13, 0x86, 0x90,
+ 0xaa, 0xff, 0x60, 0x6c, 0x17, 0xf5, 0x3f, 0x2d, 0x2b, 0xe7, 0xff, 0xa4, 0x49, 0x93, 0x50, 0xb0,
+ 0x9b, 0x9b, 0x1b, 0x51, 0x62, 0x20, 0xcb, 0x33, 0x33, 0x33, 0x31, 0xc4, 0x45, 0x44, 0x44, 0xee,
+ 0x31, 0x08, 0xc9, 0x28, 0x3d, 0x64, 0x28, 0x5c, 0xfc, 0x1f, 0x8c, 0x83, 0x2b, 0xfe, 0x77, 0xf4,
+ 0x4d, 0xf8, 0x7f, 0xf8, 0xf0, 0x61, 0x14, 0x1c, 0x17, 0x17, 0x47, 0x94, 0xd8, 0x94, 0x29, 0x53,
+ 0xfe, 0xf7, 0xf6, 0xf6, 0x62, 0x88, 0x8b, 0x8a, 0x8a, 0xde, 0x1e, 0x4d, 0x0c, 0xe4, 0x5b, 0x84,
+ 0x5e, 0x7a, 0xfb, 0x06, 0x04, 0x81, 0x0d, 0x41, 0xc6, 0x66, 0x66, 0x66, 0x44, 0x89, 0x85, 0x84,
+ 0x84, 0xfc, 0x0f, 0x08, 0x08, 0xc0, 0x10, 0x07, 0x66, 0xd8, 0x87, 0xa3, 0x71, 0x44, 0x81, 0x45,
+ 0x68, 0x8d, 0x13, 0x6a, 0x5b, 0xf4, 0xe4, 0xc9, 0x13, 0x50, 0x3e, 0xba, 0x86, 0xd1, 0xdc, 0x12,
+ 0x97, 0x90, 0x7a, 0x2a, 0x25, 0x25, 0xf5, 0x08, 0x19, 0x03, 0x15, 0x3e, 0x27, 0x46, 0x4c, 0x5c,
+ 0x5c, 0xfc, 0x09, 0x10, 0xa3, 0xe8, 0x07, 0xfa, 0xe6, 0xae, 0xb0, 0xb0, 0x70, 0x10, 0xdd, 0xda,
+ 0x8f, 0x00, 0x62, 0x96, 0x75, 0xd5, 0x49, 0xff, 0x1d, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45,
+ 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82,
+};
+
+const BITMAP_OPAQUE spreadsheet_xpm[1] = {{ png, sizeof( png ), "spreadsheet_xpm" }};
+
+//EOF
diff --git a/bitmaps_png/sources/spreadsheet.svg b/bitmaps_png/sources/spreadsheet.svg
new file mode 100644
index 0000000..9dcb7d7
--- /dev/null
+++ b/bitmaps_png/sources/spreadsheet.svg
@@ -0,0 +1,440 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/";
+   xmlns:cc="http://creativecommons.org/ns#";
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+   xmlns:svg="http://www.w3.org/2000/svg";
+   xmlns="http://www.w3.org/2000/svg";
+   xmlns:xlink="http://www.w3.org/1999/xlink";
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd";
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape";
+   version="1.0"
+   width="26"
+   height="26"
+   id="svg2"
+   inkscape:version="0.91 r13725"
+   sodipodi:docname="spreadsheet.svg">
+  <metadata
+     id="metadata166">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage"; />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="1920"
+     inkscape:window-height="1017"
+     id="namedview164"
+     showgrid="true"
+     inkscape:zoom="11.313709"
+     inkscape:cx="-3.9181807"
+     inkscape:cy="-0.64398435"
+     inkscape:window-x="-8"
+     inkscape:window-y="-8"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="g4260"
+     inkscape:snap-to-guides="false"
+     inkscape:snap-grids="false">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3041"
+       empspacing="1"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <defs
+     id="defs4">
+    <clipPath
+       id="ba">
+      <path
+         style="fill:#ffffff"
+         d="m 0,96 v 60 H 96 V 96 H 0 z m 68,20 c 9.9411,0 18,8.0589 18,18 0,9.9411 -8.0589,18 -18,18 -9.9411,0 -18,-8.0589 -18,-18 0,-9.9411 8.0589,-18 18,-18 z"
+         id="path125"
+         inkscape:connector-curvature="0" />
+    </clipPath>
+    <linearGradient
+       id="bl"
+       y2="5.9782"
+       gradientUnits="userSpaceOnUse"
+       x2="69"
+       gradientTransform="matrix(-0.2255,-0.071329,0.05452,-0.20327,7.6326,90.834)"
+       y1="122"
+       x1="69">
+      <stop
+         stop-color="#1e71ac"
+         offset="0"
+         id="stop128" />
+      <stop
+         stop-color="#81c1e9"
+         offset="1"
+         id="stop130" />
+    </linearGradient>
+    <linearGradient
+       id="bm"
+       y2="67.706001"
+       xlink:href="#a"
+       gradientUnits="userSpaceOnUse"
+       x2="118.33"
+       gradientTransform="matrix(0.39018,0.62586,-0.63862,0.30043,3.5817,-20.909)"
+       y1="87.488998"
+       x1="120.65" />
+    <linearGradient
+       id="a">
+      <stop
+         offset="0"
+         id="stop15" />
+      <stop
+         stop-opacity="0"
+         offset="1"
+         id="stop17" />
+    </linearGradient>
+    <linearGradient
+       id="bn"
+       y2="5.9782"
+       gradientUnits="userSpaceOnUse"
+       x2="69"
+       gradientTransform="matrix(-0.2255,-0.071329,0.05452,-0.20327,7.6018,90.825)"
+       y1="122"
+       x1="69">
+      <stop
+         stop-color="#cd2323"
+         offset="0"
+         id="stop134" />
+      <stop
+         stop-color="#ef7474"
+         offset="1"
+         id="stop136" />
+    </linearGradient>
+    <linearGradient
+       id="ao"
+       y2="67.706001"
+       xlink:href="#a"
+       gradientUnits="userSpaceOnUse"
+       x2="118.33"
+       y1="87.488998"
+       x1="120.65" />
+    <clipPath
+       id="aq">
+      <path
+         style="fill:url(#linearGradient4033)"
+         d="m 118,56 c -9.9411,0 -18,8.0589 -18,18 0,9.9411 8.0589,18 18,18 9.7305,0 17.637,-7.7253 17.969,-17.375 v -1.25 C 135.639,63.725 127.729,56 117.999,56 z m -6,10.75 c 5.9493,0.05747 10.832,4.9413 11.031,10.875 l 3.75,0.03125 -6,8.7188 -6.1562,-8.8125 3.9688,0.03125 c -0.25101,-4.9057 -4.4893,-9.9506 -11.719,-9.625 1.5223,-0.80073 3.2718,-1.2367 5.125,-1.2188 z"
+         id="path122"
+         inkscape:connector-curvature="0" />
+    </clipPath>
+    <linearGradient
+       id="bo"
+       y2="5.1837001"
+       xlink:href="#an"
+       gradientUnits="userSpaceOnUse"
+       x2="84.360001"
+       gradientTransform="matrix(0.21868,0.069171,-0.053262,0.19858,-13.124,56.327)"
+       y1="79.417"
+       x1="84.360001" />
+    <linearGradient
+       id="an">
+      <stop
+         stop-color="#fff"
+         offset="0"
+         id="stop65" />
+      <stop
+         stop-color="#fff"
+         stop-opacity=".49804"
+         offset=".43290"
+         id="stop67" />
+      <stop
+         stop-color="#fff"
+         stop-opacity="0"
+         offset="1"
+         id="stop69" />
+    </linearGradient>
+    <linearGradient
+       id="bp"
+       y2="67.706001"
+       xlink:href="#a"
+       gradientUnits="userSpaceOnUse"
+       x2="118.33"
+       gradientTransform="matrix(-0.39018,-0.62586,0.63862,-0.30043,-9.9736,166.82)"
+       y1="87.488998"
+       x1="120.65" />
+    <linearGradient
+       y2="67.706001"
+       x2="118.33"
+       y1="87.488998"
+       x1="120.65"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3263"
+       xlink:href="#a"
+       inkscape:collect="always" />
+    <linearGradient
+       y2="5.1837001"
+       x2="84.360001"
+       y1="79.417"
+       x1="84.360001"
+       gradientTransform="matrix(-0.21868,-0.069171,0.053262,-0.19858,6.7324,89.587)"
+       gradientUnits="userSpaceOnUse"
+       id="linearGradient3265"
+       xlink:href="#an"
+       inkscape:collect="always" />
+    <linearGradient
+       id="i"
+       y2="6.7758002"
+       gradientUnits="userSpaceOnUse"
+       x2="20.631001"
+       gradientTransform="matrix(0.87827,0,0,0.87827,56.157,5.6701)"
+       y1="42.254002"
+       x1="19.648001">
+      <stop
+         stop-color="#b6b6b6"
+         offset="0"
+         id="stop3120" />
+      <stop
+         stop-color="#f2f2f2"
+         offset=".5"
+         id="stop3122" />
+      <stop
+         stop-color="#fafafa"
+         offset=".67613"
+         id="stop3124" />
+      <stop
+         stop-color="#d8d8d8"
+         offset=".84052"
+         id="stop3126" />
+      <stop
+         stop-color="#f2f2f2"
+         offset=".875"
+         id="stop3128" />
+      <stop
+         stop-color="#dbdbdb"
+         offset="1"
+         id="stop3130" />
+    </linearGradient>
+    <linearGradient
+       id="j"
+       y2="-4.3003001"
+       gradientUnits="userSpaceOnUse"
+       x2="25.291"
+       gradientTransform="matrix(0.87827,0,0,0.87827,43.255,-36.26)"
+       y1="-3.6324"
+       x1="50.153">
+      <stop
+         stop-color="#fff"
+         offset="0"
+         id="stop3133"
+         style="stop-color:#4754ba;stop-opacity:1;" />
+      <stop
+         offset="1"
+         id="stop3135" />
+    </linearGradient>
+    <linearGradient
+       id="k"
+       y2="6.6286001"
+       gradientUnits="userSpaceOnUse"
+       x2="37.535"
+       gradientTransform="matrix(0.87827,0,0,0.87827,56.467,6.2911)"
+       y1="13.603"
+       x1="38.228001">
+      <stop
+         stop-color="#98a0a9"
+         offset="0"
+         id="stop3138" />
+      <stop
+         stop-color="#c3d0dd"
+         offset="1"
+         id="stop3140" />
+    </linearGradient>
+    <linearGradient
+       id="l"
+       y2="9.6569004"
+       gradientUnits="userSpaceOnUse"
+       x2="40.859001"
+       gradientTransform="translate(53.62,0.70241)"
+       y1="19.822001"
+       x1="31.177">
+      <stop
+         stop-color="#fff"
+         offset="0"
+         id="stop3143" />
+      <stop
+         stop-color="#fff"
+         stop-opacity="0"
+         offset="1"
+         id="stop3145" />
+    </linearGradient>
+    <linearGradient
+       id="m"
+       y2="39.443001"
+       gradientUnits="userSpaceOnUse"
+       x2="16.915001"
+       gradientTransform="matrix(0.87827,0,0,0.87827,56.157,5.6701)"
+       y1="32.284"
+       x1="9.7503004">
+      <stop
+         stop-color="#3465a4"
+         offset="0"
+         id="stop3148" />
+      <stop
+         stop-color="#9fbce1"
+         offset="0"
+         id="stop3150" />
+      <stop
+         stop-color="#6b95ca"
+         offset="0"
+         id="stop3152" />
+      <stop
+         stop-color="#3d6aa5"
+         offset=".75"
+         id="stop3154" />
+      <stop
+         stop-color="#386eb4"
+         offset="1"
+         id="stop3156" />
+    </linearGradient>
+    <linearGradient
+       id="n"
+       y2="33.195"
+       gradientUnits="userSpaceOnUse"
+       x2="10.651"
+       gradientTransform="matrix(1.0073,-0.026365,0.026365,1.0073,55.213,0.7816)"
+       y1="35.688"
+       x1="12.005">
+      <stop
+         stop-color="#fff"
+         offset="0"
+         id="stop3159" />
+      <stop
+         stop-color="#fff"
+         stop-opacity="0"
+         offset="1"
+         id="stop3161" />
+    </linearGradient>
+    <linearGradient
+       inkscape:collect="always"
+       xlink:href="#o"
+       id="linearGradient4456"
+       gradientUnits="userSpaceOnUse"
+       gradientTransform="matrix(0.77155263,-0.0151812,0.01522193,0.76948813,58.140667,26.736849)"
+       x1="14.018"
+       y1="36.943001"
+       x2="15.416"
+       y2="38.268002" />
+    <linearGradient
+       id="o"
+       y2="38.268002"
+       gradientUnits="userSpaceOnUse"
+       x2="15.416"
+       gradientTransform="matrix(0.8781,-0.017324,0.017324,0.8781,55.783,4.7703)"
+       y1="36.943001"
+       x1="14.018">
+      <stop
+         offset="0"
+         id="stop3164" />
+      <stop
+         stop-opacity="0"
+         offset="1"
+         id="stop3166" />
+    </linearGradient>
+    <clipPath
+       clipPathUnits="userSpaceOnUse"
+       id="clipPath4282">
+      <rect
+         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+         id="rect4284"
+         width="24.723595"
+         height="22.915451"
+         x="0.47398946"
+         y="1.1851474"
+         rx="0.84872037"
+         ry="0.84872037" />
+    </clipPath>
+  </defs>
+  <g
+     id="g4260"
+     transform="translate(0.16421321,0.35712707)"
+     style="fill:#f2f2f2">
+    <rect
+       ry="0.84872037"
+       rx="0.84872037"
+       y="1.1851474"
+       x="0.47398946"
+       height="22.915451"
+       width="24.723595"
+       id="rect3442"
+       style="fill:#e6e6e6;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       style="fill:#0085c0;fill-opacity:1;stroke-width:0.5;stroke-miterlimit:4;stroke-dasharray:none"
+       clip-path="url(#clipPath4282)"
+       d="m 0.39828682,0.0989943 26.62500018,-0.65625 -0.375,5.5642841 -22.7500002,0.033034 0,19.7903105 -3.49999998,0 z"
+       id="rect4278"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="ccccccc" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path4244"
+       d="m 0.40018765,19.266078 24.87119735,0"
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 0.40018765,14.536363 24.87119735,0"
+       id="path4246"
+       inkscape:connector-curvature="0" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path4248"
+       d="m 0.40018765,9.8066493 24.87119735,0"
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+    <path
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 0.40018765,5.076934 24.87119735,0"
+       id="path4250"
+       inkscape:connector-curvature="0" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path4254"
+       d="m 19.854056,24.026795 0,-22.758288"
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 14.512679,24.026795 0,-22.758288"
+       id="path4256"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <path
+       inkscape:connector-curvature="0"
+       id="path4258"
+       d="m 9.1713038,24.026795 0,-22.758288"
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       sodipodi:nodetypes="cc" />
+    <path
+       style="fill:#f2f2f2;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       d="m 3.8299284,24.026795 0,-22.758288"
+       id="path4270"
+       inkscape:connector-curvature="0"
+       sodipodi:nodetypes="cc" />
+    <rect
+       style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.51315969;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+       id="rect4286"
+       width="24.723595"
+       height="22.915451"
+       x="0.47398946"
+       y="1.1851474"
+       rx="0.84872037"
+       ry="0.84872037" />
+  </g>
+</svg>
diff --git a/common/dialog_shim.cpp b/common/dialog_shim.cpp
index 2b1a682..22d5515 100644
--- a/common/dialog_shim.cpp
+++ b/common/dialog_shim.cpp
@@ -97,7 +97,8 @@ DIALOG_SHIM::~DIALOG_SHIM()
     if( IsQuasiModal() )
         EndQuasiModal( wxID_CANCEL );
 
-    delete m_qmodal_parent_disabler;    // usually NULL by now
+    if( m_qmodal_parent_disabler )
+        delete m_qmodal_parent_disabler;    // usually NULL by now
 }
 
 void DIALOG_SHIM::FinishDialogSettings()
diff --git a/common/wildcards_and_files_ext.cpp b/common/wildcards_and_files_ext.cpp
index 0e295f0..ddeaef3 100644
--- a/common/wildcards_and_files_ext.cpp
+++ b/common/wildcards_and_files_ext.cpp
@@ -94,6 +94,7 @@ const wxString ComponentFileWildcard( _( "KiCad cmp/footprint link files (*.cmp)
 const wxString DrillFileWildcard( _( "Drill files (*.drl)|*.drl;*.DRL" ) );
 const wxString SVGFileWildcard( _( "SVG files (*.svg)|*.svg;*.SVG" ) );
 const wxString HtmlFileWildcard( _( "HTML files (*.html)|*.htm;*.html" ) );
+const wxString CsvFileWildcard( _( "CSV Files (*.csv)|*.csv" ) );
 const wxString PdfFileWildcard( _( "Portable document format files (*.pdf)|*.pdf" ) );
 const wxString PSFileWildcard( _( "PostScript files (.ps)|*.ps" ) );
 const wxString ReportFileWildcard = _( "Report files (*.rpt)|*.rpt" );
diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt
index c539563..fd1135e 100644
--- a/eeschema/CMakeLists.txt
+++ b/eeschema/CMakeLists.txt
@@ -25,6 +25,8 @@ set( EESCHEMA_DLGS
     dialogs/dialog_annotate_base.cpp
     dialogs/dialog_bom.cpp
     dialogs/dialog_bom_base.cpp
+	dialogs/dialog_bom_editor.cpp
+	dialogs/dialog_bom_editor_base.cpp
     dialogs/dialog_bom_cfg_keywords.cpp
     dialogs/dialog_choose_component.cpp
     dialogs/dialog_lib_edit_text.cpp
@@ -85,6 +87,9 @@ set( EESCHEMA_SRCS
     backanno.cpp
     block.cpp
     block_libedit.cpp
+    bom_exporter.cpp
+    bom_table_model.cpp
+    bom_table_column.cpp
     busentry.cpp
     bus-wire-junction.cpp
     class_drc_erc_item.cpp
diff --git a/eeschema/bom_exporter.cpp b/eeschema/bom_exporter.cpp
new file mode 100644
index 0000000..0c2a43f
--- /dev/null
+++ b/eeschema/bom_exporter.cpp
@@ -0,0 +1,420 @@
+/*
+* This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 "bom_exporter.h"
+
+/**
+ * BOM_FILE_WRITER class (pure virtual)
+ */
+BOM_FILE_WRITER::BOM_FILE_WRITER() :
+    m_includeExtraData( true ),
+    m_showRowNumbers( true )
+{
+}
+
+void BOM_FILE_WRITER::SetHeader( const wxArrayString aHeader )
+{
+    m_bomHeader = aHeader;
+}
+
+void BOM_FILE_WRITER::AddLine( wxArrayString aLine )
+{
+    m_bomLines.push_back( aLine );
+}
+
+/**
+ * Function ExtraDataPairs
+ * Format extra data for writing to file
+ */
+wxArrayString BOM_FILE_WRITER::ExtraDataPairs()
+{
+    wxArrayString pairs;
+
+    if( m_groupCount != m_componentCount )
+    {
+        pairs.Add( DataPair( _( "Group Count" ), m_groupCount ) );
+    }
+
+    pairs.Add( DataPair( _( "Component Count" ), m_componentCount ) );
+    pairs.Add( DataPair( _( "Schematic Title" ), m_schematicTitle ) );
+    pairs.Add( DataPair( _( "Schematic Date" ), m_schematicDate ) );
+    pairs.Add( DataPair( _( "Schematic Version" ), m_schematicVersion ) );
+    pairs.Add( DataPair( _( "KiCad Version" ), m_kicadVersion ) );
+
+    return pairs;
+}
+
+BOM_CSV_WRITER::BOM_CSV_WRITER( wxChar aDelim ) :
+        BOM_FILE_WRITER()
+{
+    m_delim = aDelim;
+}
+
+/**
+ * Function WriteToFile
+ * Write delimited data to file
+ */
+bool BOM_CSV_WRITER::WriteToFile( wxFile& aFile )
+{
+
+    // Generate table header
+    wxString line = wxJoin( EscapeLine( m_bomHeader ), m_delim )+ "\n";
+
+    if( m_showRowNumbers )
+    {
+        line = m_delim + line;
+    }
+
+    if( !aFile.Write( line ))
+    {
+        return false;
+    }
+
+    // Write each line in the file
+    for( unsigned int ii=0; ii<m_bomLines.size(); ii++ )
+    {
+        line = wxJoin( EscapeLine( m_bomLines[ii]), m_delim ) + "\n";
+
+        if( m_showRowNumbers )
+        {
+            line = wxString::Format( _( "%i" ), ii+1 ) + m_delim + line;
+        }
+
+        if( !aFile.Write( line ) )
+        {
+            return false;
+        }
+    }
+
+    // Write extra options
+    if( m_includeExtraData )
+    {
+        wxString extra;
+
+        extra += "\n\n";
+
+        for( wxString pair : ExtraDataPairs() )
+        {
+            extra += pair;
+            extra += "\n";
+        }
+
+        if( !aFile.Write( extra ) )
+            return false;
+    }
+
+    // File writing successful
+    return true;
+}
+
+/**
+ * Function DataPair
+ * Combine two items into a delimited pair
+ */
+wxString BOM_CSV_WRITER::DataPair( const wxString& aFirst, const wxString& aSecond )
+{
+    wxArrayString pair;
+
+    pair.Add( aFirst );
+    pair.Add( aSecond );
+
+    return wxJoin( pair, m_delim );
+}
+
+/**
+ * Function EscapeLine
+ * Any values that contain the delimiter are escaped with quotes
+ */
+wxArrayString BOM_CSV_WRITER::EscapeLine( wxArrayString line )
+{
+    wxArrayString escaped;
+
+    for( wxString item : line )
+    {
+        if( item.Contains( m_delim ) &&
+            !item.StartsWith( "\"" ) &&
+            !item.EndsWith( "\"" ) )
+        {
+            item = "\"" + item + "\"";
+        }
+
+        escaped.Add( item );
+    }
+
+    return escaped;
+}
+
+BOM_HTML_WRITER::BOM_HTML_WRITER() :
+        BOM_FILE_WRITER()
+{
+    // Strings to check for hyperlinkable text
+    m_linkChecks.Add( "http:*" );
+    m_linkChecks.Add( "https:* " );
+    m_linkChecks.Add( "ftp:*" );
+    m_linkChecks.Add( "www.*" );
+    m_linkChecks.Add( "*.pdf" );
+    m_linkChecks.Add( "*.html" );
+    m_linkChecks.Add( "*.htm" );
+}
+
+/**
+ * Function WriteToFile
+ * Write HTML BoM Data
+ */
+bool BOM_HTML_WRITER::WriteToFile( wxFile& aFile )
+{
+    // Write HTML header
+    if( !aFile.Write( HtmlHeader() ) )
+        return false;
+
+    if( m_includeExtraData )
+    {
+        if( !aFile.Write( ExtraData() ) )
+            return false;
+    }
+
+    // Table data
+    wxString tableTitle = "<h2>";
+
+    tableTitle += _( "Bill of Materials" );
+    tableTitle += "</h2>\n";
+
+    if( !aFile.Write( tableTitle ) )
+        return false;
+
+    if( !aFile.Write( "<table border=\"1\">\n" ) )
+        return false;
+
+    if( !aFile.Write( TableHeader( m_bomHeader ) ) )
+        return false;
+
+    // Write each line of the BOM
+    for( unsigned int ii=0; ii<m_bomLines.size(); ii++ )
+    {
+        if( !aFile.Write( TableRow( ii+1, m_bomLines[ii] ) ) )
+            return false;
+    }
+
+    if( !aFile.Write( "</table>\n" ) )
+        return false;
+
+    if( !aFile.Write( HtmlFooter() ) )
+        return false;
+
+    return true;
+}
+
+wxString BOM_HTML_WRITER::HtmlHeader()
+{
+    wxString header = wxEmptyString;
+
+    header += "<html>\n<head>\n";
+    //TODO - Project title
+    header += "<title>";
+    header += m_schematicTitle;
+    header += "</title>\n";
+
+    header += HtmlMetaTag( "charset", "UTF-8" ) + "\n";
+
+    //TODO - KiCad reference data here
+
+    header += "</head>\n\n";
+
+    header += "<body>\n";
+
+    return header;
+}
+
+wxString BOM_HTML_WRITER::HtmlFooter()
+{
+    wxString footer = wxEmptyString;
+
+    footer += "</body>\n\n";
+    footer += "</html>\n";
+
+    return footer;
+}
+
+wxString BOM_HTML_WRITER::HtmlMetaTag( const wxString aTitle, const wxString aData )
+{
+    wxString tag = "<meta name=\"";
+
+    tag += aTitle + "\"";
+    tag += " content=\"";
+    tag += aData + "\"";
+
+    tag += ">";
+
+    return tag;
+}
+
+/**
+ * Function ExtraData
+ * Write extra project information
+ */
+wxString BOM_HTML_WRITER::ExtraData()
+{
+    wxString extra;
+
+    extra += "<h2>";
+    extra += _( "Project details" );
+    extra += "</h2>\n";
+
+    extra += "<table border=\"1\">\n";
+
+    for( wxString pair : ExtraDataPairs() )
+    {
+        extra += pair + "\n";
+    }
+
+    extra += "</table>\n";
+
+    return extra;
+}
+
+/**
+ * Function LinkText
+ * Automatically detect linkable text, and wrap it in <a> tag
+ * @aText - Text to (potentially) link
+ */
+wxString BOM_HTML_WRITER::LinkText( const wxString& aText )
+{
+    // Should we provide a link to the text?
+    wxString lower = aText.Lower();
+
+    bool found = false;
+
+    for( wxString check : m_linkChecks )
+    {
+        if( lower.Matches( check ) )
+        {
+            found = true;
+            break;
+        }
+    }
+
+    if( found )
+    {
+        wxString link = "<a href=\"";
+
+        link += aText;
+        link += "\">";
+        link += aText;
+        link += "</a>";
+
+        return link;
+    }
+    else
+    {
+        return aText;
+    }
+}
+
+wxString BOM_HTML_WRITER::TableHeader( const wxArrayString& aHeaderData )
+{
+    wxString header = "<tr>\n";
+
+    if( m_showRowNumbers )
+    {
+        header += "<th></th>\n";
+    }
+
+    for( wxString item : aHeaderData )
+    {
+        header += "<th align=\"center\">";
+        header += item;
+        header += "</th>";
+        header += "\n";
+    }
+
+    header += "</tr>\n";
+
+    return header;
+}
+
+wxString BOM_HTML_WRITER::DataPair( const wxString& aFirst, const wxString& aSecond )
+{
+    wxString html = "<tr>\n";
+
+    html += TableEntry( aFirst ) + "\n";
+    html += TableEntry( aSecond ) + "\n";
+
+    html += "</tr>\n";
+
+    return html;
+}
+
+/**
+ * Function TableRow
+ * Generate a single row of BOM data
+ * @aRowNum is the number of the row
+ * @aRowData is the array of data for the given row
+ */
+wxString BOM_HTML_WRITER::TableRow( const int& aRowNum, const wxArrayString& aRowData )
+{
+    wxString row = wxEmptyString;
+
+    row += "<tr>\n";
+
+    if( m_showRowNumbers )
+    {
+        row += "<td>";
+        row += wxString::Format( "%i", aRowNum );
+        row += "</td>\n";
+    }
+
+    for( wxString data : aRowData )
+    {
+        row += TableEntry( data );
+        row += "\n";
+    }
+
+    row += "</tr>\n";
+
+    return row;
+}
+
+/**
+ * Function TableEntry
+ * Wrap a string in <td> tags
+ * @aData is the text to be wrapped
+ * @aColor is an (optional) HTML background color
+ */
+wxString BOM_HTML_WRITER::TableEntry( wxString aData, wxString aColor )
+{
+    wxString cell = "<td align=\"center\"";
+
+    if( !aColor.IsEmpty() )
+    {
+        cell += " bgcolor=\"" + aColor + "\"";
+    }
+
+    cell += ">";
+
+    cell += LinkText( aData );
+
+    cell += "</td>";
+
+    return cell;
+}
diff --git a/eeschema/bom_exporter.h b/eeschema/bom_exporter.h
new file mode 100644
index 0000000..8ee2f34
--- /dev/null
+++ b/eeschema/bom_exporter.h
@@ -0,0 +1,123 @@
+/*
+* This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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
+ */
+
+#ifndef EESCHEMA_BOM_EXPORTER_H_
+#define EESCHEMA_BOM_EXPORTER_H_
+
+#include <vector>
+#include <wx/file.h>
+
+#include "bom_table_column.h"
+#include "bom_table_model.h"
+
+enum BOM_EXPORT_TYPE
+{
+    BOM_EXPORT_CSV = 0,
+    BOM_EXPORT_HTML
+};
+
+class BOM_FILE_WRITER
+{
+public:
+    BOM_FILE_WRITER();
+    virtual ~BOM_FILE_WRITER() {};
+
+    virtual bool WriteToFile( wxFile& aFile ) = 0;
+
+    void SetHeader( const wxArrayString aHeader );
+    void AddLine( const wxArrayString aLine );
+
+    void IncludeExtraData( bool aInclude = true ) { m_includeExtraData = aInclude; }
+    void ShowRowNumbers( bool aShow = true ) { m_showRowNumbers = aShow; }
+
+    // Project information
+    void SetKicadVersion( const wxString aVersion ) { m_kicadVersion = aVersion; }
+    void SetSchematicTitle( const wxString aProject ) { m_schematicTitle = aProject; }
+    void SetSchematicVersion( const wxString aVersion ) { m_schematicVersion = aVersion; }
+    void SetSchematicDate( const wxString aDate ) { m_schematicDate = aDate; }
+
+    void SetGroupCount( unsigned int aCount ) { m_groupCount = wxString::Format( "%u", aCount ); }
+    void SetComponentCount( unsigned int aCount ) { m_componentCount = wxString::Format( "%u", aCount ); }
+
+protected:
+    wxArrayString ExtraDataPairs();
+    virtual wxString DataPair( const wxString& aFirst, const wxString& aSecond ) = 0;
+
+    wxArrayString m_bomHeader;
+    std::vector< wxArrayString > m_bomLines;
+
+    bool m_includeExtraData;
+    bool m_showRowNumbers;
+
+    // Extra details for BOM file
+    wxString m_kicadVersion;
+    wxString m_schematicTitle;
+    wxString m_schematicVersion;
+    wxString m_schematicDate;
+
+    wxString m_componentCount;
+    wxString m_groupCount;
+
+};
+
+class BOM_CSV_WRITER : public BOM_FILE_WRITER
+{
+public:
+    BOM_CSV_WRITER( wxChar aDelim=',' );
+
+    virtual bool WriteToFile( wxFile& aFile ) override;
+
+protected:
+    wxArrayString EscapeLine( wxArrayString line );
+    virtual wxString DataPair( const wxString& aFirst, const wxString& aSecond ) override;
+
+    wxChar m_delim;
+};
+
+class BOM_HTML_WRITER : public BOM_FILE_WRITER
+{
+public:
+    BOM_HTML_WRITER();
+
+    virtual bool WriteToFile( wxFile& aFile ) override;
+
+protected:
+    virtual wxString DataPair( const wxString& aFirst, const wxString& aSecond ) override;
+
+    wxString HtmlHeader();
+    wxString HtmlFooter();
+    wxString HtmlMetaTag( const wxString aTitle, const wxString aData );
+
+    wxString ExtraData();
+
+    wxString LinkText( const wxString& aText );
+
+    wxString TableHeader( const wxArrayString& aHeaderData );
+    wxString TableRow( const int& aRowNum, const wxArrayString& aRowData );
+    wxString TableEntry( wxString aData, wxString aColor = wxEmptyString );
+
+    wxArrayString m_linkChecks;
+};
+
+#endif /* EESCHEMA_BOM_EXPORTER_H_ */
diff --git a/eeschema/bom_table_column.cpp b/eeschema/bom_table_column.cpp
new file mode 100644
index 0000000..01b7120
--- /dev/null
+++ b/eeschema/bom_table_column.cpp
@@ -0,0 +1,136 @@
+/*
+* This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 "bom_table_column.h"
+
+BOM_COLUMN_LIST::BOM_COLUMN_LIST() : m_nextFieldId( BOM_COL_ID_USER )
+{
+
+}
+
+void BOM_COLUMN_LIST::Clear()
+{
+    Columns.clear();
+    m_nextFieldId = BOM_COL_ID_USER;
+}
+
+/**
+ * Return the number of columns
+ * @param aIncludeHidden - If this is false, only visible columns will be included
+ */
+unsigned int BOM_COLUMN_LIST::ColumnCount( bool aIncludeHidden ) const
+{
+    unsigned int count = 0;
+
+    for( BOM_COLUMN* col : Columns )
+    {
+        if( col && ( col->IsVisible() || aIncludeHidden ) )
+        {
+            count++;
+        }
+    }
+
+    return count;
+}
+
+/**
+ * Return a column based on its stored position
+ */
+BOM_COLUMN* BOM_COLUMN_LIST::GetColumnByIndex( unsigned int aColId )
+{
+    if( aColId < Columns.size() )
+        return Columns[aColId];
+
+    return nullptr;
+}
+
+/**
+ * Return a column based on its unique ID
+ */
+BOM_COLUMN* BOM_COLUMN_LIST::GetColumnById( unsigned int aColId )
+{
+    for( unsigned int ii=0; ii<Columns.size(); ii++ )
+    {
+        if( Columns[ii] && Columns[ii]->Id() == aColId )
+            return Columns[ii];
+    }
+
+    return nullptr;
+}
+
+/**
+ * Return a column based on its string title
+ */
+BOM_COLUMN* BOM_COLUMN_LIST::GetColumnByTitle( wxString aColTitle )
+{
+    for( unsigned int ii=0; ii<Columns.size(); ii++ )
+    {
+        if( Columns[ii] && Columns[ii]->Title().CmpNoCase( aColTitle ) == 0 )
+            return Columns[ii];
+    }
+
+    return nullptr;
+}
+
+/**
+ * Test if the list includes a column with the given unique ID
+ */
+bool BOM_COLUMN_LIST::ContainsColumn( unsigned int aColId )
+{
+    for( BOM_COLUMN* col : Columns )
+    {
+        if( col && col->Id() == aColId )
+            return true;
+    }
+
+    return false;
+}
+
+/**
+ * Test if the list includes a column with the given title
+ */
+bool BOM_COLUMN_LIST::ContainsColumn( wxString aColTitle )
+{
+    return nullptr != GetColumnByTitle( aColTitle );
+}
+
+/**
+ * Add a new column to the list
+ */
+bool BOM_COLUMN_LIST::AddColumn( BOM_COLUMN* aCol )
+{
+    if( nullptr == aCol )
+        return false;
+
+    if( ContainsColumn( aCol->Id() ) )
+        return false;
+
+    Columns.push_back( aCol );
+
+    // If this is a user field, increment the counter
+    if( aCol->Id() >= BOM_COL_ID_USER )
+        m_nextFieldId++;
+
+    return true;
+}
diff --git a/eeschema/bom_table_column.h b/eeschema/bom_table_column.h
new file mode 100644
index 0000000..3e29756
--- /dev/null
+++ b/eeschema/bom_table_column.h
@@ -0,0 +1,147 @@
+/*
+* This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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
+ */
+
+#ifndef EESCHEMA_BOM_TABLE_COLUMN_H_
+#define EESCHEMA_BOM_TABLE_COLUMN_H_
+
+#include <wx/regex.h>
+#include <wx/string.h>
+#include <vector>
+
+// Default column names (translated)
+#define BOM_COL_TITLE_REFERENCE    _( "Reference" )
+#define BOM_COL_TITLE_DESCRIPTION  _( "Description" )
+#define BOM_COL_TITLE_FOOTPRINT    _( "Footprint" )
+#define BOM_COL_TITLE_VALUE        _( "Value" )
+#define BOM_COL_TITLE_DATASHEET    _( "Datasheet" )
+#define BOM_COL_TITLE_QUANTITY     _( "Quantity" )
+
+/**
+ * Column type enumeration
+ * Not currently implemented,
+ * in the future the different column 'types' might
+ * be used for something...
+ */
+enum BOM_COLUMN_TYPE
+{
+    BOM_COL_TYPE_KICAD = 0,     ///< Default column (editable)
+    BOM_COL_TYPE_LIBRARY,       ///< Default column (non-editable)
+    BOM_COL_TYPE_GENERATED,     ///< Generated column (e.g. Quantity)
+    BOM_COL_TYPE_USER,          ///< User data
+};
+
+
+/**
+ * Predefined column ID values for default columns.
+ * User columns are assigned IDs of 1000 and above
+ */
+enum BOM_COLUMN_ID
+{
+    // Default component fields
+    BOM_COL_ID_REFERENCE = 0,
+    BOM_COL_ID_DESCRIPTION,
+    BOM_COL_ID_FOOTPRINT,
+    BOM_COL_ID_VALUE,
+    BOM_COL_ID_DATASHEET,
+
+    // Meta-data fields
+    BOM_COL_ID_QUANTITY = 100,
+
+    // Custom data fields
+    BOM_COL_ID_USER = 1000,
+};
+
+/**
+ * BOM_COLUMN class
+ * Models a single column in the BOM view
+ * Each column can be used to group components,
+ * and can be hidden from the output BOM
+ */
+class BOM_COLUMN
+{
+protected:
+    unsigned int        m_id;       ///< Unique column ID
+    BOM_COLUMN_TYPE     m_Type;     ///< Column type
+
+    wxString    m_Title;        ///< The column (field) title
+    bool        m_Show;         ///< Is this column visible?
+    bool        m_ReadOnly;     ///< Is this column read only?
+
+public:
+    BOM_COLUMN( unsigned int aId, BOM_COLUMN_TYPE aType, const wxString aTitle, bool aShow, bool aReadOnly = false ) :
+            m_id( aId ),
+            m_Type( aType ),
+            m_Title( aTitle.Strip( wxString::both ) ),
+            m_Show( aShow ),
+            m_ReadOnly( aReadOnly )
+    {
+    }
+
+    unsigned int Id() const { return m_id; }
+    BOM_COLUMN_TYPE Type() const { return m_Type; }
+    wxString Title() const { return m_Title; }
+    bool IsVisible() const { return m_Show; }
+    bool IsReadOnly() const { return m_ReadOnly; }
+
+    //TODO - Should renaming of columns be allowed?
+    //bool SetTitle( const wxString aTitle );
+    void SetVisible( bool aShow = true ) { m_Show = aShow; }
+    void SetReadOnly( bool aReadOnly = true ) { m_ReadOnly = aReadOnly; }
+
+};
+
+/*
+ * The BOM_COLUMN_LIST class contains information
+ * on all columns existing in the BOM
+ */
+class BOM_COLUMN_LIST
+{
+protected:
+
+    unsigned int m_nextFieldId;
+
+public:
+    std::vector< BOM_COLUMN* > Columns;
+
+    BOM_COLUMN_LIST();
+
+    void Clear();
+
+    unsigned int NextFieldId() const { return m_nextFieldId; }
+    unsigned int ColumnCount( bool aIncludeHidden = true ) const;
+
+    BOM_COLUMN* GetColumnByIndex( unsigned int aColIndex );
+    BOM_COLUMN* GetColumnById( unsigned int aColId );
+    BOM_COLUMN* GetColumnByTitle( const wxString aColTitle ) ;
+
+    bool ContainsColumn( unsigned int aColId );
+    bool ContainsColumn( const wxString aColTitle );
+
+    bool AddColumn( BOM_COLUMN* aCol );
+
+};
+
+
+
+#endif /* EESCHEMA_BOM_TABLE_COLUMN_H_ */
diff --git a/eeschema/bom_table_model.cpp b/eeschema/bom_table_model.cpp
new file mode 100644
index 0000000..a43d749
--- /dev/null
+++ b/eeschema/bom_table_model.cpp
@@ -0,0 +1,1404 @@
+/*
+* This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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 "bom_table_model.h"
+
+// Indicator that multiple values exist in child rows
+#define ROW_MULT_ITEMS wxString( "<...>" )
+
+static const wxColor ROW_COLOUR_ITEM_CHANGED( 200, 0, 0 );
+static const wxColor ROW_COLOUR_MULTIPLE_ITEMS( 60, 90, 200 );
+
+/**
+ * Convert BOM_TABLE_ROW -> wxDataViewItem
+ */
+static wxDataViewItem RowToItem( BOM_TABLE_ROW const* aRow )
+{
+    return wxDataViewItem( const_cast<void*>( static_cast<void const*>( aRow ) ) );
+}
+
+/**
+ * Convert wxDataViewItem -> BOM_TABEL_ROW
+ */
+static BOM_TABLE_ROW const* ItemToRow( wxDataViewItem aItem )
+{
+    if( !aItem.IsOk() )
+    {
+        return nullptr;
+    }
+    else
+    {
+        return static_cast<BOM_TABLE_ROW const*>( aItem.GetID() );
+    }
+}
+
+BOM_TABLE_ROW::BOM_TABLE_ROW() : m_columnList( nullptr )
+{
+}
+
+/**
+ * Update cell attributes based on parameters of the cell
+ * Default implementation highlights cells that have been altered
+ */
+bool BOM_TABLE_ROW::GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const
+{
+    auto field = m_columnList->GetColumnById( aFieldId );
+
+    if( HasValueChanged( field ) )
+    {
+        aAttr.SetBold( true );
+        aAttr.SetItalic( true );
+        aAttr.SetColour( ROW_COLOUR_ITEM_CHANGED );
+        return true;
+    }
+
+    return false;
+}
+
+bool BOM_TABLE_ROW::HasChanged() const
+{
+    if( !m_columnList )
+        return false;
+
+    for( auto& column : m_columnList->Columns )
+    {
+        if( column && HasValueChanged( column ) )
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * Create a new group (which contains one or more components)
+ */
+BOM_TABLE_GROUP::BOM_TABLE_GROUP( BOM_COLUMN_LIST* aColumnList )
+{
+    m_columnList = aColumnList;
+}
+
+bool BOM_TABLE_GROUP::GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const
+{
+    if( GetFieldValue( aFieldId ).Cmp( ROW_MULT_ITEMS ) == 0 )
+    {
+        aAttr.SetItalic( true );
+        aAttr.SetColour( ROW_COLOUR_MULTIPLE_ITEMS );
+        return true;
+    }
+
+    return BOM_TABLE_ROW::GetAttr( aFieldId, aAttr );
+}
+
+/**
+ * Return the value associated with a given field in the group.
+ * Some fields require special attention.
+ */
+wxString BOM_TABLE_GROUP::GetFieldValue( unsigned int aFieldId ) const
+{
+    wxString value;
+
+    // Account for special cases
+    switch( aFieldId )
+    {
+    // QUANTITY returns the size of the group
+    case BOM_COL_ID_QUANTITY:
+        value = wxString::Format( "%u", (unsigned int) GroupSize() );
+        break;
+    // REFERENCE field returns consolidated list of references
+    case BOM_COL_ID_REFERENCE:
+        value = wxJoin( GetReferences(), ' ' );
+        break;
+    // Otherwise, return component data
+    default:
+        if( Components.size() == 0 )
+        {
+            value = wxEmptyString;
+        }
+        else
+        {
+            // If the components in this group contain multiple items,
+            // display a special string indicating this
+            for( unsigned int i=0; i<Components.size(); i++ )
+            {
+                auto const& cmp = Components[i];
+
+                if( i == 0 )
+                {
+                    value = cmp->GetFieldValue( aFieldId );
+                }
+                // Mismatch found
+                else if( value.Cmp( cmp->GetFieldValue( aFieldId ) ) != 0 )
+                {
+                    value = ROW_MULT_ITEMS;
+                    break;
+                }
+            }
+        }
+        break;
+    }
+
+    return value;
+}
+
+/**
+ * Set the value of a field in a group
+ * The new value is pushed to all components that are children of this group
+ */
+bool BOM_TABLE_GROUP::SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite )
+{
+    bool result = false;
+
+    for( auto& cmp : Components )
+    {
+        result |= cmp->SetFieldValue( aFieldId, aValue, aOverwrite );
+    }
+
+    return result;
+}
+
+/**
+ * Determines if a given component matches against a particular field.
+ *
+ * - Tests each field in turn; all fields must match
+ * - Some fields require special checking
+ *
+ * @aFieldId - The ID of the field
+ * @aCmp - The component being tested
+ */
+bool BOM_TABLE_GROUP::TestField( BOM_COLUMN* aField, BOM_TABLE_COMPONENT* aComponent ) const
+{
+    if( !aField || !aComponent )
+        return false;
+
+    if( Components.size() == 0 )
+        return true;
+
+    wxString componentValue;
+    wxString comparisonValue;
+
+    // Some fields are handled in a special manner
+    // (handle these first)
+    switch( aField->Id() )
+    {
+    // These fields should NOT be compared (return True)
+    case BOM_COL_ID_QUANTITY:
+        return true;
+    // Reference matching is done only on prefix
+    case BOM_COL_ID_REFERENCE:
+        componentValue = aComponent->GetPrefix();
+        comparisonValue = Components[0]->GetPrefix();
+        break;
+    default:
+        componentValue = aComponent->GetFieldValue( aField->Id() );
+        comparisonValue = Components[0]->GetFieldValue( aField->Id() );
+        break;
+    }
+
+    bool result = componentValue.Cmp( comparisonValue ) == 0;
+
+    return result;
+}
+
+/**
+ * Add a new component to the group.
+ * It is assumed at this stage that the component is a good match for the group.
+ * @param aCmp is the new component to add
+ */
+bool BOM_TABLE_GROUP::AddComponent( BOM_TABLE_COMPONENT* aComponent )
+{
+    if( !aComponent )
+        return false;
+
+    // To be a match, all fields must match!
+    bool match = true;
+
+    for( auto* column : m_columnList->Columns )
+    {
+        match = TestField( column, aComponent );
+
+        // Escape on first mismatch
+        if( !match )
+        {
+            break;
+        }
+    }
+
+    if( match )
+    {
+        aComponent->SetParent( this );
+        Components.push_back( aComponent );
+        return true;
+    }
+    else
+    {
+        return false;
+    }
+
+    return false;
+}
+
+
+/**
+ * Adds each child row to the supplied list, and returns the total child count
+ */
+unsigned int BOM_TABLE_GROUP::GetChildren( wxDataViewItemArray& aChildren ) const
+{
+    // Show drop-down for child components
+    for( auto& row : Components )
+    {
+        if( row )
+        {
+            aChildren.push_back( RowToItem( &*row ) );
+        }
+    }
+
+    return aChildren.size();
+}
+
+/**
+ * Test if any components in this group have a new value in the provided field
+ * @param aField is the field to test
+ * @return true if any children have changed else false
+ */
+bool BOM_TABLE_GROUP::HasValueChanged( BOM_COLUMN* aField ) const
+{
+
+    bool changed = false;
+
+    if( !aField )
+        return false;
+
+    for( auto const& row : Components )
+    {
+        if( row->HasValueChanged( aField ) )
+        {
+            changed = true;
+            break;
+        }
+    }
+
+    // If the value has changed, the group field data must be updated
+    if( changed )
+    {
+        //TODO
+    }
+
+    return changed;
+}
+
+/**
+ * Return a list of (ordered) references
+ * for all the components in this group
+ *
+ * @aSort - Sort the references
+ */
+wxArrayString BOM_TABLE_GROUP::GetReferences( bool aSort) const
+{
+    wxArrayString refs;
+
+    for( auto const& cmp : Components )
+    {
+        if( cmp )
+        {
+            refs.Add( cmp->GetFieldValue( BOM_COL_ID_REFERENCE ) );
+        }
+    }
+
+    if( aSort )
+    {
+        refs.Sort( SortReferences );
+    }
+
+    return refs;
+}
+
+/**
+ * Compare two references (e.g. "R100", "R19") and perform a 'natural' sort
+ * This sorting must preserve numerical order rather than alphabetical
+ * e.g. "R100" is lower (alphabetically) than "R19"
+ * BUT should be placed after R19
+ */
+int BOM_TABLE_GROUP::SortReferences( const wxString& aFirst, const wxString& aSecond )
+{
+    // Default sorting
+    int defaultSort = aFirst.Cmp( aSecond );
+
+    static const wxString REGEX_STRING = "^([a-zA-Z]+)(\\d+)$";
+
+    // Compile regex statically
+    static wxRegEx regexFirst( REGEX_STRING, wxRE_ICASE | wxRE_ADVANCED );
+    static wxRegEx regexSecond( REGEX_STRING, wxRE_ICASE | wxRE_ADVANCED );
+
+    if( !regexFirst.Matches( aFirst ) || !regexSecond.Matches( aSecond ) )
+    {
+        return defaultSort;
+    }
+
+    // First priority is to order by prefix
+    wxString prefixFirst  = regexFirst.GetMatch( aFirst, 1 );
+    wxString prefixSecond = regexSecond.GetMatch( aSecond, 1 );
+
+    if( prefixFirst.CmpNoCase( prefixSecond ) != 0 ) // Different prefixes!
+    {
+        return defaultSort;
+    }
+
+    wxString numStrFirst   = regexFirst.GetMatch( aFirst, 2 );
+    wxString numStrSecond  = regexSecond.GetMatch( aSecond, 2 );
+
+    // If either match failed, just return normal string comparison
+    if( numStrFirst.IsEmpty() || numStrSecond.IsEmpty() )
+    {
+        return defaultSort;
+    }
+
+    // Convert each number string to an integer
+    long numFirst    = 0;
+    long numSecond   = 0;
+
+    // If either conversion fails, return normal string comparison
+    if( !numStrFirst.ToLong( &numFirst ) || !numStrSecond.ToLong( &numSecond ) )
+    {
+        return defaultSort;
+    }
+
+    return (int) (numFirst - numSecond);
+}
+
+/**
+ * Compare two VALUE fields.
+ * A value field can reasonably be expected to be one of:
+ * a) Purely numerical e.g. '22'
+ * b) Numerical with included units e.g. '15uF'
+ * c) Numerical with included prefix but no units e.g. '20n'
+ * d) Numerical with prefix inside number e.g. '4K7'
+ * e) Other, e.g. 'MAX232'
+ *
+ * Cases a) to d) should be detected and converted to a common representation
+ * Values that do not match this pattern should revert to standard string comparison
+ */
+int BOM_TABLE_GROUP::SortValues( const wxString& aFirst, const wxString& aSecond )
+{
+    //TODO - Intelligent comparison of component values
+    // e.g. 4K > 499
+    // e.g. 1nF < 0.1u
+
+    // For now, just return default comparison
+
+    return aFirst.CmpNoCase( aSecond );
+}
+
+/**
+ * Create a new COMPONENT row
+ * Each COMPONENT row is associated with a single component item.
+ */
+BOM_TABLE_COMPONENT::BOM_TABLE_COMPONENT( BOM_TABLE_GROUP* aParent,
+                                          BOM_COLUMN_LIST* aColumnList)
+{
+    m_parent = aParent;
+    m_columnList = aColumnList;
+}
+
+/**
+ * Try to add a unit to this component
+ * If the references match, it will be added
+ */
+bool BOM_TABLE_COMPONENT::AddUnit( SCH_REFERENCE aUnit )
+{
+    // Addition is successful if the references match or there are currently no units in the group
+    if( Units.size() == 0  || Units[0].GetRef().Cmp( aUnit.GetRef() ) == 0 )
+    {
+        Units.push_back( aUnit );
+
+        wxString value;
+
+        // Extract the component data
+        for( auto column : m_columnList->Columns )
+        {
+            auto cmp = aUnit.GetComp();
+
+            switch( column->Id() )
+            {
+            case BOM_COL_ID_QUANTITY:
+                value = wxEmptyString;
+                break;
+            case BOM_COL_ID_DESCRIPTION:
+                value = cmp->GetAliasDescription();
+                break;
+            case BOM_COL_ID_DATASHEET:
+                value = cmp->GetField( DATASHEET )->GetText();
+                if( value.IsEmpty() )
+                {
+                    value = cmp->GetAliasDocumentation();
+                }
+                break;
+            case BOM_COL_ID_REFERENCE:
+                value = cmp->GetField( REFERENCE )->GetText();
+                break;
+            case BOM_COL_ID_VALUE:
+                value = cmp->GetField( VALUE )->GetText();
+                break;
+            case BOM_COL_ID_FOOTPRINT:
+                value = cmp->GetField( FOOTPRINT )->GetText();
+                break;
+
+            // User fields
+            default:
+                value = cmp->GetFieldText( column->Title() );
+                break;
+            }
+
+            SetFieldValue( column->Id(), value );
+
+            // Add the value to the fallback map
+            m_fallbackData[column->Id()] = value;
+        }
+
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * Return the value associated with a particular field
+ * If no field is found, return an empty string
+ */
+wxString BOM_TABLE_COMPONENT::GetFieldValue( unsigned int aFieldId ) const
+{
+    auto search = m_fieldData.find( aFieldId );
+
+    if( search != m_fieldData.end()  )
+    {
+        return search->second;
+    }
+    else
+    {
+        return wxEmptyString;
+    }
+}
+
+/**
+ * Set the value of a field in the component
+ * @param aFieldId is the unique ID of the field to update
+ * @param aValue is the new value
+ * @param aOverwrite enforces writing even if a value exists
+ */
+bool BOM_TABLE_COMPONENT::SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite )
+{
+    if( aOverwrite || m_fieldData.count( aFieldId ) == 0 || m_fieldData[aFieldId].IsEmpty() )
+    {
+        m_fieldData[aFieldId] = aValue;
+        return true;
+    }
+
+    return false;
+}
+
+/**
+ * Return the prefix of a component e.g. "R23" -> "R"
+ */
+wxString BOM_TABLE_COMPONENT::GetPrefix() const
+{
+    if( Units.size() == 0 )
+        return wxEmptyString;
+
+    return Units[0].GetComp()->GetPrefix();
+}
+
+/**
+ * Return the reference of a component e.g. "R23"
+ */
+wxString BOM_TABLE_COMPONENT::GetReference() const
+{
+    if( Units.size() == 0 )
+        return wxEmptyString;
+
+    return Units[0].GetRef();
+}
+
+/**
+ * Determines if the given field has been changed for this component
+ */
+bool BOM_TABLE_COMPONENT::HasValueChanged( BOM_COLUMN* aField ) const
+{
+    if( !aField )
+    {
+        return false;
+    }
+
+    auto value = m_fieldData.find( aField->Id() );
+    auto backup = m_fallbackData.find( aField->Id() );
+
+    wxString currentValue = value == m_fieldData.end() ? wxString() : value->second;
+    wxString backupValue = backup == m_fallbackData.end() ? wxString() : backup->second;
+
+    return currentValue.Cmp( backupValue ) != 0;
+}
+
+/**
+ * If any changes have been made to this component,
+ * they are now applied to the schematic component
+ */
+void BOM_TABLE_COMPONENT::ApplyFieldChanges()
+{
+    for( auto& unit : Units )
+    {
+        auto cmp = unit.GetComp();
+
+        if( !cmp )
+            continue;
+
+        // Iterate over each column
+        SCH_FIELD* field;
+
+        for( auto& column : m_columnList->Columns )
+        {
+            if( column && HasValueChanged( column ) )
+            {
+                wxString value = GetFieldValue( column->Id() );
+
+                switch( column->Id() )
+                {
+                // Ignore read-only fields
+                case BOM_COL_ID_REFERENCE:
+                case BOM_COL_ID_QUANTITY:
+                    continue;
+                // Special field considerations
+                case BOM_COL_ID_FOOTPRINT:
+                    field = cmp->GetField( FOOTPRINT );
+                    break;
+                case BOM_COL_ID_VALUE:
+                    field = cmp->GetField( VALUE );
+                    break;
+                case BOM_COL_ID_DATASHEET:
+                    field = cmp->GetField( DATASHEET );
+                    break;
+                default:
+                    field = cmp->FindField( column->Title() );
+                    break;
+                }
+
+                if( !field && !value.IsEmpty() )
+                {
+                    SCH_FIELD newField( wxPoint( 0, 0 ), -1, cmp, column->Title() );
+                    field = cmp->AddField( newField );
+                }
+
+                if( field )
+                {
+                    field->SetText( value );
+                }
+            }
+        }
+    }
+}
+
+/**
+ * Revert the displayed fields for this component
+ * to their original values (matching the schematic data)
+ */
+void BOM_TABLE_COMPONENT::RevertFieldChanges()
+{
+    for( auto& column : m_columnList->Columns )
+    {
+        switch( column->Id() )
+        {
+        case BOM_COL_ID_REFERENCE:
+        case BOM_COL_ID_QUANTITY:
+            continue;
+        default:
+            break;
+        }
+
+        if( column && HasValueChanged( column ) )
+        {
+            if( m_fallbackData.count( column->Id() ) > 0 )
+            {
+                m_fieldData[column->Id()] = m_fallbackData[column->Id()];
+            }
+            else
+            {
+                m_fieldData[column->Id()] = wxEmptyString;
+            }
+        }
+    }
+}
+
+BOM_TABLE_MODEL::BOM_TABLE_MODEL() :
+        m_widget( nullptr ),
+        m_sortingColumn( BOM_COL_ID_REFERENCE ),
+        m_sortingOrder( true )
+{
+    //TODO
+}
+
+/**
+ * Create a container for the BOM_TABLE_MODEL
+ * This is required for reference counting by wxDataViewCtrl
+ */
+BOM_TABLE_MODEL::MODEL_PTR BOM_TABLE_MODEL::Create()
+{
+    auto model = new BOM_TABLE_MODEL();
+
+    auto container = BOM_TABLE_MODEL::MODEL_PTR( model );
+
+    return container;
+}
+
+BOM_TABLE_MODEL::~BOM_TABLE_MODEL()
+{
+   //TODO
+}
+
+wxDataViewColumn* BOM_TABLE_MODEL::AddColumn( BOM_COLUMN* aColumn, int aPosition )
+{
+    static const unsigned int flags = wxDATAVIEW_COL_RESIZABLE | wxDATAVIEW_COL_SORTABLE;
+
+    if( !m_widget || !aColumn || !aColumn->IsVisible() )
+        return nullptr;
+
+    wxDataViewCellMode editFlag = aColumn->IsReadOnly() ? wxDATAVIEW_CELL_INERT : wxDATAVIEW_CELL_EDITABLE;
+
+    auto renderer = new wxDataViewTextRenderer( "string" , editFlag );
+
+    auto column = new wxDataViewColumn( aColumn->Title(),
+                                        renderer,
+                                        aColumn->Id(),
+                                        150, //TODO - variable default width?
+                                        wxAlignment( wxALIGN_CENTER ),
+                                        flags );
+
+    // Work out where to insert the column
+    std::set<unsigned int> columnsBefore;
+
+    for( auto testCol : ColumnList.Columns )
+    {
+        if( testCol->Id() == aColumn->Id() )
+        {
+            break;
+        }
+        else
+        {
+            columnsBefore.insert( testCol->Id() );
+        }
+    }
+
+    bool found = false;
+
+    for( unsigned int ii=0; ii<m_widget->GetColumnCount(); ii++ )
+    {
+        auto col = m_widget->GetColumn( ii );
+
+        if( !col )
+            continue;
+
+        // If the new column is already in the view, escape
+        if( col->GetModelColumn() == aColumn->Id() )
+        {
+            return col;
+        }
+
+        // If we should insert the new column BEFORE this one
+        if( columnsBefore.count( col->GetModelColumn() ) == 0 )
+        {
+            found = true;
+            m_widget->InsertColumn( ii, column );
+            break;
+        }
+    }
+
+    if( !found )
+        m_widget->AppendColumn( column );
+
+    //TODO - wxCOL_WIDTH_AUTOSIZE prevents columns from thereafter being resized
+    // This requires some further attention
+
+    /**
+    column->SetWidth( wxCOL_WIDTH_AUTOSIZE );
+    column->SetWidth( column->GetWidth() );
+    **/
+    column->SetResizeable( true );
+
+    return column;
+}
+
+/**
+ * Gracefully remove the given column from the wxDataViewCtrl
+ * Removing columns individually prevents bad redraw of entire table
+ */
+bool BOM_TABLE_MODEL::RemoveColumn( BOM_COLUMN* aColumn )
+{
+    if( !m_widget || !aColumn )
+        return false;
+
+    for( unsigned int ii=0; ii<m_widget->GetColumnCount(); ii++ )
+    {
+        auto col = m_widget->GetColumn( ii );
+
+        if( col && col->GetModelColumn() == aColumn->Id() )
+        {
+            m_widget->DeleteColumn( col );
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/**
+ * Attach the MODEL to a particular VIEW
+ * This function causes the view to be updated appropriately
+ */
+void BOM_TABLE_MODEL::AttachTo( wxDataViewCtrl* aView )
+{
+    if( !aView )
+    {
+        return;
+    }
+
+    m_widget = aView;
+    aView->Freeze();
+    Cleared();
+
+    aView->AssociateModel( this );
+    aView->ClearColumns();
+
+    // Add all columns
+    for( auto col : ColumnList.Columns )
+    {
+        AddColumn( col );
+    }
+
+    aView->Thaw();
+
+    // Notify the view that the data needs to be redrawn
+    aView->Update();
+}
+
+/**
+ * Return the total number of components displayed by the model
+ */
+unsigned int BOM_TABLE_MODEL::ComponentCount() const
+{
+    unsigned int count = 0;
+
+    for( auto& group : Groups )
+    {
+        if( group )
+            count += group->GroupSize();
+    }
+
+    return count;
+}
+
+void BOM_TABLE_MODEL::ClearColumns()
+{
+    ColumnList.Clear();
+}
+
+/**
+ * Add default columns to the table
+ * These columns are ALWAYS available in the table
+ * They are immutable - can be hidden by user but not removed
+ */
+void BOM_TABLE_MODEL::AddDefaultColumns()
+{
+    // Reference column is read-only
+    ColumnList.AddColumn( new BOM_COLUMN(
+                BOM_COL_ID_REFERENCE,
+                BOM_COL_TYPE_GENERATED,
+                BOM_COL_TITLE_REFERENCE,
+                true, true ) );
+
+    ColumnList.AddColumn( new BOM_COLUMN(
+               BOM_COL_ID_VALUE,
+               BOM_COL_TYPE_KICAD,
+               BOM_COL_TITLE_VALUE,
+               true, false ) );
+
+    ColumnList.AddColumn( new BOM_COLUMN(
+               BOM_COL_ID_FOOTPRINT,
+               BOM_COL_TYPE_KICAD,
+               BOM_COL_TITLE_FOOTPRINT,
+               true, false ) );
+
+    ColumnList.AddColumn( new BOM_COLUMN(
+               BOM_COL_ID_DATASHEET,
+               BOM_COL_TYPE_KICAD,
+               BOM_COL_TITLE_DATASHEET,
+               true, false ) );
+
+    // Description comes from .dcm file and is read-only
+    ColumnList.AddColumn( new BOM_COLUMN(
+               BOM_COL_ID_DESCRIPTION,
+               BOM_COL_TYPE_LIBRARY,
+               BOM_COL_TITLE_DESCRIPTION,
+               true, true ) );
+
+    // Quantity column is read-only
+    ColumnList.AddColumn( new BOM_COLUMN(
+               BOM_COL_ID_QUANTITY,
+               BOM_COL_TYPE_GENERATED,
+               BOM_COL_TITLE_QUANTITY,
+               true, true ) );
+}
+
+/**
+ * Extract field data from all components
+ * Compiles an inclusive list of all field names from all components
+ */
+void BOM_TABLE_MODEL::AddComponentFields( SCH_COMPONENT* aCmp )
+{
+    std::vector< SCH_FIELD* > fields;
+
+    SCH_FIELD* field;
+    wxString fieldName;
+
+    if( nullptr == aCmp )
+        return;
+
+    // Extract custom columns from component
+    fields.clear();
+    aCmp->GetFields( fields, false );
+
+    // Iterate over custom field datas
+    for( unsigned int i=MANDATORY_FIELDS; i<fields.size(); i++ )
+    {
+        field = fields[i];
+
+        if( nullptr == field ) continue;
+
+        fieldName = field->GetName();
+
+        auto existing = ColumnList.GetColumnByTitle( fieldName );
+
+        // As columns are sorted by ID, we can allow user to
+        // create a column with a "special" name
+        if( existing && existing->Id() >= MANDATORY_FIELDS)
+            continue;
+
+        ColumnList.AddColumn( new BOM_COLUMN( ColumnList.NextFieldId(),
+                                         BOM_COL_TYPE_USER,
+                                         field->GetName(),
+                                         true, false ) );
+    }
+}
+
+/**
+ * Add a list of component items to the BOM manager
+ * Creates consolidated groups of components as required
+ */
+void BOM_TABLE_MODEL::SetComponents( SCH_REFERENCE_LIST aRefs )
+{
+    // Add default columns
+    AddDefaultColumns();
+
+    // Extract all component fields
+    for( unsigned int ii=0; ii<aRefs.GetCount(); ii++ )
+    {
+        auto ref = aRefs.GetItem( ii );
+        auto cmp = ref.GetComp();
+
+        if( cmp )
+        {
+            AddComponentFields( cmp );
+        }
+    }
+
+    // Group multi-unit components together
+    m_components.clear();
+
+    for( unsigned int ii=0; ii<aRefs.GetCount(); ii++ )
+    {
+        auto ref = aRefs.GetItem( ii );
+
+        bool found = false;
+
+        for( auto& cmp : m_components )
+        {
+            if( cmp->AddUnit( ref ) )
+            {
+                found = true;
+                break;
+            }
+        }
+
+        if( !found )
+        {
+            auto* newComponent = new BOM_TABLE_COMPONENT( nullptr, &ColumnList );
+            newComponent->AddUnit( ref );
+
+            m_components.push_back( std::unique_ptr<BOM_TABLE_COMPONENT>( newComponent ) );
+        }
+    }
+}
+
+/**
+ *  Recalculate grouping of components and reload table
+ **/
+void BOM_TABLE_MODEL::ReloadTable()
+{
+    if( m_widget )
+    {
+        m_widget->Freeze();
+    }
+
+    // Alert the view that the model data has changed
+    Cleared();
+
+    Groups.clear();
+
+    for( auto& cmp : m_components )
+    {
+        bool grouped = false;
+
+        if( m_groupColumns )
+        {
+            for( auto& group : Groups )
+            {
+                if( group->AddComponent( &*cmp ) )
+                {
+                    grouped = true;
+                    break;
+                }
+            }
+        }
+
+        // No suitable group was found for this component
+        if( !grouped )
+        {
+            auto* newGroup = new BOM_TABLE_GROUP( &ColumnList );
+
+            newGroup->AddComponent( &*cmp );
+
+            Groups.push_back( std::unique_ptr<BOM_TABLE_GROUP>( newGroup ) );
+        }
+    }
+
+    // Update the display
+    if( m_widget )
+    {
+        //Cleared();
+        m_widget->AssociateModel( this );
+        m_widget->Thaw();
+    }
+}
+
+/**
+ * Return a string array of data from a given row
+ */
+wxArrayString BOM_TABLE_MODEL::GetRowData( unsigned int aRow, std::vector<BOM_COLUMN*> aColumns ) const
+{
+    wxArrayString row;
+
+    wxString data;
+
+    if( Groups.size() <= aRow )
+        return row;
+
+    auto const& group = Groups[aRow];
+
+    if ( !group )
+        return row;
+
+    for( auto const col : aColumns )
+    {
+        if( !col )
+        {
+            row.Add( wxEmptyString );
+            continue;
+        }
+
+        row.Add( group->GetFieldValue( col->Id() ) );
+    }
+
+    return row;
+}
+
+/**
+ * Get the value of a particular item in the model
+ */
+void BOM_TABLE_MODEL::GetValue(
+        wxVariant& aVariant,
+        const wxDataViewItem& aItem,
+        unsigned int aFieldId ) const
+{
+    auto row = ItemToRow( aItem );
+
+    if( row )
+    {
+        aVariant = row->GetFieldValue( aFieldId );
+    }
+}
+
+/**
+ * Set the value of a particular item in the model
+ */
+bool BOM_TABLE_MODEL::SetValue(
+        const wxVariant& aVariant,
+        const wxDataViewItem& aItem,
+        unsigned int aFieldId )
+{
+    if( !aItem.IsOk() || !m_widget )
+    {
+        return false;
+    }
+
+    // Extract the value to be set
+    if( aVariant.GetType().Cmp( "string" ) == 0 )
+    {
+        wxString value = aVariant.GetString();
+
+        bool result = false;
+
+        wxDataViewItemArray selectedItems;
+        m_widget->GetSelections( selectedItems );
+
+        // Set the row value for all selected rows
+
+        for( auto item : selectedItems )
+        {
+            auto selectedRow = static_cast<BOM_TABLE_ROW*>( item.GetID() );
+
+            if( selectedRow )
+            {
+                result |= selectedRow->SetFieldValue( aFieldId, value, true );
+            }
+        }
+
+        return result;
+    }
+
+    // Default
+    return false;
+}
+
+/**
+ * Return the parent item for a given item in the model.
+ * If no parent is found (or the item is invalid) return an invalid item.
+ */
+wxDataViewItem BOM_TABLE_MODEL::GetParent( const wxDataViewItem& aItem ) const
+{
+    auto row = ItemToRow( aItem );
+    auto parent = row ? row->GetParent() : nullptr;
+
+    if( parent )
+    {
+        return RowToItem( parent );
+    }
+
+    // Return an invalid item
+    return wxDataViewItem();
+}
+
+/**
+ * Returns true if the supplied item has children
+ */
+bool BOM_TABLE_MODEL::IsContainer( const wxDataViewItem& aItem ) const
+{
+    auto row = ItemToRow( aItem );
+
+    if( row )
+    {
+        return row->HasChildren();
+    }
+
+    return true;
+}
+
+/**
+ * Push all children of the supplied item into the list
+ * If the supplied item is invalid, push all the top-level items
+ */
+unsigned int BOM_TABLE_MODEL::GetChildren(
+        const wxDataViewItem& aItem,
+        wxDataViewItemArray& aChildren ) const
+{
+    auto row = aItem.IsOk() ? ItemToRow( aItem ) : nullptr;
+
+    // Valid row, return its children
+    if( row )
+    {
+        return row->GetChildren( aChildren );
+    }
+    else
+    {
+        for( auto& group : Groups )
+        {
+            aChildren.Add( RowToItem( &*group ) );
+        }
+
+        return aChildren.size();
+    }
+}
+
+bool BOM_TABLE_MODEL::GetAttr( const wxDataViewItem& aItem,
+                           unsigned int aFieldId,
+                           wxDataViewItemAttr& aAttr ) const
+{
+    auto row = aItem.IsOk() ? ItemToRow( aItem ) : nullptr;
+
+    if( row )
+    {
+        return row->GetAttr( aFieldId, aAttr );
+    }
+    else
+    {
+        return false;
+    }
+}
+
+/**
+ * Custom comparison function for improved column sorting
+ * Alphanumeric sorting is not sufficient for correct ordering of some fields
+ * Some columns are sorted numerically, others with more complex rules.
+ */
+int BOM_TABLE_MODEL::Compare( const wxDataViewItem& aItem1,
+                          const wxDataViewItem& aItem2,
+                          unsigned int aColumnId,
+                          bool aAscending ) const
+{
+    if( !aItem1.IsOk() || !aItem2.IsOk() )
+        return 0;
+
+    int result = 0;
+
+    auto row1 = ItemToRow( aItem1 );
+    auto row2 = ItemToRow( aItem2 );
+
+    if( !row1 || !row2 )
+        return 0;
+
+    if( row1->GetParent() != row2->GetParent() )
+        return 0;
+
+    wxString strVal1 = row1->GetFieldValue( aColumnId );
+    wxString strVal2 = row2->GetFieldValue( aColumnId );
+
+    long numVal1;
+    long numVal2;
+
+    switch( aColumnId )
+    {
+    // Reference column sorted by reference val
+    case BOM_COL_ID_REFERENCE:
+        result = BOM_TABLE_GROUP::SortReferences( strVal1, strVal2 );
+        break;
+    case BOM_COL_ID_VALUE:
+        result = BOM_TABLE_GROUP::SortValues( strVal1, strVal2 );
+        break;
+    // These columns are sorted numerically
+    case BOM_COL_ID_QUANTITY:
+        if( strVal1.ToLong( &numVal1 ) && strVal2.ToLong( &numVal2 ) )
+        {
+            result = numVal1 - numVal2;
+        }
+        else
+        {
+            result = strVal1.Cmp( strVal2 );
+        }
+        break;
+    default:
+        // Default comparison (no special case)
+        result = strVal1.Cmp( strVal2 );
+        break;
+    }
+
+    // If initial sorting failed, sort secondly by reference
+    if( result == 0 && aColumnId != BOM_COL_ID_REFERENCE )
+    {
+        result = BOM_TABLE_GROUP::SortReferences(
+                row1->GetFieldValue( BOM_COL_ID_REFERENCE ),
+                row2->GetFieldValue( BOM_COL_ID_REFERENCE ) );
+    }
+
+    // If sorting still failed, sort thirdly by value
+    if( result == 0 && aColumnId != BOM_COL_ID_VALUE )
+    {
+        result = BOM_TABLE_GROUP::SortValues(
+                row1->GetFieldValue( BOM_COL_ID_VALUE ),
+                row2->GetFieldValue( BOM_COL_ID_VALUE ) );
+    }
+
+    if( !aAscending )
+    {
+        result *= -1;
+    }
+
+    return result;
+}
+
+/**
+ * Revert all component data back to the original values.
+ * The table view is updated accordingly
+ */
+void BOM_TABLE_MODEL::RevertFieldChanges()
+{
+    for( auto& group : Groups )
+    {
+        if( !group )
+            continue;
+
+        bool changed = false;
+
+        for( auto& component : group->Components )
+        {
+            if( !component )
+                continue;
+
+            if( component->HasChanged() )
+            {
+                component->RevertFieldChanges();
+                ItemChanged( RowToItem( &*component ) );
+                changed = true;
+            }
+        }
+
+        // Update the group if any components changed
+        if( changed )
+        {
+            ItemChanged( RowToItem( &*group ) );
+        }
+    }
+}
+
+/**
+ * Apply all outstanding field changes.
+ * This is performed only when the window is closed
+ */
+void BOM_TABLE_MODEL::ApplyFieldChanges()
+{
+    for( auto& group : Groups )
+    {
+        if( !group )
+            continue;
+
+        bool changed = false;
+
+        for( auto& component : group->Components )
+        {
+            if( !component )
+                continue;
+
+            if( component->HasChanged() )
+            {
+                component->ApplyFieldChanges();
+                ItemChanged( RowToItem( &*component ) );
+                changed = true;
+            }
+        }
+
+        if( changed )
+        {
+            ItemChanged( RowToItem( &*group ) );
+        }
+    }
+}
+
+/**
+ * Tests if any component values in the table have been altered
+ */
+bool BOM_TABLE_MODEL::HaveFieldsChanged() const
+{
+    for( auto const& group : Groups )
+    {
+        if( !group )
+            continue;
+
+        for( auto const& cmp : group->Components )
+        {
+            if( !cmp )
+                continue;
+
+            if( cmp->HasChanged() )
+            {
+                return true;
+            }
+        }
+    }
+
+    return false;
+}
+
+/**
+ * Returns a list of only those components that have been changed
+ */
+std::vector<SCH_COMPONENT*> BOM_TABLE_MODEL::GetChangedComponents()
+{
+    std::vector<SCH_COMPONENT*> components;
+
+    for( auto& group : Groups )
+    {
+        if( !group )
+            continue;
+
+        for( auto& component : group->Components )
+        {
+            if( !component )
+                continue;
+
+            if( component->HasChanged() )
+            {
+                for( auto& unit : component->Units )
+                {
+                    auto cmp = unit.GetComp();
+
+                    if( cmp )
+                    {
+                        components.push_back( cmp );
+                    }
+                }
+            }
+        }
+    }
+
+    return components;
+}
+
+/**
+ * Returns a count of the components that have been changed
+ */
+unsigned int BOM_TABLE_MODEL::CountChangedComponents()
+{
+    unsigned int count = 0;
+
+    for( auto& group : Groups )
+    {
+        if( !group )
+            continue;
+
+        for( auto& component : group->Components )
+        {
+            if( component && component->HasChanged() )
+            {
+                count++;
+            }
+        }
+    }
+
+    return count;
+}
diff --git a/eeschema/bom_table_model.h b/eeschema/bom_table_model.h
new file mode 100644
index 0000000..8cf3898
--- /dev/null
+++ b/eeschema/bom_table_model.h
@@ -0,0 +1,282 @@
+/*
+* This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * 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
+ */
+
+#ifndef _EESCHEMA_BOM_TABLE_MODEL_H_
+#define _EESCHEMA_BOM_TABLE_MODEL_H_
+
+#include <wx/dataview.h>
+#include <wx/regex.h>
+
+#include <vector>
+#include <map>
+
+#include <sch_component.h>
+#include <sch_reference_list.h>
+#include <class_netlist_object.h>
+#include <template_fieldnames.h>
+
+#include "bom_table_column.h"
+
+// Forward-declare classes
+class BOM_TABLE_ROW;        // Base-class for table row data model
+class BOM_TABLE_GROUP;      // Class for displaying a group of components
+class BOM_TABLE_COMPONENT;  // Class for displaying a single component
+
+/**
+ * Virtual base class determining how a row is displayed
+ * There are three types of rows:
+ * GROUP - Displays a group of (one or more) components
+ * COMPONENT - Displays a single component
+ * UNIT - Child of COMPONENT for multi-unit components
+ */
+class BOM_TABLE_ROW
+{
+public:
+    BOM_TABLE_ROW();
+    virtual ~BOM_TABLE_ROW() {}
+
+    /// Set display properties for a cell
+    virtual bool GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const;
+
+    /// Get the row value associated with provided field ID
+    virtual wxString GetFieldValue( unsigned int aFieldId ) const = 0;
+
+    /// Set the field value associated with the provided field ID
+    virtual bool SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite = false ) = 0;
+
+    /// Return parent item
+    virtual BOM_TABLE_ROW* GetParent() const { return nullptr; }
+
+    /// Test if row has any child rows
+    virtual bool HasChildren() const { return false; }
+
+    /// Return any child rows
+    virtual unsigned int GetChildren( wxDataViewItemArray& aChildren ) const { return 0; }
+
+    /// Determine if a value has changed
+    virtual bool HasValueChanged( BOM_COLUMN* aField ) const { return false; }
+
+    /// Determine if any values have changed
+    bool HasChanged() const;
+
+protected:
+
+    /// Pointer to list of columns
+    BOM_COLUMN_LIST* m_columnList;
+};
+
+/**
+ * BOM_TABLE_GROUP class displays a group of similar components
+ * If the group contains more than one component,
+ * they are each displayed as child items of the group
+ */
+class BOM_TABLE_GROUP : public BOM_TABLE_ROW
+{
+public:
+    // List of components stored in this group
+    std::vector<BOM_TABLE_COMPONENT*> Components;
+
+    BOM_TABLE_GROUP( BOM_COLUMN_LIST* aColumnList );
+    virtual ~BOM_TABLE_GROUP() {}
+
+    // Set display properties for
+    virtual bool GetAttr( unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const override;
+
+    // Get group row value
+    virtual wxString GetFieldValue( unsigned int aFieldId ) const override;
+
+    // Set group row value
+    virtual bool SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite = false ) override;
+
+    // Attempt to add a new component to the group
+    bool AddComponent( BOM_TABLE_COMPONENT* aComponent );
+
+    // Test if this group should display children
+    virtual bool HasChildren() const override { return Components.size() > 1; }
+
+    // Return a list of children items of this group
+    virtual unsigned int GetChildren( wxDataViewItemArray& aChildren ) const override;
+
+    // Test if any children have changed
+    virtual bool HasValueChanged( BOM_COLUMN* aField ) const override;
+
+    // Return the number of child items in this group
+    unsigned int GroupSize( void ) const { return Components.size(); }
+
+    // Return a sorted, concatenated list of references
+    wxArrayString GetReferences( bool aSort = true ) const;
+
+    // Function for sorting two reference strings
+    static int SortReferences( const wxString& aFirst, const wxString& aSecond );
+
+    // Function for sorting two value strings
+    static int SortValues( const wxString& aFirst, const wxString& aSecond );
+
+protected:
+    // Test if a particular field matches against another component
+    bool TestField( BOM_COLUMN* aField, BOM_TABLE_COMPONENT* aComponent ) const;
+};
+
+class BOM_TABLE_COMPONENT : public BOM_TABLE_ROW
+{
+public:
+    // List of units associated with this component
+    std::vector<SCH_REFERENCE> Units;
+
+    BOM_TABLE_COMPONENT( BOM_TABLE_GROUP* aParent, BOM_COLUMN_LIST* aColumnList );
+
+    bool AddUnit( SCH_REFERENCE aUnit );
+
+    virtual wxString GetFieldValue( unsigned int aFieldId ) const override;
+
+    virtual bool SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite = false ) override;
+
+    virtual bool HasValueChanged( BOM_COLUMN* aField ) const override;
+
+    // Return the reference of the first unit (all units must be the same
+    wxString GetReference() const;
+
+    wxString GetPrefix() const;
+
+    void ApplyFieldChanges();
+
+    void RevertFieldChanges();
+
+    void SetParent( BOM_TABLE_GROUP* aParent ) { m_parent = aParent; }
+
+    virtual BOM_TABLE_ROW* GetParent() const override { return m_parent; }
+
+protected:
+    // Initial data for reverting component values
+    std::map<unsigned int, wxString> m_fallbackData;
+
+    // Data as it is updated
+    std::map<unsigned int, wxString> m_fieldData;
+
+    BOM_TABLE_GROUP* m_parent;
+};
+
+/**
+ * BOM_TABLE_MODEL class
+ *
+ * Contains complete BOM information:
+ * a) List of columns (fields) to display
+ * b) List of groups of consolidated components
+ */
+class BOM_TABLE_MODEL : public wxDataViewModel
+{
+protected:
+    BOM_TABLE_MODEL();
+
+    std::vector<std::unique_ptr<BOM_TABLE_COMPONENT>> m_components;
+
+    // BOM Preferences
+    //! Group components based on values
+    bool m_groupColumns = true;
+    //! Filter components
+    bool m_filterColumns = false;
+    //! Allow blank fields to be merged with otherwise matching groups
+    bool m_mergeBlankFields = false;
+
+    wxDataViewCtrl* m_widget;
+
+    //! ID of column to sort by
+    unsigned int m_sortingColumn;
+    bool m_sortingOrder;
+
+    void AddDefaultColumns();
+    void ClearColumns();
+
+    virtual bool            HasContainerColumns( const wxDataViewItem& aItem ) const override { return true; }
+
+    virtual bool            IsContainer( const wxDataViewItem& aItem ) const override;
+
+    virtual wxDataViewItem  GetParent( const wxDataViewItem& aItem ) const override;
+
+    virtual unsigned int    GetChildren( const wxDataViewItem& aItem, wxDataViewItemArray& aChildren ) const override;
+
+    virtual unsigned int    GetColumnCount() const override { return ColumnList.ColumnCount( false ); }
+
+    virtual wxString        GetColumnType( unsigned int aFieldId ) const override { return wxString( "string" ); }
+
+    virtual void            GetValue( wxVariant& aVariant, const wxDataViewItem& aItem, unsigned int aFieldId ) const override;
+
+    virtual bool            SetValue( const wxVariant& aVariant, const wxDataViewItem& item, unsigned int aFieldId ) override;
+
+public:
+
+    virtual ~BOM_TABLE_MODEL();
+
+    BOM_COLUMN_LIST ColumnList;
+
+    /// List of component groups
+    std::vector<std::unique_ptr<BOM_TABLE_GROUP>> Groups;
+
+    typedef wxObjectDataPtr<BOM_TABLE_MODEL> MODEL_PTR;
+
+    static MODEL_PTR Create();
+
+    void AttachTo( wxDataViewCtrl* aView );
+
+    wxDataViewColumn* AddColumn( BOM_COLUMN* aColumn, int aPosition = -1 );
+    bool RemoveColumn( BOM_COLUMN* aColumn );
+
+    // wxDataViewModel functions
+    virtual bool            GetAttr( const wxDataViewItem& aItem, unsigned int aFieldId, wxDataViewItemAttr& aAttr ) const override;
+    virtual bool            HasDefaultCompare() const override { return false; }
+    virtual int             Compare( const wxDataViewItem& aItem1,
+                                     const wxDataViewItem& aItem2,
+                                     unsigned int aColumnId,
+                                     bool aAscending ) const override;
+
+    void                    ReloadTable();
+
+    unsigned int ColumnCount() const { return ColumnList.ColumnCount(); }
+    unsigned int GroupCount() const { return (unsigned int) Groups.size(); }
+    unsigned int ComponentCount() const;
+
+    void SetColumnGrouping( const bool aGroup = true ) { m_groupColumns = aGroup; }
+    bool GetColumnGrouping() const { return m_groupColumns; }
+
+    void SetColumnFiltering( const bool aFilter = true ) { m_filterColumns = aFilter; }
+    bool GetColumnFiltering() const { return m_filterColumns; }
+
+    void SetBlankMerging( const bool aMerge = true ) { m_mergeBlankFields = aMerge; }
+    bool GetBlankMerging() const { return m_mergeBlankFields; }
+
+    wxArrayString GetRowData( unsigned int aRow, std::vector<BOM_COLUMN*> aColumns ) const;
+
+    void SetComponents( SCH_REFERENCE_LIST aRefs );
+    void AddComponentFields( SCH_COMPONENT* aCmp );
+
+    void RevertFieldChanges();
+    void ApplyFieldChanges();
+
+    bool HaveFieldsChanged() const;
+
+    std::vector<SCH_COMPONENT*> GetChangedComponents();
+    unsigned int CountChangedComponents();
+};
+
+#endif // _EESCHEMA_BOM_TABLE_MODEL_H_
diff --git a/eeschema/dialogs/dialog_bom_editor.cpp b/eeschema/dialogs/dialog_bom_editor.cpp
new file mode 100644
index 0000000..a835b03
--- /dev/null
+++ b/eeschema/dialogs/dialog_bom_editor.cpp
@@ -0,0 +1,439 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 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 <wx/colour.h>
+#include <wx/msgdlg.h>
+#include <wx/progdlg.h>
+#include <wx/file.h>
+#include <wx/filename.h>
+
+#include <confirm.h>
+
+#include <build_version.h>
+#include <general.h>
+#include <class_library.h>
+
+#include <bom_exporter.h>
+
+#include "dialog_bom_editor.h"
+#include <bom_table_model.h>
+
+/* BOM Table Colours */
+
+// Create and show BOM editor
+int InvokeDialogCreateBOMEditor( SCH_EDIT_FRAME* aCaller )
+{
+    DIALOG_BOM_EDITOR dlg( aCaller );
+    return dlg.ShowModal();
+}
+
+DIALOG_BOM_EDITOR::DIALOG_BOM_EDITOR( SCH_EDIT_FRAME* parent ) :
+        DIALOG_BOM_EDITOR_BASE( parent ),
+        m_parent( parent )
+{
+    m_bom = BOM_TABLE_MODEL::Create();
+
+    m_columnListCtrl->DeleteAllItems();
+    m_columnListCtrl->ClearColumns();
+
+    auto nameColumn = m_columnListCtrl->AppendTextColumn( _( "Field" ) );
+
+    auto showColumn = m_columnListCtrl->AppendToggleColumn(
+                                        _( "Show" ),
+                                        wxDATAVIEW_CELL_ACTIVATABLE,
+                                        100 );
+
+    // Resize the columns appropriately
+    m_columnListCtrl->Update();
+
+    showColumn->SetWidth( wxCOL_WIDTH_AUTOSIZE );
+    showColumn->SetMinWidth( showColumn->GetWidth() );
+    showColumn->SetResizeable( false );
+
+    m_columnListCtrl->Update();
+
+    nameColumn->SetWidth( wxCOL_WIDTH_AUTOSIZE );
+    nameColumn->SetResizeable( true );
+
+    // Read all components
+    LoadComponents();
+
+    LoadColumnNames();
+    ReloadColumns();
+
+    m_bom->ReloadTable();
+
+    UpdateTitle();
+}
+
+DIALOG_BOM_EDITOR::~DIALOG_BOM_EDITOR()
+{
+    //TODO
+}
+
+/**
+ * When the component table dialog is closed,
+ * work out if we need to save any changed.
+ * If so, capture those changes and push them to the undo stack.
+ */
+void DIALOG_BOM_EDITOR::OnBomEditorClosed( wxCloseEvent& event )
+{
+    bool saveChanges = false;
+
+    // If there are changed values, warn the user first
+    if( m_bom->HaveFieldsChanged() )
+    {
+        int result = DisplayExitDialog( this, _( "Changes exist in component table" ) );
+
+        switch( result )
+        {
+        // Save and exit
+        case wxID_YES:
+            saveChanges = true;
+            break;
+        // Cancel (do not exit)
+        case wxID_CANCEL:
+            event.Veto();
+            return;
+        // Do not save, exit
+        default:
+            break;
+        }
+    }
+
+    if( saveChanges )
+    {
+        /** Create a list of picked items for undo
+         * PICKED_ITEMS_LIST contains multiple ITEM_PICKER instances
+         * Each ITEM_PICKER contains a component and a command
+         */
+
+        auto pickerList = PICKED_ITEMS_LIST();
+
+        // List of components that have changed
+        auto changed = m_bom->GetChangedComponents();
+
+        ITEM_PICKER picker;
+
+        for( auto cmp : changed )
+        {
+            // Push the component into the picker list
+            picker = ITEM_PICKER( cmp, UR_CHANGED );
+            picker.SetFlags( cmp->GetFlags() );
+            //picker.SetLink( DuplicateStruct( cmp, true ) );
+
+            pickerList.PushItem( picker );
+        }
+
+        if( pickerList.GetCount() > 0 )
+        {
+            m_parent->SaveCopyInUndoList( pickerList, UR_CHANGED );
+            m_bom->ApplyFieldChanges();
+            m_parent->Refresh();
+        }
+    }
+
+    Destroy();
+}
+
+/**
+ * Update the window title to reflect the contents of the table
+ */
+void DIALOG_BOM_EDITOR::UpdateTitle()
+{
+    wxString title = _( "Component table" ) + wxString( " - " );
+
+    title += wxString::Format( "%u %s",
+                              m_bom->ComponentCount(),
+                              _( "components" ) );
+
+    if( m_bom->GetColumnGrouping() )
+    {
+        title += wxString::Format( " %s %u %s",
+                              _( "in" ),
+                              m_bom->Groups.size(),
+                              _( "groups" ) );
+    }
+
+    unsigned int count = m_bom->CountChangedComponents();
+
+    if( count > 0 )
+    {
+        title += wxString::Format( " - %u %s",
+                                   count,
+                                   _( "changed" ) );
+    }
+
+    SetTitle( title );
+}
+
+/**
+ * Load component data from the entire schematic set
+ */
+void DIALOG_BOM_EDITOR::LoadComponents()
+{
+    if( !m_parent ) return;
+
+    // List of component objects
+    SCH_REFERENCE_LIST refs;
+
+    // Generate a list of schematic sheets
+    SCH_SHEET_LIST sheets( g_RootSheet );
+    sheets.GetComponents( m_parent->Prj().SchLibs(), refs, false );
+
+    // Pass the references through to the model
+    m_bom->SetComponents( refs );
+}
+
+/**
+ * Display list of columns (fields)
+ */
+void DIALOG_BOM_EDITOR::LoadColumnNames()
+{
+    m_columnListCtrl->DeleteAllItems();
+
+    wxVector< wxVariant > data;
+
+    for( auto* col : m_bom->ColumnList.Columns )
+    {
+        if( nullptr == col )
+            continue;
+
+        data.clear();
+
+        data.push_back( wxVariant( col->Title() ) );        // Column title      (string)
+        data.push_back( wxVariant( col->IsVisible() ) );    // Column visibility (bool)
+
+        m_columnListCtrl->AppendItem( data );
+    }
+}
+
+void DIALOG_BOM_EDITOR::ReloadColumns()
+{
+    m_bom->AttachTo( m_bomView );
+
+    UpdateTitle();
+}
+
+void DIALOG_BOM_EDITOR::OnColumnItemToggled( wxDataViewEvent& event )
+{
+    wxDataViewItem item = event.GetItem();
+
+    int row = m_columnListCtrl->ItemToRow( item );
+
+    int col = event.GetColumn();
+
+    if( row == wxNOT_FOUND || row < 0 || row >= (int) m_bom->ColumnCount() ) return;
+
+    BOM_COLUMN* bomColumn = m_bom->ColumnList.GetColumnByIndex( row );
+
+    if( nullptr == bomColumn ) return;
+
+    bool bValue = m_columnListCtrl->GetToggleValue( row, col );
+
+    switch ( col )
+    {
+    default:
+        break;
+    case 1: // Column visibility
+        bomColumn->SetVisible( bValue );
+
+        // Insert a new column
+        if( bValue )
+        {
+            m_bom->AddColumn( bomColumn );
+        }
+        else
+        {
+            m_bom->RemoveColumn( bomColumn );
+        }
+        break;
+    }
+}
+
+/**
+ * Called when the "Group Components" toggle is pressed
+ */
+void DIALOG_BOM_EDITOR::OnGroupComponentsToggled( wxCommandEvent& event )
+{
+    bool group = m_groupComponentsBox->GetValue();
+
+    m_bom->SetColumnGrouping( group );
+    m_bom->ReloadTable();
+
+    m_regroupComponentsButton->Enable( group );
+
+    UpdateTitle();
+}
+
+/**
+ * Called when the "Export BOM" button is pressed
+ * Extract row data from the component table,
+ * and export it to a BOM file
+ */
+void DIALOG_BOM_EDITOR::OnExportBOM( wxCommandEvent& event )
+{
+    // Allowable BOM file formats
+    static const wxString wildcard = _( "BOM Files" ) + wxString( " *.csv, *.tsv, *.html)|*.csv;*.tsv;*.htm;*.html" );
+
+    wxFileDialog bomFileDialog(this, _("Select BOM file"),
+                Prj().GetProjectPath(),
+                wxEmptyString,
+                wildcard,
+                wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
+
+
+    if( bomFileDialog.ShowModal() == wxID_CANCEL )
+    {
+        return;
+    }
+
+    // Ensure the component groups are correct
+    m_bom->ReloadTable();
+
+    wxString msg;
+
+    wxFileName filename = bomFileDialog.GetPath();
+
+    // Ensure correct file format
+    BOM_FILE_WRITER* writer;
+
+    wxString fn = filename.GetFullPath().Lower();
+
+    // CSV File
+    if( fn.EndsWith( ".csv" ) )
+    {
+        writer = new BOM_CSV_WRITER();
+    }
+    // TSV file
+    else if( fn.EndsWith( ".tsv" ) )
+    {
+        writer = new BOM_CSV_WRITER( '\t' );
+    }
+    // HTML file
+    else if( fn.EndsWith( ".html" ) || fn.EndsWith( ".htm" ) )
+    {
+        writer = new BOM_HTML_WRITER();
+    }
+    // Unknown file!
+    else
+    {
+        msg.Printf("%s:\n%s",
+                   _( "Unsupported file type" ),
+                   filename.GetExt() );
+
+        wxMessageBox( msg );
+        return;
+    }
+
+    // Set export preferences
+    writer->IncludeExtraData( m_includeProjectData->GetValue() );
+    writer->ShowRowNumbers( m_showRowNumbers->GetValue() );
+
+    // Project information
+    writer->SetKicadVersion( GetBuildVersion() );
+
+    // Extract sheet info from top-level sheet
+    if( g_RootSheet )
+    {
+        const TITLE_BLOCK& tb = g_RootSheet->GetScreen()->GetTitleBlock();
+
+        writer->SetSchematicDate( tb.GetDate() );
+        writer->SetSchematicVersion( tb.GetRevision() );
+        writer->SetSchematicTitle( tb.GetTitle() );
+    }
+
+    std::vector<BOM_COLUMN*> columns;
+    wxArrayString headings;
+
+    // Extract the visible column data
+    for( auto column : m_bom->ColumnList.Columns )
+    {
+        if( column && column->IsVisible() )
+        {
+            columns.push_back( column );
+            headings.push_back( column->Title() );
+        }
+    }
+
+    writer->SetHeader( headings );
+
+    // Extract the row data
+    for( unsigned int row=0; row<m_bom->GroupCount(); row++ )
+    {
+        writer->AddLine( m_bom->GetRowData( row, columns ) );
+    }
+
+    writer->SetGroupCount( m_bom->GroupCount() );
+    writer->SetComponentCount( m_bom->ComponentCount() );
+
+    // Open the BOM file for writing
+    wxFile bomFile( filename.GetFullPath(), wxFile::write );
+
+    if( bomFile.IsOpened() )
+    {
+        if( !writer->WriteToFile( bomFile ) )
+        {
+            msg.Printf( "%s:\n%s",
+                        _( "Error writing BOM file" ),
+                        filename.GetFullPath() );
+        }
+
+        bomFile.Close();
+    }
+    else
+    {
+        msg.Printf( "%s:\n%s",
+                    _( "Error opening BOM file" ),
+                    filename.GetFullPath() );
+
+        wxMessageBox( msg );
+    }
+}
+
+void DIALOG_BOM_EDITOR::OnTableValueChanged( wxDataViewEvent& event )
+{
+    m_reloadTableButton->Enable( m_bom->HaveFieldsChanged() );
+
+    UpdateTitle();
+}
+
+void DIALOG_BOM_EDITOR::OnRegroupComponents( wxCommandEvent& event )
+{
+    m_bom->ReloadTable();
+}
+
+void DIALOG_BOM_EDITOR::OnRevertFieldChanges( wxCommandEvent& event )
+{
+    if( m_bom->HaveFieldsChanged() )
+    {
+        if( IsOK( this, _( "Revert all component table changes?" ) ) )
+        {
+            m_bom->RevertFieldChanges();
+            m_reloadTableButton->Enable( m_bom->HaveFieldsChanged() );
+            UpdateTitle();
+        }
+    }
+}
diff --git a/eeschema/dialogs/dialog_bom_editor.h b/eeschema/dialogs/dialog_bom_editor.h
new file mode 100644
index 0000000..9269134
--- /dev/null
+++ b/eeschema/dialogs/dialog_bom_editor.h
@@ -0,0 +1,83 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2017 Oliver Walters
+ * Copyright (C) 2017 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
+ */
+
+/**
+ * @file eeschema/dialogs/dialog_bom.cpp
+ * @brief Dialog box for creating bom and other documents from generic netlist.
+ */
+
+#ifndef EESCHEMA_DIALOGS_DIALOG_BOM_EDITOR_H_
+#define EESCHEMA_DIALOGS_DIALOG_BOM_EDITOR_H_
+
+#include <wx/dataview.h>
+
+#include <schframe.h>
+#include <sch_sheet.h>
+#include <sch_sheet_path.h>
+#include <sch_component.h>
+#include <invoke_sch_dialog.h>
+#include <dialog_bom_editor_base.h>
+#include <class_netlist_object.h>
+#include <sch_reference_list.h>
+#include <vector>
+
+#include <bom_table_model.h>
+
+class DIALOG_BOM_EDITOR : public DIALOG_BOM_EDITOR_BASE
+{
+
+public:
+    DIALOG_BOM_EDITOR( SCH_EDIT_FRAME* parent );
+    virtual ~DIALOG_BOM_EDITOR();
+
+private:
+    //! Parent object (Schematic)
+    SCH_EDIT_FRAME* m_parent;
+
+    BOM_TABLE_MODEL::MODEL_PTR m_bom;
+
+    void LoadComponents( void );
+
+    void LoadColumnNames( void );
+    void ReloadColumns( void );
+
+    // Checkbox event callbacks
+    virtual void OnColumnItemToggled( wxDataViewEvent& event ) override;
+    virtual void OnGroupComponentsToggled( wxCommandEvent& event ) override;
+
+    virtual void OnExportBOM( wxCommandEvent& event ) override;
+
+    virtual void OnRevertFieldChanges( wxCommandEvent& event ) override;
+
+    virtual void OnRegroupComponents( wxCommandEvent& event ) override;
+
+    // Called after a value in the table has changed
+    virtual void OnTableValueChanged( wxDataViewEvent& event ) override;
+
+    virtual void OnBomEditorClosed( wxCloseEvent& event ) override;
+
+    void UpdateTitle( void );
+};
+
+#endif /* EESCHEMA_DIALOGS_DIALOG_BOM_EDITOR_H_ */
diff --git a/eeschema/dialogs/dialog_bom_editor_base.cpp b/eeschema/dialogs/dialog_bom_editor_base.cpp
new file mode 100644
index 0000000..d5e07a4
--- /dev/null
+++ b/eeschema/dialogs/dialog_bom_editor_base.cpp
@@ -0,0 +1,150 @@
+///////////////////////////////////////////////////////////////////////////
+// C++ code generated with wxFormBuilder (version Apr  1 2017)
+// http://www.wxformbuilder.org/
+//
+// PLEASE DO "NOT" EDIT THIS FILE!
+///////////////////////////////////////////////////////////////////////////
+
+#include "dialog_bom_editor_base.h"
+
+///////////////////////////////////////////////////////////////////////////
+
+BEGIN_EVENT_TABLE( DIALOG_BOM_EDITOR_BASE, DIALOG_SHIM )
+	EVT_CLOSE( DIALOG_BOM_EDITOR_BASE::_wxFB_OnBomEditorClosed )
+	EVT_CHECKBOX( OPT_GROUP_COMPONENTS, DIALOG_BOM_EDITOR_BASE::_wxFB_OnGroupComponentsToggled )
+	EVT_BUTTON( ID_BUTTON_REGROUP, DIALOG_BOM_EDITOR_BASE::_wxFB_OnRegroupComponents )
+	EVT_BUTTON( ID_BUTTON_REVERT_CHANGES, DIALOG_BOM_EDITOR_BASE::_wxFB_OnRevertFieldChanges )
+	EVT_DATAVIEW_ITEM_VALUE_CHANGED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnColumnItemToggled )
+	EVT_BUTTON( wxID_BOM_BUTTON_EXPORT, DIALOG_BOM_EDITOR_BASE::_wxFB_OnExportBOM )
+	EVT_DATAVIEW_COLUMN_REORDERED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnBomColumReordered )
+	EVT_DATAVIEW_COLUMN_SORTED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnBomColumnSorted )
+	EVT_DATAVIEW_ITEM_EDITING_DONE( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnTableValueChanged )
+	EVT_DATAVIEW_SELECTION_CHANGED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnSelectionChanged )
+END_EVENT_TABLE()
+
+DIALOG_BOM_EDITOR_BASE::DIALOG_BOM_EDITOR_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 );
+	
+	wxBoxSizer* bHorizontalSizer;
+	bHorizontalSizer = new wxBoxSizer( wxVERTICAL );
+	
+	m_panel = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	wxBoxSizer* bSizer7;
+	bSizer7 = new wxBoxSizer( wxVERTICAL );
+	
+	m_splitter1 = new wxSplitterWindow( m_panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSP_3D );
+	m_splitter1->Connect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_BOM_EDITOR_BASE::m_splitter1OnIdle ), NULL, this );
+	
+	m_leftPanel = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	wxBoxSizer* bSizer6;
+	bSizer6 = new wxBoxSizer( wxVERTICAL );
+	
+	wxStaticBoxSizer* sbSizer1;
+	sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Options") ), wxVERTICAL );
+	
+	m_groupComponentsBox = new wxCheckBox( sbSizer1->GetStaticBox(), OPT_GROUP_COMPONENTS, _("Group components"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_groupComponentsBox->SetValue(true); 
+	m_groupComponentsBox->SetToolTip( _("Group components together based on common properties") );
+	
+	sbSizer1->Add( m_groupComponentsBox, 0, wxALL|wxEXPAND, 5 );
+	
+	m_regroupComponentsButton = new wxButton( sbSizer1->GetStaticBox(), ID_BUTTON_REGROUP, _("Regroup components"), wxDefaultPosition, wxDefaultSize, 0 );
+	sbSizer1->Add( m_regroupComponentsButton, 0, wxALL|wxEXPAND, 5 );
+	
+	m_reloadTableButton = new wxButton( sbSizer1->GetStaticBox(), ID_BUTTON_REVERT_CHANGES, _("Revert all changes"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_reloadTableButton->Enable( false );
+	m_reloadTableButton->SetToolTip( _("Reload table (reverts component field changes)") );
+	
+	sbSizer1->Add( m_reloadTableButton, 0, wxALL|wxEXPAND, 5 );
+	
+	
+	bSizer6->Add( sbSizer1, 0, wxEXPAND, 5 );
+	
+	wxBoxSizer* bSizer9;
+	bSizer9 = new wxBoxSizer( wxVERTICAL );
+	
+	wxStaticBoxSizer* m_fieldListSizer;
+	m_fieldListSizer = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Fields") ), wxVERTICAL );
+	
+	m_columnListCtrl = new wxDataViewListCtrl( m_fieldListSizer->GetStaticBox(), wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
+	m_fieldListSizer->Add( m_columnListCtrl, 1, wxALL|wxEXPAND, 5 );
+	
+	
+	bSizer9->Add( m_fieldListSizer, 1, wxEXPAND, 5 );
+	
+	
+	bSizer6->Add( bSizer9, 5, wxEXPAND, 5 );
+	
+	
+	bSizer6->Add( 0, 0, 0, wxEXPAND, 5 );
+	
+	wxStaticBoxSizer* sbSizer2;
+	sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Export options") ), wxVERTICAL );
+	
+	m_includeProjectData = new wxCheckBox( sbSizer2->GetStaticBox(), wxID_BOM_OPT_INC_PRJ_DATA, _("Include project data"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_includeProjectData->SetValue(true); 
+	m_includeProjectData->SetToolTip( _("Include project information in BOM file") );
+	
+	sbSizer2->Add( m_includeProjectData, 0, wxALL|wxEXPAND, 5 );
+	
+	m_showRowNumbers = new wxCheckBox( sbSizer2->GetStaticBox(), wxID_BOM_OPT_SHOW_ROW_NUMS, _("Show row numbers"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_showRowNumbers->SetValue(true); 
+	m_showRowNumbers->SetToolTip( _("Show BOM row numbers ") );
+	
+	sbSizer2->Add( m_showRowNumbers, 0, wxALL|wxEXPAND, 5 );
+	
+	
+	sbSizer2->Add( 0, 0, 1, wxEXPAND, 5 );
+	
+	wxBoxSizer* bSizer13;
+	bSizer13 = new wxBoxSizer( wxHORIZONTAL );
+	
+	
+	bSizer13->Add( 0, 0, 1, wxEXPAND, 5 );
+	
+	m_exportButton = new wxButton( sbSizer2->GetStaticBox(), wxID_BOM_BUTTON_EXPORT, _("Export BOM"), wxDefaultPosition, wxDefaultSize, 0 );
+	bSizer13->Add( m_exportButton, 0, wxALL, 5 );
+	
+	
+	sbSizer2->Add( bSizer13, 0, wxEXPAND, 5 );
+	
+	
+	bSizer6->Add( sbSizer2, 0, wxEXPAND, 5 );
+	
+	
+	m_leftPanel->SetSizer( bSizer6 );
+	m_leftPanel->Layout();
+	bSizer6->Fit( m_leftPanel );
+	m_panel4 = new wxPanel( m_splitter1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
+	wxBoxSizer* bSizer5;
+	bSizer5 = new wxBoxSizer( wxVERTICAL );
+	
+	m_bomView = new wxDataViewCtrl( m_panel4, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES );
+	m_bomView->SetMinSize( wxSize( 250,250 ) );
+	
+	bSizer5->Add( m_bomView, 1, wxALL|wxEXPAND, 5 );
+	
+	
+	m_panel4->SetSizer( bSizer5 );
+	m_panel4->Layout();
+	bSizer5->Fit( m_panel4 );
+	m_splitter1->SplitVertically( m_leftPanel, m_panel4, 231 );
+	bSizer7->Add( m_splitter1, 1, wxEXPAND, 5 );
+	
+	
+	m_panel->SetSizer( bSizer7 );
+	m_panel->Layout();
+	bSizer7->Fit( m_panel );
+	bHorizontalSizer->Add( m_panel, 1, wxEXPAND | wxALL, 5 );
+	
+	
+	this->SetSizer( bHorizontalSizer );
+	this->Layout();
+	
+	this->Centre( wxBOTH );
+}
+
+DIALOG_BOM_EDITOR_BASE::~DIALOG_BOM_EDITOR_BASE()
+{
+}
diff --git a/eeschema/dialogs/dialog_bom_editor_base.fbp b/eeschema/dialogs/dialog_bom_editor_base.fbp
new file mode 100644
index 0000000..9d1cf28
--- /dev/null
+++ b/eeschema/dialogs/dialog_bom_editor_base.fbp
@@ -0,0 +1,1202 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<wxFormBuilder_Project>
+    <FileVersion major="1" minor="13" />
+    <object class="Project" expanded="1">
+        <property name="class_decoration"></property>
+        <property name="code_generation">C++</property>
+        <property name="disconnect_events">1</property>
+        <property name="disconnect_mode">source_name</property>
+        <property name="disconnect_php_events">0</property>
+        <property name="disconnect_python_events">0</property>
+        <property name="embedded_files_path">res</property>
+        <property name="encoding">UTF-8</property>
+        <property name="event_generation">table</property>
+        <property name="file">dialog_bom_editor_base</property>
+        <property name="first_id">1000</property>
+        <property name="help_provider">none</property>
+        <property name="internationalize">1</property>
+        <property name="name">dialog_bom_editor_base</property>
+        <property name="namespace"></property>
+        <property name="path">.</property>
+        <property name="precompiled_header"></property>
+        <property name="relative_path">1</property>
+        <property name="skip_lua_events">1</property>
+        <property name="skip_php_events">1</property>
+        <property name="skip_python_events">1</property>
+        <property name="ui_table">UI</property>
+        <property name="use_enum">0</property>
+        <property name="use_microsoft_bom">0</property>
+        <object class="Dialog" expanded="1">
+            <property name="aui_managed">0</property>
+            <property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
+            <property name="bg"></property>
+            <property name="center">wxBOTH</property>
+            <property name="context_help"></property>
+            <property name="context_menu">1</property>
+            <property name="enabled">1</property>
+            <property name="event_handler">impl_virtual</property>
+            <property name="extra_style"></property>
+            <property name="fg"></property>
+            <property name="font"></property>
+            <property name="hidden">0</property>
+            <property name="id">wxID_ANY</property>
+            <property name="maximum_size"></property>
+            <property name="minimum_size"></property>
+            <property name="name">DIALOG_BOM_EDITOR_BASE</property>
+            <property name="pos"></property>
+            <property name="size">1047,649</property>
+            <property name="style">wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER</property>
+            <property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
+            <property name="title">BOM editor</property>
+            <property name="tooltip"></property>
+            <property name="window_extra_style"></property>
+            <property name="window_name"></property>
+            <property name="window_style"></property>
+            <event name="OnActivate"></event>
+            <event name="OnActivateApp"></event>
+            <event name="OnAuiFindManager"></event>
+            <event name="OnAuiPaneButton"></event>
+            <event name="OnAuiPaneClose"></event>
+            <event name="OnAuiPaneMaximize"></event>
+            <event name="OnAuiPaneRestore"></event>
+            <event name="OnAuiRender"></event>
+            <event name="OnChar"></event>
+            <event name="OnClose">OnBomEditorClosed</event>
+            <event name="OnEnterWindow"></event>
+            <event name="OnEraseBackground"></event>
+            <event name="OnHibernate"></event>
+            <event name="OnIconize"></event>
+            <event name="OnIdle"></event>
+            <event name="OnInitDialog"></event>
+            <event name="OnKeyDown"></event>
+            <event name="OnKeyUp"></event>
+            <event name="OnKillFocus"></event>
+            <event name="OnLeaveWindow"></event>
+            <event name="OnLeftDClick"></event>
+            <event name="OnLeftDown"></event>
+            <event name="OnLeftUp"></event>
+            <event name="OnMiddleDClick"></event>
+            <event name="OnMiddleDown"></event>
+            <event name="OnMiddleUp"></event>
+            <event name="OnMotion"></event>
+            <event name="OnMouseEvents"></event>
+            <event name="OnMouseWheel"></event>
+            <event name="OnPaint"></event>
+            <event name="OnRightDClick"></event>
+            <event name="OnRightDown"></event>
+            <event name="OnRightUp"></event>
+            <event name="OnSetFocus"></event>
+            <event name="OnSize"></event>
+            <event name="OnUpdateUI"></event>
+            <object class="wxBoxSizer" expanded="1">
+                <property name="minimum_size"></property>
+                <property name="name">bHorizontalSizer</property>
+                <property name="orient">wxVERTICAL</property>
+                <property name="permission">none</property>
+                <object class="sizeritem" expanded="1">
+                    <property name="border">5</property>
+                    <property name="flag">wxEXPAND | wxALL</property>
+                    <property name="proportion">1</property>
+                    <object class="wxPanel" 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="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_panel</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="subclass"></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">wxTAB_TRAVERSAL</property>
+                        <event name="OnChar"></event>
+                        <event name="OnEnterWindow"></event>
+                        <event name="OnEraseBackground"></event>
+                        <event name="OnKeyDown"></event>
+                        <event name="OnKeyUp"></event>
+                        <event name="OnKillFocus"></event>
+                        <event name="OnLeaveWindow"></event>
+                        <event name="OnLeftDClick"></event>
+                        <event name="OnLeftDown"></event>
+                        <event name="OnLeftUp"></event>
+                        <event name="OnMiddleDClick"></event>
+                        <event name="OnMiddleDown"></event>
+                        <event name="OnMiddleUp"></event>
+                        <event name="OnMotion"></event>
+                        <event name="OnMouseEvents"></event>
+                        <event name="OnMouseWheel"></event>
+                        <event name="OnPaint"></event>
+                        <event name="OnRightDClick"></event>
+                        <event name="OnRightDown"></event>
+                        <event name="OnRightUp"></event>
+                        <event name="OnSetFocus"></event>
+                        <event name="OnSize"></event>
+                        <event name="OnUpdateUI"></event>
+                        <object class="wxBoxSizer" expanded="1">
+                            <property name="minimum_size"></property>
+                            <property name="name">bSizer7</property>
+                            <property name="orient">wxVERTICAL</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="wxSplitterWindow" 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="max_size"></property>
+                                    <property name="maximize_button">0</property>
+                                    <property name="maximum_size"></property>
+                                    <property name="min_pane_size">0</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_splitter1</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="sashgravity">0.0</property>
+                                    <property name="sashpos">231</property>
+                                    <property name="sashsize">-1</property>
+                                    <property name="show">1</property>
+                                    <property name="size"></property>
+                                    <property name="splitmode">wxSPLIT_VERTICAL</property>
+                                    <property name="style">wxSP_3D</property>
+                                    <property name="subclass"></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>
+                                    <event name="OnChar"></event>
+                                    <event name="OnEnterWindow"></event>
+                                    <event name="OnEraseBackground"></event>
+                                    <event name="OnKeyDown"></event>
+                                    <event name="OnKeyUp"></event>
+                                    <event name="OnKillFocus"></event>
+                                    <event name="OnLeaveWindow"></event>
+                                    <event name="OnLeftDClick"></event>
+                                    <event name="OnLeftDown"></event>
+                                    <event name="OnLeftUp"></event>
+                                    <event name="OnMiddleDClick"></event>
+                                    <event name="OnMiddleDown"></event>
+                                    <event name="OnMiddleUp"></event>
+                                    <event name="OnMotion"></event>
+                                    <event name="OnMouseEvents"></event>
+                                    <event name="OnMouseWheel"></event>
+                                    <event name="OnPaint"></event>
+                                    <event name="OnRightDClick"></event>
+                                    <event name="OnRightDown"></event>
+                                    <event name="OnRightUp"></event>
+                                    <event name="OnSetFocus"></event>
+                                    <event name="OnSize"></event>
+                                    <event name="OnSplitterDClick"></event>
+                                    <event name="OnSplitterSashPosChanged"></event>
+                                    <event name="OnSplitterSashPosChanging"></event>
+                                    <event name="OnSplitterUnsplit"></event>
+                                    <event name="OnUpdateUI"></event>
+                                    <object class="splitteritem" expanded="1">
+                                        <object class="wxPanel" 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="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_leftPanel</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="subclass"></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">wxTAB_TRAVERSAL</property>
+                                            <event name="OnChar"></event>
+                                            <event name="OnEnterWindow"></event>
+                                            <event name="OnEraseBackground"></event>
+                                            <event name="OnKeyDown"></event>
+                                            <event name="OnKeyUp"></event>
+                                            <event name="OnKillFocus"></event>
+                                            <event name="OnLeaveWindow"></event>
+                                            <event name="OnLeftDClick"></event>
+                                            <event name="OnLeftDown"></event>
+                                            <event name="OnLeftUp"></event>
+                                            <event name="OnMiddleDClick"></event>
+                                            <event name="OnMiddleDown"></event>
+                                            <event name="OnMiddleUp"></event>
+                                            <event name="OnMotion"></event>
+                                            <event name="OnMouseEvents"></event>
+                                            <event name="OnMouseWheel"></event>
+                                            <event name="OnPaint"></event>
+                                            <event name="OnRightDClick"></event>
+                                            <event name="OnRightDown"></event>
+                                            <event name="OnRightUp"></event>
+                                            <event name="OnSetFocus"></event>
+                                            <event name="OnSize"></event>
+                                            <event name="OnUpdateUI"></event>
+                                            <object class="wxBoxSizer" expanded="1">
+                                                <property name="minimum_size"></property>
+                                                <property name="name">bSizer6</property>
+                                                <property name="orient">wxVERTICAL</property>
+                                                <property name="permission">none</property>
+                                                <object class="sizeritem" expanded="1">
+                                                    <property name="border">5</property>
+                                                    <property name="flag">wxEXPAND</property>
+                                                    <property name="proportion">0</property>
+                                                    <object class="wxStaticBoxSizer" expanded="1">
+                                                        <property name="id">wxID_ANY</property>
+                                                        <property name="label">Options</property>
+                                                        <property name="minimum_size"></property>
+                                                        <property name="name">sbSizer1</property>
+                                                        <property name="orient">wxVERTICAL</property>
+                                                        <property name="parent">1</property>
+                                                        <property name="permission">none</property>
+                                                        <event name="OnUpdateUI"></event>
+                                                        <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="0">
+                                                                <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="checked">1</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">OPT_GROUP_COMPONENTS</property>
+                                                                <property name="label">Group components</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_groupComponentsBox</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"></property>
+                                                                <property name="toolbar_pane">0</property>
+                                                                <property name="tooltip">Group components together based on common properties</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="OnChar"></event>
+                                                                <event name="OnCheckBox">OnGroupComponentsToggled</event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALL|wxEXPAND</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="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">0</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">ID_BUTTON_REGROUP</property>
+                                                                <property name="label">Regroup components</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_regroupComponentsButton</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"></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">OnRegroupComponents</event>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="0">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxALL|wxEXPAND</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxButton" expanded="0">
+                                                                <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">0</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">0</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">ID_BUTTON_REVERT_CHANGES</property>
+                                                                <property name="label">Revert all changes</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_reloadTableButton</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"></property>
+                                                                <property name="toolbar_pane">0</property>
+                                                                <property name="tooltip">Reload table (reverts component field changes)</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">OnRevertFieldChanges</event>
+                                                                <event name="OnChar"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                    </object>
+                                                </object>
+                                                <object class="sizeritem" expanded="1">
+                                                    <property name="border">5</property>
+                                                    <property name="flag">wxEXPAND</property>
+                                                    <property name="proportion">5</property>
+                                                    <object class="wxBoxSizer" expanded="1">
+                                                        <property name="minimum_size"></property>
+                                                        <property name="name">bSizer9</property>
+                                                        <property name="orient">wxVERTICAL</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="wxStaticBoxSizer" expanded="1">
+                                                                <property name="id">wxID_ANY</property>
+                                                                <property name="label">Fields</property>
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">m_fieldListSizer</property>
+                                                                <property name="orient">wxVERTICAL</property>
+                                                                <property name="parent">1</property>
+                                                                <property name="permission">none</property>
+                                                                <event name="OnUpdateUI"></event>
+                                                                <object class="sizeritem" expanded="0">
+                                                                    <property name="border">5</property>
+                                                                    <property name="flag">wxALL|wxEXPAND</property>
+                                                                    <property name="proportion">1</property>
+                                                                    <object class="wxDataViewListCtrl" expanded="0">
+                                                                        <property name="bg"></property>
+                                                                        <property name="context_help"></property>
+                                                                        <property name="context_menu">1</property>
+                                                                        <property name="enabled">1</property>
+                                                                        <property name="fg"></property>
+                                                                        <property name="font"></property>
+                                                                        <property name="hidden">0</property>
+                                                                        <property name="id">wxID_ANY</property>
+                                                                        <property name="maximum_size"></property>
+                                                                        <property name="minimum_size"></property>
+                                                                        <property name="name">m_columnListCtrl</property>
+                                                                        <property name="permission">protected</property>
+                                                                        <property name="pos"></property>
+                                                                        <property name="size"></property>
+                                                                        <property name="style"></property>
+                                                                        <property name="subclass"></property>
+                                                                        <property name="tooltip"></property>
+                                                                        <property name="window_extra_style"></property>
+                                                                        <property name="window_name"></property>
+                                                                        <property name="window_style"></property>
+                                                                        <event name="OnChar"></event>
+                                                                        <event name="OnDataViewListCtrlColumnHeaderClick"></event>
+                                                                        <event name="OnDataViewListCtrlColumnHeaderRightClick"></event>
+                                                                        <event name="OnDataViewListCtrlColumnReordered"></event>
+                                                                        <event name="OnDataViewListCtrlColumnSorted"></event>
+                                                                        <event name="OnDataViewListCtrlItemActivated"></event>
+                                                                        <event name="OnDataViewListCtrlItemBeginDrag"></event>
+                                                                        <event name="OnDataViewListCtrlItemCollapsed"></event>
+                                                                        <event name="OnDataViewListCtrlItemCollapsing"></event>
+                                                                        <event name="OnDataViewListCtrlItemContextMenu"></event>
+                                                                        <event name="OnDataViewListCtrlItemDrop"></event>
+                                                                        <event name="OnDataViewListCtrlItemDropPossible"></event>
+                                                                        <event name="OnDataViewListCtrlItemEditingDone"></event>
+                                                                        <event name="OnDataViewListCtrlItemEditingStarted"></event>
+                                                                        <event name="OnDataViewListCtrlItemExpanded"></event>
+                                                                        <event name="OnDataViewListCtrlItemExpanding"></event>
+                                                                        <event name="OnDataViewListCtrlItemStartEditing"></event>
+                                                                        <event name="OnDataViewListCtrlItemValueChanged">OnColumnItemToggled</event>
+                                                                        <event name="OnDataViewListCtrlSelectionChanged"></event>
+                                                                        <event name="OnEnterWindow"></event>
+                                                                        <event name="OnEraseBackground"></event>
+                                                                        <event name="OnKeyDown"></event>
+                                                                        <event name="OnKeyUp"></event>
+                                                                        <event name="OnKillFocus"></event>
+                                                                        <event name="OnLeaveWindow"></event>
+                                                                        <event name="OnLeftDClick"></event>
+                                                                        <event name="OnLeftDown"></event>
+                                                                        <event name="OnLeftUp"></event>
+                                                                        <event name="OnMiddleDClick"></event>
+                                                                        <event name="OnMiddleDown"></event>
+                                                                        <event name="OnMiddleUp"></event>
+                                                                        <event name="OnMotion"></event>
+                                                                        <event name="OnMouseEvents"></event>
+                                                                        <event name="OnMouseWheel"></event>
+                                                                        <event name="OnPaint"></event>
+                                                                        <event name="OnRightDClick"></event>
+                                                                        <event name="OnRightDown"></event>
+                                                                        <event name="OnRightUp"></event>
+                                                                        <event name="OnSetFocus"></event>
+                                                                        <event name="OnSize"></event>
+                                                                        <event name="OnUpdateUI"></event>
+                                                                    </object>
+                                                                </object>
+                                                            </object>
+                                                        </object>
+                                                    </object>
+                                                </object>
+                                                <object class="sizeritem" expanded="1">
+                                                    <property name="border">5</property>
+                                                    <property name="flag">wxEXPAND</property>
+                                                    <property name="proportion">0</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">wxEXPAND</property>
+                                                    <property name="proportion">0</property>
+                                                    <object class="wxStaticBoxSizer" expanded="0">
+                                                        <property name="id">wxID_ANY</property>
+                                                        <property name="label">Export options</property>
+                                                        <property name="minimum_size"></property>
+                                                        <property name="name">sbSizer2</property>
+                                                        <property name="orient">wxVERTICAL</property>
+                                                        <property name="parent">1</property>
+                                                        <property name="permission">none</property>
+                                                        <event name="OnUpdateUI"></event>
+                                                        <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="0">
+                                                                <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="checked">1</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_BOM_OPT_INC_PRJ_DATA</property>
+                                                                <property name="label">Include project data</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_includeProjectData</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"></property>
+                                                                <property name="toolbar_pane">0</property>
+                                                                <property name="tooltip">Include project information in BOM file</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="OnChar"></event>
+                                                                <event name="OnCheckBox"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <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="0">
+                                                                <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="checked">1</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_BOM_OPT_SHOW_ROW_NUMS</property>
+                                                                <property name="label">Show row numbers</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_showRowNumbers</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"></property>
+                                                                <property name="toolbar_pane">0</property>
+                                                                <property name="tooltip">Show BOM row numbers </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="OnChar"></event>
+                                                                <event name="OnCheckBox"></event>
+                                                                <event name="OnEnterWindow"></event>
+                                                                <event name="OnEraseBackground"></event>
+                                                                <event name="OnKeyDown"></event>
+                                                                <event name="OnKeyUp"></event>
+                                                                <event name="OnKillFocus"></event>
+                                                                <event name="OnLeaveWindow"></event>
+                                                                <event name="OnLeftDClick"></event>
+                                                                <event name="OnLeftDown"></event>
+                                                                <event name="OnLeftUp"></event>
+                                                                <event name="OnMiddleDClick"></event>
+                                                                <event name="OnMiddleDown"></event>
+                                                                <event name="OnMiddleUp"></event>
+                                                                <event name="OnMotion"></event>
+                                                                <event name="OnMouseEvents"></event>
+                                                                <event name="OnMouseWheel"></event>
+                                                                <event name="OnPaint"></event>
+                                                                <event name="OnRightDClick"></event>
+                                                                <event name="OnRightDown"></event>
+                                                                <event name="OnRightUp"></event>
+                                                                <event name="OnSetFocus"></event>
+                                                                <event name="OnSize"></event>
+                                                                <event name="OnUpdateUI"></event>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="0">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxEXPAND</property>
+                                                            <property name="proportion">1</property>
+                                                            <object class="spacer" expanded="0">
+                                                                <property name="height">0</property>
+                                                                <property name="permission">protected</property>
+                                                                <property name="width">0</property>
+                                                            </object>
+                                                        </object>
+                                                        <object class="sizeritem" expanded="0">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxEXPAND</property>
+                                                            <property name="proportion">0</property>
+                                                            <object class="wxBoxSizer" expanded="0">
+                                                                <property name="minimum_size"></property>
+                                                                <property name="name">bSizer13</property>
+                                                                <property name="orient">wxHORIZONTAL</property>
+                                                                <property name="permission">none</property>
+                                                                <object class="sizeritem" expanded="0">
+                                                                    <property name="border">5</property>
+                                                                    <property name="flag">wxEXPAND</property>
+                                                                    <property name="proportion">1</property>
+                                                                    <object class="spacer" expanded="0">
+                                                                        <property name="height">0</property>
+                                                                        <property name="permission">protected</property>
+                                                                        <property name="width">0</property>
+                                                                    </object>
+                                                                </object>
+                                                                <object class="sizeritem" expanded="0">
+                                                                    <property name="border">5</property>
+                                                                    <property name="flag">wxALL</property>
+                                                                    <property name="proportion">0</property>
+                                                                    <object class="wxButton" expanded="0">
+                                                                        <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">0</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_BOM_BUTTON_EXPORT</property>
+                                                                        <property name="label">Export BOM</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_exportButton</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"></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">OnExportBOM</event>
+                                                                        <event name="OnChar"></event>
+                                                                        <event name="OnEnterWindow"></event>
+                                                                        <event name="OnEraseBackground"></event>
+                                                                        <event name="OnKeyDown"></event>
+                                                                        <event name="OnKeyUp"></event>
+                                                                        <event name="OnKillFocus"></event>
+                                                                        <event name="OnLeaveWindow"></event>
+                                                                        <event name="OnLeftDClick"></event>
+                                                                        <event name="OnLeftDown"></event>
+                                                                        <event name="OnLeftUp"></event>
+                                                                        <event name="OnMiddleDClick"></event>
+                                                                        <event name="OnMiddleDown"></event>
+                                                                        <event name="OnMiddleUp"></event>
+                                                                        <event name="OnMotion"></event>
+                                                                        <event name="OnMouseEvents"></event>
+                                                                        <event name="OnMouseWheel"></event>
+                                                                        <event name="OnPaint"></event>
+                                                                        <event name="OnRightDClick"></event>
+                                                                        <event name="OnRightDown"></event>
+                                                                        <event name="OnRightUp"></event>
+                                                                        <event name="OnSetFocus"></event>
+                                                                        <event name="OnSize"></event>
+                                                                        <event name="OnUpdateUI"></event>
+                                                                    </object>
+                                                                </object>
+                                                            </object>
+                                                        </object>
+                                                    </object>
+                                                </object>
+                                            </object>
+                                        </object>
+                                    </object>
+                                    <object class="splitteritem" expanded="1">
+                                        <object class="wxPanel" 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="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_panel4</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="subclass"></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">wxTAB_TRAVERSAL</property>
+                                            <event name="OnChar"></event>
+                                            <event name="OnEnterWindow"></event>
+                                            <event name="OnEraseBackground"></event>
+                                            <event name="OnKeyDown"></event>
+                                            <event name="OnKeyUp"></event>
+                                            <event name="OnKillFocus"></event>
+                                            <event name="OnLeaveWindow"></event>
+                                            <event name="OnLeftDClick"></event>
+                                            <event name="OnLeftDown"></event>
+                                            <event name="OnLeftUp"></event>
+                                            <event name="OnMiddleDClick"></event>
+                                            <event name="OnMiddleDown"></event>
+                                            <event name="OnMiddleUp"></event>
+                                            <event name="OnMotion"></event>
+                                            <event name="OnMouseEvents"></event>
+                                            <event name="OnMouseWheel"></event>
+                                            <event name="OnPaint"></event>
+                                            <event name="OnRightDClick"></event>
+                                            <event name="OnRightDown"></event>
+                                            <event name="OnRightUp"></event>
+                                            <event name="OnSetFocus"></event>
+                                            <event name="OnSize"></event>
+                                            <event name="OnUpdateUI"></event>
+                                            <object class="wxBoxSizer" expanded="1">
+                                                <property name="minimum_size"></property>
+                                                <property name="name">bSizer5</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|wxEXPAND</property>
+                                                    <property name="proportion">1</property>
+                                                    <object class="wxDataViewCtrl" expanded="1">
+                                                        <property name="bg"></property>
+                                                        <property name="context_help"></property>
+                                                        <property name="context_menu">1</property>
+                                                        <property name="enabled">1</property>
+                                                        <property name="fg"></property>
+                                                        <property name="font"></property>
+                                                        <property name="hidden">0</property>
+                                                        <property name="id">wxID_ANY</property>
+                                                        <property name="maximum_size"></property>
+                                                        <property name="minimum_size">250,250</property>
+                                                        <property name="name">m_bomView</property>
+                                                        <property name="permission">protected</property>
+                                                        <property name="pos"></property>
+                                                        <property name="size"></property>
+                                                        <property name="style">wxDV_MULTIPLE|wxDV_ROW_LINES|wxDV_VERT_RULES</property>
+                                                        <property name="subclass"></property>
+                                                        <property name="tooltip"></property>
+                                                        <property name="window_extra_style"></property>
+                                                        <property name="window_name"></property>
+                                                        <property name="window_style"></property>
+                                                        <event name="OnChar"></event>
+                                                        <event name="OnDataViewCtrlColumnHeaderClick"></event>
+                                                        <event name="OnDataViewCtrlColumnHeaderRightClick"></event>
+                                                        <event name="OnDataViewCtrlColumnReordered">OnBomColumReordered</event>
+                                                        <event name="OnDataViewCtrlColumnSorted">OnBomColumnSorted</event>
+                                                        <event name="OnDataViewCtrlItemActivated"></event>
+                                                        <event name="OnDataViewCtrlItemBeginDrag"></event>
+                                                        <event name="OnDataViewCtrlItemCollapsed"></event>
+                                                        <event name="OnDataViewCtrlItemCollapsing"></event>
+                                                        <event name="OnDataViewCtrlItemContextMenu"></event>
+                                                        <event name="OnDataViewCtrlItemDrop"></event>
+                                                        <event name="OnDataViewCtrlItemDropPossible"></event>
+                                                        <event name="OnDataViewCtrlItemEditingDone">OnTableValueChanged</event>
+                                                        <event name="OnDataViewCtrlItemEditingStarted"></event>
+                                                        <event name="OnDataViewCtrlItemExpanded"></event>
+                                                        <event name="OnDataViewCtrlItemExpanding"></event>
+                                                        <event name="OnDataViewCtrlItemStartEditing"></event>
+                                                        <event name="OnDataViewCtrlItemValueChanged"></event>
+                                                        <event name="OnDataViewCtrlSelectionChanged">OnSelectionChanged</event>
+                                                        <event name="OnEnterWindow"></event>
+                                                        <event name="OnEraseBackground"></event>
+                                                        <event name="OnKeyDown"></event>
+                                                        <event name="OnKeyUp"></event>
+                                                        <event name="OnKillFocus"></event>
+                                                        <event name="OnLeaveWindow"></event>
+                                                        <event name="OnLeftDClick"></event>
+                                                        <event name="OnLeftDown"></event>
+                                                        <event name="OnLeftUp"></event>
+                                                        <event name="OnMiddleDClick"></event>
+                                                        <event name="OnMiddleDown"></event>
+                                                        <event name="OnMiddleUp"></event>
+                                                        <event name="OnMotion"></event>
+                                                        <event name="OnMouseEvents"></event>
+                                                        <event name="OnMouseWheel"></event>
+                                                        <event name="OnPaint"></event>
+                                                        <event name="OnRightDClick"></event>
+                                                        <event name="OnRightDown"></event>
+                                                        <event name="OnRightUp"></event>
+                                                        <event name="OnSetFocus"></event>
+                                                        <event name="OnSize"></event>
+                                                        <event name="OnUpdateUI"></event>
+                                                    </object>
+                                                </object>
+                                            </object>
+                                        </object>
+                                    </object>
+                                </object>
+                            </object>
+                        </object>
+                    </object>
+                </object>
+            </object>
+        </object>
+    </object>
+</wxFormBuilder_Project>
diff --git a/eeschema/dialogs/dialog_bom_editor_base.h b/eeschema/dialogs/dialog_bom_editor_base.h
new file mode 100644
index 0000000..277bcff
--- /dev/null
+++ b/eeschema/dialogs/dialog_bom_editor_base.h
@@ -0,0 +1,101 @@
+///////////////////////////////////////////////////////////////////////////
+// C++ code generated with wxFormBuilder (version Apr  1 2017)
+// http://www.wxformbuilder.org/
+//
+// PLEASE DO "NOT" EDIT THIS FILE!
+///////////////////////////////////////////////////////////////////////////
+
+#ifndef __DIALOG_BOM_EDITOR_BASE_H__
+#define __DIALOG_BOM_EDITOR_BASE_H__
+
+#include <wx/artprov.h>
+#include <wx/xrc/xmlres.h>
+#include <wx/intl.h>
+class DIALOG_SHIM;
+
+#include "dialog_shim.h"
+#include <wx/string.h>
+#include <wx/checkbox.h>
+#include <wx/gdicmn.h>
+#include <wx/font.h>
+#include <wx/colour.h>
+#include <wx/settings.h>
+#include <wx/button.h>
+#include <wx/sizer.h>
+#include <wx/statbox.h>
+#include <wx/dataview.h>
+#include <wx/panel.h>
+#include <wx/splitter.h>
+#include <wx/dialog.h>
+
+///////////////////////////////////////////////////////////////////////////
+
+#define OPT_GROUP_COMPONENTS 1000
+#define ID_BUTTON_REGROUP 1001
+#define ID_BUTTON_REVERT_CHANGES 1002
+#define wxID_BOM_OPT_INC_PRJ_DATA 1003
+#define wxID_BOM_OPT_SHOW_ROW_NUMS 1004
+#define wxID_BOM_BUTTON_EXPORT 1005
+
+///////////////////////////////////////////////////////////////////////////////
+/// Class DIALOG_BOM_EDITOR_BASE
+///////////////////////////////////////////////////////////////////////////////
+class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
+{
+	DECLARE_EVENT_TABLE()
+	private:
+		
+		// Private event handlers
+		void _wxFB_OnBomEditorClosed( wxCloseEvent& event ){ OnBomEditorClosed( event ); }
+		void _wxFB_OnGroupComponentsToggled( wxCommandEvent& event ){ OnGroupComponentsToggled( event ); }
+		void _wxFB_OnRegroupComponents( wxCommandEvent& event ){ OnRegroupComponents( event ); }
+		void _wxFB_OnRevertFieldChanges( wxCommandEvent& event ){ OnRevertFieldChanges( event ); }
+		void _wxFB_OnColumnItemToggled( wxDataViewEvent& event ){ OnColumnItemToggled( event ); }
+		void _wxFB_OnExportBOM( wxCommandEvent& event ){ OnExportBOM( event ); }
+		void _wxFB_OnBomColumReordered( wxDataViewEvent& event ){ OnBomColumReordered( event ); }
+		void _wxFB_OnBomColumnSorted( wxDataViewEvent& event ){ OnBomColumnSorted( event ); }
+		void _wxFB_OnTableValueChanged( wxDataViewEvent& event ){ OnTableValueChanged( event ); }
+		void _wxFB_OnSelectionChanged( wxDataViewEvent& event ){ OnSelectionChanged( event ); }
+		
+	
+	protected:
+		wxPanel* m_panel;
+		wxSplitterWindow* m_splitter1;
+		wxPanel* m_leftPanel;
+		wxCheckBox* m_groupComponentsBox;
+		wxButton* m_regroupComponentsButton;
+		wxButton* m_reloadTableButton;
+		wxDataViewListCtrl* m_columnListCtrl;
+		wxCheckBox* m_includeProjectData;
+		wxCheckBox* m_showRowNumbers;
+		wxButton* m_exportButton;
+		wxPanel* m_panel4;
+		wxDataViewCtrl* m_bomView;
+		
+		// Virtual event handlers, overide them in your derived class
+		virtual void OnBomEditorClosed( wxCloseEvent& event ) { event.Skip(); }
+		virtual void OnGroupComponentsToggled( wxCommandEvent& event ) { event.Skip(); }
+		virtual void OnRegroupComponents( wxCommandEvent& event ) { event.Skip(); }
+		virtual void OnRevertFieldChanges( wxCommandEvent& event ) { event.Skip(); }
+		virtual void OnColumnItemToggled( wxDataViewEvent& event ) { event.Skip(); }
+		virtual void OnExportBOM( wxCommandEvent& event ) { event.Skip(); }
+		virtual void OnBomColumReordered( wxDataViewEvent& event ) { event.Skip(); }
+		virtual void OnBomColumnSorted( wxDataViewEvent& event ) { event.Skip(); }
+		virtual void OnTableValueChanged( wxDataViewEvent& event ) { event.Skip(); }
+		virtual void OnSelectionChanged( wxDataViewEvent& event ) { event.Skip(); }
+		
+	
+	public:
+		
+		DIALOG_BOM_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("BOM editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 1047,649 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER ); 
+		~DIALOG_BOM_EDITOR_BASE();
+		
+		void m_splitter1OnIdle( wxIdleEvent& )
+		{
+			m_splitter1->SetSashPosition( 231 );
+			m_splitter1->Disconnect( wxEVT_IDLE, wxIdleEventHandler( DIALOG_BOM_EDITOR_BASE::m_splitter1OnIdle ), NULL, this );
+		}
+	
+};
+
+#endif //__DIALOG_BOM_EDITOR_BASE_H__
diff --git a/eeschema/invoke_sch_dialog.h b/eeschema/invoke_sch_dialog.h
index fe36a41..9e8c55b 100644
--- a/eeschema/invoke_sch_dialog.h
+++ b/eeschema/invoke_sch_dialog.h
@@ -80,6 +80,9 @@ int InvokeDialogPrintUsingPrinter( SCH_EDIT_FRAME* aCaller );
 /// DIALOG_BOM::ShowModal() returns.
 int InvokeDialogCreateBOM( SCH_EDIT_FRAME* aCaller );
 
+/// Create and show DIALOG_BOM_EDITOR
+int InvokeDialogCreateBOMEditor( SCH_EDIT_FRAME* aCaller );
+
 /**
  * Function InvokeDialogNetList
  * creates and shows NETLIST_DIALOG and returns whatever
diff --git a/eeschema/menubar.cpp b/eeschema/menubar.cpp
index a6da75e..0d2a2d9 100644
--- a/eeschema/menubar.cpp
+++ b/eeschema/menubar.cpp
@@ -503,11 +503,18 @@ void prepareToolsMenu( wxMenu* aParentMenu )
                  KiBitmap( netlist_xpm ) );
 
     AddMenuItem( aParentMenu,
+                 ID_OPEN_CMP_TABLE,
+                 _( "Component Table &View" ),
+                 KiBitmap( spreadsheet_xpm ) );
+
+    AddMenuItem( aParentMenu,
                  ID_GET_TOOLS,
                  _( "Generate Bill of &Materials..." ),
                  HELP_GENERATE_BOM,
                  KiBitmap( bom_xpm ) );
 
+
+
     aParentMenu->AppendSeparator();
 
     // Run CvPcb
diff --git a/eeschema/sch_component.cpp b/eeschema/sch_component.cpp
index fa2ce5e..8c9f64b 100644
--- a/eeschema/sch_component.cpp
+++ b/eeschema/sch_component.cpp
@@ -293,6 +293,43 @@ void SCH_COMPONENT::SetLibId( const LIB_ID& aLibId, SYMBOL_LIB_TABLE* aSymLibTab
     }
 }
 
+/**
+ * Function GetAliasDescription
+ * Return the description text for the given part alias
+ */
+wxString SCH_COMPONENT::GetAliasDescription() const
+{
+    if( PART_SPTR part = m_part.lock() )
+    {
+        LIB_ALIAS* alias = part->GetAlias( GetLibId().GetLibItemName() );
+
+        if( !alias )
+            return wxEmptyString;
+
+        return alias->GetDescription();
+    }
+
+    return wxEmptyString;
+}
+
+/**
+ * Function GetAliasDocumentation
+ * Return the documentation text for the given part alias
+ */
+wxString SCH_COMPONENT::GetAliasDocumentation() const
+{
+    if( PART_SPTR part = m_part.lock() )
+    {
+        LIB_ALIAS* alias = part->GetAlias( GetLibId().GetLibItemName() );
+
+        if( !alias )
+            return wxEmptyString;
+
+        return alias->GetDocFileName();
+    }
+
+    return wxEmptyString;
+}
 
 bool SCH_COMPONENT::Resolve( PART_LIBS* aLibs )
 {
@@ -732,6 +769,37 @@ SCH_FIELD* SCH_COMPONENT::GetField( int aFieldNdx ) const
     return (SCH_FIELD*) field;
 }
 
+wxString SCH_COMPONENT::GetFieldText( wxString aFieldName ) const
+{
+
+    // Field name for comparison
+    wxString cmpFieldName;
+
+    // Default field names
+    for ( unsigned int i=0; i<MANDATORY_FIELDS; i++)
+    {
+        cmpFieldName = TEMPLATE_FIELDNAME::GetDefaultFieldName( i );
+
+        if( cmpFieldName.Cmp( aFieldName ) == 0 )
+        {
+            return m_Fields[i].GetText();
+        }
+    }
+
+    // Search custom fields
+    for( unsigned int ii=MANDATORY_FIELDS; ii<m_Fields.size(); ii++ )
+    {
+        cmpFieldName = m_Fields[ii].GetName();
+
+        if( cmpFieldName.Cmp( aFieldName ) == 0 )
+        {
+            return m_Fields[ii].GetText();
+        }
+    }
+
+    return wxEmptyString;
+}
+
 
 void SCH_COMPONENT::GetFields( std::vector<SCH_FIELD*>& aVector, bool aVisibleOnly )
 {
diff --git a/eeschema/sch_component.h b/eeschema/sch_component.h
index 9469e7e..958b845 100644
--- a/eeschema/sch_component.h
+++ b/eeschema/sch_component.h
@@ -170,6 +170,12 @@ public:
     PART_REF& GetPartRef() { return m_part; }
 
     /**
+     * Return information about the aliased parts
+     */
+    wxString GetAliasDescription() const;
+    wxString GetAliasDocumentation() const;
+
+    /**
      * Function Resolve
      * [re-]assigns the current LIB_PART from aLibs which this component
      * is based on.
@@ -293,6 +299,12 @@ public:
     SCH_FIELD* GetField( int aFieldNdx ) const;
 
     /**
+     * Returns text associated with a given field (if such a field exists)
+     * @aFieldName is the name of the field
+     */
+    wxString GetFieldText( wxString aFieldName ) const;
+
+    /**
      * Function GetFields
      * populates a std::vector with SCH_FIELDs.
      * @param aVector - vector to populate.
diff --git a/eeschema/schframe.cpp b/eeschema/schframe.cpp
index 42687c2..3e7c2dd 100644
--- a/eeschema/schframe.cpp
+++ b/eeschema/schframe.cpp
@@ -267,6 +267,7 @@ BEGIN_EVENT_TABLE( SCH_EDIT_FRAME, EDA_DRAW_FRAME )
     EVT_TOOL( ID_GET_NETLIST, SCH_EDIT_FRAME::OnCreateNetlist )
     EVT_TOOL( ID_UPDATE_PCB_FROM_SCH, SCH_EDIT_FRAME::OnUpdatePCB )
     EVT_TOOL( ID_GET_TOOLS, SCH_EDIT_FRAME::OnCreateBillOfMaterials )
+    EVT_TOOL( ID_OPEN_CMP_TABLE, SCH_EDIT_FRAME::OnLaunchBomManager )
     EVT_TOOL( ID_FIND_ITEMS, SCH_EDIT_FRAME::OnFindItems )
     EVT_TOOL( wxID_REPLACE, SCH_EDIT_FRAME::OnFindItems )
     EVT_TOOL( ID_BACKANNO_ITEMS, SCH_EDIT_FRAME::OnLoadCmpToFootprintLinkFile )
@@ -764,6 +765,8 @@ void SCH_EDIT_FRAME::OnModify()
     GetScreen()->SetSave();
 
     m_foundItems.SetForceSearch();
+
+    m_canvas->Refresh();
 }
 
 
@@ -912,6 +915,14 @@ void SCH_EDIT_FRAME::OnCreateBillOfMaterials( wxCommandEvent& )
     InvokeDialogCreateBOM( this );
 }
 
+void SCH_EDIT_FRAME::OnLaunchBomManager( wxCommandEvent& event )
+{
+    // First ensure that entire schematic is annotated
+    if( !prepareForNetlist() )
+        return;
+
+    InvokeDialogCreateBOMEditor( this );
+}
 
 void SCH_EDIT_FRAME::OnFindItems( wxCommandEvent& aEvent )
 {
diff --git a/eeschema/schframe.h b/eeschema/schframe.h
index 4fe4a65..b2d8783 100644
--- a/eeschema/schframe.h
+++ b/eeschema/schframe.h
@@ -833,6 +833,7 @@ private:
     void OnUpdatePCB( wxCommandEvent& event );
     void OnSimulate( wxCommandEvent& event );
     void OnCreateBillOfMaterials( wxCommandEvent& event );
+    void OnLaunchBomManager( wxCommandEvent& event );
     void OnFindItems( wxCommandEvent& event );
     void OnFindDialogClose( wxFindDialogEvent& event );
     void OnFindDrcMarker( wxFindDialogEvent& event );
diff --git a/eeschema/tool_sch.cpp b/eeschema/tool_sch.cpp
index 6060e36..1b08747 100644
--- a/eeschema/tool_sch.cpp
+++ b/eeschema/tool_sch.cpp
@@ -160,10 +160,13 @@ void SCH_EDIT_FRAME::ReCreateHToolbar()
     m_mainToolBar->AddTool( ID_GET_NETLIST, wxEmptyString, KiBitmap( netlist_xpm ),
                             _( "Generate netlist" ) );
 
+    m_mainToolBar->AddTool( ID_OPEN_CMP_TABLE, wxEmptyString, KiBitmap( spreadsheet_xpm ),
+                            _( "Component table view"  ) );
+
+
     m_mainToolBar->AddTool( ID_GET_TOOLS, wxEmptyString, KiBitmap( bom_xpm ),
                             HELP_GENERATE_BOM );
 
-
     m_mainToolBar->AddSeparator();
 
     m_mainToolBar->AddTool( ID_RUN_PCB, wxEmptyString, KiBitmap( pcbnew_xpm ),
diff --git a/include/bitmaps.h b/include/bitmaps.h
index e58ade3..cd0d990 100644
--- a/include/bitmaps.h
+++ b/include/bitmaps.h
@@ -493,6 +493,7 @@ EXTERN_BITMAP( showtrack_xpm )
 EXTERN_BITMAP( show_zone_xpm )
 EXTERN_BITMAP( show_zone_disable_xpm )
 EXTERN_BITMAP( show_zone_outline_only_xpm )
+EXTERN_BITMAP( spreadsheet_xpm )
 EXTERN_BITMAP( svg_file_xpm )
 EXTERN_BITMAP( swap_layer_xpm )
 EXTERN_BITMAP( text_sketch_xpm )
diff --git a/include/id.h b/include/id.h
index c01676d..780958d 100644
--- a/include/id.h
+++ b/include/id.h
@@ -249,6 +249,7 @@ enum main_id
     ID_PAN_RIGHT,
 
     ID_GET_NETLIST,
+    ID_OPEN_CMP_TABLE,
     ID_GET_TOOLS,
     ID_FIND_ITEMS,
 
diff --git a/include/wildcards_and_files_ext.h b/include/wildcards_and_files_ext.h
index 63b43fc..5bd7fa1 100644
--- a/include/wildcards_and_files_ext.h
+++ b/include/wildcards_and_files_ext.h
@@ -83,6 +83,7 @@ extern const wxString BoardFileWildcard;
 extern const wxString NetlistFileWildcard;
 extern const wxString GerberFileWildcard;
 extern const wxString HtmlFileWildcard;
+extern const wxString CsvFileWildcard;
 extern const wxString LegacyPcbFileWildcard;
 extern const wxString PcbFileWildcard;
 extern const wxString EaglePcbFileWildcard;
-- 
2.7.4

From 56eb8e3333285c37c346567a23d7e2d9ea3c07e1 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 4 Apr 2017 22:27:13 +1000
Subject: [PATCH 2/8] Fixed wxString::Format assert

---
 eeschema/dialogs/dialog_bom_editor.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eeschema/dialogs/dialog_bom_editor.cpp b/eeschema/dialogs/dialog_bom_editor.cpp
index a835b03..12f77c6 100644
--- a/eeschema/dialogs/dialog_bom_editor.cpp
+++ b/eeschema/dialogs/dialog_bom_editor.cpp
@@ -173,7 +173,7 @@ void DIALOG_BOM_EDITOR::UpdateTitle()
     {
         title += wxString::Format( " %s %u %s",
                               _( "in" ),
-                              m_bom->Groups.size(),
+                              (unsigned int) m_bom->Groups.size(),
                               _( "groups" ) );
     }
 
-- 
2.7.4

From 632bcfcbeee0a641f4d8d4adb5e311e95819b8c7 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Sun, 16 Apr 2017 16:43:59 +1000
Subject: [PATCH 3/8] Mark schematic as dirty

Notify schematic of changes when window is closed
---
 eeschema/dialogs/dialog_bom_editor.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/eeschema/dialogs/dialog_bom_editor.cpp b/eeschema/dialogs/dialog_bom_editor.cpp
index 12f77c6..f4b73b4 100644
--- a/eeschema/dialogs/dialog_bom_editor.cpp
+++ b/eeschema/dialogs/dialog_bom_editor.cpp
@@ -153,6 +153,8 @@ void DIALOG_BOM_EDITOR::OnBomEditorClosed( wxCloseEvent& event )
             m_bom->ApplyFieldChanges();
             m_parent->Refresh();
         }
+
+        m_parent->OnModify();
     }
 
     Destroy();
-- 
2.7.4

From 0edc11c49faa22289ca764eb462f9debe737a0ed Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Mon, 17 Apr 2017 12:08:21 +1000
Subject: [PATCH 4/8] Fixed display of references for duplicate sheets

Display part reference rather than REFERENCE field value
---
 eeschema/bom_table_model.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/eeschema/bom_table_model.cpp b/eeschema/bom_table_model.cpp
index a43d749..5301e95 100644
--- a/eeschema/bom_table_model.cpp
+++ b/eeschema/bom_table_model.cpp
@@ -456,7 +456,7 @@ bool BOM_TABLE_COMPONENT::AddUnit( SCH_REFERENCE aUnit )
                 }
                 break;
             case BOM_COL_ID_REFERENCE:
-                value = cmp->GetField( REFERENCE )->GetText();
+                value = aUnit.GetRef();
                 break;
             case BOM_COL_ID_VALUE:
                 value = cmp->GetField( VALUE )->GetText();
-- 
2.7.4

From 638390123de77170c84a3e35fce09e88a56a6157 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 18 Apr 2017 19:25:02 +1000
Subject: [PATCH 5/8] Reworked UI

- Buttons are enabled/disabled within wxUpdateUI events
- Save/Cancel dialog used to close window and apply (or reject) changes
---
 eeschema/dialogs/dialog_bom_editor.cpp      | 28 +++++++++--------
 eeschema/dialogs/dialog_bom_editor.h        |  8 +++--
 eeschema/dialogs/dialog_bom_editor_base.cpp | 19 ++++++++++--
 eeschema/dialogs/dialog_bom_editor_base.fbp | 47 +++++++++++++++++++++++++++--
 eeschema/dialogs/dialog_bom_editor_base.h   | 11 ++++---
 5 files changed, 90 insertions(+), 23 deletions(-)

diff --git a/eeschema/dialogs/dialog_bom_editor.cpp b/eeschema/dialogs/dialog_bom_editor.cpp
index f4b73b4..19b0c79 100644
--- a/eeschema/dialogs/dialog_bom_editor.cpp
+++ b/eeschema/dialogs/dialog_bom_editor.cpp
@@ -85,7 +85,7 @@ DIALOG_BOM_EDITOR::DIALOG_BOM_EDITOR( SCH_EDIT_FRAME* parent ) :
 
     m_bom->ReloadTable();
 
-    UpdateTitle();
+    Update();
 }
 
 DIALOG_BOM_EDITOR::~DIALOG_BOM_EDITOR()
@@ -98,7 +98,7 @@ DIALOG_BOM_EDITOR::~DIALOG_BOM_EDITOR()
  * work out if we need to save any changed.
  * If so, capture those changes and push them to the undo stack.
  */
-void DIALOG_BOM_EDITOR::OnBomEditorClosed( wxCloseEvent& event )
+bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
 {
     bool saveChanges = false;
 
@@ -115,11 +115,10 @@ void DIALOG_BOM_EDITOR::OnBomEditorClosed( wxCloseEvent& event )
             break;
         // Cancel (do not exit)
         case wxID_CANCEL:
-            event.Veto();
-            return;
+            return false;
         // Do not save, exit
         default:
-            break;
+            return true;
         }
     }
 
@@ -157,7 +156,7 @@ void DIALOG_BOM_EDITOR::OnBomEditorClosed( wxCloseEvent& event )
         m_parent->OnModify();
     }
 
-    Destroy();
+    return true;
 }
 
 /**
@@ -285,7 +284,14 @@ void DIALOG_BOM_EDITOR::OnGroupComponentsToggled( wxCommandEvent& event )
     m_bom->SetColumnGrouping( group );
     m_bom->ReloadTable();
 
-    m_regroupComponentsButton->Enable( group );
+    Update();
+}
+
+void DIALOG_BOM_EDITOR::OnUpdateUI( wxUpdateUIEvent& event )
+{
+    m_regroupComponentsButton->Enable( m_bom->GetColumnGrouping() );
+
+    m_reloadTableButton->Enable( m_bom->HaveFieldsChanged() );
 
     UpdateTitle();
 }
@@ -417,14 +423,13 @@ void DIALOG_BOM_EDITOR::OnExportBOM( wxCommandEvent& event )
 
 void DIALOG_BOM_EDITOR::OnTableValueChanged( wxDataViewEvent& event )
 {
-    m_reloadTableButton->Enable( m_bom->HaveFieldsChanged() );
-
-    UpdateTitle();
+    Update();
 }
 
 void DIALOG_BOM_EDITOR::OnRegroupComponents( wxCommandEvent& event )
 {
     m_bom->ReloadTable();
+    Update();
 }
 
 void DIALOG_BOM_EDITOR::OnRevertFieldChanges( wxCommandEvent& event )
@@ -434,8 +439,7 @@ void DIALOG_BOM_EDITOR::OnRevertFieldChanges( wxCommandEvent& event )
         if( IsOK( this, _( "Revert all component table changes?" ) ) )
         {
             m_bom->RevertFieldChanges();
-            m_reloadTableButton->Enable( m_bom->HaveFieldsChanged() );
-            UpdateTitle();
+            Update();
         }
     }
 }
diff --git a/eeschema/dialogs/dialog_bom_editor.h b/eeschema/dialogs/dialog_bom_editor.h
index 9269134..0f79e98 100644
--- a/eeschema/dialogs/dialog_bom_editor.h
+++ b/eeschema/dialogs/dialog_bom_editor.h
@@ -62,6 +62,9 @@ private:
     void LoadColumnNames( void );
     void ReloadColumns( void );
 
+    // Called when the OK button is pressed
+    virtual bool TransferDataFromWindow() override;
+
     // Checkbox event callbacks
     virtual void OnColumnItemToggled( wxDataViewEvent& event ) override;
     virtual void OnGroupComponentsToggled( wxCommandEvent& event ) override;
@@ -75,9 +78,10 @@ private:
     // Called after a value in the table has changed
     virtual void OnTableValueChanged( wxDataViewEvent& event ) override;
 
-    virtual void OnBomEditorClosed( wxCloseEvent& event ) override;
-
     void UpdateTitle( void );
+
+    virtual void OnUpdateUI( wxUpdateUIEvent& event ) override;
+
 };
 
 #endif /* EESCHEMA_DIALOGS_DIALOG_BOM_EDITOR_H_ */
diff --git a/eeschema/dialogs/dialog_bom_editor_base.cpp b/eeschema/dialogs/dialog_bom_editor_base.cpp
index d5e07a4..d83d34d 100644
--- a/eeschema/dialogs/dialog_bom_editor_base.cpp
+++ b/eeschema/dialogs/dialog_bom_editor_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Apr  1 2017)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -10,7 +10,7 @@
 ///////////////////////////////////////////////////////////////////////////
 
 BEGIN_EVENT_TABLE( DIALOG_BOM_EDITOR_BASE, DIALOG_SHIM )
-	EVT_CLOSE( DIALOG_BOM_EDITOR_BASE::_wxFB_OnBomEditorClosed )
+	EVT_UPDATE_UI( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnUpdateUI )
 	EVT_CHECKBOX( OPT_GROUP_COMPONENTS, DIALOG_BOM_EDITOR_BASE::_wxFB_OnGroupComponentsToggled )
 	EVT_BUTTON( ID_BUTTON_REGROUP, DIALOG_BOM_EDITOR_BASE::_wxFB_OnRegroupComponents )
 	EVT_BUTTON( ID_BUTTON_REVERT_CHANGES, DIALOG_BOM_EDITOR_BASE::_wxFB_OnRevertFieldChanges )
@@ -112,6 +112,21 @@ DIALOG_BOM_EDITOR_BASE::DIALOG_BOM_EDITOR_BASE( wxWindow* parent, wxWindowID id,
 	
 	bSizer6->Add( sbSizer2, 0, wxEXPAND, 5 );
 	
+	wxStaticBoxSizer* sbSizer4;
+	sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Apply changes") ), wxVERTICAL );
+	
+	m_sdbSizer1 = new wxStdDialogButtonSizer();
+	m_sdbSizer1OK = new wxButton( sbSizer4->GetStaticBox(), wxID_OK );
+	m_sdbSizer1->AddButton( m_sdbSizer1OK );
+	m_sdbSizer1Cancel = new wxButton( sbSizer4->GetStaticBox(), wxID_CANCEL );
+	m_sdbSizer1->AddButton( m_sdbSizer1Cancel );
+	m_sdbSizer1->Realize();
+	
+	sbSizer4->Add( m_sdbSizer1, 1, wxEXPAND, 5 );
+	
+	
+	bSizer6->Add( sbSizer4, 1, wxEXPAND, 5 );
+	
 	
 	m_leftPanel->SetSizer( bSizer6 );
 	m_leftPanel->Layout();
diff --git a/eeschema/dialogs/dialog_bom_editor_base.fbp b/eeschema/dialogs/dialog_bom_editor_base.fbp
index 9d1cf28..2fcc929 100644
--- a/eeschema/dialogs/dialog_bom_editor_base.fbp
+++ b/eeschema/dialogs/dialog_bom_editor_base.fbp
@@ -45,7 +45,7 @@
             <property name="name">DIALOG_BOM_EDITOR_BASE</property>
             <property name="pos"></property>
             <property name="size">1047,649</property>
-            <property name="style">wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER</property>
+            <property name="style">wxCAPTION|wxMAXIMIZE_BOX|wxRESIZE_BORDER|wxSTAY_ON_TOP</property>
             <property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
             <property name="title">BOM editor</property>
             <property name="tooltip"></property>
@@ -61,7 +61,7 @@
             <event name="OnAuiPaneRestore"></event>
             <event name="OnAuiRender"></event>
             <event name="OnChar"></event>
-            <event name="OnClose">OnBomEditorClosed</event>
+            <event name="OnClose"></event>
             <event name="OnEnterWindow"></event>
             <event name="OnEraseBackground"></event>
             <event name="OnHibernate"></event>
@@ -87,7 +87,7 @@
             <event name="OnRightUp"></event>
             <event name="OnSetFocus"></event>
             <event name="OnSize"></event>
-            <event name="OnUpdateUI"></event>
+            <event name="OnUpdateUI">OnUpdateUI</event>
             <object class="wxBoxSizer" expanded="1">
                 <property name="minimum_size"></property>
                 <property name="name">bHorizontalSizer</property>
@@ -1037,6 +1037,47 @@
                                                         </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="wxStaticBoxSizer" expanded="1">
+                                                        <property name="id">wxID_ANY</property>
+                                                        <property name="label">Apply changes</property>
+                                                        <property name="minimum_size"></property>
+                                                        <property name="name">sbSizer4</property>
+                                                        <property name="orient">wxVERTICAL</property>
+                                                        <property name="parent">1</property>
+                                                        <property name="permission">none</property>
+                                                        <event name="OnUpdateUI"></event>
+                                                        <object class="sizeritem" expanded="1">
+                                                            <property name="border">5</property>
+                                                            <property name="flag">wxEXPAND</property>
+                                                            <property name="proportion">1</property>
+                                                            <object class="wxStdDialogButtonSizer" expanded="1">
+                                                                <property name="Apply">0</property>
+                                                                <property name="Cancel">1</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_sdbSizer1</property>
+                                                                <property name="permission">protected</property>
+                                                                <event name="OnApplyButtonClick"></event>
+                                                                <event name="OnCancelButtonClick"></event>
+                                                                <event name="OnContextHelpButtonClick"></event>
+                                                                <event name="OnHelpButtonClick"></event>
+                                                                <event name="OnNoButtonClick"></event>
+                                                                <event name="OnOKButtonClick"></event>
+                                                                <event name="OnSaveButtonClick"></event>
+                                                                <event name="OnYesButtonClick"></event>
+                                                            </object>
+                                                        </object>
+                                                    </object>
+                                                </object>
                                             </object>
                                         </object>
                                     </object>
diff --git a/eeschema/dialogs/dialog_bom_editor_base.h b/eeschema/dialogs/dialog_bom_editor_base.h
index 277bcff..87d70ef 100644
--- a/eeschema/dialogs/dialog_bom_editor_base.h
+++ b/eeschema/dialogs/dialog_bom_editor_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Apr  1 2017)
+// C++ code generated with wxFormBuilder (version Mar 22 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -46,7 +46,7 @@ class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
 	private:
 		
 		// Private event handlers
-		void _wxFB_OnBomEditorClosed( wxCloseEvent& event ){ OnBomEditorClosed( event ); }
+		void _wxFB_OnUpdateUI( wxUpdateUIEvent& event ){ OnUpdateUI( event ); }
 		void _wxFB_OnGroupComponentsToggled( wxCommandEvent& event ){ OnGroupComponentsToggled( event ); }
 		void _wxFB_OnRegroupComponents( wxCommandEvent& event ){ OnRegroupComponents( event ); }
 		void _wxFB_OnRevertFieldChanges( wxCommandEvent& event ){ OnRevertFieldChanges( event ); }
@@ -69,11 +69,14 @@ class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
 		wxCheckBox* m_includeProjectData;
 		wxCheckBox* m_showRowNumbers;
 		wxButton* m_exportButton;
+		wxStdDialogButtonSizer* m_sdbSizer1;
+		wxButton* m_sdbSizer1OK;
+		wxButton* m_sdbSizer1Cancel;
 		wxPanel* m_panel4;
 		wxDataViewCtrl* m_bomView;
 		
 		// Virtual event handlers, overide them in your derived class
-		virtual void OnBomEditorClosed( wxCloseEvent& event ) { event.Skip(); }
+		virtual void OnUpdateUI( wxUpdateUIEvent& event ) { event.Skip(); }
 		virtual void OnGroupComponentsToggled( wxCommandEvent& event ) { event.Skip(); }
 		virtual void OnRegroupComponents( wxCommandEvent& event ) { event.Skip(); }
 		virtual void OnRevertFieldChanges( wxCommandEvent& event ) { event.Skip(); }
@@ -87,7 +90,7 @@ class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
 	
 	public:
 		
-		DIALOG_BOM_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("BOM editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 1047,649 ), long style = wxDEFAULT_DIALOG_STYLE|wxMAXIMIZE_BOX|wxRESIZE_BORDER ); 
+		DIALOG_BOM_EDITOR_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = _("BOM editor"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 1047,649 ), long style = wxCAPTION|wxMAXIMIZE_BOX|wxRESIZE_BORDER|wxSTAY_ON_TOP ); 
 		~DIALOG_BOM_EDITOR_BASE();
 		
 		void m_splitter1OnIdle( wxIdleEvent& )
-- 
2.7.4

From bc0827aed8ee5497183988bca4663753267820b6 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 18 Apr 2017 22:43:40 +1000
Subject: [PATCH 6/8] Reworked field association

- Allow duplicate components to access same field data
---
 eeschema/bom_table_model.cpp | 163 ++++++++++++++++++++++++++++++++++---------
 eeschema/bom_table_model.h   |  54 ++++++++++++--
 2 files changed, 178 insertions(+), 39 deletions(-)

diff --git a/eeschema/bom_table_model.cpp b/eeschema/bom_table_model.cpp
index 5301e95..6e8a0f0 100644
--- a/eeschema/bom_table_model.cpp
+++ b/eeschema/bom_table_model.cpp
@@ -53,6 +53,86 @@ static BOM_TABLE_ROW const* ItemToRow( wxDataViewItem aItem )
     }
 }
 
+BOM_FIELD_VALUES::BOM_FIELD_VALUES( wxString aRefDes ) : m_refDes( aRefDes )
+{
+}
+
+/**
+ * Return the current value for the provided field ID
+ */
+bool BOM_FIELD_VALUES::GetFieldValue( unsigned int aFieldId, wxString& aValue ) const
+{
+    auto search = m_currentValues.find( aFieldId );
+
+    if( search == m_currentValues.end() )
+        return false;
+
+    aValue = search->second;
+
+    return true;
+}
+
+/**
+ * Return the backup value for the provided field ID
+ */
+bool BOM_FIELD_VALUES::GetBackupValue( unsigned int aFieldId, wxString& aValue ) const
+{
+    auto search = m_backupValues.find( aFieldId );
+
+    if( search == m_backupValues.end() )
+        return false;
+
+    aValue = search->second;
+
+    return true;
+}
+
+/**
+ * Set the value for the provided field ID
+ * Field value is set under any of the following conditions:
+ * - param aOverwrite is true
+ * - There is no current value
+ * - The current value is empty
+ */
+void BOM_FIELD_VALUES::SetFieldValue( unsigned int aFieldId, wxString aValue, bool aOverwrite )
+{
+    if( aOverwrite || m_currentValues.count( aFieldId ) == 0 || m_currentValues[aFieldId].IsEmpty() )
+    {
+        m_currentValues[aFieldId] = aValue;
+    }
+}
+
+/**
+ * Set the backup value for the provided field ID
+ * If the backup value is already set, new value is ignored
+ */
+void BOM_FIELD_VALUES::SetBackupValue( unsigned int aFieldId, wxString aValue )
+{
+    if( m_backupValues.count( aFieldId ) == 0 || m_backupValues[aFieldId].IsEmpty() )
+    {
+        m_backupValues[aFieldId] = aValue;
+    }
+}
+
+bool BOM_FIELD_VALUES::HasValueChanged( unsigned int aFieldId) const
+{
+    wxString currentValue, backupValue;
+
+    GetFieldValue( aFieldId, currentValue );
+    GetBackupValue( aFieldId, backupValue );
+
+    return currentValue.Cmp( backupValue ) != 0;
+}
+
+void BOM_FIELD_VALUES::RevertChanges( unsigned int aFieldId )
+{
+    wxString backupValue;
+
+    GetBackupValue( aFieldId, backupValue );
+
+    SetFieldValue( aFieldId, backupValue, true );
+}
+
 BOM_TABLE_ROW::BOM_TABLE_ROW() : m_columnList( nullptr )
 {
 }
@@ -416,10 +496,12 @@ int BOM_TABLE_GROUP::SortValues( const wxString& aFirst, const wxString& aSecond
  * Each COMPONENT row is associated with a single component item.
  */
 BOM_TABLE_COMPONENT::BOM_TABLE_COMPONENT( BOM_TABLE_GROUP* aParent,
-                                          BOM_COLUMN_LIST* aColumnList)
+                                          BOM_COLUMN_LIST* aColumnList,
+                                          BOM_FIELD_VALUES* aFieldValues )
 {
     m_parent = aParent;
     m_columnList = aColumnList;
+    m_fieldValues = aFieldValues;
 }
 
 /**
@@ -471,10 +553,8 @@ bool BOM_TABLE_COMPONENT::AddUnit( SCH_REFERENCE aUnit )
                 break;
             }
 
-            SetFieldValue( column->Id(), value );
-
-            // Add the value to the fallback map
-            m_fallbackData[column->Id()] = value;
+            m_fieldValues->SetFieldValue( column->Id(), value );
+            m_fieldValues->SetBackupValue( column->Id(), value );
         }
 
         return true;
@@ -489,16 +569,22 @@ bool BOM_TABLE_COMPONENT::AddUnit( SCH_REFERENCE aUnit )
  */
 wxString BOM_TABLE_COMPONENT::GetFieldValue( unsigned int aFieldId ) const
 {
-    auto search = m_fieldData.find( aFieldId );
+    wxString value;
 
-    if( search != m_fieldData.end()  )
-    {
-        return search->second;
-    }
-    else
+    switch ( aFieldId )
     {
+    case BOM_COL_ID_QUANTITY:
         return wxEmptyString;
+    case BOM_COL_ID_REFERENCE:
+        return GetReference();
+    default:
+        break;
     }
+
+    if( m_fieldValues )
+        m_fieldValues->GetFieldValue( aFieldId, value );
+
+    return value;
 }
 
 /**
@@ -509,9 +595,9 @@ wxString BOM_TABLE_COMPONENT::GetFieldValue( unsigned int aFieldId ) const
  */
 bool BOM_TABLE_COMPONENT::SetFieldValue( unsigned int aFieldId, const wxString aValue, bool aOverwrite )
 {
-    if( aOverwrite || m_fieldData.count( aFieldId ) == 0 || m_fieldData[aFieldId].IsEmpty() )
+    if( m_fieldValues )
     {
-        m_fieldData[aFieldId] = aValue;
+        m_fieldValues->SetFieldValue( aFieldId, aValue, aOverwrite );
         return true;
     }
 
@@ -550,13 +636,7 @@ bool BOM_TABLE_COMPONENT::HasValueChanged( BOM_COLUMN* aField ) const
         return false;
     }
 
-    auto value = m_fieldData.find( aField->Id() );
-    auto backup = m_fallbackData.find( aField->Id() );
-
-    wxString currentValue = value == m_fieldData.end() ? wxString() : value->second;
-    wxString backupValue = backup == m_fallbackData.end() ? wxString() : backup->second;
-
-    return currentValue.Cmp( backupValue ) != 0;
+    return m_fieldValues->HasValueChanged( aField->Id() );
 }
 
 /**
@@ -634,17 +714,7 @@ void BOM_TABLE_COMPONENT::RevertFieldChanges()
             break;
         }
 
-        if( column && HasValueChanged( column ) )
-        {
-            if( m_fallbackData.count( column->Id() ) > 0 )
-            {
-                m_fieldData[column->Id()] = m_fallbackData[column->Id()];
-            }
-            else
-            {
-                m_fieldData[column->Id()] = wxEmptyString;
-            }
-        }
+        m_fieldValues->RevertChanges( column->Id() );
     }
 }
 
@@ -931,6 +1001,7 @@ void BOM_TABLE_MODEL::SetComponents( SCH_REFERENCE_LIST aRefs )
 
     // Group multi-unit components together
     m_components.clear();
+    m_fieldValues.clear();
 
     for( unsigned int ii=0; ii<aRefs.GetCount(); ii++ )
     {
@@ -949,7 +1020,30 @@ void BOM_TABLE_MODEL::SetComponents( SCH_REFERENCE_LIST aRefs )
 
         if( !found )
         {
-            auto* newComponent = new BOM_TABLE_COMPONENT( nullptr, &ColumnList );
+            // Find the field:value map associated with this component
+            wxString refDes = ref.GetComp()->GetField( REFERENCE )->GetText();
+
+            bool dataFound = false;
+
+            BOM_FIELD_VALUES* values;
+
+            for( auto& data : m_fieldValues )
+            {
+                // Look for a match based on RefDes
+                if( data->GetReference().Cmp( refDes ) == 0 )
+                {
+                    dataFound = true;
+                    values = &*data;
+                }
+            }
+
+            if( !dataFound )
+            {
+                values = new BOM_FIELD_VALUES( refDes );
+                m_fieldValues.push_back( std::unique_ptr<BOM_FIELD_VALUES>( values ) );
+            }
+
+            auto* newComponent = new BOM_TABLE_COMPONENT( nullptr, &ColumnList, values );
             newComponent->AddUnit( ref );
 
             m_components.push_back( std::unique_ptr<BOM_TABLE_COMPONENT>( newComponent ) );
@@ -1090,6 +1184,11 @@ bool BOM_TABLE_MODEL::SetValue(
             }
         }
 
+        if( m_widget )
+        {
+            m_widget->Update();
+        }
+
         return result;
     }
 
diff --git a/eeschema/bom_table_model.h b/eeschema/bom_table_model.h
index 8cf3898..7b160bb 100644
--- a/eeschema/bom_table_model.h
+++ b/eeschema/bom_table_model.h
@@ -43,6 +43,46 @@ class BOM_TABLE_ROW;        // Base-class for table row data model
 class BOM_TABLE_GROUP;      // Class for displaying a group of components
 class BOM_TABLE_COMPONENT;  // Class for displaying a single component
 
+// Map column IDs to field values (for quick lookup)
+typedef std::map<unsigned int, wxString> FIELD_VALUE_MAP;
+
+
+/**
+ * The BOM_FIELD_VALUES class provides quick lookup of component values
+ * (based on Field ID)
+ * This is done for the following reasons:
+ * - Increase lookup speed for table values
+ * - Allow field values to be reverted to original values
+ * - Allow duplicate components to reference the same data
+ */
+class BOM_FIELD_VALUES
+{
+public:
+    BOM_FIELD_VALUES(wxString aRefDes);
+
+    bool GetFieldValue( unsigned int aFieldId, wxString& aValue ) const;
+    bool GetBackupValue( unsigned int aFieldId, wxString& aValue ) const;
+
+    void SetFieldValue( unsigned int aFieldId, wxString aValue, bool aOverwrite = false );
+    void SetBackupValue( unsigned int aFieldId, wxString aValue );
+
+    wxString GetReference() const { return m_refDes; }
+
+    bool HasValueChanged( unsigned int aFieldId ) const;
+
+    void RevertChanges( unsigned int aFieldId );
+
+protected:
+    //! The RefDes to which these values correspond
+    wxString m_refDes;
+
+    //! Current values for each column
+    FIELD_VALUE_MAP m_currentValues;
+
+    //! Backup values for each column
+    FIELD_VALUE_MAP m_backupValues;
+};
+
 /**
  * Virtual base class determining how a row is displayed
  * There are three types of rows:
@@ -144,7 +184,7 @@ public:
     // List of units associated with this component
     std::vector<SCH_REFERENCE> Units;
 
-    BOM_TABLE_COMPONENT( BOM_TABLE_GROUP* aParent, BOM_COLUMN_LIST* aColumnList );
+    BOM_TABLE_COMPONENT( BOM_TABLE_GROUP* aParent, BOM_COLUMN_LIST* aColumnList, BOM_FIELD_VALUES* aValues );
 
     bool AddUnit( SCH_REFERENCE aUnit );
 
@@ -168,13 +208,9 @@ public:
     virtual BOM_TABLE_ROW* GetParent() const override { return m_parent; }
 
 protected:
-    // Initial data for reverting component values
-    std::map<unsigned int, wxString> m_fallbackData;
-
-    // Data as it is updated
-    std::map<unsigned int, wxString> m_fieldData;
-
     BOM_TABLE_GROUP* m_parent;
+
+    BOM_FIELD_VALUES* m_fieldValues;
 };
 
 /**
@@ -189,8 +225,12 @@ class BOM_TABLE_MODEL : public wxDataViewModel
 protected:
     BOM_TABLE_MODEL();
 
+    // Vector of unique component rows
     std::vector<std::unique_ptr<BOM_TABLE_COMPONENT>> m_components;
 
+    // Vector of field values mapped to field IDs
+    std::vector<std::unique_ptr<BOM_FIELD_VALUES>> m_fieldValues;
+
     // BOM Preferences
     //! Group components based on values
     bool m_groupColumns = true;
-- 
2.7.4

From a64dca29546ecad4f23540c81489c94684c28d8b Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Wed, 19 Apr 2017 00:10:17 +1000
Subject: [PATCH 7/8] Fixed UNDO behaviour

- Undo actions are pushed to the appropriate sheet(s)
- Each sheet's actions are grouped together
---
 eeschema/bom_table_model.cpp           | 11 ++---
 eeschema/bom_table_model.h             |  2 +-
 eeschema/dialogs/dialog_bom_editor.cpp | 78 +++++++++++++++++++++++++++++-----
 3 files changed, 71 insertions(+), 20 deletions(-)

diff --git a/eeschema/bom_table_model.cpp b/eeschema/bom_table_model.cpp
index 6e8a0f0..1005a78 100644
--- a/eeschema/bom_table_model.cpp
+++ b/eeschema/bom_table_model.cpp
@@ -1446,9 +1446,9 @@ bool BOM_TABLE_MODEL::HaveFieldsChanged() const
 /**
  * Returns a list of only those components that have been changed
  */
-std::vector<SCH_COMPONENT*> BOM_TABLE_MODEL::GetChangedComponents()
+std::vector<SCH_REFERENCE> BOM_TABLE_MODEL::GetChangedComponents()
 {
-    std::vector<SCH_COMPONENT*> components;
+    std::vector<SCH_REFERENCE> components;
 
     for( auto& group : Groups )
     {
@@ -1464,12 +1464,7 @@ std::vector<SCH_COMPONENT*> BOM_TABLE_MODEL::GetChangedComponents()
             {
                 for( auto& unit : component->Units )
                 {
-                    auto cmp = unit.GetComp();
-
-                    if( cmp )
-                    {
-                        components.push_back( cmp );
-                    }
+                    components.push_back( unit );
                 }
             }
         }
diff --git a/eeschema/bom_table_model.h b/eeschema/bom_table_model.h
index 7b160bb..933db5c 100644
--- a/eeschema/bom_table_model.h
+++ b/eeschema/bom_table_model.h
@@ -315,7 +315,7 @@ public:
 
     bool HaveFieldsChanged() const;
 
-    std::vector<SCH_COMPONENT*> GetChangedComponents();
+    std::vector<SCH_REFERENCE> GetChangedComponents();
     unsigned int CountChangedComponents();
 };
 
diff --git a/eeschema/dialogs/dialog_bom_editor.cpp b/eeschema/dialogs/dialog_bom_editor.cpp
index 19b0c79..722cbd5 100644
--- a/eeschema/dialogs/dialog_bom_editor.cpp
+++ b/eeschema/dialogs/dialog_bom_editor.cpp
@@ -93,6 +93,18 @@ DIALOG_BOM_EDITOR::~DIALOG_BOM_EDITOR()
     //TODO
 }
 
+/* Struct for keeping track of schematic sheet changes
+ * Stores:
+ * SHEET_PATH - Schematic to apply changes to
+ * PICKED_ITEMS_LIST - List of changes to apply
+ */
+
+typedef struct
+{
+    SCH_SHEET_PATH path;
+    PICKED_ITEMS_LIST items;
+} SheetUndoList;
+
 /**
  * When the component table dialog is closed,
  * work out if we need to save any changed.
@@ -124,36 +136,80 @@ bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
 
     if( saveChanges )
     {
-        /** Create a list of picked items for undo
-         * PICKED_ITEMS_LIST contains multiple ITEM_PICKER instances
-         * Each ITEM_PICKER contains a component and a command
+        /**
+         * As we may be saving changes across multiple sheets,
+         * we need to first determine which changes need to be made to which sheet.
+         * To this end, we perform the following:
+         * 1. Save the "path" of the currently displayed sheet
+         * 2. Create a MAP of <SheetPath:ChangeList> changes that need to be made
+         * 3. Push UNDO actions to appropriate sheets
+         * 4. Perform all the update actions
+         * 5. Reset the sheet view to the current sheet
          */
 
-        auto pickerList = PICKED_ITEMS_LIST();
+        auto currentSheet = m_parent->GetCurrentSheet();
+
+        //! Create a map of changes required for each sheet
+        std::map<wxString, SheetUndoList> undoSheetMap;
 
         // List of components that have changed
         auto changed = m_bom->GetChangedComponents();
 
         ITEM_PICKER picker;
 
-        for( auto cmp : changed )
+        // Iterate through each of the components that were changed
+        for( auto ref : changed )
         {
+            // Extract the SCH_COMPONENT* object
+            auto cmp = ref.GetComp();
+
+            wxString path = ref.GetSheetPath().Path();
+
             // Push the component into the picker list
             picker = ITEM_PICKER( cmp, UR_CHANGED );
             picker.SetFlags( cmp->GetFlags() );
-            //picker.SetLink( DuplicateStruct( cmp, true ) );
 
-            pickerList.PushItem( picker );
+
+            /*
+             * If there is not currently an undo list for the given sheet,
+             * create an empty one
+             */
+
+            if( undoSheetMap.count( path ) == 0 )
+            {
+                SheetUndoList newList;
+
+                newList.path = ref.GetSheetPath();
+
+                undoSheetMap[path] = newList;
+            }
+
+            auto& pickerList = undoSheetMap[path];
+
+            pickerList.items.PushItem( picker );
         }
 
-        if( pickerList.GetCount() > 0 )
+        // Iterate through each sheet that needs updating
+        for( auto it = undoSheetMap.begin(); it != undoSheetMap.end(); ++it )
         {
-            m_parent->SaveCopyInUndoList( pickerList, UR_CHANGED );
-            m_bom->ApplyFieldChanges();
-            m_parent->Refresh();
+            auto undo = it->second;
+
+            m_parent->SetCurrentSheet( undo.path );
+            m_parent->SaveCopyInUndoList( undo.items, UR_CHANGED );
+            m_parent->OnModify();
         }
 
+        // Apply all the field changes
+        m_bom->ApplyFieldChanges();
+
+        // Redraw the current sheet and mark as dirty
+        m_parent->Refresh();
         m_parent->OnModify();
+
+        // Reset the view to where we left the user
+        m_parent->SetCurrentSheet(currentSheet);
+
+
     }
 
     return true;
-- 
2.7.4

From 013dfaf7e7e168b7d5653b3f76c55a1851790f35 Mon Sep 17 00:00:00 2001
From: Oliver Walters <oliver.henry.walters@xxxxxxxxx>
Date: Tue, 25 Apr 2017 12:55:49 +1000
Subject: [PATCH 8/8] Removed BOM functionality

- Removed ability to generate BOM to file
- Removed Save/Cancel window when closing table
- No longer updates table <after> table is closed
- Bugfix for field names (previously comparison was case insensitive)
---
 eeschema/CMakeLists.txt                     |   5 +-
 eeschema/bom_exporter.cpp                   | 420 ----------------------------
 eeschema/bom_exporter.h                     | 123 --------
 eeschema/bom_table_column.cpp               |   2 +-
 eeschema/bom_table_model.cpp                |  10 +-
 eeschema/dialogs/dialog_bom_editor.cpp      | 178 ++----------
 eeschema/dialogs/dialog_bom_editor.h        |   8 +-
 eeschema/dialogs/dialog_bom_editor_base.cpp |  38 +--
 eeschema/dialogs/dialog_bom_editor_base.fbp | 314 +--------------------
 eeschema/dialogs/dialog_bom_editor_base.h   |  14 +-
 10 files changed, 44 insertions(+), 1068 deletions(-)
 delete mode 100644 eeschema/bom_exporter.cpp
 delete mode 100644 eeschema/bom_exporter.h

diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt
index fd1135e..8624b1b 100644
--- a/eeschema/CMakeLists.txt
+++ b/eeschema/CMakeLists.txt
@@ -25,8 +25,8 @@ set( EESCHEMA_DLGS
     dialogs/dialog_annotate_base.cpp
     dialogs/dialog_bom.cpp
     dialogs/dialog_bom_base.cpp
-	dialogs/dialog_bom_editor.cpp
-	dialogs/dialog_bom_editor_base.cpp
+    dialogs/dialog_bom_editor.cpp
+    dialogs/dialog_bom_editor_base.cpp
     dialogs/dialog_bom_cfg_keywords.cpp
     dialogs/dialog_choose_component.cpp
     dialogs/dialog_lib_edit_text.cpp
@@ -87,7 +87,6 @@ set( EESCHEMA_SRCS
     backanno.cpp
     block.cpp
     block_libedit.cpp
-    bom_exporter.cpp
     bom_table_model.cpp
     bom_table_column.cpp
     busentry.cpp
diff --git a/eeschema/bom_exporter.cpp b/eeschema/bom_exporter.cpp
deleted file mode 100644
index 0c2a43f..0000000
--- a/eeschema/bom_exporter.cpp
+++ /dev/null
@@ -1,420 +0,0 @@
-/*
-* This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2017 Oliver Walters
- * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * 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 "bom_exporter.h"
-
-/**
- * BOM_FILE_WRITER class (pure virtual)
- */
-BOM_FILE_WRITER::BOM_FILE_WRITER() :
-    m_includeExtraData( true ),
-    m_showRowNumbers( true )
-{
-}
-
-void BOM_FILE_WRITER::SetHeader( const wxArrayString aHeader )
-{
-    m_bomHeader = aHeader;
-}
-
-void BOM_FILE_WRITER::AddLine( wxArrayString aLine )
-{
-    m_bomLines.push_back( aLine );
-}
-
-/**
- * Function ExtraDataPairs
- * Format extra data for writing to file
- */
-wxArrayString BOM_FILE_WRITER::ExtraDataPairs()
-{
-    wxArrayString pairs;
-
-    if( m_groupCount != m_componentCount )
-    {
-        pairs.Add( DataPair( _( "Group Count" ), m_groupCount ) );
-    }
-
-    pairs.Add( DataPair( _( "Component Count" ), m_componentCount ) );
-    pairs.Add( DataPair( _( "Schematic Title" ), m_schematicTitle ) );
-    pairs.Add( DataPair( _( "Schematic Date" ), m_schematicDate ) );
-    pairs.Add( DataPair( _( "Schematic Version" ), m_schematicVersion ) );
-    pairs.Add( DataPair( _( "KiCad Version" ), m_kicadVersion ) );
-
-    return pairs;
-}
-
-BOM_CSV_WRITER::BOM_CSV_WRITER( wxChar aDelim ) :
-        BOM_FILE_WRITER()
-{
-    m_delim = aDelim;
-}
-
-/**
- * Function WriteToFile
- * Write delimited data to file
- */
-bool BOM_CSV_WRITER::WriteToFile( wxFile& aFile )
-{
-
-    // Generate table header
-    wxString line = wxJoin( EscapeLine( m_bomHeader ), m_delim )+ "\n";
-
-    if( m_showRowNumbers )
-    {
-        line = m_delim + line;
-    }
-
-    if( !aFile.Write( line ))
-    {
-        return false;
-    }
-
-    // Write each line in the file
-    for( unsigned int ii=0; ii<m_bomLines.size(); ii++ )
-    {
-        line = wxJoin( EscapeLine( m_bomLines[ii]), m_delim ) + "\n";
-
-        if( m_showRowNumbers )
-        {
-            line = wxString::Format( _( "%i" ), ii+1 ) + m_delim + line;
-        }
-
-        if( !aFile.Write( line ) )
-        {
-            return false;
-        }
-    }
-
-    // Write extra options
-    if( m_includeExtraData )
-    {
-        wxString extra;
-
-        extra += "\n\n";
-
-        for( wxString pair : ExtraDataPairs() )
-        {
-            extra += pair;
-            extra += "\n";
-        }
-
-        if( !aFile.Write( extra ) )
-            return false;
-    }
-
-    // File writing successful
-    return true;
-}
-
-/**
- * Function DataPair
- * Combine two items into a delimited pair
- */
-wxString BOM_CSV_WRITER::DataPair( const wxString& aFirst, const wxString& aSecond )
-{
-    wxArrayString pair;
-
-    pair.Add( aFirst );
-    pair.Add( aSecond );
-
-    return wxJoin( pair, m_delim );
-}
-
-/**
- * Function EscapeLine
- * Any values that contain the delimiter are escaped with quotes
- */
-wxArrayString BOM_CSV_WRITER::EscapeLine( wxArrayString line )
-{
-    wxArrayString escaped;
-
-    for( wxString item : line )
-    {
-        if( item.Contains( m_delim ) &&
-            !item.StartsWith( "\"" ) &&
-            !item.EndsWith( "\"" ) )
-        {
-            item = "\"" + item + "\"";
-        }
-
-        escaped.Add( item );
-    }
-
-    return escaped;
-}
-
-BOM_HTML_WRITER::BOM_HTML_WRITER() :
-        BOM_FILE_WRITER()
-{
-    // Strings to check for hyperlinkable text
-    m_linkChecks.Add( "http:*" );
-    m_linkChecks.Add( "https:* " );
-    m_linkChecks.Add( "ftp:*" );
-    m_linkChecks.Add( "www.*" );
-    m_linkChecks.Add( "*.pdf" );
-    m_linkChecks.Add( "*.html" );
-    m_linkChecks.Add( "*.htm" );
-}
-
-/**
- * Function WriteToFile
- * Write HTML BoM Data
- */
-bool BOM_HTML_WRITER::WriteToFile( wxFile& aFile )
-{
-    // Write HTML header
-    if( !aFile.Write( HtmlHeader() ) )
-        return false;
-
-    if( m_includeExtraData )
-    {
-        if( !aFile.Write( ExtraData() ) )
-            return false;
-    }
-
-    // Table data
-    wxString tableTitle = "<h2>";
-
-    tableTitle += _( "Bill of Materials" );
-    tableTitle += "</h2>\n";
-
-    if( !aFile.Write( tableTitle ) )
-        return false;
-
-    if( !aFile.Write( "<table border=\"1\">\n" ) )
-        return false;
-
-    if( !aFile.Write( TableHeader( m_bomHeader ) ) )
-        return false;
-
-    // Write each line of the BOM
-    for( unsigned int ii=0; ii<m_bomLines.size(); ii++ )
-    {
-        if( !aFile.Write( TableRow( ii+1, m_bomLines[ii] ) ) )
-            return false;
-    }
-
-    if( !aFile.Write( "</table>\n" ) )
-        return false;
-
-    if( !aFile.Write( HtmlFooter() ) )
-        return false;
-
-    return true;
-}
-
-wxString BOM_HTML_WRITER::HtmlHeader()
-{
-    wxString header = wxEmptyString;
-
-    header += "<html>\n<head>\n";
-    //TODO - Project title
-    header += "<title>";
-    header += m_schematicTitle;
-    header += "</title>\n";
-
-    header += HtmlMetaTag( "charset", "UTF-8" ) + "\n";
-
-    //TODO - KiCad reference data here
-
-    header += "</head>\n\n";
-
-    header += "<body>\n";
-
-    return header;
-}
-
-wxString BOM_HTML_WRITER::HtmlFooter()
-{
-    wxString footer = wxEmptyString;
-
-    footer += "</body>\n\n";
-    footer += "</html>\n";
-
-    return footer;
-}
-
-wxString BOM_HTML_WRITER::HtmlMetaTag( const wxString aTitle, const wxString aData )
-{
-    wxString tag = "<meta name=\"";
-
-    tag += aTitle + "\"";
-    tag += " content=\"";
-    tag += aData + "\"";
-
-    tag += ">";
-
-    return tag;
-}
-
-/**
- * Function ExtraData
- * Write extra project information
- */
-wxString BOM_HTML_WRITER::ExtraData()
-{
-    wxString extra;
-
-    extra += "<h2>";
-    extra += _( "Project details" );
-    extra += "</h2>\n";
-
-    extra += "<table border=\"1\">\n";
-
-    for( wxString pair : ExtraDataPairs() )
-    {
-        extra += pair + "\n";
-    }
-
-    extra += "</table>\n";
-
-    return extra;
-}
-
-/**
- * Function LinkText
- * Automatically detect linkable text, and wrap it in <a> tag
- * @aText - Text to (potentially) link
- */
-wxString BOM_HTML_WRITER::LinkText( const wxString& aText )
-{
-    // Should we provide a link to the text?
-    wxString lower = aText.Lower();
-
-    bool found = false;
-
-    for( wxString check : m_linkChecks )
-    {
-        if( lower.Matches( check ) )
-        {
-            found = true;
-            break;
-        }
-    }
-
-    if( found )
-    {
-        wxString link = "<a href=\"";
-
-        link += aText;
-        link += "\">";
-        link += aText;
-        link += "</a>";
-
-        return link;
-    }
-    else
-    {
-        return aText;
-    }
-}
-
-wxString BOM_HTML_WRITER::TableHeader( const wxArrayString& aHeaderData )
-{
-    wxString header = "<tr>\n";
-
-    if( m_showRowNumbers )
-    {
-        header += "<th></th>\n";
-    }
-
-    for( wxString item : aHeaderData )
-    {
-        header += "<th align=\"center\">";
-        header += item;
-        header += "</th>";
-        header += "\n";
-    }
-
-    header += "</tr>\n";
-
-    return header;
-}
-
-wxString BOM_HTML_WRITER::DataPair( const wxString& aFirst, const wxString& aSecond )
-{
-    wxString html = "<tr>\n";
-
-    html += TableEntry( aFirst ) + "\n";
-    html += TableEntry( aSecond ) + "\n";
-
-    html += "</tr>\n";
-
-    return html;
-}
-
-/**
- * Function TableRow
- * Generate a single row of BOM data
- * @aRowNum is the number of the row
- * @aRowData is the array of data for the given row
- */
-wxString BOM_HTML_WRITER::TableRow( const int& aRowNum, const wxArrayString& aRowData )
-{
-    wxString row = wxEmptyString;
-
-    row += "<tr>\n";
-
-    if( m_showRowNumbers )
-    {
-        row += "<td>";
-        row += wxString::Format( "%i", aRowNum );
-        row += "</td>\n";
-    }
-
-    for( wxString data : aRowData )
-    {
-        row += TableEntry( data );
-        row += "\n";
-    }
-
-    row += "</tr>\n";
-
-    return row;
-}
-
-/**
- * Function TableEntry
- * Wrap a string in <td> tags
- * @aData is the text to be wrapped
- * @aColor is an (optional) HTML background color
- */
-wxString BOM_HTML_WRITER::TableEntry( wxString aData, wxString aColor )
-{
-    wxString cell = "<td align=\"center\"";
-
-    if( !aColor.IsEmpty() )
-    {
-        cell += " bgcolor=\"" + aColor + "\"";
-    }
-
-    cell += ">";
-
-    cell += LinkText( aData );
-
-    cell += "</td>";
-
-    return cell;
-}
diff --git a/eeschema/bom_exporter.h b/eeschema/bom_exporter.h
deleted file mode 100644
index 8ee2f34..0000000
--- a/eeschema/bom_exporter.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
-* This program source code file is part of KiCad, a free EDA CAD application.
- *
- * Copyright (C) 2017 Oliver Walters
- * Copyright (C) 2017 KiCad Developers, see CHANGELOG.TXT for contributors.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * 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
- */
-
-#ifndef EESCHEMA_BOM_EXPORTER_H_
-#define EESCHEMA_BOM_EXPORTER_H_
-
-#include <vector>
-#include <wx/file.h>
-
-#include "bom_table_column.h"
-#include "bom_table_model.h"
-
-enum BOM_EXPORT_TYPE
-{
-    BOM_EXPORT_CSV = 0,
-    BOM_EXPORT_HTML
-};
-
-class BOM_FILE_WRITER
-{
-public:
-    BOM_FILE_WRITER();
-    virtual ~BOM_FILE_WRITER() {};
-
-    virtual bool WriteToFile( wxFile& aFile ) = 0;
-
-    void SetHeader( const wxArrayString aHeader );
-    void AddLine( const wxArrayString aLine );
-
-    void IncludeExtraData( bool aInclude = true ) { m_includeExtraData = aInclude; }
-    void ShowRowNumbers( bool aShow = true ) { m_showRowNumbers = aShow; }
-
-    // Project information
-    void SetKicadVersion( const wxString aVersion ) { m_kicadVersion = aVersion; }
-    void SetSchematicTitle( const wxString aProject ) { m_schematicTitle = aProject; }
-    void SetSchematicVersion( const wxString aVersion ) { m_schematicVersion = aVersion; }
-    void SetSchematicDate( const wxString aDate ) { m_schematicDate = aDate; }
-
-    void SetGroupCount( unsigned int aCount ) { m_groupCount = wxString::Format( "%u", aCount ); }
-    void SetComponentCount( unsigned int aCount ) { m_componentCount = wxString::Format( "%u", aCount ); }
-
-protected:
-    wxArrayString ExtraDataPairs();
-    virtual wxString DataPair( const wxString& aFirst, const wxString& aSecond ) = 0;
-
-    wxArrayString m_bomHeader;
-    std::vector< wxArrayString > m_bomLines;
-
-    bool m_includeExtraData;
-    bool m_showRowNumbers;
-
-    // Extra details for BOM file
-    wxString m_kicadVersion;
-    wxString m_schematicTitle;
-    wxString m_schematicVersion;
-    wxString m_schematicDate;
-
-    wxString m_componentCount;
-    wxString m_groupCount;
-
-};
-
-class BOM_CSV_WRITER : public BOM_FILE_WRITER
-{
-public:
-    BOM_CSV_WRITER( wxChar aDelim=',' );
-
-    virtual bool WriteToFile( wxFile& aFile ) override;
-
-protected:
-    wxArrayString EscapeLine( wxArrayString line );
-    virtual wxString DataPair( const wxString& aFirst, const wxString& aSecond ) override;
-
-    wxChar m_delim;
-};
-
-class BOM_HTML_WRITER : public BOM_FILE_WRITER
-{
-public:
-    BOM_HTML_WRITER();
-
-    virtual bool WriteToFile( wxFile& aFile ) override;
-
-protected:
-    virtual wxString DataPair( const wxString& aFirst, const wxString& aSecond ) override;
-
-    wxString HtmlHeader();
-    wxString HtmlFooter();
-    wxString HtmlMetaTag( const wxString aTitle, const wxString aData );
-
-    wxString ExtraData();
-
-    wxString LinkText( const wxString& aText );
-
-    wxString TableHeader( const wxArrayString& aHeaderData );
-    wxString TableRow( const int& aRowNum, const wxArrayString& aRowData );
-    wxString TableEntry( wxString aData, wxString aColor = wxEmptyString );
-
-    wxArrayString m_linkChecks;
-};
-
-#endif /* EESCHEMA_BOM_EXPORTER_H_ */
diff --git a/eeschema/bom_table_column.cpp b/eeschema/bom_table_column.cpp
index 01b7120..ef27021 100644
--- a/eeschema/bom_table_column.cpp
+++ b/eeschema/bom_table_column.cpp
@@ -86,7 +86,7 @@ BOM_COLUMN* BOM_COLUMN_LIST::GetColumnByTitle( wxString aColTitle )
 {
     for( unsigned int ii=0; ii<Columns.size(); ii++ )
     {
-        if( Columns[ii] && Columns[ii]->Title().CmpNoCase( aColTitle ) == 0 )
+        if( Columns[ii] && Columns[ii]->Title().Cmp( aColTitle ) == 0 )
             return Columns[ii];
     }
 
diff --git a/eeschema/bom_table_model.cpp b/eeschema/bom_table_model.cpp
index 1005a78..d531dbd 100644
--- a/eeschema/bom_table_model.cpp
+++ b/eeschema/bom_table_model.cpp
@@ -682,6 +682,7 @@ void BOM_TABLE_COMPONENT::ApplyFieldChanges()
                     break;
                 }
 
+                // New field needs to be added?
                 if( !field && !value.IsEmpty() )
                 {
                     SCH_FIELD newField( wxPoint( 0, 0 ), -1, cmp, column->Title() );
@@ -1396,8 +1397,6 @@ void BOM_TABLE_MODEL::ApplyFieldChanges()
         if( !group )
             continue;
 
-        bool changed = false;
-
         for( auto& component : group->Components )
         {
             if( !component )
@@ -1406,15 +1405,8 @@ void BOM_TABLE_MODEL::ApplyFieldChanges()
             if( component->HasChanged() )
             {
                 component->ApplyFieldChanges();
-                ItemChanged( RowToItem( &*component ) );
-                changed = true;
             }
         }
-
-        if( changed )
-        {
-            ItemChanged( RowToItem( &*group ) );
-        }
     }
 }
 
diff --git a/eeschema/dialogs/dialog_bom_editor.cpp b/eeschema/dialogs/dialog_bom_editor.cpp
index 722cbd5..2b070b8 100644
--- a/eeschema/dialogs/dialog_bom_editor.cpp
+++ b/eeschema/dialogs/dialog_bom_editor.cpp
@@ -35,8 +35,6 @@
 #include <general.h>
 #include <class_library.h>
 
-#include <bom_exporter.h>
-
 #include "dialog_bom_editor.h"
 #include <bom_table_model.h>
 
@@ -112,31 +110,9 @@ typedef struct
  */
 bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
 {
-    bool saveChanges = false;
-
-    // If there are changed values, warn the user first
     if( m_bom->HaveFieldsChanged() )
     {
-        int result = DisplayExitDialog( this, _( "Changes exist in component table" ) );
-
-        switch( result )
-        {
-        // Save and exit
-        case wxID_YES:
-            saveChanges = true;
-            break;
-        // Cancel (do not exit)
-        case wxID_CANCEL:
-            return false;
-        // Do not save, exit
-        default:
-            return true;
-        }
-    }
-
-    if( saveChanges )
-    {
-        /**
+         /**
          * As we may be saving changes across multiple sheets,
          * we need to first determine which changes need to be made to which sheet.
          * To this end, we perform the following:
@@ -144,7 +120,7 @@ bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
          * 2. Create a MAP of <SheetPath:ChangeList> changes that need to be made
          * 3. Push UNDO actions to appropriate sheets
          * 4. Perform all the update actions
-         * 5. Reset the sheet view to the current sheet
+         * 5. Reset the view to the current sheet
          */
 
         auto currentSheet = m_parent->GetCurrentSheet();
@@ -169,7 +145,6 @@ bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
             picker = ITEM_PICKER( cmp, UR_CHANGED );
             picker.SetFlags( cmp->GetFlags() );
 
-
             /*
              * If there is not currently an undo list for the given sheet,
              * create an empty one
@@ -199,7 +174,7 @@ bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
             m_parent->OnModify();
         }
 
-        // Apply all the field changes
+        // Make all component changes
         m_bom->ApplyFieldChanges();
 
         // Redraw the current sheet and mark as dirty
@@ -209,7 +184,6 @@ bool DIALOG_BOM_EDITOR::TransferDataFromWindow()
         // Reset the view to where we left the user
         m_parent->SetCurrentSheet(currentSheet);
 
-
     }
 
     return true;
@@ -352,131 +326,6 @@ void DIALOG_BOM_EDITOR::OnUpdateUI( wxUpdateUIEvent& event )
     UpdateTitle();
 }
 
-/**
- * Called when the "Export BOM" button is pressed
- * Extract row data from the component table,
- * and export it to a BOM file
- */
-void DIALOG_BOM_EDITOR::OnExportBOM( wxCommandEvent& event )
-{
-    // Allowable BOM file formats
-    static const wxString wildcard = _( "BOM Files" ) + wxString( " *.csv, *.tsv, *.html)|*.csv;*.tsv;*.htm;*.html" );
-
-    wxFileDialog bomFileDialog(this, _("Select BOM file"),
-                Prj().GetProjectPath(),
-                wxEmptyString,
-                wildcard,
-                wxFD_SAVE | wxFD_OVERWRITE_PROMPT );
-
-
-    if( bomFileDialog.ShowModal() == wxID_CANCEL )
-    {
-        return;
-    }
-
-    // Ensure the component groups are correct
-    m_bom->ReloadTable();
-
-    wxString msg;
-
-    wxFileName filename = bomFileDialog.GetPath();
-
-    // Ensure correct file format
-    BOM_FILE_WRITER* writer;
-
-    wxString fn = filename.GetFullPath().Lower();
-
-    // CSV File
-    if( fn.EndsWith( ".csv" ) )
-    {
-        writer = new BOM_CSV_WRITER();
-    }
-    // TSV file
-    else if( fn.EndsWith( ".tsv" ) )
-    {
-        writer = new BOM_CSV_WRITER( '\t' );
-    }
-    // HTML file
-    else if( fn.EndsWith( ".html" ) || fn.EndsWith( ".htm" ) )
-    {
-        writer = new BOM_HTML_WRITER();
-    }
-    // Unknown file!
-    else
-    {
-        msg.Printf("%s:\n%s",
-                   _( "Unsupported file type" ),
-                   filename.GetExt() );
-
-        wxMessageBox( msg );
-        return;
-    }
-
-    // Set export preferences
-    writer->IncludeExtraData( m_includeProjectData->GetValue() );
-    writer->ShowRowNumbers( m_showRowNumbers->GetValue() );
-
-    // Project information
-    writer->SetKicadVersion( GetBuildVersion() );
-
-    // Extract sheet info from top-level sheet
-    if( g_RootSheet )
-    {
-        const TITLE_BLOCK& tb = g_RootSheet->GetScreen()->GetTitleBlock();
-
-        writer->SetSchematicDate( tb.GetDate() );
-        writer->SetSchematicVersion( tb.GetRevision() );
-        writer->SetSchematicTitle( tb.GetTitle() );
-    }
-
-    std::vector<BOM_COLUMN*> columns;
-    wxArrayString headings;
-
-    // Extract the visible column data
-    for( auto column : m_bom->ColumnList.Columns )
-    {
-        if( column && column->IsVisible() )
-        {
-            columns.push_back( column );
-            headings.push_back( column->Title() );
-        }
-    }
-
-    writer->SetHeader( headings );
-
-    // Extract the row data
-    for( unsigned int row=0; row<m_bom->GroupCount(); row++ )
-    {
-        writer->AddLine( m_bom->GetRowData( row, columns ) );
-    }
-
-    writer->SetGroupCount( m_bom->GroupCount() );
-    writer->SetComponentCount( m_bom->ComponentCount() );
-
-    // Open the BOM file for writing
-    wxFile bomFile( filename.GetFullPath(), wxFile::write );
-
-    if( bomFile.IsOpened() )
-    {
-        if( !writer->WriteToFile( bomFile ) )
-        {
-            msg.Printf( "%s:\n%s",
-                        _( "Error writing BOM file" ),
-                        filename.GetFullPath() );
-        }
-
-        bomFile.Close();
-    }
-    else
-    {
-        msg.Printf( "%s:\n%s",
-                    _( "Error opening BOM file" ),
-                    filename.GetFullPath() );
-
-        wxMessageBox( msg );
-    }
-}
-
 void DIALOG_BOM_EDITOR::OnTableValueChanged( wxDataViewEvent& event )
 {
     Update();
@@ -499,3 +348,24 @@ void DIALOG_BOM_EDITOR::OnRevertFieldChanges( wxCommandEvent& event )
         }
     }
 }
+
+// Called when a cell is left-clicked
+void DIALOG_BOM_EDITOR::OnTableItemActivated( wxDataViewEvent& event )
+{
+    /* TODO
+     * - Focus on component selected in SCH_FRAME
+     */
+
+    event.Skip();
+}
+// Called when a cell is right-clicked
+void DIALOG_BOM_EDITOR::OnTableItemContextMenu( wxDataViewEvent& event )
+{
+    /* TODO
+     * - Display contect menu
+     * - Option to revert local changes if changes have been made
+     * - Option to select footprint if FOOTPRINT column selected
+     */
+
+    event.Skip();
+}
diff --git a/eeschema/dialogs/dialog_bom_editor.h b/eeschema/dialogs/dialog_bom_editor.h
index 0f79e98..90a18ff 100644
--- a/eeschema/dialogs/dialog_bom_editor.h
+++ b/eeschema/dialogs/dialog_bom_editor.h
@@ -69,8 +69,6 @@ private:
     virtual void OnColumnItemToggled( wxDataViewEvent& event ) override;
     virtual void OnGroupComponentsToggled( wxCommandEvent& event ) override;
 
-    virtual void OnExportBOM( wxCommandEvent& event ) override;
-
     virtual void OnRevertFieldChanges( wxCommandEvent& event ) override;
 
     virtual void OnRegroupComponents( wxCommandEvent& event ) override;
@@ -78,6 +76,12 @@ private:
     // Called after a value in the table has changed
     virtual void OnTableValueChanged( wxDataViewEvent& event ) override;
 
+    // Called when a cell is left-clicked
+    virtual void OnTableItemActivated( wxDataViewEvent& event ) override;
+
+    // Called when a cell is right-clicked
+    virtual void OnTableItemContextMenu( wxDataViewEvent& event ) override;
+
     void UpdateTitle( void );
 
     virtual void OnUpdateUI( wxUpdateUIEvent& event ) override;
diff --git a/eeschema/dialogs/dialog_bom_editor_base.cpp b/eeschema/dialogs/dialog_bom_editor_base.cpp
index d83d34d..018e2b2 100644
--- a/eeschema/dialogs/dialog_bom_editor_base.cpp
+++ b/eeschema/dialogs/dialog_bom_editor_base.cpp
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Mar 22 2017)
+// C++ code generated with wxFormBuilder (version Apr  1 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -15,9 +15,10 @@ BEGIN_EVENT_TABLE( DIALOG_BOM_EDITOR_BASE, DIALOG_SHIM )
 	EVT_BUTTON( ID_BUTTON_REGROUP, DIALOG_BOM_EDITOR_BASE::_wxFB_OnRegroupComponents )
 	EVT_BUTTON( ID_BUTTON_REVERT_CHANGES, DIALOG_BOM_EDITOR_BASE::_wxFB_OnRevertFieldChanges )
 	EVT_DATAVIEW_ITEM_VALUE_CHANGED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnColumnItemToggled )
-	EVT_BUTTON( wxID_BOM_BUTTON_EXPORT, DIALOG_BOM_EDITOR_BASE::_wxFB_OnExportBOM )
 	EVT_DATAVIEW_COLUMN_REORDERED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnBomColumReordered )
 	EVT_DATAVIEW_COLUMN_SORTED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnBomColumnSorted )
+	EVT_DATAVIEW_ITEM_ACTIVATED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnTableItemActivated )
+	EVT_DATAVIEW_ITEM_CONTEXT_MENU( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnTableItemContextMenu )
 	EVT_DATAVIEW_ITEM_EDITING_DONE( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnTableValueChanged )
 	EVT_DATAVIEW_SELECTION_CHANGED( wxID_ANY, DIALOG_BOM_EDITOR_BASE::_wxFB_OnSelectionChanged )
 END_EVENT_TABLE()
@@ -79,39 +80,6 @@ DIALOG_BOM_EDITOR_BASE::DIALOG_BOM_EDITOR_BASE( wxWindow* parent, wxWindowID id,
 	
 	bSizer6->Add( 0, 0, 0, wxEXPAND, 5 );
 	
-	wxStaticBoxSizer* sbSizer2;
-	sbSizer2 = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Export options") ), wxVERTICAL );
-	
-	m_includeProjectData = new wxCheckBox( sbSizer2->GetStaticBox(), wxID_BOM_OPT_INC_PRJ_DATA, _("Include project data"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_includeProjectData->SetValue(true); 
-	m_includeProjectData->SetToolTip( _("Include project information in BOM file") );
-	
-	sbSizer2->Add( m_includeProjectData, 0, wxALL|wxEXPAND, 5 );
-	
-	m_showRowNumbers = new wxCheckBox( sbSizer2->GetStaticBox(), wxID_BOM_OPT_SHOW_ROW_NUMS, _("Show row numbers"), wxDefaultPosition, wxDefaultSize, 0 );
-	m_showRowNumbers->SetValue(true); 
-	m_showRowNumbers->SetToolTip( _("Show BOM row numbers ") );
-	
-	sbSizer2->Add( m_showRowNumbers, 0, wxALL|wxEXPAND, 5 );
-	
-	
-	sbSizer2->Add( 0, 0, 1, wxEXPAND, 5 );
-	
-	wxBoxSizer* bSizer13;
-	bSizer13 = new wxBoxSizer( wxHORIZONTAL );
-	
-	
-	bSizer13->Add( 0, 0, 1, wxEXPAND, 5 );
-	
-	m_exportButton = new wxButton( sbSizer2->GetStaticBox(), wxID_BOM_BUTTON_EXPORT, _("Export BOM"), wxDefaultPosition, wxDefaultSize, 0 );
-	bSizer13->Add( m_exportButton, 0, wxALL, 5 );
-	
-	
-	sbSizer2->Add( bSizer13, 0, wxEXPAND, 5 );
-	
-	
-	bSizer6->Add( sbSizer2, 0, wxEXPAND, 5 );
-	
 	wxStaticBoxSizer* sbSizer4;
 	sbSizer4 = new wxStaticBoxSizer( new wxStaticBox( m_leftPanel, wxID_ANY, _("Apply changes") ), wxVERTICAL );
 	
diff --git a/eeschema/dialogs/dialog_bom_editor_base.fbp b/eeschema/dialogs/dialog_bom_editor_base.fbp
index 2fcc929..b6427b0 100644
--- a/eeschema/dialogs/dialog_bom_editor_base.fbp
+++ b/eeschema/dialogs/dialog_bom_editor_base.fbp
@@ -730,316 +730,6 @@
                                                 <object class="sizeritem" expanded="1">
                                                     <property name="border">5</property>
                                                     <property name="flag">wxEXPAND</property>
-                                                    <property name="proportion">0</property>
-                                                    <object class="wxStaticBoxSizer" expanded="0">
-                                                        <property name="id">wxID_ANY</property>
-                                                        <property name="label">Export options</property>
-                                                        <property name="minimum_size"></property>
-                                                        <property name="name">sbSizer2</property>
-                                                        <property name="orient">wxVERTICAL</property>
-                                                        <property name="parent">1</property>
-                                                        <property name="permission">none</property>
-                                                        <event name="OnUpdateUI"></event>
-                                                        <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="0">
-                                                                <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="checked">1</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_BOM_OPT_INC_PRJ_DATA</property>
-                                                                <property name="label">Include project data</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_includeProjectData</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"></property>
-                                                                <property name="toolbar_pane">0</property>
-                                                                <property name="tooltip">Include project information in BOM file</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="OnChar"></event>
-                                                                <event name="OnCheckBox"></event>
-                                                                <event name="OnEnterWindow"></event>
-                                                                <event name="OnEraseBackground"></event>
-                                                                <event name="OnKeyDown"></event>
-                                                                <event name="OnKeyUp"></event>
-                                                                <event name="OnKillFocus"></event>
-                                                                <event name="OnLeaveWindow"></event>
-                                                                <event name="OnLeftDClick"></event>
-                                                                <event name="OnLeftDown"></event>
-                                                                <event name="OnLeftUp"></event>
-                                                                <event name="OnMiddleDClick"></event>
-                                                                <event name="OnMiddleDown"></event>
-                                                                <event name="OnMiddleUp"></event>
-                                                                <event name="OnMotion"></event>
-                                                                <event name="OnMouseEvents"></event>
-                                                                <event name="OnMouseWheel"></event>
-                                                                <event name="OnPaint"></event>
-                                                                <event name="OnRightDClick"></event>
-                                                                <event name="OnRightDown"></event>
-                                                                <event name="OnRightUp"></event>
-                                                                <event name="OnSetFocus"></event>
-                                                                <event name="OnSize"></event>
-                                                                <event name="OnUpdateUI"></event>
-                                                            </object>
-                                                        </object>
-                                                        <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="0">
-                                                                <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="checked">1</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_BOM_OPT_SHOW_ROW_NUMS</property>
-                                                                <property name="label">Show row numbers</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_showRowNumbers</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"></property>
-                                                                <property name="toolbar_pane">0</property>
-                                                                <property name="tooltip">Show BOM row numbers </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="OnChar"></event>
-                                                                <event name="OnCheckBox"></event>
-                                                                <event name="OnEnterWindow"></event>
-                                                                <event name="OnEraseBackground"></event>
-                                                                <event name="OnKeyDown"></event>
-                                                                <event name="OnKeyUp"></event>
-                                                                <event name="OnKillFocus"></event>
-                                                                <event name="OnLeaveWindow"></event>
-                                                                <event name="OnLeftDClick"></event>
-                                                                <event name="OnLeftDown"></event>
-                                                                <event name="OnLeftUp"></event>
-                                                                <event name="OnMiddleDClick"></event>
-                                                                <event name="OnMiddleDown"></event>
-                                                                <event name="OnMiddleUp"></event>
-                                                                <event name="OnMotion"></event>
-                                                                <event name="OnMouseEvents"></event>
-                                                                <event name="OnMouseWheel"></event>
-                                                                <event name="OnPaint"></event>
-                                                                <event name="OnRightDClick"></event>
-                                                                <event name="OnRightDown"></event>
-                                                                <event name="OnRightUp"></event>
-                                                                <event name="OnSetFocus"></event>
-                                                                <event name="OnSize"></event>
-                                                                <event name="OnUpdateUI"></event>
-                                                            </object>
-                                                        </object>
-                                                        <object class="sizeritem" expanded="0">
-                                                            <property name="border">5</property>
-                                                            <property name="flag">wxEXPAND</property>
-                                                            <property name="proportion">1</property>
-                                                            <object class="spacer" expanded="0">
-                                                                <property name="height">0</property>
-                                                                <property name="permission">protected</property>
-                                                                <property name="width">0</property>
-                                                            </object>
-                                                        </object>
-                                                        <object class="sizeritem" expanded="0">
-                                                            <property name="border">5</property>
-                                                            <property name="flag">wxEXPAND</property>
-                                                            <property name="proportion">0</property>
-                                                            <object class="wxBoxSizer" expanded="0">
-                                                                <property name="minimum_size"></property>
-                                                                <property name="name">bSizer13</property>
-                                                                <property name="orient">wxHORIZONTAL</property>
-                                                                <property name="permission">none</property>
-                                                                <object class="sizeritem" expanded="0">
-                                                                    <property name="border">5</property>
-                                                                    <property name="flag">wxEXPAND</property>
-                                                                    <property name="proportion">1</property>
-                                                                    <object class="spacer" expanded="0">
-                                                                        <property name="height">0</property>
-                                                                        <property name="permission">protected</property>
-                                                                        <property name="width">0</property>
-                                                                    </object>
-                                                                </object>
-                                                                <object class="sizeritem" expanded="0">
-                                                                    <property name="border">5</property>
-                                                                    <property name="flag">wxALL</property>
-                                                                    <property name="proportion">0</property>
-                                                                    <object class="wxButton" expanded="0">
-                                                                        <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">0</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_BOM_BUTTON_EXPORT</property>
-                                                                        <property name="label">Export BOM</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_exportButton</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"></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">OnExportBOM</event>
-                                                                        <event name="OnChar"></event>
-                                                                        <event name="OnEnterWindow"></event>
-                                                                        <event name="OnEraseBackground"></event>
-                                                                        <event name="OnKeyDown"></event>
-                                                                        <event name="OnKeyUp"></event>
-                                                                        <event name="OnKillFocus"></event>
-                                                                        <event name="OnLeaveWindow"></event>
-                                                                        <event name="OnLeftDClick"></event>
-                                                                        <event name="OnLeftDown"></event>
-                                                                        <event name="OnLeftUp"></event>
-                                                                        <event name="OnMiddleDClick"></event>
-                                                                        <event name="OnMiddleDown"></event>
-                                                                        <event name="OnMiddleUp"></event>
-                                                                        <event name="OnMotion"></event>
-                                                                        <event name="OnMouseEvents"></event>
-                                                                        <event name="OnMouseWheel"></event>
-                                                                        <event name="OnPaint"></event>
-                                                                        <event name="OnRightDClick"></event>
-                                                                        <event name="OnRightDown"></event>
-                                                                        <event name="OnRightUp"></event>
-                                                                        <event name="OnSetFocus"></event>
-                                                                        <event name="OnSize"></event>
-                                                                        <event name="OnUpdateUI"></event>
-                                                                    </object>
-                                                                </object>
-                                                            </object>
-                                                        </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="wxStaticBoxSizer" expanded="1">
                                                         <property name="id">wxID_ANY</property>
@@ -1191,11 +881,11 @@
                                                         <event name="OnDataViewCtrlColumnHeaderRightClick"></event>
                                                         <event name="OnDataViewCtrlColumnReordered">OnBomColumReordered</event>
                                                         <event name="OnDataViewCtrlColumnSorted">OnBomColumnSorted</event>
-                                                        <event name="OnDataViewCtrlItemActivated"></event>
+                                                        <event name="OnDataViewCtrlItemActivated">OnTableItemActivated</event>
                                                         <event name="OnDataViewCtrlItemBeginDrag"></event>
                                                         <event name="OnDataViewCtrlItemCollapsed"></event>
                                                         <event name="OnDataViewCtrlItemCollapsing"></event>
-                                                        <event name="OnDataViewCtrlItemContextMenu"></event>
+                                                        <event name="OnDataViewCtrlItemContextMenu">OnTableItemContextMenu</event>
                                                         <event name="OnDataViewCtrlItemDrop"></event>
                                                         <event name="OnDataViewCtrlItemDropPossible"></event>
                                                         <event name="OnDataViewCtrlItemEditingDone">OnTableValueChanged</event>
diff --git a/eeschema/dialogs/dialog_bom_editor_base.h b/eeschema/dialogs/dialog_bom_editor_base.h
index 87d70ef..c7689db 100644
--- a/eeschema/dialogs/dialog_bom_editor_base.h
+++ b/eeschema/dialogs/dialog_bom_editor_base.h
@@ -1,5 +1,5 @@
 ///////////////////////////////////////////////////////////////////////////
-// C++ code generated with wxFormBuilder (version Mar 22 2017)
+// C++ code generated with wxFormBuilder (version Apr  1 2017)
 // http://www.wxformbuilder.org/
 //
 // PLEASE DO "NOT" EDIT THIS FILE!
@@ -33,9 +33,6 @@ class DIALOG_SHIM;
 #define OPT_GROUP_COMPONENTS 1000
 #define ID_BUTTON_REGROUP 1001
 #define ID_BUTTON_REVERT_CHANGES 1002
-#define wxID_BOM_OPT_INC_PRJ_DATA 1003
-#define wxID_BOM_OPT_SHOW_ROW_NUMS 1004
-#define wxID_BOM_BUTTON_EXPORT 1005
 
 ///////////////////////////////////////////////////////////////////////////////
 /// Class DIALOG_BOM_EDITOR_BASE
@@ -51,9 +48,10 @@ class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
 		void _wxFB_OnRegroupComponents( wxCommandEvent& event ){ OnRegroupComponents( event ); }
 		void _wxFB_OnRevertFieldChanges( wxCommandEvent& event ){ OnRevertFieldChanges( event ); }
 		void _wxFB_OnColumnItemToggled( wxDataViewEvent& event ){ OnColumnItemToggled( event ); }
-		void _wxFB_OnExportBOM( wxCommandEvent& event ){ OnExportBOM( event ); }
 		void _wxFB_OnBomColumReordered( wxDataViewEvent& event ){ OnBomColumReordered( event ); }
 		void _wxFB_OnBomColumnSorted( wxDataViewEvent& event ){ OnBomColumnSorted( event ); }
+		void _wxFB_OnTableItemActivated( wxDataViewEvent& event ){ OnTableItemActivated( event ); }
+		void _wxFB_OnTableItemContextMenu( wxDataViewEvent& event ){ OnTableItemContextMenu( event ); }
 		void _wxFB_OnTableValueChanged( wxDataViewEvent& event ){ OnTableValueChanged( event ); }
 		void _wxFB_OnSelectionChanged( wxDataViewEvent& event ){ OnSelectionChanged( event ); }
 		
@@ -66,9 +64,6 @@ class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
 		wxButton* m_regroupComponentsButton;
 		wxButton* m_reloadTableButton;
 		wxDataViewListCtrl* m_columnListCtrl;
-		wxCheckBox* m_includeProjectData;
-		wxCheckBox* m_showRowNumbers;
-		wxButton* m_exportButton;
 		wxStdDialogButtonSizer* m_sdbSizer1;
 		wxButton* m_sdbSizer1OK;
 		wxButton* m_sdbSizer1Cancel;
@@ -81,9 +76,10 @@ class DIALOG_BOM_EDITOR_BASE : public DIALOG_SHIM
 		virtual void OnRegroupComponents( wxCommandEvent& event ) { event.Skip(); }
 		virtual void OnRevertFieldChanges( wxCommandEvent& event ) { event.Skip(); }
 		virtual void OnColumnItemToggled( wxDataViewEvent& event ) { event.Skip(); }
-		virtual void OnExportBOM( wxCommandEvent& event ) { event.Skip(); }
 		virtual void OnBomColumReordered( wxDataViewEvent& event ) { event.Skip(); }
 		virtual void OnBomColumnSorted( wxDataViewEvent& event ) { event.Skip(); }
+		virtual void OnTableItemActivated( wxDataViewEvent& event ) { event.Skip(); }
+		virtual void OnTableItemContextMenu( wxDataViewEvent& event ) { event.Skip(); }
 		virtual void OnTableValueChanged( wxDataViewEvent& event ) { event.Skip(); }
 		virtual void OnSelectionChanged( wxDataViewEvent& event ) { event.Skip(); }
 		
-- 
2.7.4


Follow ups

References