import pandas as pd from PyQt6.QtCore import Qt from PyQt6.QtGui import QPixmap, QAction from PyQt6.QtWidgets import QHBoxLayout, QLabel, QMenu, QInputDialog, \ QMessageBox import banking_breakdown.ui from banking_breakdown.ui.pandas_model import PandasModel from importlib import resources class WarningItem(QHBoxLayout): """Item appearing at top of Window with warning icon.""" def __init__(self, text: str, parent=None): super(WarningItem, self).__init__() self._warningIcon = QLabel() pixmap_path = f"{resources.files(banking_breakdown.ui)}/warning.png" pixmap = QPixmap(pixmap_path) self._warningIcon.setPixmap(pixmap) self._label = QLabel(text) self._label.setWordWrap(True) self.addWidget(self._warningIcon) self.addWidget(self._label) self.setStretch(0, 0) self.setStretch(1, 1) def hide(self): self._label.hide() self._warningIcon.hide() class HeaderContextMenu(QMenu): """Context menu appearing when right-clicking the header of the QTableView. """ def __init__(self, column_index, pandas_model: PandasModel, callback=None, parent=None): super(HeaderContextMenu, self).__init__() self._pandas_model = pandas_model self._callback = callback self._column_index = column_index self._column_text \ = self._pandas_model.headerData(self._column_index, Qt.Orientation.Horizontal) # Define assign action assign_menu = QMenu("Assign type", self) assign_date_action = QAction("date", self) assign_float_action = QAction("float", self) assign_menu.addAction(assign_date_action) assign_menu.addAction(assign_float_action) assign_date_action.triggered.connect(self._assign_date_handler) assign_float_action.triggered.connect(self._assign_float_handler) # Define other actions rename_action = QAction("Rename", self) delete_action = QAction("Delete", self) switch_action = QAction("Switch position", self) rename_action.triggered.connect(self._rename_handler) delete_action.triggered.connect(self._delete_handler) switch_action.triggered.connect(self._switch_handler) # Add actions to menu self.addAction(rename_action) self.addAction(delete_action) self.addAction(switch_action) self.addAction(assign_menu.menuAction()) def _rename_handler(self): new_name, flag = QInputDialog.getText(self, "Rename column", "New name:", text=self._column_text) if not flag: return if (new_name != self._column_text) and (new_name != ''): try: self._pandas_model.rename_column(self._column_text, new_name) except: QMessageBox.warning(self, "No action performed", "An error occurred.") if self._callback: self._callback() def _delete_handler(self): button = QMessageBox.question(self, "Delete column", f"Are you sure you want to delete" f" column '{self._column_text}'?") if button == QMessageBox.StandardButton.Yes: self._pandas_model.delete_column_by_index(self._column_index) if self._callback: self._callback() def _switch_handler(self): df = self._pandas_model.get_dataframe() columns = [column for column in df.columns if column != self._column_text] other_name, flag = QInputDialog.getItem(self, "Switch column position", f"Switch position of colum " f"'{self._column_text}' with:", columns, editable=False) if not flag: return self._pandas_model.switch_columns(self._column_text, other_name) if self._callback: self._callback() def _assign_date_handler(self): date_format, flag = QInputDialog.getText(self, "Format", "Format:", text="%d.%m.%Y") if not flag: return try: self._pandas_model.assign_date_column(self._column_text, date_format) except: QMessageBox.warning(self, "No action performed", "An error occurred.") if self._callback: self._callback() def _assign_float_handler(self): chars = ['.', ','] decimal_sep, flag = QInputDialog.getItem(self, "Decimal separator", "Decimal separator:", chars, editable=False) if not flag: return try: self._pandas_model.assign_float_column(self._column_text, decimal_sep) except: QMessageBox.warning(self, "No action performed", "An error occurred.") if self._callback: self._callback()