from PyQt5.QtWidgets import QPlainTextEdit, QWidget, QHBoxLayout, QVBoxLayout, QPushButton, QLineEdit
from PyQt5.QtGui import QTextOption, QTextCursor
from PyQt5.QtCore import pyqtSlot, QTimer
import glob
import os
import getpass
from . import transphire_utils as tu
from . import logviewerdialog
[docs]class LogViewer(QWidget):
def __init__(self, show_indicators=False, indicator='', file_name='', parent=None):
super(LogViewer, self).__init__(parent)
# Setup layout
global_layout = QHBoxLayout(self)
global_layout.setContentsMargins(0, 0, 0, 0)
widget = QWidget(self)
widget.setObjectName('logview')
global_layout.addWidget(widget)
layout = QVBoxLayout(widget)
layout.setContentsMargins(0, 0, 0, 0)
self.project_path = ''
self.log_path = ''
self.error_path = ''
self.indicator_names = ('log', 'error', 'sys_log', 'notes')
self.indicator = indicator
self.text = QPlainTextEdit(widget)
if file_name:
self.text.setObjectName('dialog')
else:
self.text.setObjectName('status')
self.text.setPlaceholderText('Welcome to TranSPHIRE!')
self.text.setToolTip('Double click after starting TranSPHIRE in order to show more information')
self.text.setReadOnly(True)
self.text.setWordWrapMode(QTextOption.WrapAnywhere)
layout.addWidget(self.text, stretch=1)
self.file_name = file_name
self.buttons = {}
if show_indicators:
layout_h1 = QHBoxLayout()
for entry in self.indicator_names:
template = '{0}: {{0}}'.format(entry)
self.buttons[entry] = [QPushButton(self), template]
self.buttons[entry][0].setObjectName('button_entry')
self.buttons[entry][0].clicked.connect(self.my_click_event)
layout_h1.addWidget(self.buttons[entry][0])
self.increment_indicator(entry, '0')
layout_h1.addStretch(1)
layout.addLayout(layout_h1)
self.change_state(False)
self.update_plain_text(force=True)
self.timer = QTimer(self)
self.timer.setInterval(1000)
self.timer.timeout.connect(self.update_plain_text)
self.timer.start()
if self.indicator == 'notes':
layout_h = QHBoxLayout()
layout_h.setContentsMargins(0, 0, 0, 0)
self.input_edit = QLineEdit('', self)
submit_button = QPushButton('Submit', self)
submit_button.clicked.connect(self.submit_text)
layout_h.addWidget(self.input_edit, stretch=1)
layout_h.addWidget(submit_button)
layout.addLayout(layout_h)
[docs] @pyqtSlot()
def update_plain_text(self, force=False):
if self.file_name and os.path.exists(self.file_name):
with open(self.file_name, 'r') as read:
text = read.read()
if force:
self.reset_plain_text(text)
elif text.replace('\n', '').replace(' ', '') != self.text.toPlainText().replace('\n', '').replace(' ', ''):
self.reset_plain_text(text)
[docs] def reset_plain_text(self, text):
self.text.setPlainText(text)
cursor = self.text.textCursor()
cursor.movePosition(QTextCursor.End)
self.text.setTextCursor(cursor)
[docs] @pyqtSlot()
def submit_text(self):
self.appendPlainText(self.input_edit.text(), indicator='notes', user=True)
self.input_edit.setText('')
[docs] def appendPlainText(self, text, indicator='log', user=False):
text_raw = tu.create_log(text)
prefix, suffix = text_raw.split(' => ', 1)
if user:
text = '{}\n{}: {}\n'.format(prefix, getpass.getuser(), suffix)
else:
text = '{}\n{}\n'.format(prefix, suffix)
try:
with open(self.file_name, 'a+') as write:
write.write(text)
except IOError:
pass
self.text.appendPlainText(text)
cursor = self.text.textCursor()
cursor.movePosition(QTextCursor.End)
self.text.setTextCursor(cursor)
print(text)
if self.project_path:
self.increment_indicator(indicator)
[docs] def increment_indicator(self, indicator, text=''):
if indicator in self.indicator_names:
button, template = self.buttons[indicator]
if text:
cur_text = text
else:
cur_text = str(1 + int(self.get_indicator(indicator)))
button.setText(template.format(cur_text))
button.setToolTip(template.format(text))
if self.get_indicator(indicator) == '0':
button.setStyleSheet('')
else:
button.setStyleSheet(tu.get_style('changed'))
else:
assert False, indicator
[docs] def get_indicator(self, indicator):
if indicator in self.indicator_names:
return self.buttons[indicator][0].text().split(':')[-1].strip()
else:
assert False, indicator
[docs] @pyqtSlot()
def my_click_event(self, event=None):
if not self.project_path:
return None
sender = self.sender()
sender_text = sender.text().split(':')[0].strip()
is_notes = False
file_path = self.log_path
if sender_text == 'log':
file_names = ['log.txt']
elif sender_text == 'notes':
is_notes = True
file_names = ['notes.txt']
elif sender_text == 'sys_log':
file_names = ['sys_log.txt']
elif sender_text == 'error':
file_names = [os.path.basename(entry) for entry in glob.glob(os.path.join(self.error_path, '*'))]
file_path = self.error_path
else:
assert False, sender.text()
if not is_notes:
self.increment_indicator(sender_text, '0')
sender.setEnabled(False)
QTimer.singleShot(5000, lambda: sender.setEnabled(True))
dialog = logviewerdialog.LogViewerDialog(self)
for file_name in file_names:
dialog.add_tab(
LogViewer(file_name=os.path.join(file_path, file_name), indicator=sender_text, parent=self),
os.path.basename(file_name),
)
dialog.show()
[docs] @pyqtSlot(str, str, str)
def set_project_path(self, project_path, log_path, error_path):
self.project_path = project_path
self.log_path = log_path
self.error_path = error_path
state = True
if not self.project_path:
state = False
self.file_name = ''
elif not self.file_name:
self.file_name = os.path.join(self.log_path, 'log.txt')
self.update_plain_text(force=True)
self.change_state(state)
[docs] def change_state(self, state):
self.text.blockSignals(not state)
for button, _ in self.buttons.values():
button.setEnabled(state)
button.blockSignals(not state)