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