Beispiel #1
0
class ViewWidget(QWidget):
    exercise_name_label = None
    exercise_name_line = None

    scroll_area = None
    base_widget = None
    exercises_widget = None

    return_button = None

    add_button = None

    def __init__(self):
        QWidget.__init__(self)

        self.file = ""
        self.setup_widget()

    def setup_widget(self):
        self.exercise_name_label = QLabel("Exercise name:", self)
        self.exercise_name_label.move(5, 5)
        self.exercise_name_label.resize(125, 25)

        self.add_button = QPushButton("Add", self)
        self.add_button.resize(75, 25)
        self.add_button.clicked.connect(self.add_line)

        self.exercise_name_line = QLineEdit(self)
        self.exercise_name_line.move(135, 5)
        self.exercise_name_line.resize(125, 25)

        self.scroll_area = QScrollArea(self)
        self.base_widget = QWidget(self)
        self.scroll_area.setWidget(self.base_widget)

        self.exercises_widget = QVBoxLayout()
        self.exercises_widget.setAlignment(Qt.AlignTop)

        self.base_widget.setLayout(self.exercises_widget)

        self.return_button = QPushButton("Return wo save", self)

    def resizeEvent(self, event):
        self.scroll_area.move(5, 35)
        self.scroll_area.resize(self.width() - 165, self.height() - 40)
        self.add_button.move(self.width() - 160 - 75, 5)
        self.return_button.move(self.width() - 155, 5)
        self.return_button.resize(150, 40)

        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

    def clear_widget(self):
        while self.exercises_widget.count() > 0:
            self.exercises_widget.takeAt(0)

    def open_exercise_file(self, file: str):
        self.file = file

        with open(self.file, "r") as json_file:
            json_data = json.load(json_file)

            name = json_data['name']

            for data in json_data['exercise']:
                movement = data['name']
                description = data['description']
                time = data['time']

                widget = PanelWidget()
                widget.set_data(movement, description, time)
                widget.remove_signal.connect(self.remove_panel_item)
                widget.move_down_signal.connect(self.move_widget_down)
                widget.move_up_signal.connect(self.move_widget_up)

                self.exercises_widget.addWidget(widget)

            json_file.close()

        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

        self.exercise_name_line.setText(name)

    @Slot()
    def add_line(self):
        widget = PanelWidget()
        self.exercises_widget.addWidget(widget)
        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)

    @Slot(QWidget)
    def move_widget_down(self, widget: QWidget):
        ind = self.exercises_widget.indexOf(widget)
        self.exercises_widget.removeWidget(widget)
        self.exercises_widget.insertWidget((ind + 1), widget)

    @Slot(QWidget)
    def move_widget_up(self, widget: QWidget):
        ind = self.exercises_widget.indexOf(widget)
        self.exercises_widget.removeWidget(widget)
        self.exercises_widget.insertWidget((ind - 1), widget)

    @Slot(QWidget)
    def remove_panel_item(self, widget: QWidget):
        self.exercises_widget.removeWidget(widget)
        self.base_widget.resize(self.scroll_area.width() - 25,
                                self.exercises_widget.count() * 25)
Beispiel #2
0
class RootsApp(QMainWindow):
    standard_deviation_threshold = 0.1                      # when I receive a measurement from the sensor I check if its standard deviation; if it's too low it means the sensor is not working
    temporary_database_filename = "temporary.db"            # the current session is stored in a temporary database. When the user saves, it is copied at the desired location
    def __init__(self):
        super().__init__();
        self.setWindowTitle("Roots")
        self.setFixedWidth(1200)
        self.resize(1200, 1200)
        self.threadpool = QThreadPool();
        self.object_list = list()
        self.is_training_on = False
        self.interaction_under_training = None
        self.n_measurements_collected = 0
        self.n_measurements_to_collect = 3
        self.sensor_not_responding = True
        self.sensor_not_responding_timeout = 2000        # milliseconds
        self.database_connection = self.create_temporary_database()
        self.active_object = None
        self.number_of_objects_added = 0
        self.sensor_start_freq = 250000
        self.sensor_end_freq = 3000000

    # creates the plot
        self.plotWidget = pyqtgraph.PlotWidget(title = "Sensor Response")
        self.plotWidget.setFixedHeight(300)
        self.plotWidget.getAxis("bottom").setLabel("Excitation frequency", "Hz")
        self.plotWidget.getAxis("left").setLabel("Volts", "V")
        self.dataPlot = self.plotWidget.plot()

    # timer used to see if the sensor is responding
        self.timer = QTimer()
        self.timer.setInterval(self.sensor_not_responding_timeout)
        self.timer.timeout.connect(self.timer_timeout)
        self.timer_timeout()

    # defines the actions in the file menu with button actions
        iconExit = QIcon("icons/icon_exit.png")
        btnActionExit = QAction(iconExit, "Exit", self)
        btnActionExit.setStatusTip("Click to terminate the program")
        btnActionExit.triggered.connect(self.exit)

        iconSave = QIcon("icons/icon_save.ico")
        buttonActionSave = QAction(iconSave, "Save current set of objects", self)
        # buttonActionSave.setStatusTip("Click to perform action 2")
        buttonActionSave.triggered.connect(self.save)

        iconOpen = QIcon("icons/icon_load.png")
        buttonActionOpen = QAction(iconOpen, "Load set of objects", self)
        buttonActionOpen.triggered.connect(self.open)

    # toolbar
        toolBar = QToolBar("Toolbar")
        toolBar.addAction(buttonActionSave)
        toolBar.addAction(buttonActionOpen)
        toolBar.setIconSize(QSize(64, 64))
        toolBar.setStyleSheet(styles.toolbar)
        self.addToolBar(toolBar)

    # menu
        menuBar = self.menuBar()
        menuBar.setStyleSheet(styles.menuBar)
        menuFile = menuBar.addMenu("File")
        menuOptions = menuBar.addMenu("Options")
        menuView = menuBar.addMenu("View")
        menuConnect = menuBar.addMenu("Connect")
        menuFile.addAction(buttonActionSave)
        menuFile.addAction(buttonActionOpen)
        menuFile.addAction(btnActionExit)

    # status bar
        self.setStatusBar(QStatusBar(self))

    # creates the "My Objects" label
        labelMyObjects = QLabel("My Objects")
        labelMyObjects.setFixedHeight(100)
        labelMyObjects.setAlignment(Qt.AlignCenter)
        labelMyObjects.setStyleSheet(styles.labelMyObjects)

    # button "add object"
        icon_plus = QIcon("icons/icon_add.png")
        self.btn_create_object = QPushButton("Add Object")
        self.btn_create_object.setCheckable(False)
        self.btn_create_object.setIcon(icon_plus)
        self.btn_create_object.setFixedHeight(80)
        self.btn_create_object.setStyleSheet(styles.addObjectButton)
        self.btn_create_object.clicked.connect(self.create_object)

    # defines the layout of the "My Objects" section
        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setContentsMargins(0,0,0,0)
        self.verticalLayout.addWidget(labelMyObjects)
        self.verticalLayout.addWidget(self.btn_create_object)
        self.spacer = QSpacerItem(0,2000, QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.verticalLayout.setSpacing(0)
        self.verticalLayout.addSpacerItem(self.spacer)  #adds spacer

    # defines the ComboBox which holds the names of the objects
        self.comboBox = QComboBox()
        self.comboBox.addItem("- no object selected")
        self.comboBox.currentIndexChanged.connect(self.comboBox_index_changed)
        self.comboBox.setFixedSize(300, 40)
        self.comboBox.setStyleSheet(styles.comboBox)
        self.update_comboBox()

    # defines the label "Selected Object" (above the comboBox)
        self.labelComboBox = QLabel()
        self.labelComboBox.setText("Selected Object:")
        self.labelComboBox.setStyleSheet(styles.labelComboBox)
        self.labelComboBox.adjustSize()

    # vertical layout for the combobox and its label
        self.VLayoutComboBox = QVBoxLayout()
        self.VLayoutComboBox.addWidget(self.labelComboBox)
        self.VLayoutComboBox.addWidget(self.comboBox)

    # label with the output text (the big one on the right)
        self.labelClassification = QLabel()
        self.labelClassification.setText("No interaction detected")
        self.labelClassification.setFixedHeight(80)
        self.labelClassification.setStyleSheet(styles.labelClassification)
        self.labelClassification.adjustSize()

        HLayoutComboBox = QHBoxLayout()
        HLayoutComboBox.addLayout(self.VLayoutComboBox)
        HLayoutComboBox.addSpacerItem(QSpacerItem(1000,0, QSizePolicy.Expanding, QSizePolicy.Expanding));  #adds spacer
        HLayoutComboBox.addWidget(self.labelClassification)

    # creates a frame that contains the combobox and the labels
        frame = QFrame()
        frame.setStyleSheet(styles.frame)
        frame.setLayout(HLayoutComboBox)

    # sets the window layout with the elements created before
        self.windowLayout = QVBoxLayout()
        self.windowLayout.addWidget(self.plotWidget)
        self.windowLayout.addWidget(frame)
        self.windowLayout.addLayout(self.verticalLayout)

    # puts everything into a frame and displays it on the window
        self.mainWindowFrame = QFrame()
        self.mainWindowFrame.setLayout(self.windowLayout)
        self.mainWindowFrame.setStyleSheet(styles.mainWindowFrame)
        self.setCentralWidget(self.mainWindowFrame)

        self.create_object()        # creates one object at the beginning



# -----------------------------------------------------------------------------------------------------------
# Shows a welcome message
    def show_welcome_msg(self):
        welcome_msg = QMessageBox()
        welcome_msg.setText("Welcome to the Roots application!")
        welcome_msg.setIcon(QMessageBox.Information)
        welcome_msg.setInformativeText(strings.welcome_text)
        welcome_msg.setWindowTitle("Welcome")
        welcome_msg.exec_()


# -----------------------------------------------------------------------------------------------------------
# When the user changes the object in the combobox, updates the active object
    def comboBox_index_changed(self, index):
        object_name = self.comboBox.currentText()
        for object in self.object_list:
            if object.name == object_name:
                self.set_active_object(object)
                print("DEBUG: selected object changed. Object name: {0}".format(object.name))
                return

# -----------------------------------------------------------------------------------------------------------
# This function allows to save the current objects on a file
    def save(self):
        current_path = os.getcwd()
        directory_path = current_path + "/Saved_Workspaces"

        if not os.path.exists(directory_path):
            os.mkdir(directory_path)

        file_path = None
        [file_path, file_extension] = QFileDialog.getSaveFileName(self,"Roots", directory_path, "Roots database (*.db)")
        if file_path is None:
            return

        temp_database_path = current_path + "/" + RootsApp.temporary_database_filename
        shutil.copyfile(temp_database_path, file_path)      # copies the temporary database to save the current workspace
        return



# -----------------------------------------------------------------------------------------------------------
# this function creates a clean database where all the data of this session will be temporarily stored
    def create_temporary_database(self):
        current_path = os.getcwd()
        file_path = current_path + "/" + RootsApp.temporary_database_filename

        if os.path.exists(file_path):   # if the database is already there it deletes it to reset it
            os.remove(file_path)
            print("DEBUG: removing database. (in 'RootsApp.create_temporary_database()'")

        database_connection = database.create_connection(RootsApp.temporary_database_filename)  # creates the temporary database
        database.create_tables(database_connection)                                             # initializes the database
        database.reset_db(database_connection)                                                  # resets the database (not needed but it doesn't cost anything to put it)

        return database_connection


# -----------------------------------------------------------------------------------------------------------
# This function allows to load previously created objects from a file
    def open(self):
        current_path = os.getcwd()
        saved_files_directory = current_path + "/Saved_Workspaces"

        [file_path, file_extension] = QFileDialog.getOpenFileName(self,"Roots", saved_files_directory, "Roots database (*.db)");
        if file_path == '':
            return

        for object in self.object_list.copy():     # deletes all the objects
            print("DEBUG: deleting object {0} (in 'open()')".format(object.name))
            self.delete_object(object)

        temp_database_path = current_path + "/" + RootsApp.temporary_database_filename
        self.database_connection.close()
        os.remove(temp_database_path)
        shutil.copyfile(file_path, temp_database_path)      # replaces the temporary database with the file to open
        self.database_connection = database.create_connection(temp_database_path)

        object_tuples = database.get_all_objects(self.database_connection)
        for object_tuple in object_tuples:
            object_ID, object_name = object_tuple
            location_IDs = database.get_locations_id_for_object(self.database_connection, object_ID)
            formatted_location_IDs = []
            for location_ID in location_IDs:
                formatted_location_IDs.append(location_ID[0])

            print("DEBUG: loading object {0} with location IDs {1}. (in 'RootsApp.open()')".format(object_name, formatted_location_IDs))
            self.add_object(object_name, object_ID, formatted_location_IDs)
            self.train_classifiers()
        return


# -----------------------------------------------------------------------------------------------------------
# This function updates the ComboBox whenever objects are created, destroyed or the active object has changed
    def update_comboBox(self):
        print("DEBUG: repainting ComboBox. (in 'RootsApp.update_comboBox()'")
        self.comboBox.clear()
        self.comboBox.addItem("none")
        for object in self.object_list:
            self.comboBox.addItem(object.name)
        self.comboBox.adjustSize()


# -----------------------------------------------------------------------------------------------------------
# This is a timer which is restarted every time a measurement is received. If it elapses it means that the sesnor is not connected
    def timer_timeout(self):
        print("DEBUG: timer timeout. (in 'RootsApp.timer_timeout()'")
        self.sensor_not_responding = True
        self.statusBar().showMessage(strings.sensor_disconnected)
        self.statusBar().setStyleSheet(styles.statusBarError)
        self.plotWidget.setTitle("Sensor not connected")

# -----------------------------------------------------------------------------------------------------------
# This function creates a new object in the database and then calls the "add_object" function, which adds the newly created object to the application
    def create_object(self):
        new_object_name = "Object {0}".format(self.number_of_objects_added + 1)
        [new_object_ID, location_IDs] = database.create_object(self.database_connection, new_object_name)
        self.add_object(new_object_name, new_object_ID, location_IDs)


# -----------------------------------------------------------------------------------------------------------
# This function deletes an object from the database, and from the application object list. It alsos destroys the object
    def delete_object(self, object):
        print("DEBUG: deleting object {0}. (in 'RootsApp.delete_object()')".format(object.ID))
        database.delete_object(self.database_connection, object.ID)
        self.object_list.remove(object)
        self.verticalLayout.removeItem(object.layout)
        self.update_comboBox()
        object.delete()


# -----------------------------------------------------------------------------------------------------------
# This function adds an object to the current application. Note that if you want to create an object ex-novo you should call "create_object". This function is useful when loading existing objects from a file
    def add_object(self, name, object_ID, location_IDs):
        self.number_of_objects_added += 1
        new_object = Object(name, object_ID, location_IDs, self)
        self.object_list.append(new_object)

        for ID in location_IDs:                                         # initializes the measurements with 0 if the measurement is empty
            #print("DEBUG: initializing location ID {0}".format(ID))
            measurements = database.get_measurements_for_location(self.database_connection, ID)

            print("DEBUG: location {0} of object {1} is trained: {2}. (in 'RootsApp.add_object()')".format(ID, new_object.name, database.is_location_trained(self.database_connection, ID)))
            if len(measurements) == 0:
                database.save_points(self.database_connection, [0], ID)
                database.set_location_trained(self.database_connection, ID, "FALSE")
            elif database.is_location_trained(self.database_connection, ID) == "TRUE":
                new_object.get_interaction_by_ID(ID).setCalibrated(True)

        # inserts the newly created object before the "Add Object" button
        index = self.verticalLayout.indexOf(self.btn_create_object)
        self.verticalLayout.insertLayout(index, new_object.layout)
        self.update_comboBox()
        print("DEBUG: object {0} added. (in 'RootsApp.add_object()')".format(new_object.name))
        return



# -----------------------------------------------------------------------------------------------------------
# This function takes as input the measurement data and formats it to plot it on the graph
    def update_graph(self, data):
        frequency_step = (self.sensor_end_freq - self.sensor_start_freq) / len(data)
        x_axis = numpy.arange(self.sensor_start_freq, self.sensor_end_freq, frequency_step)
        formatted_data = numpy.transpose(numpy.asarray([x_axis, data]))
        self.dataPlot.setData(formatted_data)


# -----------------------------------------------------------------------------------------------------------
# This function starts the UDP server that receives the measurements
    def run_UDP_server(self, UDP_IP, UDP_PORT):
        self.UDPServer = UDPServer(UDP_IP, UDP_PORT)
        self.UDPServer.signals.measurementReceived.connect(self.process_measurement)
        self.threadpool.start(self.UDPServer)


# -----------------------------------------------------------------------------------------------------------
# This function changes some global variables to tell the application to save the incoming measurements into the database. The measurements belong to the interaction passed as argument
    def start_collecting_measurements(self, interaction):
        if self.sensor_not_responding:
            print("DEBUG: warning! Can't start calibration, the sensor is not responding! (in 'RootsApp.start_collecting_measurements()')")
            error_msg = QMessageBox()
            error_msg.setText("Can't start calibration!")
            error_msg.setIcon(QMessageBox.Critical)
            error_msg.setInformativeText('The sensor is not responding, make sure it is connected')
            error_msg.setWindowTitle("Error")
            error_msg.exec_()
        else:
            print("starting to collect measurements into the database at location ID {0} (in 'RootsApp.start_collecting_measurements()')".format(interaction.ID));
            self.is_training_on = True
            self.interaction_under_training = interaction
            database.delete_measurements_from_location(self.database_connection, interaction.ID)   # resets the location measurements

            self.progress_dialog = QProgressDialog("Calibrating", "Abort", 0, self.n_measurements_to_collect, self)
            self.progress_dialog.setWindowModality(Qt.WindowModal)
            self.progress_dialog.setWindowTitle("Calibration")
            self.progress_dialog.setFixedSize(400, 200)
            self.progress_dialog.setValue(0)
            self.progress_dialog.exec_()



# -----------------------------------------------------------------------------------------------------------
# This function is called by the UDP thread every time that a measurement is received. It does the following:
#   1. Plots the incoming measurement
#   2. IF training mode IS on:
#           Predicts the interaction (tries to guess where the user is touching)
#      ELSE:
#           Saves the measurement and retrains the classifier with the new data
    def process_measurement(self, received_data):
        self.sensor_not_responding = False
        self.plotWidget.setTitle("Sensor response")
        self.timer.start()                                          # starts the timer that checks if we are receiving data from the sensor

        measurement = received_data.split(' ')                      # get rid of separator
        measurement = [float(i) for i in measurement]               # convert strings to float
        self.update_graph(measurement)
        self.predict_interaction(measurement)

        # checks the standard deviation of the received data to see if the sensor is working well
        if (numpy.std(measurement) < self.standard_deviation_threshold):
            self.statusBar().showMessage(strings.sensor_not_working)
            self.statusBar().setStyleSheet(styles.statusBarError)
        else:
            self.statusBar().setStyleSheet(styles.statusBar)

        if self.is_training_on:
            print("saving measurement {0} into database at location_ID {1}. (in 'RootsApp.process_measurement()')".format(self.n_measurements_collected + 1, self.interaction_under_training.ID))
            database.save_points(self.database_connection, measurement, self.interaction_under_training.ID)
            self.n_measurements_collected += 1
            self.progress_dialog.setValue(self.n_measurements_collected)
            if (self.n_measurements_collected >= self.n_measurements_to_collect):
                self.is_training_on = False
                self.n_measurements_collected = 0
                print("DEBUG: {0} measurements were saved at location_ID {1}. (in 'RootsApp.process_measurement()')".format(self.n_measurements_to_collect, self.interaction_under_training.ID))
                self.train_classifiers()
                self.interaction_under_training.setCalibrated(True)     # this makes the button "Calibrate" change coulour


# -----------------------------------------------------------------------------------------------------------
# This function retrains the classifiers using all the measurements present in the database and assigns to each object its classifier
    def train_classifiers(self):
        #[objects_ID, classifiers]
        classifiers = classifier.get_classifiers(self.database_connection)
        print("DEBUG: the following classifiers were created: {0}. (in 'RootsApp.train_classifiers')".format(classifiers))
        for object in self.object_list:
            for index, tuple in enumerate(classifiers):
                object_ID, classif = tuple;  # extracts the object ID and the classifier from the tuple
                if object_ID == object.ID:
                    object.classifier = classif
                    del classifiers[index]


# -----------------------------------------------------------------------------------------------------------
# This function changes the current active object (the software tries to guess where the user is touching using the calibration data from the active object)
    def set_active_object(self, active_object):
        self.active_object = active_object

        for obj in self.object_list:
            if obj == active_object:
                active_object.set_highlighted(True)
            else:
                obj.set_highlighted(False)

        index = self.comboBox.findText(self.active_object.name)     # updates the index of the ComboBox
        self.comboBox.setCurrentIndex(index)


# -----------------------------------------------------------------------------------------------------------
# This function changes the name of an object. It updates the database AND the application data structure.
    def rename_object(self, object, new_name):
        print("DEBUG: changing name of object '{0}' (in 'RootsApp.rename_object')".format(object.name))
        object.set_name(new_name)
        database.rename_object(self.database_connection, object.ID, new_name)
        self.update_comboBox()



# -----------------------------------------------------------------------------------------------------------
# This function uses the classifier of the active object to guess where the user is touching, based on the incoming measurement
    def predict_interaction(self, measurement):
        if (len(self.object_list) <= 0):
            self.labelClassification.setText("No objects available")
            self.statusBar().showMessage(strings.no_objects)
            return
        if self.active_object is None:
            self.labelClassification.setText("No object selected")
            self.statusBar().showMessage(strings.no_object_selected)
            return
        if self.active_object.classifier is None:
            self.labelClassification.setText("The object is not calibrated")
            self.statusBar().showMessage(strings.object_not_calibrated)
            return
        else:
            predicted_interaction_id = self.active_object.classifier(measurement)
            interaction = self.active_object.get_interaction_by_ID(predicted_interaction_id)
            self.labelClassification.setText(interaction.name)
            self.statusBar().showMessage("")
            #print("DEBUG: predicted interaction ID: ", interaction.ID)



# -----------------------------------------------------------------------------------------------------------
# This is a system event that gets called whenever the user tries to close the application. It calls the "exit()"
# function (just below) to open a dialog to make sure the user really wants to quit.
    def closeEvent(self, event):
        if not self.exit():
            event.ignore()


# -----------------------------------------------------------------------------------------------------------
# This function gets called when the user cliks on the "Exit" button in the "File" menu or when it tries to close the window (indirectly)
# Here we open a dialog to make sure the user really wants to quit.
    def exit(self):
        dialogWindow = DialogExit()
        answer = dialogWindow.exec_()
        if (answer == True):
            self.UDPServer.stop()
            self.close()
        return answer
Beispiel #3
0
class DBWorkspace(QWidget):
    def __init__(self, db, table, parent=None):
        super().__init__(parent)

        self.main_layout = QVBoxLayout()
        self.tab_widget = None
        self.handler = None
        self.db = db
        self.table = table
        self.table_model = None
        self.create_tab_widget()

        self.main_table = DBTableView(self.tab_widget)
        self.main_table.setSelectionMode(QAbstractItemView.SingleSelection)
        self.main_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.init_table()
        self.main_table.clicked.connect(self.row_selected)

        self.package = QVBoxLayout()
        self.package.addStretch(1)

        self.toolBar = QToolBar()
        self.toolBar.setMovable(True)

        self.up = QAction(
            QIcon("view/images/toolbar/baseline_expand_less_black_48dp.png"),
            "Up", self.main_table)
        self.up.setStatusTip("Move one up")
        self.up.triggered.connect(self.jump_up)

        self.down = QAction(
            QIcon("view/images/toolbar/baseline_expand_more_black_48dp.png"),
            "Down", self.main_table)
        self.down.setStatusTip("Move one down")
        self.down.triggered.connect(self.jump_down)

        self.first = QAction(
            QIcon("view/images/toolbar/baseline_first_page_black_48dp.png"),
            "Jump to first", self.main_table)
        self.first.setStatusTip("Jump to first")
        self.first.triggered.connect(self.jump_to_first)

        self.last = QAction(
            QIcon("view/images/toolbar/baseline_last_page_black_48dp.png"),
            "Jump to last", self.main_table)
        self.last.setStatusTip("Jump to last")
        self.last.triggered.connect(self.jump_to_last)

        self.toolBar.addAction(QIcon("view/images/toolbar/list_48px.png"),
                               "Manage Data")
        self.toolBar.addAction(QIcon("view/images/toolbar/add_new_40px.png"),
                               "Add Data")
        self.toolBar.addAction(self.first)
        self.toolBar.addAction(self.up)
        self.toolBar.addAction(self.down)
        self.toolBar.addAction(self.last)
        self.toolBar.addAction(
            QIcon("view/images/toolbar/close_window_26px.png"), "Close")

        self.manageData = DBManageData(self.main_table)
        self.addData = DBAddData(self.main_table)

        self.stacked_layout = QVBoxLayout()
        self.label = QLabel()
        self.label.setText("Work with data, choose state.")

        self.toolBar.actionTriggered.connect(self.toolbar_actions)

        self.package.addWidget(self.toolBar)
        self.package.addLayout(self.stacked_layout)
        self.package.addWidget(self.main_table)

        self.main_layout.addLayout(self.package)

        self.selected_row = 0

        self.main_layout.addStretch(2)
        self.setLayout(self.main_layout)

    def toolbar_actions(self, action):
        if action.iconText() == "Manage Data":
            if self.stacked_layout.indexOf(
                    self.addData) == -1 and self.stacked_layout.indexOf(
                        self.manageData) == -1 and self.stacked_layout.indexOf(
                            self.label) == -1:
                self.stacked_layout.addWidget(self.manageData)
                self.manageData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.addData) != -1:
                self.stacked_layout.removeWidget(self.addData)
                self.addData.setVisible(False)
                self.stacked_layout.addWidget(self.manageData)
                self.manageData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.label) != -1:
                self.stacked_layout.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout.addWidget(self.manageData)
                self.manageData.setVisible(True)
                return
            return

        elif action.iconText() == "Add Data":
            if self.stacked_layout.indexOf(
                    self.addData) == -1 and self.stacked_layout.indexOf(
                        self.manageData) == -1 and self.stacked_layout.indexOf(
                            self.label) == -1:
                self.stacked_layout.addWidget(self.addData)
                self.addData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.manageData) != -1:
                self.stacked_layout.removeWidget(self.manageData)
                self.manageData.setVisible(False)
                self.stacked_layout.addWidget(self.addData)
                self.addData.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.label) != -1:
                self.stacked_layout.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout.addWidget(self.addData)
                self.addData.setVisible(True)
                return
            return

        elif action.iconText() == "Close":
            if self.stacked_layout.indexOf(
                    self.addData) == -1 and self.stacked_layout.indexOf(
                        self.manageData) == -1 and self.stacked_layout.indexOf(
                            self.label) == -1:
                self.stacked_layout.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.addData) != -1:
                self.stacked_layout.removeWidget(self.addData)
                self.addData.setVisible(False)
                self.stacked_layout.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout.indexOf(self.manageData) != -1:
                self.stacked_layout.removeWidget(self.manageData)
                self.manageData.setVisible(False)
                self.stacked_layout.addWidget(self.label)
                self.label.setVisible(True)
                return
            return

    def row_selected(self, index):
        if index.column() == len(self.main_table.model().columns):

            model = self.main_table.model()
            selected_data = model.get_element(index)

            self.selected_row = index.row()

    def create_tab_widget(self):
        self.tab_widget = QTabWidget()
        self.tab_widget.setTabsClosable(True)
        self.tab_widget.tabCloseRequested.connect(self.delete_tab)

    def delete_tab(self, index):
        self.tab_widget.removeTab(index)

    def init_table(self):
        self.handler = DBHandler(self.db, self.table, self)
        self.table_model = DBTableModel(self.handler)
        self.main_table.setModel(self.table_model)

    """
    Table navigation jumps
    """

    def jump_up(self):
        if self.selected_row != 0:
            self.selected_row -= 1
            self.main_table.selectRow(self.selected_row)

    def jump_down(self):
        if self.selected_row < len(self.main_table.model().displayed_d) - 1:
            self.selected_row += 1
            self.main_table.selectRow(self.selected_row)

    def jump_to_first(self):
        self.selected_row = 0
        self.main_table.selectRow(self.selected_row)

    def jump_to_last(self):
        self.selected_row = len(self.main_table.model().displayed_d) - 1
        self.main_table.selectRow(self.selected_row)

    def sub_up(self):
        if self.selected_row != 0:
            self.selected_row -= 1
            self.subtable.selectRow(self.selected_row)

    def sub_down(self):
        if self.selected_row < len(self.subtable.model().displayed_d) - 1:
            self.selected_row += 1
            self.subtable.selectRow(self.selected_row)

    def sub_first(self):
        self.selected_row = 0
        self.subtable.selectRow(self.selected_row)

    def sub_last(self):
        self.selected_row = len(self.subtable.model().displayed_d) - 1
        self.subtable.selectRow(self.selected_row)
Beispiel #4
0
class SubtableWidget(QWidget):
    def __init__(self, subtable, parent=None):
        super().__init__(parent)
        self.subtable = subtable
        self.subtable.setSelectionMode(QAbstractItemView.SingleSelection)
        self.subtable.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.subtable.clicked.connect(self.row_selected)
        self.selected_row = 0

        self.package = QVBoxLayout()

        self.toolBar = QToolBar()
        self.toolBar.setMovable(True)

        sub_up = QAction(
            QIcon("view/images/toolbar/baseline_expand_less_black_48dp.png"),
            "Up", self.subtable)
        sub_up.setStatusTip("Move one up")
        sub_up.triggered.connect(self.sub_up)

        sub_down = QAction(
            QIcon("view/images/toolbar/baseline_expand_more_black_48dp.png"),
            "Down", self.subtable)
        sub_down.setStatusTip("Move one down")
        sub_down.triggered.connect(self.sub_down)

        sub_first = QAction(
            QIcon("view/images/toolbar/baseline_first_page_black_48dp.png"),
            "Jump to first", self.subtable)
        sub_first.setStatusTip("Jump to first")
        sub_first.triggered.connect(self.sub_first)

        sub_last = QAction(
            QIcon("view/images/toolbar/baseline_last_page_black_48dp.png"),
            "Jump to last", self.subtable)
        sub_last.setStatusTip("Jump to last")
        sub_last.triggered.connect(self.sub_last)

        self.toolBar.addAction(QIcon("view/images/toolbar/list_48px.png"),
                               "Manage Data")
        self.toolBar.addAction(QIcon("view/images/toolbar/add_new_40px.png"),
                               "Add Data")
        self.toolBar.addAction(sub_first)
        self.toolBar.addAction(sub_up)
        self.toolBar.addAction(sub_down)
        self.toolBar.addAction(sub_last)
        self.toolBar.addAction(
            QIcon("view/images/toolbar/close_window_26px.png"), "Close")

        self.manageData2 = ManageData(self.subtable)

        self.addData2 = AddData(self.subtable)
        self.label = QLabel()
        self.label.setText("Work with data, choose state.")

        self.stacked_layout_2 = QVBoxLayout()
        self.stacked_layout_2.addStretch(0)

        self.toolBar.actionTriggered.connect(self.sub_toolbar_actions)

        self.package.addWidget(self.toolBar)
        self.package.addLayout(self.stacked_layout_2)
        self.package.addWidget(self.subtable)

        self.setLayout(self.package)

    def sub_toolbar_actions(self, action):
        if action.iconText() == "Manage Data":
            if self.stacked_layout_2.indexOf(
                    self.addData2) == -1 and self.stacked_layout_2.indexOf(
                        self.manageData2
                    ) == -1 and self.stacked_layout_2.indexOf(
                        self.label) == -1:
                self.stacked_layout_2.addWidget(self.manageData2)
                self.manageData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.addData2) != -1:
                self.stacked_layout_2.removeWidget(self.addData2)
                self.addData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.manageData2)
                self.manageData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.label) != -1:
                self.stacked_layout_2.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout_2.addWidget(self.manageData2)
                self.manageData2.setVisible(True)
                return
            return

        elif action.iconText() == "Add Data":
            if self.stacked_layout_2.indexOf(
                    self.addData2) == -1 and self.stacked_layout_2.indexOf(
                        self.manageData2
                    ) == -1 and self.stacked_layout_2.indexOf(
                        self.label) == -1:
                self.stacked_layout_2.addWidget(self.addData2)
                self.addData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.manageData2) != -1:
                self.stacked_layout_2.removeWidget(self.manageData2)
                self.manageData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.addData2)
                self.addData2.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.label) != -1:
                self.stacked_layout_2.removeWidget(self.label)
                self.label.setVisible(False)
                self.stacked_layout_2.addWidget(self.addData2)
                self.addData2.setVisible(True)
                return
            return

        elif action.iconText() == "Close":
            if self.stacked_layout_2.indexOf(
                    self.addData2) == -1 and self.stacked_layout_2.indexOf(
                        self.manageData2
                    ) == -1 and self.stacked_layout_2.indexOf(
                        self.label) == -1:
                self.stacked_layout_2.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.addData2) != -1:
                self.stacked_layout_2.removeWidget(self.addData2)
                self.addData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.label)
                self.label.setVisible(True)
                return
            if self.stacked_layout_2.indexOf(self.manageData2) != -1:
                self.stacked_layout_2.removeWidget(self.manageData2)
                self.manageData2.setVisible(False)
                self.stacked_layout_2.addWidget(self.label)
                self.label.setVisible(True)
                return
            return

    def row_selected(self, index):
        self.selected_row = index.row()

    def sub_up(self):
        if self.selected_row != 0:
            self.selected_row -= 1
            self.subtable.selectRow(self.selected_row)

    def sub_down(self):
        if self.selected_row < len(self.subtable.model().displayed_d) - 1:
            self.selected_row += 1
            self.subtable.selectRow(self.selected_row)

    def sub_first(self):
        self.selected_row = 0
        self.subtable.selectRow(self.selected_row)

    def sub_last(self):
        self.selected_row = len(self.subtable.model().displayed_d) - 1
        self.subtable.selectRow(self.selected_row)