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