Exemple #1
0
    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)
Exemple #2
0
    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)
Exemple #3
0
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()
Exemple #4
0
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()
Exemple #5
0
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()
Exemple #6
0
    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)