main_windows.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. import os
  2. import queue
  3. import re
  4. import sys
  5. import threading
  6. from PySide2.QtWidgets import QApplication, QMainWindow
  7. from PySide2.QtUiTools import QUiLoader
  8. from PySide2.QtWidgets import *
  9. from PySide2.QtCore import *
  10. from PySide2 import QtCore
  11. from PySide2.QtGui import *
  12. from ui.ui_MainWindows import Ui_MainWindow
  13. from ui.Analyze import AnalyzeWindow
  14. from sub_windows import SubWindows,LineEditWin,FormWindow, get_sub_win_list,get_sub_win
  15. from ui.About import AboutWindow
  16. from ui.Elaborate import Elaborate
  17. from ui.Read_Timing_Constraint import ReadTimeWindow
  18. from ui.ReportException import ReportExceptionWindow
  19. from ui.ReportClocks import ReportClocks
  20. import GuiType
  21. class Stream(QObject):
  22. """Redirects console output to text widget."""
  23. newText = Signal(str)
  24. def __init__(self):
  25. super().__init__()
  26. self.stdout_bak = sys.stdout
  27. self.buffer = self.stdout_bak.buffer
  28. self.close = self.stdout_bak.close
  29. self.closed = self.stdout_bak.closed
  30. self.detach = self.stdout_bak.detach
  31. self.encoding = self.stdout_bak.encoding
  32. self.errors = self.stdout_bak.errors
  33. self.fileno = self.stdout_bak.fileno
  34. self.flush = self.stdout_bak.flush
  35. self.isatty = self.stdout_bak.isatty
  36. self.line_buffering = self.stdout_bak.line_buffering
  37. self.mode = self.stdout_bak.mode
  38. self.name = self.stdout_bak.name
  39. self.newlines = self.stdout_bak.newlines
  40. self.read = self.stdout_bak.read
  41. self.readable = self.stdout_bak.readable
  42. self.readline = self.stdout_bak.readline
  43. self.readlines = self.stdout_bak.readlines
  44. self.reconfigure = self.stdout_bak.reconfigure
  45. self.seek = self.stdout_bak.seek
  46. self.seekable = self.stdout_bak.seekable
  47. self.tell = self.stdout_bak.tell
  48. self.truncate = self.stdout_bak.truncate
  49. self.writable = self.stdout_bak.writable
  50. self.write_through = self.stdout_bak.write_through
  51. self.writelines = self.stdout_bak.writelines
  52. def write(self, text:str):
  53. self.stdout_bak.write(str(text))
  54. self.stdout_bak.flush()
  55. if len(text) == 0:
  56. return
  57. if text.isspace():
  58. return
  59. self.newText.emit(str(text+'\n'))
  60. class MessageItem(QTreeWidgetItem):
  61. def __init__(self, parent, msg:GuiType._GuiMessage):
  62. super().__init__(parent)
  63. self.setText(0, msg.Text)
  64. self.msg = msg
  65. class MessagesWidgetItem(QTreeWidgetItem):
  66. def __init__(self, parent, messages:GuiType._GuiMessages, level):
  67. super().__init__(parent)
  68. summary = messages.GetSummary()
  69. self.setText(0, level + f"({messages.Size})")
  70. for id_, size, text in summary:
  71. sumary_item = QTreeWidgetItem(self)
  72. sumary_item.setText(0, f"{id_}({size}):{text}")
  73. for msg in messages.GetMsgByID(id_):
  74. msg:GuiType._GuiMessage
  75. MessageItem(sumary_item, msg)
  76. class MainWindow(Ui_MainWindow, QMainWindow):
  77. textEdit_sig = Signal(str)
  78. sig = Signal(object)
  79. def __init__(self, GUI) -> None:
  80. super().__init__()
  81. self.setupUi(self)
  82. # 这里显示一下是为了能获取到 mdiArea 的尺寸,给 sub_windows 使用
  83. self.GUI = GUI
  84. self.setWindowTitle(GUI.Title)
  85. self.show()
  86. sys.stdout = Stream()
  87. sys.stdout.newText.connect(self.outputWritten)
  88. sys.stderr = sys.stdout
  89. self.btn_shell.setText(GUI.Prompt)
  90. self.btn_shell.clicked.connect(self.click_btn_sell)
  91. self.tabWidget.currentChanged.connect(self.table_widget_change)
  92. self.tableHistory.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
  93. self.tableHistory.customContextMenuRequested.connect(self.history_right_click_menu)
  94. self.MessageTreeView.customContextMenuRequested.connect(self.message_right_click_menu)
  95. self.status_label = QLabel("Ready")
  96. self.statusbar.addWidget(self.status_label)
  97. self.loader = QUiLoader()
  98. # -- MENUE --
  99. # file
  100. self.actionStop_GUI.triggered.connect(GUI.Stop)
  101. self.actionExit.triggered.connect(GUI.Exit)
  102. # Edit
  103. self.actionCopy.triggered.connect(self.action_copy)
  104. self.actionPast.triggered.connect(self.action_paste)
  105. self.actionSelect_all.triggered.connect(self.action_select_all)
  106. # View
  107. self.actionIncr_Font
  108. self.actionDecr_Font
  109. self.actionToolbar.triggered.connect(lambda: self.toolBar.setHidden(not self.actionToolbar.isChecked()))
  110. self.actionSidebar.triggered.connect(lambda: self.sub_win.side_bar.mdisubwin.setHidden(not self.actionSidebar.isChecked()))
  111. self.actionConsole.triggered.connect(lambda: self.tabWidget.setHidden(not self.actionConsole.isChecked()))
  112. self.actionStatusBar.triggered.connect(lambda: self.statusbar.setHidden(not self.actionStatusBar.isChecked()))
  113. self.actionSave_as_Default
  114. self.actionPreferences
  115. # Design
  116. self.actionAnalyze.triggered.connect(self.show_analyze_window)
  117. self.actionElaborate.triggered.connect(self.elaborate_window)
  118. self.actionRead_Timing_Constraint.triggered.connect(self.read_timing_constraint)
  119. self.actionRead_Power_Intent
  120. self.actionReload_Design.triggered.connect(self.reload_design)
  121. # Windows
  122. # 先实例一个 ActionGroup,等到创建动态窗口的时候,才会在 菜单栏-Window 中添加Action
  123. self.action_win_group = QActionGroup(self)
  124. # 获取分隔符,方便 菜单栏-Window-Action 插入到分隔符之前
  125. self.action_win_separator = self.menuWindow.actions()[0]
  126. action_tabgroup = QActionGroup(self)
  127. self.actionLog.setActionGroup(action_tabgroup)
  128. self.actionHistory.setActionGroup(action_tabgroup)
  129. self.actionMessages.setActionGroup(action_tabgroup)
  130. self.actionLog.triggered.connect(self.action_tab_widget)
  131. self.actionHistory.triggered.connect(self.action_tab_widget)
  132. self.actionMessages.triggered.connect(self.action_tab_widget)
  133. # Report
  134. self.actionReport_Exceptions.triggered.connect(self.reportException)
  135. self.actionReport_Clocks.triggered.connect(self.reportClocks)
  136. self.actionReport_Virtual_Timing
  137. self.actionAbout.triggered.connect(self.about)
  138. self.textEdit.document().contentsChanged.connect(self.textEdit_change_size)
  139. self.textEdit.document().contentsChange.connect(self.textEdit_change_contents)
  140. self.sub_win = SubWindows(self)
  141. self.sub_win.sig.connect(self.sub_win.add_windows)
  142. def action_copy(self):
  143. # 获得文本光标所在控件
  144. widget:QTextBrowser = self.focusWidget()
  145. if type(widget) not in (QTextBrowser, QTextEdit):
  146. return
  147. cur:QTextCursor = widget.textCursor()
  148. self.copy(cur.selectedText())
  149. def action_paste(self):
  150. clipboard = QApplication.clipboard()
  151. # 获得文本光标所在控件
  152. widget:QTextBrowser = self.focusWidget()
  153. if type(widget) not in (QTextBrowser, QTextEdit):
  154. return
  155. widget.textCursor().insertText(clipboard.text())
  156. def action_select_all(self):
  157. # 获得文本光标所在控件
  158. widget:QTextBrowser = self.focusWidget()
  159. if type(widget) not in (QTextBrowser, QTextEdit):
  160. return
  161. widget.selectAll()
  162. def action_tab_widget(self):
  163. action_sender = self.sender()
  164. action = {
  165. self.actionLog: 0,
  166. self.actionHistory: 1,
  167. self.actionMessages: 2,
  168. }
  169. index = action.get(action_sender)
  170. if index != None:
  171. self.tabWidget.setCurrentIndex(index)
  172. def read_timing_constraint(self):
  173. ReadTimeWindow(self, os.getcwd())
  174. def table_widget_change(self, index):
  175. member = {
  176. 0: None,
  177. 1: self.show_history,
  178. 2: self.show_message
  179. }
  180. method = member.get(index)
  181. if method:
  182. method()
  183. def show_history(self):
  184. self.tableHistory.clear()
  185. blank_row = self.tableHistory.height() / self.tableHistory.verticalHeader().height() + 2
  186. self.tableHistory.setRowCount(blank_row)
  187. for row_text in self.GUI.GetHistory():
  188. end_row = self.tableHistory.rowCount()
  189. self.tableHistory.insertRow(end_row)
  190. self.tableHistory.setItem(end_row, 0, QTableWidgetItem(row_text))
  191. self.tableHistory.scrollToBottom()
  192. def copy(self, text):
  193. clipboard = QApplication.clipboard()
  194. clipboard.setText(text)
  195. def history_right_click_menu(self):
  196. itemPos = self.tableHistory.mapFromGlobal(QCursor().pos())
  197. item = self.tableHistory.itemAt(itemPos)
  198. if type(item) != QTableWidgetItem:
  199. return
  200. pop_menu = QMenu()
  201. pop_menu.addAction(QAction('Copy', pop_menu))
  202. pop_menu.triggered.connect(lambda: self.copy(self.tableHistory.currentItem().text()))
  203. pop_menu.exec_(QCursor.pos())
  204. def message_right_click_menu(self):
  205. itemPos = self.MessageTreeView.mapFromGlobal(QCursor().pos())
  206. item:MessageItem = self.MessageTreeView.itemAt(itemPos)
  207. if type(item) != MessageItem:
  208. return
  209. pop_menu = QMenu()
  210. pop_menu.addAction(QAction('Crossprobe', pop_menu))
  211. pop_menu.addAction(QAction('Properties', pop_menu))
  212. pop_menu.triggered.connect(lambda action: self.message_popmenu_action(action, item))
  213. pop_menu.exec_(QCursor.pos())
  214. def message_popmenu_action(self, action, item):
  215. if action.text() == 'Crossprobe':
  216. win_line_text = item.msg.CrossProbe()
  217. win = get_sub_win(self.mdiArea, LineEditWin, win_line_text.Title)
  218. # 如果窗口已经存在,关闭窗口,以便重新更新数据
  219. if win:
  220. win.close()
  221. LineEditWin(self, win_line_text)
  222. elif action.text() == 'Properties':
  223. win_form = item.msg.Properties()
  224. # 如果窗口已经存在,关闭窗口,以便重新更新数据
  225. win = get_sub_win(self.mdiArea, FormWindow, win_form.Title)
  226. if win:
  227. win.close()
  228. FormWindow(self, win_form)
  229. def show_message(self):
  230. for _ in range(self.MessageTreeView.topLevelItemCount()):
  231. self.MessageTreeView.takeTopLevelItem(0)
  232. MessagesWidgetItem(self.MessageTreeView, self.GUI.GetErrors(), "Errors")
  233. MessagesWidgetItem(self.MessageTreeView, self.GUI.GetCriticalWarnings(), "CriticalWarnings")
  234. MessagesWidgetItem(self.MessageTreeView, self.GUI.GetWarnings(), "Warnings")
  235. MessagesWidgetItem(self.MessageTreeView, self.GUI.GetInfos(), "Infos")
  236. def about(self):
  237. d = AboutWindow(self, self.GUI.About)
  238. d.exec_()
  239. def show_analyze_window(self):
  240. d = AnalyzeWindow(self, self.GUI.Shell_Execute)
  241. d.exec_()
  242. def elaborate_window(self):
  243. d = Elaborate(self)
  244. d.exec_()
  245. def reportException(self):
  246. d = ReportExceptionWindow(self)
  247. d.exec_()
  248. def reportClocks(self):
  249. d = ReportClocks(self)
  250. d.exec_()
  251. def outputWritten(self, text):
  252. cursor = self.LogText.textCursor()
  253. cursor.movePosition(QTextCursor.End)
  254. cursor.insertText(text)
  255. self.LogText.setTextCursor(cursor)
  256. self.LogText.ensureCursorVisible()
  257. def textEdit_change_size(self):
  258. height = self.textEdit.document().size().height()
  259. self.textEdit.setMinimumHeight(height)
  260. def click_btn_sell(self):
  261. self.textEdit.append('\n')
  262. def textEdit_change_contents(self, from_index, charsRemoved, charsAdded):
  263. if not charsAdded:
  264. return
  265. stdin = self.textEdit.toPlainText()
  266. if not stdin:
  267. return
  268. # 捕获回车键
  269. if stdin[from_index] != '\n':
  270. return
  271. # 回车时,判断字符串代码是否结束
  272. if self.GUI.Shell_IsCmdFinished(stdin):
  273. # 删除回车字符
  274. stdin = stdin[:from_index] + stdin[from_index+1:]
  275. print(stdin)
  276. thread = threading.Thread(target=self.GUI.Shell_Execute, args=(stdin,))
  277. thread.start()
  278. self.textEdit.setText('')
  279. self.textEdit_change_size()
  280. def reload_design(self):
  281. thread = threading.Thread(target=self.GUI.ReloadDesign)
  282. thread.start()
  283. def add_sub_win(self):
  284. print('add sub')
  285. self.t = self.loader.load("ui/TimingAnalyze.ui")
  286. self.mdiArea.addSubWindow(self.t)
  287. self.t.show()