예제 #1
0
class MP3TagManipulator(QWidget):
    last_directory = '.'
    song = None

    def __init__(self):
        super().__init__()
        self.title = 'MP3TagManipulator v1.0'
        self.top = 100
        self.left = 100
        self.height = 400
        self.width = 640

        self.init_ui()

    def init_ui(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.top, self.left, self.width, self.height)

        # layout root of application
        main_layout = QVBoxLayout(self)
        self.setLayout(main_layout)

        # to set the model of tree
        model = QFileSystemModel()
        model.setRootPath("/home/denison/Downloads/music")
        model.setNameFilters(['*.mp3', '*.m4a', '*.flac'])
        model.setNameFilterDisables(False)

        self.tree = QTreeView()
        self.tree.setModel(model)
        self.tree.setAnimated(True)
        self.tree.setColumnWidth(0, 500)

        file_layout = QHBoxLayout()
        label_file = QLabel('file/directory')
        text_file = QLineEdit()
        btn_load = QPushButton('load')
        file_layout.addWidget(label_file)
        file_layout.addWidget(text_file)
        file_layout.addWidget(btn_load)

        grid_info_layout = QGridLayout()
        # strings to labels
        self.labels = [
            'ARTIST', 'ALBUMARTIST', 'ALBUM', 'TITLE', 'GENRE', 'DATE'
        ]

        # line edits to tags
        self.text_artist = QLineEdit('ARTIST')
        self.text_album = QLineEdit('ALBUM')
        self.text_album_artist = QLineEdit('ALBUMARTIST')
        self.text_title = QLineEdit('TITLE')
        self.text_genre = QLineEdit('GENRE')
        self.text_date = QLineEdit('DATE')

        self.text_tags = [
            self.text_artist, self.text_album_artist, self.text_album,
            self.text_title, self.text_genre, self.text_date
        ]

        for text in self.text_tags:
            text.setEnabled(False)
            #text.textChanged.connect(self.enable_save)

        # labels
        for label, i in zip(self.labels, range(6)):
            grid_info_layout.addWidget(QLabel(label), i, 0)

        # cb_artist = QCheckBox()
        # cb_album_artist = QCheckBox()
        # cb_album = QCheckBox()
        # cb_title = QCheckBox()
        # cb_genre = QCheckBox()
        # cb_date = QCheckBox()
        # self.checkboxes = [
        #     cb_artist, cb_album_artist, cb_album,
        #     cb_title, cb_genre, cb_date
        # ]

        # for cb in self.checkboxes:
        #     cb.setText('editar')

        # cb_artist.stateChanged.connect(lambda: self.enable_tag_edit(self.text_artist))
        # cb_album_artist.stateChanged.connect(lambda: self.enable_tag_edit(self.text_album_artist))
        # cb_album.stateChanged.connect(lambda: self.enable_tag_edit(self.text_album))
        # cb_title.stateChanged.connect(lambda: self.enable_tag_edit(self.text_title))
        # cb_genre.stateChanged.connect(lambda: self.enable_tag_edit(self.text_genre))
        # cb_date.stateChanged.connect(lambda: self.enable_tag_edit(self.text_date))

        for i, text in zip(range(6), self.text_tags):
            grid_info_layout.addWidget(text, i, 1)

        # for cb, i in zip(self.checkboxes, range(6)) :
        #     grid_info_layout.addWidget(cb, i, 2)

        action_layout = QHBoxLayout()
        btn_exit = QPushButton('Exit')
        self.btn_save = QPushButton('save changes')
        self.btn_save.setDisabled(True)
        action_layout.addWidget(btn_exit)
        action_layout.addWidget(self.btn_save)

        #main_layout.addLayout(file_layout)
        main_layout.addWidget(self.tree)
        main_layout.addLayout(grid_info_layout)
        main_layout.addLayout(action_layout)

        btn_load.clicked.connect(self.open_file)
        btn_exit.clicked.connect(self.close_application)
        self.btn_save.clicked.connect(self.edit_tags)
        self.tree.doubleClicked.connect(self.get_selected_file)
        self.show()

    def enable_edit_text(self):
        if self.song:
            for t in self.text_tags:
                t.setEnabled(True)
            self.enable_save()
        else:
            for t in self.text_tags:
                t.setEnabled(False)

    def enable_save(self):
        self.btn_save.setEnabled(True)

    def close_application(self):
        if self.song:
            self.song.close()
        print('vazando...;-)')
        self.close()

    def enable_tag_edit(self, txt_edit):
        txt_edit.setEnabled(not txt_edit.isEnabled())
        for edit in self.text_tags:
            edit.textChanged.connect(self.enable_save)
        print('executou self.enable_tag_edit()')
        print('não sei o q tá acontecendo :(')

    def get_selected_file(self):
        print('executou self.get_selected_file()')
        selected = self.tree.selectedIndexes()[0]
        print(selected.model().filePath(selected))
        self.song = taglib.File(selected.model().filePath(selected))
        self.enable_edit_text()
        self.load_song_info(self.song)
        return self.song

    def edit_tags(self):
        print("não tá funcionando 8'-(")
        self.song.tags['ARTIST'] = self.text_artist.text()
        self.song.tags['ALBUMARTIST'] = self.text_album_artist.text()
        self.song.tags['ALBUM'] = self.text_album.text()
        self.song.tags['TITLE'] = self.text_title.text()
        self.song.tags['GENRE'] = self.text_genre.text()
        self.song.tags['DATE'] = self.text_date.text()
        self.song.save()
        print(self.song.tags)
        self.btn_save.setDisabled(True)
        self.song.close()

    def open_file(self):
        print('*** quase lá *** ')
        dialog = QFileDialog(self)
        dialog.setViewMode(QFileDialog.Detail)
        file = dialog.getOpenFileName(self, 'load...', self.last_directory,
                                      'songs (*.mp3 *.m4a *.flac *.wma)')
        song = taglib.File(file[0])
        # print(song.tags)
        self.show_song_info(song)
        song.close()

    def load_song_info(self, song):
        print('executou self.load_song_info()')
        for t, tag in zip(self.text_tags, self.labels):
            try:
                t.setText(song.tags[tag][0])
            except KeyError:
                t.setText('none')
예제 #2
0
파일: main.py 프로젝트: mattdoiron/idfplus
    def create_ui(self):
        """Setup main UI elements, dock widgets, UI-related elements, etc.
        """

        log.debug('Loading UI')

        # Undo Stack
        self.undo_stack = QUndoStack(self)
        self.undo_stack.setUndoLimit(100)

        # Object navigation history
        self.obj_history = deque([], config.MAX_OBJ_HISTORY)

        app = QApplication.instance()
        base_font = QFont()
        base_font.fromString(self.prefs['base_font'])
        app.setFont(base_font)

        # Object class table widget
        # classTable = QTableView(self)
        classTable = classtable.TableView(self)
        classTable.setObjectName("classTable")
        classTable.setAlternatingRowColors(True)
        classTable.setFrameShape(QFrame.StyledPanel)
        classTable_font = QFont()
        classTable_font.fromString(self.prefs['class_table_font'])
        classTable.setFont(classTable_font)
        fm = classTable.fontMetrics()
        classTable.setWordWrap(True)
        classTable.setEditTriggers(QAbstractItemView.EditKeyPressed |
                                   QAbstractItemView.DoubleClicked |
                                   QAbstractItemView.AnyKeyPressed |
                                   QAbstractItemView.SelectedClicked)
        # classTable.horizontalHeader().setMovable(True)
        # classTable.verticalHeader().setMovable(False)
        classTable.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
        classTable.verticalHeader().setSectionResizeMode(QHeaderView.Interactive)
        classTable.horizontalHeader().setDefaultSectionSize(self.prefs['default_column_width'])
        classTable.verticalHeader().setDefaultSectionSize(fm.height() + 0)
        classTable.setSelectionMode(QAbstractItemView.ExtendedSelection)
        classTable.setContextMenuPolicy(Qt.CustomContextMenu)
        classTable.customContextMenuRequested.connect(self.custom_table_context_menu)

        # Create table model and proxy layers for transposing and filtering
        self.classTableModel = classtable.IDFObjectTableModel(classTable)
        self.transposeableModel = classtable.TransposeProxyModel(self.classTableModel)
        self.transposeableModel.setSourceModel(self.classTableModel)
        self.sortableModel = classtable.SortFilterProxyModel(self.transposeableModel)
        self.sortableModel.setSourceModel(self.transposeableModel)

        # Assign model to table (enable sorting FIRST)
        # table.setSortingEnabled(True) # Disable for now, CRUD actions won't work!
        classTable.setModel(self.sortableModel)

        # Connect some signals
        selection_model = classTable.selectionModel()
        selection_model.selectionChanged.connect(self.table_selection_changed)
        scroll_bar = classTable.verticalScrollBar()
        scroll_bar.valueChanged.connect(self.scroll_changed)

        # These are currently broken
        # classTable.horizontalHeader().sectionMoved.connect(self.moveObject)
        # classTable.verticalHeader().sectionMoved.connect(self.moveObject)

        # Object class tree widget
        classTreeDockWidget = QDockWidget("Object Classes and Counts", self)
        classTreeDockWidget.setObjectName("classTreeDockWidget")
        classTreeDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)

        classTree = QTreeView(classTreeDockWidget)
        classTree.setUniformRowHeights(True)
        classTree.setAllColumnsShowFocus(True)
        classTree.setRootIsDecorated(False)
        classTree.setExpandsOnDoubleClick(True)
        classTree.setIndentation(15)
        classTree.setAnimated(True)
        classTree_font = QFont()
        classTree_font.fromString(self.prefs['class_tree_font'])
        classTree.setFont(classTree_font)
        classTree.setAlternatingRowColors(True)
        classTree.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
        palette = classTree.palette()
        palette.setColor(QPalette.Highlight, Qt.darkCyan)
        classTree.setPalette(palette)

        class_tree_window = QWidget(classTreeDockWidget)
        class_tree_dock_layout_v = QVBoxLayout()
        class_tree_dock_layout_h = QHBoxLayout()
        class_tree_dock_layout_v.setContentsMargins(0, 8, 0, 0)
        class_tree_dock_layout_h.setContentsMargins(0, 0, 0, 0)

        class_tree_filter_edit = QLineEdit(classTreeDockWidget)
        class_tree_filter_edit.setPlaceholderText("Filter Classes")
        class_tree_filter_edit.textChanged.connect(self.treeFilterRegExpChanged)

        class_tree_filter_cancel = QPushButton("Clear", classTreeDockWidget)
        class_tree_filter_cancel.setMaximumWidth(45)
        class_tree_filter_cancel.clicked.connect(self.clearTreeFilterClicked)

        class_tree_dock_layout_h.addWidget(class_tree_filter_edit)
        class_tree_dock_layout_h.addWidget(class_tree_filter_cancel)
        class_tree_dock_layout_v.addLayout(class_tree_dock_layout_h)
        class_tree_dock_layout_v.addWidget(classTree)
        class_tree_window.setLayout(class_tree_dock_layout_v)

        classTreeDockWidget.setWidget(class_tree_window)
        classTreeDockWidget.setContentsMargins(0,0,0,0)

        # Comments widget
        commentDockWidget = QDockWidget("Comments", self)
        commentDockWidget.setObjectName("commentDockWidget")
        commentDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        commentView = UndoRedoTextEdit(commentDockWidget, self)
        commentView.setLineWrapMode(QTextEdit.FixedColumnWidth)
        commentView.setLineWrapColumnOrWidth(499)
        commentView.setFrameShape(QFrame.StyledPanel)
        commentView_font = QFont()
        commentView_font.fromString(self.prefs['comments_font'])
        commentView.setFont(commentView_font)
        commentDockWidget.setWidget(commentView)

        # Info and help widget
        infoDockWidget = QDockWidget("Info", self)
        infoDockWidget.setObjectName("infoDockWidget")
        infoDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        infoView = QTextEdit(infoDockWidget)
        infoView.setFrameShape(QFrame.StyledPanel)
        infoView.setReadOnly(True)
        infoDockWidget.setWidget(infoView)

        # Node list and jump menu widget
        refDockWidget = QDockWidget("Field References", self)
        refDockWidget.setObjectName("refDockWidget")
        refDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        ref_model = reftree.ReferenceTreeModel(None, refDockWidget)
        refView = QTreeView(refDockWidget)
        refView.setModel(ref_model)
        refView.setUniformRowHeights(True)
        refView.setRootIsDecorated(False)
        refView.setIndentation(15)
        refView.setColumnWidth(0, 160)
        refView.setFrameShape(QFrame.StyledPanel)
        refDockWidget.setWidget(refView)
        refView.doubleClicked.connect(self.ref_tree_double_clicked)

        # Logging and debugging widget
        logDockWidget = QDockWidget("Log Viewer", self)
        logDockWidget.setObjectName("logDockWidget")
        logDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        logView = QPlainTextEdit(logDockWidget)
        logView.setLineWrapMode(QPlainTextEdit.NoWrap)
        logView.setReadOnly(True)
        logView_font = QFont()
        logView_font.fromString(self.prefs['base_font'])
        logView.setFont(logView_font)
        logView.ensureCursorVisible()
        logDockWidget.setWidget(logView)

        # Undo view widget
        undoDockWidget = QDockWidget("Undo History", self)
        undoDockWidget.setObjectName("undoDockWidget")
        undoDockWidget.setAllowedAreas(Qt.AllDockWidgetAreas)
        undoView = QUndoView(self.undo_stack)
        undoDockWidget.setWidget(undoView)

        # Define corner docking behaviour
        self.setDockNestingEnabled(True)
        self.setCorner(Qt.TopLeftCorner,
                       Qt.LeftDockWidgetArea)
        self.setCorner(Qt.TopRightCorner,
                       Qt.RightDockWidgetArea)
        self.setCorner(Qt.BottomLeftCorner,
                       Qt.LeftDockWidgetArea)
        self.setCorner(Qt.BottomRightCorner,
                       Qt.RightDockWidgetArea)

        # Assign main widget and dock widgets to QMainWindow
        self.setCentralWidget(classTable)
        self.addDockWidget(Qt.LeftDockWidgetArea, classTreeDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, commentDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, infoDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, refDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, logDockWidget)
        self.addDockWidget(Qt.RightDockWidgetArea, undoDockWidget)

        # Store widgets for access by other objects
        self.classTable = classTable
        self.commentView = commentView
        self.infoView = infoView
        self.classTree = classTree
        self.logView = logView
        self.undoView = undoView
        self.refView = refView
        self.filterTreeBox = class_tree_filter_edit

        # Store docks for access by other objects
        self.commentDockWidget = commentDockWidget
        self.infoDockWidget = infoDockWidget
        self.classTreeDockWidget = classTreeDockWidget
        self.logDockWidget = logDockWidget
        self.undoDockWidget = undoDockWidget
        self.refDockWidget = refDockWidget

        # Perform other UI-related initialization tasks
        self.center()
        self.setUnifiedTitleAndToolBarOnMac(True)
        self.setWindowIcon(QIcon(':/images/logo.png'))

        # Status bar setup
        self.statusBar().showMessage('Status: Ready')
        self.unitsLabel = QLabel()
        self.unitsLabel.setAlignment(Qt.AlignCenter)
        self.unitsLabel.setMinimumSize(self.unitsLabel.sizeHint())
        self.unitsLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.unitsLabel)
        self.pathLabel = QLabel()
        self.pathLabel.setAlignment(Qt.AlignCenter)
        self.pathLabel.setMinimumSize(self.pathLabel.sizeHint())
        self.pathLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.pathLabel)
        self.versionLabel = QLabel()
        self.versionLabel.setAlignment(Qt.AlignCenter)
        self.versionLabel.setMinimumSize(self.versionLabel.sizeHint())
        self.versionLabel.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
        self.statusBar().addPermanentWidget(self.versionLabel)
        self.progressBarIDF = QProgressBar()
        self.progressBarIDF.setAlignment(Qt.AlignCenter)
        self.progressBarIDF.setMaximumWidth(200)
        self.statusBar().addPermanentWidget(self.progressBarIDF)

        self.clipboard = QApplication.instance().clipboard()
        self.obj_clipboard = []

        self.setStyleSheet("""
            QToolTip {
               background-color: gray;
               color: white;
               border: black solid 1px
            } 
            # QMenu {
            #     background-color: rgbf(0.949020, 0.945098, 0.941176);
            #     color: rgb(255,255,255);
            # }
            # QMenu::item::selected {
            #     background-color: rgbf(0.949020, 0.945098, 0.941176);
            # }
            """)
예제 #3
0
class Dock(QDockWidget):
    def __init__(self, title, central_widget, parent=None):
        super().__init__(title, parent=parent)
        self.central_widget = central_widget

        self.model = QFileSystemModel()
        self.model.setRootPath(QDir.currentPath())
        self.tree = QTreeView()
        self.tree.pressed.connect(self.setIndex)
        self.index_ = None

        self.db_tree = QTreeView()
        self.db_tree.setAnimated(True)
        self.db_model = QStandardItemModel()
        self.db_model.setHorizontalHeaderLabels(["Database"])
        self.db_root = self.db_model.invisibleRootItem()

        self.dbs = []

    def contextMenuEvent(self, event):
        contextMenu = QMenu(self)
        deleteFile = contextMenu.addAction("Delete File")
        action = contextMenu.exec_(self.mapToGlobal(event.pos()))
        if action == deleteFile:
            alert = QMessageBox()
            alert.setWindowTitle("Action Dialog")
            alert.setText("Are you sure you want to delete this file?")
            alert.setStandardButtons(QMessageBox.No | QMessageBox.Yes)
            alert.setDefaultButton(QMessageBox.No)
            response = alert.exec_()
            if response == QMessageBox.No:
                contextMenu.close()
            else:
                file_name = self.model.filePath(
                    self.index_).split("storage/")[1]
                os.remove(self.model.filePath(self.index_))
                os.remove(
                    self.model.filePath(self.index_).split("/storage")[0] +
                    "/meta/" + file_name + "_metadata.json")
                contextMenu.close()

    def setIndex(self, index):
        self.index_ = index

    def tree_init(self):
        self.tree.setModel(self.model)
        self.tree.setRootIndex(
            self.model.index(QDir.currentPath() + "/model/storage"))

        self.tree.clicked.connect(self.file_clicked)

        self.setWidget(self.tree)

    def init_db_tree(self):
        self.clear_tree()
        self.db_tree.setModel(self.db_model)
        self.db_tree.clicked.connect(self.table_clicked)
        self.setWidget(self.db_tree)
        self.connected_dbs()

    def file_clicked(self, index):
        file_path = self.model.filePath(index)
        workspace = Workspace(file_path, self.central_widget)
        self.central_widget.add_tab(
            workspace,
            QIcon("view/images/dark/baseline_notes_black_48dp.png"),
            file_path.split("storage/")[1],
        )

    def connected_dbs(self):
        if os.path.exists("model/session/connected_dbs") and os.path.getsize(
                "model/session/connected_dbs") > 0:
            self.clear_tree()

            self.dbs = []

            with open("model/session/connected_dbs", "rb") as sessions:
                db_sessions = pickle.load(sessions)

            for db in db_sessions:
                connection = mysql.connect(
                    host=db["host"],
                    user=db["user"],
                    password=db["password"],
                    db=db["db"],
                    charset="utf8mb4",
                    cursorclass=mysql.cursors.DictCursor)

                temp_db = StandardItem(db["db"], 10, is_bold=True)

                self.dbs.append(db["db"])

                try:
                    with connection.cursor() as cursor:
                        cursor.execute("SHOW TABLES")
                        db_tables = cursor.fetchall()

                    for table in db_tables:
                        for key in table.keys():
                            temp_table = StandardItem(table[key], 9)
                            temp_db.appendRow(temp_table)
                finally:
                    connection.close()

                self.db_root.appendRow(temp_db)
        else:
            self.clear_tree()
            self.dbs = []
            no_db = StandardItem("No Connected Databases", 10, is_bold=True)
            self.db_root.appendRow(no_db)

    def table_clicked(self, val):
        self.is_db = False
        if os.path.exists("model/session/connected_dbs") and len(
                self.dbs) != 0:
            for db in self.dbs:
                if db == val.data():
                    self.is_db = True

                    remove_choice = QMessageBox.question(
                        self.db_tree, "Disconnect Database",
                        f'Do you want to remove "{val.data()}" from connected databases?',
                        QMessageBox.Yes | QMessageBox.No)

                    if remove_choice == QMessageBox.Yes:
                        with open("model/session/connected_dbs",
                                  "rb") as sessions:
                            db_sessions = pickle.load(sessions)

                        db_sessions[:] = [
                            db for db in db_sessions
                            if db.get('db') != val.data()
                        ]

                        for db in db_sessions:
                            if db["index"] != 1:
                                db["index"] -= 1

                        self.dbs[:] = [
                            db for db in self.dbs if db != val.data()
                        ]

                        if len(db_sessions) == 0:
                            os.remove("model/session/connected_dbs")
                        else:
                            with open("model/session/connected_dbs",
                                      "wb") as sessions:
                                pickle.dump(db_sessions, sessions)

                        QMessageBox.information(
                            self.db_tree, "(㇏(•̀ᵥᵥ•́)ノ)",
                            f'Database "{val.data()}" successfully disconnected.',
                            QMessageBox.Ok)
                        self.connected_dbs()
                        break

                    if remove_choice == QMessageBox.No:
                        break

            if not self.is_db:
                user_reply = QMessageBox.question(
                    self.db_tree, "Answer. Thanks.",
                    f'Do you want to open the "{val.data()}" table?',
                    QMessageBox.Open | QMessageBox.Cancel)

                if user_reply == QMessageBox.Cancel:
                    pass

                if user_reply == QMessageBox.Open:
                    workspace = DBWorkspace(val.parent().data(), val.data(),
                                            self.central_widget)
                    self.central_widget.add_tab(
                        workspace,
                        QIcon("view/images/menubar/database-connect.png"),
                        val.data(),
                    )

    def clear_tree(self):
        self.db_model.clear()
        self.db_model.setHorizontalHeaderLabels(["Database"])
        self.db_root = self.db_model.invisibleRootItem()