Source code for widgets.table

import os
import platform
import json
import sys

from PyQt5.QtWidgets import (QToolButton, QTableView, QAbstractItemView,
                             QAction, QHeaderView, QTableWidget, QDialog,
                             QTableWidgetItem, QLabel, QPushButton, qApp,
                             QVBoxLayout, QLineEdit)
from PyQt5.QtCore import pyqtSignal, Qt, QPersistentModelIndex, QSize
from PyQt5.QtGui import QFont, QCursor, QIcon, QPixmap

from utilities import database, corpusbasestatistics
from cultures.makam import utilities as makam_utilities
from widgets.playerframe import load_pd, load_tonic
from .progressbar import ProgressBar
from .contextmenu import RCMenu, RCMenuCollTable
from .widgetutilities import set_css, convert_str
from .models.recordingmodel import CollectionTableModel
from .models.proxymodel import SortFilterProxyModel


if platform.system() == 'Linux':
    FONT_SIZE = 9
else:
    FONT_SIZE = 12


DOCS_PATH = os.path.join(os.path.dirname(__file__), '..', 'cultures',
                         'documents')
DUNYA_ICON = os.path.join(os.path.dirname(__file__), '..', 'ui_files',
                          'icons', 'dunya.svg')
CHECK_ICON = os.path.join(os.path.dirname(__file__), '..', 'ui_files',
                          'icons', 'tick-inside-circle.svg')
QUEUE_ICON = os.path.join(os.path.dirname(__file__), '..', 'ui_files',
                          'icons', 'add-to-queue-button.svg')
DOWNLOAD_ICON = os.path.join(os.path.dirname(__file__), '..', 'ui_files',
                             'icons', 'download.svg')
COMPMUSIC_ICON = os.path.join(os.path.dirname(__file__), '..', 'ui_files',
                              'icons', 'compmusic_white.png')
PLAY_ICON = os.path.join(os.path.dirname(__file__), '..', 'ui_files', 'icons',
                         'playback', 'play-button_gray.svg')
CSS_PATH = os.path.join(os.path.dirname(__file__), '..', 'ui_files',
                        'style.qss')


[docs]class TableView(QTableView): open_dunya_triggered = pyqtSignal(object) add_to_collection = pyqtSignal(str, object) def __init__(self, parent=None): QTableView.__init__(self, parent=parent) # setting the table for no edit and row selection self.setEditTriggers(QAbstractItemView.NoEditTriggers) self.setSelectionBehavior(QAbstractItemView.SelectRows) # self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.setMouseTracking(True) self.horizontalHeader().setStretchLastSection(True) font = QFont() font.setPointSize(13) self.horizontalHeader().setFont(font) # hiding the vertical headers self.verticalHeader().hide() # arranging the artist column for being multi-line self.setWordWrap(True) self.setTextElideMode(Qt.ElideMiddle) self._last_index = QPersistentModelIndex() self.viewport().installEventFilter(self) self._set_font() def _set_font(self): """Sets the font of the table""" font = QFont() font.setPointSize(FONT_SIZE) self.setFont(font)
[docs] def contextMenuEvent(self, event): """Pops up the context menu when the right button is clicked.""" try: index = self._get_current_index menu = RCMenu(self) menu.popup(QCursor.pos()) self.selected_indexes = menu.return_selected_row_indexes() menu.overall_hist_action.triggered.connect( self._compute_overall_histograms) except UnboundLocalError: pass
@property def _get_current_index(self): """ Returns the index of clicked item. :return: (int) Index of clicked item. """ if self.selectionModel().selection().indexes(): for index in self.selectionModel().selection().indexes(): row, column = index.row(), index.column() self.index = index return index def _compute_overall_histograms(self): """ Computes the overall histograms of selected items in a table. """ coll_widget = self.parent().parent().listView_collections coll = str(coll_widget.currentItem().text()) conn, c = database.connect() histograms = {} for row in self.selected_indexes: mbid = str(database.get_nth_row(c, coll, row)[0]) pd_path = os.path.join(DOCS_PATH, mbid, 'audioanalysis--pitch_distribution.json') tnc_path = os.path.join(DOCS_PATH, mbid, 'audioanalysis--tonic.json') vals, bins = load_pd(pd_path) tonic = load_tonic(tnc_path) histograms[mbid] = [[vals, bins], tonic] corpusbasestatistics.compute_overall_histogram(histograms)
[docs] def send_rec(self): """Emits 'open_dunya_triggered' signal and the current index to open the player""" self.index = self._get_current_index if self.index: self.open_dunya_triggered.emit(self.index) self.index = None
[docs] def get_selected_rows(self): """Returns the current selected rows in the table.""" selected_rows = [] for item in self.selectionModel().selectedRows(): if item.row() not in selected_rows: selected_rows.append(item) return selected_rows
[docs] def send_to_db(self, coll): """Emits 'add_to_collection' signal to add the selected rows to the database""" if self.index: self.add_to_collection.emit(coll, self.index) self.index = None
[docs]class TableViewResults(TableView): """Table view widget of query results.""" def __init__(self, parent=None): TableView.__init__(self) self.setSortingEnabled(True) self.setDragDropMode(QAbstractItemView.DragOnly) self.horizontal_header = self.horizontalHeader() self._set_horizontal_header() self.add_maincoll = QAction("Add to main collection", self) self.setColumnWidth(0, 10) self.setSelectionMode(QAbstractItemView.SingleSelection) def _set_menu(self): """ """ self.add_maincoll = QAction("Add to main collection", self) self.menu.addSeparator() self.open_dunya = QAction("Open on Player", self) self.open_dunya.setIcon(QIcon(DUNYA_ICON)) def _set_horizontal_header(self): """ Sets the settings of the horizontal header. """ self.horizontal_header.setStretchLastSection(True) self.horizontal_header.hide() self.horizontal_header.setResizeMode(QHeaderView.Fixed)
[docs]class TableViewCollections(TableView): def __index__(self, parent=None): TableView.__init__(self) self.setSortingEnabled(True) self.setDragDropMode(QAbstractItemView.NoDragDrop) self.horizontal_header = self.horizontalHeader() self.setSelectionMode(QAbstractItemView.SingleSelection) def contextMenuEvent(self, QContextMenuEvent): menu = RCMenuCollTable(self) menu.popup(QCursor.pos()) def _rc_remove_triggerred(self): """ Removes the selected item by clicking on the remove option in context menu. """ index = self._get_current_index model = self.model().sourceModel() docid = model.items[index.row()] coll_name = self._get_current_coll_name # removing the selected item conn, c = database.connect() database.delete_nth_row(conn, c, coll_name, docid) # refreshing the model model.clear_items() collection = database.fetch_collection(c, coll_name) model.add_recording(collection) conn.close() @property def _get_current_coll_name(self): """ Returns the name of the collection. :return: (str) Name of the collection """ coll_label = self.parent().findChildren(QLabel)[0] return coll_label.text()
[docs]class TableWidget(QTableWidget, TableView): added_new_doc = pyqtSignal(list) open_dunya_triggered = pyqtSignal(object) set_result_checked = pyqtSignal(str) def __init__(self, parent=None): QTableWidget.__init__(self, parent=parent) TableView.__init__(self, parent=parent) self.setDragDropMode(QAbstractItemView.DropOnly) self.setAcceptDrops(True) self.setDragDropOverwriteMode(False) self._set_columns() self.setDisabled(True) self.recordings = [] self.indexes = {} self.coll = '' def _set_columns(self): self.setColumnCount(2) self.setHorizontalHeaderLabels(['Status', 'Title']) self.horizontalHeader().setResizeMode(QHeaderView.Fixed) def dropMimeData(self, p_int, p_int_1, QMimeData, Qt_DropAction): self.last_drop_row = p_int return True # self.last_drop_row = self.rowCount() # return True def dropEvent(self, event): # The QTableWidget from which selected rows will be moved sender = event.source() # Default dropEvent method fires dropMimeData with appropriate # parameters (we're interested in the row index). super(QTableWidget, self).dropEvent(event) # Now we know where to insert selected row(s) drop_row = self.last_drop_row selected_rows = sender.get_selected_rows() selected_rows_index = [item.row() for item in selected_rows] # if sender == receiver (self), after creating new empty rows selected # rows might change their locations sel_rows_offsets = [0 if self != sender or srow < drop_row else len(selected_rows_index) for srow in selected_rows_index] selected_rows_index = [row + offset for row, offset in zip(selected_rows_index, sel_rows_offsets)] # copy content of selected rows into empty ones docs = [] conn, c = database.connect() for i, srow in enumerate(selected_rows): source_index = sender.model().mapToSource(srow) if database.add_doc_to_coll( conn, c, self.recordings[source_index.row()], self.coll): # index in the source model index = sender.model().mapToSource(selected_rows[i]) # item in the source model item = sender.model().sourceModel().item(index.row(), 1) if item: self.add_item(item.text()) docs.append(self.recordings[source_index.row()]) self.indexes[self.recordings[source_index.row()]] = \ self.rowCount() - 1 # sender.model().sourceModel().set_checked( # [selected_rows_index[i]]) if docs: self.added_new_doc.emit(docs) event.accept() def add_item(self, text): self.insertRow(self.rowCount()) self.set_status(self.rowCount() - 1, 0) source = QTableWidgetItem(text) self.setItem(self.rowCount() - 1, 1, source) def create_table(self, coll): # first cleans the table, sets the columns and enables the widget self.setRowCount(0) self._set_columns() self.setEnabled(True) for i, item in enumerate(coll): set_check = False path = os.path.join(DOCS_PATH, item, 'audioanalysis--metadata.json') if makam_utilities.check_doc(item): metadata = json.load(open(path)) cell = QTableWidgetItem(metadata['title']) set_check = 1 else: print("Needs to be downloaded {0}".format(item)) cell = QTableWidgetItem(item) self.insertRow(self.rowCount()) self.setItem(i, 1, cell) self.setColumnWidth(0, 60) if set_check is 1: self.set_status(self.rowCount()-1, 1) else: self.set_status(self.rowCount()-1, 2) def set_progress_bar(self, status): docid = status.docid step = status.step n_progress = status.n_progress self.setCellWidget(self.indexes[docid], 0, ProgressBar(self)) progress_bar = self.cellWidget(self.indexes[docid], 0) if progress_bar: if not step == n_progress: progress_bar.update_progress_bar(step, n_progress) else: self.set_status(self.indexes[docid], 1) self.refresh_row(docid) def set_status(self, raw, exist=None): item = QLabel() item.setAlignment(Qt.AlignCenter) if exist is 0: icon = QPixmap(QUEUE_ICON).scaled(20, 20, Qt.KeepAspectRatio, Qt.SmoothTransformation) item.setPixmap(icon) item.setToolTip('Waiting in the download queue...') if exist is 1: icon = QPixmap(CHECK_ICON).scaled(20, 20, Qt.KeepAspectRatio, Qt.SmoothTransformation) item.setPixmap(icon) item.setToolTip('All the features are downloaded...') if exist is 2: item = QPushButton(self) item.setToolTip('Download') item.setIcon(QIcon(DOWNLOAD_ICON)) item.clicked.connect(self.download_clicked) self.setCellWidget(raw, 0, item) def download_clicked(self): click_me = qApp.focusWidget() index = self.indexAt(click_me.pos()) if index.isValid(): row = index.row() if sys.version_info[0] == 2: docid = convert_str(self.item(row, 1).text()) else: docid = self.item(row, 1).text() self.set_status(row, 0) self.indexes[docid] = row self.added_new_doc.emit([docid])
[docs] def refresh_row(self, docid): """checks the status and the title columns of given row""" row = self.indexes[docid] if self.item(row, 1): if makam_utilities.check_doc(docid): self.set_status(row, exist=1) title = json.load(open(os.path.join( DOCS_PATH, docid, 'audioanalysis--metadata.json')))['title'] item = QTableWidgetItem(title) self.setItem(row, 1, item) self.set_result_checked.emit(docid) else: self.set_status(row, 2)
[docs]class DialogCollTable(QDialog): def __init__(self, parent): QDialog.__init__(self, parent=parent) self.setMinimumSize(QSize(1200, 600)) layout = QVBoxLayout(self) self.label_collection = QLabel() self.label_collection.setAlignment(Qt.AlignCenter) layout.addWidget(self.label_collection) self.lineedit_filter = QLineEdit(self) layout.addWidget(self.lineedit_filter) self.coll_table = TableViewCollections(self) layout.addWidget(self.coll_table) self.model = CollectionTableModel() self.proxy_model = SortFilterProxyModel() self.proxy_model.setSourceModel(self.model) self.proxy_model.setFilterKeyColumn(-1) self.coll_table.setModel(self.proxy_model) # signals self.lineedit_filter.textChanged.connect(self._lineedit_changed) def _lineedit_changed(self): self.proxy_model.filter_table(self.lineedit_filter.text()) def _set_line_edit(self): self.lineedit_filter.setPlaceholderText('Type here to filter') def closeEvent(self, QCloseEvent): self.model.clear_items()
[docs]class TablePlaylist(TableWidget, TableViewCollections): item_changed = pyqtSignal(str) def __init__(self, parent=None): TableWidget.__init__(self) TableViewCollections.__init__(self, parent=parent) self.setEnabled(True) self.setDragDropMode(QAbstractItemView.NoDragDrop) self._set_columns() set_css(self, CSS_PATH) self.items = {} self.itemClicked.connect(self._item_clicked) def _item_clicked(self, item): current_index = self.currentIndex().row() conn, c = database.connect() coll_label = self.parent().findChildren(QLabel)[0] coll_name = coll_label.text() mbid = database.get_nth_row(c, coll_name, current_index)[0] self.item_changed.emit(mbid) def _set_columns(self): self.setColumnCount(4) self.setHorizontalHeaderLabels(['', '', 'Title', 'Artists']) self.horizontalHeader().setResizeMode(QHeaderView.Fixed) def add_recordings(self, recording): for index, mbid in enumerate(recording): metadata = CollectionTableModel._get_metadata(self, mbid[0], index) if metadata: self._add_item(metadata) else: self.setItem(self.rowCount() - 1, 2, self._make_item(mbid[0])) def _add_item(self, metadata): self.insertRow(self.rowCount()) # add play button play_button = QToolButton(self) play_button.setIcon(QIcon(PLAY_ICON)) self.setItem(self.rowCount()-1, 0, self._make_item(str(self.rowCount()))) self.setCellWidget(self.rowCount()-1, 1, play_button) self.setItem(self.rowCount()-1, 2, self._make_item(metadata['title'])) self.setItem(self.rowCount()-1, 3, self._make_item(metadata['artists'])) self.setColumnWidth(0, 23) self.setColumnWidth(1, 28) def _make_item(self, text): return QTableWidgetItem(text) def _button_clicked(self): print('meh')