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  showWarningDialog(QCoreApplication::translate("LogViewer",
76  "Cannot find any logs to show!"));
77 }
78 
80 {
81  gCoreContext->SaveDurSetting("LogViewerUpdateTime", m_updateTime);
82  gCoreContext->SaveSetting("LogViewerAutoUpdate", m_autoUpdate ? "1" : "0");
83  delete m_updateTimer;
84 }
85 
87 {
88  // Load the theme for this screen
89  bool foundtheme = LoadWindowFromXML("mytharchive-ui.xml", "logviewer", this);
90  if (!foundtheme)
91  return false;
92 
93  bool err = false;
94  UIUtilE::Assign(this, m_logList, "loglist", &err);
95  UIUtilE::Assign(this, m_logText, "logitem_text", &err);
96  UIUtilE::Assign(this, m_cancelButton, "cancel_button", &err);
97  UIUtilE::Assign(this, m_updateButton, "update_button", &err);
98  UIUtilE::Assign(this, m_exitButton, "exit_button", &err);
99 
100  if (err)
101  {
102  LOG(VB_GENERAL, LOG_ERR, "Cannot load screen 'logviewer'");
103  return false;
104  }
105 
109 
111  this, &LogViewer::updateLogItem);
112 
113  m_updateTimer = nullptr;
114  m_updateTimer = new QTimer(this);
116 
117  BuildFocusList();
118 
120 
121  return true;
122 }
123 
124 void LogViewer::Init(void)
125 {
126  updateClicked();
127  if (m_logList->GetCount() > 0)
129 }
130 
131 bool LogViewer::keyPressEvent(QKeyEvent *event)
132 {
133  if (GetFocusWidget()->keyPressEvent(event))
134  return true;
135 
136  QStringList actions;
137  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
138 
139  for (int i = 0; i < actions.size() && !handled; i++)
140  {
141  QString action = actions[i];
142  handled = true;
143 
144  if (action == "MENU")
145  ShowMenu();
146  else
147  handled = false;
148  }
149 
150  if (!handled && MythScreenType::keyPressEvent(event))
151  handled = true;
152 
153  return handled;
154 }
155 
157 {
158  updateClicked();
159 }
160 
162 {
164 
165  if (m_autoUpdate)
166  m_updateTimer->start(m_updateTime);
167  else
168  m_updateTimer->stop();
169 }
170 
172 {
173  if (item)
174  m_logText->SetText(item->GetText());
175 }
176 
178 {
179  QString tempDir = gCoreContext->GetSetting("MythArchiveTempDir", "");
180  QFile lockFile(tempDir + "/logs/mythburncancel.lck");
181 
182  if (!lockFile.open(QIODevice::WriteOnly | QIODevice::Truncate))
183  LOG(VB_GENERAL, LOG_ERR,
184  "LogViewer: Failed to create mythburncancel.lck file");
185 
186  lockFile.write("Cancel\n\r");
187  lockFile.close();
188 
189  ShowOkPopup(tr("Background creation has been asked to stop.\n"
190  "This may take a few minutes."));
191 }
192 
194 {
195  m_updateTimer->stop();
196 
197  QStringList list;
199 
200  if (!list.empty())
201  {
202  bool bUpdateCurrent =
203  (m_logList->GetCount() == m_logList->GetCurrentPos() + 1) ||
204  (m_logList->GetCurrentPos() == 0);
205 
206  for (const auto & label : std::as_const(list))
207  new MythUIButtonListItem(m_logList, label);
208 
209  if (bUpdateCurrent)
211  }
212 
213  bool bRunning = (getSetting("MythArchiveLastRunStatus") == "Running");
214 
215  if (!bRunning)
216  {
217  m_cancelButton->SetEnabled(false);
218  m_updateButton->SetEnabled(false);
219  }
220 
221  if (m_autoUpdate)
222  {
223  if (m_logList->GetCount() > 0)
224  m_updateTimer->start(m_updateTime);
225  else
226  m_updateTimer->start(500ms);
227  }
228 }
229 
230 QString LogViewer::getSetting(const QString &key)
231 {
232  // read the setting direct from the DB rather than from the settings cache
233  // which isn't aware that the script may have changed something
234  MSqlQuery query(MSqlQuery::InitCon());
235  if (query.isConnected())
236  {
237  query.prepare("SELECT data FROM settings WHERE value = :VALUE "
238  "AND hostname = :HOSTNAME ;");
239  query.bindValue(":VALUE", key);
240  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
241 
242  if (query.exec() && query.next())
243  {
244  return query.value(0).toString();
245  }
246  }
247  else
248  {
249  LOG(VB_GENERAL, LOG_ERR,
250  QString("Database not open while trying to load setting: %1")
251  .arg(key));
252  }
253 
254  return {""};
255 }
256 
257 bool LogViewer::loadFile(const QString& filename, QStringList &list, int startline)
258 {
259  bool strip = !(filename.endsWith("progress.log") || filename.endsWith("mythburn.log"));
260 
261  list.clear();
262 
263  QFile file(filename);
264 
265  if (!file.exists())
266  return false;
267 
268  if (file.open( QIODevice::ReadOnly ))
269  {
270  QString s;
271  QTextStream stream(&file);
272 
273  // ignore the first startline lines
274  while ( !stream.atEnd() && startline > 0)
275  {
276  stream.readLine();
277  startline--;
278  }
279 
280  // read rest of file
281  while ( !stream.atEnd() )
282  {
283  s = stream.readLine();
284 
285  if (strip)
286  {
287  // the logging from mytharchivehelper contains a lot of junk
288  // we are not interested in so just strip it out
289  int pos = s.indexOf(" - ");
290  if (pos != -1)
291  s = s.mid(pos + 3);
292  }
293 
294  list.append(s);
295  }
296  file.close();
297  }
298  else
299  return false;
300 
301  return true;
302 }
303 
304 void LogViewer::setFilenames(const QString &progressLog, const QString &fullLog)
305 {
306  m_progressLog = progressLog;
307  m_fullLog = fullLog;
308  m_currentLog = progressLog;
309 }
310 
312 {
314  m_logList->Reset();
315  updateClicked();
316 }
317 
319 {
321  m_logList->Reset();
322  updateClicked();
323 }
324 
326 {
327  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
328  auto *menuPopup = new MythDialogBox(tr("Menu"), popupStack, "actionmenu");
329 
330  if (menuPopup->Create())
331  popupStack->AddScreen(menuPopup);
332 
333  menuPopup->SetReturnEvent(this, "action");
334 
335  if (m_autoUpdate)
336  menuPopup->AddButton(tr("Don't Auto Update"), &LogViewer::toggleAutoUpdate);
337  else
338  menuPopup->AddButton(tr("Auto Update"), &LogViewer::toggleAutoUpdate);
339 
340  menuPopup->AddButton(tr("Show Progress Log"), &LogViewer::showProgressLog);
341  menuPopup->AddButton(tr("Show Full Log"), &LogViewer::showFullLog);
342 }
LogViewer::toggleAutoUpdate
void toggleAutoUpdate(void)
Definition: logviewer.cpp:161
MythUIButton::Clicked
void Clicked()
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:813
LogViewer::~LogViewer
~LogViewer(void) override
Definition: logviewer.cpp:79
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:127
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:318
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:102
LogViewer::setFilenames
void setFilenames(const QString &progressLog, const QString &fullLog)
Definition: logviewer.cpp:304
mythuitext.h
LogViewer::updateLogItem
void updateLogItem(MythUIButtonListItem *item)
Definition: logviewer.cpp:171
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:386
MythUIButtonList::itemSelected
void itemSelected(MythUIButtonListItem *item)
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:619
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:177
MythUIButtonList::GetCount
int GetCount() const
Definition: mythuibuttonlist.cpp:1656
LogViewer::Create
bool Create(void) override
Definition: logviewer.cpp:86
MythScreenType::GetFocusWidget
MythUIType * GetFocusWidget(void) const
Definition: mythscreentype.cpp:113
showWarningDialog
void showWarningDialog(const QString &msg)
Definition: archiveutil.cpp:272
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
LogViewer::getSetting
static QString getSetting(const QString &key)
Definition: logviewer.cpp:230
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:1112
MythUIButtonList::GetCurrentPos
int GetCurrentPos() const
Definition: mythuibuttonlist.h:238
archiveutil.h
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:118
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:325
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:551
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
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:124
MythUIType::SetEnabled
void SetEnabled(bool enable)
Definition: mythuitype.cpp:1133
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:3315
LogViewer::showFullLog
void showFullLog(void)
Definition: logviewer.cpp:318
MythScreenType::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
Definition: mythscreentype.cpp:404
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:687
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:889
LogViewer::showProgressLog
void showProgressLog(void)
Definition: logviewer.cpp:311
LogViewer::updateTimerTimeout
void updateTimerTimeout(void)
Definition: logviewer.cpp:156
MythUIText::SetText
virtual void SetText(const QString &text)
Definition: mythuitext.cpp:132
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:1558
build_compdb.action
action
Definition: build_compdb.py:9
mythuibutton.h
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:323
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:257
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:838
LogViewer::updateClicked
void updateClicked(void)
Definition: logviewer.cpp:193
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:881
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:562
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:898
LogViewer::keyPressEvent
bool keyPressEvent(QKeyEvent *e) override
Key event handler.
Definition: logviewer.cpp:131
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:838