def __init__(self, plugin):
        DefaultConfigWidget.__init__(self, plugin)
        c = plugin_prefs[STORE_NAME]

        other_group_box = QGroupBox('Other options', self)
        self.l.addWidget(other_group_box, self.l.rowCount(), 0, 1, 2)
        other_group_box_layout = QGridLayout()
        other_group_box.setLayout(other_group_box_layout)

        max_downloads_label = QLabel('Maximum title/author search matches to download/evaluate (1 = fastest):', self)
        max_downloads_label.setToolTip('More matches means higher chance of better\n'
                             'metadata (but not necessarily).\n')
        other_group_box_layout.addWidget(max_downloads_label, 1, 0, 1, 1)
        self.max_downloads_spin = QtGui.QSpinBox(self)
        self.max_downloads_spin.setMinimum(1)
        self.max_downloads_spin.setMaximum(100)
        self.max_downloads_spin.setProperty('value', c.get(KEY_MAX_DOWNLOADS, DEFAULT_STORE_VALUES[KEY_MAX_DOWNLOADS]))
        other_group_box_layout.addWidget(self.max_downloads_spin, 1, 1, 1, 1)
        other_group_box_layout.setColumnStretch(2, 1)
def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, parent=None):
    def widget_factory(typ, key):
        if bulk:
            w = bulk_widgets[typ](db, key, parent)
        else:
            w = widgets[typ](db, key, parent)
        if book_id is not None:
            w.initialize(book_id)
        return w
    fm = db.field_metadata

    # Get list of all non-composite custom fields. We must make widgets for these
    fields = fm.custom_field_keys(include_composites=False)
    cols_to_display = fields
    cols_to_display.sort(key=partial(field_sort_key, fm=fm))

    # This will contain the fields in the order to display them
    cols = []

    # The fields named here must be first in the widget list
    tweak_cols = tweaks['metadata_edit_custom_column_order']
    comments_in_tweak = 0
    for key in (tweak_cols or ()):
        # Add the key if it really exists in the database
        if key in cols_to_display:
            cols.append(key)
            if fm[key]['datatype'] == 'comments':
                comments_in_tweak += 1

    # Add all the remaining fields
    comments_not_in_tweak = 0
    for key in cols_to_display:
        if key not in cols:
            cols.append(key)
            if fm[key]['datatype'] == 'comments':
                comments_not_in_tweak += 1

    count = len(cols)
    layout_rows_for_comments = 9
    if two_column:
        turnover_point = ((count-comments_not_in_tweak+1) +
                          comments_in_tweak*(layout_rows_for_comments-1))/2
    else:
        # Avoid problems with multi-line widgets
        turnover_point = count + 1000
    ans = []
    column = row = base_row = max_row = 0
    for key in cols:
        if not fm[key]['is_editable']:
            continue  # this almost never happens
        dt = fm[key]['datatype']
        if dt == 'composite' or (bulk and dt == 'comments'):
            continue
        w = widget_factory(dt, fm[key]['colnum'])
        ans.append(w)
        if two_column and dt == 'comments':
            # Here for compatibility with old layout. Comments always started
            # in the left column
            comments_in_tweak -= 1
            # no special processing if the comment field was named in the tweak
            if comments_in_tweak < 0 and comments_not_in_tweak > 0:
                # Force a turnover, adding comments widgets below max_row.
                # Save the row to return to if we turn over again
                column = 0
                row = max_row
                base_row = row
                turnover_point = row + (comments_not_in_tweak * layout_rows_for_comments)/2
                comments_not_in_tweak = 0

        l = QGridLayout()
        if dt == 'comments':
            layout.addLayout(l, row, column, layout_rows_for_comments, 1)
            layout.setColumnStretch(column, 100)
            row += layout_rows_for_comments
        else:
            layout.addLayout(l, row, column, 1, 1)
            layout.setColumnStretch(column, 100)
            row += 1
        for c in range(0, len(w.widgets), 2):
            if dt != 'comments':
                w.widgets[c].setWordWrap(True)
                w.widgets[c].setBuddy(w.widgets[c+1])
                l.addWidget(w.widgets[c], c, 0)
                l.addWidget(w.widgets[c+1], c, 1)
                l.setColumnStretch(1, 10000)
            else:
                l.addWidget(w.widgets[0], 0, 0, 1, 2)
        l.addItem(QSpacerItem(0, 0, vPolicy=QSizePolicy.Expanding), c, 0, 1, 1)
        max_row = max(max_row, row)
        if row >= turnover_point:
            column = 1
            turnover_point = count + 1000
            row = base_row

    items = []
    if len(ans) > 0:
        items.append(QSpacerItem(10, 10, QSizePolicy.Minimum,
            QSizePolicy.Expanding))
        layout.addItem(items[-1], layout.rowCount(), 0, 1, 1)
        layout.setRowStretch(layout.rowCount()-1, 100)
    return ans, items
示例#3
0
    def __init__(self, window, plugin, device_id):
        title = _("%s Settings") % plugin.device
        super(SettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)

        devmgr = plugin.device_manager()
        config = devmgr.config
        keystore = window.wallet.get_keystore()
        handler = keystore.handler
        thread = keystore.thread
        # wallet can be None, needn't be window.wallet
        wallet = devmgr.wallet_by_id(device_id)
        hs_rows, hs_cols = (64, 128)

        def invoke_client(method, *args, **kw_args):
            unpair_after = kw_args.pop('unpair_after', False)

            def task():
                client = devmgr.client_by_id(device_id, handler)
                if not client:
                    raise RuntimeError("Device not connected")
                if method:
                    getattr(client, method)(*args, **kw_args)
                if unpair_after:
                    devmgr.unpair_id(device_id)
                return client.features

            thread.add(task, on_success=update)

        def update(features):
            self.features = features
            set_label_enabled()
            bl_hash = features.bootloader_hash.encode('hex')
            bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
            noyes = [_("No"), _("Yes")]
            endis = [_("Enable Passphrases"), _("Disable Passphrases")]
            disen = [_("Disabled"), _("Enabled")]
            setchange = [_("Set a PIN"), _("Change PIN")]

            version = "%d.%d.%d" % (features.major_version,
                                    features.minor_version,
                                    features.patch_version)
            coins = ", ".join(coin.coin_name for coin in features.coins)

            device_label.setText(features.label)
            pin_set_label.setText(noyes[features.pin_protection])
            passphrases_label.setText(disen[features.passphrase_protection])
            bl_hash_label.setText(bl_hash)
            label_edit.setText(features.label)
            device_id_label.setText(features.device_id)
            initialized_label.setText(noyes[features.initialized])
            version_label.setText(version)
            coins_label.setText(coins)
            clear_pin_button.setVisible(features.pin_protection)
            clear_pin_warning.setVisible(features.pin_protection)
            pin_button.setText(setchange[features.pin_protection])
            pin_msg.setVisible(not features.pin_protection)
            passphrase_button.setText(endis[features.passphrase_protection])
            language_label.setText(features.language)

        def set_label_enabled():
            label_apply.setEnabled(label_edit.text() != self.features.label)

        def rename():
            invoke_client('change_label', unicode(label_edit.text()))

        def toggle_passphrase():
            title = _("Confirm Toggle Passphrase Protection")
            currently_enabled = self.features.passphrase_protection
            if currently_enabled:
                msg = _("After disabling passphrases, you can only pair this "
                        "Electrum wallet if it had an empty passphrase.  "
                        "If its passphrase was not empty, you will need to "
                        "create a new wallet with the install wizard.  You "
                        "can use this wallet again at any time by re-enabling "
                        "passphrases and entering its passphrase.")
            else:
                msg = _("Your current Electrum wallet can only be used with "
                        "an empty passphrase.  You must create a separate "
                        "wallet with the install wizard for other passphrases "
                        "as each one generates a new set of addresses.")
            msg += "\n\n" + _("Are you sure you want to proceed?")
            if not self.question(msg, title=title):
                return
            invoke_client('toggle_passphrase', unpair_after=currently_enabled)

        def change_homescreen():
            from PIL import Image  # FIXME
            dialog = QFileDialog(self, _("Choose Homescreen"))
            filename = dialog.getOpenFileName()
            if filename:
                im = Image.open(str(filename))
                if im.size != (hs_cols, hs_rows):
                    raise Exception('Image must be 64 x 128 pixels')
                im = im.convert('1')
                pix = im.load()
                img = ''
                for j in range(hs_rows):
                    for i in range(hs_cols):
                        img += '1' if pix[i, j] else '0'
                img = ''.join(
                    chr(int(img[i:i + 8], 2)) for i in range(0, len(img), 8))
                invoke_client('change_homescreen', img)

        def clear_homescreen():
            invoke_client('change_homescreen', '\x00')

        def set_pin():
            invoke_client('set_pin', remove=False)

        def clear_pin():
            invoke_client('set_pin', remove=True)

        def wipe_device():
            if wallet and sum(wallet.get_balance()):
                title = _("Confirm Device Wipe")
                msg = _("Are you SURE you want to wipe the device?\n"
                        "Your wallet still has bitcoins in it!")
                if not self.question(
                        msg, title=title, icon=QMessageBox.Critical):
                    return
            invoke_client('wipe_device', unpair_after=True)

        def slider_moved():
            mins = timeout_slider.sliderPosition()
            timeout_minutes.setText(_("%2d minutes") % mins)

        def slider_released():
            config.set_session_timeout(timeout_slider.sliderPosition() * 60)

        # Information tab
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        info_glayout = QGridLayout()
        info_glayout.setColumnStretch(2, 1)
        device_label = QLabel()
        pin_set_label = QLabel()
        passphrases_label = QLabel()
        version_label = QLabel()
        device_id_label = QLabel()
        bl_hash_label = QLabel()
        bl_hash_label.setWordWrap(True)
        coins_label = QLabel()
        coins_label.setWordWrap(True)
        language_label = QLabel()
        initialized_label = QLabel()
        rows = [
            (_("Device Label"), device_label),
            (_("PIN set"), pin_set_label),
            (_("Passphrases"), passphrases_label),
            (_("Firmware Version"), version_label),
            (_("Device ID"), device_id_label),
            (_("Bootloader Hash"), bl_hash_label),
            (_("Supported Coins"), coins_label),
            (_("Language"), language_label),
            (_("Initialized"), initialized_label),
        ]
        for row_num, (label, widget) in enumerate(rows):
            info_glayout.addWidget(QLabel(label), row_num, 0)
            info_glayout.addWidget(widget, row_num, 1)
        info_layout.addLayout(info_glayout)

        # Settings tab
        settings_tab = QWidget()
        settings_layout = QVBoxLayout(settings_tab)
        settings_glayout = QGridLayout()

        # Settings tab - Label
        label_msg = QLabel(
            _("Name this %s.  If you have mutiple devices "
              "their labels help distinguish them.") % plugin.device)
        label_msg.setWordWrap(True)
        label_label = QLabel(_("Device Label"))
        label_edit = QLineEdit()
        label_edit.setMinimumWidth(150)
        label_edit.setMaxLength(plugin.MAX_LABEL_LEN)
        label_apply = QPushButton(_("Apply"))
        label_apply.clicked.connect(rename)
        label_edit.textChanged.connect(set_label_enabled)
        settings_glayout.addWidget(label_label, 0, 0)
        settings_glayout.addWidget(label_edit, 0, 1, 1, 2)
        settings_glayout.addWidget(label_apply, 0, 3)
        settings_glayout.addWidget(label_msg, 1, 1, 1, -1)

        # Settings tab - PIN
        pin_label = QLabel(_("PIN Protection"))
        pin_button = QPushButton()
        pin_button.clicked.connect(set_pin)
        settings_glayout.addWidget(pin_label, 2, 0)
        settings_glayout.addWidget(pin_button, 2, 1)
        pin_msg = QLabel(
            _("PIN protection is strongly recommended.  "
              "A PIN is your only protection against someone "
              "stealing your bitcoins if they obtain physical "
              "access to your %s.") % plugin.device)
        pin_msg.setWordWrap(True)
        pin_msg.setStyleSheet("color: red")
        settings_glayout.addWidget(pin_msg, 3, 1, 1, -1)

        # Settings tab - Homescreen
        if plugin.device != 'KeepKey':  # Not yet supported by KK firmware
            homescreen_layout = QHBoxLayout()
            homescreen_label = QLabel(_("Homescreen"))
            homescreen_change_button = QPushButton(_("Change..."))
            homescreen_clear_button = QPushButton(_("Reset"))
            homescreen_change_button.clicked.connect(change_homescreen)
            homescreen_clear_button.clicked.connect(clear_homescreen)
            homescreen_msg = QLabel(
                _("You can set the homescreen on your "
                  "device to personalize it.  You must "
                  "choose a %d x %d monochrome black and "
                  "white image.") % (hs_rows, hs_cols))
            homescreen_msg.setWordWrap(True)
            settings_glayout.addWidget(homescreen_label, 4, 0)
            settings_glayout.addWidget(homescreen_change_button, 4, 1)
            settings_glayout.addWidget(homescreen_clear_button, 4, 2)
            settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1)

        # Settings tab - Session Timeout
        timeout_label = QLabel(_("Session Timeout"))
        timeout_minutes = QLabel()
        timeout_slider = QSlider(Qt.Horizontal)
        timeout_slider.setRange(1, 60)
        timeout_slider.setSingleStep(1)
        timeout_slider.setTickInterval(5)
        timeout_slider.setTickPosition(QSlider.TicksBelow)
        timeout_slider.setTracking(True)
        timeout_msg = QLabel(
            _("Clear the session after the specified period "
              "of inactivity.  Once a session has timed out, "
              "your PIN and passphrase (if enabled) must be "
              "re-entered to use the device."))
        timeout_msg.setWordWrap(True)
        timeout_slider.setSliderPosition(config.get_session_timeout() // 60)
        slider_moved()
        timeout_slider.valueChanged.connect(slider_moved)
        timeout_slider.sliderReleased.connect(slider_released)
        settings_glayout.addWidget(timeout_label, 6, 0)
        settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3)
        settings_glayout.addWidget(timeout_minutes, 6, 4)
        settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1)
        settings_layout.addLayout(settings_glayout)
        settings_layout.addStretch(1)

        # Advanced tab
        advanced_tab = QWidget()
        advanced_layout = QVBoxLayout(advanced_tab)
        advanced_glayout = QGridLayout()

        # Advanced tab - clear PIN
        clear_pin_button = QPushButton(_("Disable PIN"))
        clear_pin_button.clicked.connect(clear_pin)
        clear_pin_warning = QLabel(
            _("If you disable your PIN, anyone with physical access to your "
              "%s device can spend your bitcoins.") % plugin.device)
        clear_pin_warning.setWordWrap(True)
        clear_pin_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(clear_pin_button, 0, 2)
        advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5)

        # Advanced tab - toggle passphrase protection
        passphrase_button = QPushButton()
        passphrase_button.clicked.connect(toggle_passphrase)
        passphrase_msg = WWLabel(PASSPHRASE_HELP)
        passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN)
        passphrase_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(passphrase_button, 3, 2)
        advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5)
        advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5)

        # Advanced tab - wipe device
        wipe_device_button = QPushButton(_("Wipe Device"))
        wipe_device_button.clicked.connect(wipe_device)
        wipe_device_msg = QLabel(
            _("Wipe the device, removing all data from it.  The firmware "
              "is left unchanged."))
        wipe_device_msg.setWordWrap(True)
        wipe_device_warning = QLabel(
            _("Only wipe a device if you have the recovery seed written down "
              "and the device wallet(s) are empty, otherwise the bitcoins "
              "will be lost forever."))
        wipe_device_warning.setWordWrap(True)
        wipe_device_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(wipe_device_button, 6, 2)
        advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5)
        advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5)
        advanced_layout.addLayout(advanced_glayout)
        advanced_layout.addStretch(1)

        tabs = QTabWidget(self)
        tabs.addTab(info_tab, _("Information"))
        tabs.addTab(settings_tab, _("Settings"))
        tabs.addTab(advanced_tab, _("Advanced"))
        dialog_vbox = QVBoxLayout(self)
        dialog_vbox.addWidget(tabs)
        dialog_vbox.addLayout(Buttons(CloseButton(self)))

        # Update information
        invoke_client(None)
示例#4
0
    def __init__(self, window, plugin, device_id):
        title = _("%s Settings") % plugin.device
        super(SettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)

        devmgr = plugin.device_manager()
        handler = window.wallet.handler
        thread = window.wallet.thread
        # wallet can be None, needn't be window.wallet
        wallet = devmgr.wallet_by_id(device_id)
        hs_rows, hs_cols = (64, 128)
        self.current_label=None

        def invoke_client(method, *args, **kw_args):
            unpair_after = kw_args.pop('unpair_after', False)

            def task():
                client = devmgr.client_by_id(device_id, handler)
                if not client:
                    raise RuntimeError("Device not connected")
                if method:
                    getattr(client, method)(*args, **kw_args)
                if unpair_after:
                    devmgr.unpair_id(device_id)
                return client.features

            thread.add(task, on_success=update)

        def update(features):
            self.current_label = features.label
            set_label_enabled()
            bl_hash = features.bootloader_hash.encode('hex')
            bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
            noyes = [_("No"), _("Yes")]
            endis = [_("Enable Passphrases"), _("Disable Passphrases")]
            disen = [_("Disabled"), _("Enabled")]
            setchange = [_("Set a PIN"), _("Change PIN")]

            version = "%d.%d.%d" % (features.major_version,
                                    features.minor_version,
                                    features.patch_version)
            coins = ", ".join(coin.coin_name for coin in features.coins)

            device_label.setText(features.label)
            pin_set_label.setText(noyes[features.pin_protection])
            passphrases_label.setText(disen[features.passphrase_protection])
            bl_hash_label.setText(bl_hash)
            label_edit.setText(features.label)
            device_id_label.setText(features.device_id)
            initialized_label.setText(noyes[features.initialized])
            version_label.setText(version)
            coins_label.setText(coins)
            clear_pin_button.setVisible(features.pin_protection)
            clear_pin_warning.setVisible(features.pin_protection)
            pin_button.setText(setchange[features.pin_protection])
            pin_msg.setVisible(not features.pin_protection)
            passphrase_button.setText(endis[features.passphrase_protection])
            language_label.setText(features.language)

        def set_label_enabled():
            label_apply.setEnabled(label_edit.text() != self.current_label)

        def rename():
            invoke_client('change_label', unicode(label_edit.text()))

        def toggle_passphrase():
            title = _("Confirm Toggle Passphrase Protection")
            msg = _("This will cause your Electrum wallet to be unpaired "
                    "unless your passphrase was or will be empty.\n\n"
                    "This is because addresses will no "
                    "longer correspond to those used by your %s.\n\n"
                    "You will need to create a new Electrum wallet "
                    "with the install wizard so that they match.\n\n"
                    "Are you sure you want to proceed?") % plugin.device
            if not self.question(msg, title=title):
                return
            invoke_client('toggle_passphrase', unpair_after=True)

        def change_homescreen():
            from PIL import Image  # FIXME
            dialog = QFileDialog(self, _("Choose Homescreen"))
            filename = dialog.getOpenFileName()
            if filename:
                im = Image.open(str(filename))
                if im.size != (hs_cols, hs_rows):
                    raise Exception('Image must be 64 x 128 pixels')
                im = im.convert('1')
                pix = im.load()
                img = ''
                for j in range(hs_rows):
                    for i in range(hs_cols):
                        img += '1' if pix[i, j] else '0'
                img = ''.join(chr(int(img[i:i + 8], 2))
                              for i in range(0, len(img), 8))
                invoke_client('change_homescreen', img)

        def clear_homescreen():
            invoke_client('change_homescreen', '\x00')

        def set_pin():
            invoke_client('set_pin', remove=False)

        def clear_pin():
            invoke_client('set_pin', remove=True)

        def wipe_device():
            if wallet and sum(wallet.get_balance()):
                title = _("Confirm Device Wipe")
                msg = _("Are you SURE you want to wipe the device?\n"
                        "Your wallet still has bitcoins in it!")
                if not self.question(msg, title=title,
                                     icon=QMessageBox.Critical):
                    return
            invoke_client('wipe_device', unpair_after=True)

        def slider_moved():
            mins = timeout_slider.sliderPosition()
            timeout_minutes.setText(_("%2d minutes") % mins)

        def slider_released():
            seconds = timeout_slider.sliderPosition() * 60
            wallet.set_session_timeout(seconds)

        # Information tab
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        info_glayout = QGridLayout()
        info_glayout.setColumnStretch(2, 1)
        device_label = QLabel()
        pin_set_label = QLabel()
        passphrases_label = QLabel()
        version_label = QLabel()
        device_id_label = QLabel()
        bl_hash_label = QLabel()
        bl_hash_label.setWordWrap(True)
        coins_label = QLabel()
        coins_label.setWordWrap(True)
        language_label = QLabel()
        initialized_label = QLabel()
        rows = [
            (_("Device Label"), device_label),
            (_("PIN set"), pin_set_label),
            (_("Passphrases"), passphrases_label),
            (_("Firmware Version"), version_label),
            (_("Device ID"), device_id_label),
            (_("Bootloader Hash"), bl_hash_label),
            (_("Supported Coins"), coins_label),
            (_("Language"), language_label),
            (_("Initialized"), initialized_label),
        ]
        for row_num, (label, widget) in enumerate(rows):
            info_glayout.addWidget(QLabel(label), row_num, 0)
            info_glayout.addWidget(widget, row_num, 1)
        info_layout.addLayout(info_glayout)

        # Settings tab
        settings_tab = QWidget()
        settings_layout = QVBoxLayout(settings_tab)
        settings_glayout = QGridLayout()

        # Settings tab - Label
        label_msg = QLabel(_("Name this %s.  If you have mutiple devices "
                             "their labels help distinguish them.")
                           % plugin.device)
        label_msg.setWordWrap(True)
        label_label = QLabel(_("Device Label"))
        label_edit = QLineEdit()
        label_edit.setMinimumWidth(150)
        label_edit.setMaxLength(plugin.MAX_LABEL_LEN)
        label_apply = QPushButton(_("Apply"))
        label_apply.clicked.connect(rename)
        label_edit.textChanged.connect(set_label_enabled)
        settings_glayout.addWidget(label_label, 0, 0)
        settings_glayout.addWidget(label_edit, 0, 1, 1, 2)
        settings_glayout.addWidget(label_apply, 0, 3)
        settings_glayout.addWidget(label_msg, 1, 1, 1, -1)

        # Settings tab - PIN
        pin_label = QLabel(_("PIN Protection"))
        pin_button = QPushButton()
        pin_button.clicked.connect(set_pin)
        settings_glayout.addWidget(pin_label, 2, 0)
        settings_glayout.addWidget(pin_button, 2, 1)
        pin_msg = QLabel(_("PIN protection is strongly recommended.  "
                           "A PIN is your only protection against someone "
                           "stealing your bitcoins if they obtain physical "
                           "access to your %s.") % plugin.device)
        pin_msg.setWordWrap(True)
        pin_msg.setStyleSheet("color: red")
        settings_glayout.addWidget(pin_msg, 3, 1, 1, -1)

        # Settings tab - Homescreen
        if plugin.device != 'KeepKey':   # Not yet supported by KK firmware
            homescreen_layout = QHBoxLayout()
            homescreen_label = QLabel(_("Homescreen"))
            homescreen_change_button = QPushButton(_("Change..."))
            homescreen_clear_button = QPushButton(_("Reset"))
            homescreen_change_button.clicked.connect(change_homescreen)
            homescreen_clear_button.clicked.connect(clear_homescreen)
            homescreen_msg = QLabel(_("You can set the homescreen on your "
                                      "device to personalize it.  You must "
                                      "choose a %d x %d monochrome black and "
                                      "white image.") % (hs_rows, hs_cols))
            homescreen_msg.setWordWrap(True)
            settings_glayout.addWidget(homescreen_label, 4, 0)
            settings_glayout.addWidget(homescreen_change_button, 4, 1)
            settings_glayout.addWidget(homescreen_clear_button, 4, 2)
            settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1)

        # Settings tab - Session Timeout
        if wallet:
            timeout_label = QLabel(_("Session Timeout"))
            timeout_minutes = QLabel()
            timeout_slider = QSlider(Qt.Horizontal)
            timeout_slider.setRange(1, 60)
            timeout_slider.setSingleStep(1)
            timeout_slider.setTickInterval(5)
            timeout_slider.setTickPosition(QSlider.TicksBelow)
            timeout_slider.setTracking(True)
            timeout_msg = QLabel(
                _("Clear the session after the specified period "
                  "of inactivity.  Once a session has timed out, "
                  "your PIN and passphrase (if enabled) must be "
                  "re-entered to use the device."))
            timeout_msg.setWordWrap(True)
            timeout_slider.setSliderPosition(wallet.session_timeout // 60)
            slider_moved()
            timeout_slider.valueChanged.connect(slider_moved)
            timeout_slider.sliderReleased.connect(slider_released)
            settings_glayout.addWidget(timeout_label, 6, 0)
            settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3)
            settings_glayout.addWidget(timeout_minutes, 6, 4)
            settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1)
        settings_layout.addLayout(settings_glayout)
        settings_layout.addStretch(1)

        # Advanced tab
        advanced_tab = QWidget()
        advanced_layout = QVBoxLayout(advanced_tab)
        advanced_glayout = QGridLayout()

        # Advanced tab - clear PIN
        clear_pin_button = QPushButton(_("Disable PIN"))
        clear_pin_button.clicked.connect(clear_pin)
        clear_pin_warning = QLabel(
            _("If you disable your PIN, anyone with physical access to your "
              "%s device can spend your bitcoins.") % plugin.device)
        clear_pin_warning.setWordWrap(True)
        clear_pin_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(clear_pin_button, 0, 2)
        advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5)

        # Advanced tab - toggle passphrase protection
        passphrase_button = QPushButton()
        passphrase_button.clicked.connect(toggle_passphrase)
        passphrase_msg = WWLabel(PASSPHRASE_HELP)
        passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN)
        passphrase_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(passphrase_button, 3, 2)
        advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5)
        advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5)

        # Advanced tab - wipe device
        wipe_device_button = QPushButton(_("Wipe Device"))
        wipe_device_button.clicked.connect(wipe_device)
        wipe_device_msg = QLabel(
            _("Wipe the device, removing all data from it.  The firmware "
              "is left unchanged."))
        wipe_device_msg.setWordWrap(True)
        wipe_device_warning = QLabel(
            _("Only wipe a device if you have the recovery seed written down "
              "and the device wallet(s) are empty, otherwise the bitcoins "
              "will be lost forever."))
        wipe_device_warning.setWordWrap(True)
        wipe_device_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(wipe_device_button, 6, 2)
        advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5)
        advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5)
        advanced_layout.addLayout(advanced_glayout)
        advanced_layout.addStretch(1)

        tabs = QTabWidget(self)
        tabs.addTab(info_tab, _("Information"))
        tabs.addTab(settings_tab, _("Settings"))
        tabs.addTab(advanced_tab, _("Advanced"))
        dialog_vbox = QVBoxLayout(self)
        dialog_vbox.addWidget(tabs)
        dialog_vbox.addLayout(Buttons(CloseButton(self)))

        # Update information
        invoke_client(None)
示例#5
0
def populate_metadata_page(layout, db, book_id, bulk=False, two_column=False, parent=None):
    def widget_factory(typ, key):
        if bulk:
            w = bulk_widgets[typ](db, key, parent)
        else:
            w = widgets[typ](db, key, parent)
        if book_id is not None:
            w.initialize(book_id)
        return w
    fm = db.field_metadata

    # Get list of all non-composite custom fields. We must make widgets for these
    fields = fm.custom_field_keys(include_composites=False)
    cols_to_display = fields
    cols_to_display.sort(key=partial(field_sort_key, fm=fm))

    # This will contain the fields in the order to display them
    cols = []

    # The fields named here must be first in the widget list
    tweak_cols = tweaks['metadata_edit_custom_column_order']
    comments_in_tweak = 0
    for key in (tweak_cols or ()):
        # Add the key if it really exists in the database
        if key in cols_to_display:
            cols.append(key)
            if fm[key]['datatype'] == 'comments':
                comments_in_tweak += 1

    # Add all the remaining fields
    comments_not_in_tweak = 0
    for key in cols_to_display:
        if key not in cols:
            cols.append(key)
            if fm[key]['datatype'] == 'comments':
                comments_not_in_tweak += 1

    count = len(cols)
    layout_rows_for_comments = 9
    if two_column:
        turnover_point = ((count-comments_not_in_tweak+1) +
                          comments_in_tweak*(layout_rows_for_comments-1))/2
    else:
        # Avoid problems with multi-line widgets
        turnover_point = count + 1000
    ans = []
    column = row = base_row = max_row = 0
    for key in cols:
        if not fm[key]['is_editable']:
            continue  # this almost never happens
        dt = fm[key]['datatype']
        if dt == 'composite' or (bulk and dt == 'comments'):
            continue
        w = widget_factory(dt, fm[key]['colnum'])
        ans.append(w)
        if two_column and dt == 'comments':
            # Here for compatibility with old layout. Comments always started
            # in the left column
            comments_in_tweak -= 1
            # no special processing if the comment field was named in the tweak
            if comments_in_tweak < 0 and comments_not_in_tweak > 0:
                # Force a turnover, adding comments widgets below max_row.
                # Save the row to return to if we turn over again
                column = 0
                row = max_row
                base_row = row
                turnover_point = row + (comments_not_in_tweak * layout_rows_for_comments)/2
                comments_not_in_tweak = 0

        l = QGridLayout()
        if dt == 'comments':
            layout.addLayout(l, row, column, layout_rows_for_comments, 1)
            layout.setColumnStretch(column, 100)
            row += layout_rows_for_comments
        else:
            layout.addLayout(l, row, column, 1, 1)
            layout.setColumnStretch(column, 100)
            row += 1
        for c in range(0, len(w.widgets), 2):
            if dt != 'comments':
                w.widgets[c].setWordWrap(True)
                w.widgets[c].setBuddy(w.widgets[c+1])
                l.addWidget(w.widgets[c], c, 0)
                l.addWidget(w.widgets[c+1], c, 1)
                l.setColumnStretch(1, 10000)
            else:
                l.addWidget(w.widgets[0], 0, 0, 1, 2)
        l.addItem(QSpacerItem(0, 0, vPolicy=QSizePolicy.Expanding), c, 0, 1, 1)
        max_row = max(max_row, row)
        if row >= turnover_point:
            column = 1
            turnover_point = count + 1000
            row = base_row

    items = []
    if len(ans) > 0:
        items.append(QSpacerItem(10, 10, QSizePolicy.Minimum,
            QSizePolicy.Expanding))
        layout.addItem(items[-1], layout.rowCount(), 0, 1, 1)
        layout.setRowStretch(layout.rowCount()-1, 100)
    return ans, items
示例#6
0
   def __init__(self, main):

      self.main = main

      ##########################################################################
      ##### Display the conversion values based on the Coinbase API
      self.lastPriceFetch = 0
      self.lblHeader    = QRichLabel(tr("""<b>Tracking buy and sell prices on 
         Coinbase every 60 seconds</b>"""), doWrap=False)
      self.lblLastTime  = QRichLabel('', doWrap=False)
      self.lblSellLabel = QRichLabel(tr('Coinbase <b>Sell</b> Price (USD):'), doWrap=False)
      self.lblBuyLabel  = QRichLabel(tr('Coinbase <b>Buy</b> Price (USD):'),  doWrap=False)
      self.lblSellPrice = QRichLabel('<Not Available>')
      self.lblBuyPrice  = QRichLabel('<Not Available>')

      self.lastSellStr = ''
      self.lastBuyStr = ''

      self.btnUpdate = QPushButton(tr('Check Now'))
      self.main.connect(self.btnUpdate, SIGNAL('clicked()'), self.checkUpdatePrice)

      ##########################################################################
      ##### A calculator for converting prices between USD and BTC
      lblCalcTitle = QRichLabel(tr("""Convert between USD and BTC using 
         Coinbase sell price"""), hAlign=Qt.AlignHCenter, doWrap=False)
      self.edtEnterUSD = QLineEdit()
      self.edtEnterBTC = QLineEdit()
      self.lblEnterUSD1 = QRichLabel('$')
      self.lblEnterUSD2 = QRichLabel('USD')
      self.lblEnterBTC = QRichLabel('BTC')
      btnClear = QPushButton('Clear')

      self.main.connect(self.edtEnterUSD, SIGNAL('textEdited(QString)'), self.updateCalcBTC)
      self.main.connect(self.edtEnterBTC, SIGNAL('textEdited(QString)'), self.updateCalcUSD)

      def clearCalc():
         self.edtEnterUSD.setText('')
         self.edtEnterBTC.setText('')

      self.main.connect(btnClear, SIGNAL('clicked()'), clearCalc)

      frmCalcMid = makeHorizFrame( [self.lblEnterUSD1,
                                    self.edtEnterUSD,
                                    self.lblEnterUSD2,
                                    'Stretch',
                                    self.edtEnterBTC,
                                    self.lblEnterBTC])

      frmCalcClear = makeHorizFrame(['Stretch', btnClear, 'Stretch'])
      frmCalc = makeVertFrame([lblCalcTitle, frmCalcMid, frmCalcClear], STYLE_PLAIN)

      ##########################################################################
      ##### A table showing you the total balance of each wallet in USD and BTC
      lblWltTableTitle = QRichLabel(tr("Wallet balances converted to USD"), 
                                            doWrap=False, hAlign=Qt.AlignHCenter)
      numWallets = len(self.main.walletMap)
      self.wltTable = QTableWidget(self.main)
      self.wltTable.setRowCount(numWallets)
      self.wltTable.setColumnCount(4)
      self.wltTable.horizontalHeader().setStretchLastSection(True)
      self.wltTable.setMinimumWidth(600)


      ##########################################################################
      ##### Setup the main layout for the tab
      mainLayout = QGridLayout()
      i=0
      mainLayout.addWidget(self.lblHeader,      i,0,  1,3)
      i+=1
      mainLayout.addItem(QSpacerItem(15,15),    i,0)
      mainLayout.addWidget(self.lblSellLabel,   i,1)
      mainLayout.addWidget(self.lblSellPrice,   i,2)
      i+=1
      mainLayout.addItem(QSpacerItem(15,15),    i,0)
      mainLayout.addWidget(self.lblBuyLabel,    i,1)
      mainLayout.addWidget(self.lblBuyPrice,    i,2)
      i+=1
      mainLayout.addWidget(self.lblLastTime,    i,0,  1,2)
      mainLayout.addWidget(self.btnUpdate,      i,2)
      i+=1
      mainLayout.addItem(QSpacerItem(20,20),    i,0)
      i+=1
      mainLayout.addWidget(frmCalc,             i,0,  1,3)
      i+=1
      mainLayout.addItem(QSpacerItem(30,30),    i,0)
      i+=1
      mainLayout.addWidget(lblWltTableTitle,    i,0,  1,3)
      i+=1
      mainLayout.addWidget(self.wltTable,       i,0,  1,3)

      mainLayout.setColumnStretch(0,0)
      mainLayout.setColumnStretch(1,1)
      mainLayout.setColumnStretch(2,1)
      tabWidget = QWidget()
      tabWidget.setLayout(mainLayout)

      frmH = makeHorizFrame(['Stretch', tabWidget, 'Stretch'])
      frm  = makeVertFrame(['Space(20)', frmH, 'Stretch'])


      # Now set the scrollarea widget to the layout
      self.tabToDisplay = QScrollArea()
      self.tabToDisplay.setWidgetResizable(True)
      self.tabToDisplay.setWidget(frm)
示例#7
0
    def __init__(self, window, plugin):
        self.plugin = plugin
        self.window = window  # The main electrum window
        title = _("%s Settings") % plugin.device
        super(SettingsDialog, self).__init__(window, title)
        self.setMaximumWidth(540)
        hs_rows, hs_cols = (64, 128)

        def get_client(lookup=DeviceMgr.PAIRED):
            return self.plugin.get_client(wallet, lookup)

        def update():
            features = get_client(DeviceMgr.PAIRED).features
            self.features = features
            # The above was for outer scopes.  Now the real logic.
            set_label_enabled()
            bl_hash = features.bootloader_hash.encode('hex')
            bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]])
            noyes = [_("No"), _("Yes")]
            endis = [_("Enable Passphrases"), _("Disable Passphrases")]
            setchange = [_("Set a PIN"), _("Change PIN")]

            version = "%d.%d.%d" % (features.major_version,
                                    features.minor_version,
                                    features.patch_version)
            coins = ", ".join(coin.coin_name for coin in features.coins)

            device_label.setText(features.label)
            pin_set_label.setText(noyes[features.pin_protection])
            bl_hash_label.setText(bl_hash)
            label_edit.setText(features.label)
            device_id_label.setText(features.device_id)
            initialized_label.setText(noyes[features.initialized])
            version_label.setText(version)
            coins_label.setText(coins)
            clear_pin_button.setVisible(features.pin_protection)
            clear_pin_warning.setVisible(features.pin_protection)
            pin_button.setText(setchange[features.pin_protection])
            pin_msg.setVisible(not features.pin_protection)
            passphrase_button.setText(endis[features.passphrase_protection])

            language_label.setText(features.language)

        def set_label_enabled():
            label_apply.setEnabled(label_edit.text() != self.features.label)

        def rename():
            get_client().change_label(unicode(label_edit.text()))
            update()

        def toggle_passphrase():
            title = _("Confirm Toggle Passphrase Protection")
            msg = _("This will cause your Electrum wallet to be unpaired "
                    "unless your passphrase was or will be empty.\n\n"
                    "This is because addresses will no "
                    "longer correspond to those used by your %s.\n\n"
                    "You will need to create a new Electrum wallet "
                    "with the install wizard so that they match.\n\n"
                    "Are you sure you want to proceed?") % plugin.device
            if not self.question(msg, title=title):
                return
            get_client().toggle_passphrase()
            self.device_manager().close_wallet(wallet)  # Unpair
            update()

        def change_homescreen():
            dialog = QFileDialog(self, _("Choose Homescreen"))
            filename = dialog.getOpenFileName()
            if filename:
                im = Image.open(str(filename))
                if im.size != (hs_cols, hs_rows):
                    raise Exception('Image must be 64 x 128 pixels')
                im = im.convert('1')
                pix = im.load()
                img = ''
                for j in range(hs_rows):
                    for i in range(hs_cols):
                        img += '1' if pix[i, j] else '0'
                img = ''.join(chr(int(img[i:i + 8], 2))
                              for i in range(0, len(img), 8))
                get_client().change_homescreen(img)

        def clear_homescreen():
            get_client().change_homescreen('\x00')

        def set_pin(remove=False):
            get_client().set_pin(remove=remove)
            update()

        def clear_pin():
            set_pin(remove=True)

        def wipe_device():
            # FIXME: cannot yet wipe a device that is only plugged in
            if sum(wallet.get_balance()):
                title = _("Confirm Device Wipe")
                msg = _("Are you SURE you want to wipe the device?\n"
                        "Your wallet still has bitcoins in it!")
                if not self.question(msg, title=title,
                                     icon=QMessageBox.Critical):
                    return
            # Note: we use PRESENT so that a user who has forgotten
            # their PIN is not prevented from wiping their device
            get_client(DeviceMgr.PRESENT).wipe_device()
            self.device_manager().close_wallet(wallet)
            update()

        def slider_moved():
            mins = timeout_slider.sliderPosition()
            timeout_minutes.setText(_("%2d minutes") % mins)

        wallet = window.wallet
        handler = wallet.handler
        device = plugin.device
        dialog_vbox = QVBoxLayout(self)

        # Information tab
        info_tab = QWidget()
        info_layout = QVBoxLayout(info_tab)
        info_glayout = QGridLayout()
        info_glayout.setColumnStretch(2, 1)
        device_label = QLabel()
        pin_set_label = QLabel()
        version_label = QLabel()
        device_id_label = QLabel()
        bl_hash_label = QLabel()
        bl_hash_label.setWordWrap(True)
        coins_label = QLabel()
        coins_label.setWordWrap(True)
        language_label = QLabel()
        initialized_label = QLabel()
        rows = [
            (_("Device Label"), device_label),
            (_("PIN set"), pin_set_label),
            (_("Firmware Version"), version_label),
            (_("Serial Number"), device_id_label),
            (_("Bootloader Hash"), bl_hash_label),
            (_("Supported Coins"), coins_label),
            (_("Language"), language_label),
            (_("Initialized"), initialized_label),
        ]
        for row_num, (label, widget) in enumerate(rows):
            info_glayout.addWidget(QLabel(label), row_num, 0)
            info_glayout.addWidget(widget, row_num, 1)
        info_layout.addLayout(info_glayout)

        # Settings tab
        settings_tab = QWidget()
        settings_layout = QVBoxLayout(settings_tab)
        settings_glayout = QGridLayout()
        #settings_glayout.setColumnStretch(3, 1)

        # Settings tab - Label
        label_msg = QLabel(_("Name this %s.  If you have mutiple devices "
                             "their labels help distinguish them.")
                           % plugin.device)
        label_msg.setWordWrap(True)
        label_label = QLabel(_("Device Label"))
        label_edit = QLineEdit()
        label_edit.setMinimumWidth(150)
        label_edit.setMaxLength(self.plugin.MAX_LABEL_LEN)
        label_apply = QPushButton(_("Apply"))
        label_apply.clicked.connect(rename)
        label_edit.textChanged.connect(set_label_enabled)
        settings_glayout.addWidget(label_label, 0, 0)
        settings_glayout.addWidget(label_edit, 0, 1, 1, 2)
        settings_glayout.addWidget(label_apply, 0, 3)
        settings_glayout.addWidget(label_msg, 1, 1, 1, -1)

        # Settings tab - PIN
        pin_label = QLabel(_("PIN Protection"))
        pin_button = QPushButton()
        pin_button.clicked.connect(set_pin)
        settings_glayout.addWidget(pin_label, 2, 0)
        settings_glayout.addWidget(pin_button, 2, 1)
        pin_msg = QLabel(_("PIN protection is strongly recommended.  "
                           "A PIN is your only protection against someone "
                           "stealing your bitcoins if they obtain physical "
                           "access to your %s.") % plugin.device)
        pin_msg.setWordWrap(True)
        pin_msg.setStyleSheet("color: red")
        settings_glayout.addWidget(pin_msg, 3, 1, 1, -1)
        settings_layout.addLayout(settings_glayout)

        # Settings tab - Homescreen
        homescreen_layout = QHBoxLayout()
        homescreen_label = QLabel(_("Homescreen"))
        homescreen_change_button = QPushButton(_("Change..."))
        homescreen_clear_button = QPushButton(_("Reset"))
        homescreen_change_button.clicked.connect(change_homescreen)
        homescreen_clear_button.clicked.connect(clear_homescreen)
        homescreen_msg = QLabel(_("You can set the homescreen on your device "
                                  "to personalize it.  You must choose a "
                                  "%d x %d monochrome black and white image.")
                                % (hs_rows, hs_cols))
        homescreen_msg.setWordWrap(True)
        settings_glayout.addWidget(homescreen_label, 4, 0)
        settings_glayout.addWidget(homescreen_change_button, 4, 1)
        settings_glayout.addWidget(homescreen_clear_button, 4, 2)
        settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1)

        # Settings tab - Session Timeout
        timeout_label = QLabel(_("Session Timeout"))
        timeout_minutes = QLabel()
        timeout_slider = self.slider = QSlider(Qt.Horizontal)
        timeout_slider.setRange(1, 60)
        timeout_slider.setSingleStep(1)
        timeout_slider.setSliderPosition(wallet.session_timeout // 60)
        timeout_slider.setTickInterval(5)
        timeout_slider.setTickPosition(QSlider.TicksBelow)
        timeout_slider.setTracking(True)
        timeout_slider.valueChanged.connect(slider_moved)
        timeout_msg = QLabel(_("Clear the session after the specified period "
                               "of inactivity.  Once a session has timed out, "
                               "your PIN and passphrase (if enabled) must be "
                               "re-entered to use the device."))
        timeout_msg.setWordWrap(True)
        settings_glayout.addWidget(timeout_label, 6, 0)
        settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3)
        settings_glayout.addWidget(timeout_minutes, 6, 4)
        settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1)

        # Advanced tab
        advanced_tab = QWidget()
        advanced_layout = QVBoxLayout(advanced_tab)
        advanced_glayout = QGridLayout()

        # Advanced tab - clear PIN
        clear_pin_button = QPushButton(_("Disable PIN"))
        clear_pin_button.clicked.connect(clear_pin)
        clear_pin_warning = QLabel(_("If you disable your PIN, anyone with "
                                     "physical access to your %s device can "
                                     "spend your bitcoins.") % plugin.device)
        clear_pin_warning.setWordWrap(True)
        clear_pin_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(clear_pin_button, 0, 2)
        advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5)

        # Advanced tab - toggle passphrase protection
        passphrase_button = QPushButton()
        passphrase_button.clicked.connect(toggle_passphrase)
        passphrase_msg = QLabel(
            _("Passphrases allow you to access new wallets, each "
              "hidden behind a particular case-sensitive passphrase.  You "
              "need to create a separate Electrum wallet for each passphrase "
              "you use as they each generate different addresses.  Changing "
              "your passphrase does not lose other wallets, each is still "
              "accessible behind its own passphrase."))
        passphrase_msg.setWordWrap(True)
        passphrase_warning = QLabel(
            _("If you forget a passphrase you will be unable to access any "
              "bitcoins in the wallet behind it.  A passphrase is not a PIN. "
              "Only change this if you are sure you understand it."))
        passphrase_warning.setWordWrap(True)
        passphrase_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(passphrase_button, 3, 2)
        advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5)
        advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5)

        # Advanced tab - wipe device
        wipe_device_button = QPushButton(_("Wipe Device"))
        wipe_device_button.clicked.connect(wipe_device)
        wipe_device_msg = QLabel(
            _("Wipe the device, removing all data from it.  The firmware "
              "is left unchanged."))
        wipe_device_msg.setWordWrap(True)
        wipe_device_warning = QLabel(
            _("Only wipe a device if you have the recovery seed written down "
              "and the device wallet(s) are empty, otherwise the bitcoins "
              "will be lost forever."))
        wipe_device_warning.setWordWrap(True)
        wipe_device_warning.setStyleSheet("color: red")
        advanced_glayout.addWidget(wipe_device_button, 6, 2)
        advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5)
        advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5)
        advanced_layout.addLayout(advanced_glayout)
        advanced_layout.addStretch(1)

        tabs = QTabWidget(self)
        tabs.addTab(info_tab, _("Information"))
        tabs.addTab(settings_tab, _("Settings"))
        tabs.addTab(advanced_tab, _("Advanced"))

        # Update information and then connect change slots
        update()
        slider_moved()

        dialog_vbox.addWidget(tabs)
        dialog_vbox.addLayout(Buttons(CloseButton(self)))
示例#8
0
class FtcGuiApplication(TouchApplication):
    def __init__(self, args):
        TouchApplication.__init__(self, args)

        # create the empty main window
        self.w = TouchWindow("Run JetsonEV")

        self.relative_path = os.path.dirname(os.path.realpath(__file__))
        self.script = os.path.join(self.relative_path, 'Run_car.py')
        self.grid = QGridLayout()
        self.grid.setSpacing(0)
        self.process = QProcess()
        self.process.readyReadStandardOutput.connect(self.stdoutReady)
        self.process.readyReadStandardError.connect(self.stderrReady)

        self.play_btn = ShadowButton(os.path.join(self.relative_path, 'start'))
        self.play_btn.setText("Start")
        self.play_btn.clicked.connect(self.start_script)
        self.grid.addWidget(self.play_btn, 0, 0, 1, 1)
        self.grid.setColumnStretch(0, 1.25)

        self.imu_box = QCheckBox('IMU')
        self.imu_box.setChecked(True)
        self.camera_box = QCheckBox('Cam')
        self.camera_box.setChecked(False)
        self.lidar_box = QCheckBox('Lidar')
        self.lidar_box.setChecked(False)
        self.grid.addWidget(self.imu_box, 0, 1, 1, 1)
        self.grid.setColumnStretch(1, 1)
        self.grid.addWidget(self.camera_box, 0, 2, 1, 1)
        self.grid.setColumnStretch(2, 1)
        self.grid.addWidget(self.lidar_box, 0, 3, 1, 1)
        self.grid.setColumnStretch(3, 1.5)
        self.grid.setAlignment(Qt.AlignCenter)

        self.stop_btn = ShadowButton(os.path.join(self.relative_path, 'stop'))
        self.stop_btn.setText("Stop")
        self.stop_btn.clicked.connect(self.stop_script)
        self.grid.addWidget(self.stop_btn, 0, 4, 1, 1)
        self.grid.setRowStretch(1, 4)

        self.console_output = QPlainTextEdit()
        self.console_output.setReadOnly(True)
        console_style = "QPlainTextEdit {" \
                        "background-color: black;" \
                        "color: white;" \
                        "}"
        self.console_output.setFocusPolicy(Qt.NoFocus)
        self.console_output.setFrameStyle(3)
        self.console_output.setStyleSheet(console_style)

        self.grid.addWidget(self.console_output, 1, 0, 1, 5)

        self.w.centralWidget.setLayout(self.grid)
        self.w.centralWidget.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.w.centralWidget, event)
        self.w.centralWidget.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.w.centralWidget, event)
        self.w.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.w, event)
        self.w.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.w, event)
        self.play_btn.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.play_btn, event)
        self.play_btn.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.play_btn, event)
        self.stop_btn.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.stop_btn, event)
        self.stop_btn.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.stop_btn, event)

        self.imu_box.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.imu_box, event)
        self.imu_box.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.imu_box, event)
        self.camera_box.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.camera_box, event)
        self.camera_box.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.camera_box, event)
        self.lidar_box.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.lidar_box, event)
        self.lidar_box.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.lidar_box, event)

        self.xbox_controller = XBoxInput()
        self.xbox_controller.cycle_right.connect(self.cycle_right)
        self.xbox_controller.cycle_left.connect(self.cycle_left)

        self.speed_widget = SpeedWidget()
        self.grid.addWidget(self.speed_widget, 1, 0, 1, 5)
        self.speed_widget.hide()

        self.imu_widget = IMUWidget()
        self.grid.addWidget(self.imu_widget, 1, 0, 1, 5)
        self.imu_widget.hide()

        self.camera_widget = VideoWidget()
        self.grid.addWidget(self.camera_widget, 1, 0, 1, 5)
        self.camera_widget.hide()

        self.lidar_widget = LidarWidget()
        self.grid.addWidget(self.lidar_widget, 1, 0, 1, 5)
        self.lidar_widget.hide()

        self.widgets_to_show = []
        self.show_widget_index = 0
        self.w.show()
        self.aboutToQuit.connect(self.xbox_controller.xbox_controller.close)
        self.exec_()

    def cycle_right(self, axis):
        last_index = self.show_widget_index
        self.show_widget_index += 1
        if self.show_widget_index >= len(self.widgets_to_show):
            self.show_widget_index = 0
        self.widgets_to_show[last_index].hide()
        self.widgets_to_show[self.show_widget_index].show()

    def cycle_left(self, axis):
        last_index = self.show_widget_index
        self.show_widget_index -= 1
        if self.show_widget_index < 0:
            self.show_widget_index = len(self.widgets_to_show) - 1
        self.widgets_to_show[last_index].hide()
        self.widgets_to_show[self.show_widget_index].show()

    def start_script(self):
        self.widgets_to_show = [self.console_output, self.speed_widget]
        flags = ['-u', self.script]
        self.speed_widget.start(port=4021)

        if self.imu_box.isChecked():
            print('starting imu socket')
            self.imu_widget.start(port=9009)
            self.widgets_to_show.append(self.imu_widget)
            flags.extend(['--enable-imu'])
        if self.lidar_box.isChecked():
            print('starting lidar socket')
            self.lidar_widget.start(port=9010)
            self.widgets_to_show.append(self.lidar_widget)
            flags.extend(['--enable-lidar'])
        if self.camera_box.isChecked():
            print('starting camera socket')
            self.camera_widget.start(port=9011)
            self.widgets_to_show.append(self.camera_widget)
            flags.extend(['--enable-camera'])
        self.process.start('python3', flags)

    def stop_script(self):
        self.imu_widget.shutdown()
        self.camera_widget.shutdown()
        self.lidar_widget.shutdown()
        self.speed_widget.shutdown()
        self.process.terminate()

    def fwd_output(self, text):
        self.console_output.appendPlainText(text)
        cursor = self.console_output.textCursor()
        cursor.movePosition(cursor.End)

    def stdoutReady(self):
        text = str(self.process.readAllStandardOutput(), encoding='utf8')
        self.fwd_output(text)

    def stderrReady(self):
        text = str(self.process.readAllStandardError(), encoding='utf8')
        self.fwd_output(text)

    def filter_out_arrow_release_keys(self, widget, event):
        if event.key() == Qt.Key_Up:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepSub)
        elif event.key() == Qt.Key_Down:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepAdd)
        else:
            type(widget).keyReleaseEvent(widget, event)

    def filter_out_arrow_press_keys(self, widget, event):
        if event.key() == Qt.Key_Up:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepSub)
        elif event.key() == Qt.Key_Down:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepAdd)
        else:
            type(widget).keyPressEvent(widget, event)
示例#9
0
class FtcGuiApplication(TouchApplication):
    def __init__(self, args):
        TouchApplication.__init__(self, args)
        self.script_directory = '/home/isys/git/JetsonEV-scripts'

        # create the empty main window
        self.w = TouchWindow("Run Python Script")

        self.relative_path = os.path.dirname(os.path.realpath(__file__))
        self.grid = QGridLayout()
        environment = QProcessEnvironment()
        environment.insert('PYTHONPATH', self.script_directory)
        self.process = QProcess()
        self.process.setProcessEnvironment(environment)
        self.process.readyReadStandardOutput.connect(self.stdoutReady)
        self.process.readyReadStandardError.connect(self.stderrReady)

        self.play_btn = ShadowButton(os.path.join(self.relative_path, 'start'))
        self.play_btn.setText("Start")
        self.play_btn.clicked.connect(self.start_script)
        self.grid.addWidget(self.play_btn, 0, 0, 1, 1)

        self.script_selector = QComboBox()
        self.scan_scripts()
        self.grid.addWidget(self.script_selector, 0, 1, 1, 3)
        self.grid.setColumnStretch(1, 1.5)

        self.grid.setAlignment(Qt.AlignCenter)

        self.stop_btn = ShadowButton(os.path.join(self.relative_path, 'stop'))
        self.stop_btn.setText("Stop")
        self.stop_btn.clicked.connect(self.stop_script)
        self.grid.addWidget(self.stop_btn, 0, 4, 1, 1)
        self.grid.setRowStretch(1, 4)

        self.console_output = QPlainTextEdit()
        self.console_output.setReadOnly(True)
        console_style = "QPlainTextEdit {" \
                        "background-color: black;" \
                        "color: white;" \
                        "}"
        self.console_output.setFocusPolicy(Qt.NoFocus)
        self.console_output.setFrameStyle(3)
        self.console_output.setStyleSheet(console_style)

        self.grid.addWidget(self.console_output, 1, 0, 1, 5)

        self.w.centralWidget.setLayout(self.grid)
        self.w.centralWidget.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.w.centralWidget, event)
        self.w.centralWidget.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.w.centralWidget, event)
        self.w.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.w, event)
        self.w.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.w, event)

        self.play_btn.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.play_btn, event)
        self.play_btn.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.play_btn, event)
        self.stop_btn.keyReleaseEvent = lambda event: self.filter_out_arrow_release_keys(
            self.stop_btn, event)
        self.stop_btn.keyPressEvent = lambda event: self.filter_out_arrow_press_keys(
            self.stop_btn, event)

        self.w.show()
        self.exec_()

    def scan_scripts(self):
        self.script_selector.clear()

        for script in os.listdir(self.script_directory):
            if os.path.isfile(os.path.join(self.script_directory, script)):
                if script[-3:] == '.py':
                    self.script_selector.addItem(script[:-3])

    def start_script(self):
        flags = [
            '-u',
            os.path.join(self.script_directory,
                         self.script_selector.currentText() + '.py')
        ]
        self.process.start('python3', flags)

    def stop_script(self):
        self.process.terminate()

    def fwd_output(self, text):
        self.console_output.appendPlainText(text)
        cursor = self.console_output.textCursor()
        cursor.movePosition(cursor.End)

    def stdoutReady(self):
        text = str(self.process.readAllStandardOutput(), encoding='utf8')
        self.fwd_output(text)

    def stderrReady(self):
        text = str(self.process.readAllStandardError(), encoding='utf8')
        self.fwd_output(text)

    def filter_out_arrow_release_keys(self, widget, event):
        if event.key() == Qt.Key_Up:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepSub)
        elif event.key() == Qt.Key_Down:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepAdd)
        else:
            type(widget).keyReleaseEvent(widget, event)

    def filter_out_arrow_press_keys(self, widget, event):
        if event.key() == Qt.Key_Up:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepSub)
        elif event.key() == Qt.Key_Down:
            self.console_output.verticalScrollBar().triggerAction(
                QAbstractSlider.SliderSingleStepAdd)
        else:
            type(widget).keyPressEvent(widget, event)