Exemple #1
0
    def __init__(self, image: str = None, parent=None) -> None:
        super().__init__(parent)

        self._path = image
        self.image = None
        if image is not None:
            self.image = os.path.basename(image)

        lyt = QtGui.QGridLayout()
        self.setLayout(lyt)
        self.close_btn = IconButton(
            QtGui.QPixmap(res("cancel_red.png", "icon")), -1)
        self.close_btn.hide()
        self.close_btn.setToolTip("Remove the Image")
        self.close_btn.clicked.connect(self.hideImage)
        self.add_btn = IconButton(QtGui.QPixmap(res("plus_green.png", "icon")),
                                  -1)
        self.add_btn.clicked.connect(self.choose_image)
        self.add_btn.setToolTip("Add an Image")
        self.lbl = QtGui.QLabel(
            "<font size=10 color=grey><i>Insert an Image<i></font>")

        lyt.addWidget(self.close_btn, 1, 1)
        lyt.addWidget(self.add_btn, 1, 1)
        lyt.addWidget(self.lbl, 0, 0, 2, 2, alignment=QtCore.Qt.AlignCenter)
        lyt.setRowStretch(0, 1)
        lyt.setColumnStretch(0, 1)

        if image is not None:
            self.setImage(image)
Exemple #2
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle("إختر امتحانًا")
        self.setWindowIcon(QtGui.QIcon(res("test.ico", "icon")))
        self.resize(600, 300)
        lyt = QtGui.QVBoxLayout()

        wrap = QtGui.QWidget()
        wrap.setLayout(lyt)
        scroll = QtGui.QScrollArea()
        scroll.setWidget(wrap)
        topmost = QtGui.QVBoxLayout()
        scroll.setWidgetResizable(True)
        topmost.addWidget(scroll)
        self.setLayout(topmost)
        lyt.setMargin(8)

        a = len(TESTS)

        if a == 0:
            lyt.addWidget(
                QtGui.QLabel("لا يوجد أية إمتحان، اضف واحدًا لتكمل."),
                alignment=QtCore.Qt.AlignCenter)
            return

        for i, test in enumerate(TESTS):
            lyt.addWidget(TestCard(test, i, self, chose=self.chose))

        if a > 1:
            lyt.addWidget(QtGui.QLabel("<hr>"))
            lyt.addWidget(QtGui.QLabel("النهاية"),
                          alignment=QtCore.Qt.AlignCenter)

        login_link = QtGui.QLabel("<a href='#open'>Open tests editor</a>")
        login_link.setOpenExternalLinks(False)

        def f(_):
            auth = Auth(parent=self)
            center_widget(auth)
            auth.parent_window = self
            auth.show()
            CURRENT_ACTIVE[0] = auth
            self.hide()

        login_link.linkActivated.connect(f)

        topmost.addWidget(QtGui.QLabel("<hr>"))
        dwn = QtGui.QHBoxLayout()
        dwn.addWidget(QtGui.QLabel())
        dwn.addWidget(QtGui.QLabel("{} Test{}".format(a,
                                                      's' if a > 1 else '')),
                      alignment=QtCore.Qt.AlignCenter)
        dwn.addWidget(login_link, alignment=QtCore.Qt.AlignRight)
        topmost.addLayout(dwn)
Exemple #3
0
        def f1(e: QtGui.QContextMenuEvent):
            selected_item = self.tests_list.itemAt(e.pos())
            if selected_item is None:
                return
            menu = QtGui.QMenu()
            delete = menu.addAction("Delete")
            delete.setIcon(QtGui.QIcon(res("halt.png", "icon")))
            action = menu.exec_(QtGui.QCursor.pos())

            if action == delete:
                self.delete_test(index=self.tests_list.row(selected_item))
Exemple #4
0
    def contextMenuEvent(self, event: QtGui.QContextMenuEvent):
        row = self.rowAt(event.pos().y())
        if row == -1:
            return
        menu = QtGui.QMenu()
        delete = menu.addAction("Delete")
        delete.setIcon(QtGui.QIcon(res("halt.png", "icon")))
        action = menu.exec_(QtGui.QCursor.pos())

        if action == delete:
            self.delete_row(row)
Exemple #5
0
def main():
    _init()
    app = QtGui.QApplication(sys.argv)
    app.setApplicationName("Examer")
    app.setApplicationVersion("0.1")
    app.setWindowIcon(QtGui.QIcon(res("test.ico", "icon")))
    main_widget = TestChooser()
    center_widget(main_widget)
    main_widget.show()
    app.exec_()
    del main_widget
    del app
    _defer()
Exemple #6
0
    def __init__(self,
                 answer: Answer,
                 index: int,
                 last=False,
                 parent: QtGui.QWidget = None,
                 **kwargs) -> None:
        QtGui.QWidget.__init__(self, parent, **kwargs)

        self._last = last
        self.index = index
        self.mod = None  # type: IconButton
        self.deleted = False

        lyt = QtGui.QHBoxLayout()

        self.add_pixmap = QtGui.QPixmap(res("plus_green.png", "icon"))
        self.remove_pixmap = QtGui.QPixmap(res("cancel_red.png", "icon"))

        self.setLayout(lyt)
        self.chk = chk = QtGui.QCheckBox()
        chk.stateChanged.connect(lambda x: self.validityChanged.emit(
            x == QtCore.Qt.Checked, self.index))
        if answer.valid:
            chk.toggle()

        lyt.addWidget(chk)

        self.edt = edt = EditableLabel("")  # to get the signal emitted
        edt.textChanged.connect(self.observe_text)
        edt.setText(answer.string)
        edt.setSizePolicy(QtGui.QSizePolicy.Expanding,
                          QtGui.QSizePolicy.Maximum)
        edt.setAlignment(QtCore.Qt.AlignAbsolute)
        lyt.addWidget(edt)

        self.last = last

        lyt.setDirection(QtGui.QBoxLayout.LeftToRight)
Exemple #7
0
    def __init__(self,
                 test: Test,
                 item: QtGui.QListWidgetItem,
                 parent: QtGui.QWidget = None) -> None:
        super().__init__(parent)

        self._item = item
        self.s_test = test
        self.setTabBar(TabBar())
        self.setTabsClosable(True)
        self.setUpdatesEnabled(True)
        self.setMovable(True)

        btn = QtGui.QToolButton()
        btn.setIcon(QtGui.QIcon(res("add.png", "icon")))
        btn.clicked.connect(self.add_question)
        self.setCornerWidget(btn)

        self.details = details = TestDetails(test, parent=self)
        details.wantFocusChanged.connect(
            lambda r: self.updateErrors.emit(self.errors))
        details.nameChanged.connect(
            lambda s: self.nameChanged.emit(self.index, s))
        self.addTab(details, "Details")
        self.tabBar().tabButton(0, QtGui.QTabBar.RightSide).resize(
            0, 0)  # makes it not closable

        self.degrees_widget = degrees_widget = DegreesWidget(
            copy.deepcopy(test), parent=self)

        def f(r):
            self.tabBar().setEnabled(
                r is DegreesTable.PreserveFocusReason.NONE)
            self.cornerWidget().setEnabled(
                r is DegreesTable.PreserveFocusReason.NONE)
            self.updateErrors.emit(self.errors)

        degrees_widget.wantFocusChanged.connect(f)
        self.addTab(degrees_widget, "Degrees")
        self.tabBar().tabButton(1, QtGui.QTabBar.RightSide).resize(
            0, 0)  # makes it not closable

        self.tabBar().tabMoved.connect(self.tab_moved)

        for question in test.questions:
            self.add_question(question=question, setfocus=False)

        self.tabCloseRequested.connect(self.delete_question)
Exemple #8
0
    def save(self) -> bool:
        errors = self.tests_widget.currentWidget().errors
        if errors:
            QtGui.QMessageBox.warning(self, "Invalid Operation",
                                      "Cannot save while there's an error.")
            return False
        else:
            self.sts_bar_lbl.setText("Saved Tests.")
            QtCore.QTimer.singleShot(3000, self.update_status_bar)

            new_tests = self.tests
            for widget, test in zip(self.widgets, new_tests):
                widget.s_test = test

            self.old_tests = TESTS[:]
            TESTS.clear()
            TESTS.extend(new_tests)

            dump_tests(new_tests, res("data.enc", "state"), encrypt=True)
            return True
Exemple #9
0
    def __init__(self, test: Test, index: int, parent=None, **kwargs) -> None:
        super().__init__(parent, **kwargs)
        self.index = index

        self.setFrameShadow(QtGui.QFrame.Sunken)
        self.setFrameShape(QtGui.QFrame.StyledPanel)
        lyt = QtGui.QGridLayout()
        lyt.addWidget(QtGui.QLabel("<b><font size=5>%s</font></b>" %
                                   test.name),
                      0,
                      0,
                      alignment=QtCore.Qt.AlignLeft)
        lyt.addWidget(QtGui.QLabel("<hr>"), 1, 0, 1, 2)
        lyt.addWidget(QtGui.QLabel("<font size=3 color=grey>%s</font>" %
                                   (test.description or "<i>"
                                    "لا يوجد وصف"
                                    "</i>")),
                      1,
                      0,
                      2,
                      2,
                      alignment=QtCore.Qt.AlignLeft)
        btn = QtGui.QPushButton("افتح", self)
        btn.setIcon(QtGui.QIcon(res("arrow.png", "icon")))
        btn.clicked.connect(self.open)
        lyt.addWidget(QtGui.QLabel(), 2, 0)
        text = re.sub(
            r'\b(\d+)\b', r'<b>\1</b>', "%s | %d درجة | %d سؤال" %
            (format_secs(test.time), int(test.degree), len(test.questions)))
        lyt.addWidget(QtGui.QLabel("<font size=3 color=grey>%s</font>" % text),
                      3,
                      0,
                      1,
                      2,
                      alignment=QtCore.Qt.AlignLeft)
        lyt.addWidget(btn, 4, 1, alignment=QtCore.Qt.AlignRight)

        self.setLayout(lyt)
Exemple #10
0
    def __init__(self, id_: int, question: Question, parent=None):

        super().__init__(parent)
        self.id = id_
        self.degree = -1
        random.shuffle(question.answers)
        self.question = question
        self.valid = [
            question.answers.index(a) for a in self.question.answers if a.valid
        ]
        self.is_radio = len(self.valid) == 1
        self.pic = QtGui.QLabel()

        my_layout = QtGui.QVBoxLayout()

        self.question = QtGui.QLabel("<font size=2 color=red><b>" +
                                     question.string + "</b></font>")
        self.question.setBackgroundRole(QtGui.QPalette.Background)
        self.question.setFont(QtGui.QFont("Times", weight=QtGui.QFont.Bold))
        self.question.setWordWrap(True)
        my_layout.addWidget(self.question)
        self.setTitle("سؤال رقم " + str(self.id))
        my_layout.addWidget(QtGui.QLabel("<hr>"))

        answers_images_lyt = QtGui.QHBoxLayout()
        answers_lyt = QtGui.QVBoxLayout()

        if self.is_radio:
            self.answers = QtGui.QButtonGroup()
            for a in question.answers:
                btn = QtGui.QRadioButton(a.string)
                btn.clicked.connect(self.answering)
                self.answers.addButton(btn)
                answers_lyt.addWidget(btn)
        else:
            self.answers = []
            for a in question.answers:
                btn = QtGui.QCheckBox(a.string)
                btn.stateChanged.connect(self.answering)
                answers_lyt.addWidget(btn)
                self.answers.append(btn)
                self.checkbox_clicked = 0

        answers_images_lyt.addLayout(answers_lyt, 3)
        answers_images_lyt.addStretch(1)
        answers_images_lyt.addWidget(self.pic,
                                     2,
                                     alignment=QtCore.Qt.AlignRight)
        my_layout.addLayout(answers_images_lyt)
        if question.pic:
            self.pic.setPixmap(QtGui.QPixmap(res(question.pic)))

        self.lcdScreen = QtGui.QLCDNumber()
        self.lcdScreen.setSegmentStyle(QtGui.QLCDNumber.Flat)

        my_layout.addItem(
            QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum,
                              QtGui.QSizePolicy.Expanding))
        my_layout.addWidget(QtGui.QLabel("<hr>"))
        child_layout = QtGui.QHBoxLayout()
        self.number_label = QtGui.QLabel()
        child_layout.addWidget(self.number_label,
                               alignment=QtCore.Qt.AlignRight)
        vline = QtGui.QFrame()
        vline.setFrameShape(QtGui.QFrame.VLine)
        vline.setFrameShadow(QtGui.QFrame.Sunken)
        child_layout.addWidget(vline)
        child_layout.addWidget(self.lcdScreen, alignment=QtCore.Qt.AlignLeft)

        my_layout.addLayout(child_layout)

        self.setLayout(my_layout)
Exemple #11
0
    def initializePage(self):
        degrees = self.wizard().degrees
        test = self.wizard().test
        name = self.field("name").title()
        school = self.field("school")
        grade = GRADES[int(self.field("grade")) - 1]
        number = self.field("number")
        sum_of_degrees = float(sum(i for i in degrees if i != -1))

        if not number.startswith("+2"):
            number = "+2" + number

        self.nameL.setText(name)
        self.schoolL.setText(school)
        self.gradeL.setText(grade)
        self.numberL.setText(number)

        failed_at = []
        left = []
        for i, v in enumerate(degrees):
            if v == 0:
                failed_at.append(i)
            elif v == -1:
                left.append(i)

        student = dict(
            zip(headers, [
                name,
                school,
                grade,
                number,
                sum_of_degrees,
                test.degree,
                left,
                failed_at,
                test.name,
            ]))

        questions_n = len(test.questions)
        left_n = len(left)
        failed_at_n = len(failed_at)
        self.grey.description.setText(self.grey.description.text().format(
            left_n / questions_n * 100))
        self.red.description.setText(self.red.description.text().format(
            failed_at_n / questions_n * 100))
        self.green.description.setText(self.green.description.text().format(
            (questions_n - (left_n + failed_at_n)) / questions_n * 100))
        pieces = (left_n * test.degree / questions_n,
                  failed_at_n * test.degree / questions_n, sum_of_degrees)
        set_angle = 0
        total = sum(pieces)
        colors = [
            QtGui.QColor(128, 128, 128),
            QtGui.QColor(255, 0, 0),
            QtGui.QColor(0, 128, 0)
        ]
        scene = QtGui.QGraphicsScene()
        for i, piece in enumerate(pieces):
            angle = round(float(piece * 5760) / total)
            ellipse = QtGui.QGraphicsEllipseItem(0, 0, 400, 400)
            ellipse.setPos(0, 0)
            ellipse.setStartAngle(set_angle)
            ellipse.setSpanAngle(angle)
            ellipse.setBrush(colors[i])
            set_angle += angle
            scene.addItem(ellipse)

        view = QtGui.QGraphicsView(scene)
        view.setStyleSheet("background-color: transparent")
        self.lyt.insertWidget(0, view)

        test.student_degrees.append(StudentDegree(**student))
        dump_tests(TESTS, res("data.enc", "state"), encrypt=True)
Exemple #12
0
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setWindowTitle("Tests Editor")

        self.just_deleted_a_test = False  # used in navigation (not to test that there were errors in the deleted test)
        self.old_tests = None  # type: Optional[List[Test]]

        open_action = QtGui.QAction("&Open", self)
        open_action.setShortcut("Ctrl+O")
        save_action = QtGui.QAction("&Save", self)
        save_action.setShortcut("Ctrl+S")
        quit_action = QtGui.QAction("&Quit", self)
        quit_action.setShortcut("Ctrl+Q")

        open_action.triggered.connect(self.open)
        save_action.triggered.connect(self.save)
        quit_action.triggered.connect(self.close)
        menu_bar = self.menuBar()

        file_menu = menu_bar.addMenu("&File")
        file_menu.addAction(open_action)
        file_menu.addAction(save_action)
        file_menu.addSeparator()
        file_menu.addAction(quit_action)

        sts_bar = QtGui.QStatusBar()
        sts_bar.setStyleSheet(
            "QStatusBar { background-color: #ccc; border-top: 1.5px solid grey } "
        )
        self.sts_bar_lbl = QtGui.QLabel("Ready.")
        self.sts_bar_lbl.setOpenExternalLinks(False)
        self.sts_bar_lbl.linkActivated.connect(
            lambda index: self.tests_widget.currentWidget().setCurrentIndex(
                int(index)))
        sts_bar.addWidget(self.sts_bar_lbl)
        self.setStatusBar(sts_bar)

        self.resize(1000, 600)
        self.parent_window = None
        self._current_row = 0

        frm = QtGui.QFrame()
        self.lyt = lyt = QtGui.QGridLayout()
        frm.setLayout(lyt)
        self.setCentralWidget(frm)

        lyt.setMargin(10)

        self.save_btn = save_btn = QtGui.QPushButton(
            QtGui.QIcon(res("save.png", "icon")), "Save")
        save_btn.clicked.connect(self.save)
        save_btn.setToolTip("Save Tests")

        filter_edit = QtGui.QLineEdit()
        filter_edit.setPlaceholderText("Search tests...")
        filter_edit.textChanged.connect(self.update_tests_list)

        self.tests_list = QtGui.QListWidget()

        def f1(e: QtGui.QContextMenuEvent):
            selected_item = self.tests_list.itemAt(e.pos())
            if selected_item is None:
                return
            menu = QtGui.QMenu()
            delete = menu.addAction("Delete")
            delete.setIcon(QtGui.QIcon(res("halt.png", "icon")))
            action = menu.exec_(QtGui.QCursor.pos())

            if action == delete:
                self.delete_test(index=self.tests_list.row(selected_item))

        def f2(e: QtGui.QKeyEvent):
            if e.key() == QtCore.Qt.Key_Delete:
                self.delete_test()

        self.tests_list.contextMenuEvent = f1
        self.tests_list.keyPressEvent = f2
        self.tests_list.setSelectionMode(
            QtGui.QAbstractItemView.SingleSelection)
        self.tests_list.currentItemChanged.connect(self.item_changed)

        left_side = QtGui.QVBoxLayout()
        left_side.addWidget(filter_edit)
        left_side.addWidget(self.tests_list)
        self.btn_add_test = btn_add_test = QtGui.QPushButton()
        btn_add_test.setToolTip("Add a new test")
        btn_add_test.setIcon(QtGui.QIcon(res("add.png", "icon")))
        btn_add_test.clicked.connect(self.open_test_dialog)

        self.btn_remove_test = btn_remove_test = QtGui.QPushButton()
        btn_remove_test.setToolTip("Remove selected test")
        btn_remove_test.setIcon(QtGui.QIcon(res("minus.png", "icon")))
        btn_remove_test.clicked.connect(self.delete_test)

        buttons = QtGui.QHBoxLayout()
        buttons.addWidget(btn_add_test, alignment=QtCore.Qt.AlignLeft)
        buttons.addStretch(1)
        buttons.addWidget(btn_remove_test, alignment=QtCore.Qt.AlignRight)

        left_side.addLayout(buttons)

        lyt.addLayout(left_side, 0, 0, 3, 1)
        lyt.addItem(QtGui.QSpacerItem(10, 1), 0, 2)

        self.tests_widget = QtGui.QStackedWidget()

        for test in TESTS:
            self.add_test(test)

        if TESTS:
            self.tests_list.setCurrentItem(self.tests_list.item(0))

        lyt.addWidget(self.tests_widget, 0, 3, 2, 3)
        lyt.addWidget(save_btn, 2, 5)

        lyt.setColumnStretch(3, 1)
        lyt.setRowStretch(1, 1)
Exemple #13
0
    def __init__(self,
                 question: Question = None,
                 index: int = -1,
                 parent: QtGui.QWidget = None) -> None:
        super().__init__(parent)

        self.want_focus_reasons = QuestionTab.PreserveFocusReason.NONE
        self.answers_lyt = QtGui.QVBoxLayout()
        self.s_question = question or Question("", None, [Answer("", False)])
        self.answers = []  # type: List[AnswerWidget]
        self.deleted = False
        self.image = QuestionImage(self.s_question.pic
                                   and res(self.s_question.pic))
        self.disabled_because = set()  # type: Set[int]
        self.questionT = QtGui.QTextEdit()
        self.questionT.textChanged.connect(self.observe_name)
        self.answers_num = 0
        self.valid_num = 0
        self.index = index

        if not self.s_question.string:
            self.questionT.setPlainText("Enter question")
            self.questionT.selectAll()
        else:
            self.questionT.setPlainText(self.s_question.string)

        lyt = QtGui.QVBoxLayout()
        self.setLayout(lyt)

        wrap = QtGui.QWidget()
        wrap.setObjectName("wrap")
        wrap.setStyleSheet("wrap { background-color: transparent; }")
        wrap.setSizePolicy(QtGui.QSizePolicy.Expanding,
                           QtGui.QSizePolicy.Maximum)
        wrap.setLayout(self.answers_lyt)
        self.scroll = answers_scroll = QtGui.QScrollArea()
        answers_scroll.setWidget(wrap)
        answers_scroll.setWidgetResizable(True)
        answers_scroll.setStyleSheet(
            "QScrollArea { border: none; background-color: transparent; }")

        image_and_answers = QtGui.QHBoxLayout()
        image_and_answers.addWidget(answers_scroll, 3)

        image_lyt = QtGui.QVBoxLayout()
        image_lyt.addWidget(self.image, 3)
        image_lyt.addWidget(QtGui.QLabel(), 2)

        image_and_answers.addLayout(image_lyt, 2)

        lyt.addWidget(self.questionT, 1)
        lyt.addWidget(QtGui.QLabel("<hr>"))
        lyt.addLayout(image_and_answers, 2)
        self.status = QtGui.QLabel()
        lyt.addWidget(self.status)

        self.add_answers(self.s_question.answers)

        self._check_reason(QuestionTab.PreserveFocusReason.EMPTY_QUESTION,
                           not self.s_question.string)
        self._check_reason(QuestionTab.PreserveFocusReason.NUMBER_OF_ANSWERS,
                           len(self.s_question.answers) < 2)
        self._check_reason(
            QuestionTab.PreserveFocusReason.NO_CORRECT_ANSWER,
            not any(ans.valid for ans in self.s_question.answers))
        self._check_reason(QuestionTab.PreserveFocusReason.ALL_ANSWERS_CORRECT,
                           all(ans.valid for ans in self.s_question.answers))
        self._check_reason(
            QuestionTab.PreserveFocusReason.EMPTY_ANSWER,
            any(not ans.string for ans in self.s_question.answers))
Exemple #14
0
from utils.helpers import res, _init
from utils.parsers import parse_tests

_init()

TESTS = parse_tests(res("data.enc", "state"), encrypted=True)