mainFunctions.py 35.7 KB
Newer Older
Zheng Yile's avatar
Zheng Yile committed
1
from datetime import datetime, timedelta
Zheng Yile's avatar
Zheng Yile committed
2
3
from pygments import highlight
from pygments.formatters import HtmlFormatter
4
5
from pygments.lexer import RegexLexer
from pygments.lexers import CLexer, CppLexer, PythonLexer, jvm, javascript, go, rust
Zheng Yile's avatar
Zheng Yile committed
6
from re import search
曹高翔's avatar
曹高翔 committed
7
from sys import platform
曹高翔's avatar
曹高翔 committed
8

9
from PyQt5.QtCore import Qt, QSize, QThread, pyqtSignal
Zheng Yile's avatar
Zheng Yile committed
10
11
12
from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import QAbstractItemView, QFileDialog
from PyQt5.QtWidgets import QHBoxLayout, QVBoxLayout
13
from PyQt5.QtWidgets import QComboBox, QLabel, QListWidgetItem, QTextEdit, QWidget
Zheng Yile's avatar
Zheng Yile committed
14
from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox
曹高翔's avatar
曹高翔 committed
15

16
from codiaclient import net_var
17
from codiaclient.network import get_pack, show_pack, start_pack, logined, get_exercise
曹高翔's avatar
曹高翔 committed
18
from codiaclient.network import submit, get_data
曹高翔's avatar
曹高翔 committed
19
from codiaclient.report import Error as codiaError, error_translate
20
from codiaclient.requests import variables as requests_var
21
from codiaclientgui.utils import QPalette, Font, Palette, Style, ErrorDisplay, NewListWidget, AdjustWindowSize, About
曹高翔's avatar
曹高翔 committed
22
from mainWindow import Ui_windowMain
曹高翔's avatar
曹高翔 committed
23

Zheng Yile's avatar
Zheng Yile committed
24

Zheng Yile's avatar
Zheng Yile committed
25
variables = {
26
    "pageNumber": 0,
27
    "packPerPage": 8,
28
29
30
31
    "lastPid": None,
    "firstPid": None,
    "hasNext": True,
    "packInfo": {},
曹高翔's avatar
曹高翔 committed
32
33
    "currentPackRow": 0,
    "currentHistoryRow": 0,
Zheng Yile's avatar
Zheng Yile committed
34
    "exerciseInfo": None,
曹高翔's avatar
曹高翔 committed
35
36
    "submitHistory": [],
    "testDataCount": 0,
Zheng Yile's avatar
Zheng Yile committed
37
38
39
40
    "workingStatus": {
        "frameExerciseInit": False,
        "frameQuestionInit": False,
    }
41
42
}

43

44
toDisplay = {
Zheng Yile's avatar
Zheng Yile committed
45
46
47
48
49
50
51
52
    "CPP": "C++",
    "C": "C",
    "JAVA": "Java",
    "JAVASCRIPT": "JavaScript",
    "GO": "Go",
    "RUST": "Rust",
    "PYTHON": "Python",
    "passed": "通过",
Zheng Yile's avatar
Zheng Yile committed
53
    "compile error": "编译错误",
Zheng Yile's avatar
Zheng Yile committed
54
55
    "wrong answer": "答案错误",
    "runtime error": "运行时错误",
Zheng Yile's avatar
Zheng Yile committed
56
57
    "time limit exceeds": "时间超限",
    "memory limit exceeds": "内存超限",
Zheng Yile's avatar
Zheng Yile committed
58
    "": "正在评测"
Zheng Yile's avatar
Zheng Yile committed
59
}
60
toData = {val: key for key, val in toDisplay.items()}
曹高翔's avatar
曹高翔 committed
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

class EmptyLexer(RegexLexer):
    name = 'Empty'
    tokens = {'root': []}

currentLexer = EmptyLexer()
currentFormatter = HtmlFormatter(noclasses = True, nobackground = True)


def GetLexer(lang: str, callback=None) -> None:
    global currentLexer
    if lang == "C" or lang == toDisplay["C"]: currentLexer = CLexer()
    elif lang == "CPP" or lang == toDisplay["CPP"]: currentLexer = CppLexer()
    elif lang == "PYTHON" or lang == toDisplay["PYTHON"]: currentLexer = PythonLexer()
    elif lang == "JAVA" or lang == toDisplay["JAVA"]: currentLexer = jvm.JavaLexer()
    elif lang == "JAVASCRIPT" or lang == toDisplay["JAVASCRIPT"]: currentLexer = javascript.JavascriptLexer()
    elif lang == "GO" or lang == toDisplay["GO"]: currentLexer = go.GoLexer()
    elif lang == "RUST" or lang == toDisplay["RUST"]: currentLexer = rust.RustLexer()
    else: currentLexer = EmptyLexer()
    callback and callback()


Zheng Yile's avatar
Zheng Yile committed
84
85
86
87
def Str(x) -> str:
    if x: return str(x)
    return ""

曹高翔's avatar
曹高翔 committed
88

Zheng Yile's avatar
Zheng Yile committed
89
class MyThread(QThread):
90
    infoSignal = pyqtSignal([dict], [list])
Zheng Yile's avatar
Zheng Yile committed
91
92
    errorSignal = pyqtSignal(codiaError)

Zheng Yile's avatar
Zheng Yile committed
93
94
    def __init__(self, *args, RunMethod, **kargs):
        super(MyThread, self).__init__(*args, **kargs)
Zheng Yile's avatar
Zheng Yile committed
95
        self.working = True
Zheng Yile's avatar
Zheng Yile committed
96
        self.RunMethod = RunMethod
Zheng Yile's avatar
Zheng Yile committed
97
98
99
100
101
102
103

    def __del__(self):
        self.working = False
        self.wait()

    def run(self):
        try:
Zheng Yile's avatar
Zheng Yile committed
104
            self.Info = self.RunMethod()
Zheng Yile's avatar
Zheng Yile committed
105
106
107
        except codiaError as e:
            self.errorSignal.emit(e)
        else:
108
            self.infoSignal[type(self.Info)].emit(self.Info)
Zheng Yile's avatar
Zheng Yile committed
109
110


Zheng Yile's avatar
Zheng Yile committed
111
# 代码高亮
112
def HighlightTextEdit(textEdit: QTextEdit, text=None, lang=None):
Zheng Yile's avatar
Zheng Yile committed
113
    global currentLexer, currentFormatter
114
115
116
    tempLexer = currentLexer
    if lang: GetLexer(lang)
    if text == None: text = textEdit.toPlainText()
Zheng Yile's avatar
Zheng Yile committed
117
118
    if text:
        pos = textEdit.textCursor().position()
119
120
        text = highlight(text, currentLexer, currentFormatter).replace("\r\n", "\n")[:-1]
        textEdit.setHtml(text)
Zheng Yile's avatar
Zheng Yile committed
121
122
123
124
125
126
127
128
        cursor = textEdit.textCursor()
        # 在文末换行时,下一条语句无法执行,此时若无此语句,光标将跳到文件头。加此语句可使得光标在文件尾。
        cursor.movePosition(QTextCursor.End)
        # 文末换行会出bug,若要解决可以在文末加一空格,在空格前换行即可。
        cursor.setPosition(pos)
        textEdit.setTextCursor(cursor)
    else:
        textEdit.setText("")
129
    currentLexer = tempLexer
Zheng Yile's avatar
Zheng Yile committed
130

Zheng Yile's avatar
Zheng Yile committed
131
# 获取题包内容信息的多线程
Zheng Yile's avatar
Zheng Yile committed
132
def ShowPack(pid, InfoRecv=lambda: None, ErrorRecv=lambda: None):
Zheng Yile's avatar
Zheng Yile committed
133
    global threadShowPack # extremely essential!
Zheng Yile's avatar
Zheng Yile committed
134
    threadShowPack = MyThread(RunMethod=lambda: show_pack(pid=pid))
Zheng Yile's avatar
Zheng Yile committed
135
136
137
138
139
    threadShowPack.infoSignal.connect(InfoRecv)
    threadShowPack.errorSignal.connect(ErrorRecv)
    uiMain.progressBarPack.setValue(90)
    threadShowPack.start()

曹高翔's avatar
曹高翔 committed
140

141
def frameExerciseInit():
Zheng Yile's avatar
Zheng Yile committed
142
143
    if variables["workingStatus"]["frameExerciseInit"]:
        return
144
    if not uiMain.listWidgetPack.selectedIndexes():
Zheng Yile's avatar
Zheng Yile committed
145
        QMessageBox.information(None, "提示", "请选择一个题包", QMessageBox.Ok)
146
        return
Zheng Yile's avatar
Zheng Yile committed
147
148

    getSelectedPid()
Zheng Yile's avatar
Zheng Yile committed
149
150
    uiMain.progressBarPack.setValue(0)
    uiMain.progressBarPack.show()
Zheng Yile's avatar
Zheng Yile committed
151
    variables["workingStatus"]["frameExerciseInit"] = True
Zheng Yile's avatar
Zheng Yile committed
152
153

    def ErrorRecv(e: codiaError):
154
        ErrorDisplay(e, error_translate, "获取失败")
Zheng Yile's avatar
Zheng Yile committed
155
        uiMain.progressBarPack.hide()
Zheng Yile's avatar
Zheng Yile committed
156
        variables["workingStatus"]["frameExerciseInit"] = False
Zheng Yile's avatar
Zheng Yile committed
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

    def exerciseListInfoRecv(exerciseListInfo):
        presentTime = datetime.now()
        if exerciseListInfo["due"]:
            endTime = datetime.strptime(search(r"^[^.]*", exerciseListInfo["due"].replace("T", " ")).group(),
                                        "%Y-%m-%d %H:%M:%S") + timedelta(hours=8)
            endTimeText = endTime.strftime("%Y-%m-%d %H:%M:%S")
        else:
            endTime = datetime.strptime("2100-01-01 00:00:00", "%Y-%m-%d %H:%M:%S")
            endTimeText = "无限制"
        createdAt = variables["packInfo"]["nodes"][variables["currentPackRow"]]["createdAt"]
        if createdAt:
            beginTime = datetime.strptime(search(r"^[^.]*", createdAt.replace("T", " ")).group(), "%Y-%m-%d %H:%M:%S") \
                        + timedelta(hours=8)
        else:
            beginTime = datetime.strptime("1900-01-01 00:00:00", "%Y-%m-%d %H:%M:%S")
        uiMain.labelDeadline.setText(f"截止时间: {endTimeText}")
        windowMain.setWindowTitle(exerciseListInfo["name"])
Zheng Yile's avatar
Zheng Yile committed
175
        if exerciseListInfo["viewerStatus"]["ongoing"] or not (beginTime < presentTime < endTime):
Zheng Yile's avatar
Zheng Yile committed
176
            uiMain.pushButtonExerciseBegin.hide()
Zheng Yile's avatar
Zheng Yile committed
177
178
        if exerciseListInfo["description"]:
            uiMain.textEditExerciseDiscription.setMarkdown(exerciseListInfo["description"]["content"])
Zheng Yile's avatar
Zheng Yile committed
179
        else:
Zheng Yile's avatar
Zheng Yile committed
180
181
            uiMain.textEditExerciseDiscription.setText("本题包未设置题包描述")
        variables["exerciseListInfo"] = exerciseListInfo["codingExercises"]["nodes"]
Zheng Yile's avatar
Zheng Yile committed
182
        uiMain.listWidgetExercise.clear()
Zheng Yile's avatar
Zheng Yile committed
183
184
        if variables["exerciseListInfo"]:
            for exercise in variables["exerciseListInfo"]:
Zheng Yile's avatar
Zheng Yile committed
185
186
                AddItemToQuestionList(exercise)
        uiMain.progressBarPack.hide()
Zheng Yile's avatar
Zheng Yile committed
187
        variables["workingStatus"]["frameExerciseInit"] = False
Zheng Yile's avatar
Zheng Yile committed
188
189
190
191
        uiMain.framePack.hide()
        uiMain.frameExercise.show()

    ShowPack(pid=requests_var["p"], InfoRecv=exerciseListInfoRecv, ErrorRecv=ErrorRecv)
曹高翔's avatar
曹高翔 committed
192
193
194
195


def AddItemToQuestionList(data: dict):
    item = QListWidgetItem()
196
197
    from codiaclientgui.utils import screenBASE
    item.setSizeHint(QSize(960 * screenBASE, 65 * screenBASE))
曹高翔's avatar
曹高翔 committed
198
199
200
201
202
203
204
    widget = GetExerciseWidget(data)
    widget.setCursor(Qt.PointingHandCursor)
    uiMain.listWidgetExercise.addItem(item)
    uiMain.listWidgetExercise.setItemWidget(item, widget)


def GetExerciseWidget(data: dict):
Zheng Yile's avatar
Zheng Yile committed
205
206
207
    if data["viewerStatus"]["passedCount"] > 0:
        labelExerciseStatus = QLabel("已通过")
        labelExerciseStatus.setPalette(Palette[QPalette.Text]["green"])
曹高翔's avatar
曹高翔 committed
208
    else:
Zheng Yile's avatar
Zheng Yile committed
209
210
        labelExerciseStatus = QLabel("未通过")
        labelExerciseStatus.setPalette(Palette[QPalette.Text]["red"])
Zheng Yile's avatar
Zheng Yile committed
211
    labelExerciseTitle = QLabel(Str(data["title"]))
Zheng Yile's avatar
Zheng Yile committed
212
213
    labelExercisePassed = QLabel(f"""通过数:{data["viewerStatus"]["passedCount"]}""")
    labelExerciseSubmit = QLabel(f"""提交数:{data["viewerStatus"]["totalCount"]}""")
214
215
216
217
218
219
220
221
222
223
224
225
226
    layoutExerciseMain = QHBoxLayout()
    layoutExerciseRight = QVBoxLayout()

    layoutExerciseRight.addWidget(labelExerciseSubmit)
    layoutExerciseRight.addWidget(labelExercisePassed)
    layoutExerciseMain.addWidget(labelExerciseStatus)
    layoutExerciseMain.addWidget(labelExerciseTitle)
    layoutExerciseMain.addLayout(layoutExerciseRight)

    labelExerciseStatus.setAlignment(Qt.AlignCenter)
    layoutExerciseMain.setStretchFactor(labelExerciseStatus, 1)
    layoutExerciseMain.setStretchFactor(labelExerciseTitle, 5)
    layoutExerciseMain.setStretchFactor(layoutExerciseRight, 3)
曹高翔's avatar
曹高翔 committed
227
228

    widget = QWidget()
229
    widget.setLayout(layoutExerciseMain)
曹高翔's avatar
曹高翔 committed
230
231
    return widget

232
233

def getSelectedPid():
234
235
236
237
    if uiMain.listWidgetPack.selectedIndexes():
        selected = uiMain.listWidgetPack.selectedIndexes()[0]
        variables["currentPackRow"] = selected.row()
        requests_var["p"] = variables["packInfo"]["nodes"][variables["currentPackRow"]]["id"]
238
239


曹高翔's avatar
曹高翔 committed
240
def getSelectedEid():
Zheng Yile's avatar
Zheng Yile committed
241
    if variables["workingStatus"]["frameQuestionInit"]:
Zheng Yile's avatar
Zheng Yile committed
242
        return
243
    selected = uiMain.listWidgetExercise.currentIndex().row()
Zheng Yile's avatar
Zheng Yile committed
244
245
    variables["currentExerciseRow"] = selected
    requests_var["e"] = variables["exerciseListInfo"][selected]["id"]
曹高翔's avatar
曹高翔 committed
246
247


248
249
250
251
def ExerciseReturn():
    uiMain.frameExercise.hide()
    uiMain.framePack.show()
    uiMain.pushButtonExerciseBegin.show()
Zheng Yile's avatar
Zheng Yile committed
252
    windowMain.setWindowTitle("题包列表")
253

曹高翔's avatar
曹高翔 committed
254

255
def BeginPack():
曹高翔's avatar
曹高翔 committed
256
257
    try:
        start_pack(requests_var["p"])
258
    except codiaError as e:
259
        ErrorDisplay(e, error_translate)
260
261
262
    else:
        QMessageBox.information(None, "消息", "成功开始题包", QMessageBox.Ok)
        uiMain.pushButtonExerciseBegin.hide()
Zheng Yile's avatar
Zheng Yile committed
263
        variables["packInfo"]["nodes"][variables["currentPackRow"]]["ongoing"] = True
264

曹高翔's avatar
曹高翔 committed
265

266
# 初始化任务,新建一个做题窗体和对应的ui
曹高翔's avatar
曹高翔 committed
267
def MainInit(callback=None):
268
    global windowMain, uiMain
269
    windowMain = QMainWindow()
270
    windowMain.setFont(Font["main"])
271
272
    uiMain = Ui_windowMain()
    uiMain.setupUi(windowMain)
273
    AdjustWindowSize(windowMain)
曹高翔's avatar
曹高翔 committed
274
    BeginMain(callback=callback)
275
    windowMain.show()
276
    GetPage()
277

曹高翔's avatar
曹高翔 committed
278

Zheng Yile's avatar
Zheng Yile committed
279
# 获取题目信息的多线程
280
def GetExercise(pid, eid, lang, InfoRecv=lambda: None, ErrorRecv=lambda: None):
Zheng Yile's avatar
Zheng Yile committed
281
    global threadGetExercise # extremely essential!
Zheng Yile's avatar
Zheng Yile committed
282
    threadGetExercise = MyThread(RunMethod=lambda: get_exercise(eid=eid, pid=pid, lang=lang))
283
284
285
286
287
288
    threadGetExercise.infoSignal.connect(InfoRecv)
    threadGetExercise.errorSignal.connect(ErrorRecv)
    uiMain.progressBarExercise.setValue(90)
    threadGetExercise.start()


曹高翔's avatar
曹高翔 committed
289
def frameQuestionInit():
Zheng Yile's avatar
Zheng Yile committed
290
291
    if variables["workingStatus"]["frameQuestionInit"]:
        return
曹高翔's avatar
曹高翔 committed
292
    if not uiMain.listWidgetExercise.selectedIndexes():
Zheng Yile's avatar
Zheng Yile committed
293
        QMessageBox.information(None, "消息", "请选择一个题目", QMessageBox.Ok)
曹高翔's avatar
曹高翔 committed
294
        return
295

Zheng Yile's avatar
Zheng Yile committed
296
297
    getSelectedEid()
    variables["workingStatus"]["frameQuestionInit"] = True
298
299
300
301
    uiMain.progressBarExercise.setValue(0)
    uiMain.progressBarExercise.show()

    def ExerciseInfoRecv(questionInfo):
Zheng Yile's avatar
Zheng Yile committed
302
303
        variables["exerciseInfo"] = questionInfo
        windowMain.setWindowTitle(questionInfo["title"])
304
        uiMain.statusbar.clearMessage()
Zheng Yile's avatar
Zheng Yile committed
305
306
        if questionInfo["tags"]:
            uiMain.statusbar.showMessage("标签:" + ", ".join(questionInfo["tags"]))
307
        else:
Zheng Yile's avatar
Zheng Yile committed
308
            uiMain.statusbar.showMessage("标签:无")
Zheng Yile's avatar
Zheng Yile committed
309

310
        sampleDataMdText = ""
Zheng Yile's avatar
Zheng Yile committed
311
312
        for i in range(0, len(questionInfo["sampleData"])):
            sampleDataMdText += f"### 样例{i + 1}\n"
Zheng Yile's avatar
Zheng Yile committed
313
314
315
316
317
318
319
320
321
322
323
            sampleDataMdText += f"#### 输入 \n```\n" + Str(questionInfo["sampleData"][i]["input"]) + "\n```\n"
            sampleDataMdText += f"#### 输出 \n```\n" + Str(questionInfo["sampleData"][i]["output"]) + "\n```\n"

        mdText = ""
        if questionInfo["description-content"]:
            mdText += "### 题目描述 \n" + Str(questionInfo["description-content"]) + "\n"
        if questionInfo["inputDescription-content"]:
            mdText += "### 题目描述 \n" + Str(questionInfo["inputDescription-content"]) + "\n"
        if questionInfo["outputDescription-content"]:
            mdText += "### 题目描述 \n" + Str(questionInfo["outputDescription-content"]) + "\n"
        mdText += sampleDataMdText
324
        uiMain.textEditQuestionDiscription.setMarkdown(mdText)
Zheng Yile's avatar
Zheng Yile committed
325
326
327
328

        passDivTotal = f"""{questionInfo["viewerStatus"]["passedCount"]}/{questionInfo["viewerStatus"]["totalCount"]}"""
        uiMain.labelQuestionStatus.setText(f"通过/尝试: {passDivTotal}")

329
        uiMain.comboBoxLanguage.clear()
Zheng Yile's avatar
Zheng Yile committed
330
        uiMain.comboBoxLanguage.addItem("请选择提交语言")
Zheng Yile's avatar
Zheng Yile committed
331
332
333
        for lang in variables["exerciseInfo"]["supportedLanguages"]:
            uiMain.comboBoxLanguage.addItem(toDisplay[lang])

334
        uiMain.labelSubmitStatus.setText(uiMain.labelQuestionStatus.text())
Zheng Yile's avatar
Zheng Yile committed
335

336
337
338
339
340
        code = variables["exerciseInfo"]["codeSnippet"]
        if not code:
            uiMain.textEditSubmit.setText("")
        else:
            HighlightTextEdit(textEdit=uiMain.textEditSubmit, text=code)
Zheng Yile's avatar
Zheng Yile committed
341
342
343

        def TryHighlight():
            uiMain.textEditSubmit.textChanged.disconnect() # 否则将无限循环。
344
            HighlightTextEdit(textEdit=uiMain.textEditSubmit)
Zheng Yile's avatar
Zheng Yile committed
345
346
347
348
            uiMain.textEditSubmit.textChanged.connect(TryHighlight)

        uiMain.textEditSubmit.textChanged.connect(TryHighlight)

349
        uiMain.progressBarExercise.hide()
Zheng Yile's avatar
Zheng Yile committed
350
        variables["workingStatus"]["frameQuestionInit"] = False
351
352
353
354
        uiMain.frameExercise.hide()
        uiMain.frameQuestion.show()

    def ErrorRecv(e: codiaError):
355
        ErrorDisplay(e, error_translate, "获取失败")
356
        uiMain.progressBarExercise.hide()
Zheng Yile's avatar
Zheng Yile committed
357
        variables["workingStatus"]["frameQuestionInit"] = False
358

Zheng Yile's avatar
Zheng Yile committed
359
360
    GetExercise(pid=requests_var["p"], eid=requests_var["e"],
                lang="CPP", InfoRecv=ExerciseInfoRecv,
361
                ErrorRecv=ErrorRecv)
曹高翔's avatar
曹高翔 committed
362
363


364
# 初始化任务,为做题窗口信号绑定槽函数
曹高翔's avatar
曹高翔 committed
365
def BeginMain(callback=None):
366
    QApplication.processEvents()
367
    nickname = logined()[1]
曹高翔's avatar
曹高翔 committed
368
369
    if not nickname:
        nickname = "UNDEFINED"
370
    verified = net_var["me"]["verified"]
曹高翔's avatar
曹高翔 committed
371
    if verified:
曹高翔's avatar
曹高翔 committed
372
        uiMain.statusbar.showMessage(f"当前用户: {nickname}", 0)
曹高翔's avatar
曹高翔 committed
373
    else:
曹高翔's avatar
曹高翔 committed
374
        uiMain.statusbar.showMessage(f"当前用户: {nickname}(未验证)", 0)
Zheng Yile's avatar
Zheng Yile committed
375
        QMessageBox.information(None, "消息", "当前账号功能受限,请尽快完成联系方式验证", QMessageBox.Ok)
376

曹高翔's avatar
曹高翔 committed
377
    uiMain.statusbar.setFont(Font["status"])
曹高翔's avatar
曹高翔 committed
378
379
    uiMain.pushButtonPackNext.clicked.connect(lambda: GetPage(before=variables["lastPid"]))
    uiMain.pushButtonPackPrevious.clicked.connect(lambda: GetPage(after=variables["firstPid"]))
380
381
    uiMain.progressBarPack.hide()
    uiMain.progressBarExercise.hide()
382
    uiMain.progressBarSubmit.hide()
383
    uiMain.progressBarHistory.hide()
曹高翔's avatar
曹高翔 committed
384
385
386
    uiMain.frameQuestion.hide()
    uiMain.frameHistory.hide()
    uiMain.frameSubmit.hide()
曹高翔's avatar
曹高翔 committed
387
388
389
    uiMain.frameExercise.hide()
    uiMain.frameCode.hide()
    uiMain.frameTestData.hide()
390
391
    uiMain.progressBarPack.setStyleSheet(Style["progressBar"])
    uiMain.progressBarExercise.setStyleSheet(Style["progressBar"])
392
    uiMain.progressBarSubmit.setStyleSheet(Style["progressBar"])
393
    uiMain.progressBarHistory.setStyleSheet(Style["progressBar"])
Zheng Yile's avatar
Zheng Yile committed
394
    if platform == "win32":
Zheng Yile's avatar
Zheng Yile committed
395
        uiMain.textEditCode.setTabStopWidth(uiMain.textEditSubmit.font().pointSize() * 4)
曹高翔's avatar
曹高翔 committed
396
397
        uiMain.textEditSubmit.setTabStopWidth(uiMain.textEditSubmit.font().pointSize() * 4)
    else:
Zheng Yile's avatar
Zheng Yile committed
398
        uiMain.textEditCode.setTabStopWidth(uiMain.textEditSubmit.font().pointSize() * 2)
曹高翔's avatar
曹高翔 committed
399
        uiMain.textEditSubmit.setTabStopWidth(uiMain.textEditSubmit.font().pointSize() * 2)
400

Zheng Yile's avatar
Zheng Yile committed
401
    # uiMain.listWidgetPack.itemClicked.connect(getSelectedPid)
402
403
404
405
    uiMain.listWidgetPack.itemDoubleClicked.connect(frameExerciseInit)
    uiMain.pushButtonPackOK.clicked.connect(frameExerciseInit)
    uiMain.pushButtonExerciseReturn.clicked.connect(ExerciseReturn)
    uiMain.pushButtonExerciseBegin.clicked.connect(BeginPack)
Zheng Yile's avatar
Zheng Yile committed
406
    # uiMain.listWidgetExercise.itemClicked.connect(getSelectedEid)
曹高翔's avatar
曹高翔 committed
407
    uiMain.listWidgetExercise.itemDoubleClicked.connect(frameQuestionInit)
曹高翔's avatar
曹高翔 committed
408
    uiMain.listWidgetPackHistory.itemDoubleClicked.connect(frameTestDataInit)
曹高翔's avatar
曹高翔 committed
409
410
    uiMain.pushButtonExerciseOK.clicked.connect(frameQuestionInit)
    uiMain.pushButtonQuestionReturn.clicked.connect(QuestionReturn)
411
412
413
414
415
416
    uiMain.pushButtonSubmit.clicked.connect(SubmitInit)
    uiMain.pushButtonSubmitCode.clicked.connect(
        lambda: SubmitCode(uiMain.comboBoxLanguageSubmit.currentText(),
                           uiMain.textEditSubmit.toPlainText()))
    uiMain.pushButtonSubmitBack.clicked.connect(SubmitReturn)
    uiMain.pushButtonSubmitFile.clicked.connect(SubmitFile)
417
    uiMain.pushButtonReadFromFile.clicked.connect(
418
        lambda: ReadFromFile(uiMain.comboBoxLanguageSubmit.currentText())
419
    )
曹高翔's avatar
曹高翔 committed
420
    uiMain.pushButtonHistory.clicked.connect(frameHistoryInit)
421
    uiMain.pushButtonHistoryBack.clicked.connect(HistoryReturn)
曹高翔's avatar
曹高翔 committed
422
423
424
425
426
    uiMain.pushButtonCodeBack.clicked.connect(CodeReturn)
    uiMain.pushButtonTestDataBack.clicked.connect(TestDataReturn)
    uiMain.pushButtonShowCode.clicked.connect(ShowCode)
    uiMain.pushButtonShowTestData.clicked.connect(ShowTestData)
    uiMain.pushButtonSubmitCodeDetails.clicked.connect(frameTestDataInit)
427
428
429
430
    uiMain.comboBoxLanguageSubmit.currentIndexChanged.connect(
        lambda: GetLexer(lang=uiMain.comboBoxLanguageSubmit.currentText(),
                         callback=lambda: HighlightTextEdit(textEdit=uiMain.textEditSubmit))
    )
431
    uiMain.actionAbout.triggered.connect(lambda: About(windowMain))
432

433
434
435
436
    uiMain.listWidgetPackHistory.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
    uiMain.listWidgetExercise.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
    uiMain.listWidgetData.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
    uiMain.listWidgetPack.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
Zheng Yile's avatar
Zheng Yile committed
437
438
439
440
    uiMain.listWidgetPack.setPalette(Palette[QPalette.Text]["black"])
    uiMain.listWidgetExercise.setPalette(Palette[QPalette.Text]["black"])
    uiMain.listWidgetPackHistory.setPalette(Palette[QPalette.Text]["black"])
    uiMain.listWidgetData.setPalette(Palette[QPalette.Text]["black"])
441

Zheng Yile's avatar
Zheng Yile committed
442
    for i in range(0, variables["packPerPage"]):
443
        AddItemToPackList(uiMain.listWidgetPack)
444

445
    uiMain.framePack.show()
446
    callback and callback()
447

曹高翔's avatar
曹高翔 committed
448

曹高翔's avatar
曹高翔 committed
449
def frameCodeInit():
Zheng Yile's avatar
Zheng Yile committed
450
    code = variables["submitHistory"][variables["currentHistoryRow"]]["solution"]["asset"]["content"]
451
452
453
454
455
    if not code:
        uiMain.textEditCode.setText("")
    else:
        HighlightTextEdit(textEdit=uiMain.textEditCode, text=code,
            lang=variables["submitHistory"][variables["currentHistoryRow"]]["solution"]['lang'])
曹高翔's avatar
曹高翔 committed
456
457
458
459


def frameTestDataInit():
    if not uiMain.listWidgetPackHistory.selectedItems():
Zheng Yile's avatar
Zheng Yile committed
460
        QMessageBox.information(None, "提示", "请选中一条历史记录", QMessageBox.Ok)
曹高翔's avatar
曹高翔 committed
461
        return
Zheng Yile's avatar
Zheng Yile committed
462
463
    variables["currentHistoryRow"] = uiMain.listWidgetPackHistory.selectedIndexes()[0].row()
    testData = variables["submitHistory"][variables["currentHistoryRow"]]["submission"]["reports"]
曹高翔's avatar
曹高翔 committed
464
465
    index = 1
    for data in testData:
Zheng Yile's avatar
Zheng Yile committed
466
467
        if data["key"] == "score":
            variables["testDataCount"] = int(data["value"].split("/")[1])
曹高翔's avatar
曹高翔 committed
468
469
    uiMain.listWidgetData.clear()
    for data in testData:
Zheng Yile's avatar
Zheng Yile committed
470
471
472
        if (data["key"] != "score" and data["key"] != "time elapsed"
                and data["key"] != "memory consumed" and data["key"] != "error"):
            AddItemToTestDataList(index, data["value"])
曹高翔's avatar
曹高翔 committed
473
474
475
476
477
478
479
            index += 1
    uiMain.frameHistory.hide()
    uiMain.frameTestData.show()


def AddItemToTestDataList(index: int, status: str):
    item = QListWidgetItem()
480
481
    from codiaclientgui.utils import screenBASE
    item.setSizeHint(QSize(960 * screenBASE, 65 * screenBASE))
曹高翔's avatar
曹高翔 committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
    widget = GetTestDataWidGet(index, status)
    uiMain.listWidgetData.addItem(item)
    uiMain.listWidgetData.setItemWidget(item, widget)


def GetTestDataWidGet(index: int, status: str):
    mainLayout = QHBoxLayout()
    statusLabel = QLabel()
    testDataLabel = QLabel()
    getScoreLabel = QLabel()

    statusLabel.setText(toDisplay[status])
    SetStatusColor(statusLabel)
    testDataLabel.setText(f"测试点 {index}")
Zheng Yile's avatar
Zheng Yile committed
496
    if status == "passed":
497
        getScoreLabel.setText("得分:%.1f" % (100 / variables["testDataCount"]))
曹高翔's avatar
曹高翔 committed
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
    else:
        getScoreLabel.setText("得分:0")

    mainLayout.addWidget(testDataLabel)
    mainLayout.addWidget(statusLabel)
    mainLayout.addWidget(getScoreLabel)

    mainLayout.setStretchFactor(testDataLabel, 1)
    mainLayout.setStretchFactor(statusLabel, 2)
    mainLayout.setStretchFactor(getScoreLabel, 1)

    widget = QWidget()
    widget.setLayout(mainLayout)
    widget.setCursor(Qt.PointingHandCursor)
    return widget


def ShowCode():
    frameCodeInit()
    uiMain.frameTestData.hide()
    uiMain.frameCode.show()


def ShowTestData():
    uiMain.frameCode.hide()
    uiMain.frameTestData.show()


def CodeReturn():
    uiMain.frameCode.hide()
    uiMain.frameHistory.show()


def TestDataReturn():
    uiMain.frameTestData.hide()
    uiMain.frameHistory.show()


536
537
538
539
def HistoryReturn():
    uiMain.frameHistory.hide()
    uiMain.frameQuestion.show()

曹高翔's avatar
曹高翔 committed
540

541
def GetHistory(eid, pid, cnt, InfoRecv=lambda: None, ErrorRecv=lambda: None):
Zheng Yile's avatar
Zheng Yile committed
542
    global threadGetHistory # extremely essential!
曹高翔's avatar
曹高翔 committed
543
    threadGetHistory = MyThread(RunMethod=lambda: get_data(eid=eid, pid=pid, cnt=cnt))
544
545
    threadGetHistory.infoSignal[list].connect(InfoRecv)
    threadGetHistory.errorSignal.connect(ErrorRecv)
Zheng Yile's avatar
Zheng Yile committed
546
    try:
Zheng Yile's avatar
Zheng Yile committed
547
        uiMain.progressBarHistory.Anime["progress"].setDuration(1500 * (cnt // 100 + 1))
Zheng Yile's avatar
Zheng Yile committed
548
549
    except:
        pass
550
551
    uiMain.progressBarHistory.setValue(90)
    threadGetHistory.start()
552

曹高翔's avatar
曹高翔 committed
553

曹高翔's avatar
曹高翔 committed
554
def frameHistoryInit():
Zheng Yile's avatar
Zheng Yile committed
555
    totalCount = variables["exerciseListInfo"][variables["currentExerciseRow"]]["viewerStatus"]["totalCount"]
曹高翔's avatar
曹高翔 committed
556
    if totalCount == 0:
557
        QMessageBox.information(None, "提示", "本题无提交记录", QMessageBox.Ok)
曹高翔's avatar
曹高翔 committed
558
        return
559
    uiMain.progressBarHistory.setValue(0)
560
    uiMain.listWidgetPackHistory.clear()
561
    uiMain.progressBarHistory.show()
562
563
564
    uiMain.frameQuestion.hide()
    uiMain.frameHistory.show()

565
566
567
    def historyInfoRecv(historyInfo):
        uiMain.progressBarHistory.setValue(95)
        historyInfo.reverse()
Zheng Yile's avatar
Zheng Yile committed
568
        variables["submitHistory"] = historyInfo
569
570
571
572
573
574
575
576
577
        uiMain.listWidgetPackHistory.clear()
        for data in historyInfo:
            AddItemToHistoryList(data)
        uiMain.progressBarHistory.hide()

    def ErrorRecv(e: codiaError):
        ErrorDisplay(e, error_translate, "获取失败")
        uiMain.progressBarHistory.hide()

Zheng Yile's avatar
Zheng Yile committed
578
    GetHistory(eid=requests_var["e"], pid=requests_var["p"], cnt=totalCount, InfoRecv=historyInfoRecv,
曹高翔's avatar
曹高翔 committed
579
               ErrorRecv=ErrorRecv)
580

581
582
583

def AddItemToHistoryList(data: dict):
    item = QListWidgetItem()
584
585
    from codiaclientgui.utils import screenBASE
    item.setSizeHint(QSize(960 * screenBASE, 65 * screenBASE))
586
    widget = GetHistoryWidget(data)
587
588
    if not widget.isEnabled():
        item.setFlags(item.flags() & ~Qt.ItemIsSelectable)
589
590
591
    uiMain.listWidgetPackHistory.addItem(item)
    uiMain.listWidgetPackHistory.setItemWidget(item, widget)

曹高翔's avatar
曹高翔 committed
592
593
594
595
596
597
598
599
600

def GetHistoryWidget(data: dict):
    mainLayout = QHBoxLayout()
    elapseLayout = QVBoxLayout()
    statusLabel = QLabel()
    languageLabel = QLabel()
    timeLabel = QLabel()
    codeLengthLabel = QLabel()
    timeElapsedLabel = QLabel()
601
    spaceElapsedLabel = QLabel()
曹高翔's avatar
曹高翔 committed
602
    scoreLabel = QLabel()
曹高翔's avatar
曹高翔 committed
603

Zheng Yile's avatar
Zheng Yile committed
604
605
    if data["scoreRate"] == 1:
        statusLabel.setText("通过")
曹高翔's avatar
曹高翔 committed
606
607
608
        statusLabel.setPalette(Palette[QPalette.Text]["green"])
    else:
        errorType = ""
Zheng Yile's avatar
Zheng Yile committed
609
610
611
        for i in data["submission"]["reports"]:
            if i["key"] == "error":
                errorType = i["value"]
612
        if not errorType:
Zheng Yile's avatar
Zheng Yile committed
613
614
615
616
            for i in data["submission"]["reports"]:
                if (i["value"] != "passed" and i["key"] != "memory consumed"
                        and i["key"] != "time elapsed" and i["key"] != "score"):
                    errorType = i["value"]
617
                    break
618
        statusLabel.setText(toDisplay[errorType])
曹高翔's avatar
曹高翔 committed
619
        SetStatusColor(statusLabel)
Zheng Yile's avatar
Zheng Yile committed
620
    languageLabel.setText(toDisplay[data["solution"]["lang"]])
曹高翔's avatar
曹高翔 committed
621
    try:
Zheng Yile's avatar
Zheng Yile committed
622
        scoreLabel.setText("得分:%.1f" % (data["scoreRate"] * 100))
曹高翔's avatar
曹高翔 committed
623
624
    except:
        pass
Zheng Yile's avatar
Zheng Yile committed
625
    timeLabel.setText("提交时间:" +
曹高翔's avatar
曹高翔 committed
626
                      (datetime.strptime(search(r"^[^.]*", data["time"].replace("T", " ")).group(),
627
                                         "%Y-%m-%d %H:%M:%S") + timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S"))
Zheng Yile's avatar
Zheng Yile committed
628
    codeLengthLabel.setText("代码长度:" + Str(len(data["solution"]["asset"]["content"])) + " B")
Zheng Yile's avatar
Zheng Yile committed
629
630
631
632
633
    for i in data["submission"]["reports"]:
        if i["key"] == "memory consumed":
            spaceElapsedLabel.setText("空间消耗:" + i["value"])
        elif i["key"] == "time elapsed":
            timeElapsedLabel.setText("时间消耗:" + i["value"])
634
635
636
637
638
639
640
641
642
    statusLabel.setAlignment(Qt.AlignCenter)

    elapseLayout.addWidget(timeElapsedLabel)
    elapseLayout.addWidget(spaceElapsedLabel)
    mainLayout.addWidget(statusLabel)
    mainLayout.addWidget(languageLabel)
    mainLayout.addWidget(timeLabel)
    mainLayout.addWidget(codeLengthLabel)
    mainLayout.addLayout(elapseLayout)
曹高翔's avatar
曹高翔 committed
643
    mainLayout.addWidget(scoreLabel)
644
645
646
647
648

    mainLayout.setStretchFactor(statusLabel, 2)
    mainLayout.setStretchFactor(languageLabel, 1)
    mainLayout.setStretchFactor(timeLabel, 4)
    mainLayout.setStretchFactor(codeLengthLabel, 2)
曹高翔's avatar
曹高翔 committed
649
650
    mainLayout.setStretchFactor(elapseLayout, 3)
    mainLayout.setStretchFactor(scoreLabel, 2)
651
652
653
654

    widget = QWidget()
    widget.setLayout(mainLayout)
    widget.setCursor(Qt.PointingHandCursor)
Zheng Yile's avatar
Zheng Yile committed
655
    if not data["submission"]["reports"]:
656
        widget.setEnabled(False)
657
    return widget
曹高翔's avatar
曹高翔 committed
658
659


曹高翔's avatar
曹高翔 committed
660
def SetStatusColor(statusLabel: QLabel):
Zheng Yile's avatar
Zheng Yile committed
661
    if statusLabel.text() == "答案错误":
662
        statusLabel.setPalette(Palette[QPalette.Text]["red"])
Zheng Yile's avatar
Zheng Yile committed
663
    elif statusLabel.text() == "运行时错误":
664
        statusLabel.setPalette(Palette[QPalette.Text]["purple"])
Zheng Yile's avatar
Zheng Yile committed
665
    elif statusLabel.text() == "超时":
666
        statusLabel.setPalette(Palette[QPalette.Text]["darkblue"])
Zheng Yile's avatar
Zheng Yile committed
667
    elif statusLabel.text() == "通过":
曹高翔's avatar
曹高翔 committed
668
        statusLabel.setPalette(Palette[QPalette.Text]["green"])
669
670
    else:
        statusLabel.setPalette(Palette[QPalette.Text]["gray"])
曹高翔's avatar
曹高翔 committed
671
672


673
def ReadFromFile(lang: str):
674
675
676
    # if lang == "请选择提交语言":
    #     QMessageBox.information(None, "提示", "请选择一种提交语言", QMessageBox.Ok)
    #     return
677
    fileWindow = QFileDialog()
Zheng Yile's avatar
Zheng Yile committed
678
679
680
681
682
683
684
685
686
687
688
689
690
691
    if lang == "C++":
        fileWindow.setNameFilter("C++ 源文件(*.cpp *.cc *.C *.cxx *.c++)")
    elif lang == "C":
        fileWindow.setNameFilter("C 源文件(*.c)")
    elif lang == "Python":
        fileWindow.setNameFilter("Python 源文件(*.py)")
    elif lang == "Java":
        fileWindow.setNameFilter("Java 源文件(*.java)")
    elif lang == "JavaScript":
        fileWindow.setNameFilter("JavaScript 源文件(*.js)")
    elif lang == "Go":
        fileWindow.setNameFilter("Go 源文件(*.go)")
    elif lang == "Rust":
        fileWindow.setNameFilter("Rust 源文件(*.rs)")
692
693
    # else:
    #     QMessageBox.critical(None, "错误", "未知错误", QMessageBox.Ok)
Zheng Yile's avatar
Zheng Yile committed
694
    # fileWindow.setDirectory("./")
695
696
697
    if fileWindow.exec_():
        fileChosen = fileWindow.selectedFiles()[0]
    else:
Zheng Yile's avatar
Zheng Yile committed
698
        QMessageBox.information(None, "提示", "请选择一个文件", QMessageBox.Ok)
699
        return None
700
701
    with open(fileChosen, "r") as inputCode:
        codeSubmit = inputCode.read()
702
703
704
705
706
    uiMain.textEditSubmit.setText(codeSubmit)
    return codeSubmit


def SubmitFile():
Zheng Yile's avatar
Zheng Yile committed
707
    if uiMain.comboBoxLanguage.currentText() == "请选择提交语言":
708
        QMessageBox.information(None, "提示", "请选择一种提交语言", QMessageBox.Ok)
709
        return
710
711
712
    codeSubmit = ReadFromFile(uiMain.comboBoxLanguage.currentText())
    if codeSubmit:
        SubmitCode(uiMain.comboBoxLanguage.currentText(), codeSubmit)
713
714
715
716
717
718


def SubmitReturn():
    uiMain.frameSubmit.hide()
    uiMain.frameQuestion.show()

曹高翔's avatar
曹高翔 committed
719

720
def Submit(pid, eid, lang, code, InfoRecv=lambda: None, ErrorRecv=lambda: None):
Zheng Yile's avatar
Zheng Yile committed
721
    global threadSubmit # extremely essential!
722
723
724
725
726
    threadSubmit = MyThread(RunMethod=lambda: submit(eid=eid, pid=pid, lang=lang, solutioncode=code))
    threadSubmit.infoSignal.connect(InfoRecv)
    threadSubmit.errorSignal.connect(ErrorRecv)
    uiMain.progressBarSubmit.setValue(90)
    threadSubmit.start()
727

曹高翔's avatar
曹高翔 committed
728

729
def SubmitCode(lang: str, code: str):
Zheng Yile's avatar
Zheng Yile committed
730
    if lang == "请选择提交语言":
731
        QMessageBox.information(None, "提示", "请选择一种提交语言", QMessageBox.Ok)
732
        return
733
734
735
736
737
738
739
740
741
742

    uiMain.progressBarSubmit.setValue(0)
    uiMain.progressBarSubmit.show()

    def ErrorRecv(e: codiaError):
        ErrorDisplay(e, error_translate, "获取失败")
        uiMain.progressBarSubmit.hide()

    def submitInfoRecv(submitInfo):
        if submitInfo:
Zheng Yile's avatar
Zheng Yile committed
743
744
            QMessageBox.information(None, "提交成功", "提交成功,请在历史记录中查看评测结果", QMessageBox.Ok)
            variables["exerciseListInfo"][variables["currentExerciseRow"]]["viewerStatus"]["totalCount"] += 1
745
746
747
            uiMain.frameSubmit.hide()
            uiMain.frameQuestion.show()
        else:
Zheng Yile's avatar
Zheng Yile committed
748
            QMessageBox.critical(None, "提交失败", "请检查语言选择是否正确", QMessageBox.Ok)
749
750
        uiMain.progressBarSubmit.hide()

Zheng Yile's avatar
Zheng Yile committed
751
    Submit(pid=requests_var["p"], eid=requests_var["e"], lang=toData[lang], code=code, InfoRecv=submitInfoRecv,
曹高翔's avatar
曹高翔 committed
752
           ErrorRecv=ErrorRecv)
753
754
755


def SubmitInit():
Zheng Yile's avatar
Zheng Yile committed
756
    languages = [toDisplay[lang] for lang in variables["exerciseInfo"]["supportedLanguages"]]
757
    uiMain.comboBoxLanguageSubmit.clear()
Zheng Yile's avatar
Zheng Yile committed
758
759
    if uiMain.comboBoxLanguage.currentText() == "请选择提交语言":
        uiMain.comboBoxLanguageSubmit.addItem("请选择提交语言")
760
    uiMain.comboBoxLanguageSubmit.addItems(languages)
Zheng Yile's avatar
Zheng Yile committed
761
    if uiMain.comboBoxLanguage.currentText() != "请选择提交语言":
762
        uiMain.comboBoxLanguageSubmit.setCurrentIndex(uiMain.comboBoxLanguage.currentIndex() - 1)
763
764
765
766
    uiMain.frameQuestion.hide()
    uiMain.frameSubmit.show()


曹高翔's avatar
曹高翔 committed
767
768
def QuestionReturn():
    uiMain.statusbar.clearMessage()
Zheng Yile's avatar
Zheng Yile committed
769
    uiMain.statusbar.showMessage("当前用户:" + net_var["me"]["nickname"])
曹高翔's avatar
曹高翔 committed
770
771
    uiMain.frameQuestion.hide()
    uiMain.frameExercise.show()
Zheng Yile's avatar
Zheng Yile committed
772
    windowMain.setWindowTitle(variables["packInfo"]["nodes"][variables["currentPackRow"]]["name"])
曹高翔's avatar
曹高翔 committed
773
774


775
# 在翻页后更新页面
776
777
778
def UpdatePage():
    variables["hasNext"] = variables["packInfo"]["pageInfo"]["hasPreviousPage"]
    packList = variables["packInfo"]["nodes"]
Zheng Yile's avatar
Zheng Yile committed
779
780
    variables["firstPid"] = packList[0]["id"]
    variables["lastPid"] = packList[-1]["id"]
781
    uiMain.pushButtonPackNext.setEnabled(variables["hasNext"] or not variables["pageNumber"])
782
783
    uiMain.pushButtonPackPrevious.setEnabled(variables["pageNumber"] > 1)
    uiMain.labelPackPage.setText("第 {} 页".format(variables["pageNumber"]))
曹高翔's avatar
曹高翔 committed
784
785
    for i in range(0, uiMain.listWidgetPack.count()):
        uiMain.listWidgetPack.takeItem(0)
Zheng Yile's avatar
Zheng Yile committed
786
    packList += [None] * (variables["packPerPage"] - len(packList))
Zheng Yile's avatar
Zheng Yile committed
787
    for i in range(0, variables["packPerPage"]):
788
        AddItemToPackList(uiMain.listWidgetPack, packList[i])
曹高翔's avatar
曹高翔 committed
789
790


Zheng Yile's avatar
Zheng Yile committed
791
# 获取题包信息的多线程
曹高翔's avatar
曹高翔 committed
792
def GetPack(before=None, after=None, InfoRecv=lambda: None, ErrorRecv=lambda: None):
Zheng Yile's avatar
Zheng Yile committed
793
    global threadGetPack # extremely essential!
Zheng Yile's avatar
Zheng Yile committed
794
    threadGetPack = MyThread(RunMethod=lambda: get_pack(cnt=variables["packPerPage"], before=before, after=after))
795
796
    threadGetPack.infoSignal.connect(InfoRecv)
    threadGetPack.errorSignal.connect(ErrorRecv)
Zheng Yile's avatar
Zheng Yile committed
797
    uiMain.progressBarPack.setValue(90)
798
799
    threadGetPack.start()

曹高翔's avatar
曹高翔 committed
800

801
# 翻页
曹高翔's avatar
曹高翔 committed
802
803
def GetPage(before=None, after=None):
    if before and after:
曹高翔's avatar
曹高翔 committed
804
        return False
Zheng Yile's avatar
Zheng Yile committed
805
806
    uiMain.progressBarPack.setValue(0)
    uiMain.progressBarPack.show()
807
808
    uiMain.pushButtonPackNext.setEnabled(False)
    uiMain.pushButtonPackPrevious.setEnabled(False)
809

810
    def PackInfoRecv(packInfo):
811
812
        if not packInfo:
            uiMain.progressBarPack.hide()
Zheng Yile's avatar
Zheng Yile committed
813
            return
814
        variables["packInfo"] = packInfo
Zheng Yile's avatar
Zheng Yile committed
815
        variables["packInfo"]["nodes"].reverse()
曹高翔's avatar
曹高翔 committed
816
817
818
819
820
821
        if before:
            variables["pageNumber"] += 1
        elif after:
            variables["pageNumber"] -= 1
        else:
            variables["pageNumber"] = 1
822
823
824
825
        uiMain.progressBarPack.hide()
        UpdatePage()

    def ErrorRecv(e: codiaError):
826
        ErrorDisplay(e, error_translate, "获取失败")
827
        uiMain.progressBarPack.hide()
曹高翔's avatar
曹高翔 committed
828
829
830
831
832
833
834
        try:
            UpdatePage()
        except:
            pass

    GetPack(before=before, after=after, InfoRecv=PackInfoRecv, ErrorRecv=ErrorRecv)

835
836

def GetPackWidget(data: dict):
曹高翔's avatar
曹高翔 committed
837
    widget = QWidget()
838
    layoutPackMain = QHBoxLayout()
839
840
841
    layoutPackRight = QVBoxLayout()
    layoutPackRightUp = QHBoxLayout()
    layoutPackRightDown = QHBoxLayout()
Zheng Yile's avatar
Zheng Yile committed
842
843
    if data["codingExercises"]:
        total = data["codingExercises"]["totalCount"]
844
845
        hasDone = data["codingExercises"]["viewerPassedCount"]
        if total == hasDone:
846
            labelPackFinish = QLabel("已完成")
847
            labelPackFinish.setPalette(Palette[QPalette.Text]["green"])
Zheng Yile's avatar
Zheng Yile committed
848
        else:
849
            labelPackFinish = QLabel("未完成")
850
851
            labelPackFinish.setPalette(Palette[QPalette.Text]["red"])
        labelPackHasDoneDivTotal = QLabel(f"已完成/总计: {hasDone}/{total}")
Zheng Yile's avatar
Zheng Yile committed
852
        if data["due"]:
曹高翔's avatar
曹高翔 committed
853
            endTimeText = (
曹高翔's avatar
曹高翔 committed
854
855
                    datetime.strptime(search(r"^[^.]*", data["due"].replace("T", " ")).group(), "%Y-%m-%d %H:%M:%S")
                    + timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")
曹高翔's avatar
曹高翔 committed
856
857
        else:
            endTimeText = "无限制"
858

Zheng Yile's avatar
Zheng Yile committed
859
        if data["createdAt"]:
曹高翔's avatar
曹高翔 committed
860
861
862
863
864
            beginTimeText = (datetime.strptime(search(r"^[^.]*", data["createdAt"].replace("T", " ")).group(),
                                               "%Y-%m-%d %H:%M:%S")
                             + timedelta(hours=8)).strftime("%Y-%m-%d %H:%M:%S")
        else:
            beginTimeText = "无限制"
Zheng Yile's avatar
Zheng Yile committed
865
    else:
866
867
        endTimeText = ""
        beginTimeText = ""
868
        labelPackFinish = QLabel("无权限")
869
        labelPackFinish.setPalette(Palette[QPalette.Text]["gray"])
870
        labelPackHasDoneDivTotal = QLabel("")
871
        widget.setEnabled(False)
872

873
874
    labelPackName = QLabel(data["name"])
    labelPackBegin = QLabel("开始时间")
875
    labelPackBeginTime = QLabel(beginTimeText)
876
    labelPackEnd = QLabel("截止时间")
877
    labelPackEndTime = QLabel(endTimeText)
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894

    layoutPackRightUp.addWidget(labelPackName)
    layoutPackRightUp.addWidget(labelPackBegin)
    layoutPackRightUp.addWidget(labelPackEnd)
    layoutPackRightUp.setStretchFactor(labelPackName, 4)
    layoutPackRightUp.setStretchFactor(labelPackBegin, 4)
    layoutPackRightUp.setStretchFactor(labelPackEnd, 4)

    layoutPackRightDown.addWidget(labelPackHasDoneDivTotal)
    layoutPackRightDown.addWidget(labelPackBeginTime)
    layoutPackRightDown.addWidget(labelPackEndTime)
    layoutPackRightDown.setStretchFactor(labelPackHasDoneDivTotal, 4)
    layoutPackRightDown.setStretchFactor(labelPackBeginTime, 4)
    layoutPackRightDown.setStretchFactor(labelPackEndTime, 4)

    layoutPackRight.addLayout(layoutPackRightUp)
    layoutPackRight.addLayout(layoutPackRightDown)