main_windows.py 14 KB

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