Esempio n. 1
0
class DownloadStatus(QScrollArea):
    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        self.setWidgetResizable(True)
        self.w = QWidget(self)
        self.l = QGridLayout(self.w)
        self.setWidget(self.w)

    def __call__(self, resources):
        self.url_map = {}
        self.labels = []
        for url in resources:
            p = self.url_map[url] = QProgressBar(self.w)
            p.setRange(0, 0)
            self.l.addWidget(p, self.l.rowCount(), 0)
            la = QLabel('\xa0' + url)
            self.labels.append(la)
            self.l.addWidget(la, self.l.rowCount() - 1, 1)
        self.l.addWidget(QLabel(''))
        self.l.setRowStretch(self.l.rowCount() - 1, 10)

    def progress(self, url, done, total):
        p = self.url_map.get(url)
        if p is not None:
            if total > 0:
                p.setRange(0, total)
                p.setValue(done)
            else:
                p.setRange(0, 0)
Esempio n. 2
0
class DownloadStatus(QScrollArea):

    def __init__(self, parent=None):
        QScrollArea.__init__(self, parent)
        self.setWidgetResizable(True)
        self.w = QWidget(self)
        self.l = QGridLayout(self.w)
        self.setWidget(self.w)

    def __call__(self, resources):
        self.url_map = {}
        self.labels = []
        for url in resources:
            p = self.url_map[url] = QProgressBar(self.w)
            p.setRange(0, 0)
            self.l.addWidget(p, self.l.rowCount(), 0)
            la = QLabel('\xa0' + url)
            self.labels.append(la)
            self.l.addWidget(la, self.l.rowCount()-1, 1)
        self.l.addWidget(QLabel(''))
        self.l.setRowStretch(self.l.rowCount()-1, 10)

    def progress(self, url, done, total):
        p = self.url_map.get(url)
        if p is not None:
            if total > 0:
                p.setRange(0, total)
                p.setValue(done)
            else:
                p.setRange(0, 0)
Esempio n. 3
0
    def add_declarant(self, var=True, gl=None):
        if not gl:
            gl = self.dec_layout
        dc = {}
        gb_l = QGridLayout()
        if self.cb.currentIndex() == 0 or gl != self.dec_layout:
            # Add Individual
            gb = QGroupBox(tr('Физическое лицо *'))
            gb_l.addWidget(QLabel(tr('Фамилия <em style="color: red">*</em>')))
            w = QLineEdit()
            gb_l.addWidget(w, 0, 1, 1, 1)
            dc['surname'] = w
            gb_l.addWidget(QLabel(tr('Имя <em style="color: red">*</em>')))
            w = QLineEdit()
            gb_l.addWidget(w)
            dc['first_name'] = w
            gb_l.addWidget(QLabel(tr('Отчество')))
            w = QLineEdit()
            gb_l.addWidget(w)
            dc['patronymic'] = w

            adr = QGroupBox(tr('Адрес регистрации *'))
            adr_l = QGridLayout()
            dc['address'] = self.__add_address(adr_l)
            adr.setLayout(adr_l)
            gb_l.addWidget(adr, gb_l.rowCount() + 1, 0, 1, 2)

            gb.setLayout(gb_l)
            gl.addWidget(gb, gl.rowCount() + 1, 0, 1, 2)
            self.individuals.append(dc)
        else:
            # Add LegalEntity
            gb = QGroupBox(
                tr('Юридическое лицо/Индивидуальный предприниматель *'))
            gb_l.addWidget(
                QLabel(
                    tr('Краткое наименование ЮЛ <em style="color: red">*</em>')
                ))
            w = QLineEdit()
            gb_l.addWidget(w, 0, 1, 1, 1)
            dc['name'] = w

            adr = QGroupBox(tr('Юридический адрес *'))
            adr_l = QGridLayout()
            dc['address'] = self.__add_address(adr_l)
            adr.setLayout(adr_l)
            gb_l.addWidget(adr, gb_l.rowCount() + 1, 0, 1, 2)

            gb.setLayout(gb_l)
            gl.addWidget(gb, gl.rowCount() + 1, 0, 1, 2)
            self.entities.append(dc)
Esempio n. 4
0
    def setup_store_checks(self):
        first_run = self.config.get('first_run', True)

        # Add check boxes for each store so the user
        # can disable searching specific stores on a
        # per search basis.
        existing = {}
        for n in self.store_checks:
            existing[n] = self.store_checks[n].isChecked()

        self.store_checks = {}

        stores_check_widget = QWidget()
        store_list_layout = QGridLayout()
        stores_check_widget.setLayout(store_list_layout)

        icon = QIcon(I('donate.png'))
        for i, x in enumerate(
                sorted(self.gui.istores.keys(), key=lambda x: x.lower())):
            cbox = QCheckBox(x)
            cbox.setChecked(existing.get(x, first_run))
            store_list_layout.addWidget(cbox, i, 0, 1, 1)
            if self.gui.istores[x].base_plugin.affiliate:
                iw = QLabel(self)
                iw.setToolTip('<p>' + _(
                    'Buying from this store supports the calibre developer: %s</p>'
                ) % self.gui.istores[x].base_plugin.author + '</p>')
                iw.setPixmap(icon.pixmap(16, 16))
                store_list_layout.addWidget(iw, i, 1, 1, 1)
            self.store_checks[x] = cbox
        store_list_layout.setRowStretch(store_list_layout.rowCount(), 10)
        self.store_list.setWidget(stores_check_widget)

        self.config['first_run'] = False
Esempio n. 5
0
    def setup_store_checks(self):
        first_run = self.config.get('first_run', True)

        # Add check boxes for each store so the user
        # can disable searching specific stores on a
        # per search basis.
        existing = {}
        for n in self.store_checks:
            existing[n] = self.store_checks[n].isChecked()

        self.store_checks = {}

        stores_check_widget = QWidget()
        store_list_layout = QGridLayout()
        stores_check_widget.setLayout(store_list_layout)

        icon = QIcon(I('donate.png'))
        for i, x in enumerate(sorted(self.gui.istores.keys(), key=lambda x: x.lower())):
            cbox = QCheckBox(x)
            cbox.setChecked(existing.get(x, first_run))
            store_list_layout.addWidget(cbox, i, 0, 1, 1)
            if self.gui.istores[x].base_plugin.affiliate:
                iw = QLabel(self)
                iw.setToolTip('<p>' + _('Buying from this store supports the calibre developer: %s</p>') % self.gui.istores[x].base_plugin.author + '</p>')
                iw.setPixmap(icon.pixmap(16, 16))
                store_list_layout.addWidget(iw, i, 1, 1, 1)
            self.store_checks[x] = cbox
        store_list_layout.setRowStretch(store_list_layout.rowCount(), 10)
        self.store_list.setWidget(stores_check_widget)

        self.config['first_run'] = False
Esempio n. 6
0
class Ui(QApplication):
    def __init__(self):
        super().__init__(argv)
        self.w = QMainWindow()
        self.w.setMinimumWidth(300)
        self.w.setMinimumHeight(300)
        # self.w.setWindowTitle(tr("Отправка запросов на ВС АУГО"))
        self.cw = QScrollArea()
        # self.__create_ui()
        self.__showed = False
        self.__wgts = {}
        self.cb = QComboBox()
        self.individuals = []
        self.entities = []
        self.documents = []
        self.doc_files = []
        self.__setupUi(self.w)
        self.w.showMaximized()

    def report_error(self, msg=None):
        if not msg:
            etype, value, tb = exc_info()
            trace = ''.join(format_exception(etype, value, tb))
            delim_len = 40
            msg = ("*" * delim_len + "\n%s\n" + "*" * delim_len) % trace
            error(msg)
        mb = QMessageBox(QMessageBox.Critical, tr('Ошибка'),
                         str(exc_info()[1]))
        mb.setDetailedText(msg)
        mb.exec()

    def __create_ui(self):
        self.l = QGridLayout()
        self.t = QTableWidget(0, 3)
        self.t.setHorizontalHeaderLabels(
            ('№ дела (обращения)', 'Дата приёма', 'Дата отправки в СМЭВ'))
        self.t.resizeColumnsToContents()
        self.l.addWidget(self.t, 0, 0, 1, 2)
        w = QWidget()
        hl = QHBoxLayout(w)
        hl.setDirection(QHBoxLayout.LeftToRight)
        hl.addWidget(QWidget())
        ok_b = QPushButton(tr('Добавить запрос'))
        ok_b.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum)
        ok_b.clicked.connect(self.__show_form)
        hl.addWidget(ok_b)
        w.setLayout(hl)
        self.l.addWidget(w, 1, 0, 1, 2)
        w = QWidget()
        w.setLayout(self.l)
        self.cw.setWidget(w)
        # self.cw.setLayout(self.l)
        # self.w.setCentralWidget(self.cw)
        w = QWidget()
        l = QVBoxLayout()
        l.addWidget(self.cw)
        w.setLayout(l)
        self.w.setCentralWidget(w)

    def __setupUi(self, mainWindow):
        mainWindow.setObjectName("MainWindow")
        self.centralwidget = QWidget(mainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.horizontalLayout = QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.scrollArea = QScrollArea(self.centralwidget)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QWidget()
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.gridLayout = QGridLayout(self.scrollAreaWidgetContents)
        self.gridLayout.setObjectName("gridLayout")
        self.__show_form()
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.horizontalLayout.addWidget(self.scrollArea)
        mainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QMenuBar(mainWindow)
        self.menubar.setObjectName("menubar")
        self.menu = QMenu(self.menubar)
        self.menu.setObjectName("menu")
        mainWindow.setMenuBar(self.menubar)
        self.statusbar = QStatusBar(mainWindow)
        self.statusbar.setObjectName("statusbar")
        mainWindow.setStatusBar(self.statusbar)
        self.action_1 = QAction(mainWindow)
        self.action_1.setObjectName("action")
        self.action_1.triggered.connect(self.send)
        self.action = QAction(mainWindow)
        self.action.setObjectName("action")
        self.action.triggered.connect(self.on_action_triggered)
        self.action_2 = QAction(mainWindow)
        self.action_2.setObjectName("action_2")
        self.action_3 = QAction(mainWindow)
        self.action_3.setObjectName("action_3")
        self.action_3.triggered.connect(self.get_response)
        self.menu.addAction(self.action)
        self.menubar.addAction(self.action_1)
        self.menubar.addAction(self.action_2)
        self.menubar.addAction(self.action_3)
        self.menubar.addAction(self.menu.menuAction())

        self.__retranslateUi(mainWindow)
        QMetaObject.connectSlotsByName(mainWindow)

    @pyqtSlot(bool)
    def get_response(self):
        try:
            from dmsic import Integration
            i = Integration(self)
            res = i.get_response()[0]
            if res:
                QMessageBox.information(self.w, tr("Получен ответ"), str(res))
        except:
            self.report_error()

    @pyqtSlot(bool)
    def send(self):
        try:
            from dmsic import Integration
            i = Integration(self)
            declar = {}
            for k, v in self.__wgts.items():
                if k in ('object_address', 'AppliedDocument', 'legal_entity',
                         'person'):
                    a = {}
                    for key, val in v.items():
                        if val.metaObject().className() == 'QDateEdit':
                            a[key] = datetime.strptime(val.text(), '%d.%m.%Y')
                        else:
                            a[key] = val.text()
                    declar[k] = a
                else:
                    if v.metaObject().className() == 'QDateEdit':
                        declar[k] = datetime.strptime(v.text(), '%d.%m.%Y')
                    else:
                        declar[k] = v.text()
            a = declar[
                'AppliedDocument'] if 'AppliedDocument' in declar else []
            for v in self.documents:
                d = {}
                for key, val in v.items():
                    if val.metaObject().className() == 'QDateEdit':
                        d[key] = datetime.strptime(val.text(), '%d.%m.%Y')
                    else:
                        d[key] = val.text()
                if not self.doc_files:
                    raise Exception('Добавте файл документа')
                d['file_name'] = self.doc_files[self.documents.index(v)]
                a.append(d)
            declar['AppliedDocument'] = a
            a = declar['person'] if 'person' in declar else []
            for v in self.individuals:
                ind = {}
                for key, val in v.items():
                    if key in ('address', 'fact_address'):
                        adr = {}
                        for k, vl in val.items():
                            adr[k] = vl.text()
                        ind[key] = adr
                    else:
                        if val.metaObject().className() == 'QDateEdit':
                            ind[key] = datetime.strptime(
                                val.text(), '%d.%m.%Y')
                        else:
                            ind[key] = val.text()
                a.append(ind)
            declar['person'] = a
            a = declar['legal_entity'] if 'legal_entity' in declar else []
            for v in self.entities:
                ent = {}
                for key, val in v.items():
                    if key == 'address':
                        adr = {}
                        for k, vl in val.items():
                            adr[k] = vl.text()
                        ent[key] = adr
                    else:
                        if val.metaObject().className() == 'QDateEdit':
                            ent[key] = datetime.strptime(
                                val.text(), '%d.%m.%Y')
                        else:
                            ent[key] = val.text()
                a.append(ent)
            declar['legal_entity'] = a
            i.send(declar)
            mb = QMessageBox(self.w)
            mb.information(self.w, tr('Готово'), tr('Запрос отправлен'))
        except:
            self.report_error()

    @pyqtSlot(bool)
    def on_action_triggered(self):
        a = Ui_Dialog()
        d = QDialog()
        a.setupUi(d)
        d.exec()

    def __retranslateUi(self, MainWindow):
        _translate = QCoreApplication.translate
        MainWindow.setWindowTitle(
            _translate("MainWindow", "Отправка запросов на ВС АУГО"))
        # self.pushButton.setText(_translate("MainWindow", "Добавить"))
        self.menu.setTitle(_translate("MainWindow", "Справка"))
        self.action_1.setText(_translate("MainWindow", "Отправить"))
        self.action_2.setText(_translate("MainWindow", "Настройка"))
        self.action.setText(_translate("MainWindow", "О программе"))
        self.action_3.setText(_translate("MainWindow", "Получить ответ"))

    @pyqtSlot(bool)
    def __show_form(self):
        if self.__showed:
            return

        self.gridLayout.addWidget(
            QLabel(tr('№ дела (обращения) <em style="color: red">*</em>')))
        w = QLineEdit()
        self.gridLayout.addWidget(w)
        w.setFocus()
        self.__wgts['declar_number'] = w
        self.gridLayout.addWidget(
            QLabel(
                tr('Услуга (код или номер, или наименование)<em style="color: red">*</em>'
                   )))
        w = QLineEdit()
        self.gridLayout.addWidget(w)
        self.__wgts['service'] = w
        self.gridLayout.addWidget(
            QLabel(
                tr('Дата регистрации запроса <em style="color: red">*</em>')))
        de = QDateEdit(QDate().currentDate())
        de.setCalendarPopup(True)
        self.gridLayout.addWidget(de)
        self.__wgts['register_date'] = de
        self.gridLayout.addWidget(
            QLabel(
                tr('Плановый срок предоставления услуги <em style="color: red">*</em>'
                   )))
        de = QDateEdit()
        self.__wgts['register_date'].dateChanged.connect(de.setMinimumDate)
        de.setCalendarPopup(True)
        de.setMinimumDate(self.__wgts['register_date'].date())
        self.gridLayout.addWidget(de)
        self.__wgts['end_date'] = de

        gb = QGroupBox(tr('Место нахождения объекта услуги'))
        gb_l = QGridLayout()
        self.__wgts['object_address'] = self.__add_address(gb_l)
        gb.setLayout(gb_l)
        self.gridLayout.addWidget(gb, self.gridLayout.rowCount() + 1, 0, 1, 2)

        doc = {}
        gb = QGroupBox(tr('Приложенный документ *'))
        gb_l = QGridLayout()
        gb_l.addWidget(
            QLabel(tr('Наименование документа <em style="color: red">*</em>')))
        w = QLineEdit()
        w.setMaxLength(1024)
        gb_l.addWidget(w, 0, 1, 1, 1)
        doc['title'] = w
        gb_l.addWidget(
            QLabel(tr('Номер документа <em style="color: red">*</em>')))
        w = QLineEdit()
        w.setMaxLength(50)
        gb_l.addWidget(w)
        doc['number'] = w
        gb_l.addWidget(
            QLabel(tr('Дата документа <em style="color: red">*</em>')))
        w = QDateEdit()
        w.setCalendarPopup(True)
        gb_l.addWidget(w)
        doc['date'] = w
        gb_l.addWidget(
            QLabel(
                tr('Прямая ссылка на файл. Поддерживаются только пртоколы '
                   'HTTP, FTP <em style="color: red">*</em>')))
        w = QLineEdit()
        gb_l.addWidget(w)
        doc['url'] = w
        gb.setLayout(gb_l)
        self.gridLayout.addWidget(gb, self.gridLayout.rowCount() + 1, 0, 1, 2)
        self.documents.append(doc)

        gb = QGroupBox(tr('Заявители *'))
        self.dec_layout = QGridLayout()
        self.cb = QComboBox()
        self.cb.addItems(('Физическое лицо',
                          'Юридическое лицо/Индивидуальный предприниматель'))
        self.dec_layout.addWidget(self.cb)
        b = QPushButton(tr('Добавить'))
        b.clicked.connect(self.add_declarant)
        self.dec_layout.addWidget(b, 0, 1, 1, 1)
        gb.setLayout(self.dec_layout)
        self.gridLayout.addWidget(gb, self.gridLayout.rowCount() + 1, 0, 1, 2)

        b = QPushButton(tr('Добавить файл документа'))
        b.clicked.connect(self.__add_doc_file)
        self.gridLayout.addWidget(b)
        self.file_label = QLabel()
        self.gridLayout.addWidget(self.file_label)
        self.warn_label = QLabel(tr("Не удаляйте файл до отправки запроса"))
        self.warn_label.setStyleSheet('color: red')
        self.warn_label.setVisible(False)
        self.gridLayout.addWidget(self.warn_label,
                                  self.gridLayout.rowCount() + 1, 0, 1, 2)

        self.__showed = True

    @pyqtSlot(bool)
    def __add_doc_file(self):
        file_name = QFileDialog.getOpenFileName(
            caption=tr('Выбурите файл'),
            filter=tr('Файлы pdf (*.pdf);;Все файлы (*.*)'))[0]
        self.file_label.setText(file_name)
        if self.doc_files:
            self.doc_files = []
        self.doc_files.append(file_name)
        self.warn_label.setVisible(True)

    def __add_address(self, gb_l):
        wgts = {}
        gb_l.addWidget(QLabel(tr('Почтовый индекс')))
        w = QLineEdit()
        gb_l.addWidget(w, 0, 1, 1, 1)
        wgts['Postal_Code'] = w
        gb_l.addWidget(QLabel(tr('Регион')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Region'] = w
        gb_l.addWidget(QLabel(tr('Район')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['District'] = w
        gb_l.addWidget(QLabel(tr('Муниципальное образование')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['City'] = w
        gb_l.addWidget(QLabel(tr('Городской район')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Urban_District'] = w
        gb_l.addWidget(QLabel(tr('Сельсовет')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Soviet_Village'] = w
        gb_l.addWidget(
            QLabel(tr('Населенный пункт <em style="color: red">*</em>')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Locality'] = w
        cb = QComboBox()
        cb.addItems(('Вариант 1', 'Вариант 2'))
        gb_l.addWidget(cb)
        st = QStackedWidget()
        p1 = QWidget()
        l = QGridLayout()
        l.setSpacing(3)
        l.addWidget(QLabel(tr('Улица <em style="color: red">*</em>')))
        w = QLineEdit()
        l.addWidget(w, 0, 1, 1, 1)
        wgts["Street"] = w
        l.addWidget(QLabel(tr('Дом <em style="color: red">*</em>')))
        w = QLineEdit()
        l.addWidget(w)
        wgts["House"] = w
        p1.setLayout(l)
        st.addWidget(p1)
        p2 = QWidget()
        l = QGridLayout()
        l.setSpacing(3)
        l.addWidget(QLabel(tr('Ориентир')))
        w = QLineEdit()
        l.addWidget(w, 0, 1, 1, 1)
        wgts["Reference_point"] = w
        p2.setLayout(l)
        st.addWidget(p2)
        gb_l.addWidget(st, 9, 0, 1, 2)
        cb.activated.connect(st.setCurrentIndex)
        gb_l.addWidget(QLabel(tr('Корпус')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Housing'] = w
        gb_l.addWidget(QLabel(tr('Строение')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Building'] = w
        gb_l.addWidget(QLabel(tr('Квартира')))
        w = QLineEdit()
        gb_l.addWidget(w)
        wgts['Apartment'] = w
        return wgts

    @pyqtSlot(bool)
    def add_declarant(self, var=True, gl=None):
        if not gl:
            gl = self.dec_layout
        dc = {}
        gb_l = QGridLayout()
        if self.cb.currentIndex() == 0 or gl != self.dec_layout:
            # Add Individual
            gb = QGroupBox(tr('Физическое лицо *'))
            gb_l.addWidget(QLabel(tr('Фамилия <em style="color: red">*</em>')))
            w = QLineEdit()
            gb_l.addWidget(w, 0, 1, 1, 1)
            dc['surname'] = w
            gb_l.addWidget(QLabel(tr('Имя <em style="color: red">*</em>')))
            w = QLineEdit()
            gb_l.addWidget(w)
            dc['first_name'] = w
            gb_l.addWidget(QLabel(tr('Отчество')))
            w = QLineEdit()
            gb_l.addWidget(w)
            dc['patronymic'] = w

            adr = QGroupBox(tr('Адрес регистрации *'))
            adr_l = QGridLayout()
            dc['address'] = self.__add_address(adr_l)
            adr.setLayout(adr_l)
            gb_l.addWidget(adr, gb_l.rowCount() + 1, 0, 1, 2)

            gb.setLayout(gb_l)
            gl.addWidget(gb, gl.rowCount() + 1, 0, 1, 2)
            self.individuals.append(dc)
        else:
            # Add LegalEntity
            gb = QGroupBox(
                tr('Юридическое лицо/Индивидуальный предприниматель *'))
            gb_l.addWidget(
                QLabel(
                    tr('Краткое наименование ЮЛ <em style="color: red">*</em>')
                ))
            w = QLineEdit()
            gb_l.addWidget(w, 0, 1, 1, 1)
            dc['name'] = w

            adr = QGroupBox(tr('Юридический адрес *'))
            adr_l = QGridLayout()
            dc['address'] = self.__add_address(adr_l)
            adr.setLayout(adr_l)
            gb_l.addWidget(adr, gb_l.rowCount() + 1, 0, 1, 2)

            gb.setLayout(gb_l)
            gl.addWidget(gb, gl.rowCount() + 1, 0, 1, 2)
            self.entities.append(dc)
class M3Dashboard(Dashboard):
    """
    Dashboard for Mekabot

    :param context: the plugin context
    :type context: qt_gui.plugin.Plugin
    """
    def setup(self, context):
        self.name = 'Meka Dashboard'
        self.max_icon_size = QSize(50, 30)
        
        self._widget_initialized = False
        self._service_ready = True
        self._last_dashboard_message_time = rospy.Time.now()
        self._path = os.path.join(rospkg.RosPack().get_path('rqt_m3dashboard'), 'images')
        self._battery_icons = {}
        self._state_buttons = {}
        
        self._dashboard_mekaros_subs = {}
        self._m3field_values = {}
        self._m3field_plots = {}
        
        NAMESPACE = '' 

        rospy.loginfo("Starting up...")
        
        # self._state_button = ControlStateButton("default", 9999)
        # TODO read this list on the parameters
        battery_names = ["m3pwr_pwr038", "m3pwr_pwr042"]
        group_names = {"left_hand":"mh26", "left_arm":"ma30", "head":"ms8", "right_arm":"ma29", "right_hand":"mh24", "zlift":"mz7", "torso":"mt6", "base":"mb7"}
        
        # create as many buttons as groups received
        for group_name in group_names.keys():
            self._state_buttons[group_name] = ControlStateButton(group_name, 0)

        battery_widget = self.init_batteries(battery_names)

        self._dashboard_agg_sub = rospy.Subscriber("/meka_roscontrol_state_manager/state", 
                                                       M3ControlStates,                               
                                                       self.state_callback,
                                                       queue_size=1)
        self._actionclient = actionlib.SimpleActionClient("/meka_state_manager", M3StateChangeAction)
        rospy.loginfo("Looking for state manager...")
        if self._actionclient.wait_for_server(timeout=rospy.Duration(0.1)) is False:
            rospy.logfatal("Failed to connect to state_manager action server in 4 sec")
            self._service_ready = False
        else:
            rospy.loginfo("Found the state manager")
            
        self._state_control = rospy.ServiceProxy('/meka_roscontrol_state_manager/change_state', M3ControlStateChange)

        self._main_widget = QWidget()
        vlayout = QVBoxLayout()
        hlayout = QHBoxLayout()
        hlayout2 = QHBoxLayout()

        self.chk_all = QCheckBox("enable_all")
        self.chk_all.setChecked(False)

        self.spin_retries = QSpinBox()
        # infinite number of times is -1
        self.spin_retries.setMinimum(-1)
        self.spin_retries.setMaximum(10)
        self.spin_retries.setValue(2)
        label_retries = QLabel("trial times")

        self.btn_start = QPushButton("start")
        self.btn_stop = QPushButton("stop")
        self.btn_freeze = QPushButton("freeze")
        if not self._service_ready:
            self.btn_start.setEnabled(False)
            self.btn_stop.setEnabled(False)
            self.btn_freeze.setEnabled(False)
            
        inspection_button = self.init_inspection()
        self.hz_rate = QSpinBox()
        # infinite number of times is -1
        self.hz_rate.setMinimum(1)
        self.hz_rate.setMaximum(100)
        self.hz_rate.setValue(1)
        label_hz = QLabel("hz")

        hlayout2.addWidget(inspection_button)
        hlayout2.addWidget(self.hz_rate)
        hlayout2.addWidget(label_hz)
        
        hlayout.addWidget(self.chk_all)
        hlayout.addWidget(label_retries)
        hlayout.addWidget(self.spin_retries)

        self.inspection_layout = QGridLayout()
        self.stiffness_layout = self.init_stiffness_ctrl()
        
        #vlayout.addWidget()
        vlayout.addWidget(battery_widget)
        vlayout.addLayout(hlayout)
        vlayout.addWidget(self.btn_start)
        vlayout.addWidget(self.btn_freeze)
        vlayout.addWidget(self.btn_stop)
        
        vlayout.addLayout(self.stiffness_layout)
        vlayout.addLayout(hlayout2)
        vlayout.addLayout(self.inspection_layout)

        self.btn_start.clicked.connect(self.on_btn_start_clicked)
        self.btn_stop.clicked.connect(self.on_btn_stop_clicked)
        self.btn_freeze.clicked.connect(self.on_btn_freeze_clicked)
        self.chk_all.stateChanged.connect(self.on_enable_all_clicked)

        self._main_widget.setLayout(vlayout)
        self.context.add_widget(self._main_widget)
        # self._main_widget.addLayout(hlayout)
        self._widget_initialized = True
        
    def init_batteries(self, battery_names):
        
        widget = QWidget()
        layout = QHBoxLayout(widget)        
        fields = ["motor_enabled", "bus_voltage"]        
        dt = Floats
                 
        for battery_name in battery_names:
            self._battery_icons[battery_name] = WrappedBattery(self.context, battery_name)
            layout.addWidget(self._battery_icons[battery_name])
            self._dashboard_mekaros_subs[(battery_name, fields[0])] = rospy.Subscriber("/meka_ros_pub/"+battery_name+"/"+fields[0], dt, self.battery_pwrd_cb, battery_name)                            
            self._dashboard_mekaros_subs[(battery_name, fields[1])] = rospy.Subscriber("/meka_ros_pub/"+battery_name+"/"+fields[1], dt, self.battery_voltage_cb, battery_name)
            
        layout.addStretch(1)
        widget.setFixedHeight(75)

        #self.bat_lbb = QLabel("Battery voltage")
        #self.bat_txt = QLabel()
        #self.bat_txt.setText("0.0")

        return widget
    
    
    def init_stiffness_ctrl(self):
        
        slayout = QVBoxLayout()
        
        prefix = "meka_roscontrol"
        suffix = "stiffness_controller/command"
        
        button = QPushButton("Stiffness controller (beta)")

        self.stiffness_pub = rospy.Publisher("/" + prefix + "/" + suffix, Float64MultiArray, queue_size=1)
        group_names = ["right_arm", "left_arm", "right_hand", "left_hand", "head", "torso", "zlift"]
        # slider for each group
        joint_names = [ "right_arm_j0",
                        "right_arm_j1",
                        "right_arm_j2",
                        "right_arm_j3",
                        "right_arm_j4",
                        "right_arm_j5",
                        "right_arm_j6",
                        "left_arm_j0",
                        "left_arm_j1",
                        "left_arm_j2",
                        "left_arm_j3",
                        "left_arm_j4",
                        "left_arm_j5",
                        "left_arm_j6",
                        "right_hand_j0",
                        "right_hand_j1",
                        "right_hand_j2",
                        "right_hand_j3",
                        "right_hand_j4",
                        "left_hand_j0",
                        "left_hand_j1",
                        "left_hand_j2",
                        "left_hand_j3",
                        "left_hand_j4",
                        "head_j0",
                        "head_j1",
                        "torso_j0",
                        "torso_j1",
                        "zlift_j0"]
        
        self._stiffness_dict = OrderedDict((name, 1.0) for name in joint_names)
        
        menu = QMenu("Menu")
        menu.setStyleSheet("QMenu { menu-scrollable: 1; }");
        self.stiffnessvals = {}
        for group in group_names:
            glayout = QHBoxLayout()
            glayout.addWidget(QLabel(group))
            slider = QSlider(Qt.Horizontal)
            slider.setRange(0,100)
            slider.setValue(100)
            slider.setTickPosition(QSlider.TicksBelow)
            slider.setTickInterval(10)
            slider.setFixedSize(200,15)
            slider.setSingleStep(10)
            slider.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
            
            val = QLabel("1.0")
            btn = QPushButton("apply")
            self.stiffnessvals[group] = val
            btn.clicked.connect(partial(self.on_stiffness_apply, group))
            
            glayout.addWidget(slider)
            glayout.addWidget(val)
            glayout.addWidget(btn)
            
            slider.valueChanged.connect(partial(self.on_stiffness_change, slider, val, group))
            
            slayout.addLayout(glayout)
            
            
            groupm = menu.addMenu(group)
            #for joint in joint_names:
                #groupm.addAction("set stiffness", partial(self.set_stiffness, groupm))
                #if group in joint:
                #    groupm.addAction(self._stiffness_dict[joint])
                #    s.addAction(joint, partial(self.request_fields, component, s))
        
        

        button.setMenu(menu)

        return slayout

    def init_inspection(self):

        button = QPushButton("Robot inspection (beta)")

        service_list_comps = '/meka_ros_publisher/list_components'
        service_list_fields = '/meka_ros_publisher/list_fields'
        service_req_values = '/meka_ros_publisher/request_values'
        rospy.loginfo("Waiting for %s, %s and %s", service_list_comps, service_list_fields, service_req_values)
        try:
            rospy.wait_for_service(service_list_comps, 4.0)
            rospy.wait_for_service(service_list_fields, 4.0)
            rospy.wait_for_service(service_req_values, 4.0)
        except rospy.ROSException:
            rospy.logerr("%s and/or %s did not show up. Giving up", service_list_comps, service_list_fields)
            return button
            
        self.list_comps_client = rospy.ServiceProxy(service_list_comps, ListComponents)
        self.list_fields_client = rospy.ServiceProxy(service_list_fields, ListFields)
        self.req_vals_client = rospy.ServiceProxy(service_req_values, RequestValues)
        rospy.loginfo("Found %s, %s and %s", service_list_comps, service_list_fields, service_req_values)

        # get all the components
        try:
            resp = self.list_comps_client("")
        except rospy.ServiceException:
            rospy.logerr("Could not call list_components")
            return button
            
        menu = QMenu("Menu")
        menu.setStyleSheet("QMenu { menu-scrollable: 1; }");
        submenus = []

        self.req_action = {}
        if(resp):
            for component in resp.components:
                s = menu.addMenu(component)
                self.req_action[component] = s.addAction("request fields", partial(self.request_fields, component, s))
                

        button.setMenu(menu)

        return button

    def init_inspection_test(self):

        button = QPushButton("Robot inspection (beta)")

        menu = QMenu("Menu")
        menu.setStyleSheet("QMenu { menu-scrollable: 1; }");
        submenus = []


        for i in range(5):
            # a component has fields which are either strings or arrays.
            s = menu.addMenu(str(i))
            for j in range(5):
                s.addAction(str(j), partial(self.subscribe_to_field_test, "blubber", j))

        button.setMenu(menu)

        return button

    def testbaloon(self, name):

        name_label = QLabel(name)
        lineedit = QLineEdit("random")
        name_label.setBuddy(lineedit);

        close_btn = QPushButton()

        pixmap = QPixmap(self._path + "/close.png")
        icon = QIcon(pixmap);
        close_btn.setIcon(icon)
        close_btn.setIconSize(pixmap.rect().size())

        idx = self.inspection_layout.rowCount()

        close_btn.clicked.connect(partial(self.remove_row, self.inspection_layout, idx, False))
        self.inspection_layout.addWidget(name_label, idx, 0);
        self.inspection_layout.addWidget(lineedit, idx, 1);
        self.inspection_layout.addWidget(close_btn, idx, 2);

    def subscribe_to_field_test(self, component, bla):

        field = str(bla)

        if (component, field) in self._m3field_values:
            rospy.logwarn("Already subscribed to field. Exiting.")
            return


        dt = Floats
        topic = str("/meka_ros_pub/" + component + "/" + field)
        self._dashboard_mekaros_subs[(component, field)] = rospy.Subscriber(topic, dt, self.field_callback, (component, field))
        self._m3field_values[(component, field)] = []

        name_label = QLabel(component + "->" + field + ":")
        for val in range(bla):
            label = QLabel(str(val)[:5])
            label.setStyleSheet("border: 2px solid grey");
            self._m3field_values[(component, field)].append(label)

        idx = self.inspection_layout.rowCount()

        plot_pixmap = QPixmap(self._path + "/plot.png")
        plot_icon = QIcon(plot_pixmap);
        plot_btn = QPushButton()
        plot_btn.setIcon(plot_icon)
        plot_btn.setIconSize(plot_pixmap.rect().size())
        plot_btn.setFixedWidth(30)
        plot_btn.clicked.connect(partial(self.plot_values, component, field))

        close_pixmap = QPixmap(self._path + "/close.png")
        close_icon = QIcon(close_pixmap);
        close_btn = QPushButton()
        close_btn.setIcon(close_icon)
        close_btn.setIconSize(close_pixmap.rect().size())
        close_btn.setFixedWidth(30)
        close_btn.clicked.connect(partial(self.remove_row, self.inspection_layout, idx, False, component, field))

        self.inspection_layout.addWidget(name_label, idx, 0)
        val_layout = QHBoxLayout()
        for label in self._m3field_values[(component, field)]:
            print label
            val_layout.addWidget(label);
        self.inspection_layout.addLayout(val_layout, idx, 1)
        self.inspection_layout.addWidget(plot_btn, idx, 2)
        self.inspection_layout.addWidget(close_btn, idx, 3)


    def request_fields(self, component, top_menu):
        
        # a component has fields which are either strings or arrays.
        try:
            resp2 = self.list_fields_client(component)
        except rospy.ServiceException:
            rospy.logerr("Could not call list_fields")
            return
        if(resp2):
            for field in resp2.fields:
                top_menu.addAction(field, partial(self.subscribe_to_field, component, field))
                
        self.req_action[component].setEnabled(False)


    def subscribe_to_field(self, component, field):
        
        if (component, field) in self._m3field_values:
            rospy.logwarn("Already subscribed to field. Exiting.")
            return
                
        try:
            resp = self.req_vals_client(component, field, "", self.hz_rate.value())
        except rospy.ServiceException:
            rospy.logerr("Could not call request_values")
            return
        
        print resp.values
        
        dt = Floats
        topic = str("/meka_ros_pub/"+component+"/"+field)
        self._dashboard_mekaros_subs[(component, field)] = rospy.Subscriber(topic, dt, self.field_callback, (component, field))
        self._m3field_values[(component, field)] = []
        
        name_label = QLabel(component+"->"+field+":")
        for val in resp.values:
            label = QLabel(str(val)[:5])
            label.setStyleSheet("border: 2px solid grey");
            self._m3field_values[(component, field)].append(label)
        
        idx = self.inspection_layout.rowCount()
        
        plot_pixmap = QPixmap(self._path + "/plot.png")
        plot_icon = QIcon(plot_pixmap);
        #plot_btn = QPushButton()
        #plot_btn.setIcon(plot_icon)
        #plot_btn.setIconSize(plot_pixmap.rect().size())
        #plot_btn.setFixedWidth(30)
        #plot_btn.clicked.connect(partial(self.plot_values, component, field))
        
        close_pixmap = QPixmap(self._path + "/close.png")
        close_icon = QIcon(close_pixmap);
        close_btn = QPushButton()
        close_btn.setIcon(close_icon)
        close_btn.setIconSize(close_pixmap.rect().size())
        close_btn.setFixedWidth(30)
        close_btn.clicked.connect(partial(self.remove_row, self.inspection_layout, idx, False, component, field))
        
        self.inspection_layout.addWidget(name_label, idx, 0)
        val_layout = QHBoxLayout()
        for label in self._m3field_values[(component, field)]:
            val_layout.addWidget(label);
        self.inspection_layout.addLayout(val_layout, idx, 1)
        #self.inspection_layout.addWidget(plot_btn, idx, 2)
        self.inspection_layout.addWidget(close_btn, idx, 3)
        
    def plot_values(self, component, field):
        """
        plot_values create a new plot for the values of the given component and field
        :params component, field:
        :type component: Identifier of the component, field: Identifier of the field
        """
        dialog = PlotDialog()
        QObject.connect(dialog, SIGNAL('rejected()'), partial(self.on_plot_close,  component, field))
        dialog.init_plot(component, field)
        dialog.show()
        
        self._m3field_plots[(component, field)] = dialog
        
        #dialog.exec_()

    
    def change_state(self, cmd):
        """
        change_state calls the m3rosctrl robot interface to change the 
        state of one or multiple joint groups (e.g. "head" to "freeze")
        :params cmd:
        :type cmd: Identifier of the new state
        """
        goal = M3StateChangeGoal()
        goal.retries = 0
        if self.spin_retries.value() == -1:
            goal.strategy = M3StateChangeGoal.KEEP_TRYING
        if self.spin_retries.value() == 0:
            goal.strategy = M3StateChangeGoal.HALT_ON_FAILURE
        if self.spin_retries.value() == 1:
            goal.strategy = M3StateChangeGoal.BEST_POSSIBLE

        if self.spin_retries.value() > 1:
            goal.strategy = M3StateChangeGoal.RETRY_N_TIMES
            goal.retries = self.spin_retries.value()

        # find enabled groups
        for group_name in self._state_buttons:
            if self._state_buttons[group_name]._enable_menu.isChecked():
                goal.command.group_name.append(group_name)
                goal.command.state.append(cmd)
        try:
            if len(goal.command.group_name) > 0:
                self._actionclient.send_goal(goal)
        except rospy.ROSException:
            rospy.logerr("Failed to call change state")

    def on_stiffness_apply(self, group):
        print "change stiffness"
        msg = Float64MultiArray()
        for name in self._stiffness_dict:
            msg.data.append(self._stiffness_dict[name])
        rospy.logdebug(msg)
        self.stiffness_pub.publish(msg)
        

    def on_stiffness_change(self, slider, val, group):
        
        newval = float(slider.value())/100.0
        
        for key, value in self._stiffness_dict.iteritems():
            if group in key:
                self._stiffness_dict[key] = newval
        
        val.setText(str(newval))
        

    def on_enable_all_clicked(self):
        """
        enable all
        """
        state_cmd = M3ControlStateChangeRequest()
                    
        for group_name in self._state_buttons:
            state_cmd.command.group_name.append(group_name)
            if self.chk_all.isChecked():
                self._state_buttons[group_name]._enable_menu.setChecked(True)
                self._state_buttons[group_name]._disable_menu.setChecked(False)
                self._state_buttons[group_name]._enable_menu.setEnabled(False)
                self._state_buttons[group_name]._disable_menu.setEnabled(True)
                state_cmd.command.state.append(STATE_CMD_ENABLE)
            else:
                self._state_buttons[group_name]._enable_menu.setChecked(False)
                self._state_buttons[group_name]._disable_menu.setChecked(True)
                self._state_buttons[group_name]._enable_menu.setEnabled(True)
                self._state_buttons[group_name]._disable_menu.setEnabled(False)
                state_cmd.command.state.append(STATE_CMD_DISABLE)
        try:
            self._state_control(state_cmd)
        except rospy.ServiceException, e:
            QMessageBox.critical(self, "Error", "Service call failed with error: %s" % (e), "Error")
Esempio n. 8
0
class _ExecuteTab(QTabWidget):
    """Tab used to execute modules or shell commands on the selected bot."""
    def __init__(self, responses_tab: _ResponsesTab, model):
        super().__init__()

        self._model = model
        self._current_layout = None
        self._current_bot = None

        self._layout = QGridLayout()
        self._sub_layout = QVBoxLayout()
        self._module_view = ModuleView(responses_tab)

        self._layout.setAlignment(Qt.AlignTop)
        self.setLayout(self._layout)
        self.set_empty_layout()

    def set_current_bot(self, bot: Bot):
        """Sets the connected bot this tab will interact with."""
        self._current_bot = bot

    def _clear_layout(self):
        while self._layout.count():
            child = self._layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()
        while self._sub_layout.count():
            child = self._sub_layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()

    def set_empty_layout(self):
        """Default layout shown when the user has not yet selected a row."""
        self._current_layout = "Empty"
        self._clear_layout()

        self._layout.addWidget(
            QLabel("Please select a bot in the table above."), 0, 0)

    def set_module_layout(self, module_name: str = "screenshot"):
        """Sets the layout which can execute modules."""
        self._current_layout = "Module"
        self._clear_layout()

        command_type_label = QLabel("Command type: ")
        command_type_combobox = QComboBox()

        command_type_combobox.addItem("Module")
        command_type_combobox.addItem("Shell")

        module_label = QLabel("Module name: ")
        module_combobox = QComboBox()

        for module_name in modules.get_names():
            module_combobox.addItem(module_name)

        module_combobox.currentTextChanged.connect(self._on_module_change)
        command_type_combobox.currentTextChanged.connect(
            self._on_command_type_change)

        self._layout.setColumnStretch(1, 1)
        self._layout.addWidget(command_type_label, 0, 0)
        self._layout.addWidget(command_type_combobox, 0, 1)
        self._layout.addWidget(module_label, 1, 0)
        self._layout.addWidget(module_combobox, 1, 1)

        # Module layout
        cached_module = modules.get_module(module_name)

        if not cached_module:
            cached_module = modules.load_module(module_name, self._module_view,
                                                self._model)

        input_fields = []

        for option_name in cached_module.get_setup_messages():
            input_field = QLineEdit()

            self._sub_layout.addWidget(QLabel(option_name))
            self._sub_layout.addWidget(input_field)
            input_fields.append(input_field)

        run_button = QPushButton("Run")
        run_button.setMaximumWidth(250)
        run_button.setMinimumHeight(25)

        run_button.pressed.connect(lambda: self._on_module_run(
            module_combobox.currentText(), input_fields))

        self._sub_layout.addWidget(QLabel(""))
        self._sub_layout.addWidget(run_button)
        self._sub_layout.setContentsMargins(0, 15, 0, 0)
        self._layout.addLayout(self._sub_layout,
                               self._layout.rowCount() + 2, 0, 1, 2)

        self._on_module_change(module_combobox.currentText())

    def set_shell_layout(self):
        """Sets the layout which can execute shell commands."""
        self._current_layout = "Shell"
        self._clear_layout()

        command_type_label = QLabel("Command type: ")
        command_type_combobox = QComboBox()

        command_type_combobox.addItem("Shell")
        command_type_combobox.addItem("Module")

        command_label = QLabel("Command:")
        command_input = QLineEdit()

        run_button = QPushButton("Run")
        run_button.setMaximumWidth(250)
        run_button.setMinimumHeight(25)

        command_type_combobox.currentTextChanged.connect(
            self._on_command_type_change)
        run_button.pressed.connect(lambda: self._on_command_run(command_input))

        self._layout.addWidget(command_type_label, 0, 0)
        self._layout.addWidget(command_type_combobox, 0, 1)
        self._layout.addWidget(command_label, 1, 0)
        self._layout.addWidget(command_input, 1, 1)

        self._sub_layout.addWidget(QLabel(""))
        self._sub_layout.addWidget(run_button)
        self._sub_layout.setContentsMargins(0, 15, 0, 0)
        self._layout.addLayout(self._sub_layout,
                               self._layout.rowCount() + 2, 0, 1, 2)

    def _on_command_type_change(self, text: str):
        """Handles the command type combobox change event."""
        if text == "Module":
            self.set_module_layout()
        else:
            self.set_shell_layout()

    def _on_module_change(self, module_name: str):
        """Handles module combobox changes."""
        while self._sub_layout.count():
            child = self._sub_layout.takeAt(0)

            if child.widget():
                child.widget().deleteLater()

        cached_module = modules.get_module(module_name)

        if not cached_module:
            cached_module = modules.load_module(module_name, self._module_view,
                                                self._model)

        input_fields = []

        for option_name in cached_module.get_setup_messages():
            input_field = QLineEdit()
            input_fields.append(input_field)

            self._sub_layout.addWidget(QLabel(option_name))
            self._sub_layout.addWidget(input_field)

        run_button = QPushButton("Run")
        run_button.setMaximumWidth(250)
        run_button.setMinimumHeight(25)

        run_button.pressed.connect(
            lambda: self._on_module_run(module_name, input_fields))

        self._sub_layout.addWidget(QLabel(""))
        self._sub_layout.addWidget(run_button)
        self._sub_layout.setContentsMargins(0, 15, 0, 0)

    def display_info(self, text: str):
        message_box = QMessageBox()

        message_box.setIcon(QMessageBox.Information)
        message_box.setWindowTitle("Information")
        message_box.setText(text)
        message_box.setStandardButtons(QMessageBox.Ok)
        message_box.exec_()

    def _on_module_run(self, module_name: str, input_fields: list):
        """Handles running modules."""
        set_options = []

        for input_field in input_fields:
            set_options.append(input_field.text())

        module = modules.get_module(module_name)

        if not module:
            module = modules.load_module(module_name, self._module_view,
                                         self._model)

        successful, options = module.setup(set_options)

        if successful:
            if module_name == "remove_bot":
                code = loaders.get_remove_code(self._current_bot.loader_name)
            elif module_name == "update_bot":
                code = loaders.get_update_code(self._current_bot.loader_name)
            else:
                code = modules.get_code(module_name)

            if not options:
                options = {}

            options["module_name"] = module_name

            self._model.add_command(self._current_bot.uid,
                                    Command(CommandType.MODULE, code, options))

            self.display_info("Module added to the queue of:\n {}@{}".format(
                self._current_bot.username, self._current_bot.hostname))

    def _on_command_run(self, command_input: QLineEdit):
        """Handles running commands."""
        if command_input.text().strip() == "":
            return

        self._model.add_command(
            self._current_bot.uid,
            Command(CommandType.SHELL,
                    command_input.text().encode()))

        command_input.clear()
        self.display_info("Command added to the queue of:\n {}@{}".format(
            self._current_bot.username, self._current_bot.hostname))
Esempio n. 9
0
class ConfigWidget(QWidget):
    def __init__(self, plugin):
        QWidget.__init__(self)
        self.plugin = plugin

        self.overl = l = QVBoxLayout(self)
        self.gb = QGroupBox(_('Metadata fields to download'), self)
        if plugin.config_help_message:
            self.pchm = QLabel(plugin.config_help_message)
            self.pchm.setWordWrap(True)
            self.pchm.setOpenExternalLinks(True)
            l.addWidget(self.pchm, 10)
        l.addWidget(self.gb)
        self.gb.l = g = QVBoxLayout(self.gb)
        g.setContentsMargins(0, 0, 0, 0)
        self.fields_view = v = FieldsList(self)
        g.addWidget(v)
        v.setFlow(QListView.Flow.LeftToRight)
        v.setWrapping(True)
        v.setResizeMode(QListView.ResizeMode.Adjust)
        self.fields_model = FieldsModel(self.plugin)
        self.fields_model.initialize()
        v.setModel(self.fields_model)
        self.memory = []
        self.widgets = []
        self.l = QGridLayout()
        self.l.setContentsMargins(0, 0, 0, 0)
        l.addLayout(self.l, 100)
        for opt in plugin.options:
            self.create_widgets(opt)

    def create_widgets(self, opt):
        val = self.plugin.prefs[opt.name]
        if opt.type == 'number':
            c = QSpinBox if isinstance(opt.default,
                                       numbers.Integral) else QDoubleSpinBox
            widget = c(self)
            widget.setValue(val)
        elif opt.type == 'string':
            widget = QLineEdit(self)
            widget.setText(val if val else '')
        elif opt.type == 'bool':
            widget = QCheckBox(opt.label, self)
            widget.setChecked(bool(val))
        elif opt.type == 'choices':
            widget = QComboBox(self)
            items = list(iteritems(opt.choices))
            items.sort(key=lambda k_v: sort_key(k_v[1]))
            for key, label in items:
                widget.addItem(label, (key))
            idx = widget.findData((val))
            widget.setCurrentIndex(idx)
        widget.opt = opt
        widget.setToolTip(textwrap.fill(opt.desc))
        self.widgets.append(widget)
        r = self.l.rowCount()
        if opt.type == 'bool':
            self.l.addWidget(widget, r, 0, 1, self.l.columnCount())
        else:
            l = QLabel(opt.label)
            l.setToolTip(widget.toolTip())
            self.memory.append(l)
            l.setBuddy(widget)
            self.l.addWidget(l, r, 0, 1, 1)
            self.l.addWidget(widget, r, 1, 1, 1)

    def commit(self):
        self.fields_model.commit()
        for w in self.widgets:
            if isinstance(w, (QSpinBox, QDoubleSpinBox)):
                val = w.value()
            elif isinstance(w, QLineEdit):
                val = unicode_type(w.text())
            elif isinstance(w, QCheckBox):
                val = w.isChecked()
            elif isinstance(w, QComboBox):
                idx = w.currentIndex()
                val = unicode_type(w.itemData(idx) or '')
            self.plugin.prefs[w.opt.name] = val