Beispiel #1
0
class TeamChooserWidget(QWidget):
    def __init__(self, parent, on_next, league=None):
        super().__init__(parent)
        self.layout = QVBoxLayout()
        self.list_view = QListView()
        self.league = league
        self.model = TeamListModel(league)
        self.list_view.setModel(self.model)
        self.list_view.setSelectionMode(QAbstractItemView.MultiSelection)
        self.list_view.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.list_view.customContextMenuRequested.connect(self.list_context_menu)
        self.layout.addWidget(self.list_view)
        self.team_add = AddItemWidget(self, "New Team Name: ", self.add_team, unavailable_options=self.model.all_team_names)
        self.layout.addWidget(self.team_add)

        self.button_h_layout = QHBoxLayout()
        self.button_cancel = QPushButton("Cancel")
        self.button_cancel.clicked.connect(self.on_cancel)
        self.button_next = QPushButton("Next")
        self.button_next.clicked.connect(on_next)
        self.button_h_layout.addWidget(self.button_cancel)
        self.button_h_layout.addWidget(self.button_next)
        self.layout.addLayout(self.button_h_layout)
        self.setLayout(self.layout)
        self.new_teams = []

    def add_team(self, name):
        self.new_teams.append(name)
        team = Team.create(name=name)
        self.model.add_team(team)

    def list_context_menu(self, pos):
        self.listMenu = QMenu()
        current_index = self.list_view.currentIndex()
        select = self.listMenu.addAction("Select")
        select.triggered.connect(
            lambda: self.list_view.selectionModel().select(current_index, QtCore.QItemSelectionModel.Select)
        )

        deselect = self.listMenu.addAction("Deselect")
        deselect.triggered.connect(
            lambda: self.list_view.selectionModel().select(current_index, QtCore.QItemSelectionModel.Deselect)
        )
        delete = self.listMenu.addAction("Delete")
        delete.setDisabled(current_index.data() not in self.new_teams)
        delete.triggered.connect(lambda: self.model.delete_team(current_index.row()))

        parentPosition = self.list_view.mapToGlobal(QtCore.QPoint(0, 0))
        self.listMenu.move(parentPosition + pos)
        self.listMenu.show()

    def on_cancel(self):
        self.model.delete_added_teams()
        self.window().close()

    def get_selected_teams(self):
        teams = []
        for i in self.list_view.selectedIndexes():
            teams.append(self.model.get_team(i.row()))
        return teams
Beispiel #2
0
class NameList(QDockWidget):
    def __init__(self, window):
        super(NameList, self).__init__('Current Plots')
        self.namelist_model = QStandardItemModel()
        self.namelist_view = QListView()
        self.namelist_view.setModel(self.namelist_model)
        self.setWidget(self.namelist_view)
        self.window = window
        self.plot_dict = {}

        self.namelist_view.doubleClicked.connect(self.activate_item)
        self.namelist_view.setContextMenuPolicy(QtConst.ActionsContextMenu)
        delete_action = QAction("Delete Selected", self.namelist_view)
        ###
        pause_action = QAction("Stop Script", self.namelist_view)
        delete_action.triggered.connect(self.delete_item)
        pause_action.triggered.connect(self.pause)
        self.namelist_view.addAction(delete_action)
        ###
        self.namelist_view.addAction(pause_action)

    def activate_item(self, index):
        item = self.namelist_model.itemFromIndex(index)
        plot = self.plot_dict[str(item.text())]
        if plot.closed:
            plot.closed = False
            self.window.add_plot(plot)

    def delete_item(self):
        index = self.namelist_view.currentIndex()
        item = self.namelist_model.itemFromIndex(index)
        del self[str(item.text())]

    def pause(self):
        sock = socket.socket()
        sock.connect(('localhost', 9091))
        sock.send(b'stop')
        sock.close()

    def __getitem__(self, item):
        return self.plot_dict[item]

    def __setitem__(self, name, plot):
        model = QStandardItem(name)
        model.setEditable(False)
        self.namelist_model.appendRow(model)
        self.plot_dict[name] = plot

    def __contains__(self, value):
        return value in self.plot_dict

    def __delitem__(self, name):
        self.namelist_model.removeRow(self.namelist_model.findItems(name)[0].index().row())
        self.plot_dict[name].close()
        del self.plot_dict[name]

    def keys(self):
        return list(self.plot_dict.keys());
Beispiel #3
0
class AbstractSubItemListView(QFrame):
    """
    THIS IS AN ABSTRACT CLASS, DO NOT INSTANTIATE
    """

    def __init__(self, parent: QObject, image_cache: ImageCache):
        super().__init__(parent)

        self._image_cache = image_cache
        self._model = AbstractItemListModel(self, image_cache, True)

        self._item_delegate = ItemDelegate(self)

        self._list_view = QListView(self)
        self._list_view.setItemDelegate(self._item_delegate)
        self._list_view.setContextMenuPolicy(Qt.CustomContextMenu)

        self._layout_manager = QVBoxLayout(self)
        self._layout_ui()

        # Connect signals to slots
        self._list_view.customContextMenuRequested.connect(self._show_context_menu)

    def _layout_ui(self):
        self._list_view.setSpacing(22)
        self._layout_manager.addWidget(self._list_view)

    def model(self) -> AbstractItemListModel:
        return self._model

    def _add_item_to_playlist(self, index: QModelIndex):
        """
        Given an index in the list, allows the user to add the selected item to a playlist of their choice
        """
        selected_item = self._list_view.model().at(index.row())
        add_dialog = AddToPlaylistDialog(self, selected_item)

        if add_dialog.exec() == QDialog.Accepted:
            # Insertion playlist has been accepted
            selected_playlist_id: int = add_dialog.get_selection()

            if type(selected_item) is Episode:
                add_episode_to_playlist(cursor, connection, selected_item.media_id, selected_item.episode_number,
                                        selected_item.name, selected_playlist_id)
            elif type(selected_item) is Song:
                add_song_to_playlist(cursor, connection, selected_item.media_id, selected_item.name,
                                     selected_playlist_id)
            elif type(selected_item) is ComedySpecial:
                add_comedy_special_to_playlist(cursor, connection, selected_item.media_id, selected_playlist_id)
            else:
                print("Attempting to add unexpected type to playlist")
                exit(1)

    @QtCore.pyqtSlot(QPoint)
    def _show_context_menu(self, pos: QPoint):
        """
        Displays a context menu of user choices on a right-click

        :param pos: Location where user clicked on the screen
        """

        index = self._list_view.indexAt(pos)

        if index.row() != -1:  # Must be a valid index
            global_pos = self._list_view.mapToGlobal(pos)

            context_menu = QMenu(self)

            # User should have the ability to add to playlist
            add_action = QAction("Add to playlist")
            add_action.triggered.connect(lambda: self._add_item_to_playlist(index))

            context_menu.addAction(add_action)

            context_menu.exec(global_pos)
            del context_menu
class comics_project_manager_docker(DockWidget):
    setupDictionary = {}
    stringName = i18n("Comics Manager")
    projecturl = None

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

        # Setup layout:
        base = QHBoxLayout()
        widget = QWidget()
        widget.setLayout(base)
        baseLayout = QSplitter()
        base.addWidget(baseLayout)
        self.setWidget(widget)
        buttonLayout = QVBoxLayout()
        buttonBox = QWidget()
        buttonBox.setLayout(buttonLayout)
        baseLayout.addWidget(buttonBox)

        # Comic page list and pages model
        self.comicPageList = QListView()
        self.comicPageList.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.comicPageList.setDragEnabled(True)
        self.comicPageList.setDragDropMode(QAbstractItemView.InternalMove)
        self.comicPageList.setDefaultDropAction(Qt.MoveAction)
        self.comicPageList.setAcceptDrops(True)
        self.comicPageList.setItemDelegate(comic_page_delegate())
        self.pagesModel = QStandardItemModel()
        self.comicPageList.doubleClicked.connect(self.slot_open_page)
        self.comicPageList.setIconSize(QSize(128, 128))
        # self.comicPageList.itemDelegate().closeEditor.connect(self.slot_write_description)
        self.pagesModel.layoutChanged.connect(self.slot_write_config)
        self.pagesModel.rowsInserted.connect(self.slot_write_config)
        self.pagesModel.rowsRemoved.connect(self.slot_write_config)
        self.pagesModel.rowsMoved.connect(self.slot_write_config)
        self.comicPageList.setModel(self.pagesModel)
        pageBox = QWidget()
        pageBox.setLayout(QVBoxLayout())
        zoomSlider = QSlider(Qt.Horizontal, None)
        zoomSlider.setRange(1, 8)
        zoomSlider.setValue(4)
        zoomSlider.setTickInterval(1)
        zoomSlider.setMinimumWidth(10)
        zoomSlider.valueChanged.connect(self.slot_scale_thumbnails)
        self.projectName = Elided_Text_Label()
        pageBox.layout().addWidget(self.projectName)
        pageBox.layout().addWidget(zoomSlider)
        pageBox.layout().addWidget(self.comicPageList)
        baseLayout.addWidget(pageBox)

        self.btn_project = QToolButton()
        self.btn_project.setPopupMode(QToolButton.MenuButtonPopup)
        self.btn_project.setSizePolicy(QSizePolicy.Minimum,
                                       QSizePolicy.Minimum)
        menu_project = QMenu()
        self.action_new_project = QAction(i18n("New Project"), self)
        self.action_new_project.triggered.connect(self.slot_new_project)
        self.action_load_project = QAction(i18n("Open Project"), self)
        self.action_load_project.triggered.connect(self.slot_open_config)
        menu_project.addAction(self.action_new_project)
        menu_project.addAction(self.action_load_project)
        self.btn_project.setMenu(menu_project)
        self.btn_project.setDefaultAction(self.action_load_project)
        buttonLayout.addWidget(self.btn_project)

        # Settings dropdown with actions for the different settings menus.
        self.btn_settings = QToolButton()
        self.btn_settings.setPopupMode(QToolButton.MenuButtonPopup)
        self.btn_settings.setSizePolicy(QSizePolicy.Minimum,
                                        QSizePolicy.Minimum)
        self.action_edit_project_settings = QAction(i18n("Project Settings"),
                                                    self)
        self.action_edit_project_settings.triggered.connect(
            self.slot_edit_project_settings)
        self.action_edit_meta_data = QAction(i18n("Meta Data"), self)
        self.action_edit_meta_data.triggered.connect(self.slot_edit_meta_data)
        self.action_edit_export_settings = QAction(i18n("Export Settings"),
                                                   self)
        self.action_edit_export_settings.triggered.connect(
            self.slot_edit_export_settings)
        menu_settings = QMenu()
        menu_settings.addAction(self.action_edit_project_settings)
        menu_settings.addAction(self.action_edit_meta_data)
        menu_settings.addAction(self.action_edit_export_settings)
        self.btn_settings.setDefaultAction(self.action_edit_project_settings)
        self.btn_settings.setMenu(menu_settings)
        buttonLayout.addWidget(self.btn_settings)
        self.btn_settings.setDisabled(True)

        # Add page drop down with different page actions.
        self.btn_add_page = QToolButton()
        self.btn_add_page.setPopupMode(QToolButton.MenuButtonPopup)
        self.btn_add_page.setSizePolicy(QSizePolicy.Minimum,
                                        QSizePolicy.Minimum)

        self.action_add_page = QAction(i18n("Add Page"), self)
        self.action_add_page.triggered.connect(self.slot_add_new_page_single)
        self.action_add_template = QAction(i18n("Add Page from Template"),
                                           self)
        self.action_add_template.triggered.connect(
            self.slot_add_new_page_from_template)
        self.action_add_existing = QAction(i18n("Add Existing Pages"), self)
        self.action_add_existing.triggered.connect(self.slot_add_page_from_url)
        self.action_remove_selected_page = QAction(i18n("Remove Page"), self)
        self.action_remove_selected_page.triggered.connect(
            self.slot_remove_selected_page)
        self.action_resize_all_pages = QAction(i18n("Batch Resize"), self)
        self.action_resize_all_pages.triggered.connect(self.slot_batch_resize)
        self.btn_add_page.setDefaultAction(self.action_add_page)
        self.action_show_page_viewer = QAction(i18n("View Page In Window"),
                                               self)
        self.action_show_page_viewer.triggered.connect(
            self.slot_show_page_viewer)
        self.action_scrape_authors = QAction(i18n("Scrape Author Info"), self)
        self.action_scrape_authors.setToolTip(
            i18n(
                "Search for author information in documents and add it to the author list. This does not check for duplicates."
            ))
        self.action_scrape_authors.triggered.connect(
            self.slot_scrape_author_list)
        self.action_scrape_translations = QAction(
            i18n("Scrape Text for Translation"), self)
        self.action_scrape_translations.triggered.connect(
            self.slot_scrape_translations)
        actionList = []
        menu_page = QMenu()
        actionList.append(self.action_add_page)
        actionList.append(self.action_add_template)
        actionList.append(self.action_add_existing)
        actionList.append(self.action_remove_selected_page)
        actionList.append(self.action_resize_all_pages)
        actionList.append(self.action_show_page_viewer)
        actionList.append(self.action_scrape_authors)
        actionList.append(self.action_scrape_translations)
        menu_page.addActions(actionList)
        self.btn_add_page.setMenu(menu_page)
        buttonLayout.addWidget(self.btn_add_page)
        self.btn_add_page.setDisabled(True)

        self.comicPageList.setContextMenuPolicy(Qt.ActionsContextMenu)
        self.comicPageList.addActions(actionList)

        # Export button that... exports.
        self.btn_export = QPushButton(i18n("Export Comic"))
        self.btn_export.clicked.connect(self.slot_export)
        buttonLayout.addWidget(self.btn_export)
        self.btn_export.setDisabled(True)

        self.btn_project_url = QPushButton(i18n("Copy Location"))
        self.btn_project_url.setToolTip(
            i18n(
                "Copies the path of the project to the clipboard. Useful for quickly copying to a file manager or the like."
            ))
        self.btn_project_url.clicked.connect(self.slot_copy_project_url)
        self.btn_project_url.setDisabled(True)
        buttonLayout.addWidget(self.btn_project_url)

        self.page_viewer_dialog = comics_project_page_viewer.comics_project_page_viewer(
        )

        Application.notifier().imageSaved.connect(
            self.slot_check_for_page_update)

        buttonLayout.addItem(
            QSpacerItem(0, 0, QSizePolicy.Minimum,
                        QSizePolicy.MinimumExpanding))

    """
    Open the config file and load the json file into a dictionary.
    """

    def slot_open_config(self):
        self.path_to_config = QFileDialog.getOpenFileName(
            caption=i18n("Please select the JSON comic config file."),
            filter=str(i18n("JSON files") + "(*.json)"))[0]
        if os.path.exists(self.path_to_config) is True:
            configFile = open(self.path_to_config,
                              "r",
                              newline="",
                              encoding="utf-16")
            self.setupDictionary = json.load(configFile)
            self.projecturl = os.path.dirname(str(self.path_to_config))
            configFile.close()
            self.load_config()

    """
    Further config loading.
    """

    def load_config(self):
        self.projectName.setMainText(
            text=str(self.setupDictionary["projectName"]))
        self.fill_pages()
        self.btn_settings.setEnabled(True)
        self.btn_add_page.setEnabled(True)
        self.btn_export.setEnabled(True)
        self.btn_project_url.setEnabled(True)

    """
    Fill the pages model with the pages from the pages list.
    """

    def fill_pages(self):
        self.loadingPages = True
        self.pagesModel.clear()
        pagesList = []
        if "pages" in self.setupDictionary.keys():
            pagesList = self.setupDictionary["pages"]
        progress = QProgressDialog()
        progress.setMinimum(0)
        progress.setMaximum(len(pagesList))
        progress.setWindowTitle(i18n("Loading Pages..."))
        for url in pagesList:
            absurl = os.path.join(self.projecturl, url)
            if (os.path.exists(absurl)):
                #page = Application.openDocument(absurl)
                page = zipfile.ZipFile(absurl, "r")
                thumbnail = QImage.fromData(page.read("preview.png"))
                pageItem = QStandardItem()
                dataList = self.get_description_and_title(
                    page.read("documentinfo.xml"))
                if (dataList[0].isspace() or len(dataList[0]) < 1):
                    dataList[0] = os.path.basename(url)
                pageItem.setText(dataList[0].replace("_", " "))
                pageItem.setDragEnabled(True)
                pageItem.setDropEnabled(False)
                pageItem.setEditable(False)
                pageItem.setIcon(QIcon(QPixmap.fromImage(thumbnail)))
                pageItem.setData(dataList[1], role=CPE.DESCRIPTION)
                pageItem.setData(url, role=CPE.URL)
                pageItem.setData(dataList[2], role=CPE.KEYWORDS)
                pageItem.setData(dataList[3], role=CPE.LASTEDIT)
                pageItem.setData(dataList[4], role=CPE.EDITOR)
                pageItem.setToolTip(url)
                page.close()
                self.pagesModel.appendRow(pageItem)
                progress.setValue(progress.value() + 1)
        progress.setValue(len(pagesList))
        self.loadingPages = False

    """
    Function that is triggered by the zoomSlider
    Resizes the thumbnails.
    """

    def slot_scale_thumbnails(self, multiplier=4):
        self.comicPageList.setIconSize(QSize(multiplier * 32, multiplier * 32))

    """
    Function that takes the documentinfo.xml and parses it for the title, subject and abstract tags,
    to get the title and description.
    
    @returns a stringlist with the name on 0 and the description on 1.
    """

    def get_description_and_title(self, string):
        xmlDoc = ET.fromstring(string)
        calligra = str("{http://www.calligra.org/DTD/document-info}")
        name = ""
        if ET.iselement(xmlDoc[0].find(calligra + 'title')):
            name = xmlDoc[0].find(calligra + 'title').text
            if name is None:
                name = " "
        desc = ""
        if ET.iselement(xmlDoc[0].find(calligra + 'subject')):
            desc = xmlDoc[0].find(calligra + 'subject').text
        if desc is None or desc.isspace() or len(desc) < 1:
            if ET.iselement(xmlDoc[0].find(calligra + 'abstract')):
                desc = xmlDoc[0].find(calligra + 'abstract').text
                if desc is not None:
                    if desc.startswith("<![CDATA["):
                        desc = desc[len("<![CDATA["):]
                    if desc.startswith("]]>"):
                        desc = desc[:-len("]]>")]
        keywords = ""
        if ET.iselement(xmlDoc[0].find(calligra + 'keyword')):
            keywords = xmlDoc[0].find(calligra + 'keyword').text
        date = ""
        if ET.iselement(xmlDoc[0].find(calligra + 'date')):
            date = xmlDoc[0].find(calligra + 'date').text
        author = []
        if ET.iselement(xmlDoc[1].find(calligra + 'creator-first-name')):
            string = xmlDoc[1].find(calligra + 'creator-first-name').text
            if string is not None:
                author.append(string)
        if ET.iselement(xmlDoc[1].find(calligra + 'creator-last-name')):
            string = xmlDoc[1].find(calligra + 'creator-last-name').text
            if string is not None:
                author.append(string)
        if ET.iselement(xmlDoc[1].find(calligra + 'full-name')):
            string = xmlDoc[1].find(calligra + 'full-name').text
            if string is not None:
                author.append(string)

        return [name, desc, keywords, date, " ".join(author)]

    """
    Scrapes authors from the author data in the document info and puts them into the author list.
    Doesn't check for duplicates.
    """

    def slot_scrape_author_list(self):
        listOfAuthors = []
        if "authorList" in self.setupDictionary.keys():
            listOfAuthors = self.setupDictionary["authorList"]
        if "pages" in self.setupDictionary.keys():
            for relurl in self.setupDictionary["pages"]:
                absurl = os.path.join(self.projecturl, relurl)
                page = zipfile.ZipFile(absurl, "r")
                xmlDoc = ET.fromstring(page.read("documentinfo.xml"))
                calligra = str("{http://www.calligra.org/DTD/document-info}")
                authorelem = xmlDoc.find(calligra + 'author')
                author = {}
                if ET.iselement(authorelem.find(calligra + 'full-name')):
                    author["nickname"] = str(
                        authorelem.find(calligra + 'full-name').text)

                if ET.iselement(
                        authorelem.find(calligra + 'creator-first-name')):
                    author["first-name"] = str(
                        authorelem.find(calligra + 'creator-first-name').text)

                if ET.iselement(authorelem.find(calligra + 'initial')):
                    author["initials"] = str(
                        authorelem.find(calligra + 'initial').text)

                if ET.iselement(authorelem.find(calligra +
                                                'creator-last-name')):
                    author["last-name"] = str(
                        authorelem.find(calligra + 'creator-last-name').text)

                if ET.iselement(authorelem.find(calligra + 'email')):
                    author["email"] = str(
                        authorelem.find(calligra + 'email').text)

                if ET.iselement(authorelem.find(calligra + 'contact')):
                    contact = authorelem.find(calligra + 'contact')
                    contactMode = contact.get("type")
                    if contactMode == "email":
                        author["email"] = str(contact.text)
                    if contactMode == "homepage":
                        author["homepage"] = str(contact.text)

                if ET.iselement(authorelem.find(calligra + 'position')):
                    author["role"] = str(
                        authorelem.find(calligra + 'position').text)
                listOfAuthors.append(author)
                page.close()
        self.setupDictionary["authorList"] = listOfAuthors

    """
    Edit the general project settings like the project name, concept, pages location, export location, template location, metadata
    """

    def slot_edit_project_settings(self):
        dialog = comics_project_settings_dialog.comics_project_details_editor(
            self.projecturl)
        dialog.setConfig(self.setupDictionary, self.projecturl)

        if dialog.exec_() == QDialog.Accepted:
            self.setupDictionary = dialog.getConfig(self.setupDictionary)
            self.slot_write_config()
            self.projectName.setMainText(
                str(self.setupDictionary["projectName"]))

    """
    This allows users to select existing pages and add them to the pages list. The pages are currently not copied to the pages folder. Useful for existing projects.
    """

    def slot_add_page_from_url(self):
        # get the pages.
        urlList = QFileDialog.getOpenFileNames(
            caption=i18n("Which existing pages to add?"),
            directory=self.projecturl,
            filter=str(i18n("Krita files") + "(*.kra)"))[0]

        # get the existing pages list.
        pagesList = []
        if "pages" in self.setupDictionary.keys():
            pagesList = self.setupDictionary["pages"]

        # And add each url in the url list to the pages list and the model.
        for url in urlList:
            if self.projecturl not in urlList:
                newUrl = os.path.join(self.projecturl,
                                      self.setupDictionary["pagesLocation"],
                                      os.path.basename(url))
                shutil.move(url, newUrl)
                url = newUrl
            relative = os.path.relpath(url, self.projecturl)
            if url not in pagesList:
                page = zipfile.ZipFile(url, "r")
                thumbnail = QImage.fromData(page.read("preview.png"))
                dataList = self.get_description_and_title(
                    page.read("documentinfo.xml"))
                if (dataList[0].isspace() or len(dataList[0]) < 1):
                    dataList[0] = os.path.basename(url)
                newPageItem = QStandardItem()
                newPageItem.setIcon(QIcon(QPixmap.fromImage(thumbnail)))
                newPageItem.setDragEnabled(True)
                newPageItem.setDropEnabled(False)
                newPageItem.setEditable(False)
                newPageItem.setText(dataList[0].replace("_", " "))
                newPageItem.setData(dataList[1], role=CPE.DESCRIPTION)
                newPageItem.setData(relative, role=CPE.URL)
                newPageItem.setData(dataList[2], role=CPE.KEYWORDS)
                newPageItem.setData(dataList[3], role=CPE.LASTEDIT)
                newPageItem.setData(dataList[4], role=CPE.EDITOR)
                newPageItem.setToolTip(relative)
                page.close()
                self.pagesModel.appendRow(newPageItem)

    """
    Remove the selected page from the list of pages. This does not remove it from disk(far too dangerous).
    """

    def slot_remove_selected_page(self):
        index = self.comicPageList.currentIndex()
        self.pagesModel.removeRow(index.row())

    """
    This function adds a new page from the default template. If there's no default template, or the file does not exist, it will 
    show the create/import template dialog. It will remember the selected item as the default template.
    """

    def slot_add_new_page_single(self):
        templateUrl = "templatepage"
        templateExists = False

        if "singlePageTemplate" in self.setupDictionary.keys():
            templateUrl = self.setupDictionary["singlePageTemplate"]
        if os.path.exists(os.path.join(self.projecturl, templateUrl)):
            templateExists = True

        if templateExists is False:
            if "templateLocation" not in self.setupDictionary.keys():
                self.setupDictionary["templateLocation"] = os.path.relpath(
                    QFileDialog.getExistingDirectory(
                        caption=i18n("Where are the templates located?"),
                        options=QFileDialog.ShowDirsOnly), self.projecturl)

            templateDir = os.path.join(
                self.projecturl, self.setupDictionary["templateLocation"])
            template = comics_template_dialog.comics_template_dialog(
                templateDir)

            if template.exec_() == QDialog.Accepted:
                templateUrl = os.path.relpath(template.url(), self.projecturl)
                self.setupDictionary["singlePageTemplate"] = templateUrl
        if os.path.exists(os.path.join(self.projecturl, templateUrl)):
            self.add_new_page(templateUrl)

    """
    This function always asks for a template showing the new template window. This allows users to have multiple different
    templates created for back covers, spreads, other and have them accessible, while still having the convenience of a singular
    "add page" that adds a default.
    """

    def slot_add_new_page_from_template(self):
        if "templateLocation" not in self.setupDictionary.keys():
            self.setupDictionary["templateLocation"] = os.path.relpath(
                QFileDialog.getExistingDirectory(
                    caption=i18n("Where are the templates located?"),
                    options=QFileDialog.ShowDirsOnly), self.projecturl)

        templateDir = os.path.join(self.projecturl,
                                   self.setupDictionary["templateLocation"])
        template = comics_template_dialog.comics_template_dialog(templateDir)

        if template.exec_() == QDialog.Accepted:
            templateUrl = os.path.relpath(template.url(), self.projecturl)
            self.add_new_page(templateUrl)

    """
    This is the actual function that adds the template using the template url.
    It will attempt to name the new page projectName+number.
    """

    def add_new_page(self, templateUrl):

        # check for page list and or location.
        pagesList = []
        if "pages" in self.setupDictionary.keys():
            pagesList = self.setupDictionary["pages"]
        if not "pageNumber" in self.setupDictionary.keys():
            self.setupDictionary['pageNumber'] = 0

        if (str(self.setupDictionary["pagesLocation"]).isspace()):
            self.setupDictionary["pagesLocation"] = os.path.relpath(
                QFileDialog.getExistingDirectory(
                    caption=i18n("Where should the pages go?"),
                    options=QFileDialog.ShowDirsOnly), self.projecturl)

        # Search for the possible name.
        extraUnderscore = str()
        if str(self.setupDictionary["projectName"])[-1].isdigit():
            extraUnderscore = "_"
        self.setupDictionary['pageNumber'] += 1
        pageName = str(self.setupDictionary["projectName"]).replace(
            " ", "_") + extraUnderscore + str(
                format(self.setupDictionary['pageNumber'], "03d"))
        url = os.path.join(str(self.setupDictionary["pagesLocation"]),
                           pageName + ".kra")

        # open the page by opening the template and resaving it, or just opening it.
        absoluteUrl = os.path.join(self.projecturl, url)
        if (os.path.exists(absoluteUrl)):
            newPage = Application.openDocument(absoluteUrl)
        else:
            booltemplateExists = os.path.exists(
                os.path.join(self.projecturl, templateUrl))
            if booltemplateExists is False:
                templateUrl = os.path.relpath(
                    QFileDialog.getOpenFileName(
                        caption=i18n(
                            "Which image should be the basis the new page?"),
                        directory=self.projecturl,
                        filter=str(i18n("Krita files") + "(*.kra)"))[0],
                    self.projecturl)
            newPage = Application.openDocument(
                os.path.join(self.projecturl, templateUrl))
            newPage.waitForDone()
            newPage.setFileName(absoluteUrl)
            newPage.setName(pageName.replace("_", " "))
            newPage.save()
            newPage.waitForDone()

        # Get out the extra data for the standard item.
        newPageItem = QStandardItem()
        newPageItem.setIcon(
            QIcon(QPixmap.fromImage(newPage.thumbnail(256, 256))))
        newPageItem.setDragEnabled(True)
        newPageItem.setDropEnabled(False)
        newPageItem.setEditable(False)
        newPageItem.setText(pageName.replace("_", " "))
        newPageItem.setData("", role=CPE.DESCRIPTION)
        newPageItem.setData(url, role=CPE.URL)
        newPageItem.setData("", role=CPE.KEYWORDS)
        newPageItem.setData("", role=CPE.LASTEDIT)
        newPageItem.setData("", role=CPE.EDITOR)
        newPageItem.setToolTip(url)

        # close page document.
        while os.path.exists(absoluteUrl) is False:
            qApp.processEvents()

        newPage.close()

        # add item to page.
        self.pagesModel.appendRow(newPageItem)

    """
    Write to the json configuration file.
    This also checks the current state of the pages list.
    """

    def slot_write_config(self):

        # Don't load when the pages are still being loaded, otherwise we'll be overwriting our own pages list.
        if (self.loadingPages is False):
            print("CPMT: writing comic configuration...")

            # Generate a pages list from the pagesmodel.
            pagesList = []
            for i in range(self.pagesModel.rowCount()):
                index = self.pagesModel.index(i, 0)
                url = str(self.pagesModel.data(index, role=CPE.URL))
                if url not in pagesList:
                    pagesList.append(url)
            self.setupDictionary["pages"] = pagesList

            # Save to our json file.
            configFile = open(self.path_to_config,
                              "w",
                              newline="",
                              encoding="utf-16")
            json.dump(self.setupDictionary,
                      configFile,
                      indent=4,
                      sort_keys=True,
                      ensure_ascii=False)
            configFile.close()
            print("CPMT: done")

    """
    Open a page in the pagesmodel in Krita.
    """

    def slot_open_page(self, index):
        if index.column() is 0:
            # Get the absolute url from the relative one in the pages model.
            absoluteUrl = os.path.join(
                self.projecturl, str(self.pagesModel.data(index,
                                                          role=CPE.URL)))

            # Make sure the page exists.
            if os.path.exists(absoluteUrl):
                page = Application.openDocument(absoluteUrl)

                # Set the title to the filename if it was empty. It looks a bit neater.
                if page.name().isspace or len(page.name()) < 1:
                    page.setName(
                        str(self.pagesModel.data(index,
                                                 role=Qt.DisplayRole)).replace(
                                                     "_", " "))

                # Add views for the document so the user can use it.
                Application.activeWindow().addView(page)
                Application.setActiveDocument(page)
            else:
                print(
                    "CPMT: The page cannot be opened because the file doesn't exist:",
                    absoluteUrl)

    """
    Call up the metadata editor dialog. Only when the dialog is "Accepted" will the metadata be saved.
    """

    def slot_edit_meta_data(self):
        dialog = comics_metadata_dialog.comic_meta_data_editor()

        dialog.setConfig(self.setupDictionary)
        if (dialog.exec_() == QDialog.Accepted):
            self.setupDictionary = dialog.getConfig(self.setupDictionary)
            self.slot_write_config()

    """
    An attempt at making the description editable from the comic pages list.
    It is currently not working because ZipFile has no overwrite mechanism,
    and I don't have the energy to write one yet.
    """

    def slot_write_description(self, index):

        for row in range(self.pagesModel.rowCount()):
            index = self.pagesModel.index(row, 1)
            indexUrl = self.pagesModel.index(row, 0)
            absoluteUrl = os.path.join(
                self.projecturl,
                str(self.pagesModel.data(indexUrl, role=CPE.URL)))
            page = zipfile.ZipFile(absoluteUrl, "a")
            xmlDoc = ET.ElementTree()
            ET.register_namespace("",
                                  "http://www.calligra.org/DTD/document-info")
            location = os.path.join(self.projecturl, "documentinfo.xml")
            xmlDoc.parse(location)
            xmlroot = ET.fromstring(page.read("documentinfo.xml"))
            calligra = "{http://www.calligra.org/DTD/document-info}"
            aboutelem = xmlroot.find(calligra + 'about')
            if ET.iselement(aboutelem.find(calligra + 'subject')):
                desc = aboutelem.find(calligra + 'subject')
                desc.text = self.pagesModel.data(index, role=Qt.EditRole)
                xmlstring = ET.tostring(xmlroot,
                                        encoding='unicode',
                                        method='xml',
                                        short_empty_elements=False)
                page.writestr(zinfo_or_arcname="documentinfo.xml",
                              data=xmlstring)
                for document in Application.documents():
                    if str(document.fileName()) == str(absoluteUrl):
                        document.setDocumentInfo(xmlstring)
            page.close()

    """
    Calls up the export settings dialog. Only when accepted will the configuration be written.
    """

    def slot_edit_export_settings(self):
        dialog = comics_export_dialog.comic_export_setting_dialog()
        dialog.setConfig(self.setupDictionary)

        if (dialog.exec_() == QDialog.Accepted):
            self.setupDictionary = dialog.getConfig(self.setupDictionary)
            self.slot_write_config()

    """
    Export the comic. Won't work without export settings set.
    """

    def slot_export(self):

        #ensure there is a unique identifier
        if "uuid" not in self.setupDictionary.keys():
            uuid = str()
            if "acbfID" in self.setupDictionary.keys():
                uuid = str(self.setupDictionary["acbfID"])
            else:
                uuid = QUuid.createUuid().toString()
            self.setupDictionary["uuid"] = uuid

        exporter = comics_exporter.comicsExporter()
        exporter.set_config(self.setupDictionary, self.projecturl)
        exportSuccess = exporter.export()
        if exportSuccess:
            print(
                "CPMT: Export success! The files have been written to the export folder!"
            )
            QMessageBox.information(
                self, i18n("Export success"),
                i18n("The files have been written to the export folder."),
                QMessageBox.Ok)

    """
    Calls up the comics project setup wizard so users can create a new json file with the basic information.
    """

    def slot_new_project(self):
        setup = comics_project_setup_wizard.ComicsProjectSetupWizard()
        setup.showDialog()

    """
    This is triggered by any document save.
    It checks if the given url in in the pages list, and if so,
    updates the appropriate page thumbnail.
    This helps with the management of the pages, because the user
    will be able to see the thumbnails as a todo for the whole comic,
    giving a good overview over whether they still need to ink, color or
    the like for a given page, and it thus also rewards the user whenever
    they save.
    """

    def slot_check_for_page_update(self, url):
        if "pages" in self.setupDictionary.keys():
            relUrl = os.path.relpath(url, self.projecturl)
            if relUrl in self.setupDictionary["pages"]:
                index = self.pagesModel.index(
                    self.setupDictionary["pages"].index(relUrl), 0)
                if index.isValid():
                    pageItem = self.pagesModel.itemFromIndex(index)
                    page = zipfile.ZipFile(url, "r")
                    dataList = self.get_description_and_title(
                        page.read("documentinfo.xml"))
                    if (dataList[0].isspace() or len(dataList[0]) < 1):
                        dataList[0] = os.path.basename(url)
                    thumbnail = QImage.fromData(page.read("preview.png"))
                    pageItem.setIcon(QIcon(QPixmap.fromImage(thumbnail)))
                    pageItem.setText(dataList[0])
                    pageItem.setData(dataList[1], role=CPE.DESCRIPTION)
                    pageItem.setData(url, role=CPE.URL)
                    pageItem.setData(dataList[2], role=CPE.KEYWORDS)
                    pageItem.setData(dataList[3], role=CPE.LASTEDIT)
                    pageItem.setData(dataList[4], role=CPE.EDITOR)
                    self.pagesModel.setItem(index.row(), index.column(),
                                            pageItem)

    """
    Resize all the pages in the pages list.
    It will show a dialog with the options for resizing.
    Then, it will try to pop up a progress dialog while resizing.
    The progress dialog shows the remaining time and pages.
    """

    def slot_batch_resize(self):
        dialog = QDialog()
        dialog.setWindowTitle(i18n("Resize all Pages"))
        buttons = QDialogButtonBox(QDialogButtonBox.Ok
                                   | QDialogButtonBox.Cancel)
        buttons.accepted.connect(dialog.accept)
        buttons.rejected.connect(dialog.reject)
        sizesBox = comics_export_dialog.comic_export_resize_widget(
            "Scale", batch=True, fileType=False)
        exporterSizes = comics_exporter.sizesCalculator()
        dialog.setLayout(QVBoxLayout())
        dialog.layout().addWidget(sizesBox)
        dialog.layout().addWidget(buttons)

        if dialog.exec_() == QDialog.Accepted:
            progress = QProgressDialog(i18n("Resizing pages..."), str(), 0,
                                       len(self.setupDictionary["pages"]))
            progress.setWindowTitle(i18n("Resizing Pages"))
            progress.setCancelButton(None)
            timer = QElapsedTimer()
            timer.start()
            config = {}
            config = sizesBox.get_config(config)
            for p in range(len(self.setupDictionary["pages"])):
                absoluteUrl = os.path.join(self.projecturl,
                                           self.setupDictionary["pages"][p])
                progress.setValue(p)
                timePassed = timer.elapsed()
                if (p > 0):
                    timeEstimated = (len(self.setupDictionary["pages"]) -
                                     p) * (timePassed / p)
                    passedString = str(int(timePassed / 60000)) + ":" + format(
                        int(timePassed / 1000), "02d") + ":" + format(
                            timePassed % 1000, "03d")
                    estimatedString = str(int(
                        timeEstimated / 60000)) + ":" + format(
                            int(timeEstimated / 1000), "02d") + ":" + format(
                                int(timeEstimated % 1000), "03d")
                    progress.setLabelText(
                        str(
                            i18n(
                                "{pages} of {pagesTotal} done. \nTime passed: {passedString}:\n Estimated:{estimated}"
                            )).format(pages=p,
                                      pagesTotal=len(
                                          self.setupDictionary["pages"]),
                                      passedString=passedString,
                                      estimated=estimatedString))
                    qApp.processEvents()
                if os.path.exists(absoluteUrl):
                    doc = Application.openDocument(absoluteUrl)
                    listScales = exporterSizes.get_scale_from_resize_config(
                        config["Scale"], [
                            doc.width(),
                            doc.height(),
                            doc.resolution(),
                            doc.resolution()
                        ])
                    doc.scaleImage(listScales[0], listScales[1], listScales[2],
                                   listScales[3], "bicubic")
                    doc.waitForDone()
                    doc.save()
                    doc.waitForDone()
                    doc.close()

    def slot_show_page_viewer(self):
        index = int(self.comicPageList.currentIndex().row())
        self.page_viewer_dialog.load_comic(self.path_to_config)
        self.page_viewer_dialog.go_to_page_index(index)
        self.page_viewer_dialog.show()

    """
    Function to copy the current project location into the clipboard.
    This is useful for users because they'll be able to use that url to quickly
    move to the project location in outside applications.
    """

    def slot_copy_project_url(self):
        if self.projecturl is not None:
            clipboard = qApp.clipboard()
            clipboard.setText(str(self.projecturl))

    """
    Scrape text files with the textlayer keys for text, and put those in a POT
    file. This makes it possible to handle translations.
    """

    def slot_scrape_translations(self):
        translationFolder = self.setupDictionary.get("translationLocation",
                                                     "translations")
        fullTranslationPath = os.path.join(self.projecturl, translationFolder)
        os.makedirs(fullTranslationPath, exist_ok=True)
        textLayersToSearch = self.setupDictionary.get("textLayerNames",
                                                      ["text"])

        scraper = comics_project_translation_scraper.translation_scraper(
            self.projecturl, translationFolder, textLayersToSearch,
            self.setupDictionary["projectName"])
        # Run text scraper.
        language = self.setupDictionary.get("language", "en")
        metadata = {}
        metadata["title"] = self.setupDictionary.get("title", "")
        metadata["summary"] = self.setupDictionary.get("summary", "")
        metadata["keywords"] = ", ".join(
            self.setupDictionary.get("otherKeywords", [""]))
        metadata["transnotes"] = self.setupDictionary.get(
            "translatorHeader", "Translator's Notes")
        scraper.start(self.setupDictionary["pages"], language, metadata)
        QMessageBox.information(
            self, i18n("Scraping success"),
            str(i18n("POT file has been written to: {file}")).format(
                file=fullTranslationPath), QMessageBox.Ok)

    """
    This is required by the dockwidget class, otherwise unused.
    """

    def canvasChanged(self, canvas):
        pass
Beispiel #5
0
class CentralWidgetParkingson(QWidget):
    pacients_tab: QWidget  # Una vez seleccionado paciente, mostrara sus datos
    cronometro_tab: QWidget  # Una vez seleccionado paciente, lo testara
    evolution_tab: QWidget  # Una vez seleccionado paciente, mostrara su rendimiento

    pacients_list_view: QListView  # Mostrara los pacientes en lista
    actions_buttons: dict  # Continene los botones de la app

    general_layout: QVBoxLayout
    buttons_layout: QHBoxLayout  # el layout de los botones de arriba
    content_layout: QHBoxLayout  # los layout de los tabs y el listview

    ADD_button_key = "add"
    DELETE_button_key = "delete"
    EDIT_button_key = "edit"

    @Utils.function_error_safety
    def __init__(self, user:str, parent=None):
        super(QWidget, self).__init__(parent)
        self.general_layout = QVBoxLayout()
        self.buttons_layout = QHBoxLayout()
        self.content_layout = QHBoxLayout()

        self.actions_buttons = {
            CentralWidgetParkingson.ADD_button_key: QPushButton('Anadir'),
            CentralWidgetParkingson.DELETE_button_key: QPushButton('Eliminar'),
            CentralWidgetParkingson.EDIT_button_key: QPushButton('Editar')
        }

        for x in self.actions_buttons:
            self.actions_buttons[x].setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
            self.actions_buttons[x].setObjectName(x + "_button")
            self.buttons_layout.addWidget(self.actions_buttons[x])

        self.buttons_layout.setAlignment(Qt.AlignLeft)
        self.buttons_layout.setSpacing(20)

        self.pacients_list_view = QListView()
        self.pacients_list_view.resize(200, 400)
        self.parent_tab_widget = QTabWidget()
        self.parent_tab_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.pacients_tab: PacientWidget = PacientWidget()  # Tab1 Color

        # self.rendimiento_tab = MplCanvas(self, width=5, height=4, dpi=100)  # Tab2 Grafica
        self.evolution_tab = EvolutionTab(user)

        self.cronometro_tab = Cronometro(user)
        self.parent_tab_widget.resize(300, 300)  # Tab Parent

        self.parent_tab_widget.addTab(self.pacients_tab, "Paciente")
        self.parent_tab_widget.addTab(self.evolution_tab, "Evolucion")
        self.parent_tab_widget.addTab(self.cronometro_tab, "Cronómetro")

        self.pacients_list_view.setMinimumSize(200, 400)
        self.pacients_list_view.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
        self.pacients_list_view.setContextMenuPolicy(Qt.CustomContextMenu)

        self.content_layout.addWidget(self.pacients_list_view, stretch=3, alignment=Qt.AlignTop)
        self.content_layout.addWidget(self.parent_tab_widget, stretch=9)

        # self.general_layout.addLayout(self.buttons_layout)
        self.general_layout.addLayout(self.content_layout)

        self.setMinimumSize(900, 600)
        self.setLayout(self.general_layout)
Beispiel #6
0
class contentView(QTabWidget):
    def __init__(self, query, TAGS, KEYWORDS):
        super().__init__()
        self.query = query
        self.TAGS = TAGS
        self.KEYWORDS = KEYWORDS
        self.initUI()
        self.updateAllPage()

    def initUI(self):
        self.allFileTab = QListView()
        self.allFileTab.clicked.connect(self.showInfo)
        self.allFileTab.setContextMenuPolicy(3)
        self.allFileTab.customContextMenuRequested[QPoint].connect(
            self.popMenu)

        self.pictureTab = QListView()
        self.pictureTab.setContextMenuPolicy(3)
        self.pictureTab.customContextMenuRequested[QPoint].connect(
            self.popMenu)

        self.addTab(self.allFileTab, "All")
        self.addTab(self.pictureTab, "Picture")

    def updateAllPage(self, *args):
        if args == ([], [], []) or args == ():
            self.query.exec(
                "SELECT FILENAME FROM FileLibrary WHERE SUFFIX != ('{}')".
                format(""))
            #如果是目录,会被排除掉
            model = QSqlQueryModel()
            model.setQuery(self.query)
            self.allFileTab.setModel(model)
        else:
            core.FileOperator.unionQuery(self.query, args[0], args[1], args[2])
            model = QSqlQueryModel()
            model.setQuery(self.query)
            self.allFileTab.setModel(model)

    def popMenu(self, point):
        qModelIndex = self.allFileTab.indexAt(point)
        self.item = qModelIndex.data()
        popMenu = QMenu()
        popMenu.addAction("Open File")
        popMenu.addAction("Open the Path")
        popMenu.addAction("Remove the File").triggered.connect(self.removeFile)

        setTag = QMenu("Tags")

        for tag in self.TAGS:
            setTag.addAction(tag).triggered.connect(self.setTag)

        setRating = QMenu("Rating")
        for rating in ["1 star", "2 star", "3 star", "4 star", "5 star"]:
            setRating.addAction(rating).triggered.connect(self.setRating)

        setKeyword = QMenu("Keyword")
        for keyword in self.KEYWORDS:
            setKeyword.addAction(keyword).triggered.connect(self.setKeyword)

        popMenu.addMenu(setTag)
        popMenu.addMenu(setRating)
        popMenu.addMenu(setKeyword)
        popMenu.exec(QCursor.pos())

    def showInfo(self, point):
        item = point.data()
        self.propertyView.showMetadata(item)

    def removeFile(self):
        pass

    def setTag(self):
        tag = self.sender().text()
        self.query.exec(
            "UPDATE FileLibrary SET USERTAGS = '{}' WHERE FILENAME == '{}'".
            format(tag, self.item))
        self.propertyView.showMetadata(self.item)

    def setRating(self):
        rating = self.sender().text()
        self.query.exec(
            "UPDATE FileLibrary SET RATING = '{}' WHERE FILENAME == '{}'".
            format(rating, self.item))
        self.propertyView.showMetadata(self.item)

    def setKeyword(self):
        keyword = self.sender().text()
        self.query.exec(
            "UPDATE FileLibrary SET KEYWORDS = '{}' WHERE FILENAME == '{}'".
            format(keyword, self.item))
        self.propertyView.showMetadata(self.item)

    def getPreviewView(self, previewView):
        self.previewView = previewView

    def getPropertyView(self, propertyView):
        self.propertyView = propertyView
Beispiel #7
0
class MusicPlayer(QWidget):
    def __init__(self, parent=None):
        QWidget.__init__(self, parent)
        self.options = self.parent().options

        self.ffmpeg = self.options['paths']['ffmpeg_bin']
        self.thumbnails = self.options['paths']['thumbnails']
        self.thumb_width = self.options['thumbnail']['width']
        self.thumb_height = self.options['thumbnail']['height']

        self.jumping = False
        self.blocked = False
        self.durations = {}
        self.playback_value = 0

        self.text = ["None", "Repeat", "Random"]
        self.playlist_list = []
        self.values = [
            QMediaPlaylist.Loop, QMediaPlaylist.CurrentItemInLoop,
            QMediaPlaylist.Random
        ]

        # Thumbnail widget
        self.image_label = QLabel()

        # Control widgets
        self.playButton = QToolButton(clicked=self.play)
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))

        self.stopButton = QToolButton(clicked=self.stop)
        self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        self.stopButton.setEnabled(False)

        self.playbackButton = QToolButton(clicked=self.playback_mode)
        self.playbackButton.setText(self.text[0])

        self.nextButton = QToolButton(clicked=self.next_song)
        self.nextButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSkipForward))

        self.previousButton = QToolButton(clicked=self.previous_song)
        self.previousButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSkipBackward))

        self.muteButton = QToolButton(clicked=self.mute_clicked)
        self.muteButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaVolume))

        self.volumeSlider = QSlider(Qt.Horizontal,
                                    sliderMoved=self.change_volume)
        self.volumeSlider.setRange(0, 100)
        self.volumeSlider.setPageStep(1)
        self.volumeSlider.setValue(50)

        # Player and playlist setup

        self.player = QMediaPlayer()
        self.player.setVolume(50)
        self.player.stateChanged.connect(self.waveform)

        self.playlist = QMediaPlaylist()
        self.playlist.setPlaybackMode(self.values[0])
        self.playlist.setCurrentIndex(1)

        self.player.setPlaylist(self.playlist)

        self.playlistModel = PlaylistModel()
        self.playlistModel.setPlaylist(self.playlist)

        self.playlistView = QListView()
        self.playlistView.setModel(self.playlistModel)
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))
        self.playlistView.activated.connect(self.jump)
        self.playlistView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.playlistView.customContextMenuRequested.connect(
            self.list_view_menu)
        self.playlist.currentIndexChanged.connect(
            lambda position: self.change_thumbnail(position))

        song_search = QLineEdit()
        song_search.textChanged.connect(self.search)
        song_search.setClearButtonEnabled(True)

        # Playlist
        self.playlist_name = QComboBox()
        self.playlist_name.currentTextChanged.connect(self.switch_playlist)
        self.refresh_lists()

        self.up_button = QToolButton(clicked=self.move_up)
        self.up_button.setIcon(self.style().standardIcon(QStyle.SP_ArrowUp))
        self.down_button = QToolButton(clicked=self.move_down)
        self.down_button.setIcon(self.style().standardIcon(
            QStyle.SP_ArrowDown))

        # Sound wave widget

        self.wave_graphic = WaveGraphic(self)
        #self.wave_graphic.hide()

        # Testing slider again
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)
        self.slider.sliderMoved.connect(self.seek)
        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)

        # Shortcuts
        QShortcut(QKeySequence(Qt.CTRL + Qt.Key_F), self, song_search.setFocus)

        # Layouts setup

        playlist_layout = QHBoxLayout()
        playlist_layout.addWidget(self.playlist_name)
        playlist_layout.addWidget(self.up_button)
        playlist_layout.addWidget(self.down_button)

        control_layout = QHBoxLayout()
        control_layout.setContentsMargins(0, 0, 0, 0)
        control_layout.addWidget(self.stopButton)
        control_layout.addWidget(self.previousButton)
        control_layout.addWidget(self.playButton)
        control_layout.addWidget(self.nextButton)
        control_layout.addWidget(self.muteButton)
        control_layout.addWidget(self.volumeSlider)
        control_layout.addWidget(self.playbackButton)

        display_layout = QVBoxLayout()
        display_layout.addWidget(song_search)
        display_layout.addWidget(self.playlistView)
        display_layout.addLayout(playlist_layout)

        music_layout = QVBoxLayout()
        music_layout.addWidget(self.image_label)
        music_layout.addWidget(self.slider)
        music_layout.addLayout(control_layout)

        main_layout = QHBoxLayout()
        main_layout.addLayout(music_layout)
        main_layout.addLayout(display_layout)

        main_2_layout = QVBoxLayout()
        main_2_layout.addLayout(main_layout)
        main_2_layout.addWidget(self.wave_graphic)

        self.setLayout(main_2_layout)

    def waveform(self, status):
        if status == QMediaPlayer.PlayingState:
            self.wave_graphic.start()
        elif status == QMediaPlayer.PausedState:
            self.wave_graphic.pause()
        else:
            self.wave_graphic.stop()

    def list_view_menu(self, point):
        menu = QMenu("Menu", self)
        recommend_action = QAction('&Recommend Songs', self)
        menu.addAction(recommend_action)

        # TODO: [FEATURE] add rename song
        recommend_action.triggered.connect(
            lambda: self.parent().call_download_manager(self.get_links()))

        rename_action = QAction('&Rename', self)
        menu.addAction(rename_action)

        # TODO: [FEATURE] add rename song
        rename_action.triggered.connect(lambda: print("rename"))

        # Show the context menu.
        menu.exec_(self.playlistView.mapToGlobal(point))

    def get_links(self):
        title = self.playlistView.selectedIndexes()[0].data()
        link = getYoutubeURLFromSearch(title)
        if len(link) > 1:
            return youtube_recommendations(link)

    def move_up(self):
        index = self.playlistView.currentIndex().row()
        if index - 1 >= 0:
            item, above = self.playlist.media(index), self.playlist.media(
                index - 1)
            self.playlist.removeMedia(index)
            self.playlist.removeMedia(index - 1)
            self.playlist.insertMedia(index - 1, item)
            self.playlist.insertMedia(index, above)
            self.blocked = True
            self.playlistView.setCurrentIndex(
                self.playlistModel.index(index - 1, 0))
            self.blocked = False
            self.stop()

    def move_down(self):
        index = self.playlistView.currentIndex().row()
        if index + 1 <= self.playlistModel.rowCount():
            item, below = self.playlist.media(index), self.playlist.media(
                index + 1)
            self.playlist.removeMedia(index + 1)
            self.playlist.removeMedia(index)
            self.playlist.insertMedia(index, below)
            self.playlist.insertMedia(index + 1, item)
            self.blocked = True
            self.playlistView.setCurrentIndex(
                self.playlistModel.index(index + 1, 0))
            self.blocked = False
            self.stop()

    def search(self, part_of_song):
        for index in range(self.playlistModel.rowCount()):
            item = self.playlistModel.data(self.playlistModel.index(
                index, 0)).lower()
            self.playlistView.setRowHidden(index,
                                           part_of_song.lower() not in item)

    def change_thumbnail(self, position=0):

        self.playlistView.setCurrentIndex(self.playlistModel.index(
            position, 0))

        song = self.playlistView.selectedIndexes()[0].data()
        if self.wave_graphic.is_song_cached(song):
            self.wave_graphic.load_waves(song)
        else:
            wc_ = WaveConverter(song, self.wave_graphic.set_wav)
            wc_.convert()

        if self.playlistView.currentIndex().data() is None or self.blocked:
            return

        max_ratio = 0
        img = None

        for item in listdir(self.thumbnails):
            if item.endswith('.jpg'):
                ratio = similar(
                    item,
                    self.playlistView.currentIndex().data().replace(
                        '.mp3', '.jpg'))
                if ratio > max_ratio:
                    max_ratio = ratio
                    img = item

        if img:
            p = QPixmap(self.thumbnails + img)
            self.image_label.setPixmap(
                p.scaled(self.thumb_width, self.thumb_height,
                         Qt.KeepAspectRatio))

    def switch_playlist(self, current_text):
        self.playlist.clear()
        if current_text == "No Playlist":
            self.refresh()
        else:
            if read_playlist(current_text):
                songs = read_playlist(current_text).split('\n')
                for song in songs:
                    self.playlist.addMedia(
                        QMediaContent(QUrl.fromLocalFile(song)))

    def refresh(self):
        # Change it so it will go to same song.
        if self.playlist_name.currentText() != "No Playlist":
            return

        paths = fetch_options()['paths']['music_path'].split(';')

        current_songs = [
            self.playlistModel.data(self.playlistModel.index(row, 0))
            for row in range(self.playlistModel.rowCount())
        ]

        for path in paths:
            if not path:
                continue
            for item in listdir(path):
                if isfile(join(path, item)) and item.endswith(".mp3") and (
                        item not in current_songs):
                    self.playlist.addMedia(
                        QMediaContent(QUrl.fromLocalFile(join(path, item))))

    def refresh_lists(self):
        path = fetch_options()['paths']['playlist']
        self.playlist_name.clear()
        self.playlist_list = ["No Playlist"]
        self.playlist_name.addItem("No Playlist")
        for item in listdir(path):
            if isfile(join(path, item)) and item.endswith(".lst"):
                self.playlist_list.append(item.split('.')[0])
                self.playlist_name.addItem(item.split('.')[0])

    def playback_mode(self):
        # Normal -> Loop -> Random
        def up_value(value, max_value=3):
            if value + 1 == max_value:
                return 0
            return value + 1

        self.playback_value = up_value(self.playback_value)
        self.playlist.setPlaybackMode(self.values[self.playback_value])
        self.playbackButton.setText(self.text[self.playback_value])

    def jump(self, index):
        if index.isValid() and not self.blocked:
            self.playlist.setCurrentIndex(index.row())
            self.jumping = True
            self.play()

    def play(self):
        if self.blocked:
            return
        if self.player.state() != QMediaPlayer.PlayingState or self.jumping:
            self.player.play()
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPause))
            self.jumping = False
        else:
            self.player.pause()
            self.playButton.setIcon(self.style().standardIcon(
                QStyle.SP_MediaPlay))
        self.stopButton.setEnabled(True)

    def change_volume(self, value):
        self.player.setVolume(value)

    def stop(self):
        if self.player.state() != QMediaPlayer.StoppedState:
            self.player.stop()
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
        self.stopButton.setEnabled(False)

    def next_song(self):
        self.playlist.next()
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))

    def previous_song(self):
        self.playlist.previous()
        self.playlistView.setCurrentIndex(
            self.playlistModel.index(self.playlist.currentIndex(), 0))

    def mute_clicked(self):
        self.player.setMuted(not self.player.isMuted())
        self.muteButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaVolume if not self.player.isMuted() else QStyle.
            SP_MediaVolumeMuted))

    def durationChanged(self, duration):
        duration /= 1000
        self.slider.setMaximum(duration)

    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)

    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)
Beispiel #8
0
class PeerListView(QFrame):
    """"
    Abstract class, sets forth a basic list for viewing peers
    """

    def __init__(self, parent: Optional[QWidget], search_placeholder: str, is_stateless: bool):
        super().__init__(parent)

        self.setProperty("class", "friends_list")
        self._layout_manager = QVBoxLayout(self)
        self._header_manager = QHBoxLayout()

        # Set up search bar
        self._search_bar = QLineEdit()
        self._search_bar.setPlaceholderText(search_placeholder)

        # Set up model
        self._peer_model = PeerList(self, is_stateless)
        self._peer_list_view = QListView(self)
        self._peer_list_view.setModel(self._peer_model)
        self._peer_list_view.setContextMenuPolicy(Qt.CustomContextMenu)

        # Connect events
        self._search_bar.returnPressed.connect(self._search_initiated)

        self._setup_ui()

    @QtCore.pyqtSlot()
    def _search_initiated(self):
        """
        Slot connected to returnPressed signal, initiates a search
        """
        print("Search!")

    def _setup_ui(self):
        """
        Establishes UI for display
        """

        # Set minimum width of search bar to length of placeholder text
        font_metrics = QFontMetrics(self._search_bar.font())
        txt_width = font_metrics.width(self._search_bar.placeholderText())
        self._search_bar.minimumSizeHint = QSize(txt_width, -1)
        self._search_bar.setFixedHeight(30)

        self._peer_list_view.setLayoutMode(QListView.Batched)  # Display as needed
        self._peer_list_view.setBatchSize(10)  # Number of messages to display
        self._peer_list_view.setFlow(QListView.TopToBottom)  # Display vertically
        self._peer_list_view.setResizeMode(QListView.Adjust)  # Items laid out every time view is resized

        # Set up header
        self._header_manager.addWidget(self._search_bar, 1)

        # Layout widgets
        self._layout_manager.addLayout(self._header_manager)
        self._layout_manager.addSpacing(10)
        self._layout_manager.addWidget(self._peer_list_view)
        self._layout_manager.setSpacing(0)

    def add_to_header(self, widget: QWidget):
        """
        Adds the given widget to the header
        :param widget: Widget to be added
        """
        self._header_manager.addSpacing(5)
        self._header_manager.addWidget(widget)

    def model(self) -> PeerList:
        """
        :return: The peer list model
        """
        return self._peer_model
Beispiel #9
0
class DesktopIconWidget(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self, parent)
        self.setFrameStyle(QFrame.Box | QFrame.Sunken)
        self.setStyleSheet("QListView{background:transparent;}")

        self.listView = QListView(self)
        self.setLayout(QHBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.listView)

        self.listView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.listView.setMovement(QListView.Snap)
        self.listView.setFlow(QListView.LeftToRight)
        self.listView.setResizeMode(QListView.Adjust)
        self.listView.setGridSize(QSize(self.logicalDpiX() / 96 * 70,
                                        self.logicalDpiY() / 96 * 70))
        self.listView.setViewMode(QListView.IconMode)

        self.quickDesktopModel = QuickDesktopModel(self.window().platform.databaseFile)
        self.listView.setModel(self.quickDesktopModel)
        self.createActions()
        self.makeConnections()

    def createActions(self):
        self.actionCreateComputer = QAction(self.tr("我的电脑(&C)"), self)
        self.actionCreateDocuments = QAction(self.tr("我的文档(&D)"), self)
        self.actionCreateMusic = QAction(self.tr("我的音乐(&M)"), self)
        self.actionCreatePictures = QAction(self.tr("我的图片(&P)"), self)
        self.actionCreateShortcut = QAction(self.tr("创建快捷方式(&C)"), self)
        self.actionCreateShortcut.setIcon(QIcon(":/images/new.png"))
        self.actionCreateBookmark = QAction(self.tr("创建网络链接(&B)"), self)
        self.actionCreateBookmark.setIcon(QIcon(":/images/insert-link.png"))
        self.actionRemoveShortcut = QAction(self.tr("删除快捷方式(&R)"), self)
        self.actionRemoveShortcut.setIcon(QIcon(":/images/delete.png"))
        self.actionRenameShortcut = QAction(self.tr("重命名(&N)"), self)
        self.actionRenameShortcut.setIcon(QIcon(":/images/edit-rename.png"))
        self.actionEditShortcut = QAction(self.tr("编辑快捷方式(&E)"), self)
        self.actionEditShortcut.setIcon(QIcon(":/images/edit.png"))

    def makeConnections(self):
        self.listView.customContextMenuRequested.connect(self.onQuickDesktopContextMenuRequest)
        self.listView.activated.connect(self.runQuickDesktopShortcut)

        self.actionCreateComputer.triggered.connect(self.createComputerShortcut)
        self.actionCreateDocuments.triggered.connect(self.createDocumentsShortcut)
        self.actionCreateMusic.triggered.connect(self.createMusicShortcut)
        self.actionCreatePictures.triggered.connect(self.createPicturesShortcut)
        self.actionCreateShortcut.triggered.connect(self.createShortcut)
        self.actionCreateBookmark.triggered.connect(self.createBookmark)
        self.actionEditShortcut.triggered.connect(self.editShortcut)
        self.actionRemoveShortcut.triggered.connect(self.removeShortcut)
        self.actionRenameShortcut.triggered.connect(self.renameShortcut)

    def onQuickDesktopContextMenuRequest(self, pos):
        index = self.listView.indexAt(pos)
        self.listView.setCurrentIndex(index)
        menu = QMenu()
        menu.addAction(self.actionCreateShortcut)
        menu.addAction(self.actionCreateBookmark)
        menu2 = menu.addMenu(self.tr("创建特殊快捷方式(&S)"))
        if os.name == "nt":
            menu2.addAction(self.actionCreateComputer)
        menu2.addAction(self.actionCreateDocuments)
        menu2.addAction(self.actionCreatePictures)
        menu2.addAction(self.actionCreateMusic)
        if index.isValid():
            menu.addAction(self.actionRemoveShortcut)
            if not self.quickDesktopModel.isSpecialShortcut(index):
                menu.addAction(self.actionEditShortcut)
            menu.addAction(self.actionRenameShortcut)
        try:
            getattr(menu, "exec")(QCursor.pos())
        except AttributeError:
            getattr(menu, "exec_")(QCursor.pos())

    def createShortcut(self):
        d = ShortcutDialog(self)
        if self.window().runDialog(d.create) == QDialog.Accepted:
            shortcut = d.getResult()
            shortcut["id"] = str(uuid.uuid4())
            self.quickDesktopModel.addShortcut(shortcut)
        d.deleteLater()

    def createBookmark(self):
        d = BookmarkDialog(self)
        if self.window().runDialog(d.create) == QDialog.Accepted:
            shortcut = {
                    "id": str(uuid.uuid4()),
                    "icon": "",
                    "openwith": "",
                    "dir": "",
            }
            shortcut.update(d.getResult())
            self.quickDesktopModel.addShortcut(shortcut)
        d.deleteLater()

    def createComputerShortcut(self):
        shortcut = {
                "id": str(uuid.uuid4()),
                "name": self.tr("我的电脑"),
                "path": COMPUTER_PATH,
                "icon": "",
                "dir": "",
                "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def createDocumentsShortcut(self):
        shortcut = {
                "id": str(uuid.uuid4()),
                "name": self.tr("我的文档"),
                "path": DOCUMENTS_PATH,
                "icon": "",
                "dir": "",
                "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def createPicturesShortcut(self):
        shortcut = {
                "id": str(uuid.uuid4()),
                "name": self.tr("图片收藏"),
                "path": PICTURES_PATH,
                "icon": "",
                "dir": "",
                "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def createMusicShortcut(self):
        shortcut = {
                "id": str(uuid.uuid4()),
                "name": self.tr("我的音乐"),
                "path": MUSIC_PATH,
                "icon": "",
                "dir": "",
                "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def renameShortcut(self):
        self.listView.edit(self.listView.currentIndex())

    def removeShortcut(self):
        self.quickDesktopModel.removeShortcut(self.listView.currentIndex())

    def editShortcut(self):
        index = self.listView.currentIndex()
        if not index.isValid():
            return
        shortcut = self.quickDesktopModel.shortcutAt(index)
        url = QUrl.fromUserInput(shortcut["path"])
        if not url.isValid():
            return
        if url.scheme() == "special":
            QMessageBox.information(self, self.tr("编辑快捷方式"), self.tr("不能编辑特殊图标。"))
            return
        elif url.scheme() == "file":
            d = ShortcutDialog(self)
        else:
            d = BookmarkDialog(self)
        if self.window().runDialog(d.edit, shortcut) == QDialog.Accepted:
            shortcut.update(d.getResult())
            self.quickDesktopModel.updateShortcut(shortcut, index)
        d.deleteLater()

    def runQuickDesktopShortcut(self):
        index = self.listView.currentIndex()
        if not index.isValid():
            return
        if not self.quickDesktopModel.runShortcut(index):
            QMessageBox.information(self, self.tr("快捷面板"), \
                    self.tr("不能运行快捷方式。请检查文件是否存在或者程序是否正确。"))
        else:
            self.window().close()
Beispiel #10
0
class DesktopIconWidget(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self, parent)
        self.setFrameStyle(QFrame.Box | QFrame.Sunken)
        self.setStyleSheet("QListView{background:transparent;}")

        self.listView = QListView(self)
        self.setLayout(QHBoxLayout())
        self.layout().setContentsMargins(0, 0, 0, 0)
        self.layout().addWidget(self.listView)

        self.listView.setContextMenuPolicy(Qt.CustomContextMenu)
        self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self.listView.setMovement(QListView.Snap)
        self.listView.setFlow(QListView.LeftToRight)
        self.listView.setResizeMode(QListView.Adjust)
        self.listView.setGridSize(
            QSize(self.logicalDpiX() / 96 * 70,
                  self.logicalDpiY() / 96 * 70))
        self.listView.setViewMode(QListView.IconMode)

        self.quickDesktopModel = QuickDesktopModel(
            self.window().platform.databaseFile)
        self.listView.setModel(self.quickDesktopModel)
        self.createActions()
        self.makeConnections()

    def createActions(self):
        self.actionCreateComputer = QAction(self.tr("我的电脑(&C)"), self)
        self.actionCreateDocuments = QAction(self.tr("我的文档(&D)"), self)
        self.actionCreateMusic = QAction(self.tr("我的音乐(&M)"), self)
        self.actionCreatePictures = QAction(self.tr("我的图片(&P)"), self)
        self.actionCreateShortcut = QAction(self.tr("创建快捷方式(&C)"), self)
        self.actionCreateShortcut.setIcon(QIcon(":/images/new.png"))
        self.actionCreateBookmark = QAction(self.tr("创建网络链接(&B)"), self)
        self.actionCreateBookmark.setIcon(QIcon(":/images/insert-link.png"))
        self.actionRemoveShortcut = QAction(self.tr("删除快捷方式(&R)"), self)
        self.actionRemoveShortcut.setIcon(QIcon(":/images/delete.png"))
        self.actionRenameShortcut = QAction(self.tr("重命名(&N)"), self)
        self.actionRenameShortcut.setIcon(QIcon(":/images/edit-rename.png"))
        self.actionEditShortcut = QAction(self.tr("编辑快捷方式(&E)"), self)
        self.actionEditShortcut.setIcon(QIcon(":/images/edit.png"))

    def makeConnections(self):
        self.listView.customContextMenuRequested.connect(
            self.onQuickDesktopContextMenuRequest)
        self.listView.activated.connect(self.runQuickDesktopShortcut)

        self.actionCreateComputer.triggered.connect(
            self.createComputerShortcut)
        self.actionCreateDocuments.triggered.connect(
            self.createDocumentsShortcut)
        self.actionCreateMusic.triggered.connect(self.createMusicShortcut)
        self.actionCreatePictures.triggered.connect(
            self.createPicturesShortcut)
        self.actionCreateShortcut.triggered.connect(self.createShortcut)
        self.actionCreateBookmark.triggered.connect(self.createBookmark)
        self.actionEditShortcut.triggered.connect(self.editShortcut)
        self.actionRemoveShortcut.triggered.connect(self.removeShortcut)
        self.actionRenameShortcut.triggered.connect(self.renameShortcut)

    def onQuickDesktopContextMenuRequest(self, pos):
        index = self.listView.indexAt(pos)
        self.listView.setCurrentIndex(index)
        menu = QMenu()
        menu.addAction(self.actionCreateShortcut)
        menu.addAction(self.actionCreateBookmark)
        menu2 = menu.addMenu(self.tr("创建特殊快捷方式(&S)"))
        if os.name == "nt":
            menu2.addAction(self.actionCreateComputer)
        menu2.addAction(self.actionCreateDocuments)
        menu2.addAction(self.actionCreatePictures)
        menu2.addAction(self.actionCreateMusic)
        if index.isValid():
            menu.addAction(self.actionRemoveShortcut)
            if not self.quickDesktopModel.isSpecialShortcut(index):
                menu.addAction(self.actionEditShortcut)
            menu.addAction(self.actionRenameShortcut)
        try:
            getattr(menu, "exec")(QCursor.pos())
        except AttributeError:
            getattr(menu, "exec_")(QCursor.pos())

    def createShortcut(self):
        d = ShortcutDialog(self)
        if self.window().runDialog(d.create) == QDialog.Accepted:
            shortcut = d.getResult()
            shortcut["id"] = str(uuid.uuid4())
            self.quickDesktopModel.addShortcut(shortcut)
        d.deleteLater()

    def createBookmark(self):
        d = BookmarkDialog(self)
        if self.window().runDialog(d.create) == QDialog.Accepted:
            shortcut = {
                "id": str(uuid.uuid4()),
                "icon": "",
                "openwith": "",
                "dir": "",
            }
            shortcut.update(d.getResult())
            self.quickDesktopModel.addShortcut(shortcut)
        d.deleteLater()

    def createComputerShortcut(self):
        shortcut = {
            "id": str(uuid.uuid4()),
            "name": self.tr("我的电脑"),
            "path": COMPUTER_PATH,
            "icon": "",
            "dir": "",
            "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def createDocumentsShortcut(self):
        shortcut = {
            "id": str(uuid.uuid4()),
            "name": self.tr("我的文档"),
            "path": DOCUMENTS_PATH,
            "icon": "",
            "dir": "",
            "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def createPicturesShortcut(self):
        shortcut = {
            "id": str(uuid.uuid4()),
            "name": self.tr("图片收藏"),
            "path": PICTURES_PATH,
            "icon": "",
            "dir": "",
            "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def createMusicShortcut(self):
        shortcut = {
            "id": str(uuid.uuid4()),
            "name": self.tr("我的音乐"),
            "path": MUSIC_PATH,
            "icon": "",
            "dir": "",
            "openwith": "",
        }
        self.quickDesktopModel.addShortcut(shortcut)

    def renameShortcut(self):
        self.listView.edit(self.listView.currentIndex())

    def removeShortcut(self):
        self.quickDesktopModel.removeShortcut(self.listView.currentIndex())

    def editShortcut(self):
        index = self.listView.currentIndex()
        if not index.isValid():
            return
        shortcut = self.quickDesktopModel.shortcutAt(index)
        url = QUrl.fromUserInput(shortcut["path"])
        if not url.isValid():
            return
        if url.scheme() == "special":
            QMessageBox.information(self, self.tr("编辑快捷方式"),
                                    self.tr("不能编辑特殊图标。"))
            return
        elif url.scheme() == "file":
            d = ShortcutDialog(self)
        else:
            d = BookmarkDialog(self)
        if self.window().runDialog(d.edit, shortcut) == QDialog.Accepted:
            shortcut.update(d.getResult())
            self.quickDesktopModel.updateShortcut(shortcut, index)
        d.deleteLater()

    def runQuickDesktopShortcut(self):
        index = self.listView.currentIndex()
        if not index.isValid():
            return
        if not self.quickDesktopModel.runShortcut(index):
            QMessageBox.information(self, self.tr("快捷面板"), \
                    self.tr("不能运行快捷方式。请检查文件是否存在或者程序是否正确。"))
        else:
            self.window().close()
class PlaylistView(QFrame):
    """
    Horizontal Scroll Area containing playlists that can be selected
    """

    # Signals
    should_display_playlist = pyqtSignal(
        int)  # Display playlist given playlist_id

    def __init__(self, parent: QObject, image_cache: ImageCache):
        super().__init__(parent)

        self.__item_delegate = PlaylistDelegate(self)
        self.__model = PlaylistModel(self, image_cache)

        self.__horizontal_list = QListView(self)
        self.__horizontal_list.setModel(self.__model)
        self.__horizontal_list.setItemDelegate(self.__item_delegate)
        self.__horizontal_list.verticalScrollBar().setEnabled(False)
        self.__horizontal_list.setContextMenuPolicy(Qt.CustomContextMenu)

        self.__layout_manager = QVBoxLayout(self)
        self.__layout_ui()

        # Connect signals to slots
        self.__horizontal_list.doubleClicked.connect(
            self.__playlist_double_clicked)
        self.__horizontal_list.customContextMenuRequested.connect(
            self.__show_context_menu)

    def __layout_ui(self):
        # Set up horizontal list
        self.__horizontal_list.setFlow(QListView.LeftToRight)
        self.__horizontal_list.setMinimumHeight(235)
        self.__horizontal_list.setSpacing(20)
        self.__layout_manager.addWidget(self.__horizontal_list)

    def model(self) -> PlaylistModel:
        return self.__model

    @QtCore.pyqtSlot(QModelIndex)
    def __playlist_double_clicked(self, index: QModelIndex):
        """
        Slot that connects to the doubleClicked signal

        Should either display contents of the playlist or allow for playlist creation (index dependent)
        :index: Index that was clicked
        """
        should_create_playlist = (index.row() != self.__model.rowCount() - 1)
        if should_create_playlist:
            # Didn't click last index (create playlist), should display contents
            self.should_display_playlist.emit(
                self.__model.at(index.row()).playlist_id)
        else:
            self.__model.create_new_playlist()

    @QtCore.pyqtSlot(QModelIndex)
    def __handle_playlist_rename(self, index: QModelIndex):
        """
        Allows the user to rename the playlist at index
        """
        playlist = self.__model.at(index.row())
        rename_dialog = RenamePlaylistDialog(self, playlist)
        if rename_dialog.exec() == QDialog.Accepted:
            # Rename successfully requested
            new_playlist_name = rename_dialog.get_new_name()
            rename_playlist(cursor, connection, playlist.playlist_id,
                            new_playlist_name)
            self.relayout()

    @QtCore.pyqtSlot(QPoint)
    def __show_context_menu(self, pos: QPoint):
        """
        Displays a context menu of user choices on a right-click

        :param pos: Location where user clicked on the screen
        """

        index = self.__horizontal_list.indexAt(pos)

        if index.row() != -1 and index.row() != self.__model.rowCount(
        ) - 1:  # Must be a valid index and not create
            global_pos = self.__horizontal_list.mapToGlobal(pos)

            context_menu = QMenu(self)

            show_action = QAction("Show Playlist")
            show_action.triggered.connect(
                lambda: self.__playlist_double_clicked(index))

            rename_action = QAction("Rename Playlist")
            rename_action.triggered.connect(
                lambda: self.__handle_playlist_rename(index))

            del_action = QAction("Delete Playlist")
            del_action.triggered.connect(
                lambda: self.__horizontal_list.model().delete_playlist(index))

            context_menu.addAction(show_action)
            context_menu.addSeparator()
            context_menu.addAction(rename_action)
            context_menu.addAction(del_action)

            context_menu.exec(global_pos)
            del context_menu

    def relayout(self):
        """
        Refreshes the UI to reflect the state of the DB
        """
        playlists = get_all_user_playlists(cursor)
        self.__model.update_playlist(playlists)
Beispiel #12
0
class NameList(QDockWidget):
    def __init__(self, window):
        super(NameList, self).__init__('Current Plots')
        self.namelist_model = QStandardItemModel()
        self.namelist_view = QListView()
        self.namelist_view.setModel(self.namelist_model)
        self.setWidget(self.namelist_view)
        self.window = window
        self.plot_dict = {}

        self.namelist_view.doubleClicked.connect(self.activate_item)
        self.namelist_view.setContextMenuPolicy(QtConst.ActionsContextMenu)
        delete_action = QAction("Delete Selected", self.namelist_view)
        ###
        pause_action = QAction("Stop Script", self.namelist_view)
        delete_action.triggered.connect(self.delete_item)
        pause_action.triggered.connect(self.pause)
        self.namelist_view.addAction(delete_action)
        self.namelist_view.addAction(pause_action)

        open_action = QAction('Open 1D Data', self)
        open_action.triggered.connect(self.open_file_dialog)
        self.namelist_view.addAction(open_action)

        open_action_2 = QAction('Open 2D Data', self)
        open_action_2.triggered.connect(self.open_file_dialog_2)
        self.namelist_view.addAction(open_action_2)

    def open_file_dialog(self, directory='', header=0):
        file_path = self.file_dialog(directory=directory)

        header_array = []
        file_to_read = open(file_path, 'r')
        for i, line in enumerate(file_to_read):
            if i is header: break
            temp = line.split(":")
            header_array.append(temp)
        file_to_read.close()

        temp = np.genfromtxt(file_path,
                             dtype=float,
                             delimiter=',',
                             skip_header=1)
        data = np.transpose(temp)

        name_plot = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        pw = self.window.add_new_plot(1, name_plot)
        pw.plot(data[0], data[1], parametric=True, name=file_path, xname='X', xscale ='Arb. U.',\
         yname='Y', yscale ='Arb. u.', scatter='False')

    def open_file_dialog_2(self, directory='', header=0):
        file_path = self.file_dialog(directory=directory)

        header_array = []
        file_to_read = open(file_path, 'r')
        for i, line in enumerate(file_to_read):
            if i is header: break
            temp = line.split(":")
            header_array.append(temp)
        file_to_read.close()

        temp = np.genfromtxt(file_path, dtype=float, delimiter=',')
        data = temp

        name_plot = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
        pw = self.window.add_new_plot(2, name_plot)
        pw.setAxisLabels(xname='X', xscale ='Arb. U.',yname='X', yscale ='Arb. U.',\
            zname='X', zscale ='Arb. U.')
        pw.setImage(data, axes={'y': 0, 'x': 1})

    def file_dialog(self, directory=''):
        root = tkinter.Tk()
        root.withdraw()

        file_path = filedialog.askopenfilename(**dict(
            initialdir = directory,
            filetypes = [("CSV", "*.csv"), ("TXT", "*.txt"),\
            ("DAT", "*.dat"), ("all", "*.*")],
            title = 'Select file to open')
            )
        return file_path

    def activate_item(self, index):
        item = self.namelist_model.itemFromIndex(index)
        plot = self.plot_dict[str(item.text())]
        if plot.closed:
            plot.closed = False
            self.window.add_plot(plot)

    def delete_item(self):
        index = self.namelist_view.currentIndex()
        item = self.namelist_model.itemFromIndex(index)
        del self[str(item.text())]

    def pause(self):
        sock = socket.socket()
        sock.connect(('localhost', 9091))
        sock.send(b'Script stopped')
        sock.close()

    def __getitem__(self, item):
        return self.plot_dict[item]

    def __setitem__(self, name, plot):
        model = QStandardItem(name)
        model.setEditable(False)
        self.namelist_model.appendRow(model)
        self.plot_dict[name] = plot

    def __contains__(self, value):
        return value in self.plot_dict

    def __delitem__(self, name):
        self.namelist_model.removeRow(
            self.namelist_model.findItems(name)[0].index().row())
        self.plot_dict[name].close()
        del self.plot_dict[name]

    def keys(self):
        return list(self.plot_dict.keys())
Beispiel #13
0
class JsonEdit(QWidget):
    def __init__(self,
                 dataPath,
                 ico,
                 parent=None,
                 flags=Qt.WindowCloseButtonHint):
        super(JsonEdit, self).__init__(parent, flags)

        self.setStyleSheet(
            '''JsonEdit{background:#272626}QLabel{color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;}
                                QPushButton{border:0px;background:#4d4d4d;color:#ffffff;font-family: "Microsoft YaHei", SimHei, SimSun;font:11pt;}
                                QPushButton:pressed{background:#606162;font:10pt;}
                                QPushButton:checked{background:#70bbe4;}
                                QPushButton:hover{border-style:solid;border-width:1px;border-color:#ffffff;}
                                QLineEdit{background-color:#4d4d4d;color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;border:0px;padding-left:5px}
                                QLineEdit:hover{border-style:solid;border-width:1px;border-color:#ffffff;padding-left:4px;}
                                QListView{background-color:#4d4d4d;color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:12pt;}
                                QComboBox:hover{border-style:solid;border-width:1px;border-color:#ffffff;padding-left:4px;}
                                QComboBox{background-color:#4d4d4d;color:#ffffff;font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;padding-left:5px;border:0px;}
                                QComboBox:drop-down{width:0px;}
                                QComboBox:down-arrow{width:0px}
                                QComboBox:selected{background-color:#606162;}
                                QComboBox:QAbstractItemView::item{font-family:"Microsoft YaHei", SimHei, SimSun;font:11pt;}
                                QComboBox:QAbstractItemView::item:selected{background-color:#606162;}
                                QInputDialog{background-color:#272626;}
                                QScrollBar:vertical{width:8px;background:rgba(0,0,0,0%);margin:0px,0px,0px,0px;padding-top:0px;padding-bottom:0px;}
                                QScrollBar:handle:vertical{width:8px;background:rgba(0,0,0,25%);border-radius:0px;min-height:20;}
                                QScrollBar:handle:vertical:hover{width:8px;background:rgba(0,0,0,50%);border-radius:0px;min-height:20;}
                                QScrollBar:add-line:vertical{height:0px;width:0px;subcontrol-position:bottom;}
                                QScrollBar:sub-line:vertical{height:0px;width:0px;subcontrol-position:top;}
                                QScrollBar:add-page:vertical,QScrollBar:sub-page:vertical{background:rgba(0,0,0,10%);border-radius:0px;}
                                QScrollBar:horizontal{height:8px;background:rgba(0,0,0,0%);margin:0px,0px,0px,0px;padding-top:0px;padding-bottom:0px;}
                                QScrollBar:handle:horizontal{width:8px;background:rgba(0,0,0,25%);border-radius:0px;min-height:20;}
                                QScrollBar:handle:horizontal:hover{width:8px;background:rgba(0,0,0,50%);border-radius:0px;min-height:20;}
                                QScrollBar:add-line:horizontal{height:0px;width:0px;subcontrol-position:bottom;}
                                QScrollBar:sub-line:horizontal{height:0px;width:0px;subcontrol-position:top;}
                                QScrollBar:add-page:horizontal,QScrollBar:sub-page:horizontal{background:rgba(0,0,0,10%);border-radius:0px;}'''
        )

        self.setWindowIcon(QIcon(ico))
        self.isshow = False

        self.isBootyMode = False
        self.bootyName = '固源岩'

        self.selPanel = BootyChoice(self, ico)

        self.json = dataPath + '/schedule.json'
        self.scheduleAdd = {
            'part': 'MAIN',
            'chap': '',
            'objLevel': '',
            'times': ''
        }
        self.transEX = {
            'ex1': '切尔诺伯格',
            'ex2': '龙门外环',
            'ex3': '龙门市区',
            'ex4': '当期委托'
        }

        self.partList = ['主线', '物资筹备', '芯片搜索', '剿灭作战']
        self.partListJson = ['MAIN', 'RS', 'PR', 'EX']
        self.mainChapList = [
            '序章', '第一章', '第二章', '第三章', '第四章', '第五章', '第六章', '第七章', '第八章'
        ]
        self.rsChapList = ['战术演习', '粉碎防御', '空中威胁', '货物运送', '资源保障']
        self.prChapList = ['医疗重装', '术士狙击', '辅助先锋', '特种近卫']
        self.exChapList = ['切尔诺伯格', '龙门外环', '龙门市区', '当期委托']
        self.chapList = [
            self.mainChapList, self.rsChapList, self.prChapList,
            self.exChapList
        ]

        self.selIndex = None

        self.grid = QGridLayout()
        self.lsv = QListView()  #计划显示框
        self.lsv.setFixedWidth(200)
        self.lsv.clicked.connect(self.clickSchedule)
        self.lsv.setContextMenuPolicy(Qt.CustomContextMenu)
        self.lsv.customContextMenuRequested.connect(self.lsvRearrange)
        self.actMoveUp = QAction('上移')
        self.actMoveUp.triggered.connect(self.moveUpLine)
        self.actMoveDown = QAction('下移')
        self.actMoveDown.triggered.connect(self.moveDownLine)
        self.actEdit = QAction('修改次数/个数')
        self.actEdit.triggered.connect(self.editLine)
        self.actDel = QAction('删除')
        self.actDel.triggered.connect(self.delLine)

        self.slm = QStringListModel()

        self.partCb = QComboBox()
        self.partCb.addItems(self.partList)
        self.partCb.activated[int].connect(self.changeChapList)
        self.partCb.setFixedSize(80, 40)
        self.partCb.setView(QListView())

        self.chapCb = QComboBox()
        self.chapCb.addItems(self.mainChapList)
        self.chapCb.activated[int].connect(self.changeLevel1List)
        self.chapCb.setFixedSize(100, 40)
        self.chapCb.setView(QListView())

        self.level1Cb = QComboBox()
        self.level1Cb.setFixedSize(60, 40)
        self.level1Cb.setView(QListView())

        self.lineLable = QLabel()
        self.lineLable.setText('-')

        self.level2Edit = QLineEdit()
        self.level2Edit.setFixedSize(50, 40)

        self.timesLable = QLabel()
        self.timesLable.setText('次数:')

        self.timeEdit = QLineEdit()
        self.timeEdit.setFixedSize(50, 40)

        self.bootyModeBtn = QPushButton()
        self.bootyModeBtn.setCheckable(True)
        self.bootyModeBtn.setText('素材模式')
        self.bootyModeBtn.setFixedHeight(40)
        self.bootyModeBtn.clicked[bool].connect(self.setBootMode)

        self.bootySelBtn = QPushButton()
        self.bootySelBtn.setText('——')
        self.bootySelBtn.setFixedHeight(40)
        self.bootySelBtn.clicked.connect(self.selPanel.myShow)

        self.delBtn = QPushButton()
        self.delBtn.setText('删除')
        self.delBtn.clicked.connect(self.delLine)
        self.delBtn.setFixedHeight(40)
        self.clearBtn = QPushButton()
        self.clearBtn.setText('清空')
        self.clearBtn.clicked.connect(self.clearLine)
        self.clearBtn.setFixedHeight(40)

        self.addBtn = QPushButton()
        self.addBtn.setText('添加')
        self.addBtn.clicked.connect(self.addLine)
        self.addBtn.setFixedHeight(40)

        self.planCb = QComboBox()
        self.planCb.setFixedSize(200, 40)
        self.planCb.setView(QListView())

        self.loadPlanBtn = QPushButton()
        self.loadPlanBtn.setText('加载配置')
        self.loadPlanBtn.setFixedHeight(40)
        self.loadPlanBtn.clicked.connect(self.loadPlan)

        self.addPlanBtn = QPushButton()
        self.addPlanBtn.setText('以当前配置新建')
        self.addPlanBtn.setFixedHeight(40)
        self.addPlanBtn.clicked.connect(self.addPlan)

        self.delPlanBtn = QPushButton()
        self.delPlanBtn.setText('删除此配置')
        self.delPlanBtn.setFixedHeight(40)
        self.delPlanBtn.clicked.connect(self.delPlan)

        self.listScheduleBefore = []
        self.listSchedule = []
        self.initJson()
        self.slm.setStringList(self.listSchedule)
        self.lsv.setModel(self.slm)
        self.lsv.setEditTriggers(QListView.NoEditTriggers)

        self.changeLevel1List(0)

        self.grid.addWidget(self.lsv, 0, 0, 3, 1)
        self.grid.addWidget(self.partCb, 0, 1, 1, 1)
        self.grid.addWidget(self.chapCb, 0, 2, 1, 1)
        self.grid.addWidget(self.level1Cb, 0, 3, 1, 1)
        self.grid.addWidget(self.lineLable, 0, 4, 1, 1)
        self.grid.addWidget(self.level2Edit, 0, 5, 1, 1)
        self.grid.addWidget(self.timesLable, 0, 6, 1, 1)
        self.grid.addWidget(self.timeEdit, 0, 7, 1, 1)
        self.grid.addWidget(self.bootyModeBtn, 1, 1, 1, 1)
        self.grid.addWidget(self.bootySelBtn, 1, 2, 1, 1)
        self.grid.addWidget(self.addBtn, 1, 3, 1, 5)
        self.grid.addWidget(self.delBtn, 2, 1, 1, 4)
        self.grid.addWidget(self.clearBtn, 2, 5, 1, 3)
        self.grid.addWidget(self.planCb, 3, 0, 1, 1)
        self.grid.addWidget(self.loadPlanBtn, 3, 1, 1, 1)
        self.grid.addWidget(self.addPlanBtn, 3, 2, 1, 3)
        self.grid.addWidget(self.delPlanBtn, 3, 5, 1, 3)

        self.setLayout(self.grid)

        self.setWindowTitle('路线规划')
        #self.resize(600,400)

        self.myTimer()
        #self.show()

    def editerShow(self):
        if not self.isVisible():
            self.show()
            cp = QDesktopWidget().availableGeometry().center()
            self.move(int(cp.x() - self.width() / 2),
                      int(cp.y() - self.height() / 2))

    def myTimer(self):
        self.updateTimer = QTimer()
        self.updateTimer.timeout.connect(self.updateList)
        self.updateTimer.start(10)

    def lsvRearrange(self):
        self.selIndex = self.lsv.currentIndex().row()
        rightClickMeun = QMenu()
        rightClickMeun.setStyleSheet(
            '''QMenu {color:#ffffff;font-family: "Microsoft YaHei", SimHei, SimSun;font:10pt;
                                        background-color:#272626; margin:3px;}
                                        QMenu:item {padding:8px 32px;}
                                        QMenu:item:selected { background-color: #3f4140;}
                                        QMenu:icon{padding: 8px 20px;}
                                        QMenu:separator{background-color: #7C7C7C; height:1px; margin-left:2px; margin-right:2px;}'''
        )
        rightClickMeun.addAction(self.actMoveUp)
        rightClickMeun.addAction(self.actMoveDown)
        rightClickMeun.addAction(self.actEdit)
        rightClickMeun.addAction(self.actDel)
        rightClickMeun.exec_(QCursor.pos())

    def initJson(self):
        with open(self.json, 'r', encoding='UTF-8') as s:
            data = s.read()
        self.jsonAll = loads(data)["main"]
        self.selPlan = self.jsonAll[0]
        self.allPlanList = self.selPlan['allplan'].split('|')

        #配置选单显示
        self.planCb.addItems(self.allPlanList)

        self.jsonDict = self.jsonAll[0]['sel']
        self.selList = self.jsonDict.copy()
        self.refreshJsonView()

    def refreshJsonView(self):
        self.listSchedule = []
        for eachDict in self.selList:
            temp = eachDict['objLevel']
            if 'ex' in temp:
                temp = self.transEX[temp]
            if eachDict['chap'] == 'LS':
                temp = temp.replace('S', 'LS')
            if isinstance(eachDict['times'], dict):
                self.listSchedule.append('{0}({1}共{2}个)'.format(
                    temp, eachDict['times']['bootyName'],
                    eachDict['times']['bootyNum']))
            else:
                self.listSchedule.append('{0}(共{1}次)'.format(
                    temp, eachDict['times']))

    def updateJson(self):
        self.jsonAll[0]['sel'] = self.selList.copy()
        self.jsonAll[0]['allplan'] = '|'.join(self.allPlanList)
        #self.jsonAll[0]['selno'] = str(self.selNo)
        tempNewJson = {'main': self.jsonAll}
        newData = dumps(tempNewJson,
                        sort_keys=True,
                        indent=4,
                        separators=(',', ': '),
                        ensure_ascii=False)
        with open(self.json, 'w', encoding='UTF-8') as j:
            j.write(newData)

    def updateList(self):
        if self.listSchedule != self.listScheduleBefore:
            self.listScheduleBefore = self.listSchedule.copy()
            self.slm.setStringList(self.listSchedule)
            self.updateJson()

    def changeChapList(self, indexI):
        self.scheduleAdd['part'] = self.partListJson[indexI]
        self.chapCb.clear()
        self.chapCb.addItems(self.chapList[indexI])
        self.changeLevel1List(0)

    def changeLevel1List(self, indexI):
        self.level1Cb.clear()
        selChap = self.chapCb.currentText()
        self.level2Edit.setReadOnly(False)
        levelList = []
        if '章' in selChap:
            self.scheduleAdd['chap'] = str(int(indexI))
            if int(indexI) != 8:
                levelList.append(f'{int(indexI)}')
            if int(indexI) != 0 and int(indexI) != 1:
                if int(indexI) != 8:
                    levelList.append(f'S{int(indexI)}')
                elif int(indexI) == 8:
                    levelList.extend([
                        f'R{int(indexI)}', f'M{int(indexI)}',
                        f'JT{int(indexI)}'
                    ])

        elif selChap == '战术演习':
            self.scheduleAdd['chap'] = 'LS'
            levelList.append('LS')

        elif selChap == '粉碎防御':
            self.scheduleAdd['chap'] = 'AP'
            levelList.append('AP')

        elif selChap == '空中威胁':
            self.scheduleAdd['chap'] = 'CA'
            levelList.append('CA')

        elif selChap == '货物运送':
            self.scheduleAdd['chap'] = 'CE'
            levelList.append('CE')

        elif selChap == '资源保障':
            self.scheduleAdd['chap'] = 'SK'
            levelList.append('SK')

        elif selChap == '医疗重装':
            self.scheduleAdd['chap'] = 'A'
            levelList.append('PR-A')

        elif selChap == '术士狙击':
            self.scheduleAdd['chap'] = 'B'
            levelList.append('PR-B')

        elif selChap == '辅助先锋':
            self.scheduleAdd['chap'] = 'C'
            levelList.append('PR-C')

        elif selChap == '特种近卫':
            self.scheduleAdd['chap'] = 'D'
            levelList.append('PR-D')

        else:
            if selChap == '切尔诺伯格':
                self.scheduleAdd['chap'] = 'external'
                self.scheduleAdd['objLevel'] = 'ex1'
            elif selChap == '龙门外环':
                self.scheduleAdd['chap'] = 'external'
                self.scheduleAdd['objLevel'] = 'ex2'
            elif selChap == '龙门市区':
                self.scheduleAdd['chap'] = 'external'
                self.scheduleAdd['objLevel'] = 'ex3'
            elif selChap == '当期委托':
                self.scheduleAdd['chap'] = 'external'
                self.scheduleAdd['objLevel'] = 'ex4'

            self.level2Edit.clear()
            self.level2Edit.setReadOnly(True)

        self.level1Cb.addItems(levelList)

    def addLine(self):
        tempLevel = self.level2Edit.text()
        if 'EX' != self.scheduleAdd['part']:
            self.scheduleAdd['objLevel'] = ''
        tempTimes = self.timeEdit.text()
        self.scheduleAdd['times'] = ''
        if tempLevel != '':
            part1 = self.level1Cb.currentText()
            if part1 == 'LS':
                part1 = 'S'
            if tempLevel.isdecimal():
                self.scheduleAdd['objLevel'] = part1 + '-' + tempLevel
        if tempTimes.isdecimal():
            if self.isBootyMode:
                self.scheduleAdd['times'] = {
                    'bootyName': self.bootyName,
                    'bootyNum': tempTimes
                }
            else:
                self.scheduleAdd['times'] = tempTimes
        if self.scheduleAdd['objLevel'] != '' and self.scheduleAdd[
                'times'] != '':
            self.selList.append(self.scheduleAdd.copy())
            self.refreshJsonView()

    def clickSchedule(self, qModelIndex):
        self.selIndex = qModelIndex.row()

    def delLine(self):
        if self.selIndex != None:
            self.listSchedule.pop(self.selIndex)
            self.selList.pop(self.selIndex)
        self.selIndex = None

    def moveUpLine(self):
        if self.selIndex != 0 and self.selIndex != None:
            #temp = self.listSchedule[self.selIndex - 1]
            self.listSchedule[self.selIndex - 1], self.listSchedule[self.selIndex] = \
                                            self.listSchedule[self.selIndex], self.listSchedule[self.selIndex - 1]
            self.selList[self.selIndex - 1], self.selList[self.selIndex] = \
                                            self.selList[self.selIndex], self.selList[self.selIndex - 1]
        self.selIndex = None

    def moveDownLine(self):
        if self.selIndex != (len(self.listSchedule) -
                             1) and self.selIndex != None:
            #temp = self.listSchedule[self.selIndex - 1]
            self.listSchedule[self.selIndex + 1], self.listSchedule[self.selIndex] = \
                                            self.listSchedule[self.selIndex], self.listSchedule[self.selIndex + 1]
            self.selList[self.selIndex + 1], self.selList[self.selIndex] = \
                                            self.selList[self.selIndex], self.selList[self.selIndex + 1]
        self.selIndex = None

    def editLine(self):
        if self.selIndex != None:
            if isinstance(self.selList[self.selIndex]['times'], dict):
                newNum, isOk = QInputDialog.getText(self, '修改', '请输入新的掉落物个数')
                if isOk:
                    self.selList[self.selIndex]['times']['bootyNum'] = newNum
            else:
                newNum, isOk = QInputDialog.getText(self, '修改', '请输入新的次数')
                self.selList[self.selIndex]['times'] = newNum
            self.refreshJsonView()
        self.selIndex = None

    def clearLine(self):
        self.listSchedule.clear()
        self.selList.clear()

    def loadPlan(self):
        if self.planCb.currentIndex() != 0:
            self.jsonDict = self.jsonAll[self.planCb.currentIndex() + 1][
                self.allPlanList[self.planCb.currentIndex()]]
            self.selList = self.jsonDict.copy()
            self.refreshJsonView()

    def addPlan(self):
        planName, ok = QInputDialog.getText(self, '配置名称', '请输入配置名称:')
        if ok:
            if '|' in planName:
                planName.replace('|', '·')
            self.allPlanList.append(planName)
            tempDict = dict()
            tempDict[planName] = self.selList.copy()
            self.jsonAll.append(tempDict)
            self.updateJson()
            self.planCb.clear()
            self.planCb.addItems(self.allPlanList)

    def delPlan(self):
        if self.planCb.currentIndex() != 0:
            self.allPlanList.pop(self.planCb.currentIndex())
            self.jsonAll.pop(self.planCb.currentIndex() + 1)
            self.updateJson()
            self.planCb.clear()
            self.planCb.addItems(self.allPlanList)

    def setBootMode(self, isChecked):
        self.isBootyMode = isChecked
        if self.isBootyMode:
            self.timesLable.setText('个数:')
            self.bootySelBtn.setText('选择掉落物')
        else:
            self.timesLable.setText('次数:')
            self.bootySelBtn.setText('———')

    def test(self):
        self.listSchedule.append('add')
        print(self.listSchedule)