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