MythTV  master
lcdprocclient.cpp
Go to the documentation of this file.
1 /*
2  lcdprocclient.cpp
3 
4  a MythTV project object to control an
5  LCDproc server
6 
7  (c) 2002, 2003 Thor Sigvaldason, Dan Morphis and Isaac Richards
8 */
9 
10 // c/c++
11 #include <chrono> // for milliseconds
12 #include <cmath>
13 #include <cstdlib>
14 #include <thread> // for sleep_for
15 
16 //qt
17 #include <QCoreApplication>
18 #include <QEvent>
19 #include <QTimer>
20 #include <utility>
21 
22 // mythtv
23 #include "mythcontext.h"
24 #include "mythdbcon.h"
25 #include "mythdate.h"
26 #include "tv.h"
27 #include "compat.h"
28 
29 //mythlcdserver
30 #include "lcdprocclient.h"
31 #include "lcdserver.h"
32 #include "lcddevice.h"
33 
34 #define LCD_START_COL 3
35 
36 #define LCD_VERSION_4 1
37 #define LCD_VERSION_5 2
38 
39 #define LCD_RECSTATUS_TIME 10000
40 #define LCD_TIME_TIME 3000
41 #define LCD_SCROLLLIST_TIME 2000
42 
44 
46  : QObject(nullptr),
47  m_socket(new QTcpSocket(this)),
48  m_timeTimer (new QTimer(this)),
49  m_scrollWTimer (new QTimer(this)),
50  m_preScrollWTimer (new QTimer(this)),
51  m_menuScrollTimer (new QTimer(this)),
52  m_menuPreScrollTimer (new QTimer(this)),
53  m_popMenuTimer (new QTimer(this)),
54  m_checkConnectionsTimer (new QTimer(this)),
55  m_recStatusTimer (new QTimer(this)),
56  m_scrollListTimer (new QTimer(this)),
57  m_showMessageTimer (new QTimer(this)),
58  m_updateRecInfoTimer (new QTimer(this)),
59  m_lcdTextItems (new QList<LCDTextItem>),
60  m_lcdMenuItems (new QList<LCDMenuItem>),
61  m_parentLCDServer (lparent)
62 {
63  // Constructor for LCDProcClient
64  //
65  // Note that this does *not* include opening the socket and initiating
66  // communications with the LDCd daemon.
67 
68  if (debug_level > 0)
69  LOG(VB_GENERAL, LOG_INFO,
70  "LCDProcClient: An LCDProcClient object now exists");
71 
72  connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)),
73  this, SLOT(veryBadThings(QAbstractSocket::SocketError)));
74  connect(m_socket, SIGNAL(readyRead()), this, SLOT(serverSendingData()));
75 
77  if ( m_lcdWidth < 12)
78  {
79  if ( m_lcdHeight == 1)
80  lcdStartCol = 0;
81  else
82  lcdStartCol = 1;
83  }
84 
85  connect( m_timeTimer, SIGNAL(timeout()), this, SLOT(outputTime()));
86 
87  connect( m_scrollWTimer, SIGNAL(timeout()), this, SLOT(scrollWidgets()));
88 
89  m_preScrollWTimer->setSingleShot(true);
90  connect( m_preScrollWTimer, SIGNAL(timeout()), this,
91  SLOT(beginScrollingWidgets()));
92 
93  m_popMenuTimer->setSingleShot(true);
94  connect( m_popMenuTimer, SIGNAL(timeout()), this, SLOT(unPopMenu()));
95 
96  connect( m_menuScrollTimer, SIGNAL(timeout()), this, SLOT(scrollMenuText()));
97 
98  connect( m_menuPreScrollTimer, SIGNAL(timeout()), this,
99  SLOT(beginScrollingMenuText()));
100 
101  connect( m_checkConnectionsTimer, SIGNAL(timeout()), this,
102  SLOT(checkConnections()));
103  m_checkConnectionsTimer->start(10000);
104 
105  connect( m_recStatusTimer, SIGNAL(timeout()), this, SLOT(outputRecStatus()));
106 
107  connect( m_scrollListTimer, SIGNAL(timeout()), this, SLOT(scrollList()));
108 
109  m_showMessageTimer->setSingleShot(true);
110  connect( m_showMessageTimer, SIGNAL(timeout()), this,
111  SLOT(removeStartupMessage()));
112 
113  m_updateRecInfoTimer->setSingleShot(true);
114  connect( m_updateRecInfoTimer, SIGNAL(timeout()), this,
115  SLOT(updateRecordingList()));
116 
117  gCoreContext->addListener(this);
118 }
119 
121 {
122  QString lcd_host = gCoreContext->GetSetting("LCDHost", "localhost");
123  int lcd_port = gCoreContext->GetNumSetting("LCDPort", 13666);
124 
125  if (lcd_host.length() > 0 && lcd_port > 1024)
126  connectToHost(lcd_host, lcd_port);
127 
128  return m_connected;
129 }
130 
131 bool LCDProcClient::connectToHost(const QString &lhostname, unsigned int lport)
132 {
133  // Open communications
134  // Store the hostname and port in case we need to reconnect.
135 
136  // cppcheck-suppress variableScope
137  int timeout = 1000;
138  m_hostname = lhostname;
139  m_port = lport;
140 
141  // Don't even try to connect if we're currently disabled.
142  if (!gCoreContext->GetBoolSetting("LCDEnable", false))
143  {
144  m_connected = false;
145  return m_connected;
146  }
147 
148  if (!m_connected )
149  {
150  QTextStream os(m_socket);
151  m_socket->connectToHost(m_hostname, m_port);
152 
153  while (--timeout && m_socket->state() != QAbstractSocket::ConnectedState)
154  {
155  qApp->processEvents();
156  std::this_thread::sleep_for(std::chrono::milliseconds(1));
157 
158  if (m_socket->state() == QAbstractSocket::ConnectedState)
159  {
160  m_connected = true;
161  os << "hello\n";
162  break;
163  }
164  }
165  }
166 
167  return m_connected;
168 }
169 
170 void LCDProcClient::sendToServer(const QString &someText)
171 {
172  // Check the socket, make sure the connection is still up
173  if (m_socket->state() != QAbstractSocket::ConnectedState)
174  {
175  if (!m_lcdReady )
176  return;
177 
178  m_lcdReady = false;
179 
180  //Stop everything
181  stopAll();
182 
183  // Ack, connection to server has been severed try to re-establish the
184  // connection
185  LOG(VB_GENERAL, LOG_ERR,
186  "LCDProcClient: Connection to LCDd died unexpectedly.");
187  return;
188  }
189 
190  QTextStream os(m_socket);
191  os.setCodec("ISO 8859-1");
192 
193  m_lastCommand = someText;
194 
195  if ( m_connected )
196  {
197  if (debug_level > 9)
198  LOG(VB_NETWORK, LOG_INFO,
199  "LCDProcClient: Sending to Server: " + someText);
200 
201  // Just stream the text out the socket
202 
203  os << someText << "\n";
204  }
205  else
206  {
207  // Buffer this up in the hope that the connection will open soon
208 
209  m_sendBuffer += someText;
210  m_sendBuffer += "\n";
211  }
212 }
213 
214 void LCDProcClient::setPriority(const QString &screen, PRIORITY priority)
215 {
216  QString aString;
217  int err = 0;
218  aString = "screen_set ";
219  aString += screen;
220  aString += " priority ";
221 
222  switch (priority) {
223  case TOP:
224  aString += m_prioTop;
225  break;
226  case URGENT:
227  aString += m_prioUrgent;
228  break;
229  case HIGH:
230  aString += m_prioHigh;
231  break;
232  case MEDIUM:
233  aString += m_prioMedium;
234  break;
235  case LOW:
236  aString += m_prioLow;
237  break;
238  case OFF:
239  aString += m_prioOff;
240  break;
241  default:
242  err = 1;
243  break;
244  }
245  if (err == 0)
246  sendToServer (aString);
247 }
248 
249 void LCDProcClient::setHeartbeat (const QString &screen, bool onoff)
250 {
251  QString msg;
252  if (onoff)
253  {
254  if ( m_pVersion == LCD_VERSION_4)
255  {
256  msg = "widget_add " + screen + " heartbeat";
257  }
258  if ( m_pVersion == LCD_VERSION_5)
259  {
260  msg = "screen_set " + screen + " heartbeat on";
261  }
262  }
263  else
264  {
265  if ( m_pVersion == LCD_VERSION_4)
266  {
267  msg = "widget_del " + screen + " heartbeat";
268  }
269  if ( m_pVersion == LCD_VERSION_5)
270  {
271  msg = "screen_set " + screen + " heartbeat off";
272  }
273  }
274  sendToServer (msg);
275 }
276 
278 {
279  if (debug_level > 0)
280  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: checking connections");
281 
282  // check connection to mythbackend
284  {
285  if (debug_level > 0)
286  LOG(VB_GENERAL, LOG_INFO,
287  "LCDProcClient: connecting to master server");
288  if (!gCoreContext->ConnectToMasterServer(false))
289  LOG(VB_GENERAL, LOG_ERR,
290  "LCDProcClient: connecting to master server failed");
291  }
292 
293  //check connection to LCDProc server
294  if (m_socket->state() != QAbstractSocket::ConnectedState)
295  {
296  if (debug_level > 0)
297  LOG(VB_GENERAL, LOG_INFO,
298  "LCDProcClient: connecting to LCDProc server");
299 
300  m_lcdReady = false;
301  m_connected = false;
302 
303  // Retry to connect. . . Maybe the user restarted LCDd?
305  }
306 }
307 
309 {
310  QString lineFromServer;
311  QString tempString;
312  QStringList aList;
313  QStringList::Iterator it;
314 
315  // This gets activated automatically by the QSocket class whenever
316  // there's something to read.
317  //
318  // We currently spend most of our time (except for the first line sent
319  // back) ignoring it.
320  //
321  // Note that if anyone has an LCDproc type lcd with buttons on it, this is
322  // where we would want to catch button presses and make the rest of
323  // mythTV/mythMusic do something (change tracks, channels, etc.)
324 
325  while(m_socket->canReadLine())
326  {
327  lineFromServer = m_socket->readLine();
328  lineFromServer = lineFromServer.replace( QRegExp("\n"), "" );
329  lineFromServer = lineFromServer.replace( QRegExp("\r"), "" );
330 
331  if (debug_level > 0)
332  {
333  // Make debugging be less noisy
334  if (lineFromServer != "success")
335  LOG(VB_NETWORK, LOG_INFO,
336  "LCDProcClient: Received from server: " + lineFromServer);
337  }
338 
339  aList = lineFromServer.split(" ");
340  if (aList.first() == "connect")
341  {
342  // We got a connect, which is a response to "hello"
343  //
344  // Need to parse out some data according the LCDproc client/server
345  // spec (which is poorly documented)
346  it = aList.begin();
347  it++;
348  if ((*it) != "LCDproc")
349  {
350  LOG(VB_GENERAL, LOG_WARNING,
351  "LCDProcClient: WARNING: Second parameter "
352  "returned from LCDd was not \"LCDproc\"");
353  }
354 
355  // Skip through some stuff
356  it++; // server version
357  QString server_version = *it;
358  it++; // the string "protocol"
359  it++; // protocol version
360  QString protocol_version = *it;
361  setVersion (server_version, protocol_version);
362  it++; // the string "lcd"
363  it++; // the string "wid";
364  it++; // Ah, the LCD width
365 
366  tempString = *it;
367  setWidth(tempString.toInt());
368 
369  it++; // the string "hgt"
370  it++; // the LCD height
371 
372  tempString = *it;
373  setHeight(tempString.toInt());
374  it++; // the string "cellwid"
375  it++; // Cell width in pixels;
376 
377  tempString = *it;
378  setCellWidth(tempString.toInt());
379 
380  it++; // the string "cellhgt"
381  it++; // Cell height in pixels;
382 
383  tempString = *it;
384  setCellHeight(tempString.toInt());
385 
386  init();
387 
388  describeServer();
389  }
390 
391  if (aList.first() == "huh?")
392  {
393  LOG(VB_GENERAL, LOG_WARNING,
394  "LCDProcClient: WARNING: Something is getting"
395  "passed to LCDd that it doesn't understand");
396  LOG(VB_GENERAL, LOG_WARNING, "last command: " + m_lastCommand );
397  }
398  else if (aList.first() == "key")
399  {
400  if ( m_parentLCDServer )
401  m_parentLCDServer->sendKeyPress(aList.last().trimmed());
402  }
403  }
404 }
405 
407 {
408  QString aString;
409  m_lcdKeyString = "";
410 
411  m_connected = true;
412 
413  // This gets called when we receive the "connect" string from the server
414  // indicating that "hello" was succesful
415  sendToServer("client_set name Myth");
416 
417  // Create all the screens and widgets (when we change activity in the myth
418  // program, we just swap the priorities of the screens to show only the
419  // "current one")
420  sendToServer("screen_add Time");
421  setPriority("Time", MEDIUM);
422 
423  if (gCoreContext->GetSetting("LCDBigClock", "1") == "1")
424  {
425  // Big Clock - spans multiple lines
426  sendToServer("widget_add Time rec1 string");
427  sendToServer("widget_add Time rec2 string");
428  sendToServer("widget_add Time rec3 string");
429  sendToServer("widget_add Time recCnt string");
430  sendToServer("widget_add Time d0 num");
431  sendToServer("widget_add Time d1 num");
432  sendToServer("widget_add Time sep num");
433  sendToServer("widget_add Time d2 num");
434  sendToServer("widget_add Time d3 num");
435  sendToServer("widget_add Time ampm string");
436  sendToServer("widget_add Time dot string");
437  }
438  else
439  {
440  sendToServer("widget_add Time timeWidget string");
441  sendToServer("widget_add Time topWidget string");
442  }
443 
444  // The Menu Screen
445  // I'm not sure how to do multi-line widgets with lcdproc so we're going
446  // the ghetto way
447  sendToServer("screen_add Menu");
448  setPriority("Menu", LOW);
449  sendToServer("widget_add Menu topWidget string");
450  for (unsigned int i = 1; i <= m_lcdHeight; i++)
451  {
452  aString = "widget_add Menu menuWidget";
453  aString += QString::number (i);
454  aString += " string";
455  sendToServer(aString);
456  }
457 
458  // The Music Screen
459  sendToServer("screen_add Music");
460  setPriority("Music", LOW);
461  sendToServer("widget_add Music topWidget1 string");
462  sendToServer("widget_add Music topWidget2 string");
463  sendToServer("widget_add Music timeWidget string");
464  sendToServer("widget_add Music infoWidget string");
465  sendToServer("widget_add Music progressBar hbar");
466 
467  // The Channel Screen
468  sendToServer("screen_add Channel");
469  setPriority("Channel", LOW);
470  sendToServer("widget_add Channel topWidget string");
471  sendToServer("widget_add Channel botWidget string");
472  sendToServer("widget_add Channel timeWidget string");
473  sendToServer("widget_add Channel progressBar hbar");
474 
475  // The Generic Screen
476  sendToServer("screen_add Generic");
477  setPriority("Generic", LOW);
478  sendToServer("widget_add Generic textWidget1 string");
479  sendToServer("widget_add Generic textWidget2 string");
480  sendToServer("widget_add Generic textWidget3 string");
481  sendToServer("widget_add Generic textWidget4 string");
482  sendToServer("widget_add Generic progressBar hbar");
483 
484  // The Volume Screen
485  sendToServer("screen_add Volume");
486  setPriority("Volume", LOW);
487  sendToServer("widget_add Volume topWidget string");
488  sendToServer("widget_add Volume botWidget string");
489  sendToServer("widget_add Volume progressBar hbar");
490 
491  // The Recording Status Screen
492  sendToServer("screen_add RecStatus");
493  setPriority("RecStatus", LOW);
494  sendToServer("widget_add RecStatus textWidget1 string");
495  sendToServer("widget_add RecStatus textWidget2 string");
496  sendToServer("widget_add RecStatus textWidget3 string");
497  sendToServer("widget_add RecStatus textWidget4 string");
498  sendToServer("widget_add RecStatus progressBar hbar");
499 
500  m_lcdReady = true;
501  loadSettings();
502 
503  // default to showing time
504  switchToTime();
505 
507 
508  // do we need to show the startup message
509  if (!m_startupMessage.isEmpty())
511 
512  // send buffer if there's anything in there
513  if ( m_sendBuffer.length() > 0)
514  {
516  m_sendBuffer = "";
517  }
518 }
519 
520 QString LCDProcClient::expandString(const QString &aString) const
521 {
522  if ( m_pVersion != LCD_VERSION_5)
523  return aString;
524 
525  QString bString;
526 
527  // if version 5 then white space seperate the list of characters
528  for (auto x : qAsConst(aString))
529  {
530  bString += x + QString(" ");
531  }
532 
533  return bString;
534 }
535 
537 {
538  if (!m_lcdReady )
539  return;
540 
541  QString aString;
542  QString old_keystring = m_lcdKeyString;
543 
544  m_timeFormat = gCoreContext->GetSetting("LCDTimeFormat", "");
545  if ( m_timeFormat.isEmpty())
546  m_timeFormat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
547 
548  m_dateFormat = gCoreContext->GetSetting("DateFormat", "dd.MM.yyyy");
549 
550  // Get LCD settings
551  m_lcdShowMusic=(gCoreContext->GetSetting("LCDShowMusic", "1")=="1");
552  m_lcdShowMusicItems=(gCoreContext->GetSetting("LCDShowMusicItems", "ArtistAlbumTitle"));
553  m_lcdShowTime=(gCoreContext->GetSetting("LCDShowTime", "1")=="1");
554  m_lcdShowChannel=(gCoreContext->GetSetting("LCDShowChannel", "1")=="1");
555  m_lcdShowGeneric=(gCoreContext->GetSetting("LCDShowGeneric", "1")=="1");
556  m_lcdShowVolume=(gCoreContext->GetSetting("LCDShowVolume", "1")=="1");
557  m_lcdShowMenu=(gCoreContext->GetSetting("LCDShowMenu", "1")=="1");
558  m_lcdShowRecstatus=(gCoreContext->GetSetting("LCDShowRecStatus", "1")=="1");
559  m_lcdBacklightOn=(gCoreContext->GetSetting("LCDBacklightOn", "1")=="1");
560  m_lcdHeartbeatOn=(gCoreContext->GetSetting("LCDHeartBeatOn", "1")=="1");
561  aString = gCoreContext->GetSetting("LCDPopupTime", "5");
562  m_lcdPopupTime = aString.toInt() * 1000;
563  m_lcdBigClock = (gCoreContext->GetSetting("LCDBigClock", "1")=="1");
564  m_lcdKeyString = gCoreContext->GetSetting("LCDKeyString", "ABCDEF");
565 
566  if (!old_keystring.isEmpty())
567  {
568  aString = "client_del_key " + expandString(old_keystring);
569  sendToServer(aString);
570  }
571 
572  aString = "client_add_key " + expandString( m_lcdKeyString );
573  sendToServer(aString);
574 
575  setHeartbeat ("Time", m_lcdHeartbeatOn );
576  if ( m_lcdBacklightOn )
577  sendToServer("screen_set Time backlight on");
578  else
579  sendToServer("screen_set Time backlight off");
580 
581  setHeartbeat ("Menu", m_lcdHeartbeatOn );
582  sendToServer("screen_set Menu backlight on");
583 
584  setHeartbeat ("Music", m_lcdHeartbeatOn );
585  sendToServer("screen_set Music backlight on");
586 
587  setHeartbeat ("Channel", m_lcdHeartbeatOn );
588  sendToServer("screen_set Channel backlight on");
589 
590  setHeartbeat ("Generic", m_lcdHeartbeatOn );
591  sendToServer("screen_set Generic backlight on");
592 
593  setHeartbeat ("Volume", m_lcdHeartbeatOn );
594  sendToServer("screen_set Volume backlight on");
595 
596  setHeartbeat ("RecStatus", m_lcdHeartbeatOn );
597  sendToServer("screen_set RecStatus backlight on");
598 }
599 
601 {
602  QList<LCDTextItem> textItems;
603 
604  QStringList list = formatScrollerText( m_startupMessage );
605 
606  int startrow = 1;
607  if (list.count() < (int) m_lcdHeight )
608  startrow = (( m_lcdHeight - list.count()) / 2) + 1;
609 
610  for (int x = 0; x < list.count(); x++)
611  {
612  if (x == (int) m_lcdHeight )
613  break;
614  textItems.append(LCDTextItem(x + startrow, ALIGN_LEFT, list[x],
615  "Generic", false));
616  }
617 
618  switchToGeneric(&textItems);
619 
620  m_showMessageTimer->start( m_startupShowTime * 1000);
621 }
622 
624 {
625  switchToTime();
626 }
627 
628 void LCDProcClient::setStartupMessage(QString msg, uint messagetime)
629 {
630  m_startupMessage = std::move(msg);
631  m_startupShowTime = messagetime;
632 }
633 
634 void LCDProcClient::setWidth(unsigned int x)
635 {
636  if (x < 1 || x > 80)
637  return;
638  m_lcdWidth = x;
639 }
640 
641 void LCDProcClient::setHeight(unsigned int x)
642 {
643  if (x < 1 || x > 80)
644  return;
645  m_lcdHeight = x;
646 }
647 
648 void LCDProcClient::setCellWidth(unsigned int x)
649 {
650  if (x < 1 || x > 16)
651  return;
652  m_cellWidth = x;
653 }
654 
655 void LCDProcClient::setCellHeight(unsigned int x)
656 {
657  if (x < 1 || x > 16)
658  return;
659  m_cellHeight = x;
660 }
661 
662 void LCDProcClient::setVersion(const QString &sversion, const QString &pversion)
663 {
664  m_protocolVersion = pversion;
665  m_serverVersion = sversion;
666 
667  // the pVersion number is used internally to designate which protocol
668  // version LCDd is using:
669 
670  if ( m_serverVersion.startsWith ("CVS-current") ||
671  m_serverVersion.startsWith ("0.5"))
672  {
673  // Latest CVS versions of LCDd has priorities switched
675  m_prioTop = "input";
676  m_prioUrgent = "alert";
677  m_prioHigh = "foreground";
678  m_prioMedium = "info";
679  m_prioLow = "background";
680  m_prioOff = "hidden";
681  }
682  else
683  {
685  m_prioTop = "64";
686  m_prioUrgent = "128";
687  m_prioHigh = "240";
688  m_prioMedium = "248";
689  m_prioLow = "252";
690  m_prioOff = "255";
691  }
692 }
693 
695 {
696  if (debug_level > 0)
697  {
698  LOG(VB_GENERAL, LOG_INFO,
699  QString("LCDProcClient: The server is %1x%2 with each cell "
700  "being %3x%4.")
701  .arg( m_lcdWidth ).arg( m_lcdHeight ).arg( m_cellWidth ).arg( m_cellHeight ));
702  LOG(VB_GENERAL, LOG_INFO,
703  QString("LCDProcClient: LCDd version %1, protocol version %2.")
704  .arg( m_serverVersion ).arg( m_protocolVersion ));
705  }
706 
707  if (debug_level > 1)
708  {
709  LOG(VB_GENERAL, LOG_INFO,
710  QString("LCDProcClient: MythTV LCD settings:"));
711  LOG(VB_GENERAL, LOG_INFO,
712  QString("LCDProcClient: - showmusic : %1")
713  .arg( m_lcdShowMusic ));
714  LOG(VB_GENERAL, LOG_INFO,
715  QString("LCDProcClient: - showmusicitems : %1")
716  .arg( m_lcdShowMusicItems ));
717  LOG(VB_GENERAL, LOG_INFO,
718  QString("LCDProcClient: - showtime : %1")
719  .arg( m_lcdShowTime ));
720  LOG(VB_GENERAL, LOG_INFO,
721  QString("LCDProcClient: - showchannel : %1")
722  .arg( m_lcdShowChannel ));
723  LOG(VB_GENERAL, LOG_INFO,
724  QString("LCDProcClient: - showrecstatus : %1")
725  .arg( m_lcdShowRecstatus ));
726  LOG(VB_GENERAL, LOG_INFO,
727  QString("LCDProcClient: - showgeneric : %1")
728  .arg( m_lcdShowGeneric ));
729  LOG(VB_GENERAL, LOG_INFO,
730  QString("LCDProcClient: - showvolume : %1")
731  .arg( m_lcdShowVolume ));
732  LOG(VB_GENERAL, LOG_INFO,
733  QString("LCDProcClient: - showmenu : %1")
734  .arg( m_lcdShowMenu ));
735  LOG(VB_GENERAL, LOG_INFO,
736  QString("LCDProcClient: - backlighton : %1")
737  .arg( m_lcdBacklightOn ));
738  LOG(VB_GENERAL, LOG_INFO,
739  QString("LCDProcClient: - heartbeaton : %1")
740  .arg( m_lcdHeartbeatOn ));
741  LOG(VB_GENERAL, LOG_INFO,
742  QString("LCDProcClient: - popuptime : %1")
743  .arg( m_lcdPopupTime ));
744  }
745 }
746 
747 void LCDProcClient::veryBadThings(QAbstractSocket::SocketError /*error*/)
748 {
749  // Deal with failures to connect and inabilities to communicate
750  LOG(VB_GENERAL, LOG_ERR, QString("Could not connect to LCDd: %1")
751  .arg(m_socket->errorString()));
752  m_socket->close();
753 }
754 
756 {
757  if ( m_scrollListItems.count() == 0)
758  return;
759 
761  return;
762 
765 
767  if ((int) m_scrollListItem >= m_scrollListItems.count())
768  m_scrollListItem = 0;
769 }
770 
772 {
773  // The usual reason things would get this far and then lcd_ready being
774  // false is the connection died and we're trying to re-establish the
775  // connection
776  if (debug_level > 1)
777  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: stopAll");
778 
779  if ( m_lcdReady )
780  {
781  setPriority("Time", OFF);
782  setPriority("Music", OFF);
783  setPriority("Channel", OFF);
784  setPriority("Generic", OFF);
785  setPriority("Volume", OFF);
786  setPriority("Menu", OFF);
787  setPriority("RecStatus", OFF);
788  }
789 
790  m_timeTimer->stop();
791  m_preScrollWTimer->stop();
792  m_scrollWTimer->stop();
793  m_popMenuTimer->stop();
794  m_menuScrollTimer->stop();
795  m_menuPreScrollTimer->stop();
796  m_recStatusTimer->stop();
797  m_scrollListTimer->stop();
798 
799  unPopMenu();
800 }
801 
803 {
804  setPriority("Time", MEDIUM);
805  setPriority("RecStatus", LOW);
806 
807  m_timeTimer->start(1000);
808  outputTime();
809  m_activeScreen = "Time";
810  m_isTimeVisible = true;
811 
814 }
815 
816 void LCDProcClient::outputText(QList<LCDTextItem> *textItems)
817 {
818  if (!m_lcdReady )
819  return;
820 
821  QList<LCDTextItem>::iterator it = textItems->begin();
822  QString num;
823  unsigned int counter = 1;
824 
825  // Do the definable scrolling in here.
826  // Use asignScrollingWidgets(curItem->getText(), "textWidget" + num);
827  // When scrolling is set, alignment has no effect
828  while (it != textItems->end() && counter < m_lcdHeight )
829  {
830  LCDTextItem *curItem = &(*it);
831  ++it;
832  num.setNum(curItem->getRow());
833 
834  if (curItem->getScroll())
835  {
836  assignScrollingWidgets(curItem->getText(), curItem->getScreen(),
837  "textWidget" + num, curItem->getRow());
838  }
839  else
840  {
841  switch (curItem->getAlignment())
842  {
843  case ALIGN_LEFT:
844  outputLeftText(curItem->getScreen(), curItem->getText(),
845  "textWidget" + num, curItem->getRow());
846  break;
847  case ALIGN_RIGHT:
848  outputRightText(curItem->getScreen(), curItem->getText(),
849  "textWidget" + num, curItem->getRow());
850  break;
851  case ALIGN_CENTERED:
852  outputCenteredText(curItem->getScreen(), curItem->getText(),
853  "textWidget" + num, curItem->getRow());
854  break;
855  default: break;
856  }
857  }
858 
859  ++counter;
860  }
861 }
862 
863 void LCDProcClient::outputCenteredText(const QString& theScreen, QString theText, const QString& widget,
864  int row)
865 {
866  QString aString;
867  unsigned int x = 0;
868 
869  x = ( m_lcdWidth - theText.length()) / 2 + 1;
870 
871  if (x > m_lcdWidth )
872  x = 1;
873 
874  aString = "widget_set ";
875  aString += theScreen;
876  aString += " " + widget + " ";
877  aString += QString::number(x);
878  aString += " ";
879  aString += QString::number(row);
880  aString += " \"";
881  aString += theText.replace ('"', "\"");
882  aString += "\"";
883  sendToServer(aString);
884 }
885 
886 void LCDProcClient::outputLeftText(const QString& theScreen, QString theText, const QString& widget,
887  int row)
888 {
889  QString aString;
890  aString = "widget_set ";
891  aString += theScreen;
892  aString += " " + widget + " 1 ";
893  aString += QString::number(row);
894  aString += " \"";
895  aString += theText.replace ('"', "\"");
896  aString += "\"";
897  sendToServer(aString);
898 }
899 
900 void LCDProcClient::outputRightText(const QString& theScreen, QString theText, const QString& widget,
901  int row)
902 {
903  QString aString;
904  unsigned int x = (int)( m_lcdWidth - theText.length()) + 1;
905 
906  aString = "widget_set ";
907  aString += theScreen;
908  aString += " " + widget + " ";
909  aString += QString::number(x);
910  aString += " ";
911  aString += QString::number(row);
912  aString += " \"";
913  aString += theText.replace ('"', "\"");
914  aString += "\"";
915  sendToServer(aString);
916 }
917 
918 void LCDProcClient::assignScrollingList(QStringList theList, QString theScreen,
919  QString theWidget, int theRow)
920 {
921  m_scrollListScreen = std::move(theScreen);
922  m_scrollListWidget = std::move(theWidget);
923  m_scrollListRow = theRow;
924  m_scrollListItems = std::move(theList);
925 
926  m_scrollListItem = 0;
927  scrollList();
929 }
930 
931 //
932 // Prepare for scrolling one or more text widgets on a single screen.
933 // Notes:
934 // - Before assigning the first text, call: lcdTextItems->clear();
935 // - After assigning the last text, call: formatScrollingWidgets()
936 // That's it ;-)
937 
938 void LCDProcClient::assignScrollingWidgets(const QString& theText, const QString& theScreen,
939  const QString& theWidget, int theRow)
940 {
941  m_scrollScreen = theScreen;
942 
943  // Alignment is not used...
944  m_lcdTextItems->append(LCDTextItem(theRow, ALIGN_LEFT, theText,
945  theScreen, true, theWidget));
946 }
947 
949 {
950  m_scrollWTimer->stop();
951  m_preScrollWTimer->stop();
952 
953  if ( m_lcdTextItems->isEmpty())
954  return; // Weird...
955 
956  int max_len = 0;
957 
958  // Get the length of the longest item to scroll
959  for (const auto & item : qAsConst(*m_lcdTextItems))
960  {
961  if (item.getText().length() > max_len)
962  max_len = item.getText().length();
963  }
964 
965  // Make all scrollable items the same lenght and do the initial output
966  auto it = m_lcdTextItems->begin();
967  while (it != m_lcdTextItems->end())
968  {
969  LCDTextItem *curItem = &(*it);
970  ++it;
971  if (curItem->getText().length() > (int) m_lcdWidth )
972  {
973  QString temp;
974  QString temp2;
975  temp = temp.fill(QChar(' '), max_len - curItem->getText().length());
976  temp2 = temp2.fill(QChar(' '), m_lcdWidth );
977  curItem->setText(temp2 + curItem->getText() + temp);
979  curItem->getText().mid( m_lcdWidth, max_len),
980  curItem->getWidget(), curItem->getRow());
981  }
982  else
983  {
984  curItem->setScrollable(false);
986  curItem->getWidget(), curItem->getRow());
987  }
988  }
989 
990  if (max_len <= (int) m_lcdWidth )
991  // We're done, no scrolling
992  return;
993 
994  m_preScrollWTimer->start(2000);
995 }
996 
998 {
1000  m_preScrollWTimer->stop();
1001  m_scrollWTimer->start(400);
1002 }
1003 
1005 {
1007  return;
1008 
1009  if ( m_lcdTextItems->isEmpty())
1010  return; // Weird...
1011 
1012  unsigned int len = 0;
1013  for (const auto & item : qAsConst(*m_lcdTextItems))
1014  {
1015  if (item.getScroll())
1016  {
1017  // Note that all scrollable items have the same length!
1018  len = item.getText().length();
1019 
1021  item.getText().mid( m_scrollPosition, m_lcdWidth ),
1022  item.getWidget(), item.getRow());
1023  }
1024  }
1025 
1026  if (len == 0)
1027  {
1028  // Shouldn't happen, but....
1029  LOG(VB_GENERAL, LOG_ERR,
1030  "LCDProcClient::scrollWidgets called without scrollable items");
1031  m_scrollWTimer->stop();
1032  return;
1033  }
1034  m_scrollPosition++;
1035  if ( m_scrollPosition >= len)
1037 }
1038 
1039 void LCDProcClient::startMusic(QString artist, const QString& album, const QString& track)
1040 {
1041  // Playing music displays:
1042  // For 1-line displays:
1043  // <ArtistAlbumTitle>
1044  // For 2-line displays:
1045  // <ArtistAlbumTitle>
1046  // <Elapse/Remaining Time>
1047  // For 3-line displays:
1048  // <ArtistAlbumTitle>
1049  // <Elapse/Remaining Time>
1050  // <Info+ProgressBar>
1051  // For displays with more than 3 lines:
1052  // <ArtistAlbum>
1053  // <Title>
1054  // <Elapse/Remaining Time>
1055  // <Info+ProgressBar>
1056 
1057  // Clear the progressBar and timeWidget before activating the Music
1058  // screen. This prevents the display of outdated junk.
1059  sendToServer("widget_set Music progressBar 1 1 0");
1060  sendToServer("widget_set Music timeWidget 1 1 \"\"");
1061  m_lcdTextItems->clear();
1062 
1063  m_musicProgress = 0.0F;
1064  QString aString = std::move(artist);
1065  if ( m_lcdShowMusicItems == "ArtistAlbumTitle")
1066  {
1067  aString += " [";
1068  aString += album;
1069  aString += "] ";
1070  }
1071  else if ( m_lcdHeight < 4)
1072  {
1073  aString += " - ";
1074  }
1075 
1076  if ( m_lcdHeight < 4)
1077  {
1078  aString += track;
1079  }
1080  else
1081  {
1082  assignScrollingWidgets(track, "Music", "topWidget2", 2);
1083  }
1084  assignScrollingWidgets(aString, "Music", "topWidget1", 1);
1086 
1087  // OK, everything is at least somewhat initialised. Activate
1088  // the music screen.
1089  m_activeScreen = "Music";
1090  if ( m_lcdShowMusic )
1091  setPriority("Music", HIGH);
1092 }
1093 
1094 void LCDProcClient::startChannel(const QString& channum, const QString& title, const QString& subtitle)
1095 {
1096  QString aString;
1097 
1098  if ( m_lcdShowChannel )
1099  setPriority("Channel", HIGH);
1100 
1101  m_activeScreen = "Channel";
1102 
1103  if ( m_lcdHeight <= 2)
1104  {
1105  aString = channum + "|" + title;
1106  if (!subtitle.isEmpty())
1107  aString += "|" + subtitle;
1108  QStringList list = formatScrollerText(aString);
1109  assignScrollingList(list, "Channel", "topWidget", 1);
1110  }
1111  else
1112  {
1113  aString = channum;
1114  m_lcdTextItems->clear();
1115  assignScrollingWidgets(aString, "Channel", "topWidget", 1);
1116  aString = title;
1117  if (subtitle.length() > 0)
1118  {
1119  aString += " - '";
1120  aString += subtitle;
1121  aString += "'";
1122  }
1123  assignScrollingWidgets(aString, "Channel", "botWidget", 2);
1125  }
1126 
1127  m_channelTime = "";
1128  m_progress = 0.0;
1129  outputChannel();
1130 }
1131 
1132 void LCDProcClient::startGeneric(QList<LCDTextItem> *textItems)
1133 {
1134  QList<LCDTextItem>::iterator it = textItems->begin();
1135  LCDTextItem *curItem = &(*it);
1136 
1137  QString aString;
1138 
1139  if ( m_lcdShowGeneric )
1140  setPriority("Generic", TOP);
1141 
1142  // Clear out the LCD. Do this before checking if its empty incase the user
1143  // wants to just clear the lcd
1144  outputLeftText("Generic", "", "textWidget1", 1);
1145  outputLeftText("Generic", "", "textWidget2", 2);
1146  outputLeftText("Generic", "", "textWidget3", 3);
1147 
1148  // If nothing, return without setting up the timer, etc
1149  if (textItems->isEmpty())
1150  return;
1151 
1152  m_activeScreen = "Generic";
1153 
1154  m_busyProgress = false;
1155  m_busyPos = 1;
1156  m_busyDirection = 1;
1157  m_busyIndicatorSize = 2.0F;
1158  m_genericProgress = 0.0;
1159 
1160  // Todo, make scrolling definable in LCDTextItem
1161  ++it;
1162 
1163 
1164  // Weird observations:
1165  // - The first item is always assumed 'scrolling', for this
1166  // item, the scrollable property is ignored...
1167  // - Why output line 1, progressbar, rest of lines? Why not
1168  // all outputlines, progressbar? That way, outputText() can
1169  // just handle the whole thing and the 'pop off' stuff can go.
1170  //
1171  m_lcdTextItems->clear();
1172  assignScrollingWidgets(curItem->getText(), "Generic",
1173  "textWidget1", curItem->getRow());
1174 
1175  outputGeneric();
1176 
1177  // Pop off the first item so item one isn't written twice
1178  textItems->removeFirst();
1179  if (!textItems->isEmpty())
1180  outputText(textItems);
1182 }
1183 
1184 void LCDProcClient::startMenu(QList<LCDMenuItem> *menuItems, QString app_name,
1185  bool popMenu)
1186 {
1187  // Now do the menu items
1188  if (menuItems->isEmpty())
1189  return;
1190 
1191  QString aString;
1192 
1193  // Stop the scrolling if the menu has changed
1194  m_menuScrollTimer->stop();
1195 
1196  // Menu is higher priority than volume
1197  if ( m_lcdShowMenu )
1198  setPriority("Menu", URGENT);
1199 
1200  // Write out the app name
1201  if ( m_lcdHeight > 1)
1202  outputCenteredText("Menu", std::move(app_name), "topWidget", 1);
1203 
1204  QList<LCDMenuItem>::iterator it = menuItems->begin();
1205 
1206  // First loop through and figure out where the selected item is in the
1207  // list so we know how many above and below to display
1208  unsigned int selectedItem = 0;
1209  unsigned int counter = 0;
1210  bool oneSelected = false;
1211 
1212  while (it != menuItems->end())
1213  {
1214  LCDMenuItem *curItem = &(*it);
1215  ++it;
1216  if (curItem->isSelected() && !oneSelected)
1217  {
1218  selectedItem = counter + 1;
1219  oneSelected = true;
1220  break;
1221  }
1222  ++counter;
1223  }
1224 
1225  // If there isn't one selected item, then write it on the display and return
1226  if (!oneSelected)
1227  {
1228  sendToServer("widget_set Menu topWidget 1 1 \"No menu item selected\"");
1229  sendToServer("widget_set Menu menuWidget1 1 2 \" ABORTING \"");
1230  m_menuScrollTimer->stop();
1231  return;
1232  }
1233 
1234  m_popMenuTimer->stop();
1235  // Start the unPop timer if this is a popup menu
1236  if (popMenu)
1237  m_popMenuTimer->start( m_lcdPopupTime );
1238 
1239  // QPtrListIterator doesn't contain a deep copy constructor. . .
1240  // This will contain a copy of the menuItems for scrolling purposes
1241  QList<LCDMenuItem>::iterator itTemp = menuItems->begin();
1242  m_lcdMenuItems->clear();
1243  counter = 1;
1244  while (itTemp != menuItems->end())
1245  {
1246  LCDMenuItem *curItem = &(*itTemp);
1247  ++itTemp;
1248  m_lcdMenuItems->append(LCDMenuItem(curItem->isSelected(),
1249  curItem->isChecked(), curItem->ItemName(),
1250  curItem->getIndent()));
1251  ++counter;
1252  }
1253 
1254  // If there is only one or two lines on the display, then just write the selected
1255  // item and leave
1256  if ( m_lcdHeight <= 2)
1257  {
1258  it = menuItems->begin();
1259  while (it != menuItems->end())
1260  {
1261  LCDMenuItem *curItem = &(*it);
1262  ++it;
1263  if (curItem->isSelected())
1264  {
1265  // Set the scroll flag if necessary, otherwise set it to false
1266  if (curItem->ItemName().length() > (int)( m_lcdWidth -lcdStartCol))
1267  {
1268  m_menuPreScrollTimer->setSingleShot(true);
1269  m_menuPreScrollTimer->start(2000);
1270  curItem->setScroll(true);
1271  }
1272  else
1273  {
1274  m_menuPreScrollTimer->stop();
1275  curItem->setScroll(false);
1276  }
1277  if ( m_lcdHeight == 2)
1278  {
1279  aString = "widget_set Menu menuWidget1 1 2 \">";
1280  }
1281  else
1282  {
1283  aString = "widget_set Menu menuWidget1 1 1 \"";
1284  }
1285 
1286  if (lcdStartCol != 0)
1287  {
1288  switch (curItem->isChecked())
1289  {
1290  case CHECKED: aString += "X "; break;
1291  case UNCHECKED: aString += "O "; break;
1292  case NOTCHECKABLE: aString += " "; break;
1293  default: break;
1294  }
1295  }
1296 
1297  aString += curItem->ItemName().left( m_lcdWidth - lcdStartCol) +
1298  "\"";
1299  sendToServer(aString);
1300  return;
1301  }
1302  }
1303 
1304  return;
1305  }
1306 
1307  // Reset things
1308  counter = 1;
1309  it = menuItems->begin();
1310 
1311  // Move the iterator to selectedItem lcdHeight/2, if > 1, -1.
1312  unsigned int midPoint = ( m_lcdHeight/2) - 1;
1313  if (selectedItem > midPoint && menuItems->size() >= (int) m_lcdHeight-1)
1314  {
1315  while (counter != selectedItem)
1316  {
1317  ++it;
1318  ++counter;
1319  }
1320  it -= midPoint;
1321  counter -= midPoint;
1322  }
1323 
1324  // Back up one if we're at the end so the last item shows up at the bottom
1325  // of the display
1326  if (counter + midPoint > menuItems->size() - midPoint && counter > midPoint)
1327  {
1328  it -= (counter + ( m_lcdHeight / 2) - 1) - (menuItems->size() - midPoint);
1329  }
1330 
1331  counter = 1;
1332  while (it != menuItems->end())
1333  {
1334  LCDMenuItem *curItem = &(*it);
1335  // Can't write more menu items then we have on the display
1336  if ((counter + 1) > m_lcdHeight )
1337  break;
1338 
1339  ++it;
1340 
1341  aString = "widget_set Menu menuWidget";
1342  aString += QString::number(counter) + " 1 ";
1343  aString += QString::number(counter + 1) + " \"";
1344 
1345  if (curItem->isSelected())
1346  aString += ">";
1347  else
1348  aString += " ";
1349 
1350  switch (curItem->isChecked())
1351  {
1352  case CHECKED: aString += "X "; break;
1353  case UNCHECKED: aString += "O "; break;
1354  case NOTCHECKABLE: aString += " "; break;
1355  default: break;
1356  }
1357 
1358  aString += curItem->ItemName().left( m_lcdWidth - lcdStartCol) + "\"";
1359  sendToServer(aString);
1360 
1361  ++counter;
1362  }
1363 
1364  // Make sure to clear out the rest of the screen
1365  while (counter < m_lcdHeight )
1366  {
1367  aString = "widget_set Menu menuWidget";
1368  aString += QString::number(counter) + " 1 ";
1369  aString += QString::number(counter + 1) + " \"\"";
1370  sendToServer(aString);
1371 
1372  ++counter;
1373  }
1374 
1375  m_menuPreScrollTimer->setSingleShot(true);
1376  m_menuPreScrollTimer->start(2000);
1377 }
1378 
1380 {
1381  // If there are items to scroll, wait 2 seconds for the user to read whats
1382  // already there
1383 
1384  if (!m_lcdMenuItems )
1385  return;
1386 
1388 
1389  QList<LCDMenuItem>::iterator it = m_lcdMenuItems->begin();
1390 
1391  QString temp;
1392  // Loop through and prepend everything with enough spaces
1393  // for smooth scrolling, and update the position
1394  while (it != m_lcdMenuItems->end())
1395  {
1396  LCDMenuItem *curItem = &(*it);
1397  ++it;
1398  // Don't setup for smooth scrolling if the item isn't long enough
1399  // (It causes problems with items being scrolled when they shouldn't)
1400  if (curItem->ItemName().length() > (int)( m_lcdWidth - lcdStartCol))
1401  {
1402  temp = temp.fill(QChar(' '), m_lcdWidth - curItem->getIndent() -
1403  lcdStartCol);
1404  curItem->setItemName(temp + curItem->ItemName());
1405  curItem->setScrollPos(curItem->getIndent() + temp.length());
1406  curItem->setScroll(true);
1407  }
1408  else
1409  curItem->setScroll(false);
1410  }
1411 
1412  // Can get segfaults if we try to start a timer thats already running. . .
1413  m_menuScrollTimer->stop();
1414  m_menuScrollTimer->start(250);
1415 }
1416 
1418 {
1419  if (!m_lcdMenuItems )
1420  return;
1421 
1422  QString aString;
1423  QString bString;
1424  QList<LCDMenuItem>::iterator it = m_lcdMenuItems->begin();
1425 
1427 
1428  // First loop through and figure out where the selected item is in the
1429  // list so we know how many above and below to display
1430  unsigned int selectedItem = 0;
1431  unsigned int counter = 0;
1432 
1433  while (it != m_lcdMenuItems->end())
1434  {
1435  LCDMenuItem *curItem = &(*it);
1436  ++it;
1437  if (curItem->isSelected())
1438  {
1439  selectedItem = counter + 1;
1440  break;
1441  }
1442  ++counter;
1443  }
1444 
1445  // If there is only one or two lines on the display, then just write
1446  // the selected item and leave
1447  it = m_lcdMenuItems->begin();
1448  if ( m_lcdHeight <= 2)
1449  {
1450  while (it != m_lcdMenuItems->end())
1451  {
1452  LCDMenuItem *curItem = &(*it);
1453  ++it;
1454  if (curItem->isSelected())
1455  {
1456  curItem->incrementScrollPos();
1457  if ((int)curItem->getScrollPos() > curItem->ItemName().length())
1458  {
1459  // Scroll slower second and subsequent times through
1460  m_menuScrollTimer->stop();
1461  m_menuScrollTimer->start(500);
1462  curItem->setScrollPos(curItem->getIndent());
1463  }
1464 
1465  // Stop the timer if this item really doesn't need to scroll.
1466  // This should never have to get invoked because in theory
1467  // the code in startMenu has done its job. . .
1468  if (curItem->ItemName().length() < (int)( m_lcdWidth - lcdStartCol))
1469  m_menuScrollTimer->stop();
1470 
1471  if ( m_lcdHeight == 2)
1472  {
1473  aString = "widget_set Menu menuWidget1 1 2 \">";
1474  }
1475  else
1476  {
1477  aString = "widget_set Menu menuWidget1 1 1 \"";
1478  }
1479 
1480  if ( m_lcdWidth < 12)
1481  {
1482  switch(curItem->isChecked())
1483  {
1484  case CHECKED: aString += "X"; break;
1485  case UNCHECKED: aString += "O"; break;
1486  case NOTCHECKABLE: aString += ""; break;
1487  default: break;
1488  }
1489  }
1490  else
1491  {
1492  switch(curItem->isChecked())
1493  {
1494  case CHECKED: aString += "X "; break;
1495  case UNCHECKED: aString += "O "; break;
1496  case NOTCHECKABLE: aString += " "; break;
1497  default: break;
1498  }
1499  }
1500 
1501  // Indent this item if nessicary
1502  aString += bString.fill(' ', curItem->getIndent());
1503 
1504  aString += curItem->ItemName().mid(curItem->getScrollPos(),
1505  ( m_lcdWidth - lcdStartCol));
1506  aString += "\"";
1507  sendToServer(aString);
1508  return;
1509  }
1510  }
1511 
1512  return;
1513  }
1514 
1515  // Find the longest line, if menuScrollPosition is longer then this, then
1516  // reset them all
1517  it = m_lcdMenuItems->begin();
1518  int longest_line = 0;
1519  int max_scroll_pos = 0;
1520 
1521  while (it != m_lcdMenuItems->end())
1522  {
1523  LCDMenuItem *curItem = &(*it);
1524  ++it;
1525  if (curItem->ItemName().length() > longest_line)
1526  longest_line = curItem->ItemName().length();
1527 
1528  if ((int)curItem->getScrollPos() > max_scroll_pos)
1529  max_scroll_pos = curItem->getScrollPos();
1530  }
1531 
1532  // If max_scroll_pos > longest_line then reset
1533  if (max_scroll_pos > longest_line)
1534  {
1535  // Scroll slower second and subsequent times through
1536  m_menuScrollTimer->stop();
1537  m_menuScrollTimer->start(500);
1539 
1540  it = m_lcdMenuItems->begin();
1541  while (it != m_lcdMenuItems->end())
1542  {
1543  LCDMenuItem *curItem = &(*it);
1544  ++it;
1545  curItem->setScrollPos(curItem->getIndent());
1546  }
1547  }
1548 
1549  // Reset things
1550  counter = 1;
1551  it = m_lcdMenuItems->begin();
1552 
1553  // Move the iterator to selectedItem -1
1554  if (selectedItem != 1 && m_lcdMenuItems->size() >= (int) m_lcdHeight )
1555  {
1556  while (counter != selectedItem)
1557  {
1558  ++it;
1559  ++counter;
1560  }
1561  --it;
1562  }
1563 
1564  // Back up one if were at the end so the last item shows up at the bottom
1565  // of the display
1566  if (counter > 1 && (int)counter == m_lcdMenuItems->size())
1567  --it;
1568 
1569  bool stopTimer = true;
1570 
1571  counter = 1;
1572  while (it != m_lcdMenuItems->end() && counter <= m_lcdHeight )
1573  {
1574  LCDMenuItem *curItem = &(*it);
1575  // Can't write more menu items then we have on the display
1576  if ((counter + 1) > m_lcdHeight )
1577  break;
1578 
1579  ++it;
1580 
1581  if (curItem->Scroll())
1582  {
1583  stopTimer = false;
1584  aString = "widget_set Menu menuWidget";
1585  aString += QString::number(counter) + " 1 ";
1586  aString += QString::number(counter + 1) + " \"";
1587 
1588  if (curItem->isSelected())
1589  aString += ">";
1590  else
1591  aString += " ";
1592 
1593  switch (curItem->isChecked())
1594  {
1595  case CHECKED: aString += "X "; break;
1596  case UNCHECKED: aString += "O "; break;
1597  case NOTCHECKABLE: aString += " "; break;
1598  default: break;
1599  }
1600 
1601  // Indent this item if nessicary
1602  bString = "";
1603  bString.fill(' ', curItem->getIndent());
1604  aString += bString;
1605 
1606  // Increment the scroll position counter for this item
1607  curItem->incrementScrollPos();
1608 
1609  if ((int)curItem->getScrollPos() <= longest_line)
1610  aString += curItem->ItemName().mid(curItem->getScrollPos(),
1611  ( m_lcdWidth-lcdStartCol));
1612 
1613  aString += "\"";
1614  sendToServer(aString);
1615  }
1616 
1617  ++counter;
1618  }
1619 
1620  // If there are no items to scroll, don't waste our time
1621  if (stopTimer)
1622  m_menuScrollTimer->stop();
1623 }
1624 
1625 void LCDProcClient::startVolume(const QString& app_name)
1626 {
1627  if ( m_lcdShowVolume )
1628  setPriority("Volume", TOP);
1629  if ( m_lcdHeight > 1)
1630  outputCenteredText("Volume", "MythTV " + app_name + " Volume");
1631  m_volumeLevel = 0.0;
1632 
1633  outputVolume();
1634 }
1635 
1637 {
1638  // Stop the scrolling timer
1639  m_menuScrollTimer->stop();
1640  setPriority("Menu", OFF);
1641 }
1642 
1643 void LCDProcClient::setChannelProgress(const QString &time, float value)
1644 {
1645  if (!m_lcdReady )
1646  return;
1647 
1648  m_progress = value;
1649  m_channelTime = time;
1650 
1651  if ( m_progress < 0.0F)
1652  m_progress = 0.0F;
1653  else if ( m_progress > 1.0F)
1654  m_progress = 1.0F;
1655 
1656  outputChannel();
1657 }
1658 
1659 void LCDProcClient::setGenericProgress(bool b, float value)
1660 {
1661  if (!m_lcdReady )
1662  return;
1663 
1664  m_genericProgress = value;
1665 
1666  if ( m_genericProgress < 0.0F)
1667  m_genericProgress = 0.0F;
1668  else if ( m_genericProgress > 1.0F)
1669  m_genericProgress = 1.0F;
1670 
1671  // Note, this will let us switch to/from busy indicator by
1672  // alternating between being passed true or false for b.
1673  m_busyProgress = b;
1674  if ( m_busyProgress )
1675  {
1676  // If we're at either end of the line, switch direction
1677  if (( m_busyPos + m_busyDirection >
1678  (signed int) m_lcdWidth - m_busyIndicatorSize ) ||
1679  ( m_busyPos + m_busyDirection < 1))
1680  {
1682  }
1685  }
1686  else
1687  {
1688  m_busyPos = 1;
1689  }
1690 
1691  outputGeneric();
1692 }
1693 
1694 void LCDProcClient::setMusicProgress(QString time, float value)
1695 {
1696  if (!m_lcdReady )
1697  return;
1698 
1699  m_musicProgress = value;
1700  m_musicTime = std::move(time);
1701 
1702  if ( m_musicProgress < 0.0F)
1703  m_musicProgress = 0.0F;
1704  else if ( m_musicProgress > 1.0F)
1705  m_musicProgress = 1.0F;
1706 
1707  outputMusic();
1708 }
1709 
1711 {
1712  if (!m_lcdReady )
1713  return;
1714 
1715  m_musicRepeat = repeat;
1716 
1717  outputMusic ();
1718 }
1719 
1721 {
1722  if (!m_lcdReady )
1723  return;
1724 
1725  m_musicShuffle = shuffle;
1726 
1727  outputMusic ();
1728 }
1729 
1731 {
1732  if (!m_lcdReady )
1733  return;
1734 
1735  m_volumeLevel = value;
1736 
1737  if ( m_volumeLevel < 0.0F)
1738  m_volumeLevel = 0.0F;
1739  if ( m_volumeLevel > 1.0F)
1740  m_volumeLevel = 1.0F;
1741 
1742  outputVolume();
1743 }
1744 
1746 {
1747  QString aString;
1748  aString = "output ";
1749  aString += QString::number(mask);
1750  sendToServer(aString);
1751 }
1752 
1754 {
1755  removeWidgets();
1756  loadSettings();
1757  init();
1758 }
1759 
1761 {
1762  QString aString;
1763  QString time = QTime::currentTime().toString( m_timeFormat );
1764  int toffset = 0;
1765  int xoffset = 0;
1766 
1767  // kludge ahead: use illegal number (11) to clear num display type
1768 
1769  // kluge - Uses string length to determine time format for parsing
1770  // 1:00 = 4 characters = 24-hour format, 1 digit hour
1771  // 12:00 = 5 characters = 24-hour format, 2 digit hour
1772  // 1:00 am = 7 characters = 12-hour format, 1 digit hour
1773  // 12:00 am = 8 characters = 12-hour format, 2 digit hour
1774  if ((time.length() == 8) || (time.length() == 5))
1775  toffset = 1;
1776 
1777  // if 12-hour clock, add AM/PM indicator to end of the 2nd line
1778  if (time.length() > 6)
1779  {
1780  aString = time.at(5 + toffset);
1781  aString += time.at(6 + toffset);
1782  xoffset = 1;
1783  }
1784  else
1785  {
1786  aString = " ";
1787  }
1788  outputRightText("Time", aString, "ampm", m_lcdHeight - 1);
1789 
1790  if ( m_isRecording )
1791  {
1792  outputLeftText("Time","R","rec1",1);
1793  outputLeftText("Time","E","rec2",2);
1794  outputLeftText("Time","C","rec3",3);
1795  aString = QString::number((int) m_tunerList.size());
1796  outputLeftText("Time",aString,"recCnt",4);
1797 
1798  }
1799  else
1800  {
1801  outputLeftText("Time"," ","rec1",1);
1802  outputLeftText("Time"," ","rec2",2);
1803  outputLeftText("Time"," ","rec3",3);
1804  outputLeftText("Time"," ","recCnt",4);
1805  }
1806 
1807  // Add Hour 10's Digit
1808  aString = "widget_set Time d0 ";
1809  aString += QString::number( m_lcdWidth/2 - 5 - xoffset) + " ";
1810  if (toffset == 0)
1811  aString += "11";
1812  else
1813  aString += time.at(0);
1814  sendToServer(aString);
1815 
1816  // Add Hour 1's Digit
1817  aString = "widget_set Time d1 ";
1818  aString += QString::number( m_lcdWidth/2 - 2 - xoffset) + " ";
1819  aString += time.at(0 + toffset);
1820  sendToServer(aString);
1821 
1822  // Add the Colon
1823  aString = "widget_set Time sep ";
1824  aString += QString::number( m_lcdWidth/2 + 1 - xoffset);
1825  aString += " 10"; // 10 means: colon
1826  sendToServer(aString);
1827 
1828  // Add Minute 10's Digit
1829  aString = "widget_set Time d2 ";
1830  aString += QString::number( m_lcdWidth/2 + 2 - xoffset) + " ";
1831  aString += time.at(2 + toffset);
1832  sendToServer(aString);
1833 
1834  // Add Minute 1's Digit
1835  aString = "widget_set Time d3 ";
1836  aString += QString::number( m_lcdWidth/2 + 5 - xoffset) + " ";
1837  aString += time.at(3 + toffset);
1838  sendToServer(aString);
1839 
1840  // Added a flashing dot in the bottom-right corner
1841  if ( m_timeFlash )
1842  {
1843  outputRightText("Time", ".", "dot", m_lcdHeight );
1844  m_timeFlash = false;
1845  }
1846  else
1847  {
1848  outputRightText("Time", " ", "dot", m_lcdHeight );
1849  m_timeFlash = true;
1850  }
1851 }
1852 
1854 {
1855  if ( m_lcdBigClock )
1856  dobigclock();
1857  else
1858  dostdclock();
1859 }
1860 
1862 {
1863  if (!m_lcdShowTime )
1864  return;
1865 
1867  {
1868  outputCenteredText("Time", tr("RECORDING"), "topWidget", 1);
1869  }
1870  else
1871  {
1873  "Time", MythDate::current().toLocalTime().toString( m_dateFormat ),
1874  "topWidget", 1);
1875  }
1876 
1877  QString aString;
1878  int x = 0;
1879  int y = 0;
1880 
1881  if ( m_lcdHeight < 3)
1882  y = m_lcdHeight;
1883  else
1884  y = (int) rint( m_lcdHeight / 2) + 1;
1885 
1886  QString time = QTime::currentTime().toString( m_timeFormat );
1887  x = ( m_lcdWidth - time.length()) / 2 + 1;
1888  aString = "widget_set Time timeWidget ";
1889  aString += QString::number(x);
1890  aString += " ";
1891  aString += QString::number(y);
1892  aString += " \"";
1893  if ( m_lcdShowTime ) {
1894  aString += time + "\"";
1895  if ( m_timeFlash )
1896  {
1897  aString = aString.replace(QRegExp(":"), " ");
1898  m_timeFlash = false;
1899  }
1900  else
1901  m_timeFlash = true;
1902  }
1903  else
1904  aString += " \"";
1905  sendToServer(aString);
1906 }
1907 
1908 // if one or more recordings are taking place we alternate between
1909 // showing the time and the recording status screen
1911 {
1913  return;
1914 
1915  if ( m_isTimeVisible || !m_lcdShowTime )
1916  {
1917  // switch to the rec status screen
1918  setPriority("RecStatus", MEDIUM);
1919  setPriority("Time", LOW);
1920 
1921  m_timeTimer->stop();
1922  m_scrollWTimer->stop();
1923  m_scrollListTimer->stop();
1924  m_isTimeVisible = false;
1925  m_activeScreen = "RecStatus";
1926 
1927  if (m_lcdTunerNo > (int) m_tunerList.size() - 1)
1928  m_lcdTunerNo = 0;
1929  }
1930  else if ( m_lcdTunerNo > (int) m_tunerList.size() - 1)
1931  {
1932  m_lcdTunerNo = 0;
1933 
1934  // switch to the time screen
1935  setPriority("Time", MEDIUM);
1936  setPriority("RecStatus", LOW);
1937 
1938  m_timeTimer->start(1000);
1939  m_scrollWTimer->stop();
1940  m_scrollListTimer->stop();
1942 
1943  outputTime();
1944  m_activeScreen = "Time";
1945  m_isTimeVisible = true;
1946 
1947  return;
1948  }
1949 
1950  QString aString;
1951  QString status;
1952  QStringList list;
1953  int listTime = 0;
1954 
1956 
1957  m_scrollListItems.clear();
1958  if ( m_lcdHeight >= 4)
1959  {
1960  // LINE 1 - "R" + Channel
1961  status = tr("R ");
1962  status += tuner.channame;
1963  outputLeftText("RecStatus", status, "textWidget1", 1);
1964 
1965  // LINE 2 - "E" + Program Title
1966  status = tr("E ");
1967  status += tuner.title;
1968  outputLeftText("RecStatus", status, "textWidget2", 2);
1969  //list = formatScrollerText(status);
1970  //assignScrollingList(list, "RecStatus", "textWidget2", 2);
1971 
1972  // LINE 3 - "C" + Program Subtitle
1973  status = tr("C ");
1974  status += tuner.subtitle;
1975  outputLeftText("RecStatus", status, "textWidget3", 3);
1976  //list = formatScrollerText(status);
1977  //assignScrollingList(list, "RecStatus", "textWidget3", 3);
1978 
1979  // LINE 4 - hh:mm-hh:mm + Progress Bar
1980  status = tuner.startTime.toLocalTime().toString("hh:mm") + "-" +
1981  tuner.endTime.toLocalTime().toString("hh:mm");
1982  outputLeftText("RecStatus", status, "textWidget4", 4);
1983 
1984  int length = tuner.startTime.secsTo(tuner.endTime);
1985  int delta = tuner.startTime.secsTo(MythDate::current());
1986  double rec_progress = (double) delta / length;
1987 
1988  aString = "widget_set RecStatus progressBar 13 ";
1989  aString += QString::number( m_lcdHeight );
1990  aString += " ";
1991  aString += QString::number((int)rint(rec_progress * ( m_lcdWidth - 13) *
1992  m_cellWidth ));
1993  sendToServer(aString);
1994 
1995  listTime = list.count() * LCD_SCROLLLIST_TIME * 2;
1996  }
1997  else
1998  {
1999  status = tr("RECORDING|");
2000  status += tuner.title;
2001  if (!tuner.subtitle.isEmpty())
2002  status += "|(" + tuner.subtitle + ")";
2003 
2004  status += "|" + tuner.startTime.toLocalTime().toString("hh:mm")
2005  + " to " +
2006  tuner.endTime.toLocalTime().toString("hh:mm");
2007 
2008  list = formatScrollerText(status);
2009  assignScrollingList(list, "RecStatus", "textWidget1", 1);
2010 
2011  if ( m_lcdHeight > 1)
2012  {
2013  int length = tuner.startTime.secsTo(tuner.endTime);
2014  int delta = tuner.startTime.secsTo(MythDate::current());
2015  double rec_progress = (double) delta / length;
2016 
2017  aString = "widget_set RecStatus progressBar 1 ";
2018  aString += QString::number( m_lcdHeight );
2019  aString += " ";
2020  aString += QString::number((int)rint(rec_progress * m_lcdWidth *
2021  m_cellWidth ));
2022  sendToServer(aString);
2023  }
2024  else
2025  sendToServer("widget_set RecStatus progressBar 1 1 0");
2026 
2027  listTime = list.count() * LCD_SCROLLLIST_TIME * 2;
2028  }
2029 
2030  if (listTime < LCD_TIME_TIME)
2031  listTime = LCD_TIME_TIME;
2032 
2033  m_recStatusTimer->start(listTime);
2034  m_lcdTunerNo++;
2035 }
2036 
2037 void LCDProcClient::outputScrollerText(const QString& theScreen, const QString& theText,
2038  const QString& widget, int top, int bottom)
2039 {
2040  QString aString;
2041  aString = "widget_set " + theScreen + " " + widget;
2042  aString += " 1 ";
2043  aString += QString::number(top) + " ";
2044  aString += QString::number( m_lcdWidth ) + " ";
2045  aString += QString::number(bottom);
2046  aString += " v 8 \"" + theText + "\"";
2047 
2048  sendToServer(aString);
2049 }
2050 
2051 QStringList LCDProcClient::formatScrollerText(const QString &text) const
2052 {
2053  QString separators = " |-_/:('<~";
2054  QStringList lines;
2055 
2056  int lastSplit = 0;
2057  QString line = "";
2058 
2059  for (auto x : qAsConst(text))
2060  {
2061  if (separators.contains(x))
2062  lastSplit = line.length();
2063 
2064  line += x;
2065  if (line.length() > (int) m_lcdWidth || x == '|')
2066  {
2067  QString formatedLine;
2068  formatedLine.fill(' ', m_lcdWidth );
2069  formatedLine = formatedLine.replace(( m_lcdWidth - lastSplit) / 2,
2070  lastSplit, line.left(lastSplit));
2071 
2072  lines.append(formatedLine);
2073 
2074  if (line[lastSplit] == ' ' || line[lastSplit] == '|')
2075  line = line.mid(lastSplit + 1);
2076  else
2077  line = line.mid(lastSplit);
2078 
2079  lastSplit = m_lcdWidth;
2080  }
2081  }
2082 
2083  // make sure we add the last line
2084  QString formatedLine;
2085  formatedLine.fill(' ', m_lcdWidth );
2086  formatedLine = formatedLine.replace(( m_lcdWidth - line.length()) / 2,
2087  line.length(), line);
2088 
2089  lines.append(formatedLine);
2090 
2091  return lines;
2092 }
2093 
2095 {
2096  // See startMusic() for a discription of the Music screen contents
2097 
2098  outputCenteredText("Music", m_musicTime, "timeWidget",
2099  m_lcdHeight < 4 ? 2 : 3);
2100 
2101  if ( m_lcdHeight > 2)
2102  {
2103  QString aString;
2104  QString shuffle = "";
2105  QString repeat = "";
2106  int info_width = 0;
2107 
2108  if ( m_musicShuffle == 1)
2109  {
2110  shuffle = "S:? ";
2111  }
2112  else if ( m_musicShuffle == 2)
2113  {
2114  shuffle = "S:i ";
2115  }
2116  else if ( m_musicShuffle == 3)
2117  {
2118  shuffle = "S:a ";
2119  }
2120 
2121  if ( m_musicRepeat == 1)
2122  {
2123  repeat = "R:1 ";
2124  }
2125  else if ( m_musicRepeat == 2)
2126  {
2127  repeat = "R:* ";
2128  }
2129 
2130  if (shuffle.length() != 0 || repeat.length() != 0)
2131  {
2132  aString = shuffle + repeat;
2133  info_width = aString.length();
2134  outputLeftText("Music", aString, "infoWidget", m_lcdHeight );
2135  }
2136  else
2137  outputLeftText("Music", " ", "infoWidget", m_lcdHeight );
2138 
2139  aString = "widget_set Music progressBar ";
2140  aString += QString::number(info_width + 1);
2141  aString += " ";
2142  aString += QString::number( m_lcdHeight );
2143  aString += " ";
2144  aString += QString::number((int)rint( m_musicProgress *
2145  ( m_lcdWidth - info_width) * m_cellWidth ));
2146  sendToServer(aString);
2147  }
2148 }
2149 
2151 {
2152  if ( m_lcdHeight > 1)
2153  {
2154  QString aString;
2155  aString = "widget_set Channel progressBar 1 ";
2156  aString += QString::number( m_lcdHeight );
2157  aString += " ";
2158  aString += QString::number((int)rint( m_progress * m_lcdWidth * m_cellWidth ));
2159  sendToServer(aString);
2160 
2161  if ( m_lcdHeight >= 4)
2162  outputCenteredText("Channel", m_channelTime, "timeWidget", 3);
2163  }
2164  else
2165  sendToServer("widget_set Channel progressBar 1 1 0");
2166 }
2167 
2169 {
2170  if ( m_lcdHeight > 1)
2171  {
2172  QString aString;
2173  aString = "widget_set Generic progressBar ";
2174  aString += QString::number ( m_busyPos );
2175  aString += " ";
2176  aString += QString::number( m_lcdHeight );
2177  aString += " ";
2178  aString += QString::number((int)rint( m_genericProgress * m_lcdWidth *
2179  m_cellWidth ));
2180  sendToServer(aString);
2181 }
2182  else sendToServer("widget_set Generic progressBar 1 1 0");
2183 }
2184 
2186 {
2187  QString aString;
2188  int line = 3;
2189 
2190  if ( m_lcdHeight > 1)
2191  {
2192  aString = "widget_set Volume progressBar 1 ";
2193  aString += QString::number( m_lcdHeight );
2194  aString += " ";
2195  aString += QString::number((int)rint( m_volumeLevel * m_lcdWidth * m_cellWidth ));
2196  sendToServer(aString);
2197  }
2198 
2199  aString = QString::number((int)( m_volumeLevel * 100));
2200  aString += "%";
2201 
2202  if ( m_lcdHeight > 3)
2203  line = 3;
2204  else
2205  line = m_lcdHeight;
2206  outputRightText("Volume", aString, "botWidget", line);
2207 }
2208 
2210 {
2211  if (!m_lcdReady )
2212  return;
2213 
2214  stopAll();
2215 
2216  if (debug_level > 1)
2217  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToTime");
2218 
2219  startTime();
2220 }
2221 
2222 void LCDProcClient::switchToMusic(const QString &artist, const QString &album, const QString &track)
2223 {
2224  if (!m_lcdReady )
2225  return;
2226 
2227  stopAll();
2228 
2229  if (debug_level > 1)
2230  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToMusic") ;
2231 
2232  startMusic(artist, album, track);
2233 }
2234 
2235 void LCDProcClient::switchToChannel(const QString& channum, const QString& title, const QString& subtitle)
2236 {
2237  if (!m_lcdReady )
2238  return;
2239 
2240  stopAll();
2241 
2242  if (debug_level > 1)
2243  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToChannel");
2244 
2245  startChannel(channum, title, subtitle);
2246 }
2247 
2248 void LCDProcClient::switchToMenu(QList<LCDMenuItem> *menuItems, const QString& app_name,
2249  bool popMenu)
2250 {
2251  if (!m_lcdReady )
2252  return;
2253 
2254  if (debug_level > 1)
2255  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToMenu");
2256 
2257  startMenu(menuItems, app_name, popMenu);
2258 }
2259 
2260 void LCDProcClient::switchToGeneric(QList<LCDTextItem> *textItems)
2261 {
2262  if (!m_lcdReady )
2263  return;
2264  stopAll();
2265 
2266  if (debug_level > 1)
2267  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToGeneric");
2268 
2269  startGeneric(textItems);
2270 }
2271 
2272 void LCDProcClient::switchToVolume(const QString& app_name)
2273 {
2274  if (!m_lcdReady )
2275  return;
2276 
2277  stopAll();
2278 
2279  if (debug_level > 1)
2280  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToVolume");
2281 
2282  startVolume(app_name);
2283 }
2284 
2286 {
2287  if (!m_lcdReady )
2288  return;
2289 
2290  stopAll();
2291 
2292  if (debug_level > 1)
2293  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToNothing");
2294 }
2295 
2297 {
2298  if (debug_level > 1)
2299  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: shutdown");
2300 
2301  stopAll();
2302 
2303  // Remove all the widgets and screens for a clean exit from the server
2304  removeWidgets();
2305 
2306  m_socket->close();
2307 
2308  m_lcdReady = false;
2309  m_connected = false;
2310 }
2311 
2313 {
2314  sendToServer("widget_del Channel progressBar");
2315  sendToServer("widget_del Channel topWidget");
2316  sendToServer("widget_del Channel timeWidget");
2317  sendToServer("screen_del Channel");
2318 
2319  sendToServer("widget_del Generic progressBar");
2320  sendToServer("widget_del Generic textWidget1");
2321  sendToServer("widget_del Generic textWidget2");
2322  sendToServer("widget_del Generic textWidget3");
2323  sendToServer("screen_del Generic");
2324 
2325  sendToServer("widget_del Volume progressBar");
2326  sendToServer("widget_del Volume topWidget");
2327  sendToServer("screen_del Volume");
2328 
2329  sendToServer("widget_del Menu topWidget");
2330  sendToServer("widget_del Menu menuWidget1");
2331  sendToServer("widget_del Menu menuWidget2");
2332  sendToServer("widget_del Menu menuWidget3");
2333  sendToServer("widget_del Menu menuWidget4");
2334  sendToServer("widget_del Menu menuWidget5");
2335  sendToServer("screen_del Menu");
2336 
2337  sendToServer("widget_del Music progressBar");
2338  sendToServer("widget_del Music infoWidget");
2339  sendToServer("widget_del Music timeWidget");
2340  sendToServer("widget_del Music topWidget");
2341  sendToServer("screen_del Music");
2342 
2343  if ( m_lcdBigClock )
2344  {
2345  sendToServer("widget_del Time rec1");
2346  sendToServer("widget_del Time rec2");
2347  sendToServer("widget_del Time rec3");
2348  sendToServer("widget_del Time recCnt");
2349  sendToServer("widget_del Time d0");
2350  sendToServer("widget_del Time d1");
2351  sendToServer("widget_del Time sep");
2352  sendToServer("widget_del Time d2");
2353  sendToServer("widget_del Time d3");
2354  sendToServer("widget_del Time ampm");
2355  sendToServer("widget_del Time dot");
2356  }
2357  else
2358  {
2359  sendToServer("widget_del Time timeWidget");
2360  sendToServer("widget_del Time topWidget");
2361  }
2362 
2363  sendToServer("screen_del Time");
2364 
2365  sendToServer("widget_del RecStatus textWidget1");
2366  sendToServer("widget_del RecStatus textWidget2");
2367  sendToServer("widget_del RecStatus textWidget3");
2368  sendToServer("widget_del RecStatus textWidget4");
2369  sendToServer("widget_del RecStatus progressBar");
2370 }
2371 
2373 {
2374  if (debug_level > 1)
2375  {
2376  LOG(VB_GENERAL, LOG_INFO,
2377  "LCDProcClient: An LCD device is being snuffed out"
2378  "of existence (~LCDProcClient() was called)");
2379  }
2380 
2381  if (m_socket)
2382  {
2383  delete m_socket;
2384  m_lcdReady = false;
2385  }
2386 
2387  delete m_lcdMenuItems;
2388 
2390 }
2391 
2393 {
2394  if (e->type() == MythEvent::MythEventMessage)
2395  {
2396  auto *me = dynamic_cast<MythEvent *>(e);
2397  if (me == nullptr)
2398  return;
2399 
2400  if (me->Message().startsWith("RECORDING_LIST_CHANGE") ||
2401  me->Message() == "UPDATE_PROG_INFO")
2402  {
2403  if ( m_lcdShowRecstatus && !m_updateRecInfoTimer->isActive())
2404  {
2405  if (debug_level > 1)
2406  LOG(VB_GENERAL, LOG_INFO,
2407  "LCDProcClient: Received recording list change");
2408 
2409  // we can't query the backend from inside the customEvent
2410  // so fire the recording list update from a timer
2411  m_updateRecInfoTimer->start(500);
2412  }
2413  }
2414  }
2415 }
2416 
2418 {
2419  m_tunerList.clear();
2420  m_isRecording = false;
2421 
2423  {
2424  if (!gCoreContext->ConnectToMasterServer(false))
2425  {
2426  LOG(VB_GENERAL, LOG_ERR,
2427  "LCDProcClient: Cannot get recording status "
2428  "- is the master server running?\n\t\t\t"
2429  "Will retry in 30 seconds");
2430  QTimer::singleShot(30 * 1000, this, SLOT(updateRecordingList()));
2431 
2432  // If we can't get the recording status and we're showing
2433  // it, switch back to time. Maybe it would be even better
2434  // to show that the backend is unreachable ?
2435  if (m_activeScreen == "RecStatus")
2436  switchToTime();
2437  return;
2438  }
2439  }
2440 
2442 
2443  m_lcdTunerNo = 0;
2444 
2445  if (m_activeScreen == "Time" || m_activeScreen == "RecStatus")
2446  startTime();
2447 }
2448 /* vim: set expandtab tabstop=4 shiftwidth=4: */
QString m_sendBuffer
QString m_lastCommand
bool isSelected() const
Definition: lcddevice.h:34
void setScrollable(bool value)
Definition: lcddevice.h:83
float m_genericProgress
QString m_lcdKeyString
int m_busyDirection
Direction of the busy indicator on the, -1 or 1, used if m_busyProgress is true.
unsigned int m_scrollPosition
QTimer * m_recStatusTimer
QDateTime endTime
Definition: tvremoteutil.h:26
QString m_channelTime
static void error(const char *str,...)
Definition: vbi.cpp:42
void outputLeftText(const QString &theScreen, QString theText, const QString &widget="topWidget", int row=1)
void dobigclock(void)
unsigned int m_port
void setItemName(const QString &value)
Definition: lcddevice.h:42
QString toString(MarkTypes type)
void sendToServer(const QString &someText)
QTcpSocket * m_socket
QString m_timeFormat
static Type MythEventMessage
Definition: mythevent.h:73
void removeListener(QObject *listener)
Remove a listener to the observable.
QList< LCDMenuItem > * m_lcdMenuItems
QTimer * m_menuPreScrollTimer
QString m_scrollListScreen
QString title
Definition: tvremoteutil.h:23
void setScroll(bool value)
Definition: lcddevice.h:43
QList< LCDTextItem > * m_lcdTextItems
void setMusicRepeat(int repeat)
void setChannelProgress(const QString &time, float value)
QString m_prioLow
void setText(const QString &value)
Definition: lcddevice.h:80
bool ConnectToMasterServer(bool blockingClient=true, bool openEventSocket=true)
void startVolume(const QString &app_name)
void switchToChannel(const QString &channum="", const QString &title="", const QString &subtitle="")
bool m_lcdShowRecstatus
QTimer * m_preScrollWTimer
QString m_protocolVersion
QTimer * m_scrollListTimer
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
recording status stuff
Definition: tvremoteutil.h:17
void switchToVolume(const QString &app_name)
unsigned int m_cellWidth
void addListener(QObject *listener)
Add a listener to the observable.
vector< TunerStatus > m_tunerList
QString m_dateFormat
QTimer * m_checkConnectionsTimer
#define LCD_VERSION_5
int debug_level
Definition: lcdserver.cpp:73
unsigned int m_cellHeight
#define LCD_SCROLLLIST_TIME
void outputCenteredText(const QString &theScreen, QString theText, const QString &widget="topWidget", int row=1)
QString m_scrollListWidget
unsigned int m_lcdWidth
QString m_hostname
void removeStartupMessage(void)
QString m_activeScreen
void startGeneric(QList< LCDTextItem > *textItems)
#define LCD_TIME_TIME
void setCellHeight(unsigned int x)
QTimer * m_scrollWTimer
void outputRightText(const QString &theScreen, QString theText, const QString &widget="topWidget", int row=1)
QString m_prioHigh
void outputText(QList< LCDTextItem > *textItems)
void switchToMenu(QList< LCDMenuItem > *menuItems, const QString &app_name="", bool popMenu=true)
QString getScreen() const
Definition: lcddevice.h:74
QString m_scrollScreen
bool IsConnectedToMaster(void)
QString m_prioMedium
QString m_prioOff
void setStartupMessage(QString msg, uint messagetime)
void beginScrollingMenuText()
void setScrollPos(unsigned int value)
Definition: lcddevice.h:45
void startChannel(const QString &channum, const QString &title, const QString &subtitle)
QTimer * m_showMessageTimer
QString m_prioTop
void switchToGeneric(QList< LCDTextItem > *textItems)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
QString ItemName() const
Definition: lcddevice.h:35
QString channame
Definition: tvremoteutil.h:22
unsigned int m_scrollListItem
void setGenericProgress(bool busy, float value)
void assignScrollingWidgets(const QString &theText, const QString &theScreen, const QString &theWidget="topWidget", int theRow=1)
void outputScrollerText(const QString &theScreen, const QString &theText, const QString &widget="scroller", int top=1, int bottom=1)
void checkConnections()
QTimer * m_popMenuTimer
QString m_prioUrgent
int lcdStartCol
unsigned int uint
Definition: compat.h:140
void customEvent(QEvent *e) override
#define LCD_VERSION_4
QString expandString(const QString &aString) const
void stopAll(void)
void updateRecordingList(void)
void startMenu(QList< LCDMenuItem > *menuItems, QString app_name, bool popMenu)
void showStartupMessage(void)
LCDServer * m_parentLCDServer
void updateLEDs(int mask)
void setMusicProgress(QString time, float value)
float m_musicProgress
void scrollWidgets(void)
CHECKED_STATE isChecked() const
Definition: lcddevice.h:33
void setWidth(unsigned int x)
void serverSendingData()
int GetNumSetting(const QString &key, int defaultval=0)
QTimer * m_timeTimer
void reset(void)
unsigned int getRow() const
Definition: lcddevice.h:71
QString m_musicTime
void setVersion(const QString &sversion, const QString &pversion)
void switchToMusic(const QString &artist, const QString &album, const QString &track)
void setHeartbeat(const QString &screen, bool onoff)
int m_busyPos
Current position of the busy indicator, used if m_busyProgress is true.
QString m_startupMessage
bool GetBoolSetting(const QString &key, bool defaultval=false)
void setVolumeLevel(float value)
TEXT_ALIGNMENT getAlignment() const
Definition: lcddevice.h:72
void setMusicShuffle(int shuffle)
void beginScrollingWidgets(void)
unsigned int m_lcdHeight
QStringList formatScrollerText(const QString &text) const
bool Scroll() const
Definition: lcddevice.h:36
QString getWidget() const
Definition: lcddevice.h:75
QString subtitle
Definition: tvremoteutil.h:24
bool getScroll() const
Definition: lcddevice.h:76
bool SetupLCD(void)
QString m_serverVersion
QString m_lcdShowMusicItems
void incrementScrollPos()
Definition: lcddevice.h:46
void startMusic(QString artist, const QString &album, const QString &track)
unsigned int getScrollPos() const
Definition: lcddevice.h:38
void veryBadThings(QAbstractSocket::SocketError error)
QString getText() const
Definition: lcddevice.h:73
#define LCD_START_COL
void formatScrollingWidgets(void)
QTimer * m_updateRecInfoTimer
void setPriority(const QString &screen, PRIORITY priority)
int RemoteGetRecordingStatus(const ProgramInfo *pginfo, int overrecsecs, int underrecsecs)
Get status of an individual programme (with pre-post roll?).
Definition: remoteutil.cpp:506
bool m_busyProgress
true if the generic progress indicator is a busy (ie.
void assignScrollingList(QStringList theList, QString theScreen, QString theWidget="topWidget", int theRow=1)
void setHeight(unsigned int x)
bool connectToHost(const QString &hostname, unsigned int port)
float m_busyIndicatorSize
How many "blocks" the busy indicator must be, used if m_busyProgress is true.
uint m_startupShowTime
LCDProcClient(LCDServer *lparent)
unsigned int m_menuScrollPosition
void sendKeyPress(const QString &key_pressed)
Definition: lcdserver.cpp:294
QDateTime startTime
Definition: tvremoteutil.h:25
~LCDProcClient() override
void setCellWidth(unsigned int x)
unsigned int getIndent() const
Definition: lcddevice.h:37
QStringList m_scrollListItems
QTimer * m_menuScrollTimer
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23