예제 #1
0
 def _createModelFromData(self, headers_blocks, data_blocks):
     """Create the model needed for GUI calculated data table and chart (based on data 2d list created previously)."""
     if self._project.experimentsCount() > 1:
         print("Currently, only 1 measured datablock is supported. Given: ",
               self._project.experimentsCount())
     experiment_id = self._project.experimentsIds()[
         0]  # only 1st measured datablock is currently taken into account
     headers, data = headers_blocks[experiment_id], data_blocks[
         experiment_id]
     row_count = len(data)
     column_count = len(data[0])
     # set headers
     headerModel = QStandardItemModel(1, column_count)
     for column_index in range(column_count):
         index = headerModel.index(0, column_index)
         value = headers[column_index]
         headerModel.setData(index, value,
                             Qt.DisplayRole)  #Qt.WhatsThisRole
     # set model data
     dataModel = QStandardItemModel(row_count, column_count)
     for row_index in range(row_count):
         for column_index in range(column_count):
             index = dataModel.index(row_index, column_index)
             value = data[row_index][column_index]
             dataModel.setData(index, value, Qt.DisplayRole)
     return headerModel, dataModel
예제 #2
0
class QCampaignList(QListView):
    def __init__(self):
        super(QCampaignList, self).__init__()
        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.setMinimumWidth(250)
        self.setMinimumHeight(350)
        self.campaigns = []
        self.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.setup_content()

    def setup_content(self):
        for i, campaign in enumerate(CAMPAIGNS):
            self.campaigns.append(campaign)
            item = QCampaignItem(*campaign)
            self.model.appendRow(item)
        self.setSelectedCampaign(0)
        self.repaint()

    def setSelectedCampaign(self, row):
        self.selectionModel().clearSelection()
        index = self.model.index(row, 0)
        if not index.isValid():
            index = self.model.index(0, 0)
        self.selectionModel().setCurrentIndex(index,
                                              QItemSelectionModel.Select)
        self.repaint()

    def clear_layout(self):
        self.model.removeRows(0, self.model.rowCount())
예제 #3
0
 def testLen(self):
     model = QStandardItemModel(2, 2)
     model.insertRow(0)
     model.insertRow(1)
     model.insertColumn(0)
     model.insertColumn(1)
     selection = QItemSelection(model.index(0,0), model.index(1,1))
     self.assertEqual(len(selection), 1)
예제 #4
0
 def testLen(self):
     model = QStandardItemModel(2, 2)
     model.insertRow(0)
     model.insertRow(1)
     model.insertColumn(0)
     model.insertColumn(1)
     selection = QItemSelection(model.index(0, 0), model.index(1, 1))
     self.assertEqual(len(selection), 1)
예제 #5
0
class QCampaignList(QListView):
    CampaignRole = Qt.UserRole

    def __init__(self, campaigns: list[Campaign],
                 show_incompatible: bool) -> None:
        super(QCampaignList, self).__init__()
        self.campaign_model = QStandardItemModel(self)
        self.setModel(self.campaign_model)
        self.setMinimumWidth(250)
        self.setMinimumHeight(350)
        self.campaigns = campaigns
        self.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.setup_content(show_incompatible)

    @property
    def selected_campaign(self) -> Campaign:
        return self.currentIndex().data(QCampaignList.CampaignRole)

    def setup_content(self, show_incompatible: bool) -> None:
        self.selectionModel().blockSignals(True)
        try:
            self.campaign_model.clear()
            for campaign in self.campaigns:
                if show_incompatible or campaign.is_compatible:
                    item = QCampaignItem(campaign)
                    self.campaign_model.appendRow(item)
        finally:
            self.selectionModel().blockSignals(False)

        self.selectionModel().setCurrentIndex(
            self.campaign_model.index(0, 0, QModelIndex()),
            QItemSelectionModel.Select)
예제 #6
0
class TableViewAllStock(QTableView):
    def __init__(self, parent=None):
        super(TableViewAllStock, self).__init__(parent)
        # self.mouseDoubleClickEvent()
        self.doubleClicked.connect(self.slotDoubleClicked)
        self.creatUI()
        self.initData()

    def creatUI(self):
        self.model = QStandardItemModel()
        self.setModel(self.model)
        self.verticalHeader().setSectionResizeMode(QHeaderView.Fixed)
        self.verticalHeader().setDefaultSectionSize(8)
        self.verticalHeader().hide()
        self.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.setEditTriggers(QTableView.NoEditTriggers)
        self.setShowGrid(True)

        arr = ["代码", "名称", "日期", "最新价", "涨跌幅", "涨跌额", "成交量(手)", "成交额", "振幅", "最高", "最低", "今开", "换手率"]
        self.model.setColumnCount(len(arr))
        for i in range(len(arr)):
            self.model.setHeaderData(i, Qt.Horizontal, arr[i])

    def Item(self, var):
        item = QStandardItem(str(var))
        item.setTextAlignment(Qt.AlignVCenter|Qt.AlignHCenter);
        return item

    def initData(self):
        kline = Kline()
        #kline.setYear(2021)
        res = kline.getLatestKlineData()
        for row in res:
            items = []
            items.append(self.Item(row['code']))
            items.append(self.Item(row['SEC_NAME']))
            items.append(self.Item(row['date']))
            items.append(self.Item(row['close']))
            items.append(self.Item(str(row['p_change'])+'%'))
            items.append(self.Item(row['price_change']))
            items.append(self.Item(row['amount']))
            items.append(self.Item(row['turnover']))

            items.append(self.Item(str(row['amplitude'])+'%'))
            items.append(self.Item(row['high']))
            items.append(self.Item(row['low']))
            items.append(self.Item(row['open']))
            items.append(self.Item(str(row['exchange'])+'%'))

            self.model.appendRow(items)

    # QModelIndex index
    def slotDoubleClicked(self, index):
        code = self.model.index(index.row(), 0).data();
        name = self.model.index(index.row(), 1).data();
        d = KlineWidget(self)
        d.setWindowTitle("%s(%s)"%(code, name))
        d.exec()
예제 #7
0
class QPlannedFlightsView(QListView):
    def __init__(self, game_model: GameModel, cp: ControlPoint) -> None:
        super(QPlannedFlightsView, self).__init__()
        self.game_model = game_model
        self.cp = cp
        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.flight_items = []
        self.setIconSize(QSize(91, 24))
        self.setSelectionBehavior(QAbstractItemView.SelectItems)
        self.set_flight_planner()

    def setup_content(self):
        self.flight_items = []
        for package in self.game_model.ato_model.packages:
            for flight in package.flights:
                if flight.from_cp == self.cp:
                    item = QFlightItem(package.package, flight)
                    self.flight_items.append(item)

        self.flight_items.sort(key=self.mission_start_for_flight)
        for item in self.flight_items:
            self.model.appendRow(item)
        self.set_selected_flight(0)

    def set_selected_flight(self, row):
        self.selectionModel().clearSelection()
        index = self.model.index(row, 0)
        if not index.isValid():
            index = self.model.index(0, 0)
        self.selectionModel().setCurrentIndex(index,
                                              QItemSelectionModel.Select)
        self.repaint()

    def clear_layout(self):
        self.model.removeRows(0, self.model.rowCount())

    def set_flight_planner(self) -> None:
        self.clear_layout()
        self.setup_content()

    @staticmethod
    def mission_start_for_flight(flight_item: QFlightItem) -> timedelta:
        return TotEstimator(flight_item.package).mission_start_time(
            flight_item.flight)
예제 #8
0
 def _createModelFromData(self, headers, data):
     """Create the model needed for GUI measured data table and chart (based on data 2d list created previously)."""
     row_count = len(data)
     column_count = len(data[0])
     # set headers
     headerModel = QStandardItemModel(1, column_count)
     for column_index in range(column_count):
         index = headerModel.index(0, column_index)
         value = headers[column_index]
         headerModel.setData(index, value,
                             Qt.DisplayRole)  #Qt.WhatsThisRole
     # set model data
     dataModel = QStandardItemModel(row_count, column_count)
     for row_index in range(row_count):
         for column_index in range(column_count):
             index = dataModel.index(row_index, column_index)
             value = data[row_index][column_index]
             dataModel.setData(index, value, Qt.DisplayRole)
     return headerModel, dataModel
예제 #9
0
파일: bug_785.py 프로젝트: linzhun/pyside2
    def testOperators(self):
        model = QStandardItemModel()
        for i in range(100):
            model.appendRow(QStandardItem("Item: %d"%i))

        first = model.index(0, 0)
        second = model.index(10, 0)
        third = model.index(20, 0)
        fourth = model.index(30, 0)

        sel = QItemSelection(first, second)
        sel2 = QItemSelection()
        sel2.select(third, fourth)

        sel3 = sel + sel2 #check operator +
        self.assertEqual(len(sel3), 2)
        sel4 = sel
        sel4 += sel2 #check operator +=
        self.assertEqual(len(sel4), 2)
        self.assertEqual(sel4, sel3)
예제 #10
0
    def testOperators(self):
        model = QStandardItemModel()
        for i in range(100):
            model.appendRow(QStandardItem("Item: %d" % i))

        first = model.index(0, 0)
        second = model.index(10, 0)
        third = model.index(20, 0)
        fourth = model.index(30, 0)

        sel = QItemSelection(first, second)
        sel2 = QItemSelection()
        sel2.select(third, fourth)

        sel3 = sel + sel2  #check operator +
        self.assertEqual(len(sel3), 2)
        sel4 = sel
        sel4 += sel2  #check operator +=
        self.assertEqual(len(sel4), 2)
        self.assertEqual(sel4, sel3)
예제 #11
0
class QPlannedFlightsView(QListView):

    def __init__(self, flight_planner: FlightPlanner):
        super(QPlannedFlightsView, self).__init__()
        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.flightitems = []
        self.setIconSize(QSize(91, 24))
        self.setSelectionBehavior(QAbstractItemView.SelectItems)
        if flight_planner:
            self.set_flight_planner(flight_planner)

    def update_content(self):
        for i, f in enumerate(self.flight_planner.flights):
            self.flightitems[i].update(f)

    def setup_content(self, row=0):
        self.flightitems = []
        for i, f in enumerate(self.flight_planner.flights):
            item = QFlightItem(f)
            self.model.appendRow(item)
            self.flightitems.append(item)
        self.setSelectedFlight(row)
        self.repaint()

    def setSelectedFlight(self, row):
        self.selectionModel().clearSelection()
        index = self.model.index(row, 0)
        if not index.isValid():
            index = self.model.index(0, 0)
        self.selectionModel().setCurrentIndex(index, QItemSelectionModel.Select)
        self.repaint()

    def clear_layout(self):
        self.model.removeRows(0, self.model.rowCount())

    def set_flight_planner(self, flight_planner: FlightPlanner, row=0):
        self.clear_layout()
        self.flight_planner = flight_planner
        if self.flight_planner:
            self.setup_content(row)
 def testIntDelegate(self):
     """PYSIDE-1250: When creating a QVariant, use int instead of long long
        for anything that fits into a int. Verify by checking that a spin
        box is created as item view editor for int."""
     item = QStandardItem()
     item.setData(123123, Qt.EditRole)  # <-- QVariant conversion here
     model = QStandardItemModel()
     model.appendRow(item)
     style_option = QStyleOptionViewItem()
     delegate = QStyledItemDelegate()
     editor = delegate.createEditor(None, style_option, model.index(0, 0))
     self.assertEqual(type(editor), QSpinBox)
예제 #13
0
class ObjectNameListEditor(ManageItemsDialog):
    """A dialog to select the object name list for a relationship using Google-like search bars."""
    def __init__(self, parent, index, object_class_names, object_names_lists,
                 current_object_names):
        """Initializes widget.

        Args:
            parent (DataStoreForm)
            index (QModelIndex)
            object_class_names (list): string object class names
            object_names_lists (list): lists of string object names
            current_object_names (list)
        """
        super().__init__(parent, None)
        self.setWindowTitle("Select objects")
        self._index = index
        self.model = QStandardItemModel(self)
        self.init_model(object_class_names, object_names_lists,
                        current_object_names)
        self.table_view.setModel(self.model)
        self.resize_window_to_columns()
        self.table_view.verticalHeader().hide()
        delegate = SearchBarDelegate(self)
        self.table_view.setItemDelegate(delegate)
        self.connect_signals()

    def connect_signals(self):
        """Connect signals to slots."""
        super().connect_signals()
        self.button_box.accepted.connect(self.accept)
        self.button_box.rejected.connect(self.reject)

    def init_model(self, object_class_names, object_names_lists,
                   current_object_names):
        self.model.setHorizontalHeaderLabels(object_class_names)
        item_list = []
        for k, object_names_list in enumerate(object_names_lists):
            try:
                obj_name = current_object_names[k]
            except IndexError:
                obj_name = None
            qitem = QStandardItem(obj_name)
            qitem.setData(object_names_list, role=Qt.UserRole)
            item_list.append(qitem)
        self.model.invisibleRootItem().appendRow(item_list)

    @Slot()
    def accept(self):
        self._index.model().setData(
            self._index, ",".join(
                self.model.index(0, j).data()
                for j in range(self.model.columnCount())))
        super().accept()
예제 #14
0
class CellParametersModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._a_role, self._b_role, self._c_role, self._alpha_role, self._beta_role, self._gamma_role = [
            Qt.UserRole + 1 + i for i in range(6)
        ]
        self._model.setItemRoleNames({
            self._a_role: b'length_a',
            self._b_role: b'length_b',
            self._c_role: b'length_c',
            self._alpha_role: b'angle_alpha',
            self._beta_role: b'angle_beta',
            self._gamma_role: b'angle_gamma'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI ..."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # set helper data list
            data = [{
                self._a_role:
                phase_dict.getItemByPath(['cell', 'length_a']).value,
                self._b_role:
                phase_dict.getItemByPath(['cell', 'length_b']).value,
                self._c_role:
                phase_dict.getItemByPath(['cell', 'length_c']).value,
                self._alpha_role:
                phase_dict.getItemByPath(['cell', 'angle_alpha']).value,
                self._beta_role:
                phase_dict.getItemByPath(['cell', 'angle_beta']).value,
                self._gamma_role:
                phase_dict.getItemByPath(['cell', 'angle_gamma']).value,
            }]
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data list created above
            for row_index, dict in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")
class AircraftTypeList(QListView):
    page_index_changed = Signal(int)

    def __init__(self, air_wing: AirWing) -> None:
        super().__init__()
        self.setIconSize(QSize(91, 24))
        self.setMinimumWidth(300)

        self.item_model = QStandardItemModel(self)
        self.setModel(self.item_model)

        self.selectionModel().setCurrentIndex(self.item_model.index(0, 0),
                                              QItemSelectionModel.Select)
        self.selectionModel().selectionChanged.connect(
            self.on_selection_changed)
        for aircraft in air_wing.squadrons:
            self.add_aircraft_type(aircraft)

    def remove_aircraft_type(self, aircraft: AircraftType):
        for item in self.item_model.findItems(aircraft.name):
            self.item_model.removeRow(item.row())
        self.page_index_changed.emit(
            self.selectionModel().currentIndex().row())

    def add_aircraft_type(self, aircraft: AircraftType):
        aircraft_item = QStandardItem(aircraft.name)
        icon = self.icon_for(aircraft)
        if icon is not None:
            aircraft_item.setIcon(icon)
        aircraft_item.setEditable(False)
        aircraft_item.setSelectable(True)
        self.item_model.appendRow(aircraft_item)

    def on_selection_changed(self, selected: QItemSelection,
                             _deselected: QItemSelection) -> None:
        indexes = selected.indexes()
        if len(indexes) > 1:
            raise RuntimeError(
                "Aircraft list should not allow multi-selection")
        if not indexes:
            return
        self.page_index_changed.emit(indexes[0].row())

    @staticmethod
    def icon_for(aircraft: AircraftType) -> Optional[QIcon]:
        name = aircraft.dcs_id
        if name in AIRCRAFT_ICONS:
            return QIcon(AIRCRAFT_ICONS[name])
        return None
예제 #16
0
    def createModel(self, start, end):
        if start == end:
            return None

        model = QStandardItemModel(min(self.block_size, len(self.data) - self.curr_start),  len(self.model_meta_data) - 1)
        step = 1 if start < end else -1

        for i in range(1, self.model_col_num):
            model.setHeaderData(i - 1, Qt.Horizontal, self.model_meta_data[i][0])
        i = 0
        for row in range(start, end, step):
            data = self.data[row]
            #print("build model index {}, data: {}".format(row, data))
            for col in range(0, self.model_col_num - 1):
                model.setData(model.index(i, col), str(data[col + 1]))
            i += 1
        return model
예제 #17
0
 def _createModelFromData(self, data):
     """Create the model needed for GUI fitables table (based on data dict created previously)."""
     model = QStandardItemModel()
     model.setRowCount(len(data))
     model.setColumnCount(1)  #model.setColumnCount(len(data[0]))
     # set model role names
     start_role = Qt.UserRole + 1
     role_names = {}
     for key, _ in data[0].items():
         column_index = list(data[0].keys()).index(key)
         role = start_role + column_index
         role_names[role] = key.encode()
     model.setItemRoleNames(role_names)
     # set model data
     for row_index, row_dict in enumerate(data):
         for key, value in row_dict.items():
             column_index = list(row_dict.keys()).index(key)
             index = model.index(row_index, 0)
             role = start_role + column_index
             model.setData(index, value, role)
     return model
예제 #18
0
 def dropEvent(self, event):
     tmp = QStandardItemModel()
     tmp.dropMimeData(event.mimeData(), event.dropAction(), 0, 0,
                      QtCore.QModelIndex())
     self.add_to_layout(LayerBoxWidget(tmp.index(0, 0).data()))
예제 #19
0
class QFlightWaypointList(QTableView):
    def __init__(self, package: Package, flight: Flight):
        super().__init__()
        self.package = package
        self.flight = flight

        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.model.setHorizontalHeaderLabels(["Name", "Alt", "TOT/DEPART"])

        header = self.horizontalHeader()
        header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
        self.update_list()

        self.selectionModel().setCurrentIndex(
            self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select
        )

    def update_list(self):
        # We need to keep just the row and rebuild the index later because the
        # QModelIndex will not be valid after the model is cleared.
        current_index = self.currentIndex().row()
        self.model.clear()

        self.model.setHorizontalHeaderLabels(["Name", "Alt", "TOT/DEPART"])

        waypoints = self.flight.flight_plan.waypoints
        for row, waypoint in enumerate(waypoints):
            self.add_waypoint_row(row, self.flight, waypoint)
        self.selectionModel().setCurrentIndex(
            self.model.index(current_index, 0), QItemSelectionModel.Select
        )
        self.resizeColumnsToContents()
        total_column_width = self.verticalHeader().width() + self.lineWidth()
        for i in range(0, self.model.columnCount()):
            total_column_width += self.columnWidth(i) + self.lineWidth()
        self.setFixedWidth(total_column_width)

    def add_waypoint_row(
        self, row: int, flight: Flight, waypoint: FlightWaypoint
    ) -> None:
        self.model.insertRow(self.model.rowCount())

        self.model.setItem(row, 0, QWaypointItem(waypoint, row))

        altitude = int(waypoint.alt.feet)
        altitude_type = "AGL" if waypoint.alt_type == "RADIO" else "MSL"
        altitude_item = QStandardItem(f"{altitude} ft {altitude_type}")
        altitude_item.setEditable(False)
        self.model.setItem(row, 1, altitude_item)

        tot = self.tot_text(flight, waypoint)
        tot_item = QStandardItem(tot)
        tot_item.setEditable(False)
        self.model.setItem(row, 2, tot_item)

    def tot_text(self, flight: Flight, waypoint: FlightWaypoint) -> str:
        if waypoint.waypoint_type == FlightWaypointType.TAKEOFF:
            return self.takeoff_text(flight)
        prefix = ""
        time = flight.flight_plan.tot_for_waypoint(waypoint)
        if time is None:
            prefix = "Depart "
            time = flight.flight_plan.depart_time_for_waypoint(waypoint)
        if time is None:
            return ""
        time = timedelta(seconds=int(time.total_seconds()))
        return f"{prefix}T+{time}"

    @staticmethod
    def takeoff_text(flight: Flight) -> str:
        takeoff_time = flight.flight_plan.takeoff_time()
        # Handle custom flight plans where we can't estimate the takeoff time.
        if takeoff_time is None:
            takeoff_time = timedelta()
        start_time = timedelta(seconds=int(takeoff_time.total_seconds()))
        return f"T+{start_time}"
예제 #20
0
class MainWindowUi(QMainWindow):
    """sets up ui properties of MainWindowUi class"""
    def __init__(self) -> None:
        """inits MainWindow class

        configuring parameters of MainWindow class and inherits from QtWidget.QMainWindow
        loads .ui file sets up file and directory path vars, inits click events(menuebar, coboboxes, btns) and
        shows gui the first time

        Returns:
            None"""
        super(MainWindowUi, self).__init__()
        self.setWindowTitle("It_Hilfe")
        self.resize(820, 450)
        self.setWindowIcon(QIcon("./data/favicon2.png"))
        self.setMinimumSize(700, 250)

        self.file_path = None
        self.dir = None
        self.last_open_file_path = None
        self.last_open_file_dir = None
        self.initial_theme = None
        self.registered_devices = {}
        self.user_config_file = "./data/user_config.json"

        # setup stackedwidget
        self.stacked_widget = QStackedWidget()
        self.setCentralWidget(self.stacked_widget)
        self.setup_menubar()
        self.setup_p_view()
        self.setup_p_register()
        self.setup_p_create()
        self.setup_p_preferences()
        self.setup_signals()

        self.font = QFont()
        self.font.setPointSize(9)

        self.validate(self.set_user_preferences,
                      file_path=self.user_config_file,
                      schema=validate_json.ItHilfeUserPreferencesSchema,
                      forbidden=[""])

        # setup statusbar
        self.statusbar = self.statusBar()

        self.stacked_widget.setCurrentWidget(self.p_view)

    def setup_menubar(self) -> None:
        """inits menubar

        Returns:
            None"""
        self.menu_Bar = self.menuBar()

        menu_file = self.menu_Bar.addMenu("file")
        self.action_open = QAction("open")
        self.action_save = QAction("save")
        self.action_new = QAction("new")
        self.action_print = QAction("print")
        self.action_preferences = QAction("preferences")
        self.action_hide_menu_bar = QAction("hide menubar")
        self.action_print.setShortcut(QKeySequence("Ctrl+p"))
        self.action_open.setShortcut(QKeySequence("Ctrl+o"))
        self.action_save.setShortcut(QKeySequence("Ctrl+s"))
        self.action_hide_menu_bar.setShortcut(QKeySequence("Ctrl+h"))
        self.action_hide_menu_bar.setIcon(QIcon("./data/show_hide.ico"))
        self.action_print.setIcon(QIcon("./data/print2.ico"))
        self.action_open.setIcon(QIcon("./data/open.ico"))
        self.action_save.setIcon(QIcon("./data/save.ico"))
        self.action_new.setIcon(QIcon("./data/newfile.ico"))
        self.action_preferences.setIcon(QIcon("./data/preferences.ico"))

        menu_file.addAction(self.action_open)
        menu_file.addAction(self.action_save)
        menu_file.addAction(self.action_new)
        menu_file.addAction(self.action_print)
        menu_file.addAction(self.action_preferences)

        menu_edit = self.menu_Bar.addMenu("edit")
        self.action_register = QAction("register")
        self.action_register.setShortcut(QKeySequence("Ctrl+n"))
        self.action_register.setIcon(QIcon("./data/register.ico"))

        menu_edit.addAction(self.action_register)

        menu_view = self.menu_Bar.addMenu("view")
        menu_view.addAction(self.action_hide_menu_bar)

    def setup_p_view(self) -> None:
        """inits stacked widget page widget

        Returns:
            None"""
        self.p_view = QtWidgets.QWidget()
        self.stacked_widget.addWidget(self.p_view)

        self.model = QStandardItemModel(self.p_view)
        self.model.setHorizontalHeaderLabels(labels)

        self.filters = []
        source_model = self.model
        for filter_num in range(7):
            filter = QSortFilterProxyModel()
            filter.setSourceModel(source_model)
            filter.setFilterKeyColumn(filter_num)
            source_model = filter
            self.filters.append(filter)

        delegate = ComboDelegate()
        self.table = QtWidgets.QTableView(self.p_view)
        self.table.setModel(self.filters[-1])
        self.table.setItemDelegateForColumn(2, delegate)
        self.table.horizontalHeader().setStretchLastSection(True)
        self.table.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        self.header = FilterHeader(self.table)
        self.header.set_filter_boxes()
        self.header.setMaximumHeight(50)
        self.table.setHorizontalHeader(self.header)

        self.bt_burger = QPushButton(self.p_view)
        self.bt_burger.setIcon(QIcon("./data/menu2.svg"))
        self.bt_burger.setIconSize(QSize(30, 30))
        self.bt_burger.setToolTip('slide out description')
        l_burger = QLabel("menu", self.p_view)

        self.bt_register_new = QPushButton(self.p_view)
        self.bt_register_new.setIcon(QIcon("./data/add.ico"))
        self.bt_register_new.setIconSize(QSize(30, 30))
        self.bt_register_new.setToolTip("register new")
        l_register_new = QLabel("register new", self.p_view)

        self.bt_delete_column = QPushButton(self.p_view)
        self.bt_delete_column.setIcon(QIcon("./data/remove.ico"))
        self.bt_delete_column.setIconSize(QSize(30, 30))
        self.bt_delete_column.setToolTip(
            "delete columns with min 1 cell selected")
        l_delete = QLabel("delete column", self.p_view)

        self.bt_hide_show_filter = QPushButton(self.p_view)
        self.bt_hide_show_filter.setIcon(QIcon("./data/show_hide.ico"))
        self.bt_hide_show_filter.setIconSize(QSize(30, 30))
        self.bt_hide_show_filter.setToolTip("hide/show filter input")
        l_hide_show = QLabel("hide/show", self.p_view)

        self.left_btn_frame = QFrame(self.p_view)
        self.left_btn_frame.setMaximumWidth(40)
        self.left_btn_frame.setContentsMargins(0, 0, 0, 0)

        self.left_menu_frame = QFrame(self.p_view)
        self.left_menu_frame.setMaximumWidth(0)
        self.left_menu_frame.setContentsMargins(0, 0, 0, 0)

        p_view_layout2 = QtWidgets.QVBoxLayout(self.left_btn_frame)
        p_view_layout2.addWidget(self.bt_burger)
        p_view_layout2.addWidget(self.bt_register_new)
        p_view_layout2.addWidget(self.bt_delete_column)
        p_view_layout2.addWidget(self.bt_hide_show_filter)
        p_view_layout2.setAlignment(Qt.AlignTop)
        p_view_layout2.setContentsMargins(0, 0, 0, 0)

        self.p_view_layout3 = QtWidgets.QVBoxLayout(self.left_menu_frame)
        self.p_view_layout3.addWidget(l_burger)
        self.p_view_layout3.addWidget(l_register_new)
        self.p_view_layout3.addWidget(l_delete)
        self.p_view_layout3.addWidget(l_hide_show)
        self.p_view_layout3.setAlignment(Qt.AlignTop | Qt.AlignCenter)
        self.p_view_layout3.setContentsMargins(0, 0, 0, 0)
        self.p_view_layout3.setSpacing(25)

        p_view_layout = QHBoxLayout(self.p_view)
        p_view_layout.setContentsMargins(0, 0, 0, 0)
        p_view_layout.addWidget(self.left_btn_frame)
        p_view_layout.addWidget(self.left_menu_frame)
        p_view_layout.addWidget(self.table)
        self.p_view.setLayout(p_view_layout)

        self.p_view.addAction(self.action_open)
        self.p_view.addAction(self.action_save)
        self.p_view.addAction(self.action_new)
        self.p_view.addAction(self.action_print)
        self.p_view.addAction(self.action_register)
        self.p_view.addAction(self.action_hide_menu_bar)

    def setup_p_register(self) -> None:
        """inits stacked widget page widgets

        Returns:
            None"""

        self.p_register = QtWidgets.QWidget()
        self.stacked_widget.addWidget(self.p_register)

        l_user = QtWidgets.QLabel("Username", self.p_register)
        self.in_username = QtWidgets.QLineEdit(self.p_register)
        l_devicename = QtWidgets.QLabel("Devicename", self.p_register)
        self.in_devicename = QtWidgets.QLineEdit(self.p_register)
        l_devicetype = QtWidgets.QLabel("DeviceType", self.p_register)
        self.in_combobox_devicetype = QtWidgets.QComboBox(self.p_register)
        l_os = QtWidgets.QLabel("OS", self.p_register)
        self.in_combobox_os = QtWidgets.QComboBox(self.p_register)
        l_comment = QtWidgets.QLabel("Comment", self.p_register)
        self.in_comment = QtWidgets.QTextEdit(self.p_register)
        self.bt_enter_register = QPushButton("register", self.p_register)
        self.bt_cancel_register = QPushButton("cancel", self.p_register)

        p_register_layout = QtWidgets.QVBoxLayout(self.p_register)
        p_register_layout.addWidget(l_user)
        p_register_layout.addWidget(self.in_username)
        p_register_layout.addWidget(l_devicename)
        p_register_layout.addWidget(self.in_devicename)
        p_register_layout.addWidget(l_devicetype)
        p_register_layout.addWidget(self.in_combobox_devicetype)
        p_register_layout.addWidget(l_os)
        p_register_layout.addWidget(self.in_combobox_os)
        p_register_layout.addWidget(l_comment)
        p_register_layout.addWidget(self.in_comment)
        p_register_layout.addWidget(self.bt_enter_register)
        p_register_layout.addWidget(self.bt_cancel_register)

    def setup_p_create(self) -> None:
        """inits stacked widget page widget

        Returns:
            None"""

        self.p_create = QtWidgets.QWidget()
        self.stacked_widget.addWidget(self.p_create)

        l_new_filepath = QtWidgets.QLabel("new filepath", self.p_create)
        self.bt_mod_new_path = QPushButton("mod filepath", self.p_create)
        self.in_new_filepath = QtWidgets.QLineEdit(self.p_create)
        l_new_filename = QtWidgets.QLabel("new filename", self.p_create)
        self.in_new_filename = QtWidgets.QLineEdit(self.p_create)
        self.bt_create = QPushButton("create", self.p_create)
        self.bt_cancel_create = QPushButton("cancel", self.p_create)

        p_create_layout = QtWidgets.QVBoxLayout(self.p_create)
        p_create_layout.addWidget(l_new_filepath)
        p_create_layout.addWidget(self.in_new_filepath)
        p_create_layout.addWidget(l_new_filename)
        p_create_layout.addWidget(self.in_new_filename)
        p_create_layout.addStretch(100)
        p_create_layout.addWidget(self.bt_mod_new_path)
        p_create_layout.addWidget(self.bt_create)
        p_create_layout.addWidget(self.bt_cancel_create)

    def setup_p_preferences(self) -> None:
        """inits setup_p_preferences stacked widget page widget

            Returns:
                None"""

        self.p_preferences = QWidget()
        self.p_preferences.resize(500, 250)
        self.p_preferences.setWindowTitle("preferences")
        self.list_Widget = QListWidget(self.p_preferences)
        self.list_Widget.addItems(["appearance", "about"])
        self.list_Widget.setMaximumWidth(100)

        self.stacked_widget_preferences = QStackedWidget(self.p_preferences)

        # setup appearance
        self.apperence_widget = QWidget()
        self.stacked_widget_preferences.addWidget(self.apperence_widget)
        self.in_combo_themes = QComboBox(self.apperence_widget)
        self.in_combo_themes.addItems(["dark_theme", "light_theme"])

        self.in_combo_theme_initial = QComboBox(self.apperence_widget)
        self.in_combo_theme_initial.addItems(["dark_theme", "light_theme"])

        self.text_size_slider = QSlider(QtCore.Qt.Orientation.Horizontal,
                                        self.apperence_widget)
        self.text_size_slider.setTickPosition(QSlider.TickPosition.TicksAbove)
        self.text_size_slider.setMaximum(15)
        self.text_size_slider.setMinimum(8)

        stacked_widget_preferences_layout = QGridLayout(self.apperence_widget)
        stacked_widget_preferences_layout.setAlignment(QtCore.Qt.AlignTop)
        stacked_widget_preferences_layout.addWidget(QLabel("theme"), 0, 0)
        stacked_widget_preferences_layout.addWidget(self.in_combo_themes, 0, 1)
        stacked_widget_preferences_layout.addWidget(QLabel("initial theme"), 1,
                                                    0)
        stacked_widget_preferences_layout.addWidget(
            self.in_combo_theme_initial, 1, 1)
        stacked_widget_preferences_layout.addWidget(QLabel("Fontsize"), 2, 0)
        stacked_widget_preferences_layout.addWidget(self.text_size_slider, 2,
                                                    1)

        self.about_widget = QWidget()
        self.stacked_widget_preferences.addWidget(self.about_widget)

        about_text_edit = QTextEdit(self.about_widget)
        about_text_edit.setText(
            "developed by Maurice Jarck\nwith kind support from Shuai Lou\n07.2020-04.2021"
        )
        about_text_edit.setEnabled(False)
        stacked_widget_about_layout = QGridLayout(self.about_widget)
        stacked_widget_about_layout.addWidget(about_text_edit)

        p_apperance_layout = QHBoxLayout(self.p_preferences)
        p_apperance_layout.addWidget(self.list_Widget)
        p_apperance_layout.addWidget(self.stacked_widget_preferences)

    def setup_signals(self) -> None:
        """connects signals

        Returns:
            None"""

        # header
        for filter, editor in zip(self.filters, self.header.editors):
            editor.textChanged.connect(filter.setFilterRegExp)

        # line edit
        self.in_new_filename.returnPressed.connect(lambda: self.validate(
            self.new,
            line_edit_list=[self.in_new_filepath, self.in_new_filename],
            data=False))

        # comboboxes
        self.in_combobox_devicetype.addItems(
            ["choose here"] + [x.__name__ for x in valid_devices])
        self.in_combobox_devicetype.currentIndexChanged.connect(
            lambda: self.update_combobox(
                self.in_combobox_os, valid_devices[
                    self.in_combobox_devicetype.currentIndex() - 1].expected_OS
            ))
        self.in_combo_themes.currentIndexChanged.connect(
            lambda: self.change_theme(self.in_combo_themes.currentText()))
        self.in_combo_theme_initial.currentTextChanged.connect(lambda: setattr(
            self, "initial_theme", self.in_combo_theme_initial.currentText()))
        # btns
        self.bt_delete_column.clicked.connect(self.delete)
        # self.bt_hide_show_filter.clicked.connect(lambda: self.toggle_hide_show_ani(37, 47, "height", self.header, b"maximumHeight"))
        self.bt_hide_show_filter.clicked.connect(self.header.hide_show)
        # self.bt_hide_show_filter.clicked.connect(lambda: self.toggle_hide_show_ani(30, 44, "height", self.header, b"maximumHeight"))
        self.bt_register_new.clicked.connect(
            lambda: self.stacked_widget.setCurrentWidget(self.p_register))
        self.bt_enter_register.clicked.connect(lambda: self.validate(
            self.register,
            line_edit_list=[self.in_username, self.in_devicename],
            combo_box_list=[self.in_combobox_devicetype, self.in_combobox_os],
            forbidden=list(self.registered_devices.keys()),
            checkfname=True))
        self.bt_create.clicked.connect(lambda: self.validate(
            self.new,
            line_edit_list=[self.in_new_filepath, self.in_new_filename],
            data=False))
        self.bt_mod_new_path.clicked.connect(lambda: self.new(True))
        self.bt_burger.clicked.connect(lambda: self.toggle_hide_show_ani(
            0,
            66,
            "width",
            self.left_menu_frame,
            b"maximumWidth",
        ))
        # menu bar
        self.action_register.triggered.connect(
            lambda: self.stacked_widget.setCurrentWidget(self.p_register))
        self.action_open.triggered.connect(self.get_open_file_path)
        self.action_save.triggered.connect(self.save)
        self.action_new.triggered.connect(lambda: self.new(True))
        self.action_print.triggered.connect(
            lambda: self.validate(self.print, data=False, checkfname=True))
        self.action_hide_menu_bar.triggered.connect(
            lambda: self.toggle_hide_show(self.menu_Bar))
        self.action_preferences.triggered.connect(self.p_preferences.show)
        # cancel
        self.bt_cancel_register.clicked.connect(lambda: self.cancel([
            self.in_username, self.in_devicename, self.in_combobox_os, self.
            in_comment
        ]))

        # list widget
        self.list_Widget.currentRowChanged.connect(
            lambda: self.stacked_widget_preferences.setCurrentIndex(
                self.list_Widget.currentIndex().row()))

        # slider
        self.text_size_slider.sliderMoved.connect(
            lambda: self.change_font_size(self.text_size_slider.value()))
        # self.text_size_slider.sliderMoved.connect(lambda: print(self.text_size_slider.value()))

    def change_theme(self, theme) -> None:
        """changes theme according to combobox selection

        Returns:
            None"""

        with open(f"./data/{theme}.css", "r") as file:
            stylesheed = " ".join(file.readlines())
            self.setStyleSheet(stylesheed)
            self.p_preferences.setStyleSheet(stylesheed)

        if self.in_combo_themes.currentText() == "dark_theme":

            self.left_btn_frame.setStyleSheet(
                u"background: #455364; border: 0px solid;")
            self.p_view_layout3.setSpacing(30)

        else:
            self.left_btn_frame.setStyleSheet(
                u"background: #ADADAD; border: 0px solid;")
            self.p_view_layout3.setSpacing(25)

        return self.in_combo_themes.currentText()

    def toggle_hide_show_ani(self, collapsed_val: int, expanded_val: int,
                             actual: str, to_animate, property: bytes):
        """interpolates over a defined range of vales and sets it to a given property of a given widget"""
        if getattr(to_animate, actual)() == expanded_val:
            destination = collapsed_val
        else:
            destination = expanded_val
        print(getattr(to_animate, actual)(), destination)
        self.ani = QPropertyAnimation(to_animate, property)
        self.ani.setDuration(300)
        self.ani.setStartValue(getattr(to_animate, actual)())
        self.ani.setEndValue(destination)
        self.ani.setEasingCurve(QEasingCurve.Linear)
        self.ani.start()

    def toggle_hide_show(self, widget: QWidget) -> None:
        """toggles visibiliy of a given widget
        Arg:
            widget: widget which is aimed to be hidden or shown
        Returs:
            None"""

        if widget.isVisible():
            widget.hide()
        else:
            widget.show()

    def reopen_last_file(self) -> None:
        """asks for reopening of the last opened file"""
        if self.last_open_file_path != "" or self.last_open_file_path is not None:
            reopen_dialog = QMessageBox.question(
                self.p_view, "reopen last file?",
                "Do you want to reopen the last edited file?",
                QMessageBox.Yes | QMessageBox.No)
            if reopen_dialog == QMessageBox.Yes:
                self.file_path = self.last_open_file_path
                self.load()

    def change_font_size(self, size: int) -> None:
        """changes all font sizes"""
        self.font.setPointSize(size)
        self.menu_Bar.setFont(self.font)
        self.header.setFont(self.font)
        self.table.setFont(self.font)
        self.p_preferences.setFont(self.font)

    def set_user_preferences(self) -> None:
        """Reads user_config file and sets its propertys"""
        with open(self.user_config_file, "r") as config_file:
            data = dict(json.load(config_file))

            self.last_open_file_path = data["last_open_file_path"]
            self.initial_theme = data['initial_theme']
            self.change_font_size(data['font_size'])
            self.text_size_slider.setValue(data['font_size'])
            self.in_combo_theme_initial.setCurrentText(self.initial_theme)
            self.in_combo_themes.setCurrentText(self.initial_theme)

            with open(f"./data/{self.initial_theme}.css") as file:
                style_sheed = " ".join(file.readlines())
                self.setStyleSheet(style_sheed)
                self.p_preferences.setStyleSheet(style_sheed)

            self.bt_burger.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.bt_register_new.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.bt_delete_column.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.bt_hide_show_filter.setStyleSheet(
                "border: 0px solid; background: transparent;")
            self.left_menu_frame.setStyleSheet(u" border: 0px solid;")

            if self.initial_theme == "dark_theme":
                self.left_btn_frame.setStyleSheet(
                    u"background: #455364; border: 0px solid;")

            else:
                self.left_btn_frame.setStyleSheet(
                    u"background: #ADADAD; border: 0px solid;")

    def cancel(self, widgets: list) -> None:
        """click event for all cancel buttons

        shows fist page in stacked widget and clears all widgets in widgets

        Args:
               widgets: defines list containing widgets to clear, only widgets with method .clear() are possible

        Returns:
            None"""
        for widget in widgets:
            widget.clear()
        self.stacked_widget.setCurrentWidget(self.p_view)

    def update_combobox(self, box, data: list) -> None:
        """ clears combo box

        updates combobox so that old content not needed any more isnt displayed and adds 'choose here' dummy
        to ensure an index change will be made (updating next box depends on index change)
        Args:
            box: instance of pyqt5.QtWidgets.qComboBox
            data: data supposed to be inserted into combobox
        Returns:
            None"""

        box.clear()
        box.addItems(["choose here"] + data)

    def validate(self,
                 command,
                 file_path: str = None,
                 schema=None,
                 line_edit_list: list = None,
                 combo_box_list: list = None,
                 data=None,
                 forbidden: list = None,
                 checkfname: bool = None) -> None:
        """validates user input

        Args:
            command: function to be called after vailidation process if finished
            line_edit_list: contents pyqt5.QtWidgets.QlineEdit instances to be checked if empty or current text in forbidden or not in allowed
            combo_box_list: contents pyqt5.QtWidgets.qComboBox instances to be checked if nothing selected
            data: data to be passed into command function if needed
            forbidden: houses keys which are not allowed to be entered
            checkfname: check weather an file path exists or not

        Returns:
            None"""

        fails = 0
        if line_edit_list is not None:
            for x in line_edit_list:
                if x.text() == "":
                    x.setText("fill all fields")
                    fails += 1
                if forbidden is not None and x.text() in forbidden:
                    x.setText("in forbidden!!")
                    fails += 1
        if combo_box_list is not None:
            for combobox in combo_box_list:
                if combobox.currentText() == "":
                    self.statusbar.showMessage("all comboboxes must be filled")
                    fails += 1
        if checkfname is True and self.file_path is None:
            self.statusbar.showMessage(
                "no file path specified, visit Ctrl+o or menuebar/edit/open to fix"
            )
            fails += 1

        if file_path is not None:
            if forbidden is not None and file_path in forbidden:
                fails += 1
                self.statusbar.showMessage("select a file to continue")
            else:
                try:
                    validate_json.validate(file_path, schema)
                except ValidationError as e:
                    self.msg_box = QtWidgets.QMessageBox.critical(
                        self, "validation failed",
                        f"Invalid Json file, problem in: {e.messages}")
                    fails += 1
        if fails == 0:
            if data is None:
                command()
            else:
                command(data)
        else:
            message = f"problem\ncommand: {command.__name__}\nfails: {fails}"
            print(message)
            return message

    def register(self) -> None:
        """registers a new device and saves

        Returns:
            None"""
        logic.register(devname=self.in_devicename.text(),
                       devtype=[
                           device for device in valid_devices
                           if device.__name__ ==
                           self.in_combobox_devicetype.currentText()
                       ].pop(),
                       username=self.in_username.text(),
                       os=self.in_combobox_os.currentText(),
                       comment=self.in_comment.toPlainText(),
                       datetime=str(datetime.datetime.now()),
                       registered_devices=self.registered_devices)

        new_values = [
            self.in_devicename.text(),
            self.in_username.text(),
            self.in_combobox_os.currentText(),
            [
                device.__name__ for device in valid_devices if device.__name__
                == self.in_combobox_devicetype.currentText()
            ].pop(),
            self.in_comment.toPlainText(),
            str(datetime.datetime.now())
        ]
        row = [QStandardItem(str(item)) for item in new_values]
        self.model.appendRow(row)

        self.stacked_widget.setCurrentWidget(self.p_view)
        self.in_devicename.clear()
        self.in_username.clear()
        self.in_combobox_os.clear()
        self.in_comment.clear()
        self.save()

    def delete(self) -> None:
        """deletes all rows associated with min 1 slected cell
        Returns:
            None"""
        rows = sorted(set(index.row()
                          for index in self.table.selectedIndexes()),
                      reverse=True)
        qb = QMessageBox()
        answ = qb.question(self, 'delete rows',
                           f"Are you sure to delete {rows} rows?",
                           qb.Yes | qb.No)

        if answ == qb.Yes:
            for row in rows:
                self.registered_devices.pop(
                    str(self.model.index(row, 0).data()))
                self.model.removeRow(row)
            qb.information(self, 'notification', f"deleted {rows} row")
        else:
            qb.information(self, 'notification', "Nothing Changed")
        self.save()

    def get_open_file_path(self) -> None:
        """gets file-path and set it to self.file_path, extra step for json validation

        Returns:
            None"""

        self.file_path = \
            QFileDialog.getOpenFileName(self, "open file", f"{self.last_open_file_dir or 'c://'}",
                                        "json files (*json)")[0]
        self.validate(command=self.load,
                      file_path=self.file_path,
                      schema=validate_json.ItHilfeDataSchema,
                      forbidden=[""])

    def load(self) -> None:
        """opens json file and loads its content into registered devices

        Returns:
            None"""

        self.model.clear()
        self.registered_devices.clear()
        with open(self.file_path, "r") as file:
            data = dict(json.load(file))
            devices = data["devices"].values()
            self.last_open_file_dir = data["last_open_file_dir"]
            for value in devices:
                row = []
                for i, item in enumerate(value):
                    cell = QStandardItem(str(item))
                    row.append(cell)
                    if i == 0 or i == 3 or i == 5:
                        cell.setEditable(False)
                self.model.appendRow(row)

                new = [x for x in valid_devices
                       if x.__name__ == value[3]].pop(0)(value[0], value[1],
                                                         value[4], value[5])
                new.OS = value[2]
                self.registered_devices[value[0]] = new

        self.model.setHorizontalHeaderLabels(labels)
        self.statusbar.showMessage("")

        # auto complete
        for a in range(len(self.header.editors)):
            completer = QCompleter([
                self.model.data(self.model.index(x, a))
                for x in range(self.model.rowCount())
            ])
            completer.setCompletionMode(QCompleter.InlineCompletion)
            self.header.editors[a].setCompleter(completer)

    def save(self) -> None:
        """saves content fo self.registered_devices into specified json file

        Returns:
            None"""
        if not self.file_path:
            self.statusbar.showMessage(
                "no file path set all changes get lost if closed")
        else:
            with open(
                    self.file_path,
                    'w',
            ) as file:
                devices = {
                    k: [
                        v.name, v.user, v.OS, v.__class__.__name__, v.comment,
                        v.datetime
                    ]
                    for (k, v) in enumerate(self.registered_devices.values())
                }
                last_open_file_dir = "/".join(self.file_path.split("/")[:-1])
                resulting_dict = {
                    "devices": devices,
                    "last_open_file_dir": last_open_file_dir
                }
                json.dump(resulting_dict, file)
                self.statusbar.showMessage("saved file")

        with open(self.user_config_file, "w") as user_preferences_file:
            json.dump(
                {
                    "last_open_file_path": self.last_open_file_path,
                    "initial_theme": self.initial_theme,
                    "font_size": self.text_size_slider.value()
                }, user_preferences_file)

    def new(self, stage: bool, test: bool = False) -> None:
        """creates new csv file to save into

        stage is True: set filepath
        stage is False: set new name, save
        Args:
            stage: determines a which stage to execute this function

        Returns:
            None"""

        if stage is True:
            if not test:
                self.dir = QFileDialog.getExistingDirectory(
                    self, "select a folder", "c://")
            self.stacked_widget.setCurrentWidget(self.p_create)
            self.in_new_filepath.setText(self.dir)
            self.registered_devices.clear()

        else:
            self.file_path = self.dir + f"/{self.in_new_filename.text()}.json"
            self.save()
            self.stacked_widget.setCurrentWidget(self.p_view)

    def print(self, test: bool) -> None:
        """setup and preview pViewTable for paper printing

        Returns:
            None"""

        with open(self.file_path) as f:
            self.data = json.dumps(dict(json.load(f)),
                                   sort_keys=True,
                                   indent=6,
                                   separators=(".", "="))
        self.document = QtWidgets.QTextEdit()
        self.document.setText(self.data)

        if not test:
            printer = QPrinter()
            previewDialog = QPrintPreviewDialog(printer, self)
            previewDialog.paintRequested.connect(
                lambda: self.document.print_(printer))
            previewDialog.exec_()
예제 #21
0
class SearchBarEditor(QTableView):
    """A Google-like search bar, implemented as a QTableView with a _CustomLineEditDelegate in the first row.
    """

    data_committed = Signal()

    def __init__(self, parent, tutor=None):
        """Initializes instance.

        Args:
            parent (QWidget): parent widget
            tutor (QWidget, NoneType): another widget used for positioning.
        """
        super().__init__(parent)
        self._tutor = tutor
        self._base_size = QSize()
        self._base_offset = QPoint()
        self._original_text = None
        self._orig_pos = None
        self.first_index = QModelIndex()
        self.model = QStandardItemModel(self)
        self.proxy_model = QSortFilterProxyModel(self)
        self.proxy_model.setSourceModel(self.model)
        self.proxy_model.filterAcceptsRow = self._proxy_model_filter_accepts_row
        self.setModel(self.proxy_model)
        self.verticalHeader().hide()
        self.horizontalHeader().hide()
        self.setShowGrid(False)
        self.setMouseTracking(True)
        self.setTabKeyNavigation(False)
        delegate = _CustomLineEditDelegate(self)
        delegate.text_edited.connect(self._handle_delegate_text_edited)
        self.setItemDelegateForRow(0, delegate)

    def set_data(self, current, items):
        """Populates model.

        Args:
            current (str)
            items (Sequence(str))
        """
        item_list = [QStandardItem(current)]
        for item in items:
            qitem = QStandardItem(item)
            item_list.append(qitem)
            qitem.setFlags(~Qt.ItemIsEditable)
        self.model.invisibleRootItem().appendRows(item_list)
        self.first_index = self.proxy_model.mapFromSource(
            self.model.index(0, 0))

    def set_base_size(self, size):
        self._base_size = size

    def set_base_offset(self, offset):
        self._base_offset = offset

    def update_geometry(self):
        """Updates geometry.
        """
        self.horizontalHeader().setDefaultSectionSize(self._base_size.width())
        self.verticalHeader().setDefaultSectionSize(self._base_size.height())
        self._orig_pos = self.pos() + self._base_offset
        if self._tutor:
            self._orig_pos += self._tutor.mapTo(self.parent(),
                                                self._tutor.rect().topLeft())
        self.refit()

    def refit(self):
        self.move(self._orig_pos)
        table_height = self.verticalHeader().length()
        size = QSize(self._base_size.width(),
                     table_height + 2).boundedTo(self.parent().size())
        self.resize(size)
        # Adjust position if widget is outside parent's limits
        bottom_right = self.mapToGlobal(self.rect().bottomRight())
        parent_bottom_right = self.parent().mapToGlobal(
            self.parent().rect().bottomRight())
        x_offset = max(0, bottom_right.x() - parent_bottom_right.x())
        y_offset = max(0, bottom_right.y() - parent_bottom_right.y())
        self.move(self.pos() - QPoint(x_offset, y_offset))

    def data(self):
        return self.first_index.data(Qt.EditRole)

    @Slot("QString")
    def _handle_delegate_text_edited(self, text):
        """Filters model as the first row is being edited."""
        self._original_text = text
        self.proxy_model.setFilterRegExp("^" + text)
        self.proxy_model.setData(self.first_index, text)
        self.refit()

    def _proxy_model_filter_accepts_row(self, source_row, source_parent):
        """Always accept first row.
        """
        if source_row == 0:
            return True
        return QSortFilterProxyModel.filterAcceptsRow(self.proxy_model,
                                                      source_row,
                                                      source_parent)

    def keyPressEvent(self, event):
        """Sets data from current index into first index as the user navigates
        through the table using the up and down keys.
        """
        super().keyPressEvent(event)
        event.accept(
        )  # Important to avoid unhandled behavior when trying to navigate outside view limits
        # Initialize original text. TODO: Is there a better place for this?
        if self._original_text is None:
            self.proxy_model.setData(self.first_index, event.text())
            self._handle_delegate_text_edited(event.text())
        # Set data from current index in model
        if event.key() in (Qt.Key_Up, Qt.Key_Down):
            current = self.currentIndex()
            if current.row() == 0:
                self.proxy_model.setData(self.first_index, self._original_text)
            else:
                self.proxy_model.setData(self.first_index, current.data())

    def currentChanged(self, current, previous):
        super().currentChanged(current, previous)
        self.edit_first_index()

    def edit_first_index(self):
        """Edits first index if valid and not already being edited.
        """
        if not self.first_index.isValid():
            return
        if self.isPersistentEditorOpen(self.first_index):
            return
        self.edit(self.first_index)

    def mouseMoveEvent(self, event):
        """Sets the current index to the one hovered by the mouse."""
        if not self.currentIndex().isValid():
            return
        index = self.indexAt(event.pos())
        if index.row() == 0:
            return
        self.setCurrentIndex(index)

    def mousePressEvent(self, event):
        """Commits data."""
        index = self.indexAt(event.pos())
        if index.row() == 0:
            return
        self.proxy_model.setData(self.first_index, index.data(Qt.EditRole))
        self.data_committed.emit()
예제 #22
0
파일: main.py 프로젝트: zdrgbsky/KDChart
class MyWidget(QWidget):
    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)

        self.view = View()
        self.grid = DateTimeGrid()
        self.slider = QSlider(self)
        self.model = QStandardItemModel(self)
        self.cmodel = ConstraintModel()

        ## proxyModel.setSourceModel( &model );
        for i in range(0, 10):
            item = MyStandardItem("Multi Item " + str(i))
            for j in range(0, 20, 3):
                item.appendRow([
                    MyStandardItem("Item " + str(j)),
                    MyStandardItem(KDGantt.TypeTask),
                    MyStandardItem(QDateTime.currentDateTime().addDays(j),
                                   KDGantt.StartTimeRole),
                    MyStandardItem(
                        QDateTime.currentDateTime().addDays(j + 1 + i / 7),
                        KDGantt.EndTimeRole),
                    MyStandardItem(50)
                ])

            item.appendRow([
                MyStandardItem("Event"),
                MyStandardItem(KDGantt.TypeEvent),
                MyStandardItem(QDateTime.currentDateTime(),
                               KDGantt.StartTimeRole),
                MyStandardItem(QDateTime(), KDGantt.EndTimeRole),
                MyStandardItem("")
            ])

            self.model.appendRow([
                item,
                MyStandardItem(KDGantt.TypeMulti),
                MyStandardItem(""),
                MyStandardItem(""),
                MyStandardItem("")
            ])

        pidx = self.model.index(0, 0)
        pidx = self.model.index(0, 0, pidx)
        self.cmodel.addConstraint(
            Constraint(self.model.index(0, 0, pidx),
                       self.model.index(1, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(1, 0, pidx),
                       self.model.index(0, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(1, 0, pidx),
                       self.model.index(10, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(3, 0, pidx),
                       self.model.index(5, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(7, 0, pidx),
                       self.model.index(4, 0, pidx)))

        self.slider.setOrientation(Qt.Horizontal)
        self.slider.setRange(1, 1000)
        self.slider.setValue(100)
        l = QVBoxLayout(self)
        l.addWidget(self.view)
        l.addWidget(self.slider)
        self.grid.setStartDateTime(QDateTime.currentDateTime().addDays(-3))
        self.grid.setDayWidth(100)
        self.grid.setFreeDays([Qt.Saturday, Qt.Sunday])
        self.grid.setFreeDaysBrush(QBrush(Qt.red))

        lv = MyListView(self)
        self.view.setLeftView(lv)
        self.view.setRowController(
            ListViewRowController(lv, self.view.ganttProxyModel()))
        self.view.setGrid(self.grid)
        self.view.setModel(self.model)
        ##view.setConstraintModel( &cmodel );
        self.slider.valueChanged.connect(self.slotZoom)

    def slotZoom(self, z):
        self.grid.setDayWidth(z)
예제 #23
0
class StatusModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._calculator = None

        # Create the status items
        chi_item = StatusItem('chiSq',
                              title='Current \u03c7\u00b2',
                              additionalData=1)
        chi_item.setReturn(True)
        chi_item.title = 'Previous \u03c7\u00b2'
        chi_item.setReturn(False)
        self._interestedList = StatusList([
            chi_item,
            StatusItem('numPars', title='Fit parameters', additionalData=1),
            StatusItem('numData', title='Experiments', additionalData=0),
            StatusItem('numPhases', title='Phases', additionalData=0)
        ])

        # minor properties
        self._first_role = Qt.UserRole + 1

        self._statusBarModel = QStandardItemModel()
        self._chartDisplayModel = QStandardItemModel()
        # set role names
        self._role_names_list = ['label', 'value']
        self._roles_list = []
        self._roles_dict = {'status': {}, 'plot': {}}
        self._setRolesListAndDict()
        self._statusBarModel.setItemRoleNames(self._roles_dict['status'])
        self._chartDisplayModel.setItemRoleNames(self._roles_dict['plot'])

        self._log = logger.getLogger(self.__class__.__module__)

    def _setRolesListAndDict(self):
        """..."""
        offset = 100
        for i, role_name in enumerate(self._role_names_list):
            display_role = self._first_role + i
            self._roles_dict['status'][display_role] = role_name.encode()
            self._roles_list.append(display_role)
            self._roles_dict['plot'][self._first_role + i +
                                     offset] = role_name.encode()

    def _setModelsFromProjectDict(self):
        """Create the initial data list with structure for GUI fitables table."""
        _ = self._statusBarModel.removeColumns(
            0, self._statusBarModel.columnCount())
        _ = self._chartDisplayModel.removeColumns(
            0, self._chartDisplayModel.columnCount())

        column_status_bar = []
        column_chart_display = []

        self._updateStatusList()

        for interest in self._interestedList:
            # Add the status bar item
            column_status_bar.append(
                self._makeItem(interest, self._roles_dict['status'].items()))
            # Does this need to added to the plot?
            if interest.additionalData == 1:
                column_chart_display.append(
                    self._makeItem(interest, self._roles_dict['plot'].items()))

            # Does this item also have previous values which need to be shown?
            if interest.hasPrevious:
                interest.setReturn(True)
                if interest.value is not None:
                    column_status_bar.append(
                        self._makeItem(interest,
                                       self._roles_dict['status'].items()))
                interest.setReturn(False)

        # Set the models
        self._statusBarModel.appendColumn(column_status_bar)
        self._chartDisplayModel.appendColumn(column_chart_display)

        self._statusBarModel.dataChanged.emit(
            self._statusBarModel.index(0, 0),
            self._statusBarModel.index(self._statusBarModel.rowCount() - 1,
                                       self._statusBarModel.columnCount() - 1),
            self._roles_list)

    def _updateStatusList(self):
        """Update the values of the Item List"""
        project_dict = self._project_dict

        # Set chi squared
        try:
            self._interestedList.setItemValue(
                'chiSq',
                round(float(project_dict['info']['chi_squared'].value), 2))
        except KeyError:
            self._interestedList.setItemValue('chiSq', 0)

        # Get number of parameters
        num_pars = get_num_refine_pars(project_dict.asDict())

        # Set the other parameters.
        self._interestedList.setItemValue('numPars', num_pars)
        self._interestedList.setItemValue('numPhases',
                                          len(project_dict['phases']))
        self._interestedList.setItemValue('numData',
                                          len(project_dict['experiments']))

    def returnStatusBarModel(self):
        """Return the status bar model."""
        return self._statusBarModel

    def onRefinementDone(self):
        """Define what to do when the refinement done is triggered"""
        self._setModelsFromProjectDict()
        self._chartDisplayModel.layoutChanged.emit()

    def returnChartModel(self):
        """Return the chart model"""
        return self._chartDisplayModel

    @staticmethod
    def _makeItem(this_interest, these_items):
        """Make an item. This can be a plot or status bar"""
        item = QStandardItem()
        for role, role_name_bytes in these_items:
            role_name = role_name_bytes.decode()
            if role_name == 'label':
                value = this_interest.title
            elif role_name == 'value':
                value = this_interest.value
            else:
                continue
            item.setData(value, role)
        return item
예제 #24
0
class MainWindow(QMainWindow):
    _tr = QCoreApplication.translate

    def __init__(self, parent=None):
        super().__init__(parent)  # 调用父类构造函数,创建窗体
        self.__scene = None  # 创建QGraphicsScene
        self.__view = None  # 创建图形视图组件
        self.ui = Ui_MainWindow()  # 创建UI对象
        self.ui.setupUi(self)  # 构造UI界面
        self.operatorFile = OperatorFile(self)

        self.__translator = None
        title = self.tr("基于Python的图的绘制及相关概念的可视化展示")
        self.setWindowTitle(title)

        self.ui.nodeDetails.setEnabled(False)
        self.ui.edgeDetails.setEnabled(False)
        self.ui.actionSave.setEnabled(False)

        self.edgeModel = QStandardItemModel(5, 5, self)
        self.edgeSelectionModel = QItemSelectionModel(self.edgeModel)
        self.edgeModel.dataChanged.connect(self.do_updateEdgeWeight)

        self.nodeModel = QStandardItemModel(5, 4, self)
        self.nodeSelectionModel = QItemSelectionModel(self.nodeModel)
        self.nodeModel.dataChanged.connect(self.do_updateNodeWeight)

        self.spinWeight = WeightSpinDelegate(0, 200, 1, self)

        self.ui.tabWidget.setVisible(False)
        self.ui.tabWidget.clear()
        self.ui.tabWidget.setTabsClosable(True)
        self.ui.tabWidget.setDocumentMode(True)
        self.setCentralWidget(self.ui.tabWidget)
        self.setAutoFillBackground(True)

        self.__buildStatusBar()  # 构造状态栏
        self.__buildUndoCommand()  # 初始化撤销重做系统
        self.__initModeMenu()
        self.__lastColumnFlag = Qt.NoItemFlags

        self.iniGraphicsSystem()

        self.__ItemId = 0  # 绘图项自定义数据的key
        self.__ItemDesc = 1  # 绘图项自定义数据的key

        self.__nodeNum = 0  # 结点的序号
        self.__edgeNum = 0  # 边的序号
        self.__textNum = 0

        self.lastColumnFlags = (Qt.ItemIsSelectable | Qt.ItemIsUserCheckable
                                | Qt.ItemIsEnabled)

        self.__graph = Graph()

    ##  ==============自定义功能函数============

    def nodeNum(self):
        return self.__nodeNum

    def edgeNum(self):
        return self.__edgeNum

    def scene(self):
        self.viewAndScene()
        return self.__scene

    def view(self):
        self.viewAndScene()
        return self.__view

    def graph(self):
        return self.__graph

    def __buildStatusBar(self):  ##构造状态栏
        self.__labViewCord = QLabel(self._tr("MainWindow", "视图坐标:"))
        self.__labViewCord.setMinimumWidth(150)
        self.ui.statusbar.addWidget(self.__labViewCord)

        self.__labSceneCord = QLabel(self._tr("MainWindow", "场景坐标:"))
        self.__labSceneCord.setMinimumWidth(150)
        self.ui.statusbar.addWidget(self.__labSceneCord)

        self.__labItemCord = QLabel(self._tr("MainWindow", "图元坐标:"))
        self.__labItemCord.setMinimumWidth(150)
        self.ui.statusbar.addWidget(self.__labItemCord)

        self.__labItemInfo = QLabel(self._tr("MainWindow", "图元信息: "))
        self.ui.statusbar.addPermanentWidget(self.__labItemInfo)
        self.__labModeInfo = QLabel(self._tr("MainWindow", "有向图模式"))
        self.ui.statusbar.addPermanentWidget(self.__labModeInfo)

    def __buildUndoCommand(self):
        self.undoStack = QUndoStack()
        self.addAction(self.ui.actionUndo)
        self.addAction(self.ui.actionRedo)
        self.ui.undoView.setStack(self.undoStack)

    def __setItemProperties(self, item, desc):  ##item是具体类型的QGraphicsItem
        self.__nodeNum = len(self.singleItems(BezierNode))
        self.__edgeNum = len(self.singleItems(BezierEdge))
        self.__textNum = len(self.singleItems(BezierText))
        item.setFlag(QGraphicsItem.ItemIsFocusable)
        item.setFlag(QGraphicsItem.ItemIsMovable)
        item.setFlag(QGraphicsItem.ItemIsSelectable)
        item.setPos(-150 + randint(1, 200), -200 + randint(1, 200))

        if type(item) is BezierNode:
            newNum = self.checkSort(self.__scene.uniqueIdList(BezierNode))
            if newNum is not None:
                item.setData(self.__ItemId, newNum)
                item.textCp.setPlainText("V" + str(newNum))
            else:
                item.setData(self.__ItemId, self.__nodeNum)
                item.textCp.setPlainText("V" + str(self.__nodeNum))
            self.__nodeNum = 1 + self.__nodeNum
        elif type(item) is BezierEdge:
            newNum = self.checkSort(self.__scene.uniqueIdList(BezierEdge))
            if newNum is not None:
                item.setData(self.__ItemId, newNum)
                item.textCp.setPlainText("e" + str(newNum))
            else:
                item.setData(self.__ItemId, self.__edgeNum)
                item.textCp.setPlainText("e" + str(self.__edgeNum))
            self.__edgeNum = 1 + self.__edgeNum
        elif type(item) is BezierText:
            newNum = self.checkSort(self.__scene.uniqueIdList(BezierText))
            if newNum is not None:
                item.setData(self.__ItemId, newNum)
            else:
                item.setData(self.__ItemId, self.__textNum)
            self.__textNum = 1 + self.__textNum

        item.setData(self.__ItemDesc, desc)  # 图件描述

        self.__scene.addItem(item)
        self.__scene.clearSelection()

        item.setSelected(True)

    def __setBrushColor(self, item):  ##设置填充颜色
        color = item.brush().__color()
        color = QColorDialog.getColor(color, self,
                                      self._tr("MainWindow", "选择填充颜色"))
        if color.isValid():
            item.setBrush(QBrush(color))

    def __initFileMenu(self):
        self.ui.actionOpen.triggered.connect(self.do_open_file)
        self.ui.actionSave.triggered.connect(self.do_save_file)
        self.ui.actionQuit.triggered.connect(self.close)

    def __initModeMenu(self):
        modeMenuGroup = QActionGroup(self)
        modeMenuGroup.addAction(self.ui.actionDigraph_Mode)
        modeMenuGroup.addAction(self.ui.actionRedigraph_Mode)

    def __updateEdgeView(self):
        edges = self.singleItems(BezierEdge)
        if len(edges):
            self.ui.edgeDetails.setEnabled(True)
        else:
            return
        edgeColCount = 5

        self.edgeModel.clear()
        edgeHeaderList = [
            self._tr("MainWindow", 'ID'),
            self._tr("MainWindow", '始点'),
            self._tr("MainWindow", '终点'),
            self._tr("MainWindow", '坐标'),
            self._tr("MainWindow", '权重')
        ]
        self.edgeModel.setHorizontalHeaderLabels(edgeHeaderList)
        self.edgeSelectionModel.currentChanged.connect(self.do_curEdgeChanged)

        self.ui.edgeDetails.setModel(self.edgeModel)
        self.ui.edgeDetails.setSelectionModel(self.edgeSelectionModel)
        self.ui.edgeDetails.verticalHeader().setSectionResizeMode(
            QHeaderView.Fixed)
        self.ui.edgeDetails.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.ui.edgeDetails.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.ui.edgeDetails.setAlternatingRowColors(True)
        self.edgeModel.setRowCount(len(edges))
        self.ui.edgeDetails.setItemDelegateForColumn(4, self.spinWeight)
        edges.reverse()
        for i in range(len(edges)):
            edge: BezierEdge = edges[i]
            sourceNode = f'V{edge.sourceNode.data(self.__ItemId)}' if edge.sourceNode else None
            destNode = f'V{edge.destNode.data(self.__ItemId)}' if edge.destNode else None

            strList = [
                f"e{edge.data(self.__ItemId)}", sourceNode, destNode,
                f"x:{edge.pos().x()},y:{edge.pos().y()}", f"{edge.weight()}"
            ]

            for j in range(edgeColCount):
                item = QStandardItem(strList[j])
                if j != edgeColCount - 1:
                    item.setFlags(self.__lastColumnFlag)
                self.edgeModel.setItem(i, j, item)

    def __updateNodeView(self):
        nodes = self.singleItems(BezierNode)
        if len(nodes):
            self.ui.nodeDetails.setEnabled(True)
        else:
            return
        nodeColCount = 4
        self.nodeModel.clear()
        nodeHeaderList = [
            self._tr("MainWindow", 'ID'),
            self._tr("MainWindow", '边数'),
            self._tr("MainWindow", '坐标'),
            self._tr("MainWindow", '权重')
        ]
        if self.ui.actionDigraph_Mode.isChecked():
            nodeHeaderList.append(self._tr("MainWindow", '出度'))
            nodeHeaderList.append(self._tr("MainWindow", '入度'))
            nodeColCount += 2
        else:
            nodeHeaderList.append(self._tr("MainWindow", "度"))
            nodeColCount += 1
        self.nodeModel.setHorizontalHeaderLabels(nodeHeaderList)
        self.nodeModel.setRowCount(len(nodes))
        self.nodeSelectionModel.currentChanged.connect(self.do_curNodeChanged)
        self.ui.nodeDetails.setModel(self.nodeModel)
        self.ui.nodeDetails.setSelectionModel(self.nodeSelectionModel)
        self.ui.nodeDetails.verticalHeader().setSectionResizeMode(
            QHeaderView.Fixed)
        self.ui.nodeDetails.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        self.ui.nodeDetails.setAlternatingRowColors(True)
        self.ui.nodeDetails.setItemDelegateForColumn(3, self.spinWeight)
        nodes.reverse()
        for i in range(len(nodes)):
            node: BezierNode = nodes[i]
            strList = [
                f"V{node.data(self.__ItemId)}",
                str(len(node.bezierEdges)),
                f"x:{node.pos().x()},y:{node.pos().y()}",
                str(node.weight())
            ]
            if self.ui.actionDigraph_Mode.isChecked():
                strList.append(
                    f'{node.degrees(self.ui.actionDigraph_Mode.isChecked())[1]}'
                )
                strList.append(
                    f'{node.degrees(self.ui.actionDigraph_Mode.isChecked())[0]}'
                )
            else:
                strList.append(
                    f'{node.degrees(self.ui.actionDigraph_Mode.isChecked())}')
            for j in range(nodeColCount):
                item = QStandardItem(strList[j])
                if j != 3:
                    item.setFlags(self.__lastColumnFlag)
                self.nodeModel.setItem(i, j, item)

    def iniGraphicsSystem(self, name=None):  ##初始化 Graphics View系统
        scene = GraphicsScene()  # 创建QGraphicsScene
        view = GraphicsView(self, scene)  # 创建图形视图组件
        view.mouseMove.connect(self.do_mouseMove)  # 鼠标移动
        view.mouseClicked.connect(self.do_mouseClicked)  # 左键按下
        scene.itemMoveSignal.connect(self.do_shapeMoved)
        scene.itemLock.connect(self.do_nodeLock)
        scene.isHasItem.connect(self.do_checkIsHasItems)
        if name:
            title = name
        else:
            text = self.tr('未命名')
            title = f'{text}{self.ui.tabWidget.count()}'
        curIndex = self.ui.tabWidget.addTab(view, title)
        self.ui.tabWidget.setCurrentIndex(curIndex)
        self.ui.tabWidget.setVisible(True)

        ##  4个信号与槽函数的关联

        # self.view.mouseDoubleClick.connect(self.do_mouseDoubleClick)  # 鼠标双击
        # self.view.keyPress.connect(self.do_keyPress)  # 左键按下

    def singleItems(self, className) -> list:
        self.viewAndScene()
        return self.__scene.singleItems(className)

    def connectGraph(self):
        self.__graph.setMode(self.ui.actionDigraph_Mode.isChecked())
        items = self.__scene.uniqueItems()
        nodeList = []
        edgeList = []
        if not len(items):
            return
        for item in items:
            if type(item) is BezierNode:
                nodeList.append(item)
            elif type(item) is BezierEdge:
                edgeList.append(item)
        for node in nodeList:
            self.__graph.addVertex(node.data(self.__ItemId))

        badEdgeList = []
        for i in range(len(edgeList)):
            for edge in edgeList:
                edge: BezierEdge
                if edge.data(self.__ItemId) == i:
                    if edge.sourceNode and edge.destNode:
                        self.__graph.addEdge(
                            edge.sourceNode.data(self.__ItemId),
                            edge.destNode.data(self.__ItemId), edge.weight())
                    else:
                        badEdgeList.append(edge)

        if len(badEdgeList) != 0:
            self.disconnectGraph()
            string = ""
            for x in range(len(badEdgeList)):
                demo = "、"
                if x == len(badEdgeList) - 1:
                    demo = ""
                string = f'{string}e{badEdgeList[x].data(self.__ItemId)}{demo}'
            QMessageBox.warning(
                self, self._tr("MainWindow", "连接故障!"),
                self._tr("MainWindow", "警告,") + string +
                self._tr("MainWindow", "的连接不完整"))
            return False

        return True

    def disconnectGraph(self):
        self.__graph.clearAllData()

    def viewAndScene(self):
        if self.ui.tabWidget.count():
            self.__view: GraphicsView = self.ui.tabWidget.currentWidget()
            self.__scene = self.__view.scene()

    def standardGraphData(self):
        mode = int(self.ui.actionDigraph_Mode.isChecked())
        nodes = self.__scene.singleItems(BezierNode)
        edges = self.__scene.singleItems(BezierEdge)
        texts = self.__scene.singleItems(BezierText)
        nodeDataList = []
        edgeDataList = []
        textDataList = []
        for node in nodes:
            node: BezierNode
            data = [
                node.data(self.__ItemId),
                node.weight(),
                node.pos().x(),
                node.pos().y()
            ]
            nodeDataList.append(data)

        for edge in edges:
            edge: BezierEdge
            data = [edge.data(self.__ItemId)]
            if edge.sourceNode:
                data.append(edge.sourceNode.data(self.__ItemId))
            else:
                data.append(-1)
            if edge.destNode:
                data.append(edge.destNode.data(self.__ItemId))
            else:
                data.append(-1)

            data = data + [
                edge.weight(),
                edge.beginCp.point().x(),
                edge.beginCp.point().y(),
                edge.edge1Cp.point().x(),
                edge.edge1Cp.point().y(),
                edge.edge2Cp.point().x(),
                edge.edge2Cp.point().y(),
                edge.endCp.point().x(),
                edge.endCp.point().y(),
                edge.scenePos().x(),
                edge.scenePos().y()
            ]
            edgeDataList.append(data)

        for text in texts:
            text: BezierText
            data = [
                text.data(self.__ItemId),
                text.toPlainText(),
                text.scenePos().x(),
                text.scenePos().y()
            ]
            textDataList.append(data)

        nodeDataList.reverse()
        edgeDataList.reverse()
        textDataList.reverse()

        return [mode, nodeDataList, edgeDataList, textDataList]

    def reverseStandardData(self, excelData):
        graphName = excelData[0]
        mode = excelData[1]
        nodes = []
        edges = []
        texts = []
        self.ui.actionDigraph_Mode.setChecked(bool(mode))

        for nodeDetail in excelData[2]:
            node = BezierNode()
            node.textCp.setPlainText(f"V{nodeDetail[0]}")
            node.setData(self.__ItemId, nodeDetail[0])
            nodeText = self._tr("MainWindow", "顶点")
            node.setData(self.__ItemDesc, nodeText)
            if len(nodeDetail) < 3:
                for i in range(2):
                    intRandom = randint(-400, 400)
                    nodeDetail.append(intRandom)

            node.setPos(QPointF(nodeDetail[2], nodeDetail[3]))
            node.weightCp.setPlainText(str(nodeDetail[1]))

            nodes.append(node)

        for edgeDetail in excelData[3]:
            edge = BezierEdge()
            edge.setData(self.__ItemId, edgeDetail[0])
            edge.setData(self.__ItemDesc, "边")
            edge.textCp.setPlainText(f"e{edgeDetail[0]}")
            edge.weightCp.setPlainText(str(edgeDetail[3]))

            if len(edgeDetail) <= 4:
                for i in range(10):
                    intRandom = randint(-400, 400)
                    edgeDetail.append(intRandom)

            edge.setPos(QPointF(edgeDetail[12], edgeDetail[13]))

            if edgeDetail[1] >= 0:
                for node in nodes:
                    node: BezierNode
                    if node.data(self.__ItemId) == edgeDetail[1]:
                        edge.setSourceNode(node)
                        node.addBezierEdge(edge, ItemType.SourceType)
                        line = QLineF(edge.mapFromScene(node.pos()),
                                      edge.edge1Cp.point())
                        length = line.length()
                        edgeOffset = QPointF(line.dx() * 10 / length,
                                             line.dy() * 10 / length)
                        source = edge.mapFromScene(node.pos()) + edgeOffset
                        edge.setSpecialControlPoint(source,
                                                    ItemType.SourceType)
                        edge.beginCp.setVisible(False)
            else:
                edge.setSpecialControlPoint(
                    QPointF(edgeDetail[4], edgeDetail[5]), ItemType.SourceType)

            if edgeDetail[2] >= 0:
                for node in nodes:
                    node: BezierNode
                    if node.data(self.__ItemId) == edgeDetail[2]:
                        edge.setDestNode(node)
                        node.addBezierEdge(edge, ItemType.DestType)
                        line = QLineF(edge.mapFromScene(node.pos()),
                                      edge.edge2Cp.point())
                        length = line.length()
                        edgeOffset = QPointF(line.dx() * 10 / length,
                                             line.dy() * 10 / length)
                        if mode:
                            dest = edge.mapFromScene(
                                node.pos()) + edgeOffset * 2.3
                        else:
                            dest = edge.mapFromScene(node.pos()) + edgeOffset
                        edge.setSpecialControlPoint(dest, ItemType.DestType)
                        edge.endCp.setVisible(False)
            else:
                edge.setSpecialControlPoint(
                    QPointF(edgeDetail[10], edgeDetail[11]), ItemType.DestType)

            edge.setEdgeControlPoint(QPointF(edgeDetail[6], edgeDetail[7]),
                                     ItemType.SourceType)
            edge.setEdgeControlPoint(QPointF(edgeDetail[8], edgeDetail[9]),
                                     ItemType.DestType)
            edge.centerCp.setPoint(edge.updateCenterPos())

            edges.append(edge)

        if len(excelData) <= 4:
            return [graphName, nodes + edges]

        for textDetail in excelData[4]:
            text = BezierText(str(textDetail[1]))
            text.setData(self.__ItemId, textDetail[0])
            text.setData(self.__ItemDesc, "文本")
            text.setPos(textDetail[2], textDetail[3])
            texts.append(text)

        return [graphName, nodes + edges + texts]

    def setTranslator(self, translator, language):
        self.__translator = translator
        if language == 'EN':
            self.ui.actionSetEnglish.setChecked(True)
        else:
            self.ui.actionSetChinese.setChecked(True)

    @classmethod
    def checkSort(cls, index: list):
        index.sort()
        for i in range(len(index)):
            if i != index[i]:
                return i

    # ==============event处理函数==========================

    # def closeEvent(self, event):  # 退出函数
    #
    #     msgBox = QMessageBox()
    #     msgBox.setWindowTitle('关闭')
    #     msgBox.setText("是否保存")
    #     msgBox.setIcon(QMessageBox.Question)
    #     btn_Do_notSave = msgBox.addButton('不保存', QMessageBox.AcceptRole)
    #     btn_cancel = msgBox.addButton('取消', QMessageBox.RejectRole)
    #     btn_save = msgBox.addButton('保存', QMessageBox.AcceptRole)
    #     msgBox.setDefaultButton(btn_save)
    #     msgBox.exec_()
    #
    #     if msgBox.clickedButton() == btn_Do_notSave:
    #         event.accept()
    #     elif msgBox.clickedButton() == btn_cancel:
    #         event.ignore()
    #     elif msgBox.clickedButton() == btn_save:
    #         self.do_save_file()
    #         event.accept()

    # def contextMenuEvent(self, event):  # 右键菜单功能
    #     rightMouseMenu = QMenu(self)
    #
    #     rightMouseMenu.addAction(self.ui.actionNew)
    #     rightMouseMenu.addAction(self.ui.actionOpen)
    #
    #     self.action = rightMouseMenu.exec_(self.mapToGlobal(event.pos()))

    #  ==========由connectSlotsByName()自动连接的槽函数============
    @Slot()  # 新建画板
    def on_actionNew_triggered(self):
        self.iniGraphicsSystem()

    @Slot()  # 添加边
    def on_actionArc_triggered(self):  # 添加曲线
        item = BezierEdge()
        item.setGraphMode(self.ui.actionDigraph_Mode.isChecked())
        self.__setItemProperties(item, self._tr("MainWindow", "边"))
        self.do_addItem(item)
        self.__updateEdgeView()
        self.__updateNodeView()

    @Slot()  # 添加顶点
    def on_actionCircle_triggered(self):  # 添加原点
        self.viewAndScene()
        item = BezierNode()
        self.__setItemProperties(item, self._tr("MainWindow", "顶点"))
        self.do_addItem(item)
        self.__updateNodeView()
        self.__updateEdgeView()

    @Slot()  # 添加注释
    def on_actionAdd_Annotation_triggered(self):
        self.viewAndScene()
        strText, OK = QInputDialog.getText(self, self._tr("MainWindow", "输入"),
                                           self._tr("MainWindow", "请输入文字"))
        if not OK:
            return
        item = BezierText(strText)
        self.__setItemProperties(item, self._tr("MainWindow", "注释"))
        self.do_addItem(item)

    @Slot(bool)  # 显示和隐藏结点权重
    def on_actionShowNodesWeight_toggled(self, check: bool):
        nodes = self.__scene.singleItems(BezierNode)
        for node in nodes:
            node: BezierNode
            node.weightCp.setVisible(check)

        # if check:
        #     self.ui.actionShowNodesWeight.setText("隐藏顶点权重")
        # else:
        #     self.ui.actionShowNodesWeight.setText("显示顶点权重")

    @Slot(bool)  # 显示和隐藏边权重
    def on_actionShowEdgesWeight_toggled(self, check: bool):
        edges = self.__scene.singleItems(BezierEdge)
        for edge in edges:
            edge: BezierEdge
            edge.weightCp.setVisible(check)
        # if check:
        #     self.ui.actionShowEdgesWeight.setText("隐藏边权重")
        # else:
        #     self.ui.actionShowEdgesWeight.setText("显示边权重")

    @Slot(bool)  # 显示和隐藏边的控制点
    def on_actionHideControlPoint_toggled(self, check: bool):
        edges = self.__scene.singleItems(BezierEdge)
        for edge in edges:
            edge: BezierEdge
            for point in edge.pointList:
                point.setVisible(check)
            if edge.sourceNode:
                edge.beginCp.setVisible(False)
            if edge.destNode:
                edge.endCp.setVisible(False)

    @Slot()  # 简单通路
    def on_actionEasy_Pathway_triggered(self):
        self.viewAndScene()
        items = self.__scene.nodeList
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "对不起,你没有选择起始节点"))
            return
        elif len(items) != 2:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "选择的起始点数目不符合要求"))
            return

        if self.connectGraph():
            PathWay = ShowDataWidget(self,
                                     items,
                                     self.__graph,
                                     name=self._tr("MainWindow", "简单通路"))
            PathWay.pathSignal.connect(self.do_ShowSelectPath)
            if PathWay.easyPath():
                PathWay.updateToolWidget()
                PathWay.show()

        self.disconnectGraph()

    @Slot()  # 简单回路
    def on_actionEasy_Loop_triggered(self):
        self.viewAndScene()
        items = self.__scene.nodeList
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "对不起,你没有选择起点"))
            return

        if self.connectGraph():
            LoopWay = ShowDataWidget(self,
                                     items,
                                     self.__graph,
                                     name=self._tr("MainWindow", "简单回路"))
            LoopWay.pathSignal.connect(self.do_ShowSelectPath)
            if LoopWay.easyLoop():
                LoopWay.updateToolWidget(mode=1)
                LoopWay.show()
        self.disconnectGraph()

    @Slot()  # 初级通路
    def on_actionPrimary_Pathway_triggered(self):
        items = self.__scene.nodeList
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "对不起,你没有选择起始节点"))
            return
        elif len(items) != 2:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "选择的起始点数目不符合要求"))
            return

        if self.connectGraph():
            PathWay = ShowDataWidget(self, items, self.__graph, name="初级通路")
            PathWay.pathSignal.connect(self.do_ShowSelectPath)
            if PathWay.primaryPath():
                PathWay.updateToolWidget(path=1)
                PathWay.show()

        self.disconnectGraph()

    @Slot()  # 初级回路
    def on_actionPrimary_Loop_triggered(self):
        items = self.__scene.nodeList
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "对不起,你没有选择起点"))
            return

        if self.connectGraph():
            LoopWay = ShowDataWidget(self,
                                     items,
                                     self.__graph,
                                     name=self._tr("MainWindow", "初级回路"))
            LoopWay.pathSignal.connect(self.do_ShowSelectPath)
            if LoopWay.primaryLoop():
                LoopWay.updateToolWidget(mode=1, path=1)
                LoopWay.show()

        self.disconnectGraph()

    @Slot()  # 邻接矩阵 边数
    def on_action_EdgeNum_triggered(self):
        self.viewAndScene()
        items = self.__scene.singleItems(BezierNode)
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "图中没有结点"))
            return
        if self.connectGraph():
            MatrixTable = ShowMatrixWidget(self, self.__graph,
                                           self._tr("MainWindow", "邻接矩阵"), 0)
            MatrixTable.show()

    @Slot()  # 邻接矩阵 权重
    def on_actionWeight_triggered(self):
        self.viewAndScene()
        items = self.__scene.singleItems(BezierNode)
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "图中没有结点"))
            return
        if self.connectGraph():
            if not self.__graph.multipleOrSimple():
                MatrixTable = ShowMatrixWidget(self, self.__graph,
                                               self._tr("MainWindow", "邻接矩阵"),
                                               1)
                MatrixTable.show()
            else:
                QMessageBox.information(self, "Sorry", "这个图不是简单图")
                self.disconnectGraph()

    @Slot()  # 可达矩阵
    def on_actionReachable_Matrix_triggered(self):
        self.viewAndScene()
        items = self.__scene.singleItems(BezierNode)
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "图中没有结点"))
            return
        if self.connectGraph():
            MatrixTable = ShowMatrixWidget(self, self.__graph,
                                           self._tr("MainWindow", "可达矩阵"))
            MatrixTable.show()

    @Slot()  # 关联矩阵
    def on_actionIncidence_Matrix_Undigraph_triggered(self):
        self.viewAndScene()
        items = self.__scene.singleItems(BezierNode)
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "图中没有结点"))
            return
        if self.ui.actionDigraph_Mode.isChecked():
            items = self.singleItems(BezierEdge)
            badNodeList = []
            badNodes = ''
            for x in range(len(items)):
                if items[x].sourceNode is not None and items[
                        x].destNode is not None:
                    if items[x].sourceNode == items[x].destNode:
                        badNodeList.append(items[x])
                        demo = "、"
                        if x == len(items) - 1:
                            demo = ""
                        badNodes = f"{badNodes}V{items[x].sourceNode.data(self.__ItemId)}{demo}"
            if len(badNodeList):
                text = self._tr("MainWindow", '有向图的关联矩阵需要有向图无环,而')
                text1 = self._tr("MainWindow", '存在环!')
                QMessageBox.warning(self, self._tr("MainWindow", "致命错误"),
                                    f"{text}{badNodes}{text1}")
                return
        if self.connectGraph():
            MatrixTable = ShowMatrixWidget(self, self.__graph,
                                           self._tr("MainWindow", "关联矩阵"))
            MatrixTable.show()

    @Slot()  # 图的连通性
    def on_actionConnectivity_triggered(self):
        name = ''
        if self.connectGraph():
            num = self.__graph.connectivity()
            if num is False:
                name = self._tr("MainWindow", '此图为非连通图')
            elif num == 2:
                name = self._tr("MainWindow", "此图为单向连通图")
            elif num == 3:
                name = self._tr("MainWindow", "此图为强连通图")
            elif num == 1:
                name = self._tr("MainWindow", '此图为连通图')

            QMessageBox.information(self, self._tr("MainWindow", "图的连通性"),
                                    name)

            self.disconnectGraph()

    @Slot()  # 完全图判定
    def on_actionCompleteGraph_triggered(self):
        if self.connectGraph():
            edge = self.__graph.completeGraph()
            if edge:
                name = self._tr("MainWindow", "此图为完全图")
            else:
                name = self._tr("MainWindow", '此图不是完全图')

            QMessageBox.information(self, self._tr("MainWindow", "完全图判定"),
                                    name)

            self.disconnectGraph()

    @Slot()  # 简单图多重图判定
    def on_actionMultipleOrSimple_triggered(self):
        if self.connectGraph():
            edges = self.__graph.multipleOrSimple()
            if not edges:
                QMessageBox.information(self,
                                        self._tr("MainWindow", "简单图与多重图的判定"),
                                        self._tr("MainWindow", "此图为简单图"))

            else:
                parallelSides = ShowDataWidget(
                    self, edges, self.__graph,
                    self._tr("MainWindow", "简单图与多重图的判定"))
                parallelSides.multipleOrSimple()
                parallelSides.show()

    @Slot()  # 最短路径
    def on_actionShortestPath_triggered(self):

        items = self.__scene.nodeList
        if len(items) == 0:
            QMessageBox.warning(self, self._tr("MainWindow", "警告"),
                                self._tr("MainWindow", "对不起,你没有选择结点"))
            return
        if self.connectGraph():
            ShortestPath = ShowDataWidget(self,
                                          items,
                                          self.__graph,
                                          name=self._tr("MainWindow", "最短路径"))
            ShortestPath.pathSignal.connect(self.do_ShowSelectPath)
            if ShortestPath.shortestPath():
                ShortestPath.updateToolWidget(mode=1, path=2)
                ShortestPath.show()

    @Slot()  # 撤销
    def on_actionUndo_triggered(self):  # 撤销
        self.undoStack.undo()
        self.__updateEdgeView()
        self.__updateNodeView()

    @Slot()  # 重做
    def on_actionRedo_triggered(self):  # 重做
        self.viewAndScene()
        self.undoStack.redo()
        self.__updateEdgeView()
        self.__updateNodeView()

    @Slot()  # 帮助
    def on_actionHelp_Document_triggered(self):
        open("https://github.com/BBlance/Discrete_math.graph_theory")

    # @Slot()
    # def on_actionPen_Color_triggered(self):  # 画笔颜色
    #     iniColor = self.view.getPenColor()
    #     color = QColorDialog.getColor(iniColor, self, "选择颜色")
    #     if color.isValid():
    #         self.view.setPenColor(color)

    # @Slot()
    # def on_actionPen_Thickness_triggered(self):  # 画笔粗细
    #     self.viewAndScene()
    #     iniThickness = self.__view.getPenThickness()
    #     intPenStyle = self.__view.getPenStyle()
    #     thicknessDialog = ThicknessDialog(None, self._tr("MainWindow", "画笔粗细与样式"), iniThickness, intPenStyle)
    #     ret = thicknessDialog.exec_()
    #     thickness = thicknessDialog.getThickness()
    #     penStyle = thicknessDialog.getPenStyle()
    #     self.__view.setPenStyle(penStyle)
    #     self.__view.setPenThickness(thickness)

    @Slot()
    def on_actionBackground_Color_triggered(self):
        self.viewAndScene()
        # iniColor = self.__view.getBackgroundColor()
        # color = QColorDialog.getColor(iniColor, self, "选择颜色")
        # if color.isValid():
        #     self.__view.setBackgroundBrush(color)
        for item in self.standardGraphData():
            print(item)

    # @Slot(bool)
    # def on_actionProperty_And_History_triggered(self, checked):
    #     self.ui.dockWidget.setVisible(checked)

    @Slot()  # 保存文件
    def on_actionSave_triggered(self):
        self.viewAndScene()
        tableName = self.ui.tabWidget.tabText(self.ui.tabWidget.currentIndex())
        filename = self.operatorFile.saveGraphData(self.standardGraphData(),
                                                   tableName)
        if filename:
            index = self.ui.tabWidget.currentIndex()
            self.ui.tabWidget.setTabText(index, filename.baseName())

    @Slot()  # 读取文件
    def on_actionOpen_triggered(self):
        graph = self.operatorFile.openGraphData()
        if graph:
            graph = self.reverseStandardData(graph)
            self.iniGraphicsSystem(graph[0])
            for item in graph[1]:
                self.__scene.addItem(item)
            self.__updateNodeView()
            self.__updateEdgeView()
            self.__scene.update()

    @Slot()  # 另存为
    def on_actionSave_As_triggered(self):
        filename = self.operatorFile.saveExcelAs(self.standardGraphData())
        if filename:
            index = self.ui.tabWidget.currentIndex()
            self.ui.tabWidget.setTabText(index, filename.baseName())

    @Slot()  # 导出数据
    def on_actionOutputData_triggered(self):
        data = self.standardGraphData()
        data = data[:3]
        dataCpoy = [data[0], [], []]
        for node in data[1]:
            node = node[:2]
            dataCpoy[1].append(node)

        for edge in data[2]:
            edge = edge[:4]
            dataCpoy[2].append(edge)

        if self.operatorFile.outputData(dataCpoy):
            title = self.tr("恭喜")
            strInfo = self.tr("数据导出成功")
            QMessageBox.information(self, title, strInfo)

    @Slot()  # 导入数据
    def on_actionImportData_triggered(self):
        data = self.operatorFile.inputData()
        if data:
            graph = self.reverseStandardData(data)
            self.iniGraphicsSystem(graph[0])
            for item in graph[1]:
                self.__scene.addItem(item)
            self.__updateNodeView()
            self.__updateEdgeView()
            self.__scene.update()

    @Slot()
    def on_actionSave_Image_triggered(self):
        self.viewAndScene()
        savePath, fileType = QFileDialog.getSaveFileName(
            self, self._tr("MainWindow", '保存图片'), '.\\', '*bmp;;*.png')
        filename = os.path.basename(savePath)
        if filename != "":
            self.__view.saveImage(savePath, fileType)

    @Slot()
    def on_actionDelete_triggered(self):
        self.viewAndScene()
        self.do_deleteItem()

    @Slot(bool)
    def on_actionDigraph_Mode_toggled(self, checked: bool):
        self.__labModeInfo.setText(self._tr("MainWindow", "有向图模式"))
        self.__graph.setMode(checked)
        items = self.__scene.singleItems(BezierEdge)
        for item in items:
            item: BezierEdge
            item.setGraphMode(True)
            item.update()

    @Slot(bool)
    def on_actionRedigraph_Mode_toggled(self, checked: bool):
        self.__labModeInfo.setText(self._tr("MainWindow", "无向图模式"))
        self.__graph.setMode(checked)
        items = self.__scene.singleItems(BezierEdge)
        for item in items:
            item: BezierEdge
            item.setGraphMode(False)
            item.update()

    @Slot(int)
    def on_tabWidget_currentChanged(self, index):  # ui.tabWidget当前页面变化
        self.viewAndScene()
        if self.__view and self.__scene:
            self.__updateEdgeView()
            self.__updateNodeView()

        hasTabs = self.ui.tabWidget.count() > 0  # 再无页面时

        self.ui.tabWidget.setVisible(hasTabs)
        self.ui.dockWidget.setVisible(hasTabs)
        self.ui.actionProperty_And_History.setChecked(hasTabs)

    @Slot(int)
    def on_tabWidget_tabCloseRequested(self, index):  # 分页关闭时关闭窗体
        if index < 0:
            return
        view = self.ui.tabWidget.widget(index)
        view.close()
        # self.__view = None
        # self.__scene = None

    #  =============自定义槽函数===============================
    def do_nodeLock(self, item):
        self.__updateNodeView()
        self.__updateEdgeView()

    def do_mouseMove(self, point):  ##鼠标移动
        ##鼠标移动事件,point是 GraphicsView的坐标,物理坐标
        view = self._tr("MainWindow", '视图坐标:')
        scene = self._tr("MainWindow", '场景坐标:')
        self.__labViewCord.setText("%s%d,%d" % (view, point.x(), point.y()))
        pt = self.ui.tabWidget.currentWidget().mapToScene(point)  # 转换到Scene坐标
        self.__labSceneCord.setText("%s%.0f,%.0f" % (scene, pt.x(), pt.y()))

    def do_mouseClicked(self, point):  ##鼠标单击
        pt = self.__view.mapToScene(point)  # 转换到Scene坐标
        item = self.__scene.itemAt(pt, self.__view.transform())  # 获取光标下的图形项
        if item is None:
            return
        pm = item.mapFromScene(pt)  # 转换为绘图项的局部坐标
        itemInfo = self._tr("MainWindow", "Item 坐标:")
        self.__labItemCord.setText("%s%.0f,%.0f" % (itemInfo, pm.x(), pm.y()))
        data = f"{item.data(self.__ItemDesc)}, ItemId={item.data(self.__ItemId)}"
        if type(item) is BezierEdge:
            data = f"{data},EdgeId=e{item.data(self.__ItemId)}"
        elif type(item) is BezierNode:
            data = f"{data}, NodeId=V{item.data(self.__ItemId)}"
        self.__labItemInfo.setText(data)

    def do_mouseDoubleClick(self, point):  ##鼠标双击
        pt = self.__view.mapToScene(point)  # 转换到Scene坐标,QPointF
        item = self.__scene.itemAt(pt, self.__view.transform())  # 获取光标下的绘图项
        if item is None:
            return

        className = str(type(item))  # 将类名称转换为字符串

        if className.find("QGraphicsRectItem") >= 0:  # 矩形框
            self.__setBrushColor(item)
        elif className.find(
                "QGraphicsEllipseItem") >= 0:  # 椭圆和圆都是 QGraphicsEllipseItem
            self.__setBrushColor(item)
        elif className.find("QGraphicsPolygonItem") >= 0:  # 梯形和三角形
            self.__setBrushColor(item)
        elif className.find("QGraphicsLineItem") >= 0:  # 直线,设置线条颜色
            pen = item.pen()
            color = item.pen().__color()
            color = QColorDialog.getColor(color, self, "选择线条颜色")
            if color.isValid():
                pen.setColor(color)
                item.setPen(pen)
        elif className.find("QGraphicsTextItem") >= 0:  # 文字,设置字体
            font = item.font()
            font, OK = QFontDialog.getFont(font)
            if OK:
                item.setFont(font)

    def do_addItem(self, item):
        add = AddCommand(self, self.__scene, item)
        self.undoStack.push(add)

    def do_shapeMoved(self, item, pos):
        move = MoveCommand(item, pos)
        self.undoStack.push(move)

    def do_deleteItem(self):
        items = self.__scene.selectedItems()
        cnt = len(items)
        for i in range(cnt):
            item = items[i]
            if str(type(item)).find("BezierNode") >= 0:
                item: BezierNode
                for edge in item.bezierEdges:
                    for node, itemType in edge.items():
                        if itemType == ItemType.SourceType:
                            node.setSourceNode(None)
                        elif itemType == ItemType.DestType:
                            node.setDestNode(None)
                self.__nodeNum -= 1
            elif str(type(item)).find("BezierEdge") >= 0:
                item: BezierEdge
                sourceNode: BezierNode = item.sourceNode
                destNode: BezierNode = item.destNode
                if sourceNode:
                    sourceNodeList = sourceNode.bezierEdges
                    for sourceEdge in sourceNodeList:
                        for edge in sourceEdge.keys():
                            if item is edge:
                                sourceNodeList.remove(sourceEdge)
                if destNode:
                    destNodeList = destNode.bezierEdges
                    for destEdge in destNodeList:
                        for edge in destEdge.keys():
                            if item is edge:
                                destNodeList.remove(destEdge)
                self.__edgeNum -= 1

            self.__scene.removeItem(item)  # 删除绘图项

    def do_curEdgeChanged(self, current, previous):
        if current is not None:
            text = f"当前单元格{current.row()},{current.column()}"
            item = self.edgeModel.itemFromIndex(current)

    def do_curNodeChanged(self, current, previous):
        if current is not None:
            text = f"当前单元格{current.row()},{current.column()}"
            item = self.nodeModel.itemFromIndex(current)

    def do_updateEdgeWeight(self, topLeft, bottomRight):
        if topLeft.column() == 4:
            edges = self.__scene.singleItems(BezierEdge)
            for edge in edges:
                edge: BezierEdge
                if edge.textCp.toPlainText() == self.edgeModel.index(
                        topLeft.row(), 0, QModelIndex()).data():
                    edge.weightCp.setPlainText(str(topLeft.data()))
                    self.__scene.update()

    def do_updateNodeWeight(self, topLeft, bottomRight):
        if topLeft.column() == 3:
            nodes = self.__scene.singleItems(BezierNode)
            for node in nodes:
                node: BezierNode
                if node.textCp.toPlainText() == self.nodeModel.index(
                        topLeft.row(), 0, QModelIndex()).data():
                    node.weightCp.setPlainText(str(topLeft.data()))
                    self.__scene.update()

    def do_ShowSelectPath(self, pathList: list):
        self.__scene.clearSelection()
        items = self.__scene.uniqueItems()
        for item in items:
            if item.textCp.toPlainText() in pathList:
                item.setSelected(True)

    def do_checkIsHasItems(self, num):
        if num:
            self.ui.actionSave.setEnabled(True)
        else:
            self.ui.actionSave.setEnabled(False)
예제 #25
0
class AtomSitesModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._label_role = Qt.UserRole + 1
        self._atom_role = Qt.UserRole + 2
        self._color_role = Qt.UserRole + 3
        self._x_role = Qt.UserRole + 4
        self._y_role = Qt.UserRole + 5
        self._z_role = Qt.UserRole + 6
        self._occupancy_role = Qt.UserRole + 7
        self._model.setItemRoleNames({
            self._label_role: b'label',
            self._atom_role: b'atom',
            self._color_role: b'colorStr',
            self._x_role: b'xPos',
            self._y_role: b'yPos',
            self._z_role: b'zPos',
            self._occupancy_role: b'occupancy'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI ..."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # set list of atoms
            data = []
            for atom_id, atom_dict in phase_dict['atoms'].items():
                label = atom_id
                atom = str(atom_dict['type_symbol'].value)
                color = atom_dict['scat_length_neutron'].value.real
                x = atom_dict['fract_x'].value
                y = atom_dict['fract_x'].value
                z = atom_dict['fract_x'].value
                occupancy = atom_dict['occupancy'].value
                data.append({
                    self._label_role: label,
                    self._atom_role: atom,
                    self._color_role: color,
                    self._x_role: x,
                    self._y_role: y,
                    self._z_role: z,
                    self._occupancy_role: occupancy
                })
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data array created above
            for row_index, dict_value in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict_value.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")
예제 #26
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None, flags=Qt.WindowFlags()):
        super(MainWindow, self).__init__(parent, flags)

        self.dayWidth = 70
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        self.initModel()
        self.initActions()
        self.initItemDelegate()
        self.initGrid()

        leftView = self.ui.ganttView.leftView()
        leftView.setColumnHidden(1, True)
        leftView.setColumnHidden(2, True)
        leftView.setColumnHidden(3, True)
        leftView.setColumnHidden(4, True)
        leftView.setColumnHidden(5, True)
        leftView.header().setStretchLastSection(True)

        self.ui.ganttView.leftView().customContextMenuRequested.connect(
            self.showContextMenu)
        self.ui.ganttView.selectionModel().selectionChanged.connect(
            self.enableActions)
        self.ui.ganttView.graphicsView().clicked.connect(self.slotClicked)
        self.ui.ganttView.graphicsView().qrealClicked.connect(
            self.slotDoubleClicked)

    def initModel(self):
        self.model = QStandardItemModel(0, 6, self)
        self.model.setHeaderData(0, Qt.Horizontal, "Task")
        self.ui.ganttView.setModel(self.model)

        self.l = QWidget(self)
        self.l.setWindowTitle("Legend")
        self.l.show()
        ##self.l.setModel(self.model)

        self.constraintModel = ConstraintModel(self)
        self.ui.ganttView.setConstraintModel(self.constraintModel)

    def initActions(self):
        self.newEntryAction = QAction("New entry", self)
        self.newEntryAction.setShortcut(QKeySequence.New)
        self.newEntryAction.triggered.connect(self.addNewEntry)

        self.removeEntryAction = QAction("Remove entry", self)
        self.removeEntryAction.setShortcut(QKeySequence.Delete)
        self.removeEntryAction.triggered.connect(self.removeEntry)

        self.demoAction = QAction("Demo entry", self)
        self.demoAction.triggered.connect(self.addDemoEntry)

        self.printAction = QAction("Print Preview...", self)
        self.printAction.triggered.connect(self.printPreview)

        self.zoomInAction = QAction("Zoom In", self)
        self.zoomInAction.setShortcut(QKeySequence.ZoomIn)
        self.zoomInAction.triggered.connect(self.zoomIn)

        self.zoomOutAction = QAction("Zoom Out", self)
        self.zoomOutAction.setShortcut(QKeySequence.ZoomOut)
        self.zoomOutAction.triggered.connect(self.zoomOut)

        self.ui.ganttView.leftView().setContextMenuPolicy(Qt.CustomContextMenu)
        self.ui.ganttView.leftView().addAction(self.newEntryAction)
        self.ui.ganttView.leftView().addAction(self.removeEntryAction)

        menuBar = QMenuBar(self)
        self.setMenuBar(menuBar)
        entryMenu = menuBar.addMenu("Entry")
        entryMenu.addAction(self.newEntryAction)
        entryMenu.addAction(self.removeEntryAction)
        entryMenu.addSeparator()
        entryMenu.addAction(self.demoAction)
        entryMenu.addSeparator()
        entryMenu.addAction(self.printAction)

        zoomMenu = menuBar.addMenu("Zoom")
        zoomMenu.addAction(self.zoomInAction)
        zoomMenu.addAction(self.zoomOutAction)

        ##self.enableActions(QItemSelection())

    def initItemDelegate(self):
        delegate = EntryDelegate(self.constraintModel, self)
        self.ui.ganttView.leftView().setItemDelegate(delegate)

    def initGrid(self):
        self.grid = DateTimeGrid()
        self.grid.setDayWidth(self.dayWidth)
        self.ui.ganttView.setGrid(self.grid)

    def showContextMenu(self, pos):
        if not self.ui.ganttView.leftView().indexAt(pos).isValid():
            self.ui.ganttView.selectionModel().clearSelection()

        menu = QMenu(self.ui.ganttView.leftView())
        menu.addAction(self.newEntryAction)
        menu.addAction(self.removeEntryAction)
        menu.exec_(self.ui.ganttView.leftView().viewport().mapToGlobal(pos))

    def enableActions(self, selected):
        if len(selected.indexes()) == 0:
            self.newEntryAction.setEnabled(True)
            self.removeEntryAction.setEnabled(False)
            return

        selectedIndex = selected.indexes()[0]
        dataType = self.model.data(self.model.index(selectedIndex.row(), 1))
        if dataType in [KDGantt.TypeEvent, KDGantt.TypeTask]:
            self.newEntryAction.setEnabled(False)
            self.removeEntryAction.setEnabled(True)
            return

        self.newEntryAction.setEnabled(True)
        self.removeEntryAction.setEnabled(True)

    def addNewEntry(self):
        dialog = EntryDialog(self.model)
        dialog.setWindowTitle("New Entry")
        if dialog.exec_() == QDialog.Rejected:
            dialog = None
            return

        selectedIndexes = self.ui.ganttView.selectionModel().selectedIndexes()
        if len(selectedIndexes) > 0:
            parent = selectedIndexes[0]
        else:
            parent = QModelIndex()

        if not self.model.insertRow(self.model.rowCount(parent), parent):
            return

        row = self.model.rowCount(parent) - 1
        if row == 0 and parent.isValid():
            self.model.insertColumns(self.model.columnCount(paren), 5, parent)

        self.model.setData(self.model.index(row, 0, parent), dialog.name())
        self.model.setData(self.model.index(row, 1, parent), dialog.type())
        if dialog.type() != KDGantt.TypeSummary:
            self.model.setData(self.model.index(row, 2, parent),
                               dialog.startDate(), KDGantt.StartTimeRole)
            self.model.setData(self.model.index(row, 3, parent),
                               dialog.endDate(), KDGantt.EndTimeRole)

        self.model.setData(self.model.index(row, 4, parent),
                           dialog.completion())
        self.model.setData(self.model.index(row, 5, parent), dialog.legend())

        self.addConstraint(dialog.depends(), self.model.index(row, 0, parent))
        self.setReadOnly(self.model.index(row, 0, parent), dialog.readOnly())

        dialog = None

    def setReadOnly(self, index, readOnly):
        row = index.row()
        parent = index.parent()

        for column in range(0, 5):
            item = self.model.itemFromIndex(
                self.model.index(row, column, parent))
            flags = None
            if readOnly:
                flags = item.flags() & ~Qt.ItemIsEditable
            else:
                flags = item.flags() | Qt.ItemIsEditable
            item.setFlags(flags)

    def addConstraint(self, index1, index2):
        if not index1.isValid() or not index2.isValid():
            return

        c = Constraint(index1, index2)
        self.ui.ganttView.constraintModel().addConstraint(c)

    def addConstraintFromItem(self, item1, item2):
        self.addConstraint(self.model.indexFromItem(item1),
                           self.model.indexFromItem(item2))

    def removeEntry(self):
        selectedIndexes = self.ui.ganttView.selectionModel().selectedIndexes()
        if len(selectedIndexes) > 0:
            index = selectedIndexes[0]
        else:
            index = QModelIndex()

        if not index.isValid():
            return

        self.model.removeRow(index.row(), index.parent())

    def addDemoEntry(self):
        softwareRelease = MyStandardItem("Software Release")
        codeFreeze = MyStandardItem("Code Freeze")
        codeFreeze.setData(KDGantt.TextPositionRole,
                           StyleOptionGanttItem.Right)
        packaging = MyStandardItem("Packaging")
        upload = MyStandardItem("Upload")
        testing = MyStandardItem("Testing")
        updateDocumentation = MyStandardItem("Update Documentation")

        now = QDateTime.currentDateTime()
        softwareRelease.appendRow([
            codeFreeze,
            MyStandardItem(KDGantt.TypeEvent),
            MyStandardItem(now, KDGantt.StartTimeRole)
        ])
        softwareRelease.appendRow([
            packaging,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(now.addDays(5), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(10), KDGantt.EndTimeRole)
        ])
        softwareRelease.appendRow([
            upload,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(
                now.addDays(10).addSecs(2 * 60 * 60), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(11), KDGantt.EndTimeRole)
        ])
        softwareRelease.appendRow([
            testing,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(now.addSecs(3 * 60 * 60), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(5), KDGantt.EndTimeRole)
        ])
        softwareRelease.appendRow([
            updateDocumentation,
            MyStandardItem(KDGantt.TypeTask),
            MyStandardItem(now.addSecs(3 * 60 * 60), KDGantt.StartTimeRole),
            MyStandardItem(now.addDays(3), KDGantt.EndTimeRole)
        ])
        self.model.appendRow(
            [softwareRelease,
             MyStandardItem(KDGantt.TypeSummary)])
        self.addConstraintFromItem(codeFreeze, packaging)
        self.addConstraintFromItem(codeFreeze, testing)
        self.addConstraintFromItem(codeFreeze, updateDocumentation)
        self.addConstraintFromItem(packaging, upload)
        self.addConstraintFromItem(testing, packaging)
        self.addConstraintFromItem(updateDocumentation, packaging)

    def zoomIn(self):
        self.dayWidth += 10
        if self.dayWidth > 400:
            self.grid.setScale(DateTimeGrid.ScaleHour)
        self.grid.setDayWidth(self.dayWidth)

    def zoomOut(self):
        self.dayWidth -= 10

        if self.dayWidth < 10:
            self.dayWidth = 10

        if self.dayWidth <= 400:
            self.grid.setScale(DateTimeGrid.ScaleDay)

        self.grid.setDayWidth(self.dayWidth)

    def printPreview(self):
        preview = QLabel(self, Qt.Window)
        preview.setAttribute(Qt.WA_DeleteOnClose)
        preview.setScaledContents(True)
        preview.setWindowTitle("Print Preview")
        pix = QPixmap(1000, 300)
        pix.fill(Qt.white)

        p = QPainter(pix)
        p.setRenderHints(QPainter.Antialiasing)
        self.ui.ganttView.print_(p, pix.rect())

        preview.setPixmap(pix)
        preview.show()

    def slotClicked(self, index):
        self.statusBar().showMessage(
            "(%d,%d,_,%s) clicked" %
            (index.row(), index.column(), index.model()))

    def slotDoubleClicked(self, index):
        self.statusBar().showMessage(
            "(%d,%d,_,%s) qreal clicked" %
            (index.row(), index.column(), index.model()))
예제 #27
0
        return False

    def setModelData(self, editor, model, index):
        '''
        The user wanted to change the old state in the opposite.
        '''
        model.setData(index, 1 if int(index.data()) == 0 else 0,
                      QtCore.Qt.EditRole)


if __name__ == '__main__':

    import sys

    app = QApplication(sys.argv)

    model = QStandardItemModel(4, 3)
    tableView = QTableView()
    tableView.setModel(model)

    delegate = CheckBoxDelegate(None)
    tableView.setItemDelegateForColumn(1, delegate)
    for row in range(4):
        for column in range(3):
            index = model.index(row, column, QModelIndex())
            model.setData(index, 1)

    tableView.setWindowTitle("Check Box Delegate")
    tableView.show()
    sys.exit(app.exec_())
예제 #28
0
class AuswahlDialog(QDialog):
    def __init__(self, title=None, parent=None):
        QDialog.__init__(self, parent)
        self.title = title
        self.listView = QListView()
        self.font = QFont("Arial", 14)
        self.okButton = QPushButton("OK")
        self.cancelButton = QPushButton("Abbrechen")
        self.model = QStandardItemModel()
        self.listView.setModel(self.model)
        self._selectedIndexes = ""
        self._createGui()

    def _createGui(self):
        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.okButton)
        hbox.addWidget(self.cancelButton)

        vbox = QVBoxLayout(self)
        vbox.addWidget(self.listView, stretch=1)
        # vbox.addStretch(1)
        vbox.addLayout(hbox)

        self.okButton.setDefault(True)

        if self.title:
            self.setWindowTitle(self.title)
        else:
            self.setWindowTitle("Auswahl")

        self.okButton.clicked.connect(self.onAccepted)
        self.cancelButton.clicked.connect(self.reject)

    def appendItemList(self, itemlist: List[str]):
        for i in itemlist:
            self.appendItem(i, None)

    def appendItem(self, text: str, userdata: Any = None):
        item = CustomItem(text)
        if userdata:
            item.userdata = userdata
        item.setFont(self.font)
        self.model.appendRow(item)
        if self.model.rowCount() == 1:
            self.listView.setCurrentIndex(self.model.index(0, 0))

    def onAccepted(self):
        self._selectedIndexes = self.listView.selectedIndexes()
        self.accept()

    def getSelectedIndexes(self):
        return self._selectedIndexes

    def getSelection(self) -> List[Tuple]:
        sel = self.getSelectedIndexes()
        l = list()
        for idx in sel:
            item: CustomItem = self.model.item(idx.row(), idx.column())
            t = (item.text(), item.userdata)
            l.append(t)

        return l
예제 #29
0
파일: main.py 프로젝트: KDAB/KDChart
class MyWidget(QWidget):
    def __init__(self):
        super(MyWidget, self).__init__(None)

        self.view = View()
        self.grid = DateTimeGrid()
        self.slider = QSlider()
        self.model = QStandardItemModel()
        self.cmodel = ConstraintModel()

        for h in range(0, 19):
            topitem = MyStandardItem("Top Item " + str(h))
            for i in range(0, 19):
                item = MyStandardItem("Multi Item " + str(i))
                for j in range(0, 29, 3):
                    item.appendRow([
                        MyStandardItem("Item " + str(j)),
                        MyStandardItem(KDGantt.TypeTask),
                        MyStandardItem(QDateTime.currentDateTime().addDays(j),
                                       KDGantt.StartTimeRole),
                        MyStandardItem(
                            QDateTime.currentDateTime().addDays(j + 1 + i / 7),
                            KDGantt.EndTimeRole),
                        MyStandardItem(50)
                    ])

                item.appendRow([
                    MyStandardItem("Event"),
                    MyStandardItem(KDGantt.TypeEvent),
                    MyStandardItem(QDateTime.currentDateTime(),
                                   KDGantt.StartTimeRole),
                    MyStandardItem(QDateTime(), KDGantt.EndTimeRole),
                    MyStandardItem("")
                ])

                topitem.appendRow([
                    item,
                    MyStandardItem(KDGantt.TypeMulti),
                    MyStandardItem(""),
                    MyStandardItem(""),
                    MyStandardItem("")
                ])

            self.model.appendRow([
                topitem,
                MyStandardItem(KDGantt.TypeMulti),
                MyStandardItem(""),
                MyStandardItem(""),
                MyStandardItem("")
            ])

        self.model.appendRow([MyStandardItem("No data")])

        ##cmodel.addConstraint( KDGantt::Constraint( proxyModel.index( 0, 3 ), proxyModel.index( 10, 3 ) ) );
        ##cmodel.addConstraint( KDGantt::Constraint( proxyModel.index( 10, 3 ), proxyModel.index( 5, 3 ) ) );
        pidx = self.model.index(0, 0)
        pidx = self.model.index(0, 0, pidx)
        self.cmodel.addConstraint(
            Constraint(self.model.index(0, 0, pidx),
                       self.model.index(1, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(1, 0, pidx),
                       self.model.index(0, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(1, 0, pidx),
                       self.model.index(10, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(3, 0, pidx),
                       self.model.index(5, 0, pidx)))
        self.cmodel.addConstraint(
            Constraint(self.model.index(7, 0, pidx),
                       self.model.index(4, 0, pidx)))

        self.slider.setOrientation(Qt.Horizontal)
        self.slider.setRange(1, 10000)
        self.slider.setValue(100)
        l = QVBoxLayout(self)
        l.addWidget(self.view)
        l.addWidget(self.slider)
        self.grid.setStartDateTime(QDateTime.currentDateTime().addDays(-3))
        self.grid.setDayWidth(100)
        ##grid.setNoInformationBrush( Qt::NoBrush );
        self.view.setGrid(self.grid)
        self.view.setModel(self.model)
        ##view.setConstraintModel( &cmodel );
        self.slider.valueChanged.connect(self.slotZoom)

        pb1 = QPushButton("Print Preview...", self)
        pb2 = QPushButton("Print...", self)

        l.addWidget(pb1)
        l.addWidget(pb2)

        pb1.clicked.connect(self.slotPrintPreview)
        pb2.clicked.connect(self.slotPrint)

        gv = self.view.graphicsView()
        gv.setHeaderContextMenuPolicy(Qt.CustomContextMenu)
        gv.headerContextMenuRequested.connect(self.slotHeaderMenu)

    def slotZoom(self, z):
        self.grid.setDayWidth(z)

    def slotPrintPreview(self):
        pix = QPixmap(1000, 200)
        pix.fill(Qt.white)

        painter = QPainter(pix)
        view.print(painter, pix.rect())
        painter.end()

        label = QLabel(this)
        label.setPixmap(pix)
        label.show()

    def slotPrint(self):
        printer = QPrinter(QPrinter.HighResolution)
        pd = QPrintDialog(printer, self)

        if pd.exec_() == QDialog.Accepted:
            r = self.view.graphicsView().mapToScene(
                self.view.graphicsView().viewport().rect()).boundingRect()
            self.view.print(printer, r.left(), r.right())

    def slotHeaderMenu(self, pt):
        menu = QMenu()
        menu.addAction("This")
        menu.addAction("is")
        menu.addAction("just")
        menu.addAction("a")
        menu.addAction("test")
        menu.exec_(pt)
예제 #30
0
class CheckListEditor(QTableView):
    """A check list editor."""
    def __init__(self, parent, tutor=None):
        """Initialize class."""
        super().__init__(parent)
        self._tutor = tutor
        self._base_size = None
        self.model = QStandardItemModel(self)
        self.setModel(self.model)
        self.verticalHeader().hide()
        self.horizontalHeader().hide()
        self.setShowGrid(False)
        self.setMouseTracking(True)

    def keyPressEvent(self, event):
        """Toggles checked state if the user presses space."""
        super().keyPressEvent(event)
        if event.key() == Qt.Key_Space:
            index = self.currentIndex()
            self.toggle_checked_state(index)

    def toggle_checked_state(self, index):
        """Toggles checked state of given index.

        Args:
            index (QModelIndex)
        """
        item = self.model.itemFromIndex(index)
        if item.checkState() == Qt.Checked:
            item.setCheckState(Qt.Unchecked)
        else:
            item.setCheckState(Qt.Checked)

    def mouseMoveEvent(self, event):
        """Sets the current index to the one under mouse."""
        index = self.indexAt(event.pos())
        self.setCurrentIndex(index)

    def mousePressEvent(self, event):
        """Toggles checked state of pressed index."""
        index = self.indexAt(event.pos())
        self.toggle_checked_state(index)

    def set_data(self, items, checked_items):
        """Sets data and updates geometry.

        Args:
            items (Sequence(str)): All items.
            checked_items (Sequence(str)): Initially checked items.
        """
        for item in items:
            qitem = QStandardItem(item)
            if item in checked_items:
                qitem.setCheckState(Qt.Checked)
            else:
                qitem.setCheckState(Qt.Unchecked)
            qitem.setFlags(~Qt.ItemIsEditable & ~Qt.ItemIsUserCheckable)
            qitem.setData(qApp.palette().window(), Qt.BackgroundRole)  # pylint: disable=undefined-variable
            self.model.appendRow(qitem)
        self.selectionModel().select(self.model.index(0, 0),
                                     QItemSelectionModel.Select)

    def data(self):
        """Returns a comma separated list of checked items.

        Returns
            str
        """
        data = []
        for q in self.model.findItems('*', Qt.MatchWildcard):
            if q.checkState() == Qt.Checked:
                data.append(q.text())
        return ",".join(data)

    def set_base_size(self, size):
        self._base_size = size

    def update_geometry(self):
        """Updates geometry.
        """
        self.horizontalHeader().setDefaultSectionSize(self._base_size.width())
        self.verticalHeader().setDefaultSectionSize(self._base_size.height())
        total_height = self.verticalHeader().length() + 2
        size = QSize(self._base_size.width(),
                     total_height).boundedTo(self.parent().size())
        self.resize(size)
        if self._tutor:
            self.move(self.pos() +
                      self._tutor.mapTo(self.parent(),
                                        self._tutor.parent().pos()))
        # Adjust position if widget is outside parent's limits
        bottom_right = self.mapToGlobal(self.rect().bottomRight())
        parent_bottom_right = self.parent().mapToGlobal(
            self.parent().rect().bottomRight())
        x_offset = max(0, bottom_right.x() - parent_bottom_right.x())
        y_offset = max(0, bottom_right.y() - parent_bottom_right.y())
        self.move(self.pos() - QPoint(x_offset, y_offset))
예제 #31
0
class FileWriterCtrl(Ui_FilewriterCtrl, QMainWindow):
    def __init__(self, instrument: Instrument):
        super().__init__()
        self.instrument = instrument
        self.setupUi()
        self.known_writers = {}
        self.known_files = {}
        self.status_consumer = None
        self.command_producer = None

    def setupUi(self):
        super().setupUi(self)

        self.status_consumer = None
        self.status_broker_led = Led(self)
        self.status_topic_layout.addWidget(self.status_broker_led)
        self.status_broker_change_timer = QTimer()
        self._set_up_broker_fields(
            self.status_broker_led,
            self.status_broker_edit,
            self.status_broker_change_timer,
            self.status_broker_timer_changed,
            StatusConsumer,
        )

        self.command_producer = None

        self.command_broker_led = Led(self)
        self.command_broker_layout.addWidget(self.command_broker_led)
        self.command_broker_change_timer = QTimer()
        self._set_up_broker_fields(
            self.command_broker_led,
            self.command_broker_edit,
            self.command_broker_change_timer,
            self.command_broker_timer_changed,
            CommandProducer,
        )

        self.command_widget.ok_button.clicked.connect(self.send_command)
        self.update_status_timer = QTimer()
        self.update_status_timer.timeout.connect(self._check_connection_status)
        self.update_status_timer.start(500)

        self.files_list.clicked.connect(self.file_list_clicked)
        self.stop_file_writing_button.clicked.connect(self.stop_file_writing_clicked)

        self.model = QStandardItemModel(0, 2, self)
        self.model.setHeaderData(0, QtCore.Qt.Horizontal, "File writer")
        self.model.setHeaderData(1, QtCore.Qt.Horizontal, "Last seen")
        self.file_writers_list.setModel(self.model)
        self.file_writers_list.setColumnWidth(0, 320)

        self.file_list_model = QStandardItemModel(0, 3, self)
        self.file_list_model.setHeaderData(0, QtCore.Qt.Horizontal, "File name")
        self.file_list_model.setHeaderData(1, QtCore.Qt.Horizontal, "Last seen")
        self.file_list_model.setHeaderData(2, QtCore.Qt.Horizontal, "File writer")
        self.files_list.setModel(self.file_list_model)

    @staticmethod
    def _set_up_broker_fields(
        led: Led,
        edit: QLineEdit,
        timer: QTimer,
        timer_callback: Callable,
        kafka_obj_type: Type[KafkaInterface],
    ):
        led.turn_off()
        validator = BrokerAndTopicValidator()
        edit.setValidator(validator)
        validator.is_valid.connect(partial(validate_line_edit, edit))
        edit.textChanged.connect(lambda: timer.start(1000))
        timer.setSingleShot(True)
        timer.timeout.connect(partial(timer_callback, kafka_obj_type))

    def _check_connection_status(self):
        if self.status_consumer is None:
            self.status_broker_led.turn_off()
        else:
            connection_ok = self.status_consumer.connected
            self.status_broker_led.set_status(connection_ok)
            if connection_ok:
                current_writers = self.status_consumer.file_writers
                self._update_writer_list(current_writers)
                self._update_files_list(self.status_consumer.files)

        if self.command_producer is None:
            self.command_broker_led.turn_off()
        else:
            self.command_broker_led.set_status(self.command_producer.connected)

    def status_broker_timer_changed(self, kafka_obj_type: KafkaInterface):
        result = BrokerAndTopicValidator.extract_addr_and_topic(
            self.status_broker_edit.text()
        )
        if result is not None:
            if self.status_consumer is not None:
                self.status_consumer.close()
            self.status_consumer = kafka_obj_type(*result)

    def command_broker_timer_changed(self, kafka_obj_type: KafkaInterface):
        result = BrokerAndTopicValidator.extract_addr_and_topic(
            self.command_broker_edit.text()
        )
        if result is not None:
            if self.command_producer is not None:
                self.command_producer.close()
            self.command_producer = kafka_obj_type(*result)

    def _update_writer_list(self, updated_list: Dict[str, Dict]):
        for key in updated_list:
            current_time, time_str = self.get_time(key, updated_list)
            if key not in self.known_writers:
                number_of_filewriter_rows = self.model.rowCount(QtCore.QModelIndex())
                new_file_writer = FileWriter(key, number_of_filewriter_rows)
                self.known_writers[key] = new_file_writer
                self.model.insertRow(number_of_filewriter_rows)
                self.model.setData(self.model.index(number_of_filewriter_rows, 0), key)
                self.model.setData(
                    self.model.index(number_of_filewriter_rows, 1), time_str
                )
            current_file_writer = self.known_writers[key]
            if current_time != current_file_writer.last_time:
                self._set_time(self.model, current_file_writer, current_time, time_str)

    def _update_files_list(self, updated_list: Dict[str, Dict]):
        for key in updated_list:
            current_time, time_str = self.get_time(key, updated_list)
            if key not in self.known_files:
                number_of_file_rows = self.file_list_model.rowCount(
                    QtCore.QModelIndex()
                )
                new_file = File(key, row=number_of_file_rows)
                self.known_files[key] = new_file
                self.file_list_model.insertRow(number_of_file_rows)
                self.file_list_model.setData(
                    self.file_list_model.index(number_of_file_rows, 0), key
                )
                self.file_list_model.setData(
                    self.file_list_model.index(number_of_file_rows, 1), time_str
                )
                self.file_list_model.setData(
                    self.file_list_model.index(number_of_file_rows, 2),
                    new_file.writer_id,
                )
            current_file = self.known_files[key]
            if current_time != current_file.last_time:
                self._set_time(
                    self.file_list_model, current_file, current_time, time_str
                )

    @staticmethod
    def get_time(key: str, updated_list: Dict[str, Dict]) -> Tuple[int, str]:
        current_time = updated_list[key]["last_seen"]
        time_struct = time.localtime(current_time / 1000)
        time_str = time.strftime("%Y-%m-%d %H:%M:%S%Z", time_struct)
        return current_time, time_str

    @staticmethod
    def _set_time(
        model: QAbstractItemModel,
        current_index: Union[File, FileWriter],
        current_time: str,
        time_str: str,
    ):
        model.setData(model.index(current_index.row, 1), time_str)
        current_index.last_time = current_time

    def send_command(self):
        if self.command_producer is not None:
            (
                nexus_file_name,
                broker,
                start_time,
                stop_time,
                service_id,
                abort_on_uninitialised_stream,
                use_swmr,
            ) = self.command_widget.get_arguments()
            in_memory_file = io.StringIO()
            generate_json(
                data=self.instrument,
                file=in_memory_file,
                nexus_file_name=nexus_file_name,
                broker=broker,
                start_time=start_time,
                stop_time=stop_time,
                service_id=service_id,
                use_swmr=use_swmr,
            )
            in_memory_file.seek(0)
            msg_to_send = in_memory_file.read()
            self.command_producer.send_command(msg_to_send)
            self.command_widget.ok_button.setEnabled(False)

    def file_list_clicked(self):
        if len(self.files_list.selectedIndexes()) > 0:
            self.stop_file_writing_button.setEnabled(True)
        else:
            self.stop_file_writing_button.setEnabled(False)

    def stop_file_writing_clicked(self):
        selected_files = self.files_list.selectedIndexes()
        for index in selected_files:
            for fileKey in self.known_files:
                current_file = self.known_files[fileKey]
                if index.row() == current_file.row:
                    send_msg = f' "cmd": "FileWriter_stop", "job_id": "{current_file.job_id}", "service_id": "{current_file.writer_id}" '
                    self.command_producer.send_command(
                        f'{{"{send_msg}"}}'.encode("utf-8")
                    )
                    break

    def closeEvent(self, event: QCloseEvent):
        if self.status_consumer is not None:
            self.status_consumer.close()
        if self.command_producer is not None:
            self.command_producer.close()
예제 #32
0
class AtomMspsModel(BaseModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._project_dict = None
        self._model = QStandardItemModel()
        # set roles
        self._label_role = Qt.UserRole + 1
        self._type_role = Qt.UserRole + 2
        self._chiiso_role = Qt.UserRole + 3
        self._chi11_role = Qt.UserRole + 4
        self._chi22_role = Qt.UserRole + 5
        self._chi33_role = Qt.UserRole + 6
        self._chi12_role = Qt.UserRole + 7
        self._chi13_role = Qt.UserRole + 8
        self._chi23_role = Qt.UserRole + 9
        self._model.setItemRoleNames({
            self._label_role: b'label',
            self._type_role: b'type',
            self._chiiso_role: b'chiiso',
            self._chi11_role: b'chi11',
            self._chi22_role: b'chi22',
            self._chi33_role: b'chi33',
            self._chi12_role: b'chi12',
            self._chi13_role: b'chi13',
            self._chi23_role: b'chi23'
        })
        self._log = logger.getLogger(self.__class__.__module__)

    def _setModelsFromProjectDict(self):
        """Create the model needed for GUI ..."""
        self._log.info("Starting to set Model from Project Dict")
        for phase_id, phase_dict in self._project_dict['phases'].items():
            # block model signals
            self._model.blockSignals(True)
            # set list of atoms
            data = []
            for atom_id, atom_dict in phase_dict['atoms'].items():
                data.append({
                    self._label_role:
                    atom_id,
                    self._type_role:
                    atom_dict.getItemByPath(['MSP', 'type']).value,
                    self._chiiso_role:
                    "",
                    self._chi11_role:
                    atom_dict.getItemByPath(['MSP', 'chi_11']).value,
                    self._chi22_role:
                    atom_dict.getItemByPath(['MSP', 'chi_22']).value,
                    self._chi33_role:
                    atom_dict.getItemByPath(['MSP', 'chi_33']).value,
                    self._chi12_role:
                    atom_dict.getItemByPath(['MSP', 'chi_12']).value,
                    self._chi13_role:
                    atom_dict.getItemByPath(['MSP', 'chi_13']).value,
                    self._chi23_role:
                    atom_dict.getItemByPath(['MSP', 'chi_23']).value,
                })
            # set model size
            self._model.setColumnCount(1)
            self._model.setRowCount(len(data))
            # set model from data list created above
            for row_index, dict_value in enumerate(data):
                index = self._model.index(row_index, 0)
                for role, value in dict_value.items():
                    self._model.setData(index, value, role)
            # unblock signals and emit model layout changed
            self._model.blockSignals(False)
            self._model.layoutChanged.emit()
        self._log.info("Finished setting Model from Project Dict")