Пример #1
0
class AddOperatorWidget(QWidget):
    def __init__(self, controller: EzCVController, parent=None):
        super().__init__(parent)
        self.setWindowFlag(Qt.WindowStaysOnTopHint)
        self._controller = controller
        self.operators = {
            cls.__name__: cls
            for cls in get_available_operators()
        }

        self.available_operators_list = QListWidget(self)
        self.available_operators_list.doubleClicked.connect(
            self.accept_operator)
        self.available_operators_list.installEventFilter(self)

        self.button_box = QDialogButtonBox(QDialogButtonBox.Ok
                                           | QDialogButtonBox.Cancel)
        self.button_box.accepted.connect(self.accept_operator)
        self.button_box.rejected.connect(self.hide)

        self.init_ui()

    def init_ui(self):
        self.resize(300, 400)

        main_layout = QVBoxLayout(self)
        main_layout.addWidget(self.available_operators_list, stretch=5)
        main_layout.addWidget(self.button_box, stretch=1)

        self.available_operators_list.addItems(self.operators.keys())
        self.available_operators_list.setCurrentRow(0)

    def accept_operator(self):
        selected_item = self.available_operators_list.currentItem().text()
        selected_operator = self.operators[selected_item]
        self._controller.add_operator(selected_operator)
        self.hide()

    def eventFilter(self, watched, event):
        """ Catch ENTER and ESC key presses
        """
        if event.type() == QEvent.KeyPress:
            if event.matches(QKeySequence.InsertParagraphSeparator):
                self.accept_operator()
            elif event.matches(QKeySequence.Cancel):
                self.hide()
        return False
Пример #2
0
class HeaderEditDialog(QDialog):

    header_changed = pyqtSignal(str, list)

    def __init__(self, parent, columns):
        super().__init__(parent)

        self.columns = copy.deepcopy(columns)
        self.setupUi()

    def setupUi(self):
        self.resize(200, 400)
        self.vbox = QVBoxLayout(self)
        self.columnList = QListWidget(self)
        self.vbox.addWidget(self.columnList)

        self.columnList.setDragDropMode(QListWidget.InternalMove)
        self.columnList.setDefaultDropAction(Qt.MoveAction)
        self.columnList.setSelectionMode(QListWidget.ExtendedSelection)
        self.columnList.setAlternatingRowColors(True)
        self.columnList.installEventFilter(self)
        self.columnList.setObjectName("ColumnList")
        # self.columnList.setContextMenuPolicy(Qt.CustomContextMenu)
        # self.columnList.customContextMenuRequested.connect(self.open_menu)

        self.buttonBox = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, self)
        self.vbox.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.fill_column_list()

    def eventFilter(self, object, event):
        if event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
                self.toggle_selected_columns()
                return True
        return False

    def fill_column_list(self):
        for column in self.columns:
            ColumnListItem(self.columnList, column)

    def accept(self):
        result = []
        for i in range(self.columnList.count()):
            item = self.columnList.item(i)
            result.append(item.column)
        self.header_changed.emit('rearrange', result)
        self.done(0)

    def reject(self):
        self.done(0)

    def toggle_selected_columns(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            value_now = item.data(Qt.CheckStateRole)
            item.setData(Qt.CheckStateRole, not value_now)
        self.columnList.reset(
        )  # @Improvement: is there a better way to update QListWidget?

    # def load_preset(self, action):
    #     name = action.text()
    #     self.result_future(('load', name))
    #
    # def save_preset(self, action):
    #     result = []
    #     for i in range(self.columnList.count()): # column list has to be generated here because if
    #         item = self.columnList.item(i)       # you rearrange and save, then what gets saved is
    #         result.append(item.column)           # the un-rearranged list from the table header
    #
    #     name = action.text()
    #     if action.property('new'):
    #         self.result_future(('save new', (name, result)))
    #     else:
    #         self.result_future(('save', (name, result)))

    # def open_menu(self, position):
    #     return  # @TODO: implement header presets
    #     menu = QMenu(self)
    #
    #     load_menu = QMenu('Load preset', self)
    #     save_menu = QMenu('Save preset as', self)
    #     save_new_action = save_menu.addAction('New')
    #     save_new_action.setProperty('new', True)
    #     save_menu.addSeparator()
    #
    #     presets = CONFIG.get_columns_presets()
    #     for preset in presets:
    #         load_menu.addAction(preset)
    #         save_menu.addAction(preset)
    #
    #     load_menu.triggered.connect(self.load_preset)
    #     save_menu.triggered.connect(self.save_preset)
    #
    #     menu.addMenu(load_menu)
    #     menu.addMenu(save_menu)
    #
    #     menu.popup(self.columnList.viewport().mapToGlobal(position))

    def get_selected_items(self):
        result = []
        selected = self.columnList.selectedIndexes()
        for index in selected:
            item = self.columnList.itemFromIndex(index)
            result.append(item)
        return result

    def enable_selected(self):
        selected = self.get_selected_items()
        for item in selected:
            item.setData(Qt.CheckStateRole, Qt.Checked)

    def disable_selected(self):
        selected = self.get_selected_items()
        for item in selected:
            item.setData(Qt.CheckStateRole, Qt.Unchecked)
Пример #3
0
class Window(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.user_interface()

    def item_click(self, item):
        number = self.view.currentRow()
        if self.shuffled == False:
            self.playlist.setCurrentIndex(number)
            self.player.play()
        elif self.shuffled == True:
            pass

    def item_doubleclick(self, item):
        self.current_item_song = item
        menu = QtWidgets.QMenu()
        createPlaylist = QAction('Create New Playlist')
        createPlaylist.triggered.connect(self.create_playlist)
        menu.addAction(createPlaylist)
        addToPlaylist = QAction('Add To Playlist')
        addToPlaylist.triggered.connect(self.add_to_playlist)
        menu.addAction(addToPlaylist)
        menu.exec_()

    def user_interface(self):
        self.all_song_button = QtWidgets.QPushButton("All songs")
        self.play_button = QtWidgets.QPushButton()
        self.play_button.setIcon(self.style().standardIcon(
            QStyle.SP_MediaPlay))
        self.next_button = QtWidgets.QPushButton()
        self.next_button.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSeekForward))
        self.prev_button = QtWidgets.QPushButton()
        self.prev_button.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSeekBackward))
        self.shuffle_button = QtWidgets.QPushButton("🔀")
        self.min_volumn = QtWidgets.QLabel("🔈")
        self.max_volumn = QtWidgets.QLabel("🔊")
        self.l_playlists = QtWidgets.QLabel("Playlists:")
        self.l_current_song = QtWidgets.QLabel("Current song:")

        self.songs = QtWidgets.QLabel("Songs:\n")

        self.view = QListWidget()
        self.viewPlaylists = QListWidget()
        self.all_songs = self.load_songs()
        self.all_playlists = self.load_playlists()
        self.viewPlaylists.adjustSize()

        self.view.adjustSize()
        self.view.itemClicked.connect(self.item_click)
        self.view.itemDoubleClicked.connect(self.item_doubleclick)

        self.view.installEventFilter(self)

        self.set_playlist()

        self.line_edit = QtWidgets.QLineEdit()
        self.line_edit.setText("")
        self.search_button = QtWidgets.QPushButton("search")

        # scroll are for list of songs
        self.songs_scroll_area = QtWidgets.QScrollArea()
        self.songs_scroll_area.setWidget(self.view)
        self.songs_scroll_area.setWidgetResizable(True)

        # scroll area for list of playlists
        self.playlists_scroll_area = QtWidgets.QScrollArea()
        self.playlists_scroll_area.setWidget(self.viewPlaylists)
        self.playlists_scroll_area.setWidgetResizable(True)
        # self.playlists_scroll_bar = QtWidgets.QScrollBar()
        # self.playlists_scroll_area.setVerticalScrollBar(self.playlists_scroll_bar)
        # self.playlists_scroll_area.setVerticalScrollBarPolicy(C.Qt.ScrollBarAlwaysOn)

        # set area for current song box
        self.current_song_area = QtWidgets.QScrollArea()
        self.current_song_area.setWidget(self.l_current_song)

        # set volumn slider
        self.volumn_slider = QtWidgets.QSlider(C.Qt.Horizontal)
        self.volumn_slider.setMaximum(100)
        self.volumn_slider.setMinimum(0)
        self.volumn_slider.setValue(50)
        self.volumn_slider.setTickPosition(QtWidgets.QSlider.TicksRight)
        self.volumn_slider.setTickInterval(10)

        self.seekSlider = QtWidgets.QSlider()
        self.seekSlider.setMinimum(0)
        self.seekSlider.setMaximum(100)
        self.seekSlider.setRange(0, self.player.duration() / 1000)
        self.seekSlider.setOrientation(C.Qt.Horizontal)
        self.seekSlider.setTracking(False)
        seekSliderLabel1 = QtWidgets.QLabel('0.00')
        seekSliderLabel2 = QtWidgets.QLabel('0.00')

        self.set_playlist()
        self.volume_change()

        # self.list_view = QtWidgets.QListView(self.all_songs)

        h_box = QtWidgets.QHBoxLayout()
        v_box = QtWidgets.QVBoxLayout()
        self.h_box4 = QtWidgets.QHBoxLayout()

        # h_box.addWidget(backGround)

        v_box.addWidget(self.all_song_button)
        v_box.addWidget(self.playlists_scroll_area)
        v_box.addWidget(self.current_song_area)

        self.h_box4.addWidget(seekSliderLabel1)
        self.h_box4.addWidget(self.seekSlider)
        self.h_box4.addWidget(seekSliderLabel2)

        h_box.addLayout(v_box)

        v_box1 = QtWidgets.QVBoxLayout()
        v_box1.addWidget(self.line_edit)

        v_box2 = QtWidgets.QVBoxLayout()
        v_box2.addWidget(self.songs_scroll_area)

        h_box.addLayout(v_box1)

        h_box1 = QtWidgets.QHBoxLayout()
        h_box1.addWidget(self.shuffle_button)
        h_box1.addWidget(self.prev_button)
        h_box1.addWidget(self.play_button)
        h_box1.addWidget(self.next_button)

        h_box3 = QtWidgets.QHBoxLayout()
        h_box3.addWidget(self.min_volumn)
        h_box3.addWidget(self.volumn_slider)
        h_box3.addWidget(self.max_volumn)

        h_box2 = QtWidgets.QHBoxLayout()
        h_box2.addWidget(self.search_button)

        v_box1.addLayout(h_box2)
        v_box1.addLayout(v_box2)
        v_box1.addLayout(self.h_box4)
        v_box1.addLayout(h_box1)
        v_box1.addLayout(h_box3)

        self.setLayout(h_box)

        self.setWindowTitle("Music Player")
        self.setGeometry(100, 100, 800, 600)
        self.show()

        self.play_button.setShortcut(' ')
        self.next_button.setShortcut('Alt+Right')
        self.prev_button.setShortcut('Alt+Left')
        self.search_button.setShortcut('Return')
        self.play_button.clicked.connect(self.play)
        self.next_button.clicked.connect(self.next)
        self.prev_button.clicked.connect(self.back)
        self.shuffle_button.clicked.connect(self.shuffle)
        self.search_button.clicked.connect(self.search)
        self.volumn_slider.valueChanged.connect(self.volume_change)
        self.all_song_button.clicked.connect(self.load_songs)
        self.player.currentMediaChanged.connect(self.current_song)
        self.player.positionChanged.connect(self.qmp_positionChanged)
        self.player.durationChanged.connect(self.change_duration)
        self.all_song_button.clicked.connect(self.show_all_songs)

        self.shuffled = False

    def add_to_playlist(self):
        menu = QtWidgets.QMenu()
        for item in self.all_playlists:
            menuItemTask = menu.addAction(item)
            menuItemTask.triggered.connect(self.picked_playlist)
            menu.addAction(menuItemTask)
        menu.exec_()

    def picked_playlist(self):
        print(self.current_item_song)
        # file = open(item, 'w')
        # file.write(self.current_item)
        # file.close()

    def create_playlist(self):
        root = C.QFileInfo(__file__).absolutePath()
        spot = (root + '/songs/')
        playlistName = self.getText()
        completeName = os.path.join(spot, f'{playlistName}.m3u')
        file = open(completeName, 'w')
        file.close()
        self.all_playlists.clear()
        self.playlists_scroll_area.update()
        self.all_playlists = self.load_playlists()
        self.playlists_scroll_area.update()

    def getText(self):
        text, okPressed = QInputDialog.getText(self, "New Playlist",
                                               "Playlist Name:",
                                               QLineEdit.Normal, "")
        if okPressed and text != '':
            return text

    def load_playlists(self):
        playlists = []
        root = C.QFileInfo(__file__).absolutePath()
        songs = os.listdir(root + "/songs")
        for item in songs:
            if str(item[-4:]) == '.m3u':
                self.viewPlaylists.addItem(item[:-4])
                print(root + "/songs" + item)
                playlists.append(root + "/songs" + item)
        return playlists

    def show_all_songs(self):
        self.view.clear()
        self.playlist.clear()
        root = C.QFileInfo(__file__).absolutePath()
        songs = os.listdir(root + "/songs")
        s = "Songs:\n"
        for item in songs:
            if item.endswith('.mp3'):
                url = C.QUrl.fromLocalFile(item)
                content = M.QMediaContent(url)
                s = (str(item[:-4]))
                self.view.addItem(s)
                self.playlist.addMedia(content)

    def current_song(self, media):
        name = media.canonicalUrl()
        name = name.toString()
        name = name.split('/')
        url = name[-1]
        url = url[:-4]
        self.l_current_song.setText('Current Song:\n\n' + url)
        self.l_current_song.adjustSize()

    def change_duration(self):
        self.seekSlider.setRange(0, self.player.duration() / 1000)

    def qmp_positionChanged(self, position):
        if self.shuffled == False:
            sliderLayout = self.h_box4.layout()
            sliderLayout.itemAt(0).widget().setText(
                '%d:%02d' % (int(position / 60000), int(
                    (position / 1000) % 60)))
            self.seekSlider.setValue(position / 1000)
            sliderLayout.itemAt(2).widget().setText(
                '%d:%02d' % (int(self.player.duration() / 60000),
                             int((self.player.duration() / 1000) % 60)))
        elif self.shuffled == True:
            sliderLayout = self.h_box4.layout()
            sliderLayout.itemAt(0).widget().setText(
                '%d:%02d' % (int(position / 60000), int(
                    (position / 1000) % 60)))
            self.seekSlider.setValue(position / 1000)
            sliderLayout.itemAt(2).widget().setText(
                '%d:%02d' % (int(self.player.duration() / 60000),
                             int((self.player.duration() / 1000) % 60)))

    def load_songs(self):
        songList = []
        s = 'Songs:\n\n'
        root = C.QFileInfo(__file__).absolutePath()
        songs = os.listdir(root + "/songs")
        for item in songs:
            if item.endswith('.mp3'):
                s += (str(item[:-4]) + '\n')
                self.view.addItem(str(item[:-4]))
                song = (root + '/songs/' + item + '\n')
                songList.append(song)
        self.songs.setText(s)
        return songList

    def set_playlist(self):
        self.player = M.QMediaPlayer(self)
        self.player2 = M.QMediaPlayer(self)
        self.playlist = M.QMediaPlaylist(self.player)
        self.playlist2 = M.QMediaPlaylist(self.player2)
        for song in self.all_songs:
            url = C.QUrl.fromLocalFile(song[:-1])
            content = M.QMediaContent(url)
            self.playlist.addMedia(content)
            self.playlist2.addMedia(content)
        self.playlist.setCurrentIndex(0)
        self.playlist2.shuffle()
        self.playlist2.setCurrentIndex(0)
        self.player.setPlaylist(self.playlist)
        self.player2.setPlaylist(self.playlist2)

    def play(self):
        if self.shuffled == False:
            if self.player.state() == 0 or self.player.state() == 2:
                self.play_button.setIcon(self.style().standardIcon(
                    QStyle.SP_MediaPause))
                self.player.play()
            else:
                self.player.pause()
                self.play_button.setIcon(self.style().standardIcon(
                    QStyle.SP_MediaPlay))
        else:
            if self.player2.state() == 0 or self.player2.state() == 2:
                self.play_button.setIcon(self.style().standardIcon(
                    QStyle.SP_MediaPause))
                self.player2.play()
            else:
                self.player2.pause()
                self.play_button.setIcon(self.style().standardIcon(
                    QStyle.SP_MediaPlay))

    def next(self):
        if self.shuffled == False:
            numb = self.playlist.currentIndex()
            self.playlist.setCurrentIndex(numb + 1)
            self.player.play()
        else:
            numb = self.playlist2.currentIndex()
            self.playlist2.setCurrentIndex(numb + 1)
            self.player2.play()

    def back(self):
        if self.shuffled == False:
            numb = self.playlist.currentIndex()
            self.playlist.setCurrentIndex(numb - 1)
            self.player.play()
        else:
            numb = self.playlist2.currentIndex()
            self.playlist2.setCurrentIndex(numb - 1)
            self.player2.play()

    def shuffle(self):
        if self.shuffled == False:
            self.player.stop()
            self.playlist2.shuffle()
            self.playlist2.setCurrentIndex(0)
            self.player2.play()
            self.shuffled = True
        elif self.shuffled == True:
            self.player2.stop()
            self.playlist.setCurrentIndex(0)
            self.player.play()
            self.shuffled = False

    def volume_change(self):
        numb = self.volumn_slider.value()
        self.player.setVolume(numb)
        self.player2.setVolume(numb)

    def display_song_list(self, list_of_songs):
        self.view.clear()
        if self.shuffled == False:
            self.playlist.clear()
        else:
            self.playlist2.clear()
        s = 'Songs:\n\n'
        for item in list_of_songs:
            url = C.QUrl.fromLocalFile(item)
            content = M.QMediaContent(url)
            if self.shuffled == False:
                self.playlist.addMedia(content)
            else:
                self.playlist2.addMedia(content)
            s += (str(item[:-4]) + '\n')
            self.view.addItem(s)

    def search(self):
        s_term = self.line_edit.text()
        filtered_list_of_songs = []
        root = C.QFileInfo(__file__).absolutePath()
        songs = os.listdir(root + "/songs")
        # search through each song in all_songs...if it matches add to filtered_list_of_songs
        for song in songs:
            if song.lower().find(s_term.lower()) > -1:
                filtered_list_of_songs.append(song)
        self.display_song_list(filtered_list_of_songs)
Пример #4
0
class Main(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('akari')
        self.setWindowIcon(QIcon('static/icon.jpg'))

        # Stores the db dictionary
        self.db = None
        # Is set to 1 when metadata view of a single photo needs to be shown
        self.viewMetadata_flag = 0
        # The full screen Image Viewer window
        self.imageViewer = imageViewer()

        # The main layout
        self.mainLayout = QHBoxLayout()
        # Add spliter to enable dyanmic resizing of taglist and imagelist
        self.splitter = QSplitter(Qt.Horizontal)
        self.leftSplitterWidget = QWidget()
        self.rightSplitterWidget = QWidget()
        self.splitter.addWidget(self.rightSplitterWidget)
        self.splitter.addWidget(self.leftSplitterWidget)

        # Initialize elements for the taglist panel
        self.sidePanel = QVBoxLayout()
        self.tagList = QListWidget()
        self.filerButton = QPushButton("Filter")
        self.clearFilerButton = QPushButton("Reset")
        self.sidePanel.addWidget(self.tagList)
        self.rightSplitterWidget.setLayout(self.sidePanel)

        # Initialize elements for the imagelist panel
        self.imagePanel = QVBoxLayout()
        self.imageList = QListWidget()
        self.imagePanelOptions = QHBoxLayout()
        self.fsToggle = QPushButton("View Images in FullScreen")
        self.quitButton = QPushButton("Quit")
        self.imagePanel.addWidget(self.imageList)
        self.leftSplitterWidget.setLayout(self.imagePanel)

        # Add the splitter to the main layout
        self.mainLayout.addWidget(self.splitter)
        self.setLayout(self.mainLayout)

        self.initUI()

    """
        Adds button widgets to their respective panels
        Sets settings (like icon size) for image list
    """

    def initUI(self):
        self.sidePanel.addWidget(self.filerButton, 1)
        self.sidePanel.addWidget(self.clearFilerButton, 1)
        self.tagList.setSelectionMode(QAbstractItemView.ExtendedSelection)

        self.imageList.setViewMode(QListView.IconMode)
        self.imageList.setIconSize(QSize(300, 300))
        self.imageList.installEventFilter(self)

        self.imagePanel.addLayout(self.imagePanelOptions)
        self.imagePanelOptions.addWidget(self.fsToggle)
        self.imagePanelOptions.addWidget(self.quitButton)

        self.addEventHandlers()
        self.show()

    def updateDB(self, db):
        self.db = db

    """
        Adds event handlers for various buttons
    """

    def addEventHandlers(self):
        self.filerButton.clicked.connect(self.filterButton_pressed)
        self.clearFilerButton.clicked.connect(self.clearFilterButton_pressed)
        self.fsToggle.clicked.connect(self.fsToggle_pressed)
        self.quitButton.clicked.connect(self.close)
        self.imageList.itemDoubleClicked.connect(self.viewMetadata)

    """
        Adds the buttons necessary to allow users to add new tags and remove tags
        These are only shown if `viewMetadata_flag` is set to 1
    """

    def addTagEditingButtons(self):
        self.addTagsButton = QPushButton("Add New Tag")
        self.removeTagsButton = QPushButton("Remove Selected Tags")
        self.sidePanel.addWidget(self.addTagsButton)
        self.sidePanel.addWidget(self.removeTagsButton)
        self.addTagsButton.clicked.connect(self.addTagsButton_pressed)
        self.removeTagsButton.clicked.connect(self.removeTagsButton_pressed)

    """
        Removes the buttons necessary to allow users to add new tags and remove tags
    """

    def removeTagEditingButtons(self):
        try:
            self.viewMetadata_flag = 0
            self.sidePanel.removeWidget(self.addTagsButton)
            self.addTagsButton.deleteLater()
            self.sidePanel.removeWidget(self.removeTagsButton)
            self.removeTagsButton.deleteLater()
        except:
            pass

    """
        Refreshes the taglist for a given image
        Called when user adds or removes some tags from an image
    """

    def refreshTagListForImage(self, image):
        self.tagList.clear()
        for tag in self.db[image]:
            self.tagList.addItem(tag)

    """
        This function is called when user presses the "View Imagesin FullScreen" button
    """

    def fsToggle_pressed(self):
        self.imageViewer.set_imageNumber(0)
        imageViewer_list = []
        for x in range(self.imageList.count()):
            imageViewer_list.append(self.imageList.item(x).data(0))
        if len(imageViewer_list) > 0:
            self.imageViewer.set_imageViewerList(imageViewer_list)
            self.imageViewer.addImage(imageViewer_list[0])
            self.imageViewer.showFullScreen()

    """
        This function is called when user presses the "Add Tags" button in the metadata view
    """

    def addTagsButton_pressed(self):
        image = self.imageList.item(0).data(0)
        tag, okPressed = QInputDialog.getText(self, "Enter Tag", "Enter Tag",
                                              QLineEdit.Normal, "")
        if okPressed and tag != '':
            if tag not in self.db[image]:
                self.db[image].append(tag)
                if tag in self.db['akari-tags']:
                    self.db['akari-tags'][tag] = self.db['akari-tags'][tag] + 1
                else:
                    self.db['akari-tags'][tag] = 1
        commit_changes(self.db)
        self.db = loadDB()
        self.refreshTagListForImage(image)

    """
        This function is called when user presses the "Remove Selected Tags" button in the metadata view
    """

    def removeTagsButton_pressed(self):
        tags_to_remove = self.tagList.selectedItems()
        image = self.imageList.item(0).data(0)
        for tag in tags_to_remove:
            tag = tag.text()
            self.db[image].remove(tag)
            self.db['akari-tags'][tag] = self.db['akari-tags'][tag] - 1
            if self.db['akari-tags'][tag] == 0:
                self.db['akari-tags'].pop(tag, None)
        commit_changes(self.db)
        self.db = loadDB()
        self.refreshTagListForImage(image)

    """
        This function is called when user presses the "Filter" button
    """

    def filterButton_pressed(self):
        selected_items = self.tagList.selectedItems()
        selected_tags = []
        filtered_images = []
        for i in range(len(selected_items)):
            selected_tags.append(
                str(self.tagList.selectedItems()[i].text()).split(" ")[-1])
        for imgPath in self.db:
            if imgPath == 'akari-tags':
                continue
            if all(elem in self.db[imgPath] for elem in selected_tags):
                if imgPath not in filtered_images:
                    filtered_images.append(imgPath)
        self.addImages(filtered_images)
        self.removeTagEditingButtons()

    """
        This function is called when user presses the "Reset" button
    """

    def clearFilterButton_pressed(self):
        imgList = self.getImgList()
        self.addImages(imgList)
        self.addTags()
        self.removeTagEditingButtons()

    """
        This function is called when user selects the "View Metadata" Option in the context menu
    """

    def viewMetadata(self):
        if self.viewMetadata_flag == 0:
            self.viewMetadata_flag = 1
            selected_image = self.imageList.selectedItems()[0].data(0)
            tags = self.db[selected_image]
            self.tagList.clear()
            self.tagList.addItems(tags)
            self.addImages([selected_image])
            self.addTagEditingButtons()

    """
        Override funtion to add "View Metadata" option in the context menu
    """

    def contextMenuEvent(self, event):
        menu = QMenu(self)
        if self.imageList.selectedItems() != []:
            viewMetadata = menu.addAction("View Metadata")
            action = menu.exec_(self.mapToGlobal(event.pos()))
            if action == viewMetadata:
                self.viewMetadata()

    """
        Returns a list of images from the db dictionary
    """

    def getImgList(self):
        imgList = []
        for imgPath in self.db:
            if imgPath == 'akari-tags':
                continue
            imgList.append(imgPath)
        return imgList

    """
        Clears all the images in the image panel and adds images from `imgList`
    """

    def addImages(self, imgList):
        self.imageList.clear()
        for imgPath in imgList:
            item = QListWidgetItem()
            icon = QIcon()
            pixmap = QPixmap(imgPath)
            icon.addPixmap(pixmap)
            item.setFont(QFont("Times", 1))
            item.setForeground(QColor("white"))
            item.setText(imgPath)
            item.setIcon(icon)
            self.imageList.addItem(item)

    """
        Clears all the tags in the tag panel and adds all the tags along with their count from the db dictionary
    """

    def addTags(self):
        self.tagList.clear()
        tagList = []
        for tag in sorted(self.db['akari-tags'],
                          key=self.db['akari-tags'].get,
                          reverse=True):
            tagList.append(str(self.db['akari-tags'][tag]) + ' ' + tag)
        self.tagList.addItems(tagList)
Пример #5
0
class AudioPlayerPage(QWidget):
    about_play_audio = pyqtSignal(str)

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

        self.audio_list_widget = QListWidget()
        self.audio_list_widget.installEventFilter(self)
        self.audio_list_widget.itemDoubleClicked.connect(self.play)

        # TODO: playlist объединить с audio_list_widget (см примеры работы с QMediaPlayer)
        self.playlist = QMediaPlaylist()
        self.playlist.currentIndexChanged.connect(
            lambda row: self.audio_list_widget.setCurrentRow(row))

        # TODO: обрабатывать сигналы плеера: http://doc.qt.io/qt-5/qmediaplayer.html#signals
        self.player = QMediaPlayer()
        self.player.setPlaylist(self.playlist)
        self.player.currentMediaChanged.connect(
            lambda media: self.about_play_audio.emit(self.audio_list_widget.
                                                     currentItem().text()))

        if not self.player.isAvailable():
            # TODO: перевод
            text = "The QMediaPlayer object does not have a valid service.\n" \
                   "Please check the media service plugins are installed."

            log.warning(text)
            QMessageBox.warning(self, "Service not available", text)

            quit()

        self.controls = PlayerControls(self.player)
        self.controls.set_state(self.player.state())
        self.controls.set_volume(self.player.volume())
        self.controls.set_muted(self.controls.is_muted())

        self.controls.play_signal.connect(self.play)
        self.controls.pause_signal.connect(self.player.pause)
        self.controls.stop_signal.connect(self.player.stop)
        self.controls.next_signal.connect(self.playlist.next)
        self.controls.previous_signal.connect(self.playlist.previous)
        self.controls.change_volume_signal.connect(self.player.setVolume)
        self.controls.change_muting_signal.connect(self.player.setMuted)

        self.progress = QProgressBar()
        self.progress.hide()

        layout = QVBoxLayout()
        layout.addWidget(self.controls)
        layout.addWidget(self.audio_list_widget)
        layout.addWidget(self.progress)

        self.setLayout(layout)

        self.thread = LoadAudioListThread()
        self.thread.about_add_audio.connect(self._add_audio)
        self.thread.about_progress.connect(self.progress.setValue)
        self.thread.about_range_progress.connect(self.progress.setRange)
        self.thread.started.connect(self._start)
        self.thread.finished.connect(self._finished)

    def _add_audio(self, title, url):
        item = QListWidgetItem(title)
        item.setData(Qt.UserRole, url)
        self.audio_list_widget.addItem(item)
        self.playlist.addMedia(QMediaContent(QUrl(url)))

        # При добавлении первой аудизаписи, вызываем воспроизведение
        if self.audio_list_widget.count() == 1:
            self.audio_list_widget.setCurrentRow(0)
            self.playlist.setCurrentIndex(0)
            self.play()

    def _start(self):
        self.audio_list_widget.clear()
        self.playlist.clear()

        self.progress.show()

    def _finished(self):
        self.progress.hide()

    def fill(self, vk):
        self.thread.vk = vk

        # Если поток запущен, останавливаем его, иначе -- запускаем
        if self.thread.isRunning():
            self.thread.exit()
        else:
            self.thread.start()

    def play(self):
        if self.playlist.currentIndex() != self.audio_list_widget.currentRow():
            self.playlist.setCurrentIndex(self.audio_list_widget.currentRow())

        self.player.play()

    def eventFilter(self, obj, event):
        # Воспроизведение видео при клике на кнопки Enter/Return в плейлисте
        if obj == self.audio_list_widget and event.type(
        ) == QKeyEvent.KeyPress:
            if self.audio_list_widget.hasFocus() and event.key(
            ) == Qt.Key_Return or event.key() == Qt.Key_Enter:
                item = self.audio_list_widget.currentItem()
                if item is not None:
                    self.play()

        return super().eventFilter(obj, event)
class MainWindow(CenterWindow):
    """
    Displays list with tasks assigned to current user in JIRA
    """
    def __init__(self, controller):
        super().__init__()
        self.setStyleSheet(QSS)
        self.controller = controller
        self.resize(1000, 600)
        self.setWindowTitle('JIRA Quick Reporter')
        self.setWindowIcon(QIcon(LOGO_PATH))
        self.center()
        self.current_item = None

        self.vbox = QVBoxLayout()

        self.save_btn_box = QHBoxLayout()
        self.filter_name_label = QLabel()
        self.filter_name_label.setObjectName('filter_name_label')
        self.filter_name_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.filter_name_label.setAlignment(Qt.AlignLeft)
        self.filter_edited_label = QLabel('-> edited')
        self.filter_edited_label.setObjectName('filter_edited_label')
        self.filter_edited_label.hide()
        self.filter_edited_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.save_filter_btn = QPushButton('Save as')
        self.save_filter_btn.setObjectName('save_filter_btn')
        self.save_filter_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.save_filter_btn.clicked.connect(self.controller.save_filter)

        self.overwrite_filter_button = QPushButton('Save')
        self.overwrite_filter_button.setToolTip('You need to edit filter query first')
        self.overwrite_filter_button.setObjectName('save_filter_btn')
        self.overwrite_filter_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.overwrite_filter_button.clicked.connect(lambda: self.controller.save_filter(True))

        self.delete_filter_btn = QPushButton()
        self.delete_filter_btn.setObjectName('delete_filter_btn')
        self.delete_filter_btn.clicked.connect(self.delete_filter)
        self.delete_filter_btn.setIcon(QIcon(DELETE_FILTER_ICON))
        self.delete_filter_btn.setIconSize(
            QSize(
                self.delete_filter_btn.sizeHint().height(),
                self.delete_filter_btn.sizeHint().height()
            )
        )
        self.delete_filter_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.delete_filter_btn.setToolTip('Delete filter')

        self.save_btn_box.addWidget(self.filter_name_label, Qt.AlignLeft)
        self.save_btn_box.addWidget(self.filter_edited_label, Qt.AlignLeft)
        self.save_btn_box.addWidget(self.save_filter_btn, Qt.AlignLeft)
        self.save_btn_box.addWidget(self.overwrite_filter_button, Qt.AlignLeft)
        self.save_btn_box.addStretch()
        self.save_btn_box.addWidget(self.delete_filter_btn, Qt.AlignRight)

        self.create_filter_box = QHBoxLayout()
        self.query_field = QLineEdit()
        self.query_field.setObjectName('query_field')
        self.query_field.setPlaceholderText('You need to write a query here')
        self.action_help = QAction()
        self.action_help.setIcon(self.style().standardIcon(QStyle.SP_MessageBoxQuestion))
        self.help_filter_url = QUrl(FILTER_FIELD_HELP_URL)
        self.action_help.triggered.connect(self.filter_field_help)
        self.query_field.addAction(self.action_help, QLineEdit.TrailingPosition)
        self.query_field.installEventFilter(self)
        self.search_issues_button = QPushButton('Search')
        self.search_issues_button.setObjectName('search_issues_button')
        self.search_issues_button.clicked.connect(self.controller.search_issues_by_query)
        self.create_filter_box.addWidget(self.query_field)
        self.create_filter_box.addWidget(self.search_issues_button)

        self.list_box = QVBoxLayout()
        self.issue_list_widget = QListWidget()
        self.issue_list_widget.setObjectName('issue_list')
        self.label_info = QLabel('You have no issues.')
        self.label_info.setAlignment(Qt.AlignCenter)
        self.list_box.addWidget(self.issue_list_widget)
        self.list_box.addWidget(self.label_info)
        self.label_info.hide()

        self.vbox.addLayout(self.save_btn_box)
        self.vbox.addLayout(self.create_filter_box)
        self.vbox.addLayout(self.list_box)

        self.filters_frame = QFrame()
        self.filters_frame.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
        self.filters_frame.setFrameShape(QFrame.StyledPanel)
        self.filters_frame.setObjectName('filters_frame')
        self.filters_box = QVBoxLayout(self.filters_frame)
        self.filters_box_label = QLabel('Issues and filters')
        self.filters_box_label.setObjectName('filters_box_label')
        self.filters_box.addWidget(self.filters_box_label)
        self.filters_list = QListWidget()
        self.filters_list.installEventFilter(self)
        self.filters_list.itemClicked.connect(self.on_filter_selected)
        self.filters_list.setObjectName('filters_list')
        self.filters_list.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.filters_box.addWidget(self.filters_list)
        self.add_filter_button = QPushButton('+')
        self.add_filter_button.clicked.connect(self.add_filter_btn_click)
        self.add_filter_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.filters_box.addWidget(self.add_filter_button, alignment=Qt.AlignRight)

        self.btn_box = QHBoxLayout()
        self.refresh_btn = QPushButton('Refresh')
        self.refresh_btn.clicked.connect(self.controller.refresh_issue_list)
        self.btn_box.addWidget(self.refresh_btn, alignment=Qt.AlignRight)
        self.vbox.addLayout(self.btn_box)

        self.toggle_frame_filters_btn = QPushButton('<')
        self.toggle_frame_filters_btn.clicked.connect(self.toggle_frame_filters)
        self.toggle_frame_filters_btn.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        self.toggle_frame_filters_btn.setObjectName('toggle_filters_btn')

        self.main_box = QHBoxLayout()
        self.main_box.addWidget(self.filters_frame)
        self.main_box.addWidget(self.toggle_frame_filters_btn, alignment=Qt.AlignTop)
        self.main_box.addLayout(self.vbox)
        self.setLayout(self.main_box)

        self.tray_icon = QSystemTrayIcon(self)
        self.tray_icon.setIcon(QIcon(LOGO_PATH))

        self.tray_menu = QMenu()
        self.action_open = QAction('Open JQR', self)
        self.action_quit = QAction('Quit JQR', self)
        self.tray_menu.addAction(self.action_open)
        self.action_open.triggered.connect(self.show_jqr_from_tray)
        self.tray_menu.addAction(self.action_quit)
        self.action_quit.triggered.connect(self.controller.quit_app)
        self.tray_icon.setContextMenu(self.tray_menu)
        self.tray_icon.show()
        self.timer_log_work = QTimer()
        self.timer_log_work.timeout.connect(self.notification_to_log_work)
        self.timer_log_work.start(LOG_TIME)

        self.timer_refresh = QTimer()
        self.timer_refresh.timeout.connect(self.controller.auto_refresh_issue_list)

    def show_jqr_from_tray(self):
        self.hide()
        self.setWindowFlags(self.windowFlags() & ~Qt.WindowStaysOnTopHint)
        self.activateWindow()
        self.show()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Return:
            self.controller.search_issues_by_query()

    def notification_to_log_work(self):
        QSound.play(RING_SOUND_PATH)
        self.tray_icon.showMessage(
            '1 hour had passed',
            'Don\'t forget to log your work!',
            msecs=2000
        )
        self.timer_log_work.start(LOG_TIME)

    def update_issues(self, update_list):
        for issue in update_list:
            item = self.issue_list_widget.findItems(
                issue['key'], Qt.MatchExactly
            )[0]
            item.setText(issue['key'])
            issue_widget = self.issue_list_widget.itemWidget(item)
            issue_widget.set_issue_key(issue['key'], issue['link'])
            issue_widget.set_issue_title(issue['title'])
            issue_widget.set_time(
                issue['estimated'],
                issue['logged'],
                issue['remaining']
            )
            issue_widget.set_workflow.clear()
            issue_widget.set_workflow.addItems(self.controller.get_possible_workflows(issue))
            issue_widget.set_workflow.setCurrentIndex(0)

            issue_widget.set_workflow.activated[str].disconnect()
            issue_widget.set_workflow.activated[str].connect(
                partial(
                    self.controller.change_workflow,
                    issue['workflow'],
                    issue['issue_obj'],
                )
            )

    def delete_issues(self, delete_list):
        for issue in delete_list:
            item = self.issue_list_widget.findItems(
                issue['key'], Qt.MatchExactly
            )[0]
            self.issue_list_widget.takeItem(
                self.issue_list_widget.row(item)
            )

    def insert_issues(self, new_issues_list):
        for issue in new_issues_list:
            issue_widget = QCustomWidget()
            issue_widget.set_issue_key(issue['key'], issue['link'])
            issue_widget.set_issue_title(issue['title'])
            issue_widget.set_time(
                issue['estimated'],
                issue['logged'],
                issue['remaining']
            )

            issue_widget.quick_log_btn.clicked.connect(
                partial(
                    self.controller.log_work_from_list,
                    issue['key']
                )
            )

            issue_widget.log_work_btn.clicked.connect(
                partial(
                    self.controller.open_time_log,
                    issue['key']
                )
            )

            issue_widget.open_pomodoro_btn.clicked.connect(
                partial(
                    self.controller.open_pomodoro_window,
                    issue['key'], issue['title']
                )
            )

            # add workflow statuses to dropdown
            possible_workflows = self.controller.get_possible_workflows(issue)

            issue_widget.set_workflow.addItems(possible_workflows)
            issue_widget.set_workflow.setCurrentIndex(0)
            issue_widget.set_workflow.activated[str].connect(
                partial(
                    self.controller.change_workflow,
                    issue['workflow'],
                    issue['issue_obj'],
                )
            )

            # add issue item to list
            issue_list_widget_item = QListWidgetItem()
            issue_list_widget_item.setText(issue['key'])
            issue_list_widget_item.setSizeHint(issue_widget.sizeHint())
            self.issue_list_widget.insertItem(issue['index'], issue_list_widget_item)
            self.issue_list_widget.setItemWidget(
                issue_list_widget_item, issue_widget
            )
        self.set_size_hint()

    def set_size_hint(self):
        self.issue_list_widget.setMinimumWidth(
            self.issue_list_widget.sizeHintForColumn(0) + 50
        )
        self.issue_list_widget.setMinimumHeight(
            self.issue_list_widget.sizeHintForRow(0) * 2
        )

    def show_filters(self, filters_dict):
        for index, key in enumerate(filters_dict):
            if key == SEARCH_ITEM_NAME:
                self.filters_list.insertItem(0, key)
            else:
                self.filters_list.addItem(key)
                self.filters_list.item(index).setToolTip(key)
        self.filters_list.item(0).setText(self.filters_list.item(0).text().capitalize())

        # add separator after first item
        separator = QFrame()
        separator.setFrameShape(QFrame.HLine)
        separator.setObjectName('separator')
        item_separator = QListWidgetItem()
        item_separator.setFlags(Qt.NoItemFlags)
        self.filters_list.insertItem(1, item_separator)
        self.filters_list.setItemWidget(item_separator, separator)

        self.filters_list.setCurrentItem(
            self.filters_list.findItems(
                MY_ISSUES_ITEM_NAME, Qt.MatchExactly
            )[0])

        self.filters_list.setSizeAdjustPolicy(QAbstractScrollArea.AdjustToContents)
        self.on_filter_selected(self.filters_list.currentItem())

    def filter_field_help(self):
        QDesktopServices.openUrl(self.help_filter_url)

    def on_filter_selected(self, item):
        if not item.text():
            return
        self.current_item = item
        if len(self.current_item.text()) > 50:
            set_text = '{}...'.format(self.current_item.text()[:50])
        else:
            set_text = self.current_item.text()
        self.issue_list_widget.scrollToTop()
        self.controller.search_issues_by_filter_name(item.text())
        self.filter_name_label.setText(set_text)
        self.filter_edited_label.hide()

        if self.filters_list.currentItem().text() == MY_ISSUES_ITEM_NAME:
            self.save_filter_btn.hide()
            self.overwrite_filter_button.hide()
            self.filter_edited_label.hide()
            self.delete_filter_btn.hide()

        elif self.filters_list.currentItem().text() == SEARCH_ITEM_NAME.capitalize():
            # activate save button
            self.overwrite_filter_button.hide()
            self.save_filter_btn.show()
            self.delete_filter_btn.hide()
        else:
            # activate overwrite button
            self.overwrite_filter_button.show()
            self.overwrite_filter_button.setEnabled(False)
            self.save_filter_btn.hide()
            self.delete_filter_btn.show()

    def toggle_frame_filters(self):
        if self.toggle_frame_filters_btn.text() == '<':
            self.toggle_frame_filters_btn.setText('>')
            self.filters_frame.hide()
        else:
            self.toggle_frame_filters_btn.setText('<')
            self.filters_frame.show()

    def add_filter_btn_click(self):
        self.overwrite_filter_button.hide()
        self.save_filter_btn.show()
        self.delete_filter_btn.hide()
        self.filter_edited_label.hide()
        self.filters_list.setCurrentItem(None)
        self.query_field.setText('')
        self.filter_name_label.setText('Add new filter')
        self.controller.current_issues.clear()
        self.show_no_issues()

    def eventFilter(self, obj, event):
        # if user started typing in filter field
        if obj is self.query_field and event.type() == QEvent.KeyRelease:
            if not self.filters_list.currentItem():
                return super().eventFilter(obj, event)
            current_filter_name = self.filters_list.currentItem().text().lower()
            # if current filter is not 'Search issues' or 'my open issues'
            if current_filter_name not in (SEARCH_ITEM_NAME, MY_ISSUES_ITEM_NAME):
                # if query of current filter has not changed
                if self.controller.filters_handler.get_filter_by_name(
                        current_filter_name
                ) != self.query_field.text():
                    # show that filter has been edited
                    self.filter_edited_label.show()
                    self.overwrite_filter_button.setEnabled(True)
                else:
                    self.filter_edited_label.hide()
                    self.overwrite_filter_button.setEnabled(False)
        return super().eventFilter(obj, event)

    def set_current_filter(self, filter_name):
        items = self.filters_list.findItems(
            filter_name, Qt.MatchExactly
        )
        self.filters_list.setCurrentItem(items[0])
        self.on_filter_selected(items[0])

    def add_filter(self, filter_name):
        self.filters_list.addItem(filter_name)
        self.set_current_filter(filter_name)

    def delete_filter(self):
        filter_name = self.filters_list.currentItem().text()
        reply = QMessageBox.question(
            self,
            'Delete filter',
            "Are you sure you want to delete "
            "'{}' filter?".format(filter_name),
            QMessageBox.Yes | QMessageBox.Cancel
        )
        if reply == QMessageBox.Yes:
            self.controller.filters_handler.delete_filter(filter_name)
            self.filters_list.takeItem(
                self.filters_list.currentRow()
            )
            self.filters_list.setCurrentItem(
                self.filters_list.findItems(
                    MY_ISSUES_ITEM_NAME, Qt.MatchExactly
                )[0])
            self.on_filter_selected(self.filters_list.currentItem())

    def show_no_issues(self, error_text=None):
        self.issue_list_widget.clear()
        self.issue_list_widget.hide()
        if error_text:
            self.label_info.setText(error_text)
        self.label_info.show()

    def set_workflow_current_state(self, issue_key):
        item = self.issue_list_widget.findItems(
            issue_key, Qt.MatchExactly
        )[0]
        custom_item = self.issue_list_widget.itemWidget(item)
        custom_item.set_workflow.setCurrentIndex(0)

    def wheelEvent(self, event):
        # top left corner coordinates of the issue list
        list_pos = self.issue_list_widget.pos()
        # check if cursor position is on the issue list
        if event.pos().x() >= list_pos.x() and event.pos().y() >= list_pos.y():
            if event.angleDelta().y() < 0:
                self.controller.refresh_issue_list(True)
                event.accept()

    def closeEvent(self, event):
        event.ignore()
        self.hide()
Пример #7
0
class HeaderEditDialog(QDialog):

    # name of the current preset, whether to set this preset as default, list of Columns
    header_changed = pyqtSignal(str, bool, list)

    def __init__(self, parent, table_header):
        super().__init__(parent)

        self.table_header = table_header
        self.default_preset_name = None
        self.preset_name = table_header.preset_name
        self.columns = copy.deepcopy(table_header.columns)
        self.setupUi()

    def setupUi(self):
        self.resize(200, 400)
        self.vbox = QVBoxLayout(self)
        self.presetLabel = QLabel("Preset: {}".format(self.preset_name), self)
        self.columnList = QListWidget(self)
        self.setAsDefaultCheckbox = QCheckBox("Set as default preset", self)
        self.vbox.addWidget(self.presetLabel)
        self.vbox.addWidget(self.columnList)
        self.vbox.addWidget(self.setAsDefaultCheckbox)

        self.columnList.setDragDropMode(QListWidget.InternalMove)
        self.columnList.setDefaultDropAction(Qt.MoveAction)
        self.columnList.setSelectionMode(QListWidget.ExtendedSelection)
        self.columnList.setAlternatingRowColors(True)
        self.columnList.installEventFilter(self)
        self.columnList.setContextMenuPolicy(Qt.CustomContextMenu)
        self.columnList.customContextMenuRequested.connect(self.open_menu)
        self.columnList.model().rowsMoved.connect(self.read_columns_from_list)

        # for a dumb qss hack to make selected checkboxes not white on a light theme
        self.columnList.setObjectName("ColumnList")

        self.buttonBox = QDialogButtonBox(QDialogButtonBox.Save | QDialogButtonBox.Cancel, self)
        self.vbox.addWidget(self.buttonBox)
        self.buttonBox.accepted.connect(self.accept)
        self.buttonBox.rejected.connect(self.reject)

        self.fill_column_list()
        self.set_default_checkbox()

    def eventFilter(self, object, event):
        if event.type() == QEvent.KeyPress:
            if event.key() == Qt.Key_Space or event.key() == Qt.Key_Return:
                self.toggle_selected_columns()
                return True
        return False

    def fill_column_list(self):
        self.columnList.clear()
        for column in self.columns:
            ColumnListItem(self.columnList, column)

    def accept(self):
        self.read_columns_from_list()
        self.header_changed.emit(self.preset_name,
                                 self.setAsDefaultCheckbox.isChecked(),
                                 self.columns)
        self.done(0)

    def reject(self):
        self.done(0)

    def read_columns_from_list(self):
        new_columns = []
        for i in range(self.columnList.count()):
            item = self.columnList.item(i)
            new_columns.append(item.column)
        self.columns = new_columns

    def toggle_selected_columns(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            value_now = item.data(Qt.CheckStateRole)
            item.setData(Qt.CheckStateRole, not value_now)
        self.columnList.reset()  # @Improvement: is there a better way to update QListWidget?

    def open_menu(self, position):
        menu = QMenu(self)

        preset_menu = menu.addMenu('Presets')
        preset_menu.addAction('New preset', self.new_preset_dialog)
        preset_menu.addSeparator()

        preset_names = CONFIG.get_header_presets()

        if len(preset_names) == 0:
            action = preset_menu.addAction('No presets')
            action.setEnabled(False)
        else:
            delete_menu = menu.addMenu('Delete preset')
            for name in preset_names:
                preset_menu.addAction(name, partial(self.load_preset, name))
                delete_menu.addAction(name, partial(self.delete_preset, name))

        menu.addSeparator()
        menu.addAction('New column...', self.create_new_column_dialog)

        if len(self.columnList.selectedIndexes()) > 0:
            menu.addAction('Delete selected', self.delete_selected)

        menu.popup(self.columnList.viewport().mapToGlobal(position))

    def load_preset(self, name):
        new_columns = CONFIG.load_header_preset(name)
        if not new_columns:
            return

        self.columns = new_columns
        self.preset_name = name
        self.fill_column_list()
        self.presetLabel.setText("Preset: {}".format(name))
        self.set_default_checkbox()

    def new_preset_dialog(self):
        d = QInputDialog(self)
        d.setLabelText('Enter the new name for the new preset:')
        d.setWindowTitle('Create new preset')
        d.textValueSelected.connect(self.create_new_preset)
        d.open()

    def create_new_preset(self, name):
        if name in CONFIG.get_header_presets():
            show_warning_dialog(self, "Preset creation error",
                                'Preset named "{}" already exists.'.format(name))
            return
        if len(name.strip()) == 0:
            show_warning_dialog(self, "Preset creation error",
                                'This preset name is not allowed.'.format(name))
            return

        self.preset_name = name
        self.presetLabel.setText("Preset: {}".format(name))
        CONFIG.save_header_preset(name, self.columns)
        self.setAsDefaultCheckbox.setChecked(False)

    def delete_preset(self, name):
        CONFIG.delete_header_preset(name)
        if name == self.preset_name:
            self.columns = copy.deepcopy(DEFAULT_COLUMNS)
            self.fill_column_list()

    def create_new_column_dialog(self):
        d = CreateNewColumnDialog(self)
        d.add_new_column.connect(self.add_new_column)
        d.setWindowTitle('Create new column')
        d.open()

    def add_new_column(self, name, title):
        new_column = Column(name, title)
        # if the last column is message, insert this column before it (i think it makes sense?)
        if self.columns[-1].name == 'message':
            self.columns.insert(-1, new_column)
        else:
            self.columns.append(new_column)
        self.fill_column_list()

    def set_default_checkbox(self):
        self.setAsDefaultCheckbox.setChecked(CONFIG['default_header_preset'] == self.preset_name)

    def delete_selected(self):
        selected = self.columnList.selectedItems()
        for item in selected:
            self.columnList.takeItem(self.columnList.row(item))
        self.read_columns_from_list()
        self.fill_column_list()
Пример #8
0
class Example(QWidget):
    def __init__(self):
        super().__init__()

        self.filenames = json_files()

        if type(self.filenames) is list:
            self.curr_file = self.filenames[0]
        else:
            self.curr_file = self.filenames

        self.initUI()

    def initUI(self):

        self.num = -1  # index for search bar query
        self.show_save = False  # bool for showing unsaved changes dialog
        self.temp_file = ".temp.csv"
        self.refresh_file = False  # failsafe 1 for itemChanged trigger

        self.list_1 = QListWidget()

        lister(file=self.curr_file, target=self.list_1, index=0, mode=0)
        self.list_1.clicked.connect(self.clear_selection)
        self.list_1.installEventFilter(self)

        self.list_items = self.list_1.count(
        )  # failsafe 2 for itemChanged trigger
        self.list_1.itemChanged.connect(self.edit_next_item)
        self.list_1.verticalScrollBar().valueChanged.connect(self.sync_scroll)

        self.list_2 = QListWidget()
        lister(file=self.curr_file, target=self.list_2, index=1, mode=0)
        self.list_2.clicked.connect(self.clear_selection)

        self.list_3 = QListWidget()
        lister(file=self.curr_file, target=self.list_3, index=2, mode=0)
        self.list_3.clicked.connect(self.clear_selection)

        self.all_lists = [self.list_1, self.list_2, self.list_3]

        self.menubar = QMenuBar()
        self.menubar.setNativeMenuBar(False)

        exit_event = QAction('Exit', self)
        exit_event.setShortcut('Ctrl+W')
        exit_event.triggered.connect(app.quit)

        showAct = QAction('Show extras', self, checkable=True)
        showAct.setChecked(False)
        showAct.setShortcut('Ctrl+E')
        showAct.triggered.connect(self.hide_notes)

        addAct = QAction('Fields', self)
        addAct.setShortcut('Ctrl+N')
        addAct.triggered.connect(self.add_item)

        fileOpen = QAction('Open file', self)
        fileOpen.triggered.connect(self.fileDialog)
        fileOpen.setShortcut('Ctrl+O')

        fileSave = QAction('Save file', self)
        fileSave.triggered.connect(self.save)
        fileSave.triggered.connect(self.refresh_recents)
        fileSave.setShortcut('Ctrl+S')

        self.fileRecents = QMenu('Recent file', self)
        self.refresh_recents()

        self.toggle_theme = QAction('Toggle theme', self, checkable=True)
        self.toggle_theme.setChecked(json_theme())
        self.toggle_theme.triggered.connect(self.theme)
        self.toggle_theme.setShortcut('Ctrl+T')

        self.col_sort_index = QMenu('Sorting column index', self)
        self.col_sort_index.addAction(QAction(str(0), self))
        self.col_sort_index.addAction(QAction(str(1), self))
        self.col_sort_index.addAction(QAction(str(2), self))
        self.col_sort_index.triggered.connect(self.sort_col_choice)

        self.col_search_index = QMenu('Searching column index', self)
        self.col_search_index.addAction(QAction(str(0), self))
        self.col_search_index.addAction(QAction(str(1), self))
        self.col_search_index.addAction(QAction(str(2), self))
        self.col_search_index.triggered.connect(self.search_col_choice)

        self.sort = QAction('Sort entries', self, checkable=True)
        self.curr_col = 0
        self.search_col = 0
        self.sort.triggered.connect(self.refresh_list)
        self.sort.setShortcut('Ctrl+R')

        self.addFields = self.menubar.addMenu('Add')
        self.addFields.addAction(addAct)

        self.optionMenu = self.menubar.addMenu('Options')
        self.optionMenu.addAction(exit_event)
        self.optionMenu.addAction(showAct)
        self.optionMenu.addAction(self.toggle_theme)
        self.optionMenu.addMenu(self.col_sort_index)
        self.optionMenu.addMenu(self.col_search_index)
        self.optionMenu.addAction(self.sort)

        self.fileMenu = self.menubar.addMenu('File')
        self.fileMenu.addAction(fileOpen)
        self.fileMenu.addAction(fileSave)
        self.fileMenu.addMenu(self.fileRecents)

        self.search_bar = QLineEdit()
        self.search_bar.setPlaceholderText('Search vocab')
        self.search_bar.setClearButtonEnabled(True)
        self.search_bar.setMaxLength(10)
        self.search_bar.returnPressed.connect(self.search_item)

        self.status_bar = QStatusBar()
        status(self.status_bar, self.list_1)

        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(self.menubar, 0, 0)
        grid.addWidget(self.list_1, 1, 0)
        grid.addWidget(self.list_2, 1, 1)
        grid.addWidget(self.list_3, 1, 2)
        grid.addWidget(self.search_bar, 0, 1)
        grid.addWidget(self.status_bar)

        self.theme()
        self.setLayout(grid)
        self.setGeometry(*json_window_size())
        self.setWindowTitle(f'{split_name(self.curr_file)}')
        self.show()

        self.list_1.scrollToBottom()
        self.list_2.verticalScrollBar().setHidden(True)
        self.list_3.verticalScrollBar().setHidden(True)
        self.list_3.setHidden(True)

    def sync_scroll(self):

        scroll_location = self.list_1.verticalScrollBar().value()

        self.list_2.verticalScrollBar().setValue(scroll_location)
        self.list_3.verticalScrollBar().setValue(scroll_location)

    def edit_next_item(self, event):
        """When an item is added and edited on the first col, starts editing its counterpart on the next col"""

        if self.list_items == self.list_1.count(
        ) - 2 or self.list_items != self.list_1.count(
        ) and self.refresh_file == False:

            item = self.list_2.item(self.list_2.count() - 1)
            self.list_2.editItem(item)

            self.list_items = self.list_1.count()

    def closeEvent(self, event):
        """Triggered upon program exit, shows a dialog for unsaved changes using a bool"""

        if self.show_save == True:

            reply = QMessageBox.question(
                self, 'Message',
                "You may have unsaved changes, are you sure you want to quit?",
                QMessageBox.Yes | QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:
                try:
                    remove(self.temp_file)
                except:
                    pass

                event.accept()
            else:
                event.ignore()

        else:
            pass

    def sort_col_choice(self, action):
        self.curr_col = int(action.text())

    def search_col_choice(self, action):
        self.search_col = int(action.text())

    def refresh_list(self):
        """Refreshes the contents of the lists, when sorting is used"""

        self.save(
            mode=1
        )  # saves a temp copy, with changes, but irreversable sorting introduced

        clear_lists(self.all_lists)

        if self.sort.isChecked() == True:
            mode = 2
        else:
            mode = 0

        try:
            lister(file=self.temp_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.temp_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

        except:
            lister(file=self.curr_file,
                   target=self.list_1,
                   index=0,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_2,
                   index=1,
                   mode=mode,
                   column=self.curr_col)
            lister(file=self.curr_file,
                   target=self.list_3,
                   index=2,
                   mode=mode,
                   column=self.curr_col)

    def refresh_recents(self):

        try:

            file_1 = QAction(self.curr_file, self)
            self.fileRecents.addAction(file_1)
            file_1.triggered.connect(self.clickedFileAct)

            if type(self.filenames) is list:

                if self.filenames[1] != None:
                    file_2 = QAction(self.filenames[1], self)
                    self.fileRecents.addAction(file_2)
                    file_2.triggered.connect(self.clickedFileAct)

                if self.filenames[2] != None:
                    file_3 = QAction(self.filenames[2], self)
                    self.fileRecents.addAction(file_3)
                    file_3.triggered.connect(self.clickedFileAct)

        except:
            pass

    def clickedFileAct(self):

        self.refresh_file = True

        file = self.sender().text()
        self.curr_file = file
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

        self.list_1.scrollToBottom()
        self.list_3.setHidden(True)

        self.refresh_file = False

    def eventFilter(self, source, event):
        """Item (row) deletion"""

        if (event.type() == QEvent.ContextMenu and source is self.list_1):
            menu = QMenu()
            menu.addAction("Delete row")
            if menu.exec_(event.globalPos()):
                item = source.itemAt(event.pos())
                try:
                    model = self.list_1.indexFromItem(item)
                    row = model.row()

                    self.show_save = True

                    self.list_1.takeItem(row)
                    self.list_2.takeItem(row)
                    self.list_3.takeItem(row)

                    status(self.status_bar, self.list_1,
                           f'Deleted row number: {row+1}.')
                    self.clearSelection()

                except:
                    pass

            return True
        return super(Example, self).eventFilter(source, event)

    def hide_notes(self):
        """Toggles showing the note column and stretches the window for clearer reading of it"""

        self.list_3.setHidden(not self.list_3.isHidden())

    def theme(self):
        """Sets the theme for the window and its widgets"""

        palette = QPalette()

        # dark theme
        if self.toggle_theme.isChecked() == True:

            palette.setColor(QPalette.Window, QColor(0, 0, 0))
            dark = "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255);"

            self.menubar.setStyleSheet(dark)
            self.addFields.setStyleSheet(dark)
            self.optionMenu.setStyleSheet(dark)
            self.fileMenu.setStyleSheet(dark)
            self.search_bar.setStyleSheet(
                "background-color: rgb(0, 0, 0); color: rgb(255, 255, 255)"
            )  # border: 0px; for transparency
            self.status_bar.setStyleSheet(dark)

            style_items(self.all_lists, dark_theme=True)

        # light theme
        elif self.toggle_theme.isChecked() == False:

            palette.setColor(QPalette.Window, QColor(255, 255, 255))
            light = "background-color: rgb(255, 255, 255); color: rgb(0, 0, 0)"

            self.menubar.setStyleSheet(light)
            self.addFields.setStyleSheet(light)
            self.optionMenu.setStyleSheet(light)
            self.fileMenu.setStyleSheet(light)
            self.search_bar.setStyleSheet(light)
            self.status_bar.setStyleSheet(light)

            style_items(self.all_lists, dark_theme=False)

        self.setPalette(palette)

        self.theme_bool = self.toggle_theme.isChecked(
        )  # used in the save func

    def search_item(self):
        """Takes input from the search bar and matches with an item, 
		gets index and scrolls to it, more reusults being qued with the num class var
		"""

        query = self.search_bar.text()
        search = self.all_lists[self.search_col].findItems(
            query, Qt.MatchContains)
        status(self.status_bar, self.list_1, f'Found {len(search)} results.')
        self.clear_selection()

        # testing search in all column

        # search_list =[]
        # for x in range(3):
        # 	search_list.append(self.all_lists[x].findItems(query, Qt.MatchContains))

        # parent_list = []
        # for x in range(3):
        # 	for y in range(len(search_list[x])):
        # 		parent_list.append(self.all_lists[x]) # replace with x

        # import itertools
        # merged = list(itertools.chain.from_iterable(search_list))

        # search_dict = dict(zip(parent_list, merged))
        # print(search_dict)
        # print()
        # print(len(merged))
        # print(len(parent_list))

        self.num += 1
        for i in search:

            try:
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            except:
                self.num = 0
                model_index = self.all_lists[self.search_col].indexFromItem(
                    search[self.num])

            item_index = model_index.row()

            self.all_lists[self.search_col].item(item_index).setSelected(True)
            self.list_1.scrollToItem(self.list_1.item(item_index),
                                     QAbstractItemView.PositionAtCenter)

    def add_item(self):

        self.show_save = True

        for x in range(3):
            if x == 0:
                lister(file=self.curr_file,
                       target=self.list_1,
                       index=x,
                       mode=1)

            elif x == 1:
                lister(file=self.curr_file,
                       target=self.list_2,
                       index=x,
                       mode=1)

            elif x == 2:
                lister(file=self.curr_file,
                       target=self.list_3,
                       index=x,
                       mode=1)

        item = self.list_1.item(self.list_1.count() - 1)
        self.list_1.editItem(item)
        status(self.status_bar, self.list_1)

        self.list_1.scrollToBottom()
        self.list_2.scrollToBottom()
        self.list_3.scrollToBottom()

    def clear_selection(self):
        """Clears all item slections for aesthetical purposes, but only single clicks"""

        self.list_1.clearSelection()
        self.list_2.clearSelection()
        self.list_3.clearSelection()

    def fileDialog(self):

        fname = QFileDialog()
        path = fname.getOpenFileName(self,
                                     'Open file',
                                     getcwd(),
                                     filter='csv (*.csv);;')
        if path[0] == '':  # failsafe for canceling the dialog
            return self.curr_file

        self.curr_file = path[0]
        self.setWindowTitle(f'{split_name(self.curr_file)}')

        clear_lists(self.all_lists)

        lister(file=self.curr_file, target=self.list_1, index=0)
        lister(file=self.curr_file, target=self.list_2, index=1)
        lister(file=self.curr_file, target=self.list_3, index=2)

        status(self.status_bar, self.list_1)
        self.theme()

    def save(self, mode=0):

        self.show_save = False

        list1_items = items_text(self.list_1)
        list2_items = items_text(self.list_2)
        list3_items = items_text(self.list_3)

        total_dicts = []
        for (a, b, c) in zip(list1_items, list2_items,
                             list3_items):  # each letter is a column
            dictionary = {'word_1': a, 'word_2': b, 'notes': c}
            total_dicts.append(dictionary)

        if mode == 0:

            writer(file=self.curr_file, data=total_dicts)
            status(self.status_bar, self.list_1, ('Saved current changes.'))

            try:
                json_template(theme=self.theme_bool,
                              files=[self.curr_file, None, None],
                              window_size=self.geometry().getRect()
                              )  # current size values of the window

            except:
                json_template(
                )  # bug cannot be avoided, even though used setChecked at the beggining

        elif mode == 1:

            self.show_save = True
            writer(file=self.temp_file, data=total_dicts)

        # avoids stacking and refreshes recent file actions
        actions = self.fileRecents.actions()
        for action in actions:
            self.fileRecents.removeAction(action)
Пример #9
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=parent)
        self.threadpool = QThreadPool()
        self.initUI()

        self.initList()
        self.initSearchTab()

    def initUI(self):

        self.tabWidget = QTabWidget(self)
        self.searchEngine = SearchEngine()
        self.setGeometry(0, 0, 495, 635)
        self.center()
        self.setCentralWidget(self.tabWidget)
        self.status = self.statusBar()
        self.mainMenu = self.menuBar()

        exitAct = QAction('&Exit', self)        
        exitAct.setShortcut('Ctrl+Q')
        exitAct.setStatusTip('Exit application')
        exitAct.triggered.connect(qApp.quit)

        exportList = QAction('Export &List',self)
        exportList.setShortcut('Ctrl+L')
        exportList.setStatusTip('Export your manga list(backup)')

        reloadList = QAction('Reload list',self)
        reloadList.setShortcut('Ctrl+R')
        reloadList.triggered.connect(self.loadManga)


        fileMenu = self.mainMenu.addMenu('&File')
        fileMenu.addAction(exportList)
        fileMenu.addAction(reloadList)
        fileMenu.addAction(exitAct)
    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.ContextMenu  and
            source is self.searchResults):
            menu = QMenu()

            infoAction = QAction('Info',self)
            infoAction.setStatusTip('Show information about this manga title')
            infoAction.triggered.connect(self.showMangaInfo)

            addMangaAction = QAction('Add to list',self)
         
            addMangaAction.triggered.connect(self.addToList)
      
            
            menu.addAction(infoAction)
            menu.addAction(addMangaAction)
            menu.exec_(event.globalPos())
            return True
        return super(QMainWindow, self).eventFilter(source, event)

    def center(self):
        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.topLeft())
    
        
    def loadManga(self):
        self.mainLayout.clearList()

        jsonObject = json.loads(open('mangalist.json').read())

        for manga in jsonObject['Manga']:
            manga = Series(self,manga['imagePath'],manga['title'])
            self.mainLayout.addWidget(manga)
        

    def initSearchTab(self):
        box = QVBoxLayout(self.tabWidget)

        widget = QWidget(self.tabWidget)

        self.inputLine = QLineEdit(widget)
        self.inputLine.returnPressed.connect(self.searchRequest)

        self.inputLine.setPlaceholderText("Search for a manga title")
        self.inputLine.setClearButtonEnabled(True)

        self.searchResults = QListWidget(widget)
        self.searchResults.setFont(QtGui.QFont('sans-serif', 10, 650))
        self.searchResults.installEventFilter(self)
        

        box.addWidget(self.inputLine)
        box.addWidget(self.searchResults)

        widget.setLayout(box)

        self.tabWidget.addTab(widget, "Search")
    
    def executeThread(self):
        self.worker = Worker(self.addToList)
        self.worker.signals.finished.connect(self.threadFinished)
        self.threadpool.start(self.worker)
    def threadFinished(self):
        
        self.loadManga()
    def addToList(self):
        url = self.searchResults.currentItem().data(QtCore.Qt.UserRole)
        self.statusBar().showMessage("Adding Manga to list.")
        driver = webdriver.PhantomJS()
        driver.get(url)
        
        soup = bs4.BeautifulSoup(driver.page_source,'lxml')

    

        title = soup.select('.tabletitle')     
        imageUrl = soup.select('.img-fluid')
        
        image  = open('images/'+title[0].text,'wb')
        image.write(requests.get(imageUrl[2]['src']).content)
        print(imageUrl[2])
        image.close()
        imagePath = 'images/'+title[0].text
        
        description = driver.find_element_by_class_name('sContent')
        
        item = {"title": "#","description":"#","imagePath":"#"}
        item["title"] =title[0].text
        item["description"]=description.text
        item["imagePath"]=imagePath

        config = json.loads(open('mangalist.json').read())

        config["Manga"].append(item)

        with open('mangalist.json','w') as f:
            f.write(json.dumps(config,indent=4))
            f.close()
    
        self.statusBar().showMessage("Manga added.",0.5)
        self.loadManga()

    def showMangaInfo(self):
        
        print(self.searchResults.currentItem().text())

    def searchRequest(self):
        resultList = self.searchEngine.search(self.inputLine.text())

        self.inputLine.clear()
        self.searchResults.clear()

        for result in resultList:
            item = QListWidgetItem(result['title'])
            item.setData(QtCore.Qt.UserRole,result['url'])

            self.searchResults.addItem(item)

    def initList(self):
        self.mainArea = QScrollArea(self)
        self.mainArea.setWidgetResizable(True)
        mangaWidget = QWidget(self.mainArea)
        self.mainLayout = FlowLayout(mangaWidget)
        self.loadManga()
        self.mainArea.setWidget(mangaWidget)
        self.tabWidget.addTab(self.mainArea, "MangaList")