class MainWidget(QtGui.QWidget): """The main tab, featuring the KiKrit client GUI. """ # Widhgets: search_line = None merchandise_list = None stack = None order_page = None balance_page = None add_button = None remove_button = None msg = None # Keyboard shortcuts: ks_left = None ks_right = None ks_enter = None ks_escape = None ks_f5 = None ks_alphanum = None def __init__(self, rfid_thread, parent=None): QtGui.QWidget.__init__(self, parent) self.rfid_thread = rfid_thread # Views: self.search_line = SearchLine(self) # self.search_line.grabKeyboard() self.merchandise_list = QtGui.QListView(self) self.merchandise_list.setModel(MerchandiseListModel(self._getItems(), self)) self.merchandise_list.setSelectionMode(QtGui.QListView.SingleSelection) self.stack = QtGui.QStackedWidget() self.order_page = OrderPage(self.stack) self.balance_page = BalancePage(self.stack) self.stack.insertWidget(0, self.order_page) self.stack.insertWidget(1, self.balance_page) self.add_button = QtGui.QPushButton("Add", self) self.remove_button = QtGui.QPushButton("Remove", self) self.msg = MessageLine() # Keyboard shortcuts: self.ks_up = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Up", "Item|prev")), self) self.ks_down = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Down", "Item|next")), self) self.ks_left = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Left", "Select|left")), self) self.ks_right = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Right", "Select|right")), self) self.ks_return = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Return", "Item|add/remove")), self) self.ks_escape = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Escape", "Cancel current action")), self) self.ks_f5 = QtGui.QShortcut(QtGui.QKeySequence(self.tr("F5", "Force refresh")), self) self.ks_ctrls = QtGui.QShortcut(QtGui.QKeySequence(self.tr("Ctrl+s", "Focus search line")), self) # Layout: grid = QtGui.QGridLayout(self) grid.addWidget(self.search_line, 0, 0) grid.addWidget(self.merchandise_list, 1, 0) grid.addWidget(self.add_button, 2, 0) grid.addWidget(self.stack, 1, 1, 1, 1) grid.addWidget(self.remove_button, 2, 1) grid.addWidget(self.msg, 0, 1) self.setLayout(grid) # Connect signals: if parent != None: self.parentWidget().currentChanged.connect(self.tabChanged) self.search_line.textChanged.connect(self.searchLineChanged) self.ks_right.activated.connect(self.rightPressed) self.ks_left.activated.connect(self.leftPressed) self.ks_up.activated.connect(self.upPressed) self.ks_down.activated.connect(self.downPressed) self.ks_return.activated.connect(self.returnPressed) self.ks_escape.activated.connect(self.escapePressed) self.ks_f5.activated.connect(self.f5Pressed) self.ks_ctrls.activated.connect(self.activateSearchLine) self.add_button.clicked.connect(self.addClicked) self.remove_button.clicked.connect(self.removeClicked) self.rfid_thread.rfid_signal.connect(self.rfidEvent) def _reset(self): if self.stack.currentWidget() != self.order_page: self.stack.setCurrentWidget(self.order_page) self.order_page.emptyList() self.search_line.setText("") self.activateSearchLine() def _tabHasFocus(self): """Returns true if self is the parrents current widget, or if there is no parent. """ parent = self.parentWidget() if parent == None or parent.currentWidget() == self: return True return False def _getItems(self): """ Queries the database for all Merchandise objects, and return them as one large list. """ return list(Merchandise.objects.all()) def _setSelected(self, list_view, new_index=None, next=False): """Takes a QListView object, and int and a bool. Changes selection to new_index, or to prev or next item in list view. """ # Get new_index: if new_index == None: if next: indexes = [i.row() + 1 for i in list_view.selectedIndexes()] if len(indexes) == 0: indexes = [0] else: indexes = [i.row() - 1 for i in list_view.selectedIndexes()] if len(indexes) == 0: indexes = [-1] new_index = indexes[0] # Check range: row_count = list_view.model().rowCount() if new_index < 0: new_index += row_count elif new_index >= row_count: new_index -= row_count # Update selection: mdl_index = list_view.model().index(new_index, 0) list_view.selectionModel().select(mdl_index, QtGui.QItemSelectionModel.ClearAndSelect) list_view.scrollTo(mdl_index) def tabChanged(self, index): if self.parentWidget().widget(index) == self: # self.search_line.grabKeyboard() self.f5Pressed() # Re-read merchandise from db. else: # self.search_line.releaseKeyboard() pass def addClicked(self): """Called when the user presses the add-button""" # Set stack index: if self.stack.currentIndex() != 0: self.stack.setCurrentIndex(0) indexes = self.merchandise_list.selectedIndexes() if len(indexes) > 0: # Add items to order_page: mdl = self.merchandise_list.model() sel = [mdl.items[i.row()] for i in indexes] self.order_page.addItems(sel) self.activateSearchLine() def activateSearchLine(self): self.search_line.setFocus() self.search_line.selectAll() def removeClicked(self): """Called when the user presses the remove-button""" indexes = self.order_page.list_view.selectedIndexes() if len(indexes) > 0: # Remove items from order_page: sel = self.order_page.items(indexes) self.order_page.removeItems(sel) # Reset selection: self.order_page.list_view.selectionModel().select(indexes[0], QtGui.QItemSelectionModel.ClearAndSelect) def searchLineChanged(self, filter_str): self.merchandise_list.model().filter(filter_str) self._setSelected(self.merchandise_list, new_index=0) def leftPressed(self): self.merchandise_list.setFocus() def rightPressed(self): self.order_page.list_view.setFocus() def upPressed(self): if self.order_page.list_view.hasFocus(): self._setSelected(self.order_page.list_view, next=False) else: self.merchandise_list.setFocus() self._setSelected(self.merchandise_list, next=False) def downPressed(self): if self.order_page.list_view.hasFocus(): self._setSelected(self.order_page.list_view, next=True) else: self.merchandise_list.setFocus() self._setSelected(self.merchandise_list, next=True) def returnPressed(self): if self.order_page.list_view.hasFocus(): self.removeClicked() else: self.addClicked() def escapePressed(self): if len(self.order_page.items()) > 0: self.msg.post("Order canceled", self.msg.STYLE_CANCEL) self._reset() def f5Pressed(self): indexes = self.merchandise_list.selectedIndexes() self.merchandise_list.model().setAllData(self._getItems()) self.merchandise_list.model().filter(u"") filter_str = self.search_line.text() self.merchandise_list.model().filter(filter_str) # Reset selection: try: self.merchandise_list.selectionModel().select(indexes[0], QtGui.QItemSelectionModel.ClearAndSelect) except IndexError: pass def rfidEvent(self, rfid_str): # GUARD: tab has focus? if not self._tabHasFocus(): return # Get account: try: card = RFIDCard.objects.get(rfid_string=unicode(rfid_str)) account = card.account except RFIDCard.DoesNotExist: self.msg.post(u"RFID card not found", self.msg.STYLE_ERROR) account = None # Execute purchase: if account != None: items = self.order_page.items() if len(items) == 0: pass elif buy_merchandise(account, items): self._reset() color = account.COLOR_CHOICES[account.get_color()][1] self.msg.post(u"A successfull purchase mr. %s" % color, self.msg.STYLE_PURCHASE) else: color = account.COLOR_CHOICES[account.get_color()][1] self.msg.post(u"Transaction was dissalowed mr. %s" % color, self.msg.STYLE_ERROR) self.balance_page.showPage(account)