示例#1
0
class AreasBrowserDialog(BaseDialog):
    def __init__(self, parent, area_name, areas):
        super().__init__(parent, _("Select the area you mean"), _("&Select"),
                         _("&Close"))
        self._areas = list(areas.items())
        for id, (parent_name, data) in self._areas:
            self._areas_list.addItem(
                _("{area_name}, {parent_name}").format(
                    area_name=area_name, parent_name=parent_name))
        self._areas_list.setCurrentRow(0)

    def create_ui(self):
        areas_label = QLabel(_("Areas"))
        self.layout.addWidget(areas_label, 0, 0)
        self._areas_list = QListWidget(self)
        areas_label.setBuddy(self._areas_list)
        self._areas_list.currentRowChanged.connect(self.on_areas_list_listbox)
        self.layout.addWidget(self._areas_list, 1, 0)
        props_label = QLabel(_("Area properties"))
        self.layout.addWidget(props_label, 0, 1)
        self._area_props = QListWidget()
        props_label.setBuddy(self._area_props)
        self.layout.addWidget(self._area_props, 1, 1)

    def on_areas_list_listbox(self, index):
        self._area_props.clear()
        for key, value in self._areas[index][1][1].items():
            self._area_props.addItem(f"{underscored_to_words(key)}: {value}")
        self._area_props.addItem(
            _("Area id: {}").format(self._areas[index][0]))

    @property
    def selected_area_id(self):
        return self._areas[self._areas_list.currentRow()][0]
示例#2
0
class SimpleTodoPlus(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.todo_list_widget = QListWidget(self)
        self.todo_list_widget.itemChanged.connect(self.onItemChanged)

        self.add_todo_btn = QPushButton("Add Todo", self)
        self.add_todo_btn.clicked.connect(self.add_todo_btn_clicked)

        self.remove_todo_btn = QPushButton("Remove Todo", self)
        self.remove_todo_btn.clicked.connect(self.remove_todo_btn_clicked)

        self.clear_todo_btn = QPushButton("Clear Todo", self)
        self.clear_todo_btn.clicked.connect(self.clear_todo_btn_clicked)

        vbox_layout = QVBoxLayout(self)
        vbox_layout.addWidget(self.todo_list_widget)

        hbox_layout = QHBoxLayout()
        hbox_layout.addWidget(self.add_todo_btn)
        hbox_layout.addWidget(self.remove_todo_btn)
        hbox_layout.addWidget(self.clear_todo_btn)

        vbox_layout.addLayout(hbox_layout)

    def add_todo_btn_clicked(self):
        item = QListWidgetItem(f"Todo {self.todo_list_widget.count() + 1}")
        item.setFlags(item.flags() | Qt.ItemIsUserCheckable
                      | Qt.ItemIsEditable)
        item.setCheckState(Qt.Unchecked)
        self.todo_list_widget.addItem(item)
        self.todo_list_widget.edit(self.todo_list_widget.indexFromItem(item))

    def remove_todo_btn_clicked(self):
        if self.todo_list_widget.count():
            self.todo_list_widget.takeItem(self.todo_list_widget.currentRow())

    def clear_todo_btn_clicked(self):
        self.todo_list_widget.clear()

    def onItemChanged(self, item):
        font = item.font()
        font.setStrikeOut(item.checkState() == Qt.Checked)
        item.setFont(font)
示例#3
0
class LevelSelector(QDialog):
    def __init__(self, parent):
        super(LevelSelector, self).__init__(parent)

        self.setWindowTitle("Level Selector")
        self.setModal(True)

        self.selected_world = 1
        self.selected_level = 1
        self.object_set = 0
        self.object_data_offset = 0x0
        self.enemy_data_offset = 0x0

        self.world_label = QLabel(parent=self, text="World")
        self.world_list = QListWidget(parent=self)
        self.world_list.addItems(WORLD_ITEMS)

        self.world_list.itemDoubleClicked.connect(self.on_ok)
        self.world_list.itemSelectionChanged.connect(self.on_world_click)

        self.level_label = QLabel(parent=self, text="Level")
        self.level_list = QListWidget(parent=self)

        self.level_list.itemDoubleClicked.connect(self.on_ok)
        self.level_list.itemSelectionChanged.connect(self.on_level_click)

        self.enemy_data_label = QLabel(parent=self, text="Enemy Data")
        self.enemy_data_spinner = Spinner(parent=self)

        self.object_data_label = QLabel(parent=self, text="Object Data")
        self.object_data_spinner = Spinner(self)

        self.object_set_label = QLabel(parent=self, text="Object Set")
        self.object_set_dropdown = QComboBox(self)
        self.object_set_dropdown.addItems(OBJECT_SET_ITEMS)

        self.button_ok = QPushButton("Ok", self)
        self.button_ok.clicked.connect(self.on_ok)
        self.button_cancel = QPushButton("Cancel", self)
        self.button_cancel.clicked.connect(self.close)

        self.window_layout = QGridLayout(self)

        self.window_layout.addWidget(self.world_label, 0, 0)
        self.window_layout.addWidget(self.level_label, 0, 1)

        self.window_layout.addWidget(self.world_list, 1, 0)
        self.window_layout.addWidget(self.level_list, 1, 1)

        self.window_layout.addWidget(self.enemy_data_label, 2, 0)
        self.window_layout.addWidget(self.object_data_label, 2, 1)
        self.window_layout.addWidget(self.enemy_data_spinner, 3, 0)
        self.window_layout.addWidget(self.object_data_spinner, 3, 1)

        self.window_layout.addWidget(self.object_set_label, 4, 0)
        self.window_layout.addWidget(self.object_set_dropdown, 4, 1)

        self.window_layout.addWidget(self.button_ok, 5, 0)
        self.window_layout.addWidget(self.button_cancel, 5, 1)

        self.setLayout(self.window_layout)

        self.world_list.setCurrentRow(1)  # select Level 1-1
        self.on_world_click()

    def keyPressEvent(self, key_event: QKeyEvent):
        if key_event.key() == Qt.Key_Escape:
            self.reject()

    def on_world_click(self):
        index = self.world_list.currentRow()

        assert index >= 0

        self.level_list.clear()

        # skip first meaningless item
        for level in Level.offsets[1:]:
            if level.game_world == index:
                if level.name:
                    self.level_list.addItem(level.name)

        if self.level_list.count():
            self.level_list.setCurrentRow(0)

            self.on_level_click()

    def on_level_click(self):
        index = self.level_list.currentRow()

        assert index >= 0

        self.selected_world = self.world_list.currentRow()
        self.selected_level = index + 1

        level_is_overworld = self.selected_world == OVERWORLD_MAPS_INDEX

        if level_is_overworld:
            level_array_offset = self.selected_level
        else:
            level_array_offset = Level.world_indexes[self.selected_world] + self.selected_level

        object_data_for_lvl = Level.offsets[level_array_offset].rom_level_offset

        if not level_is_overworld:
            object_data_for_lvl -= Level.HEADER_LENGTH

        self.object_data_spinner.setValue(object_data_for_lvl)

        if not level_is_overworld:
            enemy_data_for_lvl = Level.offsets[level_array_offset].enemy_offset
        else:
            enemy_data_for_lvl = 0

        if enemy_data_for_lvl > 0:
            # data in look up table is off by one, since workshop ignores the first byte
            enemy_data_for_lvl -= 1

        self.enemy_data_spinner.setValue(enemy_data_for_lvl)
        self.enemy_data_spinner.setEnabled(not level_is_overworld)

        # if self.selected_world >= WORLD_1_INDEX:
        object_set_index = Level.offsets[level_array_offset].real_obj_set
        self.object_set_dropdown.setCurrentIndex(object_set_index)

        self.button_ok.setDisabled(self.selected_world == 0)

    def on_ok(self, _):
        if self.selected_world == 0:
            return

        self.object_set = self.object_set_dropdown.currentIndex()
        self.object_data_offset = self.object_data_spinner.value()
        # skip the first byte, because it seems useless
        self.enemy_data_offset = self.enemy_data_spinner.value() + 1

        self.accept()

    def closeEvent(self, _close_event: QCloseEvent):
        self.reject()
示例#4
0
class ObjectsBrowserWindow(QWidget):
    def __init__(self,
                 parent,
                 title,
                 person,
                 unsorted_objects,
                 autoshow=True,
                 progress_indicator=None):
        super().__init__(None)
        act = QAction("close", self)
        act.triggered.connect(self._do_close)
        act.setShortcut(QKeySequence("escape"))
        self.addAction(act)
        layout = QGridLayout()
        bar = QMenuBar(self)
        self._object_actions = bar.addMenu(_("Object actions"))
        property_actions = bar.addMenu(_("Property actions"))
        self._create_item(property_actions, _("Copy property value"), "ctrl+c",
                          self.on_copypropvalue_selected)
        self._create_item(property_actions, _("Copy property name"), "alt+c",
                          self.on_copypropname_selected)
        self._create_item(property_actions, _("Copy property name and value"),
                          "ctrl+alt+c", self.on_copypropline_selected)
        objects_label = QLabel(_("Objects"), self)
        layout.addWidget(objects_label, 0, 0)
        self._objects_list = QListWidget(self)
        self._objects_list.setAccessibleName(objects_label.text())
        self._objects_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._objects_list.currentRowChanged.connect(self.on_objects_listbox)
        self._objects_list.customContextMenuRequested.connect(
            self._on_objects_list_menu)
        objects_label.setBuddy(self._objects_list)
        layout.addWidget(self._objects_list, 1, 0)
        props_label = QLabel(_("Object properties"), self)
        layout.addWidget(props_label, 0, 1)
        self._props = QTreeWidget(self)
        self._props.setAccessibleName(props_label.text())
        props_label.setBuddy(self._props)
        layout.addWidget(self._props, 1, 1)
        goto_button = QPushButton(_("Go to"), self)
        goto_button.setDefault(True)
        goto_button.clicked.connect(self.on_goto_clicked)
        self._objects_list.itemActivated.connect(goto_button.click)
        layout.addWidget(goto_button, 2, 0)
        close_button = QPushButton(_("Close"), self)
        close_button.clicked.connect(self.close)
        layout.addWidget(close_button, 2, 1)
        self.setLayout(layout)
        self.setWindowTitle(title + _(" ({num_objects} objects shown)").format(
            num_objects=len(unsorted_objects)))
        self._person = person
        self._autoshow = autoshow
        self._progress_indicator = progress_indicator
        self._all_actions = []
        for member in object_actions.__dict__.values():
            if inspect.isclass(member) and issubclass(member, ObjectAction):
                self._all_actions.append(member)
        self._objects_list.setCurrentRow(0)
        self._sorter = ObjectsSorter(unsorted_objects, person)
        self._sorter.objects_sorted.connect(self._objects_sorted)
        self._sorter.start()

    def _objects_sorted(self, data):
        objects, item_data = data
        self._objects = objects
        for (desc, dist, rel_bearing) in item_data:
            self._objects_list.addItem(
                _("{object}: distance {distance} meters, {rel_bearing}").
                format(object=desc, distance=dist, rel_bearing=rel_bearing))
        if self._progress_indicator:
            self._progress_indicator.hide()
            self._progress_indicator.deleteLater()
        if self._autoshow:
            self._objects_list.setCurrentRow(0)
            self.show()

    def _create_item(self, menu, label, shortcut, callback):
        action = menu.addAction(label)
        action.triggered.connect(callback)
        action.setShortcut(QKeySequence(shortcut))

    def on_goto_clicked(self, evt):
        self._person.move_to(self.selected_object[2], force=True)

    def _do_close(self):
        self.close()
        self.destroy()
        windows = QApplication.topLevelWidgets()
        other_browsers = [
            w for w in windows if w is not self
            and isinstance(w, self.__class__) and w.isVisible()
        ]
        if other_browsers:
            other_browsers[-1].activateWindow()
        else:
            menu_service().ensure_key_capturer_focus()

    def on_objects_listbox(self, current_index):
        selected = self._objects[current_index][1]
        self._props.clear()
        common_item = QTreeWidgetItem([_("Common properties")])
        specific_item = QTreeWidgetItem([_("Specific properties")])
        other_item = QTreeWidgetItem([
            _("Other properties - they can not be searched and are not processed in any way"
              )
        ])
        common_fields = list(
            EntityMetadata.for_discriminator("OSMEntity").fields.keys())
        selected_metadata = EntityMetadata.for_discriminator(
            selected.discriminator)
        known_fields = selected_metadata.all_fields
        formatted_values = {}
        for field_name in selected.defined_field_names():
            raw_value = selected.value_of_field(field_name)
            if field_name not in known_fields:
                # By the mere fact that the other fields have no defined order, we can add them there without losing anything.
                other_item.addChild(
                    QTreeWidgetItem([
                        "%s: %s" %
                        (underscored_to_words(field_name), raw_value)
                    ]))
            else:
                value_str = "%s: %s" % (
                    underscored_to_words(field_name),
                    format_field_value(raw_value,
                                       known_fields[field_name].type_name))
                formatted_values[field_name] = value_str
        for common in common_fields:
            del known_fields[common]
            common_item.addChild(QTreeWidgetItem([formatted_values[common]]))
        for specific in known_fields.keys(
        ):  # Because we deleted the common ones in the loop before this, only the specific remain.
            if specific in formatted_values:
                specific_item.addChild(
                    QTreeWidgetItem([formatted_values[specific]]))
        # We add the entity ID mainly for debugging purposes, and that's the reason why it is added the last and so special in the first place.
        common_item.addChild(
            QTreeWidgetItem([_("Object id: {}").format(selected.id)]))
        self._props.addTopLevelItem(common_item)
        if specific_item.childCount() > 0:
            self._props.addTopLevelItem(specific_item)
            self._props.expandItem(specific_item)
            #self._props.setCurrentItem(specific_item) # Breaks focus behavior slightly, but annoingly enough.
        if other_item.childCount() > 0:
            self._props.addTopLevelItem(other_item)
        self._object_actions.clear()
        for action in self._all_actions:
            if action.executable(selected):
                mi = self._object_actions.addAction(action.label)
                mi.triggered.connect(
                    action_execution_handler_factory(action, selected, self))

    @property
    def selected_object(self):
        return self._objects[self._objects_list.currentRow()]

    def on_copypropvalue_selected(self, evt):
        prop = self._props.currentItem().text(0)
        val = prop.split(": ", 1)[1]
        QApplication.clipboard().setText(val)

    def on_copypropname_selected(self, evt):
        prop = self._props.currentItem().text(0)
        name = prop.split(": ", 1)[0]
        QApplication.clipboard().setText(name)

    def on_copypropline_selected(self, evt):
        prop = self._props.currentItem().text(0)
        QApplication.clipboard().setText(prop)

    def _on_objects_list_menu(self, point):
        self._object_actions.exec_(point)
示例#5
0
class Form(QWidget):
    """"""
    def __init__(
        self,
        parent: QApplication = None,
        *,
        title: str = "wooo",
        width: int = 400,
        height: int = 600,
    ) -> None:
        """Constructor"""
        super().__init__(parent)
        mixer.init()  # initializethe pygame mixer

        self.assets_path: str = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'assets')

        if parent is not None:
            self.parent = parent
        """
        self.parent.iconbitmap()
        """
        horiz_pos = 100  # from left of screen
        vertic_pos = 200  # from top of screen
        self.height = height
        self.width = width
        self.title = title

        self.setGeometry(horiz_pos, vertic_pos, self.width,
                         self.height)  # QtCore.QRect(x, y, w, h)
        self.setWindowTitle(self.title)

        self.setWindowIcon(QtGui.QIcon(self.assets_path + '/icons/melody.ico'))
        self.init_vol: int = 70
        self.paused: bool = False
        self.muted: bool = False
        self.playing: bool = False
        self.current_song: Opt[str] = None
        self.selected_song_num: Opt[int] = None
        self.playlist: List[str] = []

        self._init_ui()
        self.show()

    def _init_ui(self) -> None:
        self.layout = QVBoxLayout()
        self._menubar()

        self._create_rightframe()
        self._create_middleframe()
        self._create_leftframe()
        self._create_bottomframe()

        self.edit = QLineEdit("Write my name here")
        self.layout.addWidget(self.edit)

        self.greet_button = QPushButton("Show Greetings")
        self.greet_button.clicked.connect(self.greetings)
        self.layout.addWidget(self.greet_button)

        self._statusbar()
        self.setLayout(self.layout)

    def _menubar(self) -> None:
        menubar = QMenuBar()
        self.layout.addWidget(menubar)

        fileMenu = menubar.addMenu('File')
        fileMenu.addAction('Open', self.browse_file)
        fileMenu.addSeparator()
        fileMenu.addAction('Exit', self.close)

        helpMenu = menubar.addMenu('Help')
        helpMenu.addSeparator()
        helpMenu.addAction('About Us', self.about_us)
        # toolbar = self.addToolBar('Exit')
        # toolbar.addAction(self.play_music)

    def _statusbar(self) -> None:
        self.statusbar = QStatusBar()
        self.layout.addWidget(self.statusbar)
        self.statusbar.showMessage('Welcome', timeout=10_000)
        # status_bar = statusbar_parent.addPermanentWidget(statusbar_parent, stretch=True)

    def _create_rightframe(self) -> None:
        self.rightframe = QVBoxLayout()
        self.layout.addLayout(self.rightframe)

        self.filelabel = QLabel(text='Lets make some noise!')
        self.rightframe.addWidget(self.filelabel)

        self.lengthlabel = QLabel(text='Total Length : --:--')
        self.rightframe.addWidget(self.lengthlabel)

        self.currenttimelabel = QLabel(text='Current Time : --:--')
        self.rightframe.addWidget(self.currenttimelabel)

    def _create_leftframe(self) -> None:
        self.leftframe = QVBoxLayout()
        self.layout.addLayout(self.leftframe)

        self.playlistbox = QListWidget(self)
        self.playlistbox.setToolTip('''PlayListBox:
                                    Select song from list to play.
                                    Use browse or delete buttons to change playlist'''
                                    )
        self.leftframe.addWidget(self.playlistbox)

        self.browse_button = QPushButton("Browse")
        self.browse_button.clicked.connect(self.browse_file)
        self.leftframe.addWidget(self.browse_button)

        self.delete_button = QPushButton("Delete")
        self.delete_button.clicked.connect(self.del_song)
        self.leftframe.addWidget(self.delete_button)

    def _create_middleframe(self) -> None:
        self.middleframe = QVBoxLayout()
        self.layout.addLayout(self.middleframe)

        self.play_button = QPushButton("Play")
        self.play_button.clicked.connect(self.play_music)
        play_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/play.png'))
        # play_icon.addPixmap(QtGui.QPixmap(self.assets_path + '/icons/play.png'))
        self.play_button.setIcon(play_icon)
        # self.play_button.setIconSize(QtCore.QSize(100, 100))
        self.middleframe.addWidget(self.play_button)

        self.stop_button = QPushButton("Stop")
        self.stop_button.clicked.connect(self.stop_music)
        stop_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/stop.png'))
        self.stop_button.setIcon(stop_icon)
        # self.stop_button.setIconSize(QtCore.QSize(100, 100))
        self.middleframe.addWidget(self.stop_button)

        self.pause_button = QPushButton("Pause")
        self.pause_button.clicked.connect(self.pause_music)
        pause_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/pause.png'))
        self.pause_button.setIcon(pause_icon)
        # self.pause_button.setIconSize(QtCore.QSize(100, 100))
        self.middleframe.addWidget(self.pause_button)

    def _create_bottomframe(self) -> None:
        self.bottomframe = QVBoxLayout()
        self.layout.addLayout(self.bottomframe)

        self.volume_button = QPushButton("Mute")
        self.mute_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/mute.png'))
        self.volume_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/volume.png'))
        self.volume_button.setIcon(self.volume_icon)
        # self.volume_button.setIconSize(QtCore.QSize(100, 100))
        self.volume_button.clicked.connect(self.mute_music)
        self.bottomframe.addWidget(self.volume_button)

        self.rewind_button = QPushButton("Rewind")
        rewind_icon = QtGui.QIcon(
            QtGui.QPixmap(self.assets_path + '/icons/rewind.png'))
        self.rewind_button.setIcon(rewind_icon)
        # self.volume_button.setIconSize(QtCore.QSize(100, 100))
        self.play_button.clicked.connect(self.rewind_music)
        self.bottomframe.addWidget(self.rewind_button)

        self.vol_scale = QSlider(QtCore.Qt.Horizontal)
        self.vol_scale.setMinimum(0)
        self.vol_scale.setMaximum(100)
        # self.vol_scale.setTickPosition(QSlider.TicksBelow)
        # self.vol_scale.setTickInterval(5)
        self.vol_scale.setValue(self.init_vol)
        self.vol_scale.valueChanged.connect(self.set_vol)
        self.bottomframe.addWidget(self.vol_scale)
        mixer.music.set_volume(self.vol_scale.value())

        # exitAction = QtGui.QAction('Exit', self)
        # exitAction.setShortcut('Ctrl+Q')
        # exitAction.setStatusTip('Exit application')
        # exitAction.triggered.connect(self.close)

    def set_vol(self) -> None:
        self.vol_from_slider: int = self.vol_scale.value()
        volume_percent: float = self.vol_from_slider / 100
        mixer.music.set_volume(volume_percent)  # from 0 to 1

    def mute_music(self) -> None:
        if self.muted:  # Unmute the music
            mixer.music.set_volume(self.vol_pre_mute / 100)
            self.volume_button.setIcon(self.volume_icon)
            self.vol_scale.setValue(
                self.vol_pre_mute)  # (self.vol_from_slider)
            self.muted = False
        else:  # mute the music
            self.vol_pre_mute: int = self.vol_scale.value()
            mixer.music.set_volume(0)
            self.volume_button.setIcon(self.mute_icon)
            self.vol_scale.setValue(0)
            self.muted = True

    def greetings(self) -> None:
        text = self.edit.text()
        print('Contents of QLineEdit widget: {}'.format(text))
        self.statusbar.showMessage(text, timeout=2_000)

    def about_us(self) -> None:
        text = self.edit.text()
        print('Contents of QLineEdit widget: {}'.format(text))

    def browse_file(self) -> None:
        get_filename_path: Tuple[str, str] = QFileDialog.getOpenFileName(
            self,  # if cancelled, returns ("", "")
            "Open Sound File",
            self.assets_path,
            "Sound Files (*.wav *.mp3 *.ogg)")
        print(get_filename_path)
        filename_path = get_filename_path[0]
        if filename_path:
            self.add_to_playlist(filename_path)
            mixer.music.queue(filename_path)

    def add_to_playlist(self, filepath: str) -> None:
        filename = os.path.basename(filepath)
        index = 0
        # print(self.playlist)
        # QListWidgetItem(self.playlistbox).setText(filename)  # last_added =
        self.playlistbox.insertItem(index, filename)  # .addItems([filenames])
        self.playlist.insert(index, filepath)
        index += 1

    def del_song(self) -> None:
        self.get_selected_song_num()  # update self.selected_song_num
        if self.selected_song_num is not None:  # if a song is selected
            print(self.selected_song_num)
            if self.playlist[
                    self.
                    selected_song_num] == self.current_song:  # if song is currently playing
                self.stop_music()  # stop it
            self.playlistbox.takeItem(
                self.selected_song_num
            )  # remove the song from the box, note returns the song object
            self.playlist.pop(self.selected_song_num)  # and playlist
            # self.selected_song_num remains same, so will play/del next song?
            self.reset_song()
            self.statusbar.showMessage("Song removed from playlist",
                                       timeout=1_000)
            self.selected_song_num = None  # reset self.selected_song_num"""

    def get_selected_song_num(self) -> None:
        if self.playlistbox.count() > 0:
            selected_song_from_box = self.playlistbox.currentItem(
            )  # get current item
            if selected_song_from_box:
                self.selected_song: str = selected_song_from_box.text(
                )  # get items text
                self.selected_song_num = self.playlistbox.currentRow()
            else:
                self.statusbar.showMessage("Choose a file from the playlist",
                                           timeout=2_000)
        else:
            self.statusbar.showMessage("No files loaded to playlist",
                                       timeout=2_000)

    def stop_music(self) -> None:
        if self.playing:
            self.playing = False
            self.current_song = None
            mixer.music.stop()
            self.statusbar.showMessage("Music Stopped", timeout=5_000)

    def pause_music(self) -> None:
        if self.playing:
            self.paused = True
            mixer.music.pause()
            self.statusbar.showMessage("Music paused", timeout=0)

    def rewind_music(self) -> None:
        if self.playing:
            self.stop_music()
            time.sleep(0.5)
            self.play_music()
            self.statusbar.showMessage("Music Rewound to start", timeout=1_000)

    def reset_song(self) -> None:
        self.current_song = None
        self.filelabel.setText("")
        self.lengthlabel.setText('Total Length : --:00')
        self.currenttimelabel.setText("Current Time : --:--")
        # self.statusbar.showMessage("", timeout=0)

    def show_details(self, play_song: str) -> None:
        self.filelabel.setText("Playing" + ' - ' + os.path.basename(play_song))
        file_data = os.path.splitext(play_song)

        if file_data[1] == '.mp3':
            audio = MP3(play_song)
            total_length = audio.info.length
        elif file_data[1] == '.wav':
            a = mixer.Sound(play_song)
            total_length = a.get_length()
        else:
            try:
                a = mixer.Sound(play_song)
                total_length = a.get_length()
            except Exception as e:
                print(e)
        self.current_song_lenth = total_length
        mins, secs = divmod(total_length, 60)  # returns (time//60, remainder)
        mins = round(mins)
        secs = round(secs)
        timeformat = '{:02d}:{:02d}'.format(mins, secs)
        self.lengthlabel.setText("Total Length" + ' - ' + timeformat)

        self.t1 = threading.Thread(target=self.start_count,
                                   args=(total_length, ))
        self.t1.start()

    def start_count(self, total_time: int) -> None:
        """"""
        current_time = 0
        while current_time <= total_time and mixer.music.get_busy(
        ):  # music.get_busy() -> Returns False when stopped
            if self.paused:
                continue  # if paused, infinite loop (don't count)
            else:
                mins, secs = divmod(current_time, 60)
                mins = round(mins)
                secs = round(secs)
                timeformat = '{:02d}:{:02d}'.format(mins, secs)
                self.currenttimelabel.setText("Current Time" + ' - ' +
                                              timeformat)
                time.sleep(1)
                current_time += 1

    def play_music(self) -> None:
        '''if not playing: play, if playing and paused, unpause'''
        self.get_selected_song_num()  # update self.selected_song_num
        if self.selected_song_num is not None and self.playlist:
            play_it: Opt[str] = self.playlist[self.selected_song_num]
        else:
            play_it = None

        if not self.playing and play_it:  # if not yet playing, play selected song
            try:
                self.stop_music()
                time.sleep(0.5)
                mixer.music.load(play_it)
                mixer.music.play()
            except Exception as e:
                # messagebox.showerror('File not found, or unknown file type. Please check again.')
                if DEBUG: print(e)
            else:
                self.playing = True
                self.current_song = play_it
                self.show_details(play_it)
                self.statusbar.showMessage("Playing music" + ' - ' +
                                           os.path.basename(play_it))
        elif self.playing and self.paused:  # if paused, resume
            mixer.music.unpause()
            # self.statusbar.showMessage("Playing music" + ' - ' + os.path.basename(play_it))
            self.statusbar.showMessage("Music Resumed", timeout=1_000)
            self.paused = False
        elif self.playing and not self.paused:
            if play_it == self.current_song and play_it is not None:  # if already playing song, do nothing
                self.statusbar.showMessage(
                    "Playing music" + ' - ' + os.path.basename(play_it),
                    timeout=0)  # TODO timout current song len
            else:  # if different song selected, retry
                self.playing = False
                self.play_music()

    def close(self) -> None:
        try:
            self.stop_music()
            QApplication.closeAllWindows()
        except Exception as e:
            sys.exit(1)
            if DEBUG: print(e)
        else:
            print('App closed')
示例#6
0
class ReportListComponent(QGroupBox):
    currentAnalysisChanged = Signal(object)

    def __init__(self):
        super().__init__()

        self.setTitle("Rapports disponibles")

        main_layout = QVBoxLayout(self)
        self._list = QListWidget()
        self._list.setContextMenuPolicy(Qt.CustomContextMenu)
        self._list.customContextMenuRequested.connect(self._showItemMenu)
        self._list.currentRowChanged.connect(self._currentAnalysisChanged)
        self._list.itemDoubleClicked.connect(lambda item: self._renameItem())

        self._analysis = None

        main_layout.addWidget(self._list)

    def reset(self, analysis: Analysis):
        self._current_analysis_file = None
        self._analysis = analysis

        self._list.clear()
        for analysis in HistoryManager.analysisList():
            item = QListWidgetItem("%s (%s)" % (analysis["name"], analysis["date"]))
            item.setData(Qt.UserRole, analysis["file"])
            item.setData(Qt.UserRole + 1, analysis["name"])
            self._list.addItem(item)
        
        self._list.setCurrentRow(0)

    @Slot(int)
    def _currentAnalysisChanged(self, row: int):
        if row < 0:
            return
        
        new_analysis_file = self._list.item(row).data(Qt.UserRole)

        if self._current_analysis_file == new_analysis_file:
            return

        if self._current_analysis_file is None:
            self._current_analysis_file = new_analysis_file
            return

        self._current_analysis_file = new_analysis_file
        self._analysis = HistoryManager.loadAnalysis(new_analysis_file)
        self.currentAnalysisChanged.emit(self._analysis)

    @Slot(QPoint)
    def _showItemMenu(self, pos: QPoint):
        globalPos = self._list.mapToGlobal(pos)

        actions_menu = QMenu()
        actions_menu.addAction("Renommer", self._renameItem)
        actions_menu.addAction("Supprimer",  self._eraseItem)

        actions_menu.exec_(globalPos)

    @Slot()
    def _renameItem(self):
        item = self._list.currentItem()
        
        input_dialog = QInputDialog(self.parentWidget(), Qt.WindowSystemMenuHint | Qt.WindowTitleHint | Qt.WindowCloseButtonHint)
        font = input_dialog.font()
        font.setPixelSize(16)
        input_dialog.setFont(font)
        input_dialog.setMinimumWidth(300)
        input_dialog.setInputMode(QInputDialog.TextInput)
        input_dialog.setWindowTitle("Renommer l'analyse")
        input_dialog.setLabelText("Nouveau nom pour '%s' :" % item.data(Qt.UserRole + 1))
        input_dialog.setTextValue(item.data(Qt.UserRole + 1))
        input_dialog.setOkButtonText("OK")
        input_dialog.setCancelButtonText("Annuler")

        if not input_dialog.exec_():
            return
        
        new_name = input_dialog.textValue()

        if self._analysis is None:
            return

        if new_name == self._analysis.parameters().name():
            return
        
        regexp = QRegExp("^[a-zA-Z0-9_-#éèêëàîï ]{5,30}$")
        
        if not regexp.exactMatch(new_name):
            QMessageBox.warning(self, "Nouveau nom invalide", "Caractères autorisés : alphanumérique, espace, #, - et _ avec une longueur maximale de 30 caractères")
            return


        self._analysis.parameters().setName(new_name)
        HistoryManager.renameAnalysis(item.data(Qt.UserRole), self._analysis)
        
        current_row = self._list.currentRow()
        self.reset(self._analysis)
        self._list.setCurrentRow(current_row)
        self.currentAnalysisChanged.emit(self._analysis)

    @Slot()
    def _eraseItem(self):
        item = self._list.currentItem()

        message_box = QMessageBox()
        message_box.setIcon(QMessageBox.Warning)
        message_box.setWindowTitle("Supprimer une analyse ?")
        message_box.setText("Voulez vous vraiment supprimer l'analyse '%s' de façon définitive ?" % item.data(Qt.UserRole + 1))
        message_box.setInformativeText("Assurez vous d'avoir exportez toutes les données dont vous avez besoin.")
        message_box.setStandardButtons(QMessageBox.Yes | QMessageBox.No)

        ret = message_box.exec_()
        if ret == QMessageBox.Yes:
            HistoryManager.deleteAnalysis(item.data(Qt.UserRole))
            self._list.takeItem(self._list.currentRow())

        if self._list.currentRow() == -1:
            self.currentAnalysisChanged.emit(None)
示例#7
0
class AreaSelectionDialog(BaseDialog):
    def __init__(self, parent):
        super().__init__(parent,
                         _("Select an area"),
                         _("&Select"),
                         _("&Exit"),
                         cancel_button_column=2,
                         buttons_to_new_row=False)
        self._initialize_areas()

    def _initialize_areas(self):
        if has_api_connectivity():
            available = get_areas()
            cache_area_names(available)
        else:
            available = get_local_area_infos()
            self.request_button.setDisabled(True)
        collator = QCollator()
        available.sort(key=functools.cmp_to_key(
            lambda a, b: collator.compare(a["name"], b["name"])))
        self._area_ids = [a["osm_id"] for a in available]
        self._area_names = [a["name"] for a in available]
        self._fill_areas(available)

    def create_ui(self):
        areas_label = QLabel(_("&Available areas"))
        self.layout.addWidget(areas_label, 0, 0, 1, 3)
        self._areas = QListWidget()
        self._areas.setAccessibleName(_("Available areas"))
        self.layout.addWidget(self._areas, 1, 0, 1, 3)
        areas_label.setBuddy(self._areas)
        self.request_button = QPushButton(_("&Request a new area"))
        self.layout.addWidget(self.request_button, 2, 1)
        self.request_button.clicked.connect(self.on_request_clicked)

    def _fill_areas(self, areas):
        for area in areas:
            area["created_at"] = rfc_3339_to_local_string(area["created_at"])
            area["updated_at"] = rfc_3339_to_local_string(area["updated_at"])
            area["db_size"] = format_size(area["db_size"])
            self._areas.addItem(
                _("{name}: {state}, last updated {updated_at}, file size {db_size}, created {created_at}"
                  ).format(**area))

    @property
    def selected_map(self):
        return self._area_ids[self._areas.currentRow()]

    @property
    def selected_map_name(self):
        return self._area_names[self._areas.currentRow()]

    def on_request_clicked(self):
        name, ok = QInputDialog.getText(
            self, _("Enter the name of the requested area"),
            _("Area name requested"))
        if not ok or not name:
            return
        self._searched_name = name
        self._searcher = AreaCandidatesSearcher(name)
        self._searcher.results_ready.connect(self._on_area_candidates)
        self._searcher.rate_limited.connect(self._on_rate_limited)
        self._indicator = SearchIndicator()
        self._indicator.show()
        self._searcher.start()

    def _on_rate_limited(self):
        self._indicator.hide()
        QMessageBox.warning(
            self, _("Query limit reached"),
            _("You've reached the query limit for the overpass API, which is used for area searches. Try to request the area in a few minutes."
              ))

    def _on_area_candidates(self, candidates):
        self._indicator.hide()
        if not candidates:
            QMessageBox.warning(
                self, _("Area not found"),
                _("The area with name {name} does not correspond to any OSM areas."
                  ).format(name=self._searched_name))
            return
        if len(candidates) == 1:
            area_id = next(iter(candidates.keys()))
            log.info("Only one candidate with an admin level of %s and id %s.",
                     next(iter(candidates.values()))[1]["admin_level"],
                     area_id)
        else:
            dialog = AreasBrowserDialog(self,
                                        area_name=self._searched_name,
                                        areas=candidates)
            res = dialog.exec_()
            if res == QDialog.DialogCode.Accepted:
                area_id = dialog.selected_area_id
            else:
                return
        reply = request_area_creation(area_id, self._searched_name)
        if reply and isinstance(
                reply,
                dict) and "state" in reply and reply["state"] == "Creating":
            QMessageBox.information(
                self, _("Success"),
                _("The area creation request has been sent successfully. The area will become updated in a few minutes."
                  ))
            self._areas.clear()
            self._initialize_areas()
        elif reply and isinstance(
                reply, dict) and "state" in reply and reply["state"] in {
                    "Creating", "Updated", "ApplyingChanges", "GettingChanges"
                }:
            QMessageBox.information(
                self, _("Success"),
                _("The area creation request has already been sent."))
        else:
            QMessageBox.warning(
                self,
                text=
                _("The area creation request failed. Response from server: {reply}"
                  ).format(reply=reply),
                title=_("Failure"))
示例#8
0
class appConfigScreen(QWidget):
    keybind_signal = Signal("QObject")
    update_signal = Signal("QObject")

    def __init__(self, appName, parms={}):
        super().__init__()
        self.dbg = False
        self.level = 'user'
        exePath = sys.argv[0]
        if os.path.islink(sys.argv[0]):
            exePath = os.path.realpath(sys.argv[0])
        baseDir = os.path.abspath(os.path.dirname(exePath))
        os.chdir(baseDir)
        self.rsrc = "%s/rsrc" % baseDir
        self.parms = parms
        self.modules = []
        self.appName = appName
        self.textDomain = self.appName.lower().replace(" ", "_")
        gettext.textdomain('{}'.format(self.textDomain))
        _ = gettext.gettext
        self.wikiPage = appName
        self.background = "%s/background.png" % self.rsrc
        self.banner = "%s/%s" % (self.rsrc, "banner.png")
        self.last_index = 0
        self.stacks = {0: {'name': _("Options"), 'icon': 'icon'}}
        self.appConfig = appConfig()
        self.config = {}

    #def init

    def _debug(self, msg):
        if self.dbg:
            print("%s" % msg)

    #def _debug

    def setWiki(self, url):
        self.wikiPage = url

    #def setWiki

    def setTextDomain(self, textDomain):
        self.textDomain = textDomain

    #def setTextDomain

    def setRsrcPath(self, rsrc):
        if os.path.isdir(rsrc):
            self.rsrc = rsrc
        else:
            self._debug("%s doesn't exists")
        self._debug("Resources dir: %s" % self.rsrc)

    #def setRsrcPath

    def setIcon(self, icon):
        self._debug("Icon: %s" % icon)
        icn = icon
        if not os.path.isfile(icon):
            sw_ko = False
            self._debug("%s not found" % icon)
            if QtGui.QIcon.fromTheme(icon):
                icn = QtGui.QIcon.fromTheme(icon)
                if icn.name() == "":
                    self._debug("%s not present at theme" % icon)
                    sw_ko = True
                else:
                    self._debug("%s found at theme" % icon)
                    self._debug("Name: %s found at theme" % icn.name())
            elif os.path.isfile("%s/%s" % (self.rsrc, icon)):
                icon = "%s/%s" % (self.rsrc, icon)
                self._debug("%s found at rsrc folder" % icon)
                icn = QtGui.QIcon(icon)
            else:
                icn = QtGui.QIcon.fromTheme("application-menu")
                self._debug("Icon not found at %s" % self.rsrc)
            if sw_ko:
                icn = QtGui.QIcon.fromTheme("application-menu")
                self._debug("Icon %s not found at theme" % icon)
        self.setWindowIcon(icn)

    #def setIcon

    def setBanner(self, banner):
        if not os.path.isfile(banner):
            if os.path.isfile("%s/%s" % (self.rsrc, banner)):
                banner = "%s/%s" % (self.rsrc, banner)
            else:
                banner = ""
                self._debug("Banner not found at %s" % self.rsrc)
        self.banner = banner

    #def setBanner

    def setBackgroundImage(self, background):
        if not os.path.isfile(background):
            if os.path.isfile("%s/%s" % (self.rsrc, background)):
                background = "%s/%s" % (self.rsrc, background)
            else:
                background = ""
                self._debug("Background not found at %s" % self.rsrc)
        self.background = background

    #def setBanner

    def setConfig(self, confDirs, confFile):
        self.appConfig.set_baseDirs(confDirs)
        self.appConfig.set_configFile(confFile)

    #def setConfig(self,confDirs,confFile):

    def _searchWiki(self):
        url = ""
        baseUrl = "https://wiki.edu.gva.es/lliurex/tiki-index.php?page="
        if self.wikiPage.startswith("http"):
            url = self.wikiPage
        else:
            url = "%s%s" % (baseUrl, self.wikiPage)
        #try:
        #	req=Request(url)
        #	content=urlopen(req).read()
        #except:
        #	self._debug("Wiki not found at %s"%url)
        #	url=""
        return (url)

    #def _searchWiki

    def _get_default_config(self):
        data = {}
        data = self.appConfig.getConfig('system')
        self.level = data['system'].get('config', 'user')
        if self.level != 'system':
            data = self.appConfig.getConfig(self.level)
            level = data[self.level].get('config', 'n4d')
            if level != self.level:
                self.level = level
                data = self.appConfig.getConfig(level)
                data[self.level]['config'] = self.level

        self._debug("Read level from config: %s" % self.level)
        return (data)

    #def _get_default_config(self,level):

    def getConfig(self, level=None, exclude=[]):
        data = self._get_default_config()
        if not level:
            level = self.level
        if level != 'system':
            data = {}
            data = self.appConfig.getConfig(level, exclude)
        self.config = data.copy()
        self._debug("Read level from config: %s" % level)
        return (data)

    #def getConfig(self,level):

    def Show(self):
        if self.config == {}:
            self.getConfig()
        self.setStyleSheet(self._define_css())
        if os.path.isdir("stacks"):
            for mod in os.listdir("stacks"):
                if mod.endswith(".py"):
                    mod_name = mod.split(".")[0]
                    mod_import = "from stacks.%s import *" % mod_name
                    try:
                        exec(mod_import)
                        self.modules.append(mod_name)
                        self._debug("Load stack %s" % mod_name)
                    except Exception as e:
                        #						self._debug("Unable to load %s: %s"%(mod_name,e))
                        print("Unable to load %s: %s" % (mod_name, e))
        idx = 1
        for mod_name in self.modules:
            try:
                mod = eval("%s(self)" % mod_name)
            except Exception as e:
                #				self._debug("Import failed for %s: %s"%(mod_name,e))
                print("Import failed for %s: %s" % (mod_name, e))
                continue
            if type(mod.index) == type(0):
                if mod.index > 0:
                    idx = mod.index
            try:
                if mod.enabled == False:
                    continue
            except:
                pass
            while idx in self.stacks.keys():
                idx += 1
                self._debug("New idx for %s: %s" % (mod_name, idx))
            if 'parm' in mod.__dict__.keys():
                try:
                    if mod.parm:
                        self._debug("Setting parms for %s" % mod_name)
                        self._debug("self.parms['%s']" % mod.parm)
                        mod.apply_parms(eval("self.parms['%s']" % mod.parm))
                except Exception as e:
                    self._debug("Failed to pass parm %s to %s: %s" %
                                (mod.parm, mod_name, e))
            try:
                mod.setTextDomain(self.textDomain)
            except Exception as e:
                print("Can't set textdomain for %s: %s" % (mod_name, e))
            try:
                mod.setAppConfig(self.appConfig)
            except Exception as e:
                print("Can't set appConfig for %s: %s" % (mod_name, e))
            try:
                if mod.visible == False:
                    visible = False
                else:
                    visible = True
            except:
                visible = True
            self.stacks[idx] = {
                'name': mod.description,
                'icon': mod.icon,
                'tooltip': mod.tooltip,
                'module': mod,
                'visible': visible
            }
            try:
                mod.message.connect(self._show_message)
            except:
                pass
        self._render_gui()
        return (False)

    def _render_gui(self):
        self.getConfig()
        box = QGridLayout()
        img_banner = QLabel()
        if os.path.isfile(self.banner):
            img = QtGui.QPixmap(self.banner)
            img_banner.setPixmap(img)
        img_banner.setAlignment(Qt.AlignCenter)
        img_banner.setObjectName("banner")
        box.addWidget(img_banner, 0, 0, 1, 2)
        self.lst_options = QListWidget()
        self.stk_widget = QStackedWidget()
        idx = 0
        if len(self.stacks) > 2:
            l_panel = self._left_panel()
            box.addWidget(l_panel, 1, 0, 1, 1, Qt.Alignment(1) | Qt.AlignTop)
        #	self.stk_widget.setCurrentIndex(0)
        else:
            idx = 1
        #	self.stk_widget.setCurrentIndex(1)
        r_panel = self._right_panel()
        self.stk_widget.setCurrentIndex(idx)
        #self.gotoStack(idx,"")
        box.addWidget(r_panel, 1, 1, 1, 1)
        self.setLayout(box)
        self.show()

    #def _render_gui

    def _left_panel(self):
        panel = QWidget()
        box = QVBoxLayout()
        btn_menu = QPushButton()
        icn = QtGui.QIcon.fromTheme("application-menu")
        btn_menu.setIcon(icn)
        btn_menu.setIconSize(QSize(BTN_MENU_SIZE, BTN_MENU_SIZE))
        btn_menu.setMaximumWidth(BTN_MENU_SIZE)
        btn_menu.setMaximumHeight(BTN_MENU_SIZE)
        btn_menu.setToolTip(_("Options"))
        btn_menu.setObjectName("menuButton")
        #		box.addWidget(btn_menu,Qt.Alignment(1))
        indexes = []
        for index, option in self.stacks.items():
            idx = index
            lst_widget = QListWidgetItem()
            lst_widget.setText(option['name'])
            mod = option.get('module', None)
            if mod:
                try:
                    idx = mod.index
                except:
                    pass
            if idx > 0:
                icn = QtGui.QIcon.fromTheme(option['icon'])
                lst_widget.setIcon(icn)
                if 'tooltip' in option.keys():
                    lst_widget.setToolTip(option['tooltip'])
                while idx in indexes:
                    idx += 1
                indexes.append(index)
            self.stacks[idx]['widget'] = lst_widget
        orderedStacks = {}
        orderedStacks[0] = self.stacks[0]
        #self.lst_options.addItem(orderedStacks[0]['widget'])
        cont = 0
        indexes.sort()
        for index in indexes:
            if index:
                orderedStacks[cont] = self.stacks[index].copy()
                if self.stacks[index].get('visible', True) == True:
                    self.lst_options.addItem(orderedStacks[cont]['widget'])
                cont += 1

        self.stacks = orderedStacks.copy()
        box.addWidget(self.lst_options)
        self.lst_options.currentRowChanged.connect(self._show_stack)
        self.lst_options.setCurrentIndex(QModelIndex())
        self.last_index = None
        panel.setLayout(box)
        self.resize(self.size().width() + box.sizeHint().width(),
                    self.size().height() + box.sizeHint().height() / 2)
        self.lst_options.setFixedSize(
            self.lst_options.sizeHintForColumn(0) + 2 *
            (self.lst_options.frameWidth() + 15), self.height()
        )  #self.lst_options.sizeHintForRow(0) * self.lst_options.count() + 2 * (self.lst_options.frameWidth()+15))

        return (panel)

    #def _left_panel

    def _right_panel(self):
        panel = QWidget()
        box = QVBoxLayout()
        idx = 0
        text = [
            _("Welcome to the configuration of ") + self.appName,
            _("From here you can:<br>")
        ]
        orderIdx = list(self.stacks.keys())
        for idx in orderIdx:
            data = self.stacks[idx]
            stack = data.get('module', None)
            if stack:
                stack.setLevel(self.level)
                stack.setConfig(self.config)
                stack._load_screen()

                if self.stacks[idx].get('visible', True) == True:
                    text.append(
                        "&nbsp;*&nbsp;<a href=\"appconf://%s\"><span style=\"font-weight:bold;text-decoration:none\">%s</span></a>"
                        % (idx + 1, stack.menu_description))
                try:
                    self.stk_widget.insertWidget(idx, stack)
                except:
                    self.stk_widget.insertWidget(idx, stack.init_stack())
        stack = QWidget()
        stack.setObjectName("panel")
        s_box = QVBoxLayout()
        lbl_txt = QLabel()
        lbl_txt.setTextFormat(Qt.RichText)
        lbl_txt.setText("<br>".join(text))
        lbl_txt.linkActivated.connect(self._linkStack)
        lbl_txt.setObjectName("desc")
        lbl_txt.setAlignment(Qt.AlignTop)
        lbl_txt.setTextInteractionFlags(Qt.TextBrowserInteraction)
        s_box.addWidget(lbl_txt, 1)
        #Get wiki page
        url = self._searchWiki()
        if url:
            desc = _("Wiki help")
            lbl_wiki = QLabel(
                "<a href=\"%s\"><span style=\"text-align: right;\">%s</span></a>"
                % (url, desc))
            lbl_wiki.setOpenExternalLinks(True)
            s_box.addWidget(lbl_wiki, 0, Qt.AlignRight)
        stack.setLayout(s_box)
        self.stk_widget.insertWidget(0, stack)
        #self.stacks[0]['module']=stack

        box.addWidget(self.stk_widget)
        panel.setLayout(box)
        return (panel)

    #def _right_panel

    def _linkStack(self, *args):
        stack = args[0].split('/')[-1]
        self.gotoStack(int(stack), '')

    def gotoStack(self, idx, parms):
        self._show_stack(idx=idx, parms=parms)

    def _show_stack(self, item=None, idx=None, parms=None):
        if (self.last_index == abs(self.lst_options.currentRow())
                and (idx == self.last_index
                     or isinstance(item, int))):  # or self.last_index==None)):
            return

        if isinstance(
                self.stacks.get(self.last_index, {}).get('module', None),
                appConfigStack) == True:
            if self.stacks[self.last_index]['module'].getChanges():
                if self._save_changes(self.stacks[self.last_index]
                                      ['module']) == QMessageBox.Cancel:
                    self.lst_options.setCurrentRow(self.last_index)
                    return
                else:
                    self.stacks[self.last_index]['module'].setChanged(False)
            self.stacks[self.last_index]['module'].initScreen()
            if self.stacks[self.last_index]['module'].refresh:
                self._debug("Refresh config")
                self.getConfig()
        else:
            self._debug(self.stacks.get(self.last_index, {}).get('module'))
            self.last_index = 0
        if isinstance(idx, int) == False:
            idx = self.lst_options.currentRow() + 1
        self.last_index = idx - 1
        try:
            self.stacks[idx]['module'].setConfig(self.config)
        except:
            pass
        self.stk_widget.setCurrentIndex(idx)
        #		self.statusBar.hide()
        if parms:
            self.stacks[idx]['module'].setParms(parms)

    #def _show_stack

    def closeEvent(self, event):
        try:
            if self.stacks[self.last_index]['module'].getChanges():
                if self._save_changes(self.stacks[self.last_index]
                                      ['module']) == QMessageBox.Cancel:
                    event.ignore()
        except:
            pass

    def _show_message(self, msg, status=None):
        return


#		self.statusBar.setText(msg)
#		if status:
#			self.statusBar.show(status)
#		else:
#		self.statusBar.show(status)
#def _show_message

    def _save_changes(self, module):
        dia = QMessageBox(
            QMessageBox.Question, _("Apply changes"),
            _("There're changes not saved at current screen.\nDiscard them and continue?"
              ), QMessageBox.Discard | QMessageBox.Cancel, self)
        return (dia.exec_())

    def _define_css(self):
        css = """
		QPushButton{
			padding: 6px;
			margin:6px;
			font: 14px Roboto;
		}
		QPushButton#menu:active{
			background:none;
		}
		QStatusBar{
			background:red;
			color:white;
			font: 14px Roboto bold;
		}
		QLabel{
			padding:6px;
			margin:6px;
		}
	
		#dlgLabel{
			font:12px Roboto;
			margin:0px;
			border:0px;
			padding:3px;
		}
		
		QLineEdit{
			border:0px;
			border-bottom:1px solid grey;
			padding:1px;
			font:14px Roboto;
			margin-right:6px;
		}
		#panel{
			background-image:url("%s");
			background-size:stretch;
			background-repeat:no-repeat;
			background-position:center;
		}
		#desc{
			background-color:rgba(255,255,255,0.7);
			color:black;
		}
		#banner{
			padding:1px;
			margin:1px;
			border:0px;
		}
		""" % self.background
        return (css)
示例#9
0
class ForceActuatorWidget(QWidget):
    """
    Abstract class for widget and graphics display of selected M1M3 values.
    Children classes must implement updateValues(data) method.

    Parameters
    ----------

    m1m3 : `SALComm`
        SALComm instance to communicate with SAL.
    userWidget : `QWidget`
        Widget to be displayed on left from value selection. Its content shall
        be update in updateValues(data) method.

    Methods
    -------

    updateValues(data)
        Must be defined in every child. This is called when selection is
        changed or when new data become available. If data parameter is None,
        then no data has been received for selected read topic.
    """
    def __init__(self, m1m3, userWidget):
        super().__init__()
        self.m1m3 = m1m3

        self.fieldDataIndex = None

        self.layout = QHBoxLayout()
        self.plotLayout = QVBoxLayout()
        self.selectionLayout = QVBoxLayout()
        self.detailsLayout = QFormLayout()
        self.filterLayout = QHBoxLayout()
        self.layout.addLayout(self.plotLayout)
        self.layout.addLayout(self.selectionLayout)
        self.selectionLayout.addLayout(self.detailsLayout)
        self.selectionLayout.addWidget(QLabel("Filter Data"))
        self.selectionLayout.addLayout(self.filterLayout)
        self.setLayout(self.layout)

        self.selectedActuatorIdLabel = QLabel("")
        self.selectedActuatorValueLabel = QLabel("")
        self.selectedActuatorWarningLabel = QLabel("")
        self.lastUpdatedLabel = TimeDeltaLabel()

        self.topicList = QListWidget()
        self.topicList.setFixedWidth(256)
        self.topicList.currentRowChanged.connect(self.currentTopicChanged)
        self.topics = Topics()
        for topic in self.topics.topics:
            self.topicList.addItem(topic.name)
        self.fieldList = QListWidget()
        self.fieldList.setFixedWidth(256)
        self.fieldList.currentRowChanged.connect(self.currentFieldChanged)

        self.plotLayout.addWidget(userWidget)

        self.detailsLayout.addRow(QLabel("Selected Actuator Details"),
                                  QLabel(""))
        self.detailsLayout.addRow(QLabel("Actuator Id"),
                                  self.selectedActuatorIdLabel)
        self.detailsLayout.addRow(QLabel("Actuator Value"),
                                  self.selectedActuatorValueLabel)
        self.detailsLayout.addRow(QLabel("Actuator Warning"),
                                  self.selectedActuatorWarningLabel)
        self.detailsLayout.addRow(QLabel("Last Updated"),
                                  self.lastUpdatedLabel)

        self.filterLayout.addWidget(self.topicList)
        self.filterLayout.addWidget(self.fieldList)

        self.topicList.setCurrentRow(0)

    @Slot(int)
    def currentTopicChanged(self, topicIndex):
        if topicIndex < 0:
            self._setUnknown()
            return

        self.fieldList.clear()
        for field in self.topics.topics[topicIndex].fields:
            self.fieldList.addItem(field[0])

        fieldIndex = self.topics.topics[topicIndex].selectedField
        if fieldIndex < 0:
            self._setUnknown()
            return

        self.fieldList.setCurrentRow(fieldIndex)
        self._changeField(topicIndex, fieldIndex)

    @Slot(int)
    def currentFieldChanged(self, fieldIndex):
        topicIndex = self.topicList.currentRow()
        if topicIndex < 0 or fieldIndex < 0:
            self._setUnknown()
            return
        self._changeField(topicIndex, fieldIndex)
        self.topics.topics[topicIndex].selectedField = fieldIndex

    def _setUnknown(self):
        self.lastUpdatedLabel.setUnknown()

    def updateSelectedActuator(self, s):
        """
        Called from childrens to update currently selected actuator display.

        Parameters
        ----------

        s : `map`
            Contains id (selected actuator ID), data (selected actuator current value) and warning (boolean, true if value is in warning).
        """
        if s is None:
            self.selectedActuatorIdLabel.setText("not selected")
            self.selectedActuatorValueLabel.setText("")
            self.selectedActuatorWarningLabel.setText("")
            return

        self.selectedActuatorIdLabel.setText(str(s.id))
        self.selectedActuatorValueLabel.setText(str(s.data))
        setWarningLabel(self.selectedActuatorWarningLabel, s.warning)

    def _changeField(self, topicIndex, fieldIndex):
        """
        Redraw actuators with new values.
        """
        topic = self.topics.topics[topicIndex]
        field = topic.fields[fieldIndex]
        self.fieldGetter = field[1]
        self.fieldDataIndex = field[2]()
        try:
            self.topics.changeTopic(topicIndex, self.dataChanged, self.m1m3)

            data = getattr(self.m1m3.remote, topic.getTopic()).get()
            self.dataChanged(data)
        except RuntimeError as err:
            print("ForceActuatorWidget._changeField", err)
            pass

    @Slot(map)
    def dataChanged(self, data):
        """
        Called when selected data are updated.

        Parameters
        ----------

        """
        self.updateValues(data)
        if data is None:
            self._setUnknown()
        else:
            self.lastUpdatedLabel.setTime(data.timestamp)
示例#10
0
class EventViewer(QDialog):
    def __init__(self, alid=0, db=0, mode=0):
        super().__init__()
        self.font = mainfont
        self.resize(1000, 600)
        layout = QGridLayout()
        self.layout = layout
        self.buttext = []
        self.dictViewer = QWidget()

        self.linedits = {}
        self.last_eid = 0
        self.photo_ids = 0
        self.QLABELM_TYPE = type(QLabelM())

        self.listWidget = QListWidget()
        self.listWidget.itemDoubleClicked.connect(self.doubleClick)
        self.listWidget.itemSelectionChanged.connect(self.itemChanged)

        self.setFont(mainfont)
        self.db = db
        self.alid = alid
        self.event_ids = db.get_all_event_ids(self.alid)
        self.photo_gallery = QLabel()
        #self.photo_gallery.setAlignment(Qt.AlignCenter)
        #self.photo_gallery.setPixmap(QPixmap('f.png').scaled(400,400,Qt.KeepAspectRatio))
        print(self.event_ids)
        if self.event_ids:
            for eid in self.event_ids:
                event = db.get_event_data(self.alid, eid)
                print(event)
                if event:
                    text = ''
                    text = event['event_head'] if type(event) == type(
                        {}) and 'event_head' in event.keys(
                        ) and event['event_head'] != '' else text
                    item = QListWidgetItem(text)
                    if type(event) == type({}) and 'eid' in event.keys():
                        item.setWhatsThis(str(event['eid']))
                    self.listWidget.addItem(item)
            if self.listWidget.count():
                self.listWidget.setCurrentRow(0)

        self.mode = mode

        def openMenu(position):
            # Создание PopupMenu
            menu = QMenu()
            if mode > 0:
                addAction = menu.addAction('Добавить событие')
                #menu.addSeparator()
                editAction = menu.addAction('Переименовать событие')
                #menu.addSeparator()
                delAction = menu.addAction('Удалить событие')
                delAllAction = menu.addAction('Удалить все события')
                menu.addSeparator()
            else:
                addAction, editAction, delAction, delAllAction = QAction(
                ), QAction(), QAction(), QAction()
            quitAction = menu.addAction('Выход')
            action = menu.exec_(self.mapToGlobal(position))

            # Привязка событий к Actions
            if action == addAction:
                text, ok = QInputDialog().getText(self, "Название события",
                                                  "Ввкдите название события:",
                                                  QLineEdit.Normal, '')
                if ok:
                    text = 'Новое событие' if text == '' else text
                    res = self.db.add_event({
                        'alid': self.alid,
                        'event_head': text
                    })
                    if len(res) == 1:
                        event = res[0]
                        text = event['event_head'] if type(event) == type(
                            {}
                        ) and 'event_head' in event.keys(
                        ) and event['event_head'] != '' else 'Новое событие'
                        item = QListWidgetItem(text)
                        item.setWhatsThis(str(event['eid']))
                        self.listWidget.addItem(item)
                        db.events.save()
                        #self.changed = True
                self.event_ids = db.get_all_event_ids(self.alid)

            if action == editAction:
                eid = self.listWidget.currentItem()
                if eid is not None:
                    eid = self.listWidget.currentItem().whatsThis()
                    last_name = self.db.get_event_data(self.alid,
                                                       eid)['event_head']
                    text, ok = QInputDialog().getText(
                        self, "Название события",
                        "Ввкдите новое название события:", QLineEdit.Normal,
                        str(last_name))
                    if ok:
                        event = self.db.edit_event({
                            'alid': self.alid,
                            'eid': eid,
                            'event_head': text
                        })
                        self.listWidget.currentItem().setText(text)
                        self.db.events.save()
                        if event:
                            event = self.db.get_event_data(alid, eid)
                            #b = layout.takeAt(1)
                            self.dictViewer.close()
                            #b.widget().deleteLater()
                            self.dictViewer = DictViewer(
                                event, 1, self.db.events.invizible_fields,
                                self.db.events.editable_fields)
                            self.layout.addWidget(self.dictViewer, 0, 2)
                    self.event_ids = db.get_all_event_ids(self.alid)

            if action == delAction:
                res = QMessageBox.question(
                    self, 'ВНИМАНИЕ!!!',
                    "Вы действительно хотите удалить событие?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if res == QMessageBox.Yes:
                    eid = self.listWidget.currentItem()
                    if eid is not None:
                        eid = self.listWidget.currentItem().whatsThis()
                        self.db.del_event({'alid': self.alid, 'eid': eid})
                        self.listWidget.takeItem(self.listWidget.currentRow())
                        self.db.events.save()
                        #self.changed = True
                    self.event_ids = db.get_all_event_ids(self.alid)

            if action == delAllAction:
                res = QMessageBox.question(
                    self, 'ВНИМАНИЕ!!!',
                    "Вы действительно хотите удалить все события?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if res == QMessageBox.Yes:
                    if self.db.del_all_events(int(self.alid)):
                        self.listWidget.clear()
                        self.db.events.save()
                        #self.changed = True
                    self.event_ids = db.get_all_event_ids(self.alid)

                    #db.photos.save()

            if action == quitAction:
                self.accept()

        self.listWidget.setContextMenuPolicy(Qt.CustomContextMenu)
        self.listWidget.customContextMenuRequested.connect(openMenu)

        layout.addWidget(self.listWidget, 0, 0, 1, 1)
        layout.addWidget(self.photo_gallery, 0, 1, 1, 1)

        self.setLayout(layout)

    def doubleClick(self, item):
        if item is not None:
            eid = item.whatsThis()
            text = self.db.get_event_path(self.alid, eid)
            print(eid)

    def closeEvent(self, event):
        if self.last_eid:
            self.check_and_save(self.last_eid)

    def itemChanged(self):
        if self.last_eid:
            self.check_and_save(self.last_eid)

        eid = self.listWidget.currentItem()
        if eid is not None:
            eid = self.listWidget.currentItem().whatsThis()
            event = self.db.get_event_data(self.alid, eid)

            if self.photo_gallery:
                self.photo_gallery.close()

            # Работаем с фотками
            self.photo_gallery = QLabelM(self.alid, self.db, 1, eid)
            self.layout.addWidget(self.photo_gallery, 0, 1,
                                  int(self.db.events.nkeys / 2), 1)

            # Заполняем данными
            self.fill_event_data(event)

            print(event)
            self.last_eid = eid
        self.setFocus()
        #print('item changed = ' + str(eid))

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Left:
            #print('left pressed')
            if type(self.photo_gallery) == self.QLABELM_TYPE:
                self.photo_gallery.prev_show()
        if event.key() == Qt.Key_Right:
            #print('right pressed')
            if type(self.photo_gallery) == self.QLABELM_TYPE:
                self.photo_gallery.next_show()
        #super().keyPressEvent(event)

    def fill_event_data(self, event):
        if type(event) != type({}):
            return

        self.dictViewer.close()
        self.dictViewer = DictViewer(event, 1, self.db.events.invizible_fields,
                                     self.db.events.editable_fields)
        self.layout.addWidget(self.dictViewer, 0, 2, 1, 1)

    def check_and_save(self, eid):
        print('check_and_save' + str(eid))
        changes = self.dictViewer.get_changes()
        event = self.db.get_event_data(self.alid, eid)

        if self.photo_gallery.changed:
            changes['photo_ids'] = self.photo_gallery.photo_ids
        print(changes)
        if len(changes) > 0 and type(event) == type({}):
            print('event changes saved')
            event.update(changes)
            self.db.edit_event(event)
            self.db.events.save()
示例#11
0
class LevelSelector(QDialog):
    def __init__(self, parent):
        super(LevelSelector, self).__init__(parent)

        self.setWindowTitle("Level Selector")
        self.setModal(True)

        self.level_name = ""

        self.object_set = 0
        self.object_data_offset = 0x0
        self.enemy_data_offset = 0x0

        self.world_label = QLabel(parent=self, text="World")
        self.world_list = QListWidget(parent=self)
        self.world_list.addItems(WORLD_ITEMS)

        self.world_list.itemDoubleClicked.connect(self.on_ok)
        self.world_list.itemSelectionChanged.connect(self.on_world_click)

        self.level_label = QLabel(parent=self, text="Level")
        self.level_list = QListWidget(parent=self)

        self.level_list.itemDoubleClicked.connect(self.on_ok)
        self.level_list.itemSelectionChanged.connect(self.on_level_click)

        self.enemy_data_label = QLabel(parent=self, text="Enemy Data")
        self.enemy_data_spinner = Spinner(parent=self)

        self.object_data_label = QLabel(parent=self, text="Object Data")
        self.object_data_spinner = Spinner(self)

        self.object_set_label = QLabel(parent=self, text="Object Set")
        self.object_set_dropdown = QComboBox(self)
        self.object_set_dropdown.addItems(OBJECT_SET_ITEMS)

        self.button_ok = QPushButton("Ok", self)
        self.button_ok.clicked.connect(self.on_ok)
        self.button_cancel = QPushButton("Cancel", self)
        self.button_cancel.clicked.connect(self.close)

        stock_level_widget = QWidget()
        stock_level_layout = QGridLayout(stock_level_widget)

        stock_level_layout.addWidget(self.world_label, 0, 0)
        stock_level_layout.addWidget(self.level_label, 0, 1)

        stock_level_layout.addWidget(self.world_list, 1, 0)
        stock_level_layout.addWidget(self.level_list, 1, 1)

        self.source_selector = QTabWidget()
        self.source_selector.addTab(stock_level_widget, "Stock Levels")

        for world_number in range(WORLD_COUNT):
            world_number += 1

            world_map_select = WorldMapLevelSelect(world_number)
            world_map_select.level_selected.connect(
                self._on_level_selected_via_world_map)

            self.source_selector.addTab(world_map_select,
                                        f"World {world_number}")

        data_layout = QGridLayout()

        data_layout.addWidget(self.enemy_data_label, 0, 0)
        data_layout.addWidget(self.object_data_label, 0, 1)
        data_layout.addWidget(self.enemy_data_spinner, 1, 0)
        data_layout.addWidget(self.object_data_spinner, 1, 1)

        data_layout.addWidget(self.object_set_label, 2, 0)
        data_layout.addWidget(self.object_set_dropdown, 2, 1)

        data_layout.addWidget(self.button_ok, 3, 0)
        data_layout.addWidget(self.button_cancel, 3, 1)

        main_layout = QVBoxLayout()
        main_layout.addWidget(self.source_selector)
        main_layout.addLayout(data_layout)

        self.setLayout(main_layout)

        self.world_list.setCurrentRow(1)  # select Level 1-1
        self.on_world_click()

    def keyPressEvent(self, key_event: QKeyEvent):
        if key_event.key() == Qt.Key_Escape:
            self.reject()

    def on_world_click(self):
        index = self.world_list.currentRow()

        assert index >= 0

        self.level_list.clear()

        # skip first meaningless item
        for level in Level.offsets[1:]:
            if level.game_world == index:
                if level.name:
                    self.level_list.addItem(level.name)

        if self.level_list.count():
            self.level_list.setCurrentRow(0)

            self.on_level_click()

    def on_level_click(self):
        index = self.level_list.currentRow()

        assert index >= 0

        level_is_overworld = self.world_list.currentRow(
        ) == OVERWORLD_MAPS_INDEX

        if level_is_overworld:
            level_array_offset = index + 1
            self.level_name = ""
        else:
            level_array_offset = Level.world_indexes[
                self.world_list.currentRow()] + index + 1
            self.level_name = f"World {self.world_list.currentRow()}, "

        self.level_name += f"{Level.offsets[level_array_offset].name}"

        object_data_for_lvl = Level.offsets[
            level_array_offset].rom_level_offset

        if not level_is_overworld:
            object_data_for_lvl -= Level.HEADER_LENGTH

        if not level_is_overworld:
            enemy_data_for_lvl = Level.offsets[level_array_offset].enemy_offset
        else:
            enemy_data_for_lvl = 0

        if enemy_data_for_lvl > 0:
            # data in look up table is off by one, since workshop ignores the first byte
            enemy_data_for_lvl -= 1

        self.enemy_data_spinner.setEnabled(not level_is_overworld)

        # if self.world_list.currentRow() >= WORLD_1_INDEX:
        object_set_index = Level.offsets[level_array_offset].real_obj_set
        self.button_ok.setDisabled(level_is_overworld)

        self._fill_in_data(object_set_index, object_data_for_lvl,
                           enemy_data_for_lvl)

    def _fill_in_data(self, object_set: int, layout_address: int,
                      enemy_address: int):
        self.object_set_dropdown.setCurrentIndex(object_set)
        self.object_data_spinner.setValue(layout_address)
        self.enemy_data_spinner.setValue(enemy_address)

    def _on_level_selected_via_world_map(self, level_name: str,
                                         object_set: int, layout_address: int,
                                         enemy_address: int):
        self.level_name = level_name

        self._fill_in_data(object_set, layout_address, enemy_address)

        self.on_ok()

    def on_ok(self, _=None):
        self.object_set = self.object_set_dropdown.currentIndex()
        self.object_data_offset = self.object_data_spinner.value()
        # skip the first byte, because it seems useless
        self.enemy_data_offset = self.enemy_data_spinner.value() + 1

        self.accept()

    def closeEvent(self, _close_event: QCloseEvent):
        self.reject()
示例#12
0
class DiscoverUi(QWidget):
    
    def __init__(self):
        super().__init__()
        
        self.discover = Discover()
        self.devices = self.discover.devices
        self.listWidget = None
        self.treeWidget = None
        self.initUI()
        self.mac_addr = None

    def initDevices(self):
        for device in self.devices:
            newItem = QListWidgetItem()
            newItem.setText(device.name + " (" + device.address + ")")
            self.listWidget.addItem(newItem)

    def initUI(self):
        self.listWidget = QListWidget()
        self.initDevices()

        self.treeWidget = QTreeWidget()
        self.treeWidget.itemPressed.connect(self.onItemPressed)
        self.treeWidget.setColumnCount(4)
        self.treeWidget.setColumnWidth(0, 250)
        self.treeWidget.setColumnWidth(1, 300)
        self.treeWidget.setColumnWidth(2, 300)
        self.treeWidget.setColumnWidth(3, 150)
        self.treeWidget.setHeaderLabels(["Service", "Service UUID", "Characteristic UUID", "Characteristic Property"])

        btn = QPushButton("Read Services")
        btn.clicked.connect(self.onPushButton)

        groupDevices = QGroupBox("Devices")
        groupDevices.setMaximumWidth(300)

        vbox = QVBoxLayout()
        vbox.addWidget(self.listWidget)
        vbox.addWidget(btn)
        groupDevices.setLayout(vbox)

        self.btnR = QPushButton("Read")
        self.btnR.clicked.connect(self.onReadButton)
        self.btnW = QPushButton("Write")
        self.btnW.clicked.connect(self.onWriteButton)
        self.lneI = QLineEdit()
        self.chkN = QCheckBox("Notify")
        self.chkN.toggled.connect(self.onNotifyCheck)
        hbox = QHBoxLayout()
        hbox.addWidget(self.btnR)
        hbox.addWidget(self.btnW)
        hbox.addWidget(self.lneI)
        hbox.addWidget(self.chkN)

        groupProperty = QGroupBox("Property")
        #groupProperty.setLayout(vbox)
        groupProperty.setLayout(hbox)

        groupServices = QGroupBox("Services")

        vbox = QVBoxLayout()
        vbox.addWidget(self.treeWidget)
        vbox.addWidget(groupProperty)
        groupServices.setLayout(vbox)

        hbox = QHBoxLayout()
        hbox.addWidget(groupDevices)
        hbox.addWidget(groupServices)
        self.setLayout(hbox)
        
        self.setGeometry(300, 300, 800, 600)
        self.setWindowTitle('BLE Discover')
        self.show()

    def onPushButton(self):
        try:
            self.mac_addr = self.devices[self.listWidget.currentRow()].address
            self.discover.getServices(self.mac_addr)
        except:
            print("Could not get GATT services.")
        else:
            svcs = self.discover.svcs
            for serviceKey, serviceValue in svcs.services.items():
                item = QTreeWidgetItem(None, [serviceValue.description, serviceValue.uuid])
                
                for characteristic in serviceValue.characteristics:
                    for property in characteristic.properties:
                        child = QTreeWidgetItem(["", "", characteristic.uuid, property])
                        item.addChild(child)

                self.treeWidget.addTopLevelItem(item)


    def onReadButton(self):
        byteArray = self.discover.readGattChar(self.mac_addr, self.chosenUuid)
        text = ''.join('{:02x}'.format(x) for x in byteArray)
        self.lneI.setText(text)

    def onWriteButton(self):
        text = self.lneI.text()
        print("onWriteButton")
        self.discover.writeGattChar(self.mac_addr, self.chosenUuid, bytes.fromhex(text))

    def notifyCallback(self, sender, data):
        text = ''.join('{:02x}'.format(x) for x in data)
        self.lneI.textChanged.emit(text)

    def onNotifyCheck(self, checked):
        if checked:
            print("onNotifyCheck")
            self.discover.startNotify(self.mac_addr, self.chosenUuid, self.notifyCallback)
        else:
            print("onNotifyCheck else")
            

    def onItemPressed(self, item, column):
        if item.child(0) is None:
            print(item)
            print(item.text(2))
            print(item.text(3))
            self.chosenUuid = item.text(2)
            property = item.text(3)

            if property == "read":
                self.btnR.setEnabled(True)
                self.btnW.setEnabled(False)
                self.lneI.setEnabled(False)
                self.chkN.setEnabled(False)
            elif property == "write":
                self.btnR.setEnabled(True)
                self.btnW.setEnabled(True)
                self.lneI.setEnabled(True)
                self.chkN.setEnabled(False)
            elif property == "notify":
                self.btnR.setEnabled(False)
                self.btnW.setEnabled(False)
                self.lneI.setEnabled(False)
                self.chkN.setEnabled(True)
示例#13
0
class AlbumViewer(QDialog):
    def __init__(self, pid=0, db=0, mode=0):
        super().__init__()
        self.font = mainfont
        self.resize(500, self.height())
        layout = QGridLayout()
        self.layout = layout
        self.buttext = []
        self.last_alid = 0

        self.listWidget = QListWidget()
        self.listWidget.itemDoubleClicked.connect(self.doubleClick)
        self.listWidget.itemSelectionChanged.connect(self.itemChanged)

        self.dictAlbum = QWidget()
        self.DICTVIEWERTYPE = type(DictViewer())
        self.setFont(mainfont)
        self.db = db
        self.pid = pid
        self.album_ids = db.get_all_albums_ids()
        print(self.album_ids)
        if self.album_ids:
            for alid in self.album_ids:
                album = db.get_album_data(alid)
                print(album)
                self.dictAlbum = DictViewer(album, 1,
                                            self.db.albums.invizible_fields,
                                            self.db.albums.editable_fields)

                if album:
                    text = ''
                    text = album['title'] if type(album) == type(
                        {}) and 'title' in album.keys(
                        ) and album['title'] != '' else text
                    item = QListWidgetItem(text)
                    if type(album) == type({}) and 'alid' in album.keys():
                        item.setWhatsThis(str(album['alid']))
                    self.listWidget.addItem(item)
            self.listWidget.setCurrentRow(0)
        self.mode = mode

        def openMenu(position):
            # Создание PopupMenu
            menu = QMenu()
            openAction = menu.addAction('Открыть альбом')
            openEAction = menu.addAction('Открыть события')
            menu.addSeparator()
            if mode > 0:
                #importAction = menu.addAction('Выгрузить альбом')
                exportAction = menu.addAction('Добавить альбом')
                renameAction = menu.addAction('Переименовать альбом')
                #menu.addSeparator()
                #editAction = menu.addAction('Заменить')
                menu.addSeparator()
                delAction = menu.addAction('Удалить альбом')
                delAllAction = menu.addAction('Удалить все альбомы')
                menu.addSeparator()
            else:
                exportAction, delAction, delAllAction = QAction(), QAction(
                ), QAction()
            quitAction = menu.addAction('Выход')
            action = menu.exec_(self.mapToGlobal(position))

            # Привязка событий к Actions
            if action == openAction:
                self.doubleClick(self.listWidget.currentItem())

            if action == openEAction:
                item = self.listWidget.currentItem()
                if item is not None:
                    alid = item.whatsThis()
                    self.events = EventViewer(int(alid), db, 1)
                    self.events.show()

            if action == exportAction:
                text, ok = QInputDialog().getText(self, "Название альбома",
                                                  "Ввкдите название альбома:",
                                                  QLineEdit.Normal, 'Альбом')
                if ok:
                    res = self.db.add_album({'imid': -1, 'title': text})
                    if len(res) == 1:
                        album = res[0]
                        item = QListWidgetItem(text)
                        item.setWhatsThis(str(album['alid']))
                        self.listWidget.addItem(item)
                self.album_ids = db.get_all_albums_ids()

            if action == renameAction:
                item = self.listWidget.currentItem()
                if item is not None:
                    alid = item.whatsThis()
                    album = db.get_album_data(alid)
                    text, ok = QInputDialog().getText(
                        self, "Название альбома", "Ввкдите название альбома:",
                        QLineEdit.Normal, album['title'])
                    if ok:
                        album = db.edit_album({
                            'alid': int(alid),
                            'imid': -1,
                            'title': text
                        })
                        item.setText(text)
                        if album:
                            album = self.db.get_album_data(alid)
                            # b = layout.takeAt(1)
                            # self.dictAlbum.close()
                            # b.widget().deleteLater()
                            self.dictAlbum = DictViewer(
                                album, 1, self.db.albums.invizible_fields,
                                self.db.albums.editable_fields)
                            self.layout.addWidget(self.dictAlbum, 0, 1)
                        self.album_ids = db.get_all_albums_ids()

            if action == delAction:
                res = QMessageBox.question(
                    self, 'ВНИМАНИЕ!!!',
                    "Вы действительно хотите удалить альбом?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if res == QMessageBox.Yes:
                    self.delete_item()

            if action == delAllAction:
                res = QMessageBox.question(
                    self, 'ВНИМАНИЕ!!!',
                    "Вы действительно хотите удалить все альбомы?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if res == QMessageBox.Yes:
                    item = self.listWidget.currentItem()
                    while item is not None:
                        self.delete_item()
                        item = self.listWidget.currentItem()

                    self.album_ids = db.get_all_albums_ids()

            if action == quitAction:
                self.accept()

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(openMenu)

        layout.addWidget(self.listWidget, 0, 0)
        layout.addWidget(self.dictAlbum, 0, 1)

        self.setLayout(layout)

    def delete_item(self):
        item = self.listWidget.currentItem()
        if item is not None:

            alid = item.whatsThis()
            self.db.del_album(int(alid))
            self.listWidget.takeItem(self.listWidget.currentRow())
            self.album_ids = self.db.get_all_albums_ids()

    def itemChanged(self):
        if self.last_alid:
            self.check_and_save(self.last_alid)

        item = self.listWidget.currentItem()
        if item is not None:
            alid = item.whatsThis()

            album = self.db.get_album_data(alid)
            self.dictAlbum = DictViewer(album, 1,
                                        self.db.albums.invizible_fields,
                                        self.db.albums.editable_fields)
            self.layout.addWidget(self.dictAlbum, 0, 1)
            self.last_alid = alid
        self.setFocus()

    def doubleClick(self, item):
        if item is not None:
            alid = item.whatsThis()
            print(alid)
            self.viewer = QLabelMA(alid, self.db, 1)
            self.viewer.show()

    def check_and_save(self, alid):
        changes = self.dictAlbum.get_changes()
        album = self.db.get_album_data(alid)

        print(changes)
        if len(changes) > 0 and type(album) == type({}):
            print('album changes saved')
            album.update(changes)
            self.db.edit_album(album)
示例#14
0
class Repertoire(QWidget):
    def __init__(self, parent=None):
        super(Repertoire, self).__init__(parent)
        global filename
        self.monRepertoire = {}
        self.labelNom = QLabel("Nom")
        self.labelPrenom = QLabel("Prenom")
        self.labelTel = QLabel("Tel")
        self.leNom = QLineEdit()
        self.lePrenom = QLineEdit()
        self.leTel = QLineEdit()
        self.lwListeNoms = QListWidget()
        self.pbAjouter = QPushButton("Ajouter")
        self.pbModifier = QPushButton("Modifier")

        self.monRepertoire = self.lireJSON(filename)

        self.lwListeNoms.itemClicked.connect(self.userSelected)
        self.pbAjouter.clicked.connect(self.addUser)
        self.pbModifier.clicked.connect(self.modifyUser)

        layoutLabels = QVBoxLayout()
        layoutLabels.addWidget(self.labelNom)
        layoutLabels.addWidget(self.labelPrenom)
        layoutLabels.addWidget(self.labelTel)

        layoutLineEdit = QVBoxLayout()
        layoutLineEdit.addWidget(self.leNom)
        layoutLineEdit.addWidget(self.lePrenom)
        layoutLineEdit.addWidget(self.leTel)

        HLayout = QHBoxLayout()
        HLayout.addWidget(self.lwListeNoms)
        HLayout.addLayout(layoutLabels)
        HLayout.addLayout(layoutLineEdit)

        HLayoutButtons = QHBoxLayout()
        HLayoutButtons.addSpacerItem(QSpacerItem(100, 10))
        HLayoutButtons.addWidget(self.pbModifier)
        HLayoutButtons.addWidget(self.pbAjouter)

        genLayout = QVBoxLayout()
        genLayout.addLayout(HLayout)
        genLayout.addLayout(HLayoutButtons)

        self.setLayout(genLayout)
        self.updateListw()

    def updateListw(self):
        self.lwListeNoms.clear()
        for fiche in self.monRepertoire["repertoire"]:
            self.lwListeNoms.addItem(fiche["nom"])

    def sauveJSON(self, fileName):
        jsonClasse = json.dumps(self.monRepertoire, sort_keys=True, indent=4)
        f = open(fileName, 'w')
        f.write(jsonClasse)
        f.close()

    def addUser(self):
        retour = QInputDialog().getText(self, "Ajout Utilisateur", "Nom:")
        if retour[0] == "":
            return

        fiche = {}
        fiche["nom"] = retour[0]
        fiche["prenom"] = ""
        fiche["tel"] = ""

        self.monRepertoire["repertoire"].append(fiche)
        self.updateListw()
        self.sauveJSON(filename)

    def modifyUser(self):
        rowSelected = self.lwListeNoms.currentRow()
        self.monRepertoire["repertoire"][rowSelected]["nom"] = self.leNom.text(
        )
        self.monRepertoire["repertoire"][rowSelected][
            "prenom"] = self.lePrenom.text()
        self.monRepertoire["repertoire"][rowSelected]["tel"] = self.leTel.text(
        )
        self.updateListw()
        self.sauveJSON(filename)

    def userSelected(self):
        rowSelected = self.lwListeNoms.currentRow()
        fiche = self.monRepertoire["repertoire"][rowSelected]
        self.leNom.setText(fiche["nom"])
        self.lePrenom.setText(fiche["prenom"])
        self.leTel.setText(fiche["tel"])

    def lireJSON(self, fileName):
        with open(fileName) as json_file:
            dico = json.load(json_file)
            return dico
        return None
示例#15
0
class Form(QDialog):
    def __init__(self, parent=None):
        self.player = vlc.MediaPlayer()
        super(Form, self).__init__(parent)
        self.setWindowTitle("Bassdrive Archive Player")

        layoutPlay = QHBoxLayout()
        self.pbPlay = QPushButton("Play")
        self.pbCast = QPushButton("Cast")
        layoutPlay.addWidget(self.pbPlay)
        layoutPlay.addWidget(self.pbCast)

        self.pbStop = QPushButton("Stop")
        self.pbRandom = QPushButton("Random")
        self.pbDownload = QPushButton("Download")

        self.pbPlay.clicked.connect(self.onPbPlay)
        self.pbDownload.clicked.connect(self.onPbDownload)
        self.pbRandom.clicked.connect(self.onPbRandom)
        self.pbStop.clicked.connect(self.onPbStop)

        self.pbPlay.setEnabled(False)
        self.xProgressBar = QProgressBar(self)

        self.listFiles = QListWidget()
        self.listFiles.itemClicked.connect(self.onItemSelected)

        # Create layout and add widgets
        layout = QVBoxLayout()

        layout.addWidget(self.xProgressBar)
        layout.addWidget(self.listFiles)

        layout.addLayout(layoutPlay)
        layout.addWidget(self.pbStop)
        layout.addWidget(self.pbRandom)
        layout.addWidget(self.pbDownload)

        self.xProgressBar.setRange(1, 100)

        # Set dialog layout
        self.setLayout(layout)

        # Read in what we've already scanned
        if os.path.isfile(DBFILE):
            with open(DBFILE, "r") as f:
                self.db = json.load(f)

                for file in self.db['files']:
                    self.listFiles.addItem(file['filename'])
        else:
            self.db = {"last_scan": "2020-01-28T19:19:10.702353", "files": []}

        if datetime.now() >= datetime.fromisoformat(
                self.db['last_scan']) + timedelta(hours=12):
            self.startWebScraping(ROOTURL)

        self.scanChromecast()

    def scanChromecast(self):
        self.listener = pychromecast.CastListener(self.cc_added_callback,
                                                  self.cc_removed_callback,
                                                  self.cc_updated_callback)
        zconf = zeroconf.Zeroconf()
        self.browser = pychromecast.discovery.start_discovery(
            self.listener, zconf)

    def cc_added_callback(self, uuid, name):
        print("Found mDNS service for cast device {}".format(uuid))
        self.list_devices()

    def cc_removed_callback(self, uuid, name, service):
        print("Lost mDNS service for cast device {} {}".format(uuid, service))
        self.list_devices()

    def cc_updated_callback(self, uuid, name):
        print("Updated mDNS service for cast device {}".format(uuid))
        self.list_devices()

    def list_devices(self):
        print("Currently known cast devices:")
        for uuid, service in self.listener.services.items():
            print("  {} {}".format(uuid, service))

    def onPbStop(self):
        self.player.stop()
        self.pbPlay.setText("Play")
        self.pbPlay.clicked.disconnect(self.onPause)
        self.pbPlay.clicked.connect(self.onPbPlay)
        self.pbPlay.setEnabled(True)

    def onPbRandom(self):
        randomNo = random.randint(0, len(self.db['files']) - 1)
        self.listFiles.setCurrentRow(randomNo)
        obj = self.db['files'][randomNo]
        self.playFile(obj)

    def playFile(self, obj):
        self.player.stop()
        self.player.set_mrl(obj['url'])
        self.player.play()
        self.pbPlay.setText("Pause")
        self.pbPlay.clicked.disconnect(self.onPbPlay)
        self.pbPlay.clicked.connect(self.onPause)
        self.pbPlay.setEnabled(True)

    def onItemSelected(self, listItem):
        self.pbPlay.setEnabled(True)
        print('Selected: {}({})'.format(listItem.text(),
                                        self.listFiles.currentRow()))

    def startWebScraping(self, rootUrl):
        print("Starting web scraping from {}...".format(rootUrl))
        self.scrapethread = ScraperThread(rootUrl)
        self.scrapethread.scraper_update.connect(self.onScraperUpdate)
        self.scrapethread.scraper_complete.connect(self.onScraperComplete)
        self.scrapethread.start()

    def onScraperUpdate(self, obj):
        pass

    def onScraperComplete(self, newdb):
        for obj in newdb['files']:
            if obj not in self.db['files']:
                self.db['files'].append(obj)
                self.listFiles.addItem(obj['filename'])
                print("Adding new mix: {}".format(obj['filename']))

        self.db['last_scan'] = datetime.now().isoformat()

        # Dump out the results
        with open(DBFILE, "w") as f:
            self.db
            json.dump(self.db, f, indent=4)

    def onBrowseClick(self):
        self.db['output'] = QFileDialog.getExistingDirectory()
        self.eOutputFolder.setText(self.db['output'])
        self.writeDb()

    def onPbDownload(self):
        self.pbDownload.setEnabled(False)
        selectedItem = self.listFiles.currentRow()
        fileObj = self.db['files'][selectedItem]
        self.download(fileObj)

    def onPbPlay(self):
        obj = self.db['files'][self.listFiles.currentRow()]
        self.playFile(obj)

    def onPause(self):
        self.player.pause()
        self.pbPlay.setText("Play")
        self.pbPlay.clicked.disconnect(self.onPause)
        self.pbPlay.clicked.connect(self.onPbPlay)

    def writeDb(self):
        self.db['output'] = self.eOutputFolder.text()
        with open(DBFILE, "w") as f:
            json.dump(self.db, f, indent=4)

    def setDownloaded(self, fullName, state):
        for obj in self.db['files']:
            if obj['filename'] == fullName:
                obj['downloaded'] = state

        self.writeDb()

    def onDownloadUpdate(self, data):
        self.xProgressBar.setValue(data)

    def onDownloadComplete(self, obj):
        #print( "Download complete on {}.".format(obj['fullName']))
        self.setDownloaded(obj['filename'], True)

    def download(self, obj):
        if not os.path.isdir('cache'):
            os.mkdir('cache')

        filename = os.path.join('cache', obj['filename'])
        print("Downloasing {}...".format(filename))
        self.downloadthread = DownloadThread('cache', obj)
        self.downloadthread.download_update.connect(self.onDownloadUpdate)
        self.downloadthread.download_complete.connect(self.onDownloadComplete)
        self.downloadthread.start()
示例#16
0
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('清单')
        self.setFixedSize(320, 480)

        # 布局
        layout = QVBoxLayout()

        # 清单视图
        self.items_view = QListWidget()
        self.items_view.setIconSize(QSize(14, 14))
        self.items_view.doubleClicked.connect(self.toggle_complete)
        layout.addWidget(self.items_view)

        # 按钮布局
        button_layout = QHBoxLayout()
        layout.addLayout(button_layout)

        # delete button
        self.delete_button = QPushButton('DELETE')
        self.delete_button.clicked.connect(self.delete)
        button_layout.addWidget(self.delete_button)

        # Complete button
        self.complete_button = QPushButton('COMPLETE')
        self.complete_button.clicked.connect(self.complete)
        button_layout.addWidget(self.complete_button)

        # add input
        self.add_input = QLineEdit()
        self.add_input.returnPressed.connect(self.add)
        layout.addWidget(self.add_input)

        # add button
        self.add_button = QPushButton('ADD')
        self.add_button.clicked.connect(self.add)
        layout.addWidget(self.add_button)

        # status bar
        self.setStatusBar(QStatusBar())

        container = QWidget()
        container.setLayout(layout)
        self.setCentralWidget(container)

        self.setStyleSheet("""
            QListWidget {
                border: 1px solid #999;
                font-size: 13px;
            }
            
            QListWidget::item {
                color: #000;
                height: 30px;
                border-bottom: 1px solid #dedede;
            }
            QListWidget::item:selected {
                background-color: #fff9dd;
            }
            
            QPushButton {
                height: 24px;
                background-color: #fddb3a;
                font-weight: 900;
            }
            
            QLineEdit {
                padding: 5px;
            }
        """)

        self.items = []
        self.load()
        self.list_items()

    @Slot()
    def add(self):
        name = self.add_input.text()
        if name:
            self.items_view.addItem(QListWidgetItem(name))
            self.add_input.setText('')
            self.items.append({'name': name, 'done': False})
            # self.save()
            db.save(name, False)

    @Slot()
    def delete(self):
        items = self.items_view.selectedItems()
        if items:
            self.items.pop(self.items_view.currentRow())
            db.delete(self.items_view.currentRow() + 1)
            self.items_view.clear()
            self.list_items()
            # self.save()

    @Slot()
    def complete(self):
        items = self.items_view.selectedItems()
        if items:
            item_data = self.items[self.items_view.currentRow()]
            if not item_data['done']:
                icon = QIcon('done.svg')
                items[0].setIcon(icon)
                item_data['done'] = True
                # self.save()
                db.update(True, self.items_view.currentRow() + 1)

    @Slot()
    def toggle_complete(self):
        items = self.items_view.selectedItems()
        if items:
            item_data = self.items[self.items_view.currentRow()]
            if not item_data['done']:
                icon = QIcon('done.svg')
                items[0].setIcon(icon)
                item_data['done'] = True
                db.update(True, self.items_view.currentRow() + 1)
            else:
                icon = QIcon('')
                items[0].setIcon(icon)
                item_data['done'] = False
                db.update(False, self.items_view.currentRow() + 1)
            # self.save()

    def list_items(self):
        for item in self.items:
            list_item = QListWidgetItem(item['name'])
            if item['done']:
                icon = QIcon('done.svg')
                list_item.setIcon(icon)
            self.items_view.addItem(list_item)

    def load(self):
        # with open('data.json', 'r') as f:
        #     self.items = json.load(f)
        self.items = db.select()

    def save(self):
        with open('data.json', 'w') as f:
            json.dump(self.items, f)
示例#17
0
class SpecifySearchConditionsDialog(BaseDialog):
    def __init__(self, parent, entity):
        super().__init__(parent, _("Search criteria"), _("&Start search"),
                         _("&Cancel"))
        self._entity = entity
        self._value_widget = None
        self._value_label = None
        self._search_expression_parts = []
        self._added_condition = False
        self._populate_fields_tree(self._entity)

    def create_ui(self):
        fields_label = QLabel(_("Class fields"), self)
        self.layout.addWidget(fields_label, 0, 0)
        self._fields_tree = QTreeWidget(self)
        fields_label.setBuddy(self._fields_tree)
        self._fields_tree.currentItemChanged.connect(
            self.on_fields_tree_sel_changed)
        self.layout.addWidget(self._fields_tree, 1, 0)
        operator_label = QLabel(_("Operator"), self)
        self.layout.addWidget(operator_label, 0, 1)
        self._operator = QListWidget(self)
        operator_label.setBuddy(self._operator)
        self.layout.addWidget(self._operator, 1, 1)
        self._operator.currentRowChanged.connect(self.on_operator_choice)
        self._operator.setCurrentRow(0)
        add_button = QPushButton(_("&Add condition"), self)
        add_button.clicked.connect(self.on_add_clicked)
        self.layout.addWidget(add_button, 2, 0, 1, 3)
        criteria_label = QLabel(_("Current search criteria"), self)
        self.layout.addWidget(criteria_label, 3, 0, 1, 3)
        self._criteria_list = QListWidget(self)
        criteria_label.setBuddy(self._criteria_list)
        self.layout.addWidget(self._criteria_list, 4, 0, 1, 3)
        remove_button = QPushButton(_("&Remove condition"), self)
        remove_button.clicked.connect(self.on_remove_clicked)
        self.layout.addWidget(remove_button, 5, 0, 1, 3)
        distance_label = QLabel(_("Search objects to distance"), self)
        self.layout.addWidget(distance_label, 6, 0)
        self._distance_field = QSpinBox(self)
        self._distance_field.setMaximum(100000)
        self._distance_field.setSuffix(" " + _("meters"))
        self._distance_field.setSpecialValueText(_("No limit"))
        distance_label.setBuddy(self._distance_field)
        self.layout.addWidget(self._distance_field, 6, 1)

    def _populate_fields_tree(self, entity, parent=None):
        if parent is None:
            parent = self._fields_tree.invisibleRootItem()
        metadata = EntityMetadata.for_discriminator(entity)
        for field_name, field in sorted(
                metadata.all_fields.items(),
                key=lambda i: underscored_to_words(i[0])):
            child_metadata = None
            try:
                child_metadata = EntityMetadata.for_discriminator(
                    field.type_name)
            except KeyError:
                pass
            if child_metadata:
                name = get_class_display_name(field.type_name)
                subparent = QTreeWidgetItem([name])
                subparent.setData(0, Qt.UserRole, field_name)
                parent.addChild(subparent)
                self._populate_fields_tree(field.type_name, subparent)
            else:
                item = QTreeWidgetItem([underscored_to_words(field_name)])
                item.setData(0, Qt.UserRole, (field_name, field))
                parent.addChild(item)

    def on_fields_tree_sel_changed(self, item):
        data = item.data(0, Qt.UserRole)
        if data is not None and not isinstance(data, str):
            self._field_name = data[0]
            self._field = data[1]
            self._operators = operators_for_column_class(self._field.type_name)
            self._operator.clear()
            self._operator.addItems([o.label for o in self._operators])
            self._added_condition = False

    def on_operator_choice(self, index):
        self._added_condition = False
        if self._value_widget:
            self.layout.removeWidget(self._value_widget)
            self._value_widget.deleteLater()
        if self._value_label:
            self.layout.removeWidget(self._value_label)
            self._value_label.deleteLater()
            self._value_label = None
        operator = self._operators[self._operator.currentRow()]
        value_label = self._create_value_label(
            operator.get_value_label(self._field))
        self._value_widget = operator.get_value_widget(self, self._field)
        if not self._value_widget:
            return
        QWidget.setTabOrder(self._operator, self._value_widget)
        self._value_label = value_label
        if self._value_label:
            self._value_label.setBuddy(self._value_widget)
            self.layout.addWidget(self._value_label, 0, 2)
        self.layout.addWidget(self._value_widget, 1, 2)

    def _create_value_label(self, label):
        if not label:
            return
        label = QLabel(label, self)
        return label

    def on_add_clicked(self, evt):
        if not hasattr(self, "_field_name"):
            return
        self._added_condition = True
        json_path = []
        parent_item = self._fields_tree.currentItem().parent()
        parent_data = parent_item.data(0, Qt.UserRole) if parent_item else None
        if isinstance(parent_data, str):
            json_path.append(parent_data)
        json_path.append(self._field_name)
        json_path = ".".join(json_path)
        operator_obj = self._operators[self._operator.currentRow()]
        expression = operator_obj.get_comparison_expression(
            self._field, FieldNamed(json_path), self._value_widget)
        self._search_expression_parts.append(expression)
        self._criteria_list.addItem(
            f"{underscored_to_words(self._field_name)} {operator_obj.label} {operator_obj.get_value_as_string(self._field, self._value_widget)}"
        )

    @property
    def distance(self):
        return self._distance_field.value()

    def create_conditions(self):
        conditions = []
        if self._search_expression_parts:
            for part in self._search_expression_parts:
                conditions.append(part)
        return conditions

    def on_remove_clicked(self, evt):
        selection = self._criteria_list.currentRow()
        if selection < 0:
            return
        del self._search_expression_parts[selection]
        self._criteria_list.removeItemWidget(self._criteria_list.currentItem())

    def ok_clicked(self):
        if not self._added_condition:
            if QMessageBox.question(
                    self, _("Question"),
                    _("It appears that you forgot to add the current condition to the conditions list. Do you want to add it before starting the search?"
                      )):
                self.on_add_clicked(None)
        super().ok_clicked()
示例#18
0
class PersonaUI(QWidget):
    """
    Widget for Persona creation view.

    :param MainFrame mainframe: application mainframe
    :param QWidget op: parent widget
    """
    def __init__(self, mainframe, op):
        QWidget.__init__(self)
        self.mainframe = mainframe
        self.op = op

        self.grid = QGridLayout()
        self.setLayout(self.grid)

        self.listP = None
        self.listLS = None
        self.listEL1 = None
        self.listEL2 = None

        self.nameT = None
        self.levelT = None
        self.textT = None
        self.strT = None
        self.magT = None
        self.endT = None
        self.agiT = None
        self.luckT = None

        self.createFrame = None
        self.buttonFrame = None
        self.bfgrid = None
        # Actual create frame variables.
        self.cfgrid = None
        self.lsdic = None
        self.slashO = None
        self.strikeO = None
        self.pierceO = None
        self.fireO = None
        self.iceO = None
        self.windO = None
        self.elecO = None
        self.darkO = None
        self.lightO = None
        self.arcO = None
        self.iSpellOs = None
        self.lsSpellO = None
        self.lslevel = None


        self.initUI(True)

    def initUI(self, infoDump):
        """
        Initializes the basic UI showing the list of Personas.
        Does a lot of stuff.

        :param dict infoDump: not sure lol
        """
        self.mainframe.setWindowTitle("Persona Creator")

        if not infoDump:
            self.createFrameDraw()

        self.initButtonFrame(infoDump)

        self.listP = QListWidget(self)
        self.grid.addWidget(self.listP, 0, 3, 2, 1)
        temp = json_reader.readPerNames()
        self.listP.addItems(temp)

    def initButtonFrame(self, infoDump):
        """
        Initializes the buttonframes that are present in all Persona creator views.

        :param dict infoDump: not sure lol
        """
        self.buttonFrame = QWidget(self)
        self.bfgrid = QGridLayout()
        self.buttonFrame.setLayout(self.bfgrid)

        self.grid.addWidget(self.buttonFrame, 3, 0, 1, 4)


        new = QPushButton(self.buttonFrame, text="New")
        new.clicked.connect(self.new)
        self.bfgrid.addWidget(new, 4, 0)

        back = QPushButton(self.buttonFrame, text="Back")
        back.clicked.connect(self.back)
        self.bfgrid.addWidget(back, 4, 4)

        remove = QPushButton(self.buttonFrame, text="Remove")
        remove.clicked.connect(self.remove)
        self.bfgrid.addWidget(remove, 4, 3)

        edit = QPushButton(self.buttonFrame, text="Edit")
        edit.clicked.connect(self.edit)
        self.bfgrid.addWidget(edit, 4, 2)

        if not infoDump:
            save = QPushButton(self.buttonFrame, text="Save")
            save.clicked.connect(self.save)
            self.bfgrid.addWidget(save, 4, 1)


    def createFrameDraw(self):
        """
        Initializes the GUI of the actual creation frame view.
        Does a LOT of stuff.
        """
        self.createFrame = QWidget(self)
        self.cfgrid = QGridLayout()
        self.createFrame.setLayout(self.cfgrid)
        self.grid.addWidget(self.createFrame, 0, 0, 2, 2)

        self.lsdic = {}

        nameL = QLabel(self.createFrame, text="Name:")
        self.cfgrid.addWidget(nameL, 0, 0)
        self.nameT = QLineEdit(self.createFrame)
        self.nameT.setFixedSize(100, 20)
        self.cfgrid.addWidget(self.nameT, 0, 1)

        strL = QLabel(self.createFrame, text="Str")
        self.cfgrid.addWidget(strL, 0, 2)
        self.strT = QLineEdit(self.createFrame)
        self.strT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.strT, 0, 3)
        magL = QLabel(self.createFrame, text="Mag")
        self.cfgrid.addWidget(magL, 1, 2)
        self.magT = QLineEdit(self.createFrame)
        self.magT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.magT, 1, 3)
        endL = QLabel(self.createFrame, text="End")
        self.cfgrid.addWidget(endL, 2, 2)
        self.endT = QLineEdit(self.createFrame)
        self.endT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.endT, 2, 3)
        agiL = QLabel(self.createFrame, text="Agi")
        self.cfgrid.addWidget(agiL, 3, 2)
        self.agiT = QLineEdit(self.createFrame)
        self.agiT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.agiT, 3, 3)
        luckL = QLabel(self.createFrame, text="Luck")
        self.cfgrid.addWidget(luckL, 4, 2)
        self.luckT = QLineEdit(self.createFrame)
        self.luckT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.luckT, 4, 3)

        resList = json_reader.data_list("resistances")
        resL = QLabel(self.createFrame, text="Resistance:")
        self.cfgrid.addWidget(resL, 0, 5)
        slashL = QLabel(self.createFrame, text="Slash")
        self.cfgrid.addWidget(slashL, 1, 5)
        self.slashO = QComboBox(self.createFrame)
        self.slashO.addItems(resList)
        self.slashO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.slashO, 1, 6)
        strikeL = QLabel(self.createFrame, text="Strike")
        self.cfgrid.addWidget(strikeL, 2, 5)
        self.strikeO = QComboBox(self.createFrame)
        self.strikeO.addItems(resList)
        self.strikeO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.strikeO, 2, 6)
        pierceL = QLabel(self.createFrame, text="Pierce")
        self.cfgrid.addWidget(pierceL, 3, 5)
        self.pierceO = QComboBox(self.createFrame)
        self.pierceO.addItems(resList)
        self.pierceO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.pierceO, 3, 6)
        fireL = QLabel(self.createFrame, text="Fire")
        self.cfgrid.addWidget(fireL, 4, 5)
        self.fireO = QComboBox(self.createFrame)
        self.fireO.addItems(resList)
        self.fireO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.fireO, 4, 6)
        iceL = QLabel(self.createFrame, text="Ice")
        self.cfgrid.addWidget(iceL, 5, 5)
        self.iceO = QComboBox(self.createFrame)
        self.iceO.addItems(resList)
        self.iceO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.iceO, 5, 6)
        elecL = QLabel(self.createFrame, text="Elec")
        self.cfgrid.addWidget(elecL, 6, 5)
        self.elecO = QComboBox(self.createFrame)
        self.elecO.addItems(resList)
        self.elecO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.elecO, 6, 6)
        windL = QLabel(self.createFrame, text="Wind")
        self.cfgrid.addWidget(windL, 7, 5)
        self.windO = QComboBox(self.createFrame)
        self.windO.addItems(resList)
        self.windO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.windO, 7, 6)
        lightL = QLabel(self.createFrame, text="Light")
        self.cfgrid.addWidget(lightL, 8, 5)
        self.lightO = QComboBox(self.createFrame)
        self.lightO.addItems(resList)
        self.lightO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.lightO, 8, 6)
        darkL = QLabel(self.createFrame, text="Dark")
        self.cfgrid.addWidget(darkL, 9, 5)
        self.darkO = QComboBox(self.createFrame)
        self.darkO.addItems(resList)
        self.darkO.setCurrentIndex(1)
        self.cfgrid.addWidget(self.darkO, 9, 6)

        spellList = json_reader.data_list("spells")
        self.listLS = QListWidget(self.createFrame)
        self.listLS.setFixedSize(200, 300)
        self.cfgrid.addWidget(self.listLS, 3, 7, 8, 2)

        newLS = QPushButton(self.createFrame, text="+")
        newLS.clicked.connect(self.addLS)
        self.cfgrid.addWidget(newLS, 2, 7)
        delLS = QPushButton(self.createFrame, text="DEL")
        delLS.clicked.connect(self.delLS)
        self.cfgrid.addWidget(delLS, 2, 8)

        lsl = QLabel(self.createFrame, text="Learned Spells:")
        self.cfgrid.addWidget(lsl, 0, 7, 1, 2)

        arcanaL = QLabel(self.createFrame, text="Arcana:")
        self.cfgrid.addWidget(arcanaL, 1, 0)
        arc_list = json_reader.data_list("arcanas")
        self.arcO = QComboBox(self.createFrame)
        self.arcO.addItems(arc_list)
        self.arcO.setCurrentIndex(0)
        self.cfgrid.addWidget(self.arcO, 1, 1)

        levelL = QLabel(self.createFrame, text="Level:")
        self.cfgrid.addWidget(levelL, 2, 0)
        self.levelT = QLineEdit(self.createFrame)
        self.levelT.setFixedSize(20, 20)
        self.cfgrid.addWidget(self.levelT, 2, 1)

        heritageL = QLabel(self.createFrame, text="Inherits:")
        self.cfgrid.addWidget(heritageL, 3, 0, 1, 2)

        elements = json_reader.data_list("elements")
        elements.append("Support")
        self.listEL1 = QComboBox(self.createFrame)
        self.listEL1.addItems(elements)
        self.cfgrid.addWidget(self.listEL1, 4, 0)
        self.listEL2 = QComboBox(self.createFrame)
        self.listEL2.addItems(elements)
        self.cfgrid.addWidget(self.listEL2, 4, 1)

        iSpellL = QLabel(self.createFrame, text="Initial Spells:")
        self.cfgrid.addWidget(iSpellL, 5, 0, 1, 2)
        self.iSpellOs = []
        for i in range(6, 9):
            temp = QComboBox(self.createFrame)
            temp.addItems(spellList)
            temp2 = QComboBox(self.createFrame)
            temp2.addItems(spellList)
            self.cfgrid.addWidget(temp, i, 0, 1, 2)
            self.cfgrid.addWidget(temp2, i, 2, 1, 2)
            self.iSpellOs.extend([temp, temp2])

        textL = QLabel(self.createFrame, text="Info:")
        self.cfgrid.addWidget(textL, 10, 0)
        self.textT = QTextEdit(self.createFrame)
        self.textT.setFixedSize(300, 100)
        self.cfgrid.addWidget(self.textT, 10, 1, 1, 5)

        self.lslevel = QLineEdit(self.createFrame)
        self.lslevel.setFixedSize(40, 20)
        self.lsSpellO = QComboBox(self.createFrame)
        self.lsSpellO.addItems(spellList)

        self.cfgrid.addWidget(self.lsSpellO, 1, 7)
        self.cfgrid.addWidget(self.lslevel, 1, 8)

    def addLS(self):
        """
        Add a learned spell to the list, based on what was entered.
        """
        print("Adding learned spell")
        chosenSpell = self.lsSpellO.currentText()
        if (int)(self.lslevel.text()) <= (int)(self.levelT.text()):
            popup("You cannot add a spell at an earlier level than the Persona's base level", "Critical")
            return
        if chosenSpell != "":
            print("Ok")
            self.lsdic[chosenSpell] = self.lslevel.text()
            self.listLS.addItem(chosenSpell + " at level " + self.lslevel.text())
            self.lslevel.setText("")
            self.lsSpellO.setCurrentIndex(0)
            return
        popup("You must choose a spell", "Critical")

    def delLS(self):
        """
        Remove the selected learned spell from the list
        """
        print("Deleting learned spell")
        key = ""
        i = 0
        while len(self.listLS.currentItem().text()) > i:
            if self.listLS.currentItem().text()[i] == " " and \
               self.listLS.currentItem().text()[i+1] == "a" and \
               self.listLS.currentItem().text()[i+2] == "t":  # TODO EWWWWWW
                break
            key += self.listLS.currentItem().text()[i]
            i = i + 1
        print(key)
        print(self.lsdic.pop(key))
        self.listLS.takeItem(self.listLS.currentRow())


    def loadPer(self, name):
        """
        Load a certain Persona from file.

        :param str name: name of Persona to load
        """
        data = json_reader.readOne(name, 'pers')
        self.nameT.setText(data["name"])
        self.textT.setText(data["desc"])
        self.strT.setText(data["stats"][0])
        self.magT.setText(data["stats"][1])
        self.endT.setText(data["stats"][2])
        self.agiT.setText(data["stats"][3])
        self.luckT.setText(data["stats"][4])
        self.levelT.setText(data["level"])

        self.arcO.setCurrentIndex(
            [self.arcO.itemText(i) for i in range(self.arcO.count())].index(data["arcana"])
        )

        self.listEL1.setCurrentIndex(
            [self.listEL1.itemText(i) for i in range(self.listEL1.count())].index(data["heritage"][0])
        )
        self.listEL2.setCurrentIndex(
            [self.listEL2.itemText(i) for i in range(self.listEL2.count())].index(data["heritage"][1])
        )

        self.slashO.setCurrentIndex(
            [self.slashO.itemText(i) for i in range(self.slashO.count())].index(data["resistance"][0])
        )
        self.strikeO.setCurrentIndex(
            [self.strikeO.itemText(i) for i in range(self.strikeO.count())].index(data["resistance"][1])
        )
        self.pierceO.setCurrentIndex(
            [self.pierceO.itemText(i) for i in range(self.pierceO.count())].index(data["resistance"][2])
        )
        self.fireO.setCurrentIndex(
            [self.fireO.itemText(i) for i in range(self.fireO.count())].index(data["resistance"][3])
        )
        self.iceO.setCurrentIndex(
            [self.iceO.itemText(i) for i in range(self.iceO.count())].index(data["resistance"][4])
        )
        self.elecO.setCurrentIndex(
            [self.elecO.itemText(i) for i in range(self.elecO.count())].index(data["resistance"][5])
        )
        self.windO.setCurrentIndex(
            [self.windO.itemText(i) for i in range(self.windO.count())].index(data["resistance"][6])
        )
        self.lightO.setCurrentIndex(
            [self.lightO.itemText(i) for i in range(self.lightO.count())].index(data["resistance"][7])
        )
        self.darkO.setCurrentIndex(
            [self.darkO.itemText(i) for i in range(self.darkO.count())].index(data["resistance"][8])
        )

        i = 0
        for combobox in self.iSpellOs:
            combobox.setCurrentIndex(
                [combobox.itemText(j) for j in range(combobox.count()-1)].index(data["spellDeck"][i])
            )
            i += 1

        self.lsdic = data["spellLearn"]
        self.listLS.clear()
        for spell, level in self.lsdic.items():
            self.listLS.addItem(spell + " at level " + level)

        print("Loaded " + data["name"])

    def edit(self):
        """
        Switch to edit view, also loads the selected Persona.
        """
        try:
            if self.listP.currentItem().text() != "":
                if self.createFrame and not popup("Override any unsaved changes?", "Warning"):
                    return
                self.loadPer(self.listP.currentItem().text())
        except AttributeError:  # To initialize createFrame UI before load
            if self.listP.currentItem().text() != "":
                temp = self.listP.currentItem().text()
                self.buttonFrame.close()
                self.initUI(False)
                self.loadPer(temp)
            else:
                return
        self.createFrame.show()
        self.mainframe.center()
        print("Changed to edit frame")

    def save(self):
        """
        Validate all info and save to file on disk.
        """
        if os.path.exists(json_reader.buildPath("data/pers/"+self.nameT.text()+".json")):
            if not popup("Override existing Persona "+self.nameT.text()+"?", "Question"):
                return
        print("Saving")
        spellDeck = []
        for combobox in self.iSpellOs:
            spellDeck.append(combobox.currentText())
        stats = [self.strT.text(), self.magT.text(), self.endT.text(), self.agiT.text(), self.luckT.text()]
        res = [self.slashO.currentText(), self.strikeO.currentText(), self.pierceO.currentText(),
               self.fireO.currentText(), self.iceO.currentText(), self.elecO.currentText(),
               self.windO.currentText(), self.lightO.currentText(), self.darkO.currentText()]
        try:
            (int)(self.levelT.text())
            (int)(self.strT.text())
            (int)(self.magT.text())
            (int)(self.endT.text())
            (int)(self.agiT.text())
            (int)(self.luckT.text())
        except ValueError:
            popup("There is a number entry that isn't valid.\nEntries requiring numbers are:\nLEVEL\nSTR"
                  "\nMAG\nEND\nAGI\nLUCK", "Critical")
            print("Not Saved")
            return
        if not (self.nameT.text() and not self.nameT.text().isspace()):
            popup("No name entered for your Persona. Name is a required field.", "Critical")
            print("No Name, not saved")
            return
        toWrite = Persona(
            self.nameT.text(),
            self.arcO.currentText(),
            self.levelT.text(),
            self.textT.toPlainText(),
            spellDeck,
            self.lsdic,
            stats,
            res,
            [self.listEL1.currentText(), self.listEL2.currentText()]
        )
        json_reader.writeOne(toWrite, 'pers')
        temp = self.nameT.text()
        if (temp not in [self.listP.item(i).text() for i in range(self.listP.count())]):
            self.listP.addItem(temp)
        self.loadPer(temp)
        print("Saved Persona")

    def remove(self):
        """
        Remove a created Persona from the list and delete the file on disk.
        """
        if self.listP.currentItem().text() == "":
            return
        if not popup(
                "Are you certain you want to completely remove this Persona?\n(Cannot be undone)", "Warning"
            ):
            return
        print("Removing Persona " + self.listP.currentItem().text())
        json_reader.deletePer(self.listP.currentItem().text())
        self.listP.takeItem(
            [self.listP.item(i).text() for i in range(self.listP.count())].index(
                self.listP.currentItem().text())
        )

    def new(self):
        """
        Open an empty Persona edit view.
        """
        if self.createFrame and not popup("Override any unsaved changes?", "Warning"):
            return
        if self.createFrame:
            self.createFrame.close()
        self.buttonFrame.close()
        self.initUI(False)
        self.createFrame.show()
        self.mainframe.center()
        print("Created")

    def back(self):
        """
        Return to the parent widget.
        """
        print("Returned to main screen")
        self.mainframe.changeState(self.op)
示例#19
0
class EditCommentBankWindow(QMainWindow):
    def __init__(self, subject_name):
        QMainWindow.__init__(self)
        self.setWindowTitle("Edit Comment Bank: {} - {} {}".format(
            subject_name, config.APP_NAME, config.APP_VERSION))
        self.setMinimumWidth(1200)
        self.setStyleSheet(config.STYLESHEET)

        self.subject = could_try_harder.load(subject_name)
        self.saved_list = could_try_harder.get_saved_list()

        # Widgets
        self.intro_comment_label = QLabel("Introductory Comment:")
        self.intro_comment_label.setProperty("styleClass", "heading")
        self.intro_comment_textedit = QTextEdit()
        self.comment_bank_label = QLabel("Comment Bank")
        self.comment_bank_label.setProperty("styleClass", "heading")
        self.comment_bank_listwidget = QListWidget()
        self.placeholder_instructions_label = QLabel(
            config.PLACEHOLDER_INSTRUCTIONS)
        self.add_comment_label = QLabel("Add Comment:")
        self.add_comment_entry = QLineEdit()
        self.add_comment_button = QPushButton("Add")
        self.update_comment_label = QLabel("Update Comment:")
        self.update_comment_entry = QLineEdit()
        self.update_comment_button = QPushButton("Update")
        self.delete_comment_button = QPushButton("Delete Comment")
        self.import_comments_combo = QComboBox()
        self.import_comments_button = QPushButton("Import...")
        self.cancel_button = QPushButton("Cancel")
        self.save_button = QPushButton("Save")

        # Layout
        self.layout = QVBoxLayout()
        self.top_layout = QHBoxLayout()
        self.intro_comment_layout = QVBoxLayout()
        self.intro_comment_layout.addWidget(self.intro_comment_label)
        self.intro_comment_layout.addWidget(self.intro_comment_textedit)
        self.top_layout.addLayout(self.intro_comment_layout)
        self.top_layout.addWidget(self.placeholder_instructions_label)
        self.layout.addLayout(self.top_layout)
        self.middle_layout = QVBoxLayout()
        self.middle_layout.addWidget(self.comment_bank_label)
        self.middle_layout.addWidget(self.comment_bank_listwidget)
        self.comment_actions_layout = QHBoxLayout()
        self.comment_actions_layout.addWidget(self.delete_comment_button, 0,
                                              Qt.AlignLeft)
        self.comment_actions_layout.addWidget(self.import_comments_combo, 1,
                                              Qt.AlignRight)
        self.comment_actions_layout.addWidget(self.import_comments_button, 0,
                                              Qt.AlignRight)
        self.middle_layout.addLayout(self.comment_actions_layout)
        self.update_comment_layout = QGridLayout()
        self.update_comment_layout.addWidget(self.update_comment_label, 0, 0)
        self.update_comment_layout.addWidget(self.update_comment_entry, 0, 1)
        self.update_comment_layout.addWidget(self.update_comment_button, 0, 2)
        self.update_comment_layout.addWidget(self.add_comment_label, 1, 0)
        self.update_comment_layout.addWidget(self.add_comment_entry, 1, 1)
        self.update_comment_layout.addWidget(self.add_comment_button, 1, 2)
        self.middle_layout.addLayout(self.update_comment_layout)
        self.layout.addLayout(self.middle_layout)
        self.bottom_layout = QHBoxLayout()
        self.bottom_layout.addWidget(self.cancel_button, 0, Qt.AlignLeft)
        self.bottom_layout.addWidget(self.save_button, 0, Qt.AlignRight)
        self.layout.addLayout(self.bottom_layout)

        # Slot connections
        self.comment_bank_listwidget.itemSelectionChanged.connect(
            self.do_update_comment_bank_selection)
        self.import_comments_button.clicked.connect(self.do_import_comments)
        self.update_comment_button.clicked.connect(self.do_update_comment)
        self.update_comment_entry.returnPressed.connect(self.do_update_comment)
        self.add_comment_button.clicked.connect(self.do_add_comment)
        self.add_comment_entry.returnPressed.connect(self.do_add_comment)
        self.delete_comment_button.clicked.connect(self.do_delete_comment)
        self.cancel_button.clicked.connect(self.do_cancel)
        self.save_button.clicked.connect(self.do_save)

        # Initial UI update
        self.update_ui()

        self.widget = QWidget()
        self.widget.setLayout(self.layout)
        self.setCentralWidget(self.widget)

    def update_ui(self):
        self.update_import_comments_list()
        self.update_intro_comment()
        self.update_comment_bank()

    def update_import_comments_list(self):
        self.import_comments_combo.clear()
        self.import_comments_combo.insertItems(0, self.saved_list)

    def update_intro_comment(self):
        self.intro_comment_textedit.clear()
        self.intro_comment_textedit.insertPlainText(
            self.subject['intro_comment'])

    def update_comment_bank(self):
        self.comment_bank_listwidget.clear()
        self.comment_bank_listwidget.addItems(self.subject['comment_bank'])
        self.do_update_comment_bank_selection()

    @Slot()
    def do_import_comments(self):
        # TODO confirm dialog first
        confirm_msg = QMessageBox(self)
        confirm_msg.setWindowTitle("Confirm")
        confirm_msg.setText("This will override current comments.")
        confirm_msg.setInformativeText("Do you want to continue?")
        confirm_msg.setStandardButtons(QMessageBox.No | QMessageBox.Yes)
        confirm_msg.setDefaultButton(QMessageBox.Yes)
        confirm = confirm_msg.exec()
        if confirm == QMessageBox.Yes:
            if self.import_comments_combo.count() > 0:
                new_subject = could_try_harder.load(
                    self.import_comments_combo.currentText())
                if new_subject:
                    self.subject['intro_comment'] = new_subject[
                        'intro_comment']
                    self.subject['comment_bank'] = new_subject['comment_bank']
                    self.update_ui()
                else:
                    # TODO better error handling here
                    print('Tried to import empty subject.')
                    return
        return

    @Slot()
    def do_update_comment_bank_selection(self):
        if self.comment_bank_listwidget.selectedItems():
            state = True
        else:
            state = False
        self.delete_comment_button.setEnabled(state)
        self.update_comment_button.setEnabled(state)
        # Update the text in the update comment line edit
        self.update_comment_entry.clear()
        if self.comment_bank_listwidget.currentItem():
            self.update_comment_entry.insert(
                self.comment_bank_listwidget.currentItem().text())

    @Slot()
    def do_update_comment(self):
        if self.update_comment_entry.text():
            self.comment_bank_listwidget.currentItem().setText(
                could_try_harder.do_style(
                    self.update_comment_entry.text().strip()))
            self.do_update_comment_bank_selection()

    @Slot()
    def do_add_comment(self):
        if self.add_comment_entry.text():
            self.comment_bank_listwidget.addItem(
                could_try_harder.do_style(
                    self.add_comment_entry.text().strip()))
            self.add_comment_entry.clear()
            self.do_update_comment_bank_selection()

    @Slot()
    def do_delete_comment(self):
        self.comment_bank_listwidget.takeItem(
            self.comment_bank_listwidget.currentRow())
        self.do_update_comment_bank_selection()

    @Slot()
    def do_cancel(self):
        self.close()

    @Slot()
    def do_save(self):
        self.subject['intro_comment'] = could_try_harder.do_style(
            self.intro_comment_textedit.toPlainText().strip())
        self.subject['comment_bank'] = []
        for i in range(self.comment_bank_listwidget.count()):
            self.subject['comment_bank'].append(
                self.comment_bank_listwidget.item(i).text())
        if could_try_harder.save(self.subject):
            self.close()
        else:
            # TODO better error handling here
            print("Save failed.")