MythTV  master
mythterminal.cpp
Go to the documentation of this file.
1 /*
2  * Class MythTerminal
3  *
4  * Copyright (C) Daniel Kristjansson 2008
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include <cinttypes>
22 #include <utility>
23 
24 // MythTV headers
25 #include "mythlogging.h"
26 #include "mythterminal.h"
27 #include "mythuibutton.h"
28 #include "mythuibuttonlist.h"
29 #include "mythuitextedit.h"
30 
31 MythTerminal::MythTerminal(MythScreenStack *parent, QString _program,
32  QStringList _arguments) :
33  MythScreenType(parent, "terminal"),
34  m_process(new QProcess()), m_program(std::move(_program)),
35  m_arguments(std::move(_arguments))
36 {
37  m_process->setProcessChannelMode(QProcess::MergedChannels);
38  connect(m_process, SIGNAL(readyRead()),
39  this, SLOT(ProcessHasText()));
40 
41  connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)),
42  this, SLOT( ProcessFinished(int, QProcess::ExitStatus)));
43 }
44 
46 {
47  if (m_process)
48  {
49  QMutexLocker locker(&m_lock);
50  if (m_process)
51  {
52  if (m_running)
53  Kill();
54  m_process->disconnect();
55  m_process->deleteLater();
56  m_process = nullptr;
57  }
58  }
59 }
60 
61 void MythTerminal::AddText(const QString &_str)
62 {
63  QMutexLocker locker(&m_lock);
64  QString str = _str;
65  while (str.length())
66  {
67  int nlf = str.indexOf("\r\n");
68  nlf = (nlf < 0) ? str.indexOf("\r") : nlf;
69  nlf = (nlf < 0) ? str.indexOf("\n") : nlf;
70 
71  QString curStr = (nlf >= 0) ? str.left(nlf) : str;
72  if (curStr.length())
73  {
74  if (!m_currentLine)
76  else
78  }
79 
80  if (nlf >= 0)
81  {
84  str = str.mid(nlf + 1);
85  }
86  else
87  {
88  str = "";
89  }
90  }
91 }
92 
94 {
95  QMutexLocker locker(&m_lock);
97  m_running = true;
98 }
99 
101 {
102  QMutexLocker locker(&m_lock);
103  m_process->kill();
104  m_running = false;
105 }
106 
107 bool MythTerminal::IsDone(void) const
108 {
109  QMutexLocker locker(&m_lock);
110  return QProcess::NotRunning == m_process->state();
111 }
112 
114 {
115  QMutexLocker locker(&m_lock);
116  int64_t len = m_process->bytesAvailable();
117 
118  if (len <= 0)
119  return;
120 
121  QByteArray buf = m_process->read(len);
122  AddText(QString(buf));
123 }
124 
126 {
127  Start();
128 }
129 
131  int exitCode, QProcess::ExitStatus exitStatus)
132 {
133  QMutexLocker locker(&m_lock);
134  if (exitStatus == QProcess::CrashExit) {
135  AddText(tr("*** Crashed with status: %1 ***").arg(exitCode));
136  } else {
137  AddText(tr("*** Exited with status: %1 ***").arg(exitCode));
138  }
139  m_running = false;
140  m_enterButton->SetEnabled(false);
141  m_textEdit->SetEnabled(false);
142 }
143 
145 {
146  if (!LoadWindowFromXML("standardsetting-ui.xml", "terminal", this))
147  return false;
148 
149  bool error = false;
150  UIUtilE::Assign(this, m_output, "output", &error);
151  UIUtilE::Assign(this, m_textEdit, "textedit", &error);
152  UIUtilE::Assign(this, m_enterButton, "enter", &error);
153 
154  if (error)
155  {
156  LOG(VB_GENERAL, LOG_ERR, "Theme elements missing.");
157  return false;
158  }
159 
160  BuildFocusList();
161 
162  MythUIButton *close = nullptr;
163  UIUtilW::Assign(this, close, "close");
164  if (close)
165  connect(close, SIGNAL(Clicked()), this, SLOT(Close()));
166 
168  this,
169  [this]()
170  {
171  QMutexLocker locker(&m_lock);
172  if (m_running)
173  {
174  QString text = m_textEdit->GetText() + "\r\n";
175  AddText(text);
176 
177  m_process->write(text.toLocal8Bit().constData());
178  }
179  });
180 
181  return true;
182 }
MythUIButton * m_enterButton
Definition: mythterminal.h:55
void ProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
MythUIButtonList * m_output
Definition: mythterminal.h:53
void SetEnabled(bool enable)
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
void Kill(void)
static void error(const char *str,...)
Definition: vbi.c:42
void AddText(const QString &)
void BuildFocusList(void)
QString m_program
Definition: mythterminal.h:50
virtual void Close()
MythUITextEdit * m_textEdit
Definition: mythterminal.h:54
QProcess * m_process
Definition: mythterminal.h:49
MythTerminal(MythScreenStack *parent, QString program, QStringList arguments)
bool IsDone(void) const
#define close
Definition: compat.h:16
bool Create(void) override
QStringList m_arguments
Definition: mythterminal.h:51
MythUIButtonListItem * m_currentLine
Definition: mythterminal.h:52
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
void SetText(const QString &text, const QString &name="", const QString &state="")
void Clicked()
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
A single button widget.
Definition: mythuibutton.h:21
QString GetText(const QString &name="") const
void TeardownAll(void)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void ProcessHasText(void)
void SetItemCurrent(MythUIButtonListItem *item)
Screen in which all other widgets are contained and rendered.
QMutex m_lock
Definition: mythterminal.h:47
void Start(void)
QString GetText(void) const