MythTV  master
logviewer.cpp
Go to the documentation of this file.
1 #include <chrono>
2 #include <cstdlib>
3 #include <iostream>
4 #include <unistd.h>
5 
6 // qt
7 #include <QKeyEvent>
8 #include <QFile>
9 #include <QTextStream>
10 #include <QCoreApplication>
11 
12 // mythtv
13 #include <mythcontext.h>
14 #include <mythdbcon.h>
15 #include <mythmainwindow.h>
16 #include <mythdialogbox.h>
17 #include <mythuibutton.h>
18 #include <mythuibuttonlist.h>
19 #include <mythuitext.h>
20 
21 // mytharchive
22 #include "archiveutil.h"
23 #include "logviewer.h"
24 
25 void showLogViewer(void)
26 {
28  QString logDir = getTempDirectory() + "logs";
29  QString progressLog;
30  QString fullLog;
31 
32  // wait for a log file to be available
33  int tries = 10;
34  while (tries--)
35  {
36  if (QFile::exists(logDir + "/progress.log"))
37  progressLog = logDir + "/progress.log";
38 
39  if (QFile::exists(logDir + "/mythburn.log"))
40  fullLog = logDir + "/mythburn.log";
41 
42  // we wait for both the progress.log and mythburn.log
43  if ((!progressLog.isEmpty()) && (!fullLog.isEmpty()))
44  break;
45 
46  // or we wait for a log from mytharchivehelper
47  if (progressLog.isEmpty() && fullLog.isEmpty())
48  {
49  QStringList logFiles;
50  QStringList filters;
51  filters << "*.log";
52 
53  QDir d(logDir);
54  logFiles = d.entryList(filters, QDir::Files | QDir::Readable, QDir::Time);
55 
56  if (!logFiles.isEmpty())
57  {
58  // the first log file should be the newest one available
59  progressLog = logDir + '/' + logFiles[0];
60  break;
61  }
62  }
63 
64  sleep(1);
65  }
66 
67  // do any logs exist?
68  if ((!progressLog.isEmpty()) || (!fullLog.isEmpty()))
69  {
70  auto *viewer = new LogViewer(mainStack);
71  viewer->setFilenames(progressLog, fullLog);
72  if (viewer->Create())
73  mainStack->AddScreen(viewer);
74  }
75  else
76  showWarningDialog(QCoreApplication::translate("LogViewer",
77  "Cannot find any logs to show!"));
78 }
79 
81  MythScreenType(parent, "logviewer")
82 {
83  m_updateTime = gCoreContext->GetDurSetting<std::chrono::seconds>(
84  "LogViewerUpdateTime", DEFAULT_UPDATE_TIME);
85  m_autoUpdate = gCoreContext->GetBoolSetting("LogViewerAutoUpdate", true);
86 }
87 
89 {
90  gCoreContext->SaveDurSetting("LogViewerUpdateTime", m_updateTime);
91  gCoreContext->SaveSetting("LogViewerAutoUpdate", m_autoUpdate ? "1" : "0");
92  delete m_updateTimer;
93 }
94 
96 {
97  // Load the theme for this screen
98  bool foundtheme = LoadWindowFromXML("mytharchive-ui.xml", "logviewer", this);
99  if (!foundtheme)
100  return false;
101 
102  bool err = false;
103  UIUtilE::Assign(this, m_logList, "loglist", &err);
104  UIUtilE::Assign(this, m_logText, "logitem_text", &err);
105  UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
106  UIUtilE::Assign(this, m_updateButton, "update_button", &err);
107  UIUtilE::Assign(this, m_exitButton, "exit_button", &err);
108 
109  if (err)
110  {
111  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'logviewer'");
112  return false;
113  }
114 
118 
120  this, &LogViewer::updateLogItem);
121 
122  m_updateTimer = nullptr;
123  m_updateTimer = new QTimer(this);
125 
126  BuildFocusList();
127 
129 
130  return true;
131 }
132 
133 void LogViewer::Init(void)
134 {
135  updateClicked();
136  if (m_logList->GetCount() > 0)
138 }
139 
140 bool LogViewer::keyPressEvent(QKeyEvent *event)
141 {
142  if (GetFocusWidget()->keyPressEvent(event))
143  return true;
144 
145  QStringList actions;
146  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
147 
148  for (int i = 0; i < actions.size() && !handled; i++)
149  {
150  QString action = actions[i];
151  handled = true;
152 
153  if (action == "MENU")
154  ShowMenu();
155  else
156  handled = false;
157  }
158 
159  if (!handled && MythScreenType::keyPressEvent(event))
160  handled = true;
161 
162  return handled;
163 }
164 
166 {
167  updateClicked();
168 }
169 
171 {
173 
174  if (m_autoUpdate)
175  m_updateTimer->start(m_updateTime);
176  else
177  m_updateTimer->stop();
178 }
179 
181 {
182  if (item)
183  m_logText->SetText(item->GetText());
184 }
185 
187 {
188  QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", "");
189  QFile lockFile(tempDir + "/logs/mythburncancel.lck");
190 
191  if (!lockFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
192  LOG(VB_GENERAL, LOG_ERR,
193  "LogViewer: Failed to create mythburncancel.lck file");
194 
195  lockFile.write("Cancel\n\r");
196  lockFile.close();
197 
198  ShowOkPopup(tr("Background creation has been asked to stop.\n"
199  "This may take a few minutes."));
200 }
201 
203 {
204  m_updateTimer->stop();
205 
206  QStringList list;
208 
209  if (!list.empty())
210  {
211  bool bUpdateCurrent =
212  (m_logList->GetCount() == m_logList->GetCurrentPos() + 1) ||
213  (m_logList->GetCurrentPos() == 0);
214 
215  for (const auto & label : qAsConst(list))
216  new MythUIButtonListItem(m_logList, label);
217 
218  if (bUpdateCurrent)
220  }
221 
222  bool bRunning = (getSetting("MythArchiveLastRunStatus") == "Running");
223 
224  if (!bRunning)
225  {
226  m_cancelButton->SetEnabled(false);
227  m_updateButton->SetEnabled(false);
228  }
229 
230  if (m_autoUpdate)
231  {
232  if (m_logList->GetCount() > 0)
233  m_updateTimer->start(m_updateTime);
234  else
235  m_updateTimer->start(500ms);
236  }
237 }
238 
239 QString LogViewer::getSetting(const QString &key)
240 {
241  // read the setting direct from the DB rather than from the settings cache
242  // which isn't aware that the script may have changed something
243  MSqlQuery query(MSqlQuery::InitCon());
244  if (query.isConnected())
245  {
246  query.prepare("SELECT data FROM settings WHERE value = :VALUE "
247  "AND hostname = :HOSTNAME ;");
248  query.bindValue(":VALUE", key);
249  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
250 
251  if (query.exec() && query.next())
252  {
253  return query.value(0).toString();
254  }
255  }
256  else
257  {
258  LOG(VB_GENERAL, LOG_ERR,
259  QString("Database not open while trying to load setting: %1")
260  .arg(key));
261  }
262 
263  return QString("");
264 }
265 
266 bool LogViewer::loadFile(const QString& filename, QStringList &list, int startline)
267 {
268  bool strip = !(filename.endsWith("progress.log") || filename.endsWith("mythburn.log"));
269 
270  list.clear();
271 
272  QFile file(filename);
273 
274  if (!file.exists())
275  return false;
276 
277  if (file.open( QIODevice::ReadOnly ))
278  {
279  QString s;
280  QTextStream stream(&file);
281 
282  // ignore the first startline lines
283  while ( !stream.atEnd() && startline > 0)
284  {
285  stream.readLine();
286  startline--;
287  }
288 
289  // read rest of file
290  while ( !stream.atEnd() )
291  {
292  s = stream.readLine();
293 
294  if (strip)
295  {
296  // the logging from mytharchivehelper contains a lot of junk
297  // we are not interested in so just strip it out
298  int pos = s.indexOf(" - ");
299  if (pos != -1)
300  s = s.mid(pos + 3);
301  }
302 
303  list.append(s);
304  }
305  file.close();
306  }
307  else
308  return false;
309 
310  return true;
311 }
312 
313 void LogViewer::setFilenames(const QString &progressLog, const QString &fullLog)
314 {
315  m_progressLog = progressLog;
316  m_fullLog = fullLog;
317  m_currentLog = progressLog;
318 }
319 
321 {
323  m_logList->Reset();
324  updateClicked();
325 }
326 
328 {
330  m_logList->Reset();
331  updateClicked();
332 }
333 
335 {
336  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
337  auto *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
338 
339  if (menuPopup->Create())
340  popupStack->AddScreen(menuPopup);
341 
342  menuPopup->SetReturnEvent(this, "action");
343 
344  if (m_autoUpdate)
345  menuPopup->AddButton(tr("Don't Auto Update"), &LogViewer::toggleAutoUpdate);
346  else
347  menuPopup->AddButton(tr("Auto Update"), &LogViewer::toggleAutoUpdate);
348 
349  menuPopup->AddButton(tr("Show Progress Log"), &LogViewer::showProgressLog);
350  menuPopup->AddButton(tr("Show Full Log"), &LogViewer::showFullLog);
351 }
LogViewer::toggleAutoUpdate
void toggleAutoUpdate(void)
Definition: logviewer.cpp:170
MythUIButton::Clicked
void Clicked()
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:802
LogViewer::~LogViewer
~LogViewer(void) override
Definition: logviewer.cpp:88
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:314
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
LogViewer::setFilenames
void setFilenames(const QString &progressLog, const QString &fullLog)
Definition: logviewer.cpp:313
mythuitext.h
DEFAULT_UPDATE_TIME
static constexpr std::chrono::seconds DEFAULT_UPDATE_TIME
Definition: logviewer.h:10
LogViewer::updateLogItem
void updateLogItem(MythUIButtonListItem *item)
Definition: logviewer.cpp:180
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:385
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:201
MythScreenStack
Definition: mythscreenstack.h:16
mythdbcon.h
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
logviewer.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:44
build_compdb.file
file
Definition: build_compdb.py:55
LogViewer
Definition: logviewer.h:18
MythCoreContext::SaveDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, void > SaveDurSetting(const QString &key, T newValue)
Definition: mythcorecontext.h:157
getTempDirectory
QString getTempDirectory(bool showError)
Definition: archiveutil.cpp:68
mythuibuttonlist.h
LogViewer::cancelClicked
static void cancelClicked(void)
Definition: logviewer.cpp:186
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1655
LogViewer::Create
bool Create(void) override
Definition: logviewer.cpp:95
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:112
showWarningDialog
void showWarningDialog(const QString &msg)
Definition: archiveutil.cpp:294
MythUIButtonListItem
Definition: mythuibuttonlist.h:34
LogViewer::getSetting
static QString getSetting(const QString &key)
Definition: logviewer.cpp:239
LogViewer::m_autoUpdate
bool m_autoUpdate
Definition: logviewer.h:47
LogViewer::m_exitButton
MythUIButton * m_exitButton
Definition: logviewer.h:58
LogViewer::m_updateButton
MythUIButton * m_updateButton
Definition: logviewer.h:60
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1102
MythUIButtonList::GetCurrentPos
int GetCurrentPos() const
Definition: mythuibuttonlist.h:224
archiveutil.h
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:117
MythDialogBox
Basic menu dialog, message and a list of options.
Definition: mythdialogbox.h:166
LogViewer::m_updateTimer
QTimer * m_updateTimer
Definition: logviewer.h:49
LogViewer::ShowMenu
void ShowMenu(void) override
Definition: logviewer.cpp:334
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
MythCoreContext::GetDurSetting
std::enable_if_t< std::chrono::__is_duration< T >::value, T > GetDurSetting(const QString &key, T defaultval=T::zero())
Definition: mythcorecontext.h:170
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:205
LogViewer::m_logText
MythUIText * m_logText
Definition: logviewer.h:56
showLogViewer
void showLogViewer(void)
Definition: logviewer.cpp:25
LogViewer::Init
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: logviewer.cpp:133
MythUIType::SetEnabled
void SetEnabled(bool enable)
Definition: mythuitype.cpp:1124
LogViewer::m_cancelButton
MythUIButton * m_cancelButton
Definition: logviewer.h:59
MSqlQuery::isConnected
bool isConnected(void) const
Only updated once during object creation.
Definition: mythdbcon.h:134
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
UIUtilDisp::Assign
static bool Assign(ContainerType *container, UIType *&item, const QString &name, bool *err=nullptr)
Definition: mythuiutils.h:27
MythCoreContext::GetBoolSetting
bool GetBoolSetting(const QString &key, bool defaultval=false)
Definition: mythcorecontext.cpp:930
MythUIButtonListItem::GetText
QString GetText(const QString &name="") const
Definition: mythuibuttonlist.cpp:3318
LogViewer::showFullLog
void showFullLog(void)
Definition: logviewer.cpp:327
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:397
LogViewer::LogViewer
LogViewer(MythScreenStack *parent)
Definition: logviewer.cpp:80
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:692
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:878
LogViewer::showProgressLog
void showProgressLog(void)
Definition: logviewer.cpp:320
LogViewer::updateTimerTimeout
void updateTimerTimeout(void)
Definition: logviewer.cpp:165
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:133
mythcontext.h
MythUIButtonList::Reset
void Reset() override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuibuttonlist.cpp:114
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:101
MythUIButtonList::SetItemCurrent
void SetItemCurrent(MythUIButtonListItem *item)
Definition: mythuibuttonlist.cpp:1557
build_compdb.action
action
Definition: build_compdb.py:9
mythuibutton.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:319
LogViewer::m_progressLog
QString m_progressLog
Definition: logviewer.h:52
LogViewer::loadFile
static bool loadFile(const QString &filename, QStringList &list, int startline)
Definition: logviewer.cpp:266
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:862
LogViewer::updateClicked
void updateClicked(void)
Definition: logviewer.cpp:202
LogViewer::m_updateTime
std::chrono::seconds m_updateTime
Definition: logviewer.h:48
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:905
LogViewer::m_logList
MythUIButtonList * m_logList
Definition: logviewer.h:55
build_compdb.filename
filename
Definition: build_compdb.py:21
mythmainwindow.h
LogViewer::m_currentLog
QString m_currentLog
Definition: logviewer.h:51
LogViewer::m_fullLog
QString m_fullLog
Definition: logviewer.h:53
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:558
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:922
LogViewer::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: logviewer.cpp:140
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:827