def create_ui(self):
        from barcode_scanner.gtk_matplotlib import ScannerView

        super(MetaDataDialog, self).create_ui()
        self.scanner_view = ScannerView(self.scanner)
        self.scanner_view.widget.show_all()

        self.scanner_window = gtk.Dialog(title='Barcode scan',
                                         parent=self.window,
                                         flags=gtk.DIALOG_MODAL |
                                         gtk.DIALOG_DESTROY_WITH_PARENT)
        (self.scanner_window.get_content_area()
         .pack_start(self.scanner_view.widget))
        self.scanner.start()
class MetaDataDialog(SchemaDialog):
    def __init__(self, schema, pipeline_command=None, **kwargs):
        from barcode_scanner.scanner import BarcodeScanner

        super(MetaDataDialog, self).__init__(schema, **kwargs)
        self.scanner = BarcodeScanner(pipeline_command)

    def create_ui(self):
        from barcode_scanner.gtk_matplotlib import ScannerView

        super(MetaDataDialog, self).create_ui()
        self.scanner_view = ScannerView(self.scanner)
        self.scanner_view.widget.show_all()

        self.scanner_window = gtk.Dialog(title='Barcode scan',
                                         parent=self.window,
                                         flags=gtk.DIALOG_MODAL |
                                         gtk.DIALOG_DESTROY_WITH_PARENT)
        (self.scanner_window.get_content_area()
         .pack_start(self.scanner_view.widget))
        self.scanner.start()

    def create_form_view(self, values=None, use_markup=True):
        super(MetaDataDialog, self).create_form_view(values, use_markup)
        table = self.form_view.widget.get_children()[0]
        children = table.get_children()

        def on_symbols_found_i(scanner, np_img, symbols, row_i):
            from .proxy import proxy_for

            # Stop listening for `symbols-found` signal.
            scanner.disconnect(row_i['callback_ids']['symbol'])
            del row_i['callback_ids']['symbol']

            # Concatenate symbols text as comma-separated list.
            symbol_data = ', '.join([symbol_j['data'] for symbol_j in symbols])

            # Fill widget with scanned value (if possible).
            proxy = proxy_for(row_i['widget'])
            try:
                proxy.set_widget_value(symbol_data)
            except TypeError:
                logger.error('Could not set value for "%s"',
                             row_i['label'].get_label(), exc_info=True)
            else:
                # Make system bell sound to indicate a scan has
                # completed.
                print '\a\a',

            # Re-enable the scan button.
            row_i['button'].set_sensitive(True)

            # Close scan dialog after a short delay (let user see the
            # scanned match).
            gtk.timeout_add(1000, lambda *args:
                            self.scanner_window.hide())
            return True

        # Attach callback for when scan dialog is closed.
        def on_scanner_view__delete_event(window, event, row_i):
            '''
            When scanner view is closed, stop the scan, hide the window and
            re-enable the button that initiated the scan.
            '''
            # Disable scanner to reduce CPU usage and prevent unexpected
            # `symbols-found` signals.  Note that GStreamer video pipeline
            # stays running.
            self.scanner_view.disable_scan()
            # Hide scanner dialog window.
            self.scanner_window.hide()
            # Enable scan button.
            row_i['button'].set_sensitive(True)
            self.scanner_window.disconnect(row_i['callback_ids']
                                           ['scanner_window'])
            del row_i['callback_ids']['scanner_window']
            return gtk.TRUE

        # From list of `gtk.Table` widget children, extract list of `(widget,
        # event_box)` pairs, one pair per form field.
        # N.B., table widgets are listed in reverse order of insertion in list
        # of children, so list of pairs is reversed (i.e., `[::-1]`).
        widget_pairs = [children[2 * i:2 * i + 2]
                        for i in xrange(len(self.form_view.form.schema))][::-1]

        for i, (name_i, form_field_i) in enumerate(self.form_view.form.schema
                                                   .iteritems()):
            widget_i, event_box_i = widget_pairs[i]
            label_i = event_box_i.get_children()[0]

            # Add scan button beside each widget.
            button_scan_i = gtk.Button('Scan')
            button_scan_i.show()
            table.attach(button_scan_i, 2, 3, i, i + 1)
            button_scan_i.props.name = label_i.get_label()

            # Add callback function for each scan button to launch a barcode
            # scanning dialog.
            def on_button_scan_i__clicked(i, widget, event_box, label):
                # Wrap callback to bind widget, etc. data to callback.  This is
                # necessary, since the `widget_i, label_i, etc.`, references
                # are modified during each loop iteration.
                def wrapped(button):
                    # Disable button until scan has completed or is cancelled.
                    button.set_sensitive(False)

                    row_i = {'widget': widget,
                             'event_box': event_box,
                             'label': label,
                             'label_label': label.get_label(),
                             'button': button,
                             'callback_ids': {}}

                    # Attach callback to signal triggered when symbol/symbols
                    # are found by the scanner.
                    row_i['callback_ids']['symbol'] =\
                        self.scanner.connect('symbols-found',
                                             on_symbols_found_i, row_i)
                    row_i['callback_ids']['scanner_window'] =\
                        (self.scanner_window
                         .connect('delete_event',
                                  on_scanner_view__delete_event, row_i))

                    # Launch barcode scan dialog.
                    self.scanner_window.show()
                    self.scanner_view.enable_scan()
                return wrapped

            button_scan_i.connect('clicked',
                                  on_button_scan_i__clicked(i, widget_i,
                                                            event_box_i,
                                                            label_i))

    def run(self, values=None, parent=None, use_markup=True):
        # Run dialog.
        result = super(MetaDataDialog, self).run(values=values, parent=parent,
                                                 use_markup=use_markup)
        try:
            # Destroy scan widget.
            self.scanner_view.hide()

            # Stop scanner.
            self.scanner.stop()
        finally:
            return result