Guest User

Untitled

a guest
May 27th, 2018
175
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 63.51 KB | None | 0 0
  1. {
  2. "cells": [
  3. {
  4. "cell_type": "code",
  5. "execution_count": 1,
  6. "metadata": {},
  7. "outputs": [],
  8. "source": [
  9. "from PyQt5 import QtCore, QtWidgets, QtGui\n",
  10. "import sys, math, os, time, re, sqlite3, hashlib"
  11. ]
  12. },
  13. {
  14. "cell_type": "code",
  15. "execution_count": 2,
  16. "metadata": {},
  17. "outputs": [],
  18. "source": [
  19. "class User:\n",
  20. " \n",
  21. " def __init__(self, db, login: str):\n",
  22. " self.db = db\n",
  23. " self.login = login\n",
  24. " self.password = hashlib.md5().hexdigest()\n",
  25. " self.upload()\n",
  26. " \n",
  27. " def setLogin(self, newLogin: str):\n",
  28. " self.login = newLogin\n",
  29. " \n",
  30. " def setPassword(self, newPassword: str):\n",
  31. " self.password = str(newPassword)\n",
  32. " \n",
  33. " def setAvatar(self, newAvatar: str) -> bool:\n",
  34. " try:\n",
  35. " self.avatarUrl = newAvatar\n",
  36. " pixAvatar = QtGui.QPixmap('Avatars/' + self.avatarUrl)\n",
  37. " self.avatar = QtGui.QIcon(pixAvatar)\n",
  38. " return True\n",
  39. " except:\n",
  40. " return False\n",
  41. " \n",
  42. " def registerUser(self) -> int:\n",
  43. " self.userId = self.db.registerUser(self)\n",
  44. " return self.userId\n",
  45. " \n",
  46. " def upload(self) -> bool:\n",
  47. " if self.db.userIsRegistered(self):\n",
  48. " try:\n",
  49. " self.db.cursor.execute(\"SELECT `user_id`, `user_password`, `user_avatar`, `user_progress` FROM `users` WHERE `user_login` = '{}'\".format(self.login))\n",
  50. " row = self.db.cursor.fetchone()\n",
  51. " self.userId = row[0]\n",
  52. " self.password = row[1]\n",
  53. " self.setAvatar(row[2])\n",
  54. " self.progress = row[3]\n",
  55. " return True\n",
  56. " finally:\n",
  57. " pass\n",
  58. " return False\n",
  59. " \n",
  60. " def deleteUser(self):\n",
  61. " self.db.deleteUser(self)\n",
  62. " self.__del__()"
  63. ]
  64. },
  65. {
  66. "cell_type": "code",
  67. "execution_count": 3,
  68. "metadata": {},
  69. "outputs": [],
  70. "source": [
  71. "class Database():\n",
  72. " users = list()\n",
  73. " \n",
  74. " def __init__(self, statusBar: QtWidgets.QStatusBar, progressBar: QtWidgets.QProgressBar, enterWindow):\n",
  75. " self.statusBar = statusBar\n",
  76. " self.progressBar = progressBar\n",
  77. " self.enterWindow = enterWindow\n",
  78. " \n",
  79. " self.progressBar.setValue(0)\n",
  80. " self.statusBar.showMessage(\"Подключение к базе данных...\")\n",
  81. " self.connection = sqlite3.connect(\"nn.db\")\n",
  82. " self.cursor = self.connection.cursor()\n",
  83. " \n",
  84. " self.progressBar.setValue(self.progressBar.maximum() * (1 / 7))\n",
  85. "\n",
  86. " self.statusBar.showMessage(\"Сканирование имеющихся таблиц...\")\n",
  87. " self.cursor.execute(\"SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT LIKE 'sqlite_%'\")\n",
  88. " existingTables = tuple(map(lambda row: row[0], self.cursor.fetchall()))\n",
  89. " self.progressBar.setValue(self.progressBar.maximum() * (2 / 7))\n",
  90. " if \"users\" not in existingTables:\n",
  91. " self.statusBar.showMessage(\"Создание таблицы users...\")\n",
  92. " self.cursor.execute(\"CREATE TABLE `users` (\"\n",
  93. " \"`user_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\"\n",
  94. " \"`user_login` TEXT DEFAULT '' UNIQUE,\"\n",
  95. " \"`user_password` TEXT DEFAULT '\" + hashlib.md5().hexdigest() + \"',\"\n",
  96. " \"`user_avatar` TEXT DEFAULT '001-man-13.png',\"\n",
  97. " \"`user_progress` REAL DEFAULT 0.0\"\n",
  98. " \")\")\n",
  99. " self.progressBar.setValue(self.progressBar.maximum() * (3 / 7))\n",
  100. " if \"saves\" not in existingTables:\n",
  101. " self.statusBar.showMessage(\"Создание таблицы saves...\")\n",
  102. " self.cursor.execute(\"CREATE TABLE `saves` (\"\n",
  103. " \"`user_id` INTEGER NOT NULL,\"\n",
  104. " \"`type` TEXT DEFAULT '',\"\n",
  105. " \"`data` TEXT DEFAULT '',\"\n",
  106. " \"`course_id` INTEGER NOT NULL,\"\n",
  107. " \"`exercise_id` INTEGER NULL,\"\n",
  108. " \"FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`) \"\n",
  109. " \"ON DELETE CASCADE \"\n",
  110. " \"ON UPDATE CASCADE\"\n",
  111. " \")\")\n",
  112. " self.progressBar.setValue(self.progressBar.maximum() * (4 / 7))\n",
  113. " if \"courses\" not in existingTables:\n",
  114. " self.statusBar.showMessage(\"Создание таблицы courses...\")\n",
  115. " self.cursor.execute(\"CREATE TABLE `courses` (\"\n",
  116. " \"`course_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\"\n",
  117. " \"`face` TEXT DEFAULT 'book.png',\"\n",
  118. " \"`author` TEXT DEFAULT 'Пользователь',\"\n",
  119. " \"`title` TEXT DEFAULT '',\"\n",
  120. " \"`description` TEXT DEFAULT ''\"\n",
  121. " \")\")\n",
  122. " self.progressBar.setValue(self.progressBar.maximum() * (5 / 7))\n",
  123. " if \"pages\" not in existingTables:\n",
  124. " self.statusBar.showMessage(\"Создание таблицы pages...\")\n",
  125. " self.cursor.execute(\"CREATE TABLE `pages` (\"\n",
  126. " \"`course_id` INTEGER NOT NULL,\"\n",
  127. " \"`page` INTEGER DEFAULT 1,\"\n",
  128. " \"`group` INTEGER NOT NULL,\"\n",
  129. " \"`title` TEXT DEFAULT '',\"\n",
  130. " \"`data` TEXT DEFAULT '',\"\n",
  131. " \"FOREIGN KEY (`course_id`) REFERENCES `courses`(`course_id`) \"\n",
  132. " \"ON DELETE CASCADE \"\n",
  133. " \"ON UPDATE CASCADE\"\n",
  134. " \")\")\n",
  135. " self.progressBar.setValue(self.progressBar.maximum() * (6 / 7))\n",
  136. " if \"exercises\" not in existingTables:\n",
  137. " self.statusBar.showMessage(\"Создание таблицы exercises...\")\n",
  138. " self.cursor.execute(\"CREATE TABLE `exercises` (\"\n",
  139. " \"`exercise_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,\"\n",
  140. " \"`course_id` INTEGER NOT NULL,\"\n",
  141. " \"`page` INTEGER NOT NULL,\"\n",
  142. " \"`group` INTEGER NOT NULL,\"\n",
  143. " \"`description` TEXT DEFAULT '',\"\n",
  144. " \"`type` TEXT DEFAULT '',\"\n",
  145. " \"`data` TEXT DEFAULT '',\"\n",
  146. " \"FOREIGN KEY (`course_id`) REFERENCES `courses`(`course_id`)\"\n",
  147. " \"ON DELETE CASCADE \"\n",
  148. " \"ON UPDATE CASCADE\"\n",
  149. " \")\")\n",
  150. " self.progressBar.setValue(self.progressBar.maximum())\n",
  151. " self.uploadExistsUsers()\n",
  152. " \n",
  153. " def __del__(self):\n",
  154. " try:\n",
  155. " self.cursor.close()\n",
  156. " self.connection.close()\n",
  157. " except:\n",
  158. " pass\n",
  159. " \n",
  160. " def offerToEnter(self):\n",
  161. " self.enterWindow.show()\n",
  162. " \n",
  163. " def uploadExistsUsers(self):\n",
  164. " self.progressBar.setValue(0)\n",
  165. " self.statusBar.showMessage(\"Загрузка пользователей...\")\n",
  166. " self.cursor.execute(\"SELECT `user_login` FROM `users`\")\n",
  167. " rows = self.cursor.fetchall()\n",
  168. " l = len(rows)\n",
  169. " for i in range(l):\n",
  170. " foundedUser = User(self, rows[i][0])\n",
  171. " self.users.append(foundedUser)\n",
  172. " self.progressBar.setValue(self.progressBar.maximum() * (i + 1) / l)\n",
  173. " self.progressBar.setValue(self.progressBar.maximum())\n",
  174. " \n",
  175. " def userIsRegistered(self, user: User) -> bool:\n",
  176. " self.cursor.execute(\"SELECT `user_login` FROM `users`\")\n",
  177. " rows = self.cursor.fetchall()\n",
  178. " for row in rows:\n",
  179. " if row[0] == user.login:\n",
  180. " return True\n",
  181. " return False\n",
  182. " \n",
  183. " def registerUser(self, user: User) -> int:\n",
  184. " try:\n",
  185. " if not self.userIsRegistered(user):\n",
  186. " self.users.append(user)\n",
  187. " self.cursor.execute(\"INSERT INTO `users` (`user_login`, `user_password`, `user_avatar`) VALUES ('{}', '{}', '{}')\".format(user.login, user.password, user.avatarUrl))\n",
  188. " else:\n",
  189. " self.cursor.execute(\"UPDATE `users` SET `user_password` = '{}', `user_avatar` = '{}' WHERE `user_login` = '{}'\".format(user.password, user.avatarUrl, user.login))\n",
  190. " self.connection.commit()\n",
  191. " user.upload()\n",
  192. " return user.userId\n",
  193. " finally:\n",
  194. " return -1\n",
  195. " \n",
  196. " def deleteUser(self, user: User) -> bool:\n",
  197. " try:\n",
  198. " if self.userIsRegistered(user):\n",
  199. " self.users.remove(user)\n",
  200. " self.cursor.execute(\"DELETE FROM `users` WHERE `user_login` = '{}'\".format(user.login))\n",
  201. " self.connection.commit()\n",
  202. " return True\n",
  203. " finally:\n",
  204. " return False"
  205. ]
  206. },
  207. {
  208. "cell_type": "code",
  209. "execution_count": 4,
  210. "metadata": {},
  211. "outputs": [],
  212. "source": [
  213. "loginRegExp = QtCore.QRegExp(r\"[a-zA-Zа-яА-Я\\_\\$][a-zA-Zа-яА-Я\\_\\$\\-0-9]*\")\n",
  214. "currentUser = None\n",
  215. "mainFrame = None"
  216. ]
  217. },
  218. {
  219. "cell_type": "code",
  220. "execution_count": 5,
  221. "metadata": {},
  222. "outputs": [],
  223. "source": [
  224. "class StyledLabel(QtWidgets.QLabel):\n",
  225. " \n",
  226. " def __init__(self, line: str=\"\", parent=None):\n",
  227. " super().__init__(line, parent)"
  228. ]
  229. },
  230. {
  231. "cell_type": "code",
  232. "execution_count": 6,
  233. "metadata": {},
  234. "outputs": [],
  235. "source": [
  236. "class RegistrationWindow(QtWidgets.QWidget):\n",
  237. " \n",
  238. " def __init__(self, enterWindow):\n",
  239. " super().__init__()\n",
  240. " self.setWindowTitle(\"Регистрация\")\n",
  241. " self.enterWindow = enterWindow\n",
  242. " self.newLogin = enterWindow.loginEdit.text()\n",
  243. " \n",
  244. " self.vbox = QtWidgets.QVBoxLayout(self)\n",
  245. " self.hbox1 = QtWidgets.QHBoxLayout()\n",
  246. " self.hbox2 = QtWidgets.QHBoxLayout()\n",
  247. " self.hbox3 = QtWidgets.QHBoxLayout()\n",
  248. " self.buttonGo = QtWidgets.QPushButton(\"Зарегистрироваться\")\n",
  249. " self.buttonGo.clicked.connect(self.register)\n",
  250. " self.label1 = StyledLabel(\"Аватар:\")\n",
  251. " self.label1.setFixedWidth(96)\n",
  252. " self.label1.setAlignment(QtCore.Qt.AlignRight)\n",
  253. " self.label2 = StyledLabel(\"Логин:\")\n",
  254. " self.label2.setFixedWidth(96)\n",
  255. " self.label2.setAlignment(QtCore.Qt.AlignRight)\n",
  256. " self.label3 = StyledLabel(\"Пароль:\")\n",
  257. " self.label3.setFixedWidth(96)\n",
  258. " self.label3.setAlignment(QtCore.Qt.AlignRight)\n",
  259. " self.lineEdit = QtWidgets.QLineEdit()\n",
  260. " self.lineEdit.setValidator(QtGui.QRegExpValidator(loginRegExp))\n",
  261. " self.lineEdit.setMaxLength(50)\n",
  262. " self.avatarsBox = QtWidgets.QComboBox()\n",
  263. " self.avatarsBox.setIconSize(QtCore.QSize(48, 48))\n",
  264. " pixList = os.listdir(\"Avatars\")\n",
  265. " pixList.sort()\n",
  266. " for pixName in pixList:\n",
  267. " self.avatarsBox.addItem(QtGui.QIcon(\"Avatars/\" + pixName), pixName)\n",
  268. " self.pwdEdit = QtWidgets.QLineEdit()\n",
  269. " self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)\n",
  270. " self.pwdEdit.setMaxLength(32)\n",
  271. " self.buttonShowPassword = QtWidgets.QCheckBox()\n",
  272. " self.buttonShowPassword.stateChanged.connect(self.checked)\n",
  273. " \n",
  274. " self.hbox1.addWidget(self.label1)\n",
  275. " self.hbox1.addWidget(self.avatarsBox)\n",
  276. " self.hbox2.addWidget(self.label2)\n",
  277. " self.hbox2.addWidget(self.lineEdit)\n",
  278. " self.hbox3.addWidget(self.label3)\n",
  279. " self.hbox3.addWidget(self.pwdEdit)\n",
  280. " self.hbox3.addWidget(self.buttonShowPassword)\n",
  281. " self.vbox.addLayout(self.hbox1)\n",
  282. " self.vbox.addLayout(self.hbox2)\n",
  283. " self.vbox.addLayout(self.hbox3)\n",
  284. " self.vbox.addWidget(self.buttonGo)\n",
  285. "\n",
  286. " def checked(self, newState):\n",
  287. " if newState == QtCore.Qt.Checked:\n",
  288. " self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Normal)\n",
  289. " else:\n",
  290. " self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)\n",
  291. "\n",
  292. " def showEvent(self, event):\n",
  293. " global db\n",
  294. " db.statusBar.showMessage(\"Регистрация пользователя...\")\n",
  295. " self.desktop = QtWidgets.QApplication.desktop()\n",
  296. " x = (self.desktop.width() - self.width()) // 2\n",
  297. " y = (self.desktop.height() - self.height()) // 2\n",
  298. " self.move(x, y)\n",
  299. "\n",
  300. " def register(self):\n",
  301. " global db\n",
  302. " newUser = User(db, self.lineEdit.text())\n",
  303. " newUser.setAvatar(self.avatarsBox.currentText())\n",
  304. " newUser.setPassword(hashlib.md5(self.pwdEdit.text().encode()).hexdigest())\n",
  305. " db.registerUser(newUser)\n",
  306. " self.hide()\n",
  307. " self.enterWindow.uploadUsers()\n",
  308. " self.enterWindow.show()"
  309. ]
  310. },
  311. {
  312. "cell_type": "code",
  313. "execution_count": 7,
  314. "metadata": {},
  315. "outputs": [],
  316. "source": [
  317. "class UsersListItem(QtWidgets.QListWidgetItem):\n",
  318. "\n",
  319. " def __init__(self, user: User, parent=None):\n",
  320. " super().__init__(parent)\n",
  321. " self.user = user\n",
  322. " self.setSizeHint(QtCore.QSize(0, 64))\n",
  323. "\n",
  324. " def updateItem(self):\n",
  325. " self.user.upload()\n",
  326. " self.setIcon(self.user.avatar)\n",
  327. " self.setText(\"{0}\\nПрогресс: {1: >5.1f}%\\n{2:\\u25CB<10}\".format(self.user.login, int(self.user.progress * 10) / 10.0, \"\\u25CF\" * int(self.user.progress // 10)))\n",
  328. "\n",
  329. " def updateUser(self, newUser: User):\n",
  330. " self.user = newUser\n",
  331. " self.updateItem()"
  332. ]
  333. },
  334. {
  335. "cell_type": "code",
  336. "execution_count": 8,
  337. "metadata": {},
  338. "outputs": [],
  339. "source": [
  340. "class UsersList(QtWidgets.QListWidget):\n",
  341. " selectedItem = None\n",
  342. " autoSelect = False\n",
  343. "\n",
  344. " def __init__(self, enterWindow=None):\n",
  345. " super().__init__(enterWindow)\n",
  346. " self.enterWindow = enterWindow\n",
  347. " self.setSortingEnabled(True)\n",
  348. " self.setAlternatingRowColors(True)\n",
  349. " self.setIconSize(QtCore.QSize(48, 48))\n",
  350. " self.itemSelectionChanged.connect(self.itemIsSelected)\n",
  351. " self.itemClicked.connect(self.itemIsClicked)\n",
  352. "\n",
  353. " def updateList(self, enteredLogin: str=\"\"):\n",
  354. " global db\n",
  355. " self.clear()\n",
  356. " if enteredLogin == \"\":\n",
  357. " for user in db.users:\n",
  358. " item = UsersListItem(user)\n",
  359. " item.updateItem()\n",
  360. " self.addItem(item)\n",
  361. " else:\n",
  362. " enteredLogin = enteredLogin.lower()\n",
  363. " for user in db.users:\n",
  364. " if user.login.lower().find(enteredLogin) != -1:\n",
  365. " item = UsersListItem(user)\n",
  366. " item.updateItem()\n",
  367. " self.addItem(item)\n",
  368. " if user is db.users[0]:\n",
  369. " self.autoSelect = True\n",
  370. " item.setSelected(True)\n",
  371. " self.autoSelect = False\n",
  372. " \n",
  373. " def itemIsSelected(self):\n",
  374. " if len(self.selectedItems()) > 0:\n",
  375. " self.selectedItem = self.selectedItems()[0]\n",
  376. " if not self.autoSelect:\n",
  377. " self.enterWindow.loginEdit.setText(self.selectedItem.user.login)\n",
  378. " self.enterWindow.loginEdit.setFocus(True)\n",
  379. " \n",
  380. " def itemIsClicked(self, clickedItem):\n",
  381. " if len(self.selectedItems()) > 0:\n",
  382. " self.selectedItem = self.selectedItems()[0]\n",
  383. " self.enterWindow.loginEdit.setText(self.selectedItem.user.login)\n",
  384. " self.enterWindow.loginEdit.setFocus(True)\n",
  385. " \n",
  386. " def deleteItem(self, item: UsersListItem):\n",
  387. " try:\n",
  388. " self.removeItemWidget(item)\n",
  389. " item.user.deleteUser()\n",
  390. " finally:\n",
  391. " return"
  392. ]
  393. },
  394. {
  395. "cell_type": "code",
  396. "execution_count": 9,
  397. "metadata": {},
  398. "outputs": [],
  399. "source": [
  400. "class EnterWindow(QtWidgets.QWidget):\n",
  401. "\n",
  402. " def __init__(self):\n",
  403. " super().__init__()\n",
  404. " self.setWindowTitle(\"Вход\")\n",
  405. "\n",
  406. " self.vbox = QtWidgets.QVBoxLayout(self)\n",
  407. " self.loginEdit = QtWidgets.QLineEdit()\n",
  408. " self.loginEdit.setObjectName(\"loginEdit\")\n",
  409. " self.loginEdit.setPlaceholderText(\"Введите логин\")\n",
  410. " self.loginEdit.setValidator(QtGui.QRegExpValidator(loginRegExp))\n",
  411. " self.loginEdit.textChanged.connect(self.loginChanged)\n",
  412. " self.vbox.addWidget(self.loginEdit)\n",
  413. "\n",
  414. " self.usersList = UsersList(self)\n",
  415. " self.vbox.addWidget(self.usersList)\n",
  416. " \n",
  417. " self.hbox = QtWidgets.QHBoxLayout()\n",
  418. " self.pwdEdit = QtWidgets.QLineEdit()\n",
  419. " self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)\n",
  420. " self.pwdEdit.setMaxLength(32)\n",
  421. " self.pwdEdit.setPlaceholderText(\"Введите пароль\")\n",
  422. " self.hbox.addWidget(self.pwdEdit)\n",
  423. " self.buttonShowPassword = QtWidgets.QCheckBox()\n",
  424. " self.buttonShowPassword.stateChanged.connect(self.checked)\n",
  425. " self.hbox.addWidget(self.buttonShowPassword)\n",
  426. " self.vbox.addLayout(self.hbox)\n",
  427. " \n",
  428. " self.buttonGo = QtWidgets.QPushButton(\"Войти\")\n",
  429. " self.buttonGo.clicked.connect(self.enterUser)\n",
  430. " self.vbox.addWidget(self.buttonGo)\n",
  431. " \n",
  432. " self.buttonNew = QtWidgets.QPushButton(\"Новый пользователь\")\n",
  433. " self.buttonNew.clicked.connect(self.createUser)\n",
  434. " self.vbox.addWidget(self.buttonNew)\n",
  435. " \n",
  436. " self.buttonDelete = QtWidgets.QPushButton(\"Удалить пользователя\")\n",
  437. " self.buttonDelete.clicked.connect(self.deleteUser)\n",
  438. " self.vbox.addWidget(self.buttonDelete)\n",
  439. " \n",
  440. " def checked(self, newState):\n",
  441. " if newState == QtCore.Qt.Checked:\n",
  442. " self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Normal)\n",
  443. " else:\n",
  444. " self.pwdEdit.setEchoMode(QtWidgets.QLineEdit.Password)\n",
  445. " \n",
  446. " def showEvent(self, event):\n",
  447. " global db\n",
  448. " db.statusBar.showMessage(\"Выбор пользователя...\")\n",
  449. " self.desktop = QtWidgets.QApplication.desktop()\n",
  450. " x = (self.desktop.width() - self.width()) // 2\n",
  451. " y = (self.desktop.height() - self.height()) // 2\n",
  452. " self.move(x, y)\n",
  453. " \n",
  454. " def uploadUsers(self):\n",
  455. " self.usersList.updateList()\n",
  456. " \n",
  457. " def loginChanged(self, enteredLogin):\n",
  458. " self.usersList.updateList(enteredLogin)\n",
  459. " if self.usersList.count() > 0 and len(enteredLogin) > 0:\n",
  460. " self.usersList.autoSelect = True\n",
  461. " self.usersList.item(0).setSelected(True)\n",
  462. " self.usersList.autoSelect = False\n",
  463. " \n",
  464. " def enterUser(self):\n",
  465. " if self.usersList.selectedItem is None:\n",
  466. " QtWidgets.QMessageBox.warning(self, \"Ошибка\", \"Выберите пользователя.\")\n",
  467. " else:\n",
  468. " pwd = hashlib.md5(self.pwdEdit.text().encode()).hexdigest()\n",
  469. " if pwd == self.usersList.selectedItem.user.password:\n",
  470. " global db, currentUser, mainFrame\n",
  471. " currentUser = self.usersList.selectedItem.user\n",
  472. " self.hide()\n",
  473. " mainFrame.menuBar.setEnabled(True)\n",
  474. " db.statusBar.showMessage(\"Добро пожаловать, {0:s}!\".format(currentUser.login))\n",
  475. " mainFrame.reloadChoiceList()\n",
  476. " mainFrame.reloadUser()\n",
  477. " else:\n",
  478. " QtWidgets.QMessageBox.warning(self, \"Ошибка\", \"Вы ввели неверный пароль пользователя.\")\n",
  479. " \n",
  480. " def closeEvent(self, event):\n",
  481. " global currentUser\n",
  482. " if currentUser is None:\n",
  483. " QtWidgets.QApplication.quit()\n",
  484. " else:\n",
  485. " event.accept()\n",
  486. " \n",
  487. " def createUser(self):\n",
  488. " self.hide()\n",
  489. " self.registrationWindow = RegistrationWindow(self)\n",
  490. " self.registrationWindow.show()\n",
  491. " \n",
  492. " def deleteUser(self):\n",
  493. " try:\n",
  494. " global db\n",
  495. " user = self.usersList.selectedItem.user\n",
  496. " if db.userIsRegistered(user):\n",
  497. " self.usersList.deleteItem(self.usersList.selectedItem)\n",
  498. " self.usersList.updateList()\n",
  499. " self.loginEdit.setText(\"\")\n",
  500. " finally:\n",
  501. " return"
  502. ]
  503. },
  504. {
  505. "cell_type": "code",
  506. "execution_count": 10,
  507. "metadata": {},
  508. "outputs": [],
  509. "source": [
  510. "class ProgressBar(QtWidgets.QProgressBar):\n",
  511. " progressBarBrightText = False\n",
  512. " \n",
  513. " def __init__(self, parent=None):\n",
  514. " super().__init__(parent)\n",
  515. " self.valueChanged.connect(self.loadingUpdate)\n",
  516. " \n",
  517. " def loadingUpdate(self, value):\n",
  518. " self.setFormat(\"{0:d}%\".format(int(self.value() * 100 / self.maximum())))\n",
  519. " if value * 2 < self.maximum() + self.fontMetrics().width(self.format()) and self.progressBarBrightText:\n",
  520. " self.setStyleSheet(\"color: rgb(32, 32, 32);\")\n",
  521. " self.progressBarBrightText = False\n",
  522. " elif value * 2 >= self.maximum() + self.fontMetrics().width(self.format()) and not self.progressBarBrightText:\n",
  523. " self.setStyleSheet(\"color: white;\")\n",
  524. " self.progressBarBrightText = True"
  525. ]
  526. },
  527. {
  528. "cell_type": "code",
  529. "execution_count": 11,
  530. "metadata": {},
  531. "outputs": [],
  532. "source": [
  533. "class ProgressBarF(QtWidgets.QProgressBar):\n",
  534. " progressBarBrightText = False\n",
  535. " \n",
  536. " def __init__(self, parent=None):\n",
  537. " super().__init__(parent)\n",
  538. " self.valueChanged.connect(self.loadingUpdate)\n",
  539. " \n",
  540. " def loadingUpdate(self, value):\n",
  541. " self.setFormat(\"{0:.2f}%\".format(self.value() * 100 / self.maximum()))\n",
  542. " if value * 2 < self.maximum() + self.fontMetrics().width(self.format()) and self.progressBarBrightText:\n",
  543. " self.setStyleSheet(\"color: rgb(32, 32, 32);\")\n",
  544. " self.progressBarBrightText = False\n",
  545. " elif value * 2 >= self.maximum() + self.fontMetrics().width(self.format()) and not self.progressBarBrightText:\n",
  546. " self.setStyleSheet(\"color: white;\")\n",
  547. " self.progressBarBrightText = True"
  548. ]
  549. },
  550. {
  551. "cell_type": "code",
  552. "execution_count": 12,
  553. "metadata": {},
  554. "outputs": [],
  555. "source": [
  556. "class CourseLabel(QtWidgets.QLabel): \n",
  557. " mouse = 0 # leaveEvent ~ 0, enterEvent ~ 1, mousePressEvent ~ 2\n",
  558. " \n",
  559. " def __init__(self, course_id: int):\n",
  560. " super().__init__()\n",
  561. " global db\n",
  562. " db.cursor.execute('SELECT face, author, title, description FROM courses WHERE course_id = {}'.format(course_id))\n",
  563. " row = db.cursor.fetchone()\n",
  564. " self.course_id, self.face, self.author, self.title, self.description = course_id, *row\n",
  565. " self.pixmap = QtGui.QPixmap('Images/' + self.face).scaledToHeight(240)\n",
  566. " self.setFixedHeight(256)\n",
  567. " \n",
  568. " def paintEvent(self, event):\n",
  569. " painter = QtGui.QPainter(self)\n",
  570. " painter.setBackgroundMode(QtCore.Qt.TransparentMode)\n",
  571. " painter.setRenderHint(QtGui.QPainter.Antialiasing, True)\n",
  572. " if self.mouse == 0:\n",
  573. " painter.setOpacity(0.125 if self.course_id & 0x01 else 0.0625)\n",
  574. " elif self.mouse == 1:\n",
  575. " painter.setOpacity(0.1875)\n",
  576. " else:\n",
  577. " painter.setOpacity(0)\n",
  578. " painter.fillRect(0, 0, self.width() - 2, self.height() - 1, QtGui.QBrush(QtCore.Qt.white, QtCore.Qt.SolidPattern))\n",
  579. " painter.setOpacity(1.0)\n",
  580. " painter.drawPixmap(8, 8, self.pixmap.width(), self.pixmap.height(), self.pixmap)\n",
  581. " painter.setFont(QtGui.QFont('Monaco', 10, QtGui.QFont.Bold))\n",
  582. " painter.setPen(QtGui.QPen(QtCore.Qt.white, 1))\n",
  583. " painter.drawText(\n",
  584. " QtCore.QRect(self.pixmap.width() + 16, 8, self.width() - self.pixmap.width() - 24, 240),\n",
  585. " QtCore.Qt.AlignLeft | QtCore.Qt.TextWordWrap,\n",
  586. " 'Автор: {}\\nНазвание: {}'.format(self.author, self.title)\n",
  587. " )\n",
  588. " \n",
  589. " def showEvent(self, event):\n",
  590. " self.update()\n",
  591. " \n",
  592. " def resizeEvent(self, event):\n",
  593. " self.update()\n",
  594. " \n",
  595. " def enterEvent(self, event):\n",
  596. " self.mouse = 1\n",
  597. " self.update()\n",
  598. " self.setCursor(QtCore.Qt.PointingHandCursor)\n",
  599. " \n",
  600. " def leaveEvent(self, event):\n",
  601. " self.mouse = 0\n",
  602. " self.update()\n",
  603. " self.setCursor(QtCore.Qt.ArrowCursor)\n",
  604. " \n",
  605. " def mousePressEvent(self, event):\n",
  606. " self.mouse = 2\n",
  607. " self.update()\n",
  608. " self.setCursor(QtCore.Qt.ArrowCursor)\n",
  609. " \"\"\"global mainFrame\n",
  610. " mainFrame.openCourse(self)\"\"\""
  611. ]
  612. },
  613. {
  614. "cell_type": "code",
  615. "execution_count": 13,
  616. "metadata": {},
  617. "outputs": [
  618. {
  619. "data": {
  620. "text/plain": [
  621. "'def CourseFrame(QtWidgets.QLabel):\\n \\n pass'"
  622. ]
  623. },
  624. "execution_count": 13,
  625. "metadata": {},
  626. "output_type": "execute_result"
  627. }
  628. ],
  629. "source": [
  630. "\"\"\"def CourseFrame(QtWidgets.QLabel):\n",
  631. " \n",
  632. " pass\"\"\""
  633. ]
  634. },
  635. {
  636. "cell_type": "code",
  637. "execution_count": 14,
  638. "metadata": {},
  639. "outputs": [],
  640. "source": [
  641. "class MainArea(QtWidgets.QScrollArea):\n",
  642. " \n",
  643. " def __init__(self, mainFrame = None):\n",
  644. " super().__init__(mainFrame)\n",
  645. " \n",
  646. " def resizeEvent(self, event):\n",
  647. " self.mainPanel.setFixedWidth(self.width() - 16)\n",
  648. " if self.courses:\n",
  649. " for courseLabel in self.courses:\n",
  650. " courseLabel.setFixedWidth(self.width() - 18)"
  651. ]
  652. },
  653. {
  654. "cell_type": "code",
  655. "execution_count": 15,
  656. "metadata": {},
  657. "outputs": [],
  658. "source": [
  659. "class MainFrame(QtWidgets.QWidget):\n",
  660. " \n",
  661. " def __init__(self, mainWindow=None):\n",
  662. " super().__init__(mainWindow)\n",
  663. " self.mainWindow = mainWindow\n",
  664. " global mainFrame\n",
  665. " mainFrame = self\n",
  666. "\n",
  667. " self.vbox = QtWidgets.QVBoxLayout(self)\n",
  668. " self.vbox.setContentsMargins(0, 0, 0, 0)\n",
  669. " self.vbox.setSpacing(0)\n",
  670. "\n",
  671. " # Нижняя строка состояния\n",
  672. " self.statusBar = QtWidgets.QStatusBar(self)\n",
  673. " self.statusBar.setObjectName(\"mainStatusBar\")\n",
  674. " self.statusBar.setFixedHeight(32)\n",
  675. " self.statusBar.setSizeGripEnabled(False)\n",
  676. " self.statusBar.setContentsMargins(0, 0, 3, 0)\n",
  677. "\n",
  678. " # Индикатор хода прогресса\n",
  679. " self.progressBar = ProgressBar(self.statusBar)\n",
  680. " self.progressBar.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)\n",
  681. " self.progressBar.setFixedWidth(160)\n",
  682. " self.progressBar.setRange(0, 160)\n",
  683. " self.statusBar.addPermanentWidget(self.progressBar)\n",
  684. " \n",
  685. " self.userLabel = QtWidgets.QLabel()\n",
  686. " self.userLabel.setObjectName(\"userLabel\")\n",
  687. " self.userLabel.setFixedHeight(100)\n",
  688. " self.userLabel.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)\n",
  689. " self.userLabel.setContentsMargins(4, 8, 4, 4)\n",
  690. " self.choiceList = QtWidgets.QTreeWidget()\n",
  691. " self.choiceList.setObjectName(\"choiceList\")\n",
  692. " self.choiceList.setHeaderHidden(True)\n",
  693. " self.choiceList.setAnimated(True)\n",
  694. " header = self.choiceList.header()\n",
  695. " header.setStretchLastSection(False)\n",
  696. " header.setSectionResizeMode(0, QtWidgets.QHeaderView.ResizeToContents)\n",
  697. " self.choiceList.setHeader(header)\n",
  698. " self.mainPanel = QtWidgets.QLabel()\n",
  699. " self.mainPanel.setObjectName('mainPanel')\n",
  700. " self.mainBox = QtWidgets.QVBoxLayout(self.mainPanel)\n",
  701. " self.mainBox.setContentsMargins(0, 0, 0, 0)\n",
  702. " self.mainBox.setSpacing(0)\n",
  703. " self.mainBox.setAlignment(QtCore.Qt.AlignHCenter)\n",
  704. " self.leftPanel = QtWidgets.QLabel()\n",
  705. " self.leftBox = QtWidgets.QVBoxLayout()\n",
  706. " self.leftBox.setContentsMargins(0, 0, 0, 0)\n",
  707. " self.leftBox.setSpacing(0)\n",
  708. " self.leftPanel.setLayout(self.leftBox)\n",
  709. " self.leftBox.addWidget(self.userLabel)\n",
  710. " self.leftBox.addWidget(self.choiceList)\n",
  711. " \n",
  712. " self.itemCourses = QtWidgets.QTreeWidgetItem(self.choiceList)\n",
  713. " self.itemCourses.setText(0, \"Курсы\")\n",
  714. " self.itemActiveCourses = QtWidgets.QTreeWidgetItem(self.itemCourses)\n",
  715. " self.itemActiveCourses.setText(0, \"Активные курсы\")\n",
  716. " self.itemNonactiveCourses = QtWidgets.QTreeWidgetItem(self.itemCourses)\n",
  717. " self.itemNonactiveCourses.setText(0, \"Закрытые курсы\")\n",
  718. " self.itemPrograms = QtWidgets.QTreeWidgetItem(self.choiceList)\n",
  719. " self.itemPrograms.setText(0, \"Python-программы\")\n",
  720. " \n",
  721. " # Режим пользователя\n",
  722. " self.splitter = QtWidgets.QSplitter()\n",
  723. " self.splitter.setOrientation(QtCore.Qt.Horizontal)\n",
  724. " self.splitter.addWidget(self.leftPanel)\n",
  725. " \n",
  726. " # Верхнее меню\n",
  727. " self.menuBar = QtWidgets.QMenuBar()\n",
  728. " self.menuBar.setFixedHeight(26)\n",
  729. " \n",
  730. " self.developerMenu = QtWidgets.QMenu(\"&Разработка\")\n",
  731. " self.developerMenu.setLayoutDirection(QtCore.Qt.LeftToRight)\n",
  732. " self.modeGroup = QtWidgets.QActionGroup(self.developerMenu)\n",
  733. " self.modeGroup.setExclusive(True)\n",
  734. " self.menuBar.addMenu(self.developerMenu)\n",
  735. " self.userMode = QtWidgets.QAction(\"Режим пользователя\", self.modeGroup)\n",
  736. " self.userMode.setCheckable(True)\n",
  737. " self.developerMode = QtWidgets.QAction(\"Режим разработчика\", self.modeGroup)\n",
  738. " self.developerMode.setCheckable(True)\n",
  739. " self.developerMenu.addAction(self.userMode)\n",
  740. " self.developerMenu.addAction(self.developerMode)\n",
  741. " self.userMode.setChecked(True)\n",
  742. " self.menuBar.setDisabled(True)\n",
  743. " self.modeGroup.triggered.connect(self.modeToggled)\n",
  744. " self.vbox.addWidget(self.menuBar)\n",
  745. " self.vbox.addWidget(self.splitter)\n",
  746. " self.vbox.addWidget(self.statusBar)\n",
  747. " \n",
  748. " # Режим разработчика\n",
  749. " self.developerWidget = QtWidgets.QWidget()\n",
  750. " self.developerLayout = QtWidgets.QVBoxLayout(self.developerWidget)\n",
  751. " self.developerLayout.setSpacing(0)\n",
  752. " self.developerLayout.setContentsMargins(0, 0, 0, 0)\n",
  753. " \n",
  754. " self.buttonsArea = QtWidgets.QScrollArea()\n",
  755. " self.buttonsArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\n",
  756. " self.buttonsArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)\n",
  757. " self.buttonsLabel = QtWidgets.QLabel()\n",
  758. " self.buttonsArea.setWidget(self.buttonsLabel)\n",
  759. " self.buttonsBox = QtWidgets.QHBoxLayout(self.buttonsLabel)\n",
  760. " self.buttonsBox.setContentsMargins(2, 2, 2, 2)\n",
  761. " self.buttonsBox.setSpacing(2)\n",
  762. " self.buttonExec = QtWidgets.QPushButton(\"Выполнить запрос (F5)\")\n",
  763. " self.buttonExec.setShortcut(QtCore.Qt.Key_F5)\n",
  764. " self.buttonExec.setIcon(QtGui.QIcon(\"Images/exec.png\"))\n",
  765. " self.buttonExec.setFixedWidth(210)\n",
  766. " self.buttonExec.clicked.connect(self.execCommand)\n",
  767. " self.buttonsBox.addWidget(self.buttonExec)\n",
  768. " self.buttonCommit = QtWidgets.QPushButton(\"Совершить транзакцию (F6)\")\n",
  769. " self.buttonCommit.setShortcut(QtCore.Qt.Key_F6)\n",
  770. " self.buttonCommit.setIcon(QtGui.QIcon(\"Images/commit.png\"))\n",
  771. " self.buttonCommit.setFixedWidth(240)\n",
  772. " self.buttonCommit.clicked.connect(self.commitCommand)\n",
  773. " self.buttonsBox.addWidget(self.buttonCommit)\n",
  774. " self.buttonClear = QtWidgets.QPushButton(\"Очистить консоль (Ctrl+R)\")\n",
  775. " self.buttonClear.setShortcut(QtCore.Qt.ControlModifier | QtCore.Qt.Key_R)\n",
  776. " self.buttonClear.setIcon(QtGui.QIcon(\"Images/clear.png\"))\n",
  777. " self.buttonClear.setFixedWidth(230)\n",
  778. " self.buttonClear.clicked.connect(self.clearCommand)\n",
  779. " self.buttonsBox.addWidget(self.buttonClear)\n",
  780. " self.buttonSave = QtWidgets.QPushButton(\"Сохранить SQL (Ctrl+S)\")\n",
  781. " self.buttonSave.setShortcut(QtCore.Qt.ControlModifier | QtCore.Qt.Key_S)\n",
  782. " self.buttonSave.setIcon(QtGui.QIcon(\"Images/save.png\"))\n",
  783. " self.buttonSave.setFixedWidth(220)\n",
  784. " self.buttonSave.clicked.connect(self.saveCommand)\n",
  785. " self.buttonsBox.addWidget(self.buttonSave)\n",
  786. " self.buttonsArea.setFixedHeight(30)\n",
  787. " self.buttonsLabel.setFixedSize(QtCore.QSize(self.buttonExec.width() + self.buttonCommit.width() + self.buttonClear.width() + self.buttonSave.width() + 10, 28))\n",
  788. " self.developerLayout.addWidget(self.buttonsArea)\n",
  789. " \n",
  790. " self.devSplitter = QtWidgets.QSplitter()\n",
  791. " self.devSplitter.setOrientation(QtCore.Qt.Vertical)\n",
  792. " self.devSplitter.setHandleWidth(4)\n",
  793. " self.developerLayout.addWidget(self.devSplitter)\n",
  794. " \n",
  795. " self.developerTextEdit = QtWidgets.QTextEdit()\n",
  796. " self.developerTextEdit.setObjectName(\"developerTextEdit\")\n",
  797. " self.developerTextEdit.setWordWrapMode(False)\n",
  798. " self.devSplitter.addWidget(self.developerTextEdit)\n",
  799. " \n",
  800. " self.consoleTextEdit = QtWidgets.QTextEdit()\n",
  801. " self.consoleTextEdit.setObjectName(\"consoleTextEdit\")\n",
  802. " self.consoleTextEdit.setReadOnly(True)\n",
  803. " self.consoleTextEdit.setWordWrapMode(False)\n",
  804. " self.devSplitter.addWidget(self.consoleTextEdit)\n",
  805. " \n",
  806. " def showEvent(self, event):\n",
  807. " self.update()\n",
  808. " \n",
  809. " def loadDatabase(self):\n",
  810. " global db\n",
  811. " db = Database(self.statusBar, self.progressBar, self.enterWindow)\n",
  812. " \n",
  813. " # Главная панель\n",
  814. " self.mainArea = MainArea()\n",
  815. " self.mainArea.setObjectName(\"mainArea\")\n",
  816. " self.mainArea.mainBox = self.mainBox\n",
  817. " self.mainArea.mainPanel = self.mainPanel\n",
  818. " self.mainArea.courses = []\n",
  819. " self.mainArea.setWidget(self.mainPanel)\n",
  820. " db.cursor.execute('SELECT course_id FROM courses')\n",
  821. " self.course_ids = [row[0] for row in db.cursor.fetchall()]\n",
  822. " self.courses = []\n",
  823. " height = 0\n",
  824. " for course_id in self.course_ids:\n",
  825. " course = CourseLabel(course_id)\n",
  826. " self.courses.append(course)\n",
  827. " self.mainBox.addWidget(course)\n",
  828. " height += course.height()\n",
  829. " \n",
  830. " # Режим пользователя\n",
  831. " self.splitter.addWidget(self.mainArea)\n",
  832. " self.splitter.setSizes((320, self.mainArea.width()))\n",
  833. " self.mainPanel.setFixedWidth(self.mainArea.width() - 16)\n",
  834. " self.mainPanel.setFixedHeight(height)\n",
  835. " for course in self.courses:\n",
  836. " course.setFixedWidth(self.mainArea.width() - 18)\n",
  837. " self.splitter.setHandleWidth(4)\n",
  838. " \n",
  839. " \"\"\"def openCourse(self, courseLabel: CourseLabel):\n",
  840. " self.currentCourseLabel = courseLabel\n",
  841. " self.hideListOfCourses()\n",
  842. " \n",
  843. " def hideListOfCourses(self):\n",
  844. " self.opacity1 = QtWidgets.QGraphicsOpacityEffect()\n",
  845. " self.mainArea.setGraphicsEffect(self.opacity1)\n",
  846. " self.anim1 = QtCore.QPropertyAnimation(self.opacity1, b\"opacity\")\n",
  847. " self.anim1.setDuration(250)\n",
  848. " self.anim1.setStartValue(1.0)\n",
  849. " self.anim1.setEndValue(0.0)\n",
  850. " self.anim1.start()\n",
  851. " self.anim1.finished.connect(self.showCourse)\n",
  852. " \n",
  853. " def showCourse(self):\n",
  854. " self.mainArea.hide()\n",
  855. " self.opacity2 = QtWidgets.QGraphicsOpacityEffect()\n",
  856. " \n",
  857. " # Открываем выбранный курс\n",
  858. " self.courseFrame = \n",
  859. " \n",
  860. " self.mainFrame.setGraphicsEffect(self.opacity2)\n",
  861. " self.mainFrame.setWindowOpacity(0.0)\n",
  862. " self.mainFrame.show()\n",
  863. " self.anim2 = QtCore.QPropertyAnimation(self.opacity2, b\"opacity\")\n",
  864. " self.anim2.setDuration(250)\n",
  865. " self.anim2.setStartValue(0.0)\n",
  866. " self.anim2.setEndValue(1.0)\n",
  867. " self.anim2.start()\n",
  868. " self.anim2.finished.connect(self.mainFrameIsVisible)\"\"\"\n",
  869. " \n",
  870. " def offerToEnter(self):\n",
  871. " global db\n",
  872. " db.offerToEnter()\n",
  873. " \n",
  874. " def modeToggled(self, action: QtWidgets.QAction):\n",
  875. " if self.userMode.isChecked():\n",
  876. " self.statusBar.showMessage(\"Режим пользователя.\")\n",
  877. " self.vbox.replaceWidget(self.developerWidget, self.splitter)\n",
  878. " self.developerWidget.setVisible(False)\n",
  879. " self.reloadUser()\n",
  880. " self.reloadChoiceList()\n",
  881. " self.splitter.setVisible(True)\n",
  882. " if self.developerMode.isChecked():\n",
  883. " self.statusBar.showMessage(\"Режим разработчика.\")\n",
  884. " self.vbox.replaceWidget(self.splitter, self.developerWidget)\n",
  885. " self.splitter.setVisible(False)\n",
  886. " self.developerWidget.setVisible(True)\n",
  887. " \n",
  888. " def reloadUser(self):\n",
  889. " self.userLabel.setText('<img src=\"Avatars/{}\" width=\"64\" height=\"64\" align=\"left\" /><span style=\"color: khaki; font-weight: bold\">&nbsp;{}</span><br><br>&nbsp;Прогресс: {:.1f}'.format(currentUser.avatarUrl, currentUser.login, currentUser.progress))\n",
  890. " \n",
  891. " def reloadChoiceList(self):\n",
  892. " for child in self.itemActiveCourses.takeChildren():\n",
  893. " self.itemActiveCourses.removeChild(child)\n",
  894. " for child in self.itemNonactiveCourses.takeChildren():\n",
  895. " self.itemActiveCourses.removeChild(child)\n",
  896. " global currentUser\n",
  897. " if currentUser:\n",
  898. " global db\n",
  899. " db.cursor.execute('SELECT course_id, face, title, description FROM courses')\n",
  900. " rows = db.cursor.fetchall()\n",
  901. " db.cursor.execute(\"SELECT course_id FROM saves WHERE user_id = {} AND type = 'isActive' AND data = 'True'\".format(currentUser.userId))\n",
  902. " activeCourses = [r[0] for r in db.cursor.fetchall()]\n",
  903. " for row in rows:\n",
  904. " course_id, face, title, description = row\n",
  905. " newItem = QtWidgets.QTreeWidgetItem(self.itemActiveCourses if (course_id in activeCourses) else self.itemNonactiveCourses)\n",
  906. " newItem.setText(0, title)\n",
  907. " \n",
  908. " def execCommand(self, event):\n",
  909. " textCursor = QtGui.QTextCursor(self.developerTextEdit.textCursor())\n",
  910. " text = textCursor.selectedText()\n",
  911. " if text == \"\":\n",
  912. " text = self.developerTextEdit.toPlainText()\n",
  913. " \n",
  914. " self.statusBar.showMessage(\"Выполнение запроса...\")\n",
  915. " self.progressBar.setValue(0)\n",
  916. " self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)\n",
  917. " self.consoleTextEdit.insertHtml(\"<span style='font-weight: bold; color: lightgray;'>{0:s}</span><br>\".format(time.asctime()))\n",
  918. "\n",
  919. " queries = [q.replace(\"\\\\n\", \"<br>\") for q in re.findall(r\"\\s*((?:(?:\\'[^\\']*?\\')|(?:\\\"[^\\\"]*?\\\")|[^\\\"\\';\\\\]|(?:\\\\(?:[^;]|\\s)))+)\\s*\\\\?;\", text.replace(\"\\\\\\n\", \"\").replace(\"\\n\", \" \"))]\n",
  920. " global db\n",
  921. " timeSum, timeBegin, timeEnd = 0, 0, 0\n",
  922. " db.progressBar.setValue(0)\n",
  923. " try:\n",
  924. " qlen = len(queries)\n",
  925. " for i in range(qlen):\n",
  926. " timeBegin = time.time()\n",
  927. " self.consoleTextEdit.setTextColor(QtGui.QColor('gold'))\n",
  928. " self.consoleTextEdit.insertPlainText(queries[i] + ';\\n')\n",
  929. " self.consoleTextEdit.setTextColor(QtGui.QColor('#336699'))\n",
  930. " db.cursor.execute(queries[i])\n",
  931. " timeEnd = time.time()\n",
  932. " self.consoleTextEdit.insertHtml(\"<span style='color: green;'>Запрос выполнен за {0:.3f} секунд.</span><br>\".format(timeEnd - timeBegin))\n",
  933. " timeSum += timeEnd - timeBegin\n",
  934. " db.progressBar.setValue(db.progressBar.maximum() * (i + 1) / qlen)\n",
  935. " rows = list(db.cursor.fetchall())\n",
  936. " desc = False\n",
  937. " if db.cursor.description:\n",
  938. " rows.insert(0, [f[0] for f in db.cursor.description])\n",
  939. " desc = True\n",
  940. " if rows:\n",
  941. " rlen = len(rows)\n",
  942. " wcount = len(rows[0])\n",
  943. " wmaxlen = [0] * wcount\n",
  944. " for x in range(wcount):\n",
  945. " wlen = 0\n",
  946. " for y in range(rlen):\n",
  947. " wyxlen = len(str(rows[y][x]))\n",
  948. " if wyxlen > wlen:\n",
  949. " wlen = wyxlen\n",
  950. " wmaxlen[x] = wlen\n",
  951. " self.consoleTextEdit.insertPlainText(\"+\")\n",
  952. " for x in range(wcount):\n",
  953. " self.consoleTextEdit.insertPlainText(\"-\" * (wmaxlen[x] + 2) + (\"+\" if x < (wcount - 1) else \"+\\n\"))\n",
  954. " if desc:\n",
  955. " for x in range(wcount):\n",
  956. " self.consoleTextEdit.insertPlainText(\"|\" + str(rows[0][x]).center(wmaxlen[x] + 2, \" \"))\n",
  957. " self.consoleTextEdit.insertPlainText(\"|\\n+\")\n",
  958. " for x in range(wcount):\n",
  959. " self.consoleTextEdit.insertPlainText(\"-\" * (wmaxlen[x] + 2) + (\"+\" if x < (wcount - 1) else \"+\\n\"))\n",
  960. " for y in range(1, rlen):\n",
  961. " for x in range(wcount):\n",
  962. " self.consoleTextEdit.insertPlainText(\"| \" + str(rows[y][x]).ljust(wmaxlen[x] + 1, \" \"))\n",
  963. " self.consoleTextEdit.insertPlainText(\"|\\n\")\n",
  964. " self.consoleTextEdit.insertPlainText(\"+\")\n",
  965. " for x in range(wcount):\n",
  966. " self.consoleTextEdit.insertPlainText(\"-\" * (wmaxlen[x] + 2) + (\"+\" if x < (wcount - 1) else \"+\\n\"))\n",
  967. " self.progressBar.setValue(self.progressBar.maximum() / qlen * (i + 1))\n",
  968. " self.statusBar.showMessage(\"Запросы выполнены за {0:.3f} секунд.\".format(timeSum))\n",
  969. " self.consoleTextEdit.insertHtml(\"<span style='color: green;'>Запросы выполнены за {0:.3f} секунд.</span><br><br>\".format(timeSum))\n",
  970. " except (sqlite3.Error, sqlite3.Warning) as e:\n",
  971. " self.statusBar.showMessage(\"Режим разработчика.\")\n",
  972. " self.consoleTextEdit.insertHtml(\"<span style='color: red;'>Ошибка: {}<br><br>\".format(e.args[0].replace(\"<\", \"<\").replace(\">\", \">\")))\n",
  973. " db.progressBar.setValue(db.progressBar.maximum())\n",
  974. " \n",
  975. " self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)\n",
  976. " self.progressBar.setValue(self.progressBar.maximum())\n",
  977. " \n",
  978. " def commitCommand(self, event):\n",
  979. " self.statusBar.showMessage(\"Выполнение транзакции...\")\n",
  980. " self.progressBar.setValue(0)\n",
  981. " self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)\n",
  982. " self.consoleTextEdit.insertHtml(\"<span style='font-weight: bold; color: lightgray;'>{0:s}</span><br>\".format(time.asctime()))\n",
  983. " \n",
  984. " global db\n",
  985. " timeDelta, timeBegin, timeEnd = 0, 0, 0\n",
  986. " db.progressBar.setValue(0)\n",
  987. " try:\n",
  988. " timeBegin = time.time()\n",
  989. " db.connection.commit()\n",
  990. " timeEnd = time.time()\n",
  991. " timeDelta = timeEnd - timeBegin\n",
  992. " \n",
  993. " self.statusBar.showMessage(\"Транзакция выполнена за {0:.3f} секунд.\".format(timeDelta))\n",
  994. " self.consoleTextEdit.insertHtml(\"<span style='color: green;'>Транзакция выполнена за {0:.3f} секунд.</span><br><br>\".format(timeDelta))\n",
  995. " except:\n",
  996. " self.statusBar.showMessage(\"Режим разработчика.\")\n",
  997. " self.consoleTextEdit.insertHtml(\"<span style='color: red;'>Ошибка: не удалось совершить транзакцию.</span><br><br>\")\n",
  998. " db.progressBar.setValue(db.progressBar.maximum())\n",
  999. " \n",
  1000. " self.consoleTextEdit.moveCursor(QtGui.QTextCursor.End)\n",
  1001. " self.progressBar.setValue(self.progressBar.maximum())\n",
  1002. " \n",
  1003. " def clearCommand(self):\n",
  1004. " self.consoleTextEdit.clear()\n",
  1005. " self.statusBar.showMessage(\"Консоль очищена...\")\n",
  1006. " \n",
  1007. " def saveCommand(self):\n",
  1008. " try:\n",
  1009. " path = QtWidgets.QFileDialog.getSaveFileName(\n",
  1010. " self,\n",
  1011. " caption=\"Сохранить SQL-код\",\n",
  1012. " directory=\"./\",\n",
  1013. " filter=\"SQL (*.sql);; TXT (*.txt);; Все файлы (*)\",\n",
  1014. " initialFilter= \"SQL (*.sql)\")[0]\n",
  1015. " file = open(path, \"w\")\n",
  1016. " file.write(self.developerTextEdit.toPlainText())\n",
  1017. " file.close()\n",
  1018. " pathConsole = re.search(r\"^(.+?)(?:\\.[^.]+)?$\", path).group(1) + \".txt\"\n",
  1019. " fileHtml = open(pathConsole, \"w\")\n",
  1020. " fileHtml.write(self.consoleTextEdit.toPlainText())\n",
  1021. " fileHtml.close()\n",
  1022. " self.statusBar.showMessage(\"SQL-код сохранён в файле \\\"{0:s}\\\", а данные консоли - в файле \\\"{1:s}\\\".\".format(path, pathConsole))\n",
  1023. " except:\n",
  1024. " self.statusBar.showMessage(\"Произошла ошибка при сохранении SQL-кода и данных консоли.\")"
  1025. ]
  1026. },
  1027. {
  1028. "cell_type": "code",
  1029. "execution_count": 16,
  1030. "metadata": {},
  1031. "outputs": [],
  1032. "source": [
  1033. "class GoLink(QtWidgets.QLabel):\n",
  1034. "\n",
  1035. " def __init__(self, text: str=\"\", presentationWindow=None, mainFrame=None):\n",
  1036. " super().__init__(presentationWindow)\n",
  1037. " self.presentationWindow = presentationWindow\n",
  1038. " self.mainFrame = mainFrame\n",
  1039. "\n",
  1040. " self.setAlignment(QtCore.Qt.AlignCenter)\n",
  1041. " self.setText(text)\n",
  1042. "\n",
  1043. " def enterEvent(self, event):\n",
  1044. " self.setCursor(QtCore.Qt.PointingHandCursor)\n",
  1045. "\n",
  1046. " def mousePressEvent(self, event):\n",
  1047. " self.opacity1 = QtWidgets.QGraphicsOpacityEffect()\n",
  1048. " self.presentationWindow.setGraphicsEffect(self.opacity1)\n",
  1049. " self.anim1 = QtCore.QPropertyAnimation(self.opacity1, b\"opacity\")\n",
  1050. " self.anim1.setDuration(250)\n",
  1051. " self.anim1.setStartValue(1.0)\n",
  1052. " self.anim1.setEndValue(0.0)\n",
  1053. " self.anim1.start()\n",
  1054. " self.anim1.finished.connect(self.presentationWindowIsInvisible)\n",
  1055. " \n",
  1056. " def presentationWindowIsInvisible(self):\n",
  1057. " self.presentationWindow.hide()\n",
  1058. " self.opacity2 = QtWidgets.QGraphicsOpacityEffect()\n",
  1059. " self.mainFrame.setGraphicsEffect(self.opacity2)\n",
  1060. " self.mainFrame.setWindowOpacity(0.0)\n",
  1061. " self.mainFrame.show()\n",
  1062. " self.anim2 = QtCore.QPropertyAnimation(self.opacity2, b\"opacity\")\n",
  1063. " self.anim2.setDuration(250)\n",
  1064. " self.anim2.setStartValue(0.0)\n",
  1065. " self.anim2.setEndValue(1.0)\n",
  1066. " self.anim2.start()\n",
  1067. " self.anim2.finished.connect(self.mainFrameIsVisible)\n",
  1068. " \n",
  1069. " def mainFrameIsVisible(self):\n",
  1070. " self.mainFrame.enterWindow = EnterWindow()\n",
  1071. " self.mainFrame.loadDatabase()\n",
  1072. " self.mainFrame.enterWindow.uploadUsers()\n",
  1073. " self.mainFrame.offerToEnter()"
  1074. ]
  1075. },
  1076. {
  1077. "cell_type": "code",
  1078. "execution_count": 17,
  1079. "metadata": {},
  1080. "outputs": [],
  1081. "source": [
  1082. "class PresentationWindow(QtWidgets.QLabel):\n",
  1083. " slideWidth = 1138 # Ширина одного слайда\n",
  1084. " slideHeight = 500 # Высота одного слайда\n",
  1085. " slidesCount = 3 # Количество слайдов\n",
  1086. " movingTime = 750 # Скорость прокрутки слайдов в миллисекундах\n",
  1087. "\n",
  1088. " def __init__(self, mainWindow=None, mainFrame=None):\n",
  1089. " super().__init__(mainWindow) # Экземпляр класса PresentationWindow будет дочерним относительно родителя mainWindow\n",
  1090. " self.mainFrame = mainFrame\n",
  1091. "\n",
  1092. " self.setFixedSize(1200, 640) # Задаем фиксированный размер для презентации\n",
  1093. " self.setAlignment(QtCore.Qt.AlignCenter) # Устанавливаем его в центр окна\n",
  1094. "\n",
  1095. " self.content = QtWidgets.QVBoxLayout(self) # Задаем вертикальный макет для содержания презентации\n",
  1096. " self.scrollArea = QtWidgets.QScrollArea() # Область с прокруткой для перелистывания слайдов\n",
  1097. " self.slides = [QtWidgets.QLabel() for i in range(self.slidesCount)] # Сами слайды (имеют тип QLabel)\n",
  1098. " self.slidesPacket = QtWidgets.QLabel()\n",
  1099. " self.slidesLayout = QtWidgets.QHBoxLayout(self.slidesPacket) # Горизонтальный макет для слайдов\n",
  1100. " self.buttonHBox = QtWidgets.QHBoxLayout() # Горизонтальный макет для radio-кнопок\n",
  1101. "\n",
  1102. " for i in range(self.slidesCount):\n",
  1103. " # Позволим пользователю выделять текст:\n",
  1104. " slide = self.slides[i]\n",
  1105. " # Пишем текст в i-ый слайд:\n",
  1106. " if i == 0:\n",
  1107. " slide.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextSelectableByKeyboard)\n",
  1108. " slide.setText(\"<img src='Images/icon.png' /><br><br>Добро пожаловать в программу <b>NeuralNetworks</b>, которая<br>научит вас программировать искусственные нейросети на языке Python!\")\n",
  1109. " elif i == 1:\n",
  1110. " slide.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextSelectableByKeyboard)\n",
  1111. " slide.setText(\"<b>NeuralNetworks</b> содержит в себе видео-уроки, теорию, тесты<br>и интерпретатор языка программирования <b>Python</b> для написания собственных программ!<br>Результаты заданий буду сохраняться в одну локальную базу данных формата <b>SQLite</b>, которая будет<br>хранить в себе <b>весь прогресс</b> и <b>весь код ваших программ</b>.\")\n",
  1112. " else:\n",
  1113. " self.goBox = QtWidgets.QVBoxLayout(slide)\n",
  1114. " self.goLink = GoLink(\"<b>Давайте приступим...</b>\", self, self.mainFrame)\n",
  1115. " self.goBox.addStretch(1)\n",
  1116. " self.goBox.addWidget(self.goLink)\n",
  1117. " self.goBox.addStretch(1)\n",
  1118. " slide.setAlignment(QtCore.Qt.AlignCenter) # Устанавливаем текст слайда по центру\n",
  1119. " slide.setFixedWidth(self.slideWidth) # Задаем ширину для слайда\n",
  1120. " slide.setObjectName(\"slide\")\n",
  1121. " self.slidesLayout.addWidget(slide) # Добавляем данный слайд в макет\n",
  1122. " # Устанавливаем размер пакета со всеми слайдами:\n",
  1123. " self.slidesPacket.setFixedSize(self.slideWidth * self.slidesCount, self.slideHeight)\n",
  1124. " self.slidesPacket.setObjectName(\"slidesPacket\")\n",
  1125. "\n",
  1126. " self.scrollArea.setObjectName(\"slides\")\n",
  1127. " self.scrollArea.setWidget(self.slidesPacket) # Задаем виджет (QLabel)slidesPacket для области прокрутки\n",
  1128. " self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) # Скрываем полосу прокрутки\n",
  1129. " self.scrollArea.horizontalScrollBar().valueChanged.connect(self.scrollAreaWheelEvent)\n",
  1130. "\n",
  1131. " self.buttonHBox.addStretch(1) # Мы добавим отступы в начале и в конце для кнопок, чтобы они были по середине\n",
  1132. " self.buttons = [QtWidgets.QRadioButton(self) for i in range(self.slidesCount)]\n",
  1133. " self.buttons[0].setChecked(True) # Первый слайд будет виден сначала\n",
  1134. " for button in self.buttons:\n",
  1135. " button.clicked.connect(self.slideToggle)\n",
  1136. " self.buttonHBox.addWidget(button)\n",
  1137. " self.buttonHBox.addStretch(1)\n",
  1138. "\n",
  1139. " # Заполняем содержимое:\n",
  1140. " self.content.addWidget(self.scrollArea)\n",
  1141. " self.content.addLayout(self.buttonHBox)\n",
  1142. "\n",
  1143. " def slideToggle(self, isChecked):\n",
  1144. " if isChecked:\n",
  1145. " # Анимируем горизонтальную прокрутку:\n",
  1146. " self.anim = QtCore.QPropertyAnimation(self.scrollArea.horizontalScrollBar(), b\"value\")\n",
  1147. " self.anim.setDuration(self.movingTime)\n",
  1148. " self.anim.setEasingCurve(QtCore.QEasingCurve.InOutExpo)\n",
  1149. " i = 0\n",
  1150. " for i in range(self.slidesCount):\n",
  1151. " if self.buttons[i].isChecked():\n",
  1152. " break\n",
  1153. " self.anim.setEndValue(self.scrollArea.horizontalScrollBar().pageStep() * i)\n",
  1154. " self.anim.start()\n",
  1155. "\n",
  1156. " def scrollAreaWheelEvent(self, value):\n",
  1157. " k = value / (self.scrollArea.horizontalScrollBar().pageStep() * self.slidesCount)\n",
  1158. " i = 0\n",
  1159. " for i in range(self.slidesCount):\n",
  1160. " if self.buttons[i].isChecked():\n",
  1161. " break\n",
  1162. " j = int(math.ceil(k * self.slidesCount - 0.5))\n",
  1163. " if j != i:\n",
  1164. " self.buttons[j].setChecked(True)"
  1165. ]
  1166. },
  1167. {
  1168. "cell_type": "code",
  1169. "execution_count": 18,
  1170. "metadata": {},
  1171. "outputs": [],
  1172. "source": [
  1173. "class MainWindow(QtWidgets.QWidget):\n",
  1174. " sourceSize = QtCore.QSize(1280, 768)\n",
  1175. "\n",
  1176. " def __init__(self):\n",
  1177. " super().__init__()\n",
  1178. "\n",
  1179. " # Создаем произвольное окно с задним фоном:\n",
  1180. " self.setWindowTitle(\"NeuralNetworks\")\n",
  1181. " self.icon = QtGui.QIcon(\"Images/icon.png\")\n",
  1182. " self.setWindowIcon(self.icon)\n",
  1183. " self.resize(self.sourceSize)\n",
  1184. " # Центруем окно по экрану:\n",
  1185. " self.desktop = QtWidgets.QApplication.desktop()\n",
  1186. " x = (self.desktop.width() - self.width()) // 2\n",
  1187. " y = (self.desktop.height() - self.height()) // 2\n",
  1188. " self.move(x, y)\n",
  1189. "\n",
  1190. " self.hbox = QtWidgets.QHBoxLayout(self)\n",
  1191. " self.hbox.setContentsMargins(0, 0, 0, 0)\n",
  1192. " self.mainFrame = MainFrame(self)\n",
  1193. " self.mainFrame.resize(self.sourceSize)\n",
  1194. " self.mainFrame.hide()\n",
  1195. " self.hbox.addWidget(self.mainFrame)\n",
  1196. "\n",
  1197. " self.presentationWindow = PresentationWindow(self, self.mainFrame)\n",
  1198. " self.hbox.addWidget(self.presentationWindow)\n",
  1199. "\n",
  1200. " self.keyEsc = QtWidgets.QShortcut(QtCore.Qt.Key_Escape, self)\n",
  1201. " self.keyEsc.activated.connect(self.pressedKeyEsc)\n",
  1202. "\n",
  1203. " self.keyF11 = QtWidgets.QShortcut(QtCore.Qt.Key_F11, self)\n",
  1204. " self.keyF11.activated.connect(self.pressedKeyF11)\n",
  1205. "\n",
  1206. " def resizeEvent(self, event):\n",
  1207. " self.mainFrame.resize(self.size())\n",
  1208. "\n",
  1209. " def paintEvent(self, event):\n",
  1210. " painter = QtGui.QPainter(self)\n",
  1211. " painter.drawPixmap(0, 0, self.width(), self.height(), QtGui.QPixmap(\"Images/background.jpg\"))\n",
  1212. "\n",
  1213. " def closeEvent(self, event):\n",
  1214. " if currentUser is not None:\n",
  1215. " msgBox = QtWidgets.QMessageBox(QtWidgets.QMessageBox.Question,\n",
  1216. " \"Закрыть программу\",\n",
  1217. " \"Вы действительно хотите выйти из программы? Все данные будут сохранены.\",\n",
  1218. " QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)\n",
  1219. " msgBox.setDefaultButton(QtWidgets.QMessageBox.No)\n",
  1220. " if msgBox.exec() == QtWidgets.QMessageBox.Yes:\n",
  1221. " QtWidgets.QApplication.closeAllWindows()\n",
  1222. " event.accept()\n",
  1223. " else:\n",
  1224. " event.ignore()\n",
  1225. " else:\n",
  1226. " QtWidgets.QApplication.quit()\n",
  1227. "\n",
  1228. " def pressedKeyEsc(self):\n",
  1229. " self.close()\n",
  1230. "\n",
  1231. " def pressedKeyF11(self):\n",
  1232. " if self.isFullScreen():\n",
  1233. " self.showNormal()\n",
  1234. " else:\n",
  1235. " self.showFullScreen()"
  1236. ]
  1237. },
  1238. {
  1239. "cell_type": "code",
  1240. "execution_count": null,
  1241. "metadata": {},
  1242. "outputs": [],
  1243. "source": [
  1244. "app = QtWidgets.QApplication(sys.argv)\n",
  1245. "\n",
  1246. "qss = open(\"stylesheet.css\")\n",
  1247. "app.setStyleSheet(qss.read())\n",
  1248. "qss.close()\n",
  1249. "\n",
  1250. "mainWindow = MainWindow()\n",
  1251. "mainWindow.show()\n",
  1252. "\n",
  1253. "code = app.exec_()\n",
  1254. "sys.exit(code)"
  1255. ]
  1256. },
  1257. {
  1258. "cell_type": "code",
  1259. "execution_count": null,
  1260. "metadata": {},
  1261. "outputs": [],
  1262. "source": []
  1263. }
  1264. ],
  1265. "metadata": {
  1266. "kernelspec": {
  1267. "display_name": "Python 3",
  1268. "language": "python",
  1269. "name": "python3"
  1270. },
  1271. "language_info": {
  1272. "codemirror_mode": {
  1273. "name": "ipython",
  1274. "version": 3
  1275. },
  1276. "file_extension": ".py",
  1277. "mimetype": "text/x-python",
  1278. "name": "python",
  1279. "nbconvert_exporter": "python",
  1280. "pygments_lexer": "ipython3",
  1281. "version": "3.6.4"
  1282. }
  1283. },
  1284. "nbformat": 4,
  1285. "nbformat_minor": 2
  1286. }
Add Comment
Please, Sign In to add comment