def setup_views(self): self.panelRooms = QHBoxLayout() self.schedule = QtSchedule(self) self.bpMonday = QLabel('--/--/----') self.bpSunday = QLabel('--/--/----') self.buttonPrev = QPushButton(self.tr('<<')) self.buttonNext = QPushButton(self.tr('>>')) self.buttonToday = QPushButton(self.tr('Today')) self.buttonPrev.setDisabled(True) self.buttonNext.setDisabled(True) self.buttonToday.setDisabled(True) # callback helper function def prev_week(): week_range = self.schedule.model().showPrevWeek() self.showWeekRange(week_range) def next_week(): week_range = self.schedule.model().showNextWeek() self.showWeekRange(week_range) def today(): week_range = self.schedule.model().showCurrWeek() self.showWeekRange(week_range) self.connect(self.buttonPrev, SIGNAL('clicked()'), prev_week) self.connect(self.buttonNext, SIGNAL('clicked()'), next_week) self.connect(self.buttonToday, SIGNAL('clicked()'), today) bottomPanel = QHBoxLayout() bottomPanel.addWidget(QLabel(self.tr('Week:'))) bottomPanel.addWidget(self.bpMonday) bottomPanel.addWidget(QLabel('-')) bottomPanel.addWidget(self.bpSunday) bottomPanel.addStretch(1) bottomPanel.addWidget(self.buttonPrev) bottomPanel.addWidget(self.buttonToday) bottomPanel.addWidget(self.buttonNext) mainLayout = QVBoxLayout() mainLayout.addLayout(self.panelRooms) mainLayout.addWidget(self.schedule) mainLayout.addLayout(bottomPanel) mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) self.printer_widget = QLabel('--', self.statusBar()) self.printer_widget.setToolTip(u'Initialization in progress') self.statusBar().addPermanentWidget(self.printer_widget)
def setup_views(self): self.panelRooms = QHBoxLayout() self.schedule = QtSchedule(self) self.bpMonday = QLabel("--/--/----") self.bpSunday = QLabel("--/--/----") self.buttonPrev = QPushButton(self.tr("<<")) self.buttonNext = QPushButton(self.tr(">>")) self.buttonToday = QPushButton(self.tr("Today")) self.buttonPrev.setDisabled(True) self.buttonNext.setDisabled(True) self.buttonToday.setDisabled(True) # callback helper function def prev_week(): week_range = self.schedule.model().showPrevWeek() self.showWeekRange(week_range) def next_week(): week_range = self.schedule.model().showNextWeek() self.showWeekRange(week_range) def today(): week_range = self.schedule.model().showCurrWeek() self.showWeekRange(week_range) self.connect(self.buttonPrev, SIGNAL("clicked()"), prev_week) self.connect(self.buttonNext, SIGNAL("clicked()"), next_week) self.connect(self.buttonToday, SIGNAL("clicked()"), today) bottomPanel = QHBoxLayout() bottomPanel.addWidget(QLabel(self.tr("Week:"))) bottomPanel.addWidget(self.bpMonday) bottomPanel.addWidget(QLabel("-")) bottomPanel.addWidget(self.bpSunday) bottomPanel.addStretch(1) bottomPanel.addWidget(self.buttonPrev) bottomPanel.addWidget(self.buttonToday) bottomPanel.addWidget(self.buttonNext) mainLayout = QVBoxLayout() mainLayout.addLayout(self.panelRooms) mainLayout.addWidget(self.schedule) mainLayout.addLayout(bottomPanel) mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) self.printer_widget = QLabel("--", self.statusBar()) self.printer_widget.setToolTip(u"Initialization in progress") self.statusBar().addPermanentWidget(self.printer_widget)
class MainWindow(QMainWindow): params = ParamStorage() # синглтон для хранения данных menu_actions = [] menu_desc = None def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowIcon(QIcon("/usr/share/pixmaps/advisor-client.xpm")) self.mimes = {"team": "application/x-team-item", "event": "application/x-calendar-event"} self.tree = [] self.rfid_id = None self.params.init_settings(obj=QSettings(), main_window=self) self.params.WEEK_DAYS = ( self.tr("Monday"), self.tr("Tuesday"), self.tr("Wednesday"), self.tr("Thursday"), self.tr("Friday"), self.tr("Saturday"), self.tr("Sunday"), ) self.params.logged_in = False self.params.work_hours = (8, 24) self.params.quant = timedelta(minutes=30) self.params.multiplier = timedelta(hours=1).seconds / self.params.quant.seconds self.menus = [] self.menu_desc = self.app_menu() self.create_menus(self.menu_desc) self.menu_state(MENU_LOGGED_OUT) self.setup_views() # если сервер не определён, показываем диалог настройки приложения settings = QSettings() settings.beginGroup("network") host = settings.value("addressHttpServer", QVariant("WrongHost")) settings.endGroup() self.webresource = WebResource() self.params.http = self.webresource.get(self) if "WrongHost" == host.toString(): self.app_settings() self.baseTitle = self.tr("Manager's interface") self.logoutTitle() self.statusBar().showMessage(self.tr("Ready"), 2000) self.resize(640, 480) def loggedTitle(self, response): last_name = response.get("last_name") first_name = response.get("first_name") if len(last_name) > 0 or len(first_name) > 0: self.setWindowTitle("%s : %s %s" % (self.baseTitle, last_name, first_name)) else: self.setWindowTitle("%s : %s" % (self.baseTitle, response.get("username"))) def logoutTitle(self): self.setWindowTitle("%s : %s" % (self.baseTitle, self.tr("Login to start session"))) def get_dynamic(self): self.bpMonday.setText(self.schedule.model().getMonday().strftime("%d/%m/%Y")) self.bpSunday.setText(self.schedule.model().getSunday().strftime("%d/%m/%Y")) def get_static(self): """ Метод для получения статической информации с сервера. """ if not self.params.http.request("/api/static/", "GET", {}): QMessageBox.critical( self, self.tr("Static info"), self.tr("Unable to fetch: %s") % self.params.http.error_msg ) return data = self.params.http.parse() if type(data) is dict and data.get("status") == 401: return None else: return data def update_interface(self): """ This method updates application's interface using static information obtained in previous method. """ # rooms rooms = self.params.static.get("rooms") if rooms: for item in rooms: uu_id = item.get("uuid") title = item.get("title") buttonFilter = QPushButton(title) buttonFilter.setCheckable(True) buttonFilter.setDisabled(True) self.panelRooms.addWidget(buttonFilter) self.connect(buttonFilter, SIGNAL("clicked()"), self.prepare_filter(uu_id, title)) def printer_init(self): self.params.printer = Printer(template=self.params.static.get("printer")) run_it = True def show_printer_status(): ok, tip = self.params.printer.get_status() self.printer_widget.setToolTip(tip) if ok: msg = self.tr("Printer is ready") else: msg = self.tr("Printer is not ready") self.printer_widget.setText(msg) self.printer_refresh = self.makeTimer(show_printer_status, self.params.printer.refresh_timeout, run_it) def prepare_filter(self, id, title): def handler(): self.statusBar().showMessage(self.tr('Filter: Room "%s" is changed its state') % title) return handler def setup_views(self): self.panelRooms = QHBoxLayout() self.schedule = QtSchedule(self) self.bpMonday = QLabel("--/--/----") self.bpSunday = QLabel("--/--/----") self.buttonPrev = QPushButton(self.tr("<<")) self.buttonNext = QPushButton(self.tr(">>")) self.buttonToday = QPushButton(self.tr("Today")) self.buttonPrev.setDisabled(True) self.buttonNext.setDisabled(True) self.buttonToday.setDisabled(True) # callback helper function def prev_week(): week_range = self.schedule.model().showPrevWeek() self.showWeekRange(week_range) def next_week(): week_range = self.schedule.model().showNextWeek() self.showWeekRange(week_range) def today(): week_range = self.schedule.model().showCurrWeek() self.showWeekRange(week_range) self.connect(self.buttonPrev, SIGNAL("clicked()"), prev_week) self.connect(self.buttonNext, SIGNAL("clicked()"), next_week) self.connect(self.buttonToday, SIGNAL("clicked()"), today) bottomPanel = QHBoxLayout() bottomPanel.addWidget(QLabel(self.tr("Week:"))) bottomPanel.addWidget(self.bpMonday) bottomPanel.addWidget(QLabel("-")) bottomPanel.addWidget(self.bpSunday) bottomPanel.addStretch(1) bottomPanel.addWidget(self.buttonPrev) bottomPanel.addWidget(self.buttonToday) bottomPanel.addWidget(self.buttonNext) mainLayout = QVBoxLayout() mainLayout.addLayout(self.panelRooms) mainLayout.addWidget(self.schedule) mainLayout.addLayout(bottomPanel) mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) self.printer_widget = QLabel("--", self.statusBar()) self.printer_widget.setToolTip(u"Initialization in progress") self.statusBar().addPermanentWidget(self.printer_widget) def showWeekRange(self, week_range): if self.schedule.model().getShowMode() == "week": monday, sunday = week_range self.bpMonday.setText(monday.strftime("%d/%m/%Y")) self.bpSunday.setText(sunday.strftime("%d/%m/%Y")) def getMime(self, name): return self.mimes.get(name, None) def app_menu(self): return [ ( self.tr("File"), [ (self.tr("Open"), "Ctrl+I", "open_session", self.tr("Open user session."), MENU_LOGGED_OUT), (self.tr("Close"), "", "close_session", self.tr("Close user session."), MENU_LOGGED_IN), None, ( self.tr("Settings"), "Ctrl+S", "app_settings", self.tr("Manage the application settings."), MENU_LOGGED_ANY, ), None, (self.tr("Exit"), "", "close", self.tr("Close the application."), MENU_LOGGED_ANY), ], ), ( self.tr("Client"), [ (self.tr("New"), "Ctrl+N", "client_new", self.tr("Register new client."), MENU_LOGGED_IN), ( self.tr("Search by RFID"), "Ctrl+D", "client_search_rfid", self.tr("Search a client with its RFID card."), MENU_LOGGED_IN | MENU_RFID, ), ( self.tr("Search by name"), "Ctrl+F", "client_search_name", self.tr("Search a client with its name."), MENU_LOGGED_IN, ), ], ), ( self.tr("Renter"), [ (self.tr("New"), "Ctrl+M", "renter_new", self.tr("Register new renter."), MENU_LOGGED_IN), ( self.tr("Search by name"), "Ctrl+G", "renter_search_name", self.tr("Search a renter with its name."), MENU_LOGGED_IN, ), ], ), ( self.tr("Help"), [(self.tr("About"), "", "help_about", self.tr("About application dialog."), MENU_LOGGED_ANY)], ), ] def create_menus(self, desc): """ Метод генерирует по переданному описанию меню приложения. Использование: Опишите меню со всеми его действиями, реализуйте обработчики для каждого элемента меню, передайте описание в данный метод. """ for topic, info in desc: action_handlers = [] menu = self.menuBar().addMenu(topic) for item in info: if item is None: menu.addSeparator() continue else: title, short, name, desc, state = item setattr(self, "act_%s" % name, QAction(title, self)) action = getattr(self, "act_%s" % name) action.setShortcut(short) action.setStatusTip(desc) self.connect(action, SIGNAL("triggered()"), getattr(self, name)) menu.addAction(action) self.menus.append(menu) action_handlers.append((action, state)) self.menu_actions.append(action_handlers) def menu_state(self, state): """ Метод для смены состояния меню. """ BITS = {"DISABLED": 0, "LOGGED_IN": 1, "LOGGED_OUT": 2, "RFID": 3, "PRINTER": 4} def is_bit_set(value, bitname): try: bitnum = BITS[bitname] except KeyError: return False else: return (state & (1 << bitnum)) != 0 for actions in self.menu_actions: for action, state in actions: if is_bit_set(state, "DISABLED"): action.setDisabled(True) continue if not self.params.logged_in: if is_bit_set(state, "LOGGED_OUT"): action.setDisabled(False) else: action.setDisabled(True) continue if self.params.logged_in: if is_bit_set(state, "LOGGED_IN"): disable = False if is_bit_set(state, "RFID"): # and RFID not present disable = True elif is_bit_set(state, "PRINTER"): # and PRINTER not present disable = True action.setDisabled(disable) else: action.setDisabled(True) continue def interface_disable(self, state): # Enable menu's action self.menu_state(state) # Enable the navigation buttons self.buttonPrev.setDisabled(not self.params.logged_in) self.buttonNext.setDisabled(not self.params.logged_in) self.buttonToday.setDisabled(not self.params.logged_in) def refresh_data(self): """ This method get the data from a server. It call periodically using timer. """ # Do nothing until user authoruized if not self.params.http.is_session_open(): return # Just refresh the calendar's model self.schedule.model().update # Menu handlers: The begin def open_session(self, **kwargs): connecting_to = u"%s %s" % ( self.params.http.hostport, self.params.http.use_ssl and self.tr("Secure") or self.tr("Unsecure"), ) self.dialog = DlgLogin(self, connecting_to=connecting_to) dlgStatus = self.dialog.exec_() dialog_title = self.tr("Open session") if not QDialog.Accepted == dlgStatus: QMessageBox.critical(self, dialog_title, self.dialog.error_msg) return status, data = self.dialog.response if status == "ALL_OK": self.params.logged_in = True self.loggedTitle(data) # подгружаем статическую информацию и список залов static = self.get_static() if not static: print "Check static!" return self.params.static = static rooms_by_index = {} rooms_by_uuid = {} for index, room in enumerate(self.params.static.get("rooms")): room_uuid = room.get("uuid") rooms_by_index[index] = room rooms_by_uuid[room_uuid] = index self.params.static["rooms_by_index"] = rooms_by_index self.params.static["rooms_by_uuid"] = rooms_by_uuid # здесь только правим текстовые метки self.get_dynamic() # изменяем свойства элементов интерфейса self.update_interface() # загружаем информацию о занятиях на расписание self.schedule.model().showCurrWeek() # # run refresh timer from settings import SCHEDULE_REFRESH_TIMEOUT self.refreshTimer = self.makeTimer(self.refresh_data, SCHEDULE_REFRESH_TIMEOUT, True) self.printer_init() self.interface_disable(MENU_LOGGED_IN | MENU_RFID | MENU_PRINTER) elif status == "NOT_IMPLEMENTED": QMessageBox.information(self, dialog_title, self.tr("Protocol is deprecated!")) elif status == "BAD_REQUEST": QMessageBox.warning(self, dialog_title, self.tr("It seems you've entered wrong login/password.")) else: QMessageBox.information(self, dialog_title, self.tr("Unknown error!")) def close_session(self): self.params.logged_in = False self.interface_disable(MENU_LOGGED_OUT) self.setWindowTitle("%s : %s" % (self.baseTitle, self.tr("Open user session"))) self.schedule.model().storage_init() # clear rooms layout layout = self.panelRooms while layout.count() > 0: item = layout.takeAt(0) if not item: continue w = item.widget() if w: w.deleteLater() def app_settings(self): self.dialog = DlgSettings(self) self.dialog.setModal(True) self.dialog.exec_() self.get_dynamic() self.params.http.disconnect() self.params.http = self.webresource.get(self) self.params.http.connect() def client_new(self, klass=ClientInfo): self.user_new(klass) def renter_new(self, klass=RenterInfo): self.user_new(klass) def client_search_name(self, klass=ClientInfo, mode="client"): self.user_search_name(klass, mode) def renter_search_name(self, klass=RenterInfo, mode="renter"): self.user_search_name(klass, mode) def client_search_rfid(self, klass=ClientInfo, mode="client"): self.user_search_rfid(klass, mode) def renter_search_rfid(self, klass=RenterInfo, mode="renter"): return self.user_search_rfid(klass, mode) def user_new(self, klass): self.dialog = klass(self) self.dialog.setModal(True) self.dialog.exec_() def user_search_rfid(self, klass, mode): """ Метод для поиска клиента по RFID. """ def callback(rfid): self.rfid_id = rfid if self.params.logged_in: dialog = WaitingRFID(self, mode=mode, callback=callback) dialog.setModal(True) if QDialog.Accepted == dialog.exec_() and self.rfid_id: h = self.params.http if not h.request("/api/%s/%s/" % (mode, self.rfid_id), "GET", force=True): QMessageBox.critical(self, self.tr("Client info"), self.tr("Unable to fetch: %s") % h.error_msg) return response = h.parse() if 0 == len(response): QMessageBox.warning(self, self.tr("Warning"), self.tr("This RFID belongs to nobody.")) else: self.dialog = klass(self) self.dialog.setModal(True) self.dialog.initData(response[0]) self.dialog.exec_() del (self.dialog) self.rfid_id = None def user_search_name(self, klass, mode): def callback(user): self.user = user if self.params.logged_in: self.dialog = Searching(self, mode=mode) self.dialog.setModal(True) self.dialog.setCallback(callback) if QDialog.Accepted == self.dialog.exec_(): self.dialog = klass(self) self.dialog.setModal(True) self.dialog.initData(self.user) self.dialog.exec_() del (self.dialog) def help_about(self): version = ".".join(map(str, self.params.version)) msg = ( """ <p>Клиентское приложение учётной системы.</p> <p>Версия %(version)s</p> <p>Сайт: <a href="http://snegiri.dontexist.org/projects/advisor/client/">Учётная система: Клиент</a>.</p> <p>Поддержка: <a href="mailto:[email protected]">Написать письмо</a>.</p> """ % locals() ) QMessageBox.about(self, self.tr("About application dialog"), msg.decode("utf-8")) def eventTraining(self): def callback(e_date, e_time, room_tuple, team): room, ok = room_tuple title, team_id, count, price, coach, duration = team begin = datetime.combine(e_date, e_time) duration = timedelta(minutes=int(duration * 60)) ajax = HttpAjax( self, "/manager/cal_event_add/", {"event_id": team_id, "room_id": room, "begin": begin, "ev_type": 0}, self.session_id, ) response = ajax.parse_json() event_info = { "id": int(response["saved_id"]), "title": title, "price": price, "count": count, "coach": coach, "duration": duration, "groups": self.tr("Waiting for update."), } eventObj = Event({}) # FIXME self.schedule.insertEvent(room, eventObj) self.dialog = DlgEventAssign("training", self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.setModel(self.tree) self.dialog.setRooms(self.rooms) self.dialog.exec_() def eventRent(self): def callback(e_date, e_time, e_duration, room_tuple, rent): room, ok = room_tuple rent_id = rent["id"] begin = datetime.combine(e_date, e_time) duration = timedelta(hours=e_duration.hour, minutes=e_duration.minute) params = { "event_id": rent_id, "room_id": room, "begin": begin, "ev_type": 1, "duration": float(duration.seconds) / 3600, } ajax = HttpAjax(self, "/manager/cal_event_add/", params, self.session_id) response = ajax.parse_json() id = int(response["saved_id"]) eventObj = Event({}) # FIXME self.schedule.insertEvent(room, eventObj) self.dialog = DlgEventAssign("rent", self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.setRooms(self.rooms) self.dialog.exec_() def addResources(self): def callback(count, price): # ajax = HttpAjax(self, '/manager/add_resource/', # {'from_date': from_range[0], # 'to_date': to_range[0]}, self.session_id) response = ajax.parse_json() self.statusBar().showMessage(self.tr("The week has been copied sucessfully.")) self.dialog = DlgAccounting(self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.exec_() # Menu handlers: The end def makeTimer(self, handler, timeout=0, run=False): timer = QTimer(self) timer.setInterval(timeout) self.connect(timer, SIGNAL("timeout()"), handler) if run: timer.start() return timer def showEventProperties(self, event, index): # , room_id): self.dialog = EventInfo(self) self.dialog.setModal(True) self.dialog.initData(event, index) self.dialog.exec_() # Drag'n'Drop section begins def mousePressEvent(self, event): if DEBUG_COMMON: print "press event", event.button() def mouseMoveEvent(self, event): if DEBUG_COMMON: print "move event", event.pos()
class MainWindow(QMainWindow): params = ParamStorage() # синглтон для хранения данных menu_actions = [] menu_desc = None def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.setWindowIcon(QIcon('/usr/share/pixmaps/advisor-client.xpm')) self.mimes = { 'team': 'application/x-team-item', 'event': 'application/x-calendar-event', } self.tree = [] self.rfid_id = None self.params.init_settings(obj=QSettings(), main_window=self) self.params.WEEK_DAYS = ( self.tr('Monday'), self.tr('Tuesday'), self.tr('Wednesday'), self.tr('Thursday'), self.tr('Friday'), self.tr('Saturday'), self.tr('Sunday'), ) self.params.logged_in = False self.params.work_hours = (8, 24) self.params.quant = timedelta(minutes=30) self.params.multiplier = timedelta( hours=1).seconds / self.params.quant.seconds self.menus = [] self.menu_desc = self.app_menu() self.create_menus(self.menu_desc) self.menu_state(MENU_LOGGED_OUT) self.setup_views() # если сервер не определён, показываем диалог настройки приложения settings = QSettings() settings.beginGroup('network') host = settings.value('addressHttpServer', QVariant('WrongHost')) settings.endGroup() self.webresource = WebResource() self.params.http = self.webresource.get(self) if 'WrongHost' == host.toString(): self.app_settings() self.baseTitle = self.tr('Manager\'s interface') self.logoutTitle() self.statusBar().showMessage(self.tr('Ready'), 2000) self.resize(640, 480) def loggedTitle(self, response): last_name = response.get('last_name') first_name = response.get('first_name') if len(last_name) > 0 or len(first_name) > 0: self.setWindowTitle('%s : %s %s' % (self.baseTitle, last_name, first_name)) else: self.setWindowTitle('%s : %s' % (self.baseTitle, response.get('username'))) def logoutTitle(self): self.setWindowTitle( '%s : %s' % (self.baseTitle, self.tr('Login to start session'))) def get_dynamic(self): self.bpMonday.setText( self.schedule.model().getMonday().strftime('%d/%m/%Y')) self.bpSunday.setText( self.schedule.model().getSunday().strftime('%d/%m/%Y')) def get_static(self): """ Метод для получения статической информации с сервера. """ if not self.params.http.request('/api/static/', 'GET', {}): QMessageBox.critical( self, self.tr('Static info'), self.tr('Unable to fetch: %s') % self.params.http.error_msg) return data = self.params.http.parse() if type(data) is dict and data.get('status') == 401: return None else: return data def update_interface(self): """ This method updates application's interface using static information obtained in previous method. """ # rooms rooms = self.params.static.get('rooms') if rooms: for item in rooms: uu_id = item.get('uuid') title = item.get('title') buttonFilter = QPushButton(title) buttonFilter.setCheckable(True) buttonFilter.setDisabled(True) self.panelRooms.addWidget(buttonFilter) self.connect(buttonFilter, SIGNAL('clicked()'), self.prepare_filter(uu_id, title)) def printer_init(self): self.params.printer = Printer( template=self.params.static.get('printer')) run_it = True def show_printer_status(): ok, tip = self.params.printer.get_status() self.printer_widget.setToolTip(tip) if ok: msg = self.tr('Printer is ready') else: msg = self.tr('Printer is not ready') self.printer_widget.setText(msg) self.printer_refresh = self.makeTimer( show_printer_status, self.params.printer.refresh_timeout, run_it) def prepare_filter(self, id, title): def handler(): self.statusBar().showMessage( self.tr('Filter: Room "%s" is changed its state') % title) return handler def setup_views(self): self.panelRooms = QHBoxLayout() self.schedule = QtSchedule(self) self.bpMonday = QLabel('--/--/----') self.bpSunday = QLabel('--/--/----') self.buttonPrev = QPushButton(self.tr('<<')) self.buttonNext = QPushButton(self.tr('>>')) self.buttonToday = QPushButton(self.tr('Today')) self.buttonPrev.setDisabled(True) self.buttonNext.setDisabled(True) self.buttonToday.setDisabled(True) # callback helper function def prev_week(): week_range = self.schedule.model().showPrevWeek() self.showWeekRange(week_range) def next_week(): week_range = self.schedule.model().showNextWeek() self.showWeekRange(week_range) def today(): week_range = self.schedule.model().showCurrWeek() self.showWeekRange(week_range) self.connect(self.buttonPrev, SIGNAL('clicked()'), prev_week) self.connect(self.buttonNext, SIGNAL('clicked()'), next_week) self.connect(self.buttonToday, SIGNAL('clicked()'), today) bottomPanel = QHBoxLayout() bottomPanel.addWidget(QLabel(self.tr('Week:'))) bottomPanel.addWidget(self.bpMonday) bottomPanel.addWidget(QLabel('-')) bottomPanel.addWidget(self.bpSunday) bottomPanel.addStretch(1) bottomPanel.addWidget(self.buttonPrev) bottomPanel.addWidget(self.buttonToday) bottomPanel.addWidget(self.buttonNext) mainLayout = QVBoxLayout() mainLayout.addLayout(self.panelRooms) mainLayout.addWidget(self.schedule) mainLayout.addLayout(bottomPanel) mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) self.printer_widget = QLabel('--', self.statusBar()) self.printer_widget.setToolTip(u'Initialization in progress') self.statusBar().addPermanentWidget(self.printer_widget) def showWeekRange(self, week_range): if self.schedule.model().getShowMode() == 'week': monday, sunday = week_range self.bpMonday.setText(monday.strftime('%d/%m/%Y')) self.bpSunday.setText(sunday.strftime('%d/%m/%Y')) def getMime(self, name): return self.mimes.get(name, None) def app_menu(self): return [ (self.tr('File'), [ (self.tr('Open'), 'Ctrl+I', 'open_session', self.tr('Open user session.'), MENU_LOGGED_OUT), (self.tr('Close'), '', 'close_session', self.tr('Close user session.'), MENU_LOGGED_IN), None, (self.tr('Settings'), 'Ctrl+S', 'app_settings', self.tr('Manage the application settings.'), MENU_LOGGED_ANY), None, (self.tr('Exit'), '', 'close', self.tr('Close the application.'), MENU_LOGGED_ANY), ]), (self.tr('Client'), [ (self.tr('New'), 'Ctrl+N', 'client_new', self.tr('Register new client.'), MENU_LOGGED_IN), (self.tr('Search by RFID'), 'Ctrl+D', 'client_search_rfid', self.tr('Search a client with its RFID card.'), MENU_LOGGED_IN | MENU_RFID), (self.tr('Search by name'), 'Ctrl+F', 'client_search_name', self.tr('Search a client with its name.'), MENU_LOGGED_IN), ]), (self.tr('Renter'), [ (self.tr('New'), 'Ctrl+M', 'renter_new', self.tr('Register new renter.'), MENU_LOGGED_IN), (self.tr('Search by name'), 'Ctrl+G', 'renter_search_name', self.tr('Search a renter with its name.'), MENU_LOGGED_IN), ]), (self.tr('Help'), [ (self.tr('About'), '', 'help_about', self.tr('About application dialog.'), MENU_LOGGED_ANY), ]), ] def create_menus(self, desc): """ Метод генерирует по переданному описанию меню приложения. Использование: Опишите меню со всеми его действиями, реализуйте обработчики для каждого элемента меню, передайте описание в данный метод. """ for topic, info in desc: action_handlers = [] menu = self.menuBar().addMenu(topic) for item in info: if item is None: menu.addSeparator() continue else: title, short, name, desc, state = item setattr(self, 'act_%s' % name, QAction(title, self)) action = getattr(self, 'act_%s' % name) action.setShortcut(short) action.setStatusTip(desc) self.connect(action, SIGNAL('triggered()'), getattr(self, name)) menu.addAction(action) self.menus.append(menu) action_handlers.append(( action, state, )) self.menu_actions.append(action_handlers) def menu_state(self, state): """ Метод для смены состояния меню. """ BITS = { 'DISABLED': 0, 'LOGGED_IN': 1, 'LOGGED_OUT': 2, 'RFID': 3, 'PRINTER': 4, } def is_bit_set(value, bitname): try: bitnum = BITS[bitname] except KeyError: return False else: return (state & (1 << bitnum)) != 0 for actions in self.menu_actions: for action, state in actions: if is_bit_set(state, 'DISABLED'): action.setDisabled(True) continue if not self.params.logged_in: if is_bit_set(state, 'LOGGED_OUT'): action.setDisabled(False) else: action.setDisabled(True) continue if self.params.logged_in: if is_bit_set(state, 'LOGGED_IN'): disable = False if is_bit_set(state, 'RFID'): # and RFID not present disable = True elif is_bit_set(state, 'PRINTER'): # and PRINTER not present disable = True action.setDisabled(disable) else: action.setDisabled(True) continue def interface_disable(self, state): # Enable menu's action self.menu_state(state) # Enable the navigation buttons self.buttonPrev.setDisabled(not self.params.logged_in) self.buttonNext.setDisabled(not self.params.logged_in) self.buttonToday.setDisabled(not self.params.logged_in) def refresh_data(self): """ This method get the data from a server. It call periodically using timer. """ # Do nothing until user authoruized if not self.params.http.is_session_open(): return # Just refresh the calendar's model self.schedule.model().update # Menu handlers: The begin def open_session(self, **kwargs): connecting_to = u'%s %s' % ( self.params.http.hostport, self.params.http.use_ssl and self.tr('Secure') or self.tr('Unsecure'), ) self.dialog = DlgLogin(self, connecting_to=connecting_to) dlgStatus = self.dialog.exec_() dialog_title = self.tr('Open session') if not QDialog.Accepted == dlgStatus: QMessageBox.critical(self, dialog_title, self.dialog.error_msg) return status, data = self.dialog.response if status == 'ALL_OK': self.params.logged_in = True self.loggedTitle(data) # подгружаем статическую информацию и список залов static = self.get_static() if not static: print 'Check static!' return self.params.static = static rooms_by_index = {} rooms_by_uuid = {} for index, room in enumerate(self.params.static.get('rooms')): room_uuid = room.get('uuid') rooms_by_index[index] = room rooms_by_uuid[room_uuid] = index self.params.static['rooms_by_index'] = rooms_by_index self.params.static['rooms_by_uuid'] = rooms_by_uuid # здесь только правим текстовые метки self.get_dynamic() # изменяем свойства элементов интерфейса self.update_interface() # загружаем информацию о занятиях на расписание self.schedule.model().showCurrWeek() # # run refresh timer from settings import SCHEDULE_REFRESH_TIMEOUT self.refreshTimer = self.makeTimer(self.refresh_data, SCHEDULE_REFRESH_TIMEOUT, True) self.printer_init() self.interface_disable(MENU_LOGGED_IN | MENU_RFID | MENU_PRINTER) elif status == 'NOT_IMPLEMENTED': QMessageBox.information(self, dialog_title, self.tr('Protocol is deprecated!')) elif status == 'BAD_REQUEST': QMessageBox.warning( self, dialog_title, self.tr('It seems you\'ve entered wrong login/password.')) else: QMessageBox.information(self, dialog_title, self.tr('Unknown error!')) def close_session(self): self.params.logged_in = False self.interface_disable(MENU_LOGGED_OUT) self.setWindowTitle('%s : %s' % (self.baseTitle, self.tr('Open user session'))) self.schedule.model().storage_init() # clear rooms layout layout = self.panelRooms while layout.count() > 0: item = layout.takeAt(0) if not item: continue w = item.widget() if w: w.deleteLater() def app_settings(self): self.dialog = DlgSettings(self) self.dialog.setModal(True) self.dialog.exec_() self.get_dynamic() self.params.http.disconnect() self.params.http = self.webresource.get(self) self.params.http.connect() def client_new(self, klass=ClientInfo): self.user_new(klass) def renter_new(self, klass=RenterInfo): self.user_new(klass) def client_search_name(self, klass=ClientInfo, mode='client'): self.user_search_name(klass, mode) def renter_search_name(self, klass=RenterInfo, mode='renter'): self.user_search_name(klass, mode) def client_search_rfid(self, klass=ClientInfo, mode='client'): self.user_search_rfid(klass, mode) def renter_search_rfid(self, klass=RenterInfo, mode='renter'): return self.user_search_rfid(klass, mode) def user_new(self, klass): self.dialog = klass(self) self.dialog.setModal(True) self.dialog.exec_() def user_search_rfid(self, klass, mode): """ Метод для поиска клиента по RFID. """ def callback(rfid): self.rfid_id = rfid if self.params.logged_in: dialog = WaitingRFID(self, mode=mode, callback=callback) dialog.setModal(True) if QDialog.Accepted == dialog.exec_() and self.rfid_id: h = self.params.http if not h.request( '/api/%s/%s/' % (mode, self.rfid_id), 'GET', force=True): QMessageBox.critical( self, self.tr('Client info'), self.tr('Unable to fetch: %s') % h.error_msg) return response = h.parse() if 0 == len(response): QMessageBox.warning( self, self.tr('Warning'), self.tr('This RFID belongs to nobody.')) else: self.dialog = klass(self) self.dialog.setModal(True) self.dialog.initData(response[0]) self.dialog.exec_() del (self.dialog) self.rfid_id = None def user_search_name(self, klass, mode): def callback(user): self.user = user if self.params.logged_in: self.dialog = Searching(self, mode=mode) self.dialog.setModal(True) self.dialog.setCallback(callback) if QDialog.Accepted == self.dialog.exec_(): self.dialog = klass(self) self.dialog.setModal(True) self.dialog.initData(self.user) self.dialog.exec_() del (self.dialog) def help_about(self): version = '.'.join(map(str, self.params.version)) msg = """ <p>Клиентское приложение учётной системы.</p> <p>Версия %(version)s</p> <p>Сайт: <a href="http://snegiri.dontexist.org/projects/advisor/client/">Учётная система: Клиент</a>.</p> <p>Поддержка: <a href="mailto:[email protected]">Написать письмо</a>.</p> """ % locals() QMessageBox.about(self, self.tr('About application dialog'), msg.decode('utf-8')) def eventTraining(self): def callback(e_date, e_time, room_tuple, team): room, ok = room_tuple title, team_id, count, price, coach, duration = team begin = datetime.combine(e_date, e_time) duration = timedelta(minutes=int(duration * 60)) ajax = HttpAjax(self, '/manager/cal_event_add/', { 'event_id': team_id, 'room_id': room, 'begin': begin, 'ev_type': 0 }, self.session_id) response = ajax.parse_json() event_info = { 'id': int(response['saved_id']), 'title': title, 'price': price, 'count': count, 'coach': coach, 'duration': duration, 'groups': self.tr('Waiting for update.') } eventObj = Event({}) # FIXME self.schedule.insertEvent(room, eventObj) self.dialog = DlgEventAssign('training', self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.setModel(self.tree) self.dialog.setRooms(self.rooms) self.dialog.exec_() def eventRent(self): def callback(e_date, e_time, e_duration, room_tuple, rent): room, ok = room_tuple rent_id = rent['id'] begin = datetime.combine(e_date, e_time) duration = timedelta(hours=e_duration.hour, minutes=e_duration.minute) params = { 'event_id': rent_id, 'room_id': room, 'begin': begin, 'ev_type': 1, 'duration': float(duration.seconds) / 3600 } ajax = HttpAjax(self, '/manager/cal_event_add/', params, self.session_id) response = ajax.parse_json() id = int(response['saved_id']) eventObj = Event({}) # FIXME self.schedule.insertEvent(room, eventObj) self.dialog = DlgEventAssign('rent', self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.setRooms(self.rooms) self.dialog.exec_() def addResources(self): def callback(count, price): # ajax = HttpAjax(self, '/manager/add_resource/', # {'from_date': from_range[0], # 'to_date': to_range[0]}, self.session_id) response = ajax.parse_json() self.statusBar().showMessage( self.tr('The week has been copied sucessfully.')) self.dialog = DlgAccounting(self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.exec_() # Menu handlers: The end def makeTimer(self, handler, timeout=0, run=False): timer = QTimer(self) timer.setInterval(timeout) self.connect(timer, SIGNAL('timeout()'), handler) if run: timer.start() return timer def showEventProperties(self, event, index): #, room_id): self.dialog = EventInfo(self) self.dialog.setModal(True) self.dialog.initData(event, index) self.dialog.exec_() # Drag'n'Drop section begins def mousePressEvent(self, event): if DEBUG_COMMON: print 'press event', event.button() def mouseMoveEvent(self, event): if DEBUG_COMMON: print 'move event', event.pos()
class MainWindow(QMainWindow): ''' Describes main window of a client application. ''' def __init__(self, parent=None): QMainWindow.__init__(self, parent) self.mimes = {'team': 'application/x-team-item', 'event': 'application/x-calendar-event', } self.rooms = [] self.tree = [] self.rfid_id = None self.http = Http(self) self.work_hours = (8, 24) self.schedule_quant = timedelta(minutes=30) self.menus = [] self.create_menus() self.setup_views() settings = QSettings() settings.beginGroup('network') host = settings.value('addressHttpServer', QVariant('WrongHost')) settings.endGroup() if 'WrongHost' == host.toString(): self.setupApp() self.baseTitle = _('Manager\'s interface') self.logoutTitle() self.statusBar().showMessage(_('Ready'), 2000) self.resize(640, 480) def loggedTitle(self, name): ''' Appends name of a manager to basic title of main window. Indended to be called after successful L{log in<???>}. @type name: string @param name: Name of a manager, that have logged in. ''' self.setWindowTitle('%s : %s' % (self.baseTitle, name)) def logoutTitle(self): ''' Appends 'Log in to start session' to basic title of main window. Indended to be used on L{logout<>} and when application L{starts<__init__>}. ''' self.setWindowTitle('%s : %s' % (self.baseTitle, _('Login to start session'))) def get_dynamic(self): ''' Updates L{labels<create_views>} bpMonday and bpSunday, that show date of beginning and end of the week, that is currently displayed by L{QtSchedule} widget. ''' self.bpMonday.setText(self.schedule.model().getMonday().strftime('%d/%m/%Y')) self.bpSunday.setText(self.schedule.model().getSunday().strftime('%d/%m/%Y')) def get_static(self): """ Gets static information from server. First, all present rooms are L{retrieved<Http.request>}. They are returned as a dict in the following format:: {'rows': [{'color': 'FFAAAA', 'text': 'red', 'id': 1}, {'color': 'AAFFAA', 'text': 'green', 'id': 2}, ...]} Then, other static info is retrieved??? """ # get rooms if not self.http.request('/manager/get_rooms/', {}): QMessageBox.critical(self, _('Room info'), _('Unable to fetch: %s') % self.http.error_msg) return default_response = {'rows': []} response = self.http.parse(default_response) self.rooms = tuple( [ (a['title'], a['color'], a['id']) for a in response['rows'] ] ) self.schedule.update_static( {'rooms': self.rooms} ) # static info if not self.http.request('/manager/static/', {}): QMessageBox.critical(self, _('Static info'), _('Unable to fetch: %s') % self.http.error_msg) return response = self.http.parse() self.static = response print 'Static is', self.static.keys() #import pprint; pprint.pprint(self.static) #self.tree = TreeModel(self.static.get('styles', None)) def update_interface(self): """ This method updates application's interface using static information obtained in previous method. """ # rooms if self.rooms and len(self.rooms) > 0: for title, color, id in self.rooms: buttonFilter = QPushButton(title) buttonFilter.setCheckable(True) buttonFilter.setDisabled(True) # BUG #28 self.panelRooms.addWidget(buttonFilter) self.connect(buttonFilter, SIGNAL('clicked()'), self.prepare_filter(id, title)) def prepare_filter(self, id, title): def handler(): self.statusBar().showMessage(_('Filter: Room "%s" is changed its state') % title) return handler def setup_views(self): ''' This method sets up layout of main window, except for dropdown menus. At the center of the window there is a custon L{QtSchedule} widget, which shows timetable of some week or of particular day. Under it there are widgets for navigation: two labels bpMonday and bpSunday display information on what date range is displayed in schedule widget, and buttons buttonPrev, buttonNext and buttonToday are used to tell schedule to show previous week, next week and current week respectively. ''' self.panelRooms = QHBoxLayout() schedule_params = { 'http': self.http, 'work_hours': self.work_hours, 'quant': self.schedule_quant, 'rooms': self.rooms, } self.schedule = QtSchedule(self, schedule_params) self.bpMonday = QLabel('--/--/----') self.bpSunday = QLabel('--/--/----') self.buttonPrev = QPushButton(_('<<')) self.buttonNext = QPushButton(_('>>')) self.buttonToday = QPushButton(_('Today')) self.buttonPrev.setDisabled(True) self.buttonNext.setDisabled(True) self.buttonToday.setDisabled(True) # callback helper function def prev_week(): week_range = self.schedule.model().showPrevWeek() self.showWeekRange(week_range) def next_week(): week_range = self.schedule.model().showNextWeek() self.showWeekRange(week_range) def today(): week_range = self.schedule.model().showCurrWeek() self.showWeekRange(week_range) self.connect(self.buttonPrev, SIGNAL('clicked()'), prev_week) self.connect(self.buttonNext, SIGNAL('clicked()'), next_week) self.connect(self.buttonToday, SIGNAL('clicked()'), today) bottomPanel = QHBoxLayout() bottomPanel.addWidget(QLabel(_('Week:'))) bottomPanel.addWidget(self.bpMonday) bottomPanel.addWidget(QLabel('-')) bottomPanel.addWidget(self.bpSunday) bottomPanel.addStretch(1) bottomPanel.addWidget(self.buttonPrev) bottomPanel.addWidget(self.buttonToday) bottomPanel.addWidget(self.buttonNext) mainLayout = QVBoxLayout() mainLayout.addLayout(self.panelRooms) mainLayout.addWidget(self.schedule) mainLayout.addLayout(bottomPanel) mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget) def showWeekRange(self, week_range): if self.schedule.model().getShowMode() == 'week': monday, sunday = week_range self.bpMonday.setText(monday.strftime('%d/%m/%Y')) self.bpSunday.setText(sunday.strftime('%d/%m/%Y')) def getMime(self, name): return self.mimes.get(name, None) def create_menus(self): """ This method generates the application dropdown menu. Menu items are specified in 'data' variable inside the method. Format is as follows: - data is list of tuples of form (menu_title, list_of_submenus), where menu_name is the name of a given menu (e.g. 'File') and list_of_submenus contains menu items, that drop down, when you click on menu_name. - submenu items are tuples (title, shortcut, handler function, comment) Current menu structure is as follows: - File. - L{Log in<login>}. - L{Log out<logout>}. - L{Application settings<setupApp>}. - Exit. - Client. - L{New<client_new>}. - L{Search by RFID<client_search_rfid>}. - L{Search by name<client_search_name>}. - Renter. - L{New<renterNew>}. - L{Search by name<renterSearchName>}. - Calendar. - L{Fill week<fillWeek>}. @important: Style of naming of functions is mixed!!! """ data = [ (_('File'), [ (_('Log in'), 'Ctrl+I', 'login', _('Start user session.')), (_('Log out'), '', 'logout', _('End user session.')), None, (_('Application settings'), 'Ctrl+G', 'setupApp', _('Manage the application settings.')), None, (_('Exit'), '', 'close', _('Close the application.')), ] ), (_('Client'), [ (_('New'), 'Ctrl+N', 'client_new', _('Register new client.')), (_('Search by RFID'), 'Ctrl+D', 'client_search_rfid', _('Search a client with its RFID card.')), (_('Search by name'), 'Ctrl+F', 'client_search_name', _('Search a client with its name.')), ] ), (_('Renter'), [ (_('New'), '', 'renterNew', _('Register new renter.')), (_('Search by name'), '', 'renterSearchName', _('Search a renter with its name.')), ] ), # (_('Event'), [ # (_('Training'), 'Ctrl+T', # 'eventTraining', _('Assign a training event.')), # (_('Rent'), 'Ctrl+R', # 'eventRent', _('Assign a rent event.')), # ] # ), (_('Calendar'), [ (_('Fill week'), 'Ctrl+L', 'fillWeek', _('Fill current week.')), # (_('Copy week'), 'Ctrl+W', # 'copyWeek', _('Copy current week into other.')), ] ), # (_('Accounting'), [ # (_('Add resources'), '', # 'addResources', _('Add new set of resources into accounting.')), # ] # ), ] for topic, info in data: menu = self.menuBar().addMenu(topic) # Disable the following menu actions, until user will be authorized. if topic != _('File'): menu.setDisabled(True) for item in info: if item is None: menu.addSeparator() continue title, short, name, desc = item setattr(self, 'act_%s' % name, QAction(title, self)) action = getattr(self, 'act_%s' % name) action.setShortcut(short) action.setStatusTip(desc) self.connect(action, SIGNAL('triggered()'), getattr(self, name)) menu.addAction(action) self.menus.append(menu) def interface_disable(self, state): # True = disabled, False = enabled ''' This method is to be invoked on L{log out<logout>} or when the application L{starts<__init__>}. It disables schedule navigation buttons and L{all dropdown menus except File<create_menus>}. ''' # Enable menu's action for menu in self.menus: if menu.title() != _('File'): menu.setDisabled(state) # Enable the navigation buttons self.buttonPrev.setDisabled(state) self.buttonNext.setDisabled(state) self.buttonToday.setDisabled(state) def refresh_data(self): """ This method gets current timetable from the server using L{update<QtSchedule.update>} method of L{QtSchedule} widget. It is called periodically using timer. Interaction with server only occurs if manager is logged in. """ # Do nothing until user authoruized if not self.http.is_session_open(): return # Just refresh the calendar's model self.schedule.model().update # Menu handlers: The begin def login(self): ''' Shows log in dialog, where manager is asked to provide login/password pair. If 'Ok' button is clicked, authentication L{request<Http.request>} is made to the server, which is then L{parsed<Http.parse>}. On success: - information about schedule is retrieved from the server and and L{QtSchedule} widget is L{updated<update_interface>}. - controls are L{activated<interface_disable>}. - window title is L{updated<loggedTitle>} - schedule information is being L{refreshed<refresh_data>} from now on. In case of failure to authenticate a message is displayed. ''' def callback(credentials): self.credentials = credentials self.dialog = DlgLogin(self) self.dialog.setCallback(callback) self.dialog.setModal(True) dlgStatus = self.dialog.exec_() if QDialog.Accepted == dlgStatus: if not self.http.request('/manager/login/', self.credentials): QMessageBox.critical(self, _('Login'), _('Unable to login: %s') % self.http.error_msg) return default_response = None response = self.http.parse(default_response) if response and 'user_info' in response: self.loggedTitle(response['user_info']) # update application's interface self.get_static() self.get_dynamic() self.update_interface() self.schedule.model().showCurrWeek() # run refresh timer self.refreshTimer = QTimer(self) from settings import SCHEDULE_REFRESH_TIMEOUT self.refreshTimer.setInterval(SCHEDULE_REFRESH_TIMEOUT) self.connect(self.refreshTimer, SIGNAL('timeout()'), self.refresh_data) self.refreshTimer.start() self.interface_disable(False) else: QMessageBox.warning(self, _('Login failed'), _('It seems you\'ve entered wrong login/password.')) def logout(self): ''' Performs sequence of clean up actions when manager logs out: - L{disables controls<interface_disable>}; - Deletes information about schedule and rooms, that are present. ''' self.interface_disable(True) self.setWindowTitle('%s : %s' % (self.baseTitle, _('Login to start session'))) self.schedule.model().storage_init() # clear rooms layout layout = self.panelRooms while layout.count() > 0: item = layout.takeAt(0) if not item: continue w = item.widget() if w: w.deleteLater() def setupApp(self): ''' Displays dialog with settings for client application. After that date range, that is being displayed is refreshed and L{reconnect<Http.reconnect>} to server is performed (just in case network settings) had been altered. ''' self.dialog = DlgSettings(self) self.dialog.setModal(True) self.dialog.exec_() self.get_dynamic() self.http.reconnect() def client_new(self): ''' Opens empty client information L{dialog<ClientInfo>} for adding new client to the database. Class for L{accessing server<Http>} and static information (???) are passed as parameters. ''' params = { 'http': self.http, 'static': self.static, } self.dialog = ClientInfo(self, params) self.dialog.setModal(True) self.dialog.exec_() def client_search_rfid(self): ''' Search client in the database by RFID (Radio Frequency IDentificator). After RFID was successfully read from card, server is L{requested<Http.request>} client info. If user is found in database, L{dialog<ClientInfo>} with information about client is displayed. Otherwise, messageboxes with warnings are displayed. ''' if not self.http or not self.http.is_session_open(): return # login first def callback(rfid): self.rfid_id = rfid params = { 'http': self.http, 'static': self.static, 'mode': 'client', 'callback': callback, } dialog = WaitingRFID(self, params) dialog.setModal(True) dlgStatus = dialog.exec_() if QDialog.Accepted == dlgStatus and self.rfid_id is not None: params = {'rfid_code': self.rfid_id, 'mode': 'client'} if not self.http.request('/manager/get_client_info/', params): QMessageBox.critical(self, _('Client info'), _('Unable to fetch: %s') % self.http.error_msg) return default_response = None response = self.http.parse(default_response) if not response or response['info'] is None: QMessageBox.warning(self, _('Warning'), _('This RFID belongs to nobody.')) else: user_info = response['info'] params = { 'http': self.http, 'static': self.static, } self.dialog = ClientInfo(self, params) self.dialog.setModal(True) self.dialog.initData(user_info) self.dialog.exec_() self.rfid_id = None def client_search_name(self): ''' Search client in the database by name. First it launches client search L{dialog<Searching>}, which tries to fetch unique user_id from the server based on information provided. If that succeeds, user_id-based search then Works analogously to L{RFID-based<client_search_rfid>} search. ''' if not self.http or not self.http.is_session_open(): return # login first def callback(user_id): self.user_id = user_id params = { 'http': self.http, 'static': self.static, 'mode': 'client', 'apply_title': _('Show'), } self.dialog = Searching(self, params) self.dialog.setModal(True) self.dialog.setCallback(callback) dlgStatus = self.dialog.exec_() if QDialog.Accepted == dlgStatus: if not self.http.request('/manager/get_client_info/', {'user_id': self.user_id, 'mode': 'client'}): QMessageBox.critical(self, _('Client info'), _('Unable to fetch: %s') % self.http.error_msg) return default_response = None response = self.http.parse(default_response) if not response or response['info'] is None: QMessageBox.warning(self, _('Warning'), _('This RFID belongs to nobody.')) else: params = { 'http': self.http, 'static': self.static, } self.dialog = ClientInfo(self, params) self.dialog.setModal(True) self.dialog.initData(response['info']) self.dialog.exec_() def renterNew(self): ''' Adding new renter. ''' self.dialog = DlgRenterInfo(self) self.dialog.setModal(True) self.dialog.exec_() def renterSearchName(self): ''' Search renter by his name. @important: by some strange reason, HttpAjax class is used instead of Http to fetch information from the server. ''' def callback(id): self.user_id = id params = { 'http': self.http, 'static': self.static, 'mode': 'client', } self.dialog = Searching(self, params) self.dialog.setModal(True) self.dialog.setCallback(callback) dlgStatus = self.dialog.exec_() if QDialog.Accepted == dlgStatus: ajax = HttpAjax(self, '/manager/get_renter_info/', {'user_id': self.user_id, 'mode': 'renter'}, self.session_id) response = ajax.parse_json() self.dialog = DlgRenterInfo(self) self.dialog.setModal(True) self.dialog.initData(response['info']) self.dialog.exec_() def eventTraining(self): def callback(e_date, e_time, room_tuple, team): room, ok = room_tuple title, team_id, count, price, coach, duration = team begin = datetime.combine(e_date, e_time) duration = timedelta(minutes=int(duration * 60)) ajax = HttpAjax(self, '/manager/cal_event_add/', {'event_id': team_id, 'room_id': room, 'begin': begin, 'ev_type': 0}, self.session_id) response = ajax.parse_json() id = int(response['saved_id']) event_info = {'id': id, 'title': title, 'price': price, 'count': count, 'coach': coach, 'duration': duration, 'groups': _('Waiting for update.')} eventObj = Event({}) # FIXME self.schedule.insertEvent(room, eventObj) self.dialog = DlgEventAssign('training', self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.setModel(self.tree) self.dialog.setRooms(self.rooms) self.dialog.exec_() def eventRent(self): def callback(e_date, e_time, e_duration, room_tuple, rent): room, ok = room_tuple rent_id = rent['id'] begin = datetime.combine(e_date, e_time) duration = timedelta(hours=e_duration.hour, minutes=e_duration.minute) params = { 'event_id': rent_id, 'room_id': room, 'begin': begin, 'ev_type': 1, 'duration': float(duration.seconds) / 3600 } ajax = HttpAjax(self, '/manager/cal_event_add/', params, self.session_id) response = ajax.parse_json() id = int(response['saved_id']) eventObj = Event({}) # FIXME self.schedule.insertEvent(room, eventObj) self.dialog = DlgEventAssign('rent', self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.setRooms(self.rooms) self.dialog.exec_() def fillWeek(self): def callback(selected_date): model = self.schedule.model() from_range = model.weekRange to_range = model.date2range(selected_date) if not self.http.request('/manager/fill_week/', {'to_date': to_range[0]}): QMessageBox.critical(self, _('Fill week'), _('Unable to fill: %s') % self.http.error_msg) return default_response = None response = self.http.parse(default_response) if response and 'saved_id' in response: # inform user info = response['saved_id'] msg = _('The week has been filled sucessfully. Copied: %(copied)i. Passed: %(passed)i.') self.statusBar().showMessage(msg % info, 3000) # FIXME: pause here, but not just sleep, use timer # update view self.schedule.model().update() self.dialog = DlgCopyWeek(self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.exec_() def copyWeek(self): def callback(selected_date): model = self.scheduleModel from_range = model.weekRange to_range = model.date2range(selected_date) ajax = HttpAjax(self, '/manager/copy_week/', {'from_date': from_range[0], 'to_date': to_range[0]}, self.session_id) response = ajax.parse_json() self.statusBar().showMessage(_('The week has been copied sucessfully.')) self.dialog = DlgCopyWeek(self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.exec_() def addResources(self): def callback(count, price): # ajax = HttpAjax(self, '/manager/add_resource/', # {'from_date': from_range[0], # 'to_date': to_range[0]}, self.session_id) response = ajax.parse_json() self.statusBar().showMessage(_('The week has been copied sucessfully.')) self.dialog = DlgAccounting(self) self.dialog.setModal(True) self.dialog.setCallback(callback) self.dialog.exec_() # Menu handlers: The end #def getUserInfo(self, rfid): # """ This method get user's information by its card's identifier. """ # ajax = HttpAjax(self, '/manager/get_client_info/', # {'rfid_code': rfid, mode='client'}) # json_like = ajax.parse_json() # print 'USER INFO:', json_like # return json_like def showEventProperties(self, calendar_event, index): #, room_id): self.dialog = EventInfo(self, {'http': self.http}) self.dialog.setModal(True) self.dialog.initData(calendar_event, index) self.dialog.exec_() # Drag'n'Drop section begins def mousePressEvent(self, event): if DEBUG: print 'press event', event.button() def mouseMoveEvent(self, event): if DEBUG: print 'move event', event.pos()
def setup_views(self): ''' This method sets up layout of main window, except for dropdown menus. At the center of the window there is a custon L{QtSchedule} widget, which shows timetable of some week or of particular day. Under it there are widgets for navigation: two labels bpMonday and bpSunday display information on what date range is displayed in schedule widget, and buttons buttonPrev, buttonNext and buttonToday are used to tell schedule to show previous week, next week and current week respectively. ''' self.panelRooms = QHBoxLayout() schedule_params = { 'http': self.http, 'work_hours': self.work_hours, 'quant': self.schedule_quant, 'rooms': self.rooms, } self.schedule = QtSchedule(self, schedule_params) self.bpMonday = QLabel('--/--/----') self.bpSunday = QLabel('--/--/----') self.buttonPrev = QPushButton(_('<<')) self.buttonNext = QPushButton(_('>>')) self.buttonToday = QPushButton(_('Today')) self.buttonPrev.setDisabled(True) self.buttonNext.setDisabled(True) self.buttonToday.setDisabled(True) # callback helper function def prev_week(): week_range = self.schedule.model().showPrevWeek() self.showWeekRange(week_range) def next_week(): week_range = self.schedule.model().showNextWeek() self.showWeekRange(week_range) def today(): week_range = self.schedule.model().showCurrWeek() self.showWeekRange(week_range) self.connect(self.buttonPrev, SIGNAL('clicked()'), prev_week) self.connect(self.buttonNext, SIGNAL('clicked()'), next_week) self.connect(self.buttonToday, SIGNAL('clicked()'), today) bottomPanel = QHBoxLayout() bottomPanel.addWidget(QLabel(_('Week:'))) bottomPanel.addWidget(self.bpMonday) bottomPanel.addWidget(QLabel('-')) bottomPanel.addWidget(self.bpSunday) bottomPanel.addStretch(1) bottomPanel.addWidget(self.buttonPrev) bottomPanel.addWidget(self.buttonToday) bottomPanel.addWidget(self.buttonNext) mainLayout = QVBoxLayout() mainLayout.addLayout(self.panelRooms) mainLayout.addWidget(self.schedule) mainLayout.addLayout(bottomPanel) mainWidget = QWidget() mainWidget.setLayout(mainLayout) self.setCentralWidget(mainWidget)