qtextedit_stdout.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. # coding:utf-8
  2. #!/usr/bin/python
  3. #
  4. # Copyright (c) Contributors to the Open 3D Engine Project.
  5. # For complete copyright and license terms please see the LICENSE at the root of this distribution.
  6. #
  7. # SPDX-License-Identifier: Apache-2.0 OR MIT
  8. #
  9. #
  10. # -------------------------------------------------------------------------
  11. from __future__ import unicode_literals
  12. # from builtins import str
  13. # built in's
  14. import sys
  15. import os
  16. import uuid
  17. # azpy
  18. from azpy import initialize_logger
  19. from azpy.shared.ui.base_widget import BaseQwidgetAzpy
  20. # 3rd Party
  21. from unipath import Path
  22. import PySide2.QtCore as QtCore
  23. import PySide2.QtWidgets as QtWidgets
  24. from PySide2.QtCore import QProcess, Signal, Slot, QTextCodec
  25. from PySide2.QtGui import QTextCursor
  26. from PySide2.QtWidgets import QPlainTextEdit
  27. from PySide2.QtCore import QTimer
  28. # -------------------------------------------------------------------------
  29. # global space debug flag
  30. _DCCSI_GDEBUG = os.getenv('DCCSI_GDEBUG', False)
  31. # global space debug flag
  32. _DCCSI_DEV_MODE = os.getenv('DCCSI_DEV_MODE', False)
  33. _MODULE_PATH = Path(__file__)
  34. _ORG_TAG = 'Amazon_Lumberyard'
  35. _APP_TAG = 'DCCsi'
  36. _TOOL_TAG = 'azpy.shared.ui.pyside2_qtextedit_stdout'
  37. _TYPE_TAG = 'test'
  38. _MODULENAME = __name__
  39. if _MODULENAME == '__main__':
  40. _MODULENAME = _TOOL_TAG
  41. if _DCCSI_GDEBUG:
  42. _LOGGER = initialize_logger(_MODULENAME, log_to_file=True)
  43. _LOGGER.debug('Something invoked :: {0}.'.format({_MODULENAME}))
  44. else:
  45. _LOGGER = initialize_logger(_MODULENAME)
  46. # -------------------------------------------------------------------------
  47. class ProcessOutputReader(QProcess):
  48. produce_output = Signal(str)
  49. def __init__(self, parent=None):
  50. super().__init__(parent=parent)
  51. # merge stderr channel into stdout channel
  52. self.setProcessChannelMode(QProcess.MergedChannels)
  53. # prepare decoding process' output to Unicode
  54. self._codec = QTextCodec.codecForLocale()
  55. self._decoder_stdout = self._codec.makeDecoder()
  56. # only necessary when stderr channel isn't merged into stdout:
  57. # self._decoder_stderr = codec.makeDecoder()
  58. self.readyReadStandardOutput.connect(self._ready_read_standard_output)
  59. # only necessary when stderr channel isn't merged into stdout:
  60. # self.readyReadStandardError.connect(self._ready_read_standard_error)
  61. @Slot()
  62. def _ready_read_standard_output(self):
  63. raw_bytes = self.readAllStandardOutput()
  64. text = self._decoder_stdout.toUnicode(raw_bytes)
  65. self.produce_output.emit(text)
  66. # only necessary when stderr channel isn't merged into stdout:
  67. # @Slot()
  68. # def _ready_read_standard_error(self):
  69. # raw_bytes = self.readAllStandardError()
  70. # text = self._decoder_stderr.toUnicode(raw_bytes)
  71. # self.produce_output.emit(text)
  72. # --------------------------------------------------------------------------
  73. class MyConsole(BaseQwidgetAzpy, QPlainTextEdit):
  74. def __init__(self, parent=None):
  75. super().__init__(parent=parent)
  76. # Set a unique object name string so Maya can easily look it up
  77. self.setObjectName('{0}_{1}'.format(self.__class__.__name__,
  78. uuid.uuid4()))
  79. self.setReadOnly(True)
  80. self.setMaximumBlockCount(10000) # limit console to 10000 lines
  81. self._cursor_output = self.textCursor()
  82. @Slot(str)
  83. def append_output(self, text):
  84. self._cursor_output.insertText(text)
  85. self.scroll_to_last_line()
  86. def scroll_to_last_line(self):
  87. cursor = self.textCursor()
  88. cursor.movePosition(QTextCursor.End)
  89. cursor.movePosition(QTextCursor.Up if cursor.atBlockStart() else
  90. QTextCursor.StartOfLine)
  91. self.setTextCursor(cursor)
  92. def output_text(self, text):
  93. self._cursor_output.insertText(text)
  94. self.scroll_to_last_line()
  95. # --------------------------------------------------------------------------
  96. if __name__ == '__main__':
  97. """Run this file as main"""
  98. import sys
  99. _ORG_TAG = 'Amazon_Lumberyard'
  100. _APP_TAG = 'DCCsi'
  101. _TOOL_TAG = 'azpy.shared.ui.pyside2_qtextedit_stdout'
  102. _TYPE_TAG = 'test'
  103. if _DCCSI_GDEBUG:
  104. _LOGGER = initialize_logger('{0}-TEST'.format(_TOOL_TAG), log_to_file=True)
  105. _LOGGER.debug('Something invoked :: {0}.'.format({_MODULENAME}))
  106. _LOGGER.debug("{0} :: if __name__ == '__main__':".format(_TOOL_TAG))
  107. _LOGGER.debug("Starting App:{0} TEST ...".format(_TOOL_TAG))
  108. # # create the application instance
  109. # _APP = QtWidgets.QApplication(sys.argv)
  110. # _APP.setOrganizationName(_ORG_TAG)
  111. # _APP.setApplicationName('{app}:{tool}'.format(app=_APP_TAG, tool=_TOOL_TAG))
  112. # create a console and connect the process output reader to it
  113. _CONSOLE = MyConsole()
  114. # create a process output reader
  115. _READER = ProcessOutputReader(parent=_CONSOLE)
  116. _READER.produce_output.connect(_CONSOLE.append_output)
  117. # start something and log (including to console)
  118. # this starts a test app
  119. _TEST_PY_FILE = Path(_MODULE_PATH.parent, 'pyside2_ui_utils.py')
  120. _READER.start('python', ['-u', _TEST_PY_FILE]) # start the process
  121. # after that starts, this will show the console
  122. # O3DE_QSS = Path(_MODULE_PATH.parent, 'resources', 'stylesheets', 'LYstyle.qss')
  123. _DARK_STYLE = Path(_MODULE_PATH.parent, 'resources', 'qdarkstyle', 'style.qss')
  124. _CONSOLE.qapp.setStyleSheet(_DARK_STYLE.read_file())
  125. _CONSOLE.show() # make the console visible
  126. _LOGGER.debug(_CONSOLE.objectName())
  127. _TIMER = QTimer()
  128. _TIMER.timeout.connect(lambda: None)
  129. _TIMER.start(100)
  130. del _LOGGER
  131. sys.exit(_CONSOLE.qapp.exec_())