Commit e7f58a0b authored by magho's avatar magho
Browse files

refactored out common frame code to inherited classes

parent a6c285b9
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -4,3 +4,5 @@
*/Hardware/History
*/Hardware/__Previews
*/Hardware/Project\ Logs*

*/__pycache__
+22 −4
Original line number Diff line number Diff line
@@ -10,8 +10,8 @@ from frames.Balance import Balance

import api_communication as API

import ble_driver as NeoBLE
import rfid
import ble_driver as ble
import rfid_driver as rfid

class NeoKomp(QtWidgets.QMainWindow):
    """
@@ -31,10 +31,16 @@ class NeoKomp(QtWidgets.QMainWindow):
        self.central_widget = QtWidgets.QStackedWidget()
        self.setCentralWidget(self.central_widget)

        # Timeout indicator always runs. Frames will connect to this timer if
        # they need to repeatedly run a routine to update a label, like a timer
        # countdown.
        self.indicator_timer = QtCore.QTimer()
        self.indicator_timer.start(100)

        # Make frames
        self.frames = {}
        for F in (Guide, Search, Cart, Receipt, Balance):
            frame = F(self)
            frame = F(parent=self)
            self.frames[frame.__class__.__name__] = frame
            self.central_widget.addWidget(frame)

@@ -51,9 +57,10 @@ class NeoKomp(QtWidgets.QMainWindow):
        self.rfid_manager.start()

        # Make BLE manager
        self.ble_manager = NeoBLE.BLEThread(self, self.device_mapping)
        self.ble_manager = ble.BLEThread(self, self.device_mapping)
        self.ble_manager.start()


    def enter_event(self, event):
        """Send enter event to the relevant frame"""
        frame = self.frames[self.state]
@@ -63,6 +70,17 @@ class NeoKomp(QtWidgets.QMainWindow):
        self.central_widget.setCurrentWidget(self.frames[frame])
        self.frames[frame].focus()

    def show_balance(self, rfid):
        self.show_frame('Balance')
        self.frames['Balance'].show_balance(rfid)

    def attempt_to_buy(self, rfid, items):
        self.show_frame('Receipt')
        self.frames['Receipt'].attempt_to_buy(rfid, items)

    def cart_has_items(self):
        return self.frames['Cart'].has_items()

    @QtCore.pyqtSlot("PyQt_PyObject")
    def ble_button_pressed(self, location):
        self.frames['Cart'].add_item_from_location(location)
+4 −5
Original line number Diff line number Diff line
@@ -18,10 +18,9 @@ class BLEThread(QtCore.QThread):
        self.parent = parent
        self.device_mapping = device_mapping

        # Find primary bluetooth controller. TODO: find a better way of getting
        # the adapter name
        # Find primary Bluetooth controller.
        ctrl_info = subprocess.check_output(['btmgmt', 'info']).decode('utf-8')
        pattern = r"([a-zA-Z]*[0-9]*):\tPrimary controller"
        pattern = r"([a-zA-Z]+[0-9]+):\tPrimary controller"
        primary_ctrl = re.search(pattern, ctrl_info).group(1)

        # Make sure ble is on and not currently connected
@@ -29,7 +28,7 @@ class BLEThread(QtCore.QThread):
        os.system("bluetoothctl power on")

        # Create BLE Manager
        self.manager = BLEKomp(parent=self, adapter_name=primary_ctrl)
        self.manager = BLEManager(parent=self, adapter_name=primary_ctrl)

        # Connect signal
        self.button_pressed.connect(parent.ble_button_pressed)
@@ -45,7 +44,7 @@ class BLEThread(QtCore.QThread):
        print("Button order: %s" % position)
        self.button_pressed.emit(position)

class BLEKomp(gatt.DeviceManager):
class BLEManager(gatt.DeviceManager):
    def __init__(self, *args, **kwargs):
        self.parent = kwargs.pop('parent')
        super().__init__(*args, **kwargs)
+6 −35
Original line number Diff line number Diff line
@@ -2,32 +2,23 @@ import sys
import traceback
import math
from PyQt5 import QtCore, QtGui, QtWidgets
from frames.FrameBase import GenericFrame, TimedFrame

import api_communication as API

BALANCE_TIMEOUT_MS = 300000
BALANCE_TIMEOUT_MS = 10000

DEBUG = True
def debug(string):
    if DEBUG:
        print(string)

class Balance(QtWidgets.QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.parent = parent
class Balance(GenericFrame, TimedFrame):
    def __init__(self, **kwargs):
        super(Balance, self).__init__(**dict(kwargs, timeout=BALANCE_TIMEOUT_MS))
        self.parent = kwargs['parent']

        self.init_layout()

        self.timer_init()

        ## Install/Enable custom eventFilter()
        self.installEventFilter(self)

    def init_layout(self):
        # General vertical layout
        self.layout = QtWidgets.QVBoxLayout(self)

        title_font = QtGui.QFont()
        title_font.setPointSize(20)
        self.title = QtWidgets.QLabel("Balance")
@@ -104,26 +95,6 @@ Start typing to search for a component."""
        # Pass event to QWidget
        return super(Balance, self).eventFilter(obj, event)


    def timer_init(self):
        # Timeout is SingleShot timer
        self.timeout_timer = QtCore.QTimer()
        self.timeout_timer.setSingleShot(True)
        self.timeout_timer.timeout.connect(self.timeout)

        # Timeout indicator always runs
        self.indicator_timer = QtCore.QTimer()
        self.indicator_timer.start(100)
        self.indicator_timer.timeout.connect(self.update_timeout_indicator)

    def restart_timer(self):
        if self.timeout_timer.isActive():
            self.timeout_timer.stop()
        self.timeout_timer.start(BALANCE_TIMEOUT_MS)

    def stop_timer(self):
        self.timeout_timer.stop()

    @QtCore.pyqtSlot()
    def timeout(self):
        #Clear it and go to guide
+75 −79
Original line number Diff line number Diff line
import sys
import math
from PyQt5 import QtCore, QtGui, QtWidgets
from frames.FrameBase import GenericFrame, TimedFrame

import api_communication as API

@@ -9,22 +10,15 @@ CART_TIMEOUT_MS = 300000
CART_TABLE_HEIGHT = 500
CART_TABLE_WIDTH = 800

DEBUG = True
def debug(string):
    if DEBUG:
        print(string)

class Cart(QtWidgets.QWidget):
    def __init__(self, parent):
        super().__init__(parent)
        self.parent = parent
class Cart(GenericFrame, TimedFrame):
    def __init__(self, **kwargs):
        super(Cart, self).__init__(**dict(kwargs, timeout=CART_TIMEOUT_MS))
        self.parent = kwargs['parent']

        self.headers = ['id', 'navn', 'beskrivelse', 'antall', 'pris']

        self.layout_init()

        self.timer_init()

        self.add_total()

        # Connect cell double click to add to cart
@@ -34,9 +28,6 @@ class Cart(QtWidgets.QWidget):
        self.installEventFilter(self)

    def layout_init(self):
        ## General vertical layout
        self.layout = QtWidgets.QVBoxLayout(self)

        ## Title
        title_font = QtGui.QFont()
        title_font.setPointSize(20)
@@ -58,10 +49,10 @@ class Cart(QtWidgets.QWidget):
        self.layout.addStretch()

        ## Help text
        self.help_text = "\
Press <Return> to remove selected item.\n\
Double click item to remove item.\n\
TODO: Scan RFID card to buy Cart."
        self.help_text = """Press <Return> to remove selected item.
Double click item to remove item.
TODO: Scan RFID card to buy Cart.
        """

        self.help_label = QtWidgets.QLabel(self.help_text)
        self.layout.addWidget(self.help_label)
@@ -102,21 +93,38 @@ TODO: Scan RFID card to buy Cart."

        self.layout.addLayout(self.navigation_buttons)

    @QtCore.pyqtSlot()
    def timeout(self):
        #Clear it and go to guide
        self.clear_cart('Guide')

    @QtCore.pyqtSlot()
    def update_timeout_indicator(self):
        if self.timeout_timer.isActive():
            time = self.timeout_timer.remainingTime()
            time = math.ceil(time / 1000) # ms to s
            self.timeout_indicator.setText("Timeout in " + str(time) + "s")
        else:
            self.timeout_indicator.setText("")

    # Install a custom eventFilter to capture enterPressed anywhere
    def eventFilter(self, obj, event):
        if event.type() == QtCore.QEvent.ShortcutOverride:
            self.restart_timer()
            if event.text().isalnum():
                self.parent.show_frame('Search')
            return False # ?

        if event.type() == QtCore.QEvent.KeyPress:
        elif event.type() == QtCore.QEvent.KeyPress:
            if event.key() == QtCore.Qt.Key_Return:
                self.return_pressed()
                return True
            if event.key() == QtCore.Qt.Key_Escape:
            elif event.key() == QtCore.Qt.Key_Escape:
                # Emulate timeout
                self.clear_cart('Guide')
                return True
            else:
                self.restart_timer()

        # Pass event to QWidget
        return super(Cart, self).eventFilter(obj, event)
@@ -138,42 +146,6 @@ TODO: Scan RFID card to buy Cart."
        if (row < self.cart.rowCount() - 1):
            self.remove_row(row)

    def timer_init(self):
        # Timeout is SingleShot timer
        self.timeout_timer = QtCore.QTimer()
        self.timeout_timer.setSingleShot(True)
        self.timeout_timer.timeout.connect(self.timeout)

        # Timeout indicator always runs
        self.indicator_timer = QtCore.QTimer()
        self.indicator_timer.start(100)
        self.indicator_timer.timeout.connect(self.update_timeout_indicator)

    def restart_timer(self):
        if self.timeout_timer.isActive():
            self.timeout_timer.stop()
        self.timeout_timer.start(CART_TIMEOUT_MS)

    def stop_timer(self):
        self.timeout_timer.stop()

    @QtCore.pyqtSlot()
    def timeout(self):
        #Clear it and go to guide
        self.clear_cart()

    @QtCore.pyqtSlot()
    def update_timeout_indicator(self):
        if self.timeout_timer.isActive():
            time = self.timeout_timer.remainingTime()
            time = math.ceil(time / 1000) # ms to s
            self.timeout_indicator.setText("Timeout in " + str(time) + "s")
        else:
            self.timeout_indicator.setText("")

    def focus(self):
        return

    def add_item_from_location(self, loc):
        item = API.AJAX_search_component_pos(loc['rom'], loc['seksjon'], loc['hylle'], loc['rad'], loc['kolonne'], loc['dybde'])
        print(item)
@@ -193,8 +165,37 @@ TODO: Scan RFID card to buy Cart."
    def has_items(self):
        return self.cart.rowCount() >= 2

    def add_to_row_amount(self, row, num):
        # Get old amount
        # Row 5 has amount
        amount = self.cart.item(row, 3).text()
        try:
            amount = int(amount) + 1
        except:
            print("EXCET")
            amount = 0

        self.cart.item(row, 3).setText(str(amount))

    def increment_row_amount(self, row):
        self.add_to_row_amount(row, 1)

    def decrement_row_amount(self, row):
        self.add_to_row_amount(row, -1)

    def add_item(self, item):
        row_positions = self.cart.rowCount()

        # Check if the item is already in the cart
        row_of_existing_item = None
        for row in range(row_positions-1):
            item_id = self.cart.item(row, 0).data(QtCore.Qt.UserRole)['id']
            if (item_id == item['id']):
                row_of_existing_item = row

        if (row_of_existing_item != None):
            self.increment_row_amount(row_of_existing_item)
        else:
            # New item goes one above the bottom (which is the Total/Sum)
            row = row_positions - 1
            self.cart.insertRow(row)
@@ -242,7 +243,6 @@ TODO: Scan RFID card to buy Cart."
        title_table_item.setFont(font)
        total_table_item.setFont(font)


    def update_total(self):
        total = 0
        row_count = self.cart.rowCount()
@@ -310,15 +310,11 @@ TODO: Scan RFID card to buy Cart."
            items.append(self.cart.item(row, 0).data(QtCore.Qt.UserRole))

        if len(items) == 0:
            self.parent.show_frame('Balance')
            self.parent.frames['Balance'].show_balance(rfid)
            self.parent.show_balance(rfid)
            return

        # Switch to receipt
        self.parent.show_frame('Receipt')

        # Issue the buy
        self.parent.frames['Receipt'].attempt_to_buy(rfid, items)

        # Clear the cart
        self.clear_cart('Receipt')

        # Issue the buy
        self.parent.attempt_to_buy(rfid, items)
Loading