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, tempString;
311  QStringList aList;
312  QStringList::Iterator it;
313 
314  // This gets activated automatically by the QSocket class whenever
315  // there's something to read.
316  //
317  // We currently spend most of our time (except for the first line sent
318  // back) ignoring it.
319  //
320  // Note that if anyone has an LCDproc type lcd with buttons on it, this is
321  // where we would want to catch button presses and make the rest of
322  // mythTV/mythMusic do something (change tracks, channels, etc.)
323 
324  while(m_socket->canReadLine())
325  {
326  lineFromServer = m_socket->readLine();
327  lineFromServer = lineFromServer.replace( QRegExp("\n"), "" );
328  lineFromServer = lineFromServer.replace( QRegExp("\r"), "" );
329 
330  if (debug_level > 0)
331  // Make debugging be less noisy
332  if (lineFromServer != "success")
333  LOG(VB_NETWORK, LOG_INFO,
334  "LCDProcClient: Received from server: " + lineFromServer);
335 
336  aList = lineFromServer.split(" ");
337  if (aList.first() == "connect")
338  {
339  // We got a connect, which is a response to "hello"
340  //
341  // Need to parse out some data according the LCDproc client/server
342  // spec (which is poorly documented)
343  it = aList.begin();
344  it++;
345  if ((*it) != "LCDproc")
346  {
347  LOG(VB_GENERAL, LOG_WARNING,
348  "LCDProcClient: WARNING: Second parameter "
349  "returned from LCDd was not \"LCDproc\"");
350  }
351 
352  // Skip through some stuff
353  it++; // server version
354  QString server_version = *it;
355  it++; // the string "protocol"
356  it++; // protocol version
357  QString protocol_version = *it;
358  setVersion (server_version, protocol_version);
359  it++; // the string "lcd"
360  it++; // the string "wid";
361  it++; // Ah, the LCD width
362 
363  tempString = *it;
364  setWidth(tempString.toInt());
365 
366  it++; // the string "hgt"
367  it++; // the LCD height
368 
369  tempString = *it;
370  setHeight(tempString.toInt());
371  it++; // the string "cellwid"
372  it++; // Cell width in pixels;
373 
374  tempString = *it;
375  setCellWidth(tempString.toInt());
376 
377  it++; // the string "cellhgt"
378  it++; // Cell height in pixels;
379 
380  tempString = *it;
381  setCellHeight(tempString.toInt());
382 
383  init();
384 
385  describeServer();
386  }
387 
388  if (aList.first() == "huh?")
389  {
390  LOG(VB_GENERAL, LOG_WARNING,
391  "LCDProcClient: WARNING: Something is getting"
392  "passed to LCDd that it doesn't understand");
393  LOG(VB_GENERAL, LOG_WARNING, "last command: " + m_lastCommand );
394  }
395  else if (aList.first() == "key")
396  {
397  if ( m_parentLCDServer )
398  m_parentLCDServer->sendKeyPress(aList.last().trimmed());
399  }
400  }
401 }
402 
404 {
405  QString aString;
406  m_lcdKeyString = "";
407 
408  m_connected = true;
409 
410  // This gets called when we receive the "connect" string from the server
411  // indicating that "hello" was succesful
412  sendToServer("client_set name Myth");
413 
414  // Create all the screens and widgets (when we change activity in the myth
415  // program, we just swap the priorities of the screens to show only the
416  // "current one")
417  sendToServer("screen_add Time");
418  setPriority("Time", MEDIUM);
419 
420  if (gCoreContext->GetSetting("LCDBigClock", "1") == "1")
421  {
422  // Big Clock - spans multiple lines
423  sendToServer("widget_add Time rec1 string");
424  sendToServer("widget_add Time rec2 string");
425  sendToServer("widget_add Time rec3 string");
426  sendToServer("widget_add Time recCnt string");
427  sendToServer("widget_add Time d0 num");
428  sendToServer("widget_add Time d1 num");
429  sendToServer("widget_add Time sep num");
430  sendToServer("widget_add Time d2 num");
431  sendToServer("widget_add Time d3 num");
432  sendToServer("widget_add Time ampm string");
433  sendToServer("widget_add Time dot string");
434  }
435  else
436  {
437  sendToServer("widget_add Time timeWidget string");
438  sendToServer("widget_add Time topWidget string");
439  }
440 
441  // The Menu Screen
442  // I'm not sure how to do multi-line widgets with lcdproc so we're going
443  // the ghetto way
444  sendToServer("screen_add Menu");
445  setPriority("Menu", LOW);
446  sendToServer("widget_add Menu topWidget string");
447  for (unsigned int i = 1; i <= m_lcdHeight; i++)
448  {
449  aString = "widget_add Menu menuWidget";
450  aString += QString::number (i);
451  aString += " string";
452  sendToServer(aString);
453  }
454 
455  // The Music Screen
456  sendToServer("screen_add Music");
457  setPriority("Music", LOW);
458  sendToServer("widget_add Music topWidget1 string");
459  sendToServer("widget_add Music topWidget2 string");
460  sendToServer("widget_add Music timeWidget string");
461  sendToServer("widget_add Music infoWidget string");
462  sendToServer("widget_add Music progressBar hbar");
463 
464  // The Channel Screen
465  sendToServer("screen_add Channel");
466  setPriority("Channel", LOW);
467  sendToServer("widget_add Channel topWidget string");
468  sendToServer("widget_add Channel botWidget string");
469  sendToServer("widget_add Channel timeWidget string");
470  sendToServer("widget_add Channel progressBar hbar");
471 
472  // The Generic Screen
473  sendToServer("screen_add Generic");
474  setPriority("Generic", LOW);
475  sendToServer("widget_add Generic textWidget1 string");
476  sendToServer("widget_add Generic textWidget2 string");
477  sendToServer("widget_add Generic textWidget3 string");
478  sendToServer("widget_add Generic textWidget4 string");
479  sendToServer("widget_add Generic progressBar hbar");
480 
481  // The Volume Screen
482  sendToServer("screen_add Volume");
483  setPriority("Volume", LOW);
484  sendToServer("widget_add Volume topWidget string");
485  sendToServer("widget_add Volume botWidget string");
486  sendToServer("widget_add Volume progressBar hbar");
487 
488  // The Recording Status Screen
489  sendToServer("screen_add RecStatus");
490  setPriority("RecStatus", LOW);
491  sendToServer("widget_add RecStatus textWidget1 string");
492  sendToServer("widget_add RecStatus textWidget2 string");
493  sendToServer("widget_add RecStatus textWidget3 string");
494  sendToServer("widget_add RecStatus textWidget4 string");
495  sendToServer("widget_add RecStatus progressBar hbar");
496 
497  m_lcdReady = true;
498  loadSettings();
499 
500  // default to showing time
501  switchToTime();
502 
504 
505  // do we need to show the startup message
506  if (!m_startupMessage.isEmpty())
508 
509  // send buffer if there's anything in there
510  if ( m_sendBuffer.length() > 0)
511  {
513  m_sendBuffer = "";
514  }
515 }
516 
517 QString LCDProcClient::expandString(const QString &aString)
518 {
519  if ( m_pVersion != LCD_VERSION_5)
520  return aString;
521 
522  QString bString;
523 
524  // if version 5 then white space seperate the list of characters
525  for (int x = 0; x < aString.length(); x++)
526  {
527  bString += aString.at(x) + QString(" ");
528  }
529 
530  return bString;
531 }
532 
534 {
535  if (!m_lcdReady )
536  return;
537 
538  QString aString;
539  QString old_keystring = m_lcdKeyString;
540 
541  m_timeFormat = gCoreContext->GetSetting("LCDTimeFormat", "");
542  if ( m_timeFormat.isEmpty())
543  m_timeFormat = gCoreContext->GetSetting("TimeFormat", "h:mm AP");
544 
545  m_dateFormat = gCoreContext->GetSetting("DateFormat", "dd.MM.yyyy");
546 
547  // Get LCD settings
548  m_lcdShowMusic=(gCoreContext->GetSetting("LCDShowMusic", "1")=="1");
549  m_lcdShowMusicItems=(gCoreContext->GetSetting("LCDShowMusicItems", "ArtistAlbumTitle"));
550  m_lcdShowTime=(gCoreContext->GetSetting("LCDShowTime", "1")=="1");
551  m_lcdShowChannel=(gCoreContext->GetSetting("LCDShowChannel", "1")=="1");
552  m_lcdShowGeneric=(gCoreContext->GetSetting("LCDShowGeneric", "1")=="1");
553  m_lcdShowVolume=(gCoreContext->GetSetting("LCDShowVolume", "1")=="1");
554  m_lcdShowMenu=(gCoreContext->GetSetting("LCDShowMenu", "1")=="1");
555  m_lcdShowRecstatus=(gCoreContext->GetSetting("LCDShowRecStatus", "1")=="1");
556  m_lcdBacklightOn=(gCoreContext->GetSetting("LCDBacklightOn", "1")=="1");
557  m_lcdHeartbeatOn=(gCoreContext->GetSetting("LCDHeartBeatOn", "1")=="1");
558  aString = gCoreContext->GetSetting("LCDPopupTime", "5");
559  m_lcdPopupTime = aString.toInt() * 1000;
560  m_lcdBigClock = (gCoreContext->GetSetting("LCDBigClock", "1")=="1");
561  m_lcdKeyString = gCoreContext->GetSetting("LCDKeyString", "ABCDEF");
562 
563  if (!old_keystring.isEmpty())
564  {
565  aString = "client_del_key " + expandString(old_keystring);
566  sendToServer(aString);
567  }
568 
569  aString = "client_add_key " + expandString( m_lcdKeyString );
570  sendToServer(aString);
571 
572  setHeartbeat ("Time", m_lcdHeartbeatOn );
573  if ( m_lcdBacklightOn )
574  sendToServer("screen_set Time backlight on");
575  else
576  sendToServer("screen_set Time backlight off");
577 
578  setHeartbeat ("Menu", m_lcdHeartbeatOn );
579  sendToServer("screen_set Menu backlight on");
580 
581  setHeartbeat ("Music", m_lcdHeartbeatOn );
582  sendToServer("screen_set Music backlight on");
583 
584  setHeartbeat ("Channel", m_lcdHeartbeatOn );
585  sendToServer("screen_set Channel backlight on");
586 
587  setHeartbeat ("Generic", m_lcdHeartbeatOn );
588  sendToServer("screen_set Generic backlight on");
589 
590  setHeartbeat ("Volume", m_lcdHeartbeatOn );
591  sendToServer("screen_set Volume backlight on");
592 
593  setHeartbeat ("RecStatus", m_lcdHeartbeatOn );
594  sendToServer("screen_set RecStatus backlight on");
595 }
596 
598 {
599  QList<LCDTextItem> textItems;
600 
601  QStringList list = formatScrollerText( m_startupMessage );
602 
603  int startrow = 1;
604  if (list.count() < (int) m_lcdHeight )
605  startrow = (( m_lcdHeight - list.count()) / 2) + 1;
606 
607  for (int x = 0; x < list.count(); x++)
608  {
609  if (x == (int) m_lcdHeight )
610  break;
611  textItems.append(LCDTextItem(x + startrow, ALIGN_LEFT, list[x],
612  "Generic", false));
613  }
614 
615  switchToGeneric(&textItems);
616 
617  m_showMessageTimer->start( m_startupShowTime * 1000);
618 }
619 
621 {
622  switchToTime();
623 }
624 
625 void LCDProcClient::setStartupMessage(QString msg, uint messagetime)
626 {
627  m_startupMessage = std::move(msg);
628  m_startupShowTime = messagetime;
629 }
630 
631 void LCDProcClient::setWidth(unsigned int x)
632 {
633  if (x < 1 || x > 80)
634  return;
635  m_lcdWidth = x;
636 }
637 
638 void LCDProcClient::setHeight(unsigned int x)
639 {
640  if (x < 1 || x > 80)
641  return;
642  m_lcdHeight = x;
643 }
644 
645 void LCDProcClient::setCellWidth(unsigned int x)
646 {
647  if (x < 1 || x > 16)
648  return;
649  m_cellWidth = x;
650 }
651 
652 void LCDProcClient::setCellHeight(unsigned int x)
653 {
654  if (x < 1 || x > 16)
655  return;
656  m_cellHeight = x;
657 }
658 
659 void LCDProcClient::setVersion(const QString &sversion, const QString &pversion)
660 {
661  m_protocolVersion = pversion;
662  m_serverVersion = sversion;
663 
664  // the pVersion number is used internally to designate which protocol
665  // version LCDd is using:
666 
667  if ( m_serverVersion.startsWith ("CVS-current") ||
668  m_serverVersion.startsWith ("0.5"))
669  {
670  // Latest CVS versions of LCDd has priorities switched
672  m_prioTop = "input";
673  m_prioUrgent = "alert";
674  m_prioHigh = "foreground";
675  m_prioMedium = "info";
676  m_prioLow = "background";
677  m_prioOff = "hidden";
678  }
679  else
680  {
682  m_prioTop = "64";
683  m_prioUrgent = "128";
684  m_prioHigh = "240";
685  m_prioMedium = "248";
686  m_prioLow = "252";
687  m_prioOff = "255";
688  }
689 }
690 
692 {
693  if (debug_level > 0)
694  {
695  LOG(VB_GENERAL, LOG_INFO,
696  QString("LCDProcClient: The server is %1x%2 with each cell "
697  "being %3x%4.")
698  .arg( m_lcdWidth ).arg( m_lcdHeight ).arg( m_cellWidth ).arg( m_cellHeight ));
699  LOG(VB_GENERAL, LOG_INFO,
700  QString("LCDProcClient: LCDd version %1, protocol version %2.")
701  .arg( m_serverVersion ).arg( m_protocolVersion ));
702  }
703 
704  if (debug_level > 1)
705  {
706  LOG(VB_GENERAL, LOG_INFO,
707  QString("LCDProcClient: MythTV LCD settings:"));
708  LOG(VB_GENERAL, LOG_INFO,
709  QString("LCDProcClient: - showmusic : %1")
710  .arg( m_lcdShowMusic ));
711  LOG(VB_GENERAL, LOG_INFO,
712  QString("LCDProcClient: - showmusicitems : %1")
713  .arg( m_lcdShowMusicItems ));
714  LOG(VB_GENERAL, LOG_INFO,
715  QString("LCDProcClient: - showtime : %1")
716  .arg( m_lcdShowTime ));
717  LOG(VB_GENERAL, LOG_INFO,
718  QString("LCDProcClient: - showchannel : %1")
719  .arg( m_lcdShowChannel ));
720  LOG(VB_GENERAL, LOG_INFO,
721  QString("LCDProcClient: - showrecstatus : %1")
722  .arg( m_lcdShowRecstatus ));
723  LOG(VB_GENERAL, LOG_INFO,
724  QString("LCDProcClient: - showgeneric : %1")
725  .arg( m_lcdShowGeneric ));
726  LOG(VB_GENERAL, LOG_INFO,
727  QString("LCDProcClient: - showvolume : %1")
728  .arg( m_lcdShowVolume ));
729  LOG(VB_GENERAL, LOG_INFO,
730  QString("LCDProcClient: - showmenu : %1")
731  .arg( m_lcdShowMenu ));
732  LOG(VB_GENERAL, LOG_INFO,
733  QString("LCDProcClient: - backlighton : %1")
734  .arg( m_lcdBacklightOn ));
735  LOG(VB_GENERAL, LOG_INFO,
736  QString("LCDProcClient: - heartbeaton : %1")
737  .arg( m_lcdHeartbeatOn ));
738  LOG(VB_GENERAL, LOG_INFO,
739  QString("LCDProcClient: - popuptime : %1")
740  .arg( m_lcdPopupTime ));
741  }
742 }
743 
744 void LCDProcClient::veryBadThings(QAbstractSocket::SocketError /*error*/)
745 {
746  // Deal with failures to connect and inabilities to communicate
747  LOG(VB_GENERAL, LOG_ERR, QString("Could not connect to LCDd: %1")
748  .arg(m_socket->errorString()));
749  m_socket->close();
750 }
751 
753 {
754  if ( m_scrollListItems.count() == 0)
755  return;
756 
758  return;
759 
762 
764  if ((int) m_scrollListItem >= m_scrollListItems.count())
765  m_scrollListItem = 0;
766 }
767 
769 {
770  // The usual reason things would get this far and then lcd_ready being
771  // false is the connection died and we're trying to re-establish the
772  // connection
773  if (debug_level > 1)
774  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: stopAll");
775 
776  if ( m_lcdReady )
777  {
778  setPriority("Time", OFF);
779  setPriority("Music", OFF);
780  setPriority("Channel", OFF);
781  setPriority("Generic", OFF);
782  setPriority("Volume", OFF);
783  setPriority("Menu", OFF);
784  setPriority("RecStatus", OFF);
785  }
786 
787  m_timeTimer->stop();
788  m_preScrollWTimer->stop();
789  m_scrollWTimer->stop();
790  m_popMenuTimer->stop();
791  m_menuScrollTimer->stop();
792  m_menuPreScrollTimer->stop();
793  m_recStatusTimer->stop();
794  m_scrollListTimer->stop();
795 
796  unPopMenu();
797 }
798 
800 {
801  setPriority("Time", MEDIUM);
802  setPriority("RecStatus", LOW);
803 
804  m_timeTimer->start(1000);
805  outputTime();
806  m_activeScreen = "Time";
807  m_isTimeVisible = true;
808 
811 }
812 
813 void LCDProcClient::outputText(QList<LCDTextItem> *textItems)
814 {
815  if (!m_lcdReady )
816  return;
817 
818  QList<LCDTextItem>::iterator it = textItems->begin();
819  QString num;
820  unsigned int counter = 1;
821 
822  // Do the definable scrolling in here.
823  // Use asignScrollingWidgets(curItem->getText(), "textWidget" + num);
824  // When scrolling is set, alignment has no effect
825  while (it != textItems->end() && counter < m_lcdHeight )
826  {
827  LCDTextItem *curItem = &(*it);
828  ++it;
829  num.setNum(curItem->getRow());
830 
831  if (curItem->getScroll())
832  assignScrollingWidgets(curItem->getText(), curItem->getScreen(),
833  "textWidget" + num, curItem->getRow());
834  else
835  {
836  switch (curItem->getAlignment())
837  {
838  case ALIGN_LEFT:
839  outputLeftText(curItem->getScreen(), curItem->getText(),
840  "textWidget" + num, curItem->getRow());
841  break;
842  case ALIGN_RIGHT:
843  outputRightText(curItem->getScreen(), curItem->getText(),
844  "textWidget" + num, curItem->getRow());
845  break;
846  case ALIGN_CENTERED:
847  outputCenteredText(curItem->getScreen(), curItem->getText(),
848  "textWidget" + num, curItem->getRow());
849  break;
850  default: break;
851  }
852  }
853 
854  ++counter;
855  }
856 }
857 
858 void LCDProcClient::outputCenteredText(const QString& theScreen, QString theText, const QString& widget,
859  int row)
860 {
861  QString aString;
862  unsigned int x = 0;
863 
864  x = ( m_lcdWidth - theText.length()) / 2 + 1;
865 
866  if (x > m_lcdWidth )
867  x = 1;
868 
869  aString = "widget_set ";
870  aString += theScreen;
871  aString += " " + widget + " ";
872  aString += QString::number(x);
873  aString += " ";
874  aString += QString::number(row);
875  aString += " \"";
876  aString += theText.replace ('"', "\"");
877  aString += "\"";
878  sendToServer(aString);
879 }
880 
881 void LCDProcClient::outputLeftText(const QString& theScreen, QString theText, const QString& widget,
882  int row)
883 {
884  QString aString;
885  aString = "widget_set ";
886  aString += theScreen;
887  aString += " " + widget + " 1 ";
888  aString += QString::number(row);
889  aString += " \"";
890  aString += theText.replace ('"', "\"");
891  aString += "\"";
892  sendToServer(aString);
893 }
894 
895 void LCDProcClient::outputRightText(const QString& theScreen, QString theText, const QString& widget,
896  int row)
897 {
898  QString aString;
899  unsigned int x = (int)( m_lcdWidth - theText.length()) + 1;
900 
901  aString = "widget_set ";
902  aString += theScreen;
903  aString += " " + widget + " ";
904  aString += QString::number(x);
905  aString += " ";
906  aString += QString::number(row);
907  aString += " \"";
908  aString += theText.replace ('"', "\"");
909  aString += "\"";
910  sendToServer(aString);
911 }
912 
913 void LCDProcClient::assignScrollingList(QStringList theList, QString theScreen,
914  QString theWidget, int theRow)
915 {
916  m_scrollListScreen = std::move(theScreen);
917  m_scrollListWidget = std::move(theWidget);
918  m_scrollListRow = theRow;
919  m_scrollListItems = std::move(theList);
920 
921  m_scrollListItem = 0;
922  scrollList();
924 }
925 
926 //
927 // Prepare for scrolling one or more text widgets on a single screen.
928 // Notes:
929 // - Before assigning the first text, call: lcdTextItems->clear();
930 // - After assigning the last text, call: formatScrollingWidgets()
931 // That's it ;-)
932 
933 void LCDProcClient::assignScrollingWidgets(const QString& theText, const QString& theScreen,
934  const QString& theWidget, int theRow)
935 {
936  m_scrollScreen = theScreen;
937 
938  // Alignment is not used...
939  m_lcdTextItems->append(LCDTextItem(theRow, ALIGN_LEFT, theText,
940  theScreen, true, theWidget));
941 }
942 
944 {
945  m_scrollWTimer->stop();
946  m_preScrollWTimer->stop();
947 
948  if ( m_lcdTextItems->isEmpty())
949  return; // Weird...
950 
951  int max_len = 0;
952  QList<LCDTextItem>::iterator it = m_lcdTextItems->begin();
953 
954  // Get the length of the longest item to scroll
955  for(; it != m_lcdTextItems->end(); ++it)
956  {
957  LCDTextItem *curItem = &(*it);
958  if (curItem->getText().length() > max_len)
959  max_len = curItem->getText().length();
960  }
961 
962  // Make all scrollable items the same lenght and do the initial output
963  it = m_lcdTextItems->begin();
964  while (it != m_lcdTextItems->end())
965  {
966  LCDTextItem *curItem = &(*it);
967  ++it;
968  if (curItem->getText().length() > (int) m_lcdWidth )
969  {
970  QString temp, temp2;
971  temp = temp.fill(QChar(' '), max_len - curItem->getText().length());
972  temp2 = temp2.fill(QChar(' '), m_lcdWidth );
973  curItem->setText(temp2 + curItem->getText() + temp);
975  curItem->getText().mid( m_lcdWidth, max_len),
976  curItem->getWidget(), curItem->getRow());
977  }
978  else
979  {
980  curItem->setScrollable(false);
982  curItem->getWidget(), curItem->getRow());
983  }
984  }
985 
986  if (max_len <= (int) m_lcdWidth )
987  // We're done, no scrolling
988  return;
989 
990  m_preScrollWTimer->start(2000);
991 }
992 
994 {
996  m_preScrollWTimer->stop();
997  m_scrollWTimer->start(400);
998 }
999 
1001 {
1003  return;
1004 
1005  if ( m_lcdTextItems->isEmpty())
1006  return; // Weird...
1007 
1008  QList<LCDTextItem>::iterator it = m_lcdTextItems->begin();
1009 
1010  unsigned int len = 0;
1011  for(; it != m_lcdTextItems->end(); ++it)
1012  {
1013  LCDTextItem *curItem = &(*it);
1014  if (curItem->getScroll())
1015  {
1016  // Note that all scrollable items have the same lenght!
1017  len = curItem->getText().length();
1018 
1020  curItem->getText().mid( m_scrollPosition, m_lcdWidth ),
1021  curItem->getWidget(), curItem->getRow());
1022  }
1023  }
1024 
1025  if (len == 0)
1026  {
1027  // Shouldn't happen, but....
1028  LOG(VB_GENERAL, LOG_ERR,
1029  "LCDProcClient::scrollWidgets called without scrollable items");
1030  m_scrollWTimer->stop();
1031  return;
1032  }
1033  m_scrollPosition++;
1034  if ( m_scrollPosition >= len)
1036 }
1037 
1038 void LCDProcClient::startMusic(QString artist, const QString& album, const QString& track)
1039 {
1040  // Playing music displays:
1041  // For 1-line displays:
1042  // <ArtistAlbumTitle>
1043  // For 2-line displays:
1044  // <ArtistAlbumTitle>
1045  // <Elapse/Remaining Time>
1046  // For 3-line displays:
1047  // <ArtistAlbumTitle>
1048  // <Elapse/Remaining Time>
1049  // <Info+ProgressBar>
1050  // For displays with more than 3 lines:
1051  // <ArtistAlbum>
1052  // <Title>
1053  // <Elapse/Remaining Time>
1054  // <Info+ProgressBar>
1055 
1056  // Clear the progressBar and timeWidget before activating the Music
1057  // screen. This prevents the display of outdated junk.
1058  sendToServer("widget_set Music progressBar 1 1 0");
1059  sendToServer("widget_set Music timeWidget 1 1 \"\"");
1060  m_lcdTextItems->clear();
1061 
1062  QString aString;
1063  m_musicProgress = 0.0F;
1064  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 == 1) // small display -> don't waste space for additional spaces
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  else if (lcdStartCol != 0)
1297  {
1298  switch (curItem->isChecked())
1299  {
1300  case CHECKED: aString += "X "; break;
1301  case UNCHECKED: aString += "O "; break;
1302  case NOTCHECKABLE: aString += " "; break;
1303  default: break;
1304  }
1305  }
1306 
1307  aString += curItem->ItemName().left( m_lcdWidth - lcdStartCol) +
1308  "\"";
1309  sendToServer(aString);
1310  return;
1311  }
1312  }
1313 
1314  return;
1315  }
1316 
1317  // Reset things
1318  counter = 1;
1319  it = menuItems->begin();
1320 
1321  // Move the iterator to selectedItem lcdHeight/2, if > 1, -1.
1322  unsigned int midPoint = ( m_lcdHeight/2) - 1;
1323  if (selectedItem > midPoint && menuItems->size() >= (int) m_lcdHeight-1)
1324  {
1325  while (counter != selectedItem)
1326  {
1327  ++it;
1328  ++counter;
1329  }
1330  it -= midPoint;
1331  counter -= midPoint;
1332  }
1333 
1334  // Back up one if we're at the end so the last item shows up at the bottom
1335  // of the display
1336  if (counter + midPoint > menuItems->size() - midPoint && counter > midPoint)
1337  {
1338  it -= (counter + ( m_lcdHeight / 2) - 1) - (menuItems->size() - midPoint);
1339  }
1340 
1341  counter = 1;
1342  while (it != menuItems->end())
1343  {
1344  LCDMenuItem *curItem = &(*it);
1345  // Can't write more menu items then we have on the display
1346  if ((counter + 1) > m_lcdHeight )
1347  break;
1348 
1349  ++it;
1350 
1351  aString = "widget_set Menu menuWidget";
1352  aString += QString::number(counter) + " 1 ";
1353  aString += QString::number(counter + 1) + " \"";
1354 
1355  if (curItem->isSelected())
1356  aString += ">";
1357  else
1358  aString += " ";
1359 
1360  switch (curItem->isChecked())
1361  {
1362  case CHECKED: aString += "X "; break;
1363  case UNCHECKED: aString += "O "; break;
1364  case NOTCHECKABLE: aString += " "; break;
1365  default: break;
1366  }
1367 
1368  aString += curItem->ItemName().left( m_lcdWidth - lcdStartCol) + "\"";
1369  sendToServer(aString);
1370 
1371  ++counter;
1372  }
1373 
1374  // Make sure to clear out the rest of the screen
1375  while (counter < m_lcdHeight )
1376  {
1377  aString = "widget_set Menu menuWidget";
1378  aString += QString::number(counter) + " 1 ";
1379  aString += QString::number(counter + 1) + " \"\"";
1380  sendToServer(aString);
1381 
1382  ++counter;
1383  }
1384 
1385  m_menuPreScrollTimer->setSingleShot(true);
1386  m_menuPreScrollTimer->start(2000);
1387 }
1388 
1390 {
1391  // If there are items to scroll, wait 2 seconds for the user to read whats
1392  // already there
1393 
1394  if (!m_lcdMenuItems )
1395  return;
1396 
1398 
1399  QList<LCDMenuItem>::iterator it = m_lcdMenuItems->begin();
1400 
1401  QString temp;
1402  // Loop through and prepend everything with enough spaces
1403  // for smooth scrolling, and update the position
1404  while (it != m_lcdMenuItems->end())
1405  {
1406  LCDMenuItem *curItem = &(*it);
1407  ++it;
1408  // Don't setup for smooth scrolling if the item isn't long enough
1409  // (It causes problems with items being scrolled when they shouldn't)
1410  if (curItem->ItemName().length() > (int)( m_lcdWidth - lcdStartCol))
1411  {
1412  temp = temp.fill(QChar(' '), m_lcdWidth - curItem->getIndent() -
1413  lcdStartCol);
1414  curItem->setItemName(temp + curItem->ItemName());
1415  curItem->setScrollPos(curItem->getIndent() + temp.length());
1416  curItem->setScroll(true);
1417  }
1418  else
1419  curItem->setScroll(false);
1420  }
1421 
1422  // Can get segfaults if we try to start a timer thats already running. . .
1423  m_menuScrollTimer->stop();
1424  m_menuScrollTimer->start(250);
1425 }
1426 
1428 {
1429  if (!m_lcdMenuItems )
1430  return;
1431 
1432  QString aString, bString;
1433  QList<LCDMenuItem>::iterator it = m_lcdMenuItems->begin();
1434 
1436 
1437  // First loop through and figure out where the selected item is in the
1438  // list so we know how many above and below to display
1439  unsigned int selectedItem = 0;
1440  unsigned int counter = 0;
1441 
1442  while (it != m_lcdMenuItems->end())
1443  {
1444  LCDMenuItem *curItem = &(*it);
1445  ++it;
1446  if (curItem->isSelected())
1447  {
1448  selectedItem = counter + 1;
1449  break;
1450  }
1451  ++counter;
1452  }
1453 
1454  // If there is only one or two lines on the display, then just write
1455  // the selected item and leave
1456  it = m_lcdMenuItems->begin();
1457  if ( m_lcdHeight <= 2)
1458  {
1459  while (it != m_lcdMenuItems->end())
1460  {
1461  LCDMenuItem *curItem = &(*it);
1462  ++it;
1463  if (curItem->isSelected())
1464  {
1465  curItem->incrementScrollPos();
1466  if ((int)curItem->getScrollPos() > curItem->ItemName().length())
1467  {
1468  // Scroll slower second and subsequent times through
1469  m_menuScrollTimer->stop();
1470  m_menuScrollTimer->start(500);
1471  curItem->setScrollPos(curItem->getIndent());
1472  }
1473 
1474  // Stop the timer if this item really doesn't need to scroll.
1475  // This should never have to get invoked because in theory
1476  // the code in startMenu has done its job. . .
1477  if (curItem->ItemName().length() < (int)( m_lcdWidth - lcdStartCol))
1478  m_menuScrollTimer->stop();
1479 
1480  if ( m_lcdHeight == 2)
1481  {
1482  aString = "widget_set Menu menuWidget1 1 2 \">";
1483  }
1484  else
1485  {
1486  aString = "widget_set Menu menuWidget1 1 1 \"";
1487  }
1488 
1489  if ( m_lcdWidth < 12)
1490  {
1491  switch(curItem->isChecked())
1492  {
1493  case CHECKED: aString += "X"; break;
1494  case UNCHECKED: aString += "O"; break;
1495  case NOTCHECKABLE: aString += ""; break;
1496  default: break;
1497  }
1498  }
1499  else
1500  {
1501  switch(curItem->isChecked())
1502  {
1503  case CHECKED: aString += "X "; break;
1504  case UNCHECKED: aString += "O "; break;
1505  case NOTCHECKABLE: aString += " "; break;
1506  default: break;
1507  }
1508  }
1509 
1510  // Indent this item if nessicary
1511  aString += bString.fill(' ', curItem->getIndent());
1512 
1513  aString += curItem->ItemName().mid(curItem->getScrollPos(),
1514  ( m_lcdWidth - lcdStartCol));
1515  aString += "\"";
1516  sendToServer(aString);
1517  return;
1518  }
1519  }
1520 
1521  return;
1522  }
1523 
1524  // Find the longest line, if menuScrollPosition is longer then this, then
1525  // reset them all
1526  it = m_lcdMenuItems->begin();
1527  int longest_line = 0;
1528  int max_scroll_pos = 0;
1529 
1530  while (it != m_lcdMenuItems->end())
1531  {
1532  LCDMenuItem *curItem = &(*it);
1533  ++it;
1534  if (curItem->ItemName().length() > longest_line)
1535  longest_line = curItem->ItemName().length();
1536 
1537  if ((int)curItem->getScrollPos() > max_scroll_pos)
1538  max_scroll_pos = curItem->getScrollPos();
1539  }
1540 
1541  // If max_scroll_pos > longest_line then reset
1542  if (max_scroll_pos > longest_line)
1543  {
1544  // Scroll slower second and subsequent times through
1545  m_menuScrollTimer->stop();
1546  m_menuScrollTimer->start(500);
1548 
1549  it = m_lcdMenuItems->begin();
1550  while (it != m_lcdMenuItems->end())
1551  {
1552  LCDMenuItem *curItem = &(*it);
1553  ++it;
1554  curItem->setScrollPos(curItem->getIndent());
1555  }
1556  }
1557 
1558  // Reset things
1559  counter = 1;
1560  it = m_lcdMenuItems->begin();
1561 
1562  // Move the iterator to selectedItem -1
1563  if (selectedItem != 1 && m_lcdMenuItems->size() >= (int) m_lcdHeight )
1564  {
1565  while (counter != selectedItem)
1566  {
1567  ++it;
1568  ++counter;
1569  }
1570  --it;
1571  }
1572 
1573  // Back up one if were at the end so the last item shows up at the bottom
1574  // of the display
1575  if (counter > 1 && (int)counter == m_lcdMenuItems->size())
1576  --it;
1577 
1578  bool stopTimer = true;
1579 
1580  counter = 1;
1581  while (it != m_lcdMenuItems->end() && counter <= m_lcdHeight )
1582  {
1583  LCDMenuItem *curItem = &(*it);
1584  // Can't write more menu items then we have on the display
1585  if ((counter + 1) > m_lcdHeight )
1586  break;
1587 
1588  ++it;
1589 
1590  if (curItem->Scroll())
1591  {
1592  stopTimer = false;
1593  aString = "widget_set Menu menuWidget";
1594  aString += QString::number(counter) + " 1 ";
1595  aString += QString::number(counter + 1) + " \"";
1596 
1597  if (curItem->isSelected())
1598  aString += ">";
1599  else
1600  aString += " ";
1601 
1602  switch (curItem->isChecked())
1603  {
1604  case CHECKED: aString += "X "; break;
1605  case UNCHECKED: aString += "O "; break;
1606  case NOTCHECKABLE: aString += " "; break;
1607  default: break;
1608  }
1609 
1610  // Indent this item if nessicary
1611  bString = "";
1612  bString.fill(' ', curItem->getIndent());
1613  aString += bString;
1614 
1615  // Increment the scroll position counter for this item
1616  curItem->incrementScrollPos();
1617 
1618  if ((int)curItem->getScrollPos() <= longest_line)
1619  aString += curItem->ItemName().mid(curItem->getScrollPos(),
1620  ( m_lcdWidth-lcdStartCol));
1621 
1622  aString += "\"";
1623  sendToServer(aString);
1624  }
1625 
1626  ++counter;
1627  }
1628 
1629  // If there are no items to scroll, don't waste our time
1630  if (stopTimer)
1631  m_menuScrollTimer->stop();
1632 }
1633 
1634 void LCDProcClient::startVolume(const QString& app_name)
1635 {
1636  if ( m_lcdShowVolume )
1637  setPriority("Volume", TOP);
1638  if ( m_lcdHeight > 1)
1639  outputCenteredText("Volume", "MythTV " + app_name + " Volume");
1640  m_volumeLevel = 0.0;
1641 
1642  outputVolume();
1643 }
1644 
1646 {
1647  // Stop the scrolling timer
1648  m_menuScrollTimer->stop();
1649  setPriority("Menu", OFF);
1650 }
1651 
1652 void LCDProcClient::setChannelProgress(const QString &time, float value)
1653 {
1654  if (!m_lcdReady )
1655  return;
1656 
1657  m_progress = value;
1658  m_channelTime = time;
1659 
1660  if ( m_progress < 0.0F)
1661  m_progress = 0.0F;
1662  else if ( m_progress > 1.0F)
1663  m_progress = 1.0F;
1664 
1665  outputChannel();
1666 }
1667 
1668 void LCDProcClient::setGenericProgress(bool b, float value)
1669 {
1670  if (!m_lcdReady )
1671  return;
1672 
1673  m_genericProgress = value;
1674 
1675  if ( m_genericProgress < 0.0F)
1676  m_genericProgress = 0.0F;
1677  else if ( m_genericProgress > 1.0F)
1678  m_genericProgress = 1.0F;
1679 
1680  // Note, this will let us switch to/from busy indicator by
1681  // alternating between being passed true or false for b.
1682  m_busyProgress = b;
1683  if ( m_busyProgress )
1684  {
1685  // If we're at either end of the line, switch direction
1686  if (( m_busyPos + m_busyDirection >
1687  (signed int) m_lcdWidth - m_busyIndicatorSize ) ||
1688  ( m_busyPos + m_busyDirection < 1))
1689  {
1691  }
1694  }
1695  else
1696  {
1697  m_busyPos = 1;
1698  }
1699 
1700  outputGeneric();
1701 }
1702 
1703 void LCDProcClient::setMusicProgress(QString time, float value)
1704 {
1705  if (!m_lcdReady )
1706  return;
1707 
1708  m_musicProgress = value;
1709  m_musicTime = std::move(time);
1710 
1711  if ( m_musicProgress < 0.0F)
1712  m_musicProgress = 0.0F;
1713  else if ( m_musicProgress > 1.0F)
1714  m_musicProgress = 1.0F;
1715 
1716  outputMusic();
1717 }
1718 
1720 {
1721  if (!m_lcdReady )
1722  return;
1723 
1724  m_musicRepeat = repeat;
1725 
1726  outputMusic ();
1727 }
1728 
1730 {
1731  if (!m_lcdReady )
1732  return;
1733 
1734  m_musicShuffle = shuffle;
1735 
1736  outputMusic ();
1737 }
1738 
1740 {
1741  if (!m_lcdReady )
1742  return;
1743 
1744  m_volumeLevel = value;
1745 
1746  if ( m_volumeLevel < 0.0F)
1747  m_volumeLevel = 0.0F;
1748  if ( m_volumeLevel > 1.0F)
1749  m_volumeLevel = 1.0F;
1750 
1751  outputVolume();
1752 }
1753 
1755 {
1756  QString aString;
1757  aString = "output ";
1758  aString += QString::number(mask);
1759  sendToServer(aString);
1760 }
1761 
1763 {
1764  removeWidgets();
1765  loadSettings();
1766  init();
1767 }
1768 
1770 {
1771  QString aString;
1772  QString time = QTime::currentTime().toString( m_timeFormat );
1773  int toffset = 0;
1774  int xoffset = 0;
1775 
1776  // kludge ahead: use illegal number (11) to clear num display type
1777 
1778  // kluge - Uses string length to determine time format for parsing
1779  // 1:00 = 4 characters = 24-hour format, 1 digit hour
1780  // 12:00 = 5 characters = 24-hour format, 2 digit hour
1781  // 1:00 am = 7 characters = 12-hour format, 1 digit hour
1782  // 12:00 am = 8 characters = 12-hour format, 2 digit hour
1783  if ((time.length() == 8) || (time.length() == 5))
1784  toffset = 1;
1785 
1786  // if 12-hour clock, add AM/PM indicator to end of the 2nd line
1787  if (time.length() > 6)
1788  {
1789  aString = time.at(5 + toffset);
1790  aString += time.at(6 + toffset);
1791  xoffset = 1;
1792  }
1793  else
1794  {
1795  aString = " ";
1796  }
1797  outputRightText("Time", aString, "ampm", m_lcdHeight - 1);
1798 
1799  if ( m_isRecording )
1800  {
1801  outputLeftText("Time","R","rec1",1);
1802  outputLeftText("Time","E","rec2",2);
1803  outputLeftText("Time","C","rec3",3);
1804  aString = QString::number((int) m_tunerList.size());
1805  outputLeftText("Time",aString,"recCnt",4);
1806 
1807  }
1808  else
1809  {
1810  outputLeftText("Time"," ","rec1",1);
1811  outputLeftText("Time"," ","rec2",2);
1812  outputLeftText("Time"," ","rec3",3);
1813  outputLeftText("Time"," ","recCnt",4);
1814  }
1815 
1816  // Add Hour 10's Digit
1817  aString = "widget_set Time d0 ";
1818  aString += QString::number( m_lcdWidth/2 - 5 - xoffset) + " ";
1819  if (toffset == 0)
1820  aString += "11";
1821  else
1822  aString += time.at(0);
1823  sendToServer(aString);
1824 
1825  // Add Hour 1's Digit
1826  aString = "widget_set Time d1 ";
1827  aString += QString::number( m_lcdWidth/2 - 2 - xoffset) + " ";
1828  aString += time.at(0 + toffset);
1829  sendToServer(aString);
1830 
1831  // Add the Colon
1832  aString = "widget_set Time sep ";
1833  aString += QString::number( m_lcdWidth/2 + 1 - xoffset);
1834  aString += " 10"; // 10 means: colon
1835  sendToServer(aString);
1836 
1837  // Add Minute 10's Digit
1838  aString = "widget_set Time d2 ";
1839  aString += QString::number( m_lcdWidth/2 + 2 - xoffset) + " ";
1840  aString += time.at(2 + toffset);
1841  sendToServer(aString);
1842 
1843  // Add Minute 1's Digit
1844  aString = "widget_set Time d3 ";
1845  aString += QString::number( m_lcdWidth/2 + 5 - xoffset) + " ";
1846  aString += time.at(3 + toffset);
1847  sendToServer(aString);
1848 
1849  // Added a flashing dot in the bottom-right corner
1850  if ( m_timeFlash )
1851  {
1852  outputRightText("Time", ".", "dot", m_lcdHeight );
1853  m_timeFlash = false;
1854  }
1855  else
1856  {
1857  outputRightText("Time", " ", "dot", m_lcdHeight );
1858  m_timeFlash = true;
1859  }
1860 }
1861 
1863 {
1864  if ( m_lcdBigClock )
1865  dobigclock();
1866  else
1867  dostdclock();
1868 }
1869 
1871 {
1872  if (!m_lcdShowTime )
1873  return;
1874 
1876  {
1877  outputCenteredText("Time", tr("RECORDING"), "topWidget", 1);
1878  }
1879  else
1880  {
1882  "Time", MythDate::current().toLocalTime().toString( m_dateFormat ),
1883  "topWidget", 1);
1884  }
1885 
1886  QString aString;
1887  int x = 0, y = 0;
1888 
1889  if ( m_lcdHeight < 3)
1890  y = m_lcdHeight;
1891  else
1892  y = (int) rint( m_lcdHeight / 2) + 1;
1893 
1894  QString time = QTime::currentTime().toString( m_timeFormat );
1895  x = ( m_lcdWidth - time.length()) / 2 + 1;
1896  aString = "widget_set Time timeWidget ";
1897  aString += QString::number(x);
1898  aString += " ";
1899  aString += QString::number(y);
1900  aString += " \"";
1901  if ( m_lcdShowTime ) {
1902  aString += time + "\"";
1903  if ( m_timeFlash )
1904  {
1905  aString = aString.replace(QRegExp(":"), " ");
1906  m_timeFlash = false;
1907  }
1908  else
1909  m_timeFlash = true;
1910  }
1911  else
1912  aString += " \"";
1913  sendToServer(aString);
1914 }
1915 
1916 // if one or more recordings are taking place we alternate between
1917 // showing the time and the recording status screen
1919 {
1921  return;
1922 
1923  if ( m_isTimeVisible || !m_lcdShowTime )
1924  {
1925  // switch to the rec status screen
1926  setPriority("RecStatus", MEDIUM);
1927  setPriority("Time", LOW);
1928 
1929  m_timeTimer->stop();
1930  m_scrollWTimer->stop();
1931  m_scrollListTimer->stop();
1932  m_isTimeVisible = false;
1933  m_activeScreen = "RecStatus";
1934 
1935  if (m_lcdTunerNo > (int) m_tunerList.size() - 1)
1936  m_lcdTunerNo = 0;
1937  }
1938  else if ( m_lcdTunerNo > (int) m_tunerList.size() - 1)
1939  {
1940  m_lcdTunerNo = 0;
1941 
1942  // switch to the time screen
1943  setPriority("Time", MEDIUM);
1944  setPriority("RecStatus", LOW);
1945 
1946  m_timeTimer->start(1000);
1947  m_scrollWTimer->stop();
1948  m_scrollListTimer->stop();
1950 
1951  outputTime();
1952  m_activeScreen = "Time";
1953  m_isTimeVisible = true;
1954 
1955  return;
1956  }
1957 
1958  QString aString, status;
1959  QStringList list;
1960  int listTime = 0;
1961 
1963 
1964  m_scrollListItems.clear();
1965  if ( m_lcdHeight >= 4)
1966  {
1967  // LINE 1 - "R" + Channel
1968  status = tr("R ");
1969  status += tuner.channame;
1970  outputLeftText("RecStatus", status, "textWidget1", 1);
1971 
1972  // LINE 2 - "E" + Program Title
1973  status = tr("E ");
1974  status += tuner.title;
1975  outputLeftText("RecStatus", status, "textWidget2", 2);
1976  //list = formatScrollerText(status);
1977  //assignScrollingList(list, "RecStatus", "textWidget2", 2);
1978 
1979  // LINE 3 - "C" + Program Subtitle
1980  status = tr("C ");
1981  status += tuner.subtitle;
1982  outputLeftText("RecStatus", status, "textWidget3", 3);
1983  //list = formatScrollerText(status);
1984  //assignScrollingList(list, "RecStatus", "textWidget3", 3);
1985 
1986  // LINE 4 - hh:mm-hh:mm + Progress Bar
1987  status = tuner.startTime.toLocalTime().toString("hh:mm") + "-" +
1988  tuner.endTime.toLocalTime().toString("hh:mm");
1989  outputLeftText("RecStatus", status, "textWidget4", 4);
1990 
1991  int length = tuner.startTime.secsTo(tuner.endTime);
1992  int delta = tuner.startTime.secsTo(MythDate::current());
1993  double rec_progress = (double) delta / length;
1994 
1995  aString = "widget_set RecStatus progressBar 13 ";
1996  aString += QString::number( m_lcdHeight );
1997  aString += " ";
1998  aString += QString::number((int)rint(rec_progress * ( m_lcdWidth - 13) *
1999  m_cellWidth ));
2000  sendToServer(aString);
2001 
2002  listTime = list.count() * LCD_SCROLLLIST_TIME * 2;
2003  }
2004  else
2005  {
2006  status = tr("RECORDING|");
2007  status += tuner.title;
2008  if (!tuner.subtitle.isEmpty())
2009  status += "|(" + tuner.subtitle + ")";
2010 
2011  status += "|" + tuner.startTime.toLocalTime().toString("hh:mm")
2012  + " to " +
2013  tuner.endTime.toLocalTime().toString("hh:mm");
2014 
2015  list = formatScrollerText(status);
2016  assignScrollingList(list, "RecStatus", "textWidget1", 1);
2017 
2018  if ( m_lcdHeight > 1)
2019  {
2020  int length = tuner.startTime.secsTo(tuner.endTime);
2021  int delta = tuner.startTime.secsTo(MythDate::current());
2022  double rec_progress = (double) delta / length;
2023 
2024  aString = "widget_set RecStatus progressBar 1 ";
2025  aString += QString::number( m_lcdHeight );
2026  aString += " ";
2027  aString += QString::number((int)rint(rec_progress * m_lcdWidth *
2028  m_cellWidth ));
2029  sendToServer(aString);
2030  }
2031  else
2032  sendToServer("widget_set RecStatus progressBar 1 1 0");
2033 
2034  listTime = list.count() * LCD_SCROLLLIST_TIME * 2;
2035  }
2036 
2037  if (listTime < LCD_TIME_TIME)
2038  listTime = LCD_TIME_TIME;
2039 
2040  m_recStatusTimer->start(listTime);
2041  m_lcdTunerNo++;
2042 }
2043 
2044 void LCDProcClient::outputScrollerText(const QString& theScreen, const QString& theText,
2045  const QString& widget, int top, int bottom)
2046 {
2047  QString aString;
2048  aString = "widget_set " + theScreen + " " + widget;
2049  aString += " 1 ";
2050  aString += QString::number(top) + " ";
2051  aString += QString::number( m_lcdWidth ) + " ";
2052  aString += QString::number(bottom);
2053  aString += " v 8 \"" + theText + "\"";
2054 
2055  sendToServer(aString);
2056 }
2057 
2058 QStringList LCDProcClient::formatScrollerText(const QString &text)
2059 {
2060  QString separators = " |-_/:('<~";
2061  QStringList lines;
2062 
2063  int lastSplit = 0;
2064  QString line = "";
2065 
2066  for (int x = 0; x < text.length(); x++)
2067  {
2068  if (separators.contains(text[x]))
2069  lastSplit = line.length();
2070 
2071  line += text[x];
2072  if (line.length() > (int) m_lcdWidth || text[x] == '|')
2073  {
2074  QString formatedLine;
2075  formatedLine.fill(' ', m_lcdWidth );
2076  formatedLine = formatedLine.replace(( m_lcdWidth - lastSplit) / 2,
2077  lastSplit, line.left(lastSplit));
2078 
2079  lines.append(formatedLine);
2080 
2081  if (line[lastSplit] == ' ' || line[lastSplit] == '|')
2082  line = line.mid(lastSplit + 1);
2083  else
2084  line = line.mid(lastSplit);
2085 
2086  lastSplit = m_lcdWidth;
2087  }
2088  }
2089 
2090  // make sure we add the last line
2091  QString formatedLine;
2092  formatedLine.fill(' ', m_lcdWidth );
2093  formatedLine = formatedLine.replace(( m_lcdWidth - line.length()) / 2,
2094  line.length(), line);
2095 
2096  lines.append(formatedLine);
2097 
2098  return lines;
2099 }
2100 
2102 {
2103  // See startMusic() for a discription of the Music screen contents
2104 
2105  outputCenteredText("Music", m_musicTime, "timeWidget",
2106  m_lcdHeight < 4 ? 2 : 3);
2107 
2108  if ( m_lcdHeight > 2)
2109  {
2110  QString aString;
2111  QString shuffle = "";
2112  QString repeat = "";
2113  int info_width = 0;
2114 
2115  if ( m_musicShuffle == 1)
2116  {
2117  shuffle = "S:? ";
2118  }
2119  else if ( m_musicShuffle == 2)
2120  {
2121  shuffle = "S:i ";
2122  }
2123  else if ( m_musicShuffle == 3)
2124  {
2125  shuffle = "S:a ";
2126  }
2127 
2128  if ( m_musicRepeat == 1)
2129  {
2130  repeat = "R:1 ";
2131  }
2132  else if ( m_musicRepeat == 2)
2133  {
2134  repeat = "R:* ";
2135  }
2136 
2137  if (shuffle.length() != 0 || repeat.length() != 0)
2138  {
2139  aString = shuffle + repeat;
2140  info_width = aString.length();
2141  outputLeftText("Music", aString, "infoWidget", m_lcdHeight );
2142  }
2143  else
2144  outputLeftText("Music", " ", "infoWidget", m_lcdHeight );
2145 
2146  aString = "widget_set Music progressBar ";
2147  aString += QString::number(info_width + 1);
2148  aString += " ";
2149  aString += QString::number( m_lcdHeight );
2150  aString += " ";
2151  aString += QString::number((int)rint( m_musicProgress *
2152  ( m_lcdWidth - info_width) * m_cellWidth ));
2153  sendToServer(aString);
2154  }
2155 }
2156 
2158 {
2159  if ( m_lcdHeight > 1)
2160  {
2161  QString aString;
2162  aString = "widget_set Channel progressBar 1 ";
2163  aString += QString::number( m_lcdHeight );
2164  aString += " ";
2165  aString += QString::number((int)rint( m_progress * m_lcdWidth * m_cellWidth ));
2166  sendToServer(aString);
2167 
2168  if ( m_lcdHeight >= 4)
2169  outputCenteredText("Channel", m_channelTime, "timeWidget", 3);
2170  }
2171  else
2172  sendToServer("widget_set Channel progressBar 1 1 0");
2173 }
2174 
2176 {
2177  if ( m_lcdHeight > 1)
2178  {
2179  QString aString;
2180  aString = "widget_set Generic progressBar ";
2181  aString += QString::number ( m_busyPos );
2182  aString += " ";
2183  aString += QString::number( m_lcdHeight );
2184  aString += " ";
2185  aString += QString::number((int)rint( m_genericProgress * m_lcdWidth *
2186  m_cellWidth ));
2187  sendToServer(aString);
2188 }
2189  else sendToServer("widget_set Generic progressBar 1 1 0");
2190 }
2191 
2193 {
2194  QString aString;
2195  int line = 3;
2196 
2197  if ( m_lcdHeight > 1)
2198  {
2199  aString = "widget_set Volume progressBar 1 ";
2200  aString += QString::number( m_lcdHeight );
2201  aString += " ";
2202  aString += QString::number((int)rint( m_volumeLevel * m_lcdWidth * m_cellWidth ));
2203  sendToServer(aString);
2204  }
2205 
2206  aString = QString::number((int)( m_volumeLevel * 100));
2207  aString += "%";
2208 
2209  if ( m_lcdHeight > 3)
2210  line = 3;
2211  else
2212  line = m_lcdHeight;
2213  outputRightText("Volume", aString, "botWidget", line);
2214 }
2215 
2217 {
2218  if (!m_lcdReady )
2219  return;
2220 
2221  stopAll();
2222 
2223  if (debug_level > 1)
2224  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToTime");
2225 
2226  startTime();
2227 }
2228 
2229 void LCDProcClient::switchToMusic(const QString &artist, const QString &album, const QString &track)
2230 {
2231  if (!m_lcdReady )
2232  return;
2233 
2234  stopAll();
2235 
2236  if (debug_level > 1)
2237  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToMusic") ;
2238 
2239  startMusic(artist, album, track);
2240 }
2241 
2242 void LCDProcClient::switchToChannel(const QString& channum, const QString& title, const QString& subtitle)
2243 {
2244  if (!m_lcdReady )
2245  return;
2246 
2247  stopAll();
2248 
2249  if (debug_level > 1)
2250  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToChannel");
2251 
2252  startChannel(channum, title, subtitle);
2253 }
2254 
2255 void LCDProcClient::switchToMenu(QList<LCDMenuItem> *menuItems, const QString& app_name,
2256  bool popMenu)
2257 {
2258  if (!m_lcdReady )
2259  return;
2260 
2261  if (debug_level > 1)
2262  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToMenu");
2263 
2264  startMenu(menuItems, app_name, popMenu);
2265 }
2266 
2267 void LCDProcClient::switchToGeneric(QList<LCDTextItem> *textItems)
2268 {
2269  if (!m_lcdReady )
2270  return;
2271  stopAll();
2272 
2273  if (debug_level > 1)
2274  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToGeneric");
2275 
2276  startGeneric(textItems);
2277 }
2278 
2279 void LCDProcClient::switchToVolume(const QString& app_name)
2280 {
2281  if (!m_lcdReady )
2282  return;
2283 
2284  stopAll();
2285 
2286  if (debug_level > 1)
2287  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToVolume");
2288 
2289  startVolume(app_name);
2290 }
2291 
2293 {
2294  if (!m_lcdReady )
2295  return;
2296 
2297  stopAll();
2298 
2299  if (debug_level > 1)
2300  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: switchToNothing");
2301 }
2302 
2304 {
2305  if (debug_level > 1)
2306  LOG(VB_GENERAL, LOG_INFO, "LCDProcClient: shutdown");
2307 
2308  stopAll();
2309 
2310  // Remove all the widgets and screens for a clean exit from the server
2311  removeWidgets();
2312 
2313  m_socket->close();
2314 
2315  m_lcdReady = false;
2316  m_connected = false;
2317 }
2318 
2320 {
2321  sendToServer("widget_del Channel progressBar");
2322  sendToServer("widget_del Channel topWidget");
2323  sendToServer("widget_del Channel timeWidget");
2324  sendToServer("screen_del Channel");
2325 
2326  sendToServer("widget_del Generic progressBar");
2327  sendToServer("widget_del Generic textWidget1");
2328  sendToServer("widget_del Generic textWidget2");
2329  sendToServer("widget_del Generic textWidget3");
2330  sendToServer("screen_del Generic");
2331 
2332  sendToServer("widget_del Volume progressBar");
2333  sendToServer("widget_del Volume topWidget");
2334  sendToServer("screen_del Volume");
2335 
2336  sendToServer("widget_del Menu topWidget");
2337  sendToServer("widget_del Menu menuWidget1");
2338  sendToServer("widget_del Menu menuWidget2");
2339  sendToServer("widget_del Menu menuWidget3");
2340  sendToServer("widget_del Menu menuWidget4");
2341  sendToServer("widget_del Menu menuWidget5");
2342  sendToServer("screen_del Menu");
2343 
2344  sendToServer("widget_del Music progressBar");
2345  sendToServer("widget_del Music infoWidget");
2346  sendToServer("widget_del Music timeWidget");
2347  sendToServer("widget_del Music topWidget");
2348  sendToServer("screen_del Music");
2349 
2350  if ( m_lcdBigClock )
2351  {
2352  sendToServer("widget_del Time rec1");
2353  sendToServer("widget_del Time rec2");
2354  sendToServer("widget_del Time rec3");
2355  sendToServer("widget_del Time recCnt");
2356  sendToServer("widget_del Time d0");
2357  sendToServer("widget_del Time d1");
2358  sendToServer("widget_del Time sep");
2359  sendToServer("widget_del Time d2");
2360  sendToServer("widget_del Time d3");
2361  sendToServer("widget_del Time ampm");
2362  sendToServer("widget_del Time dot");
2363  }
2364  else
2365  {
2366  sendToServer("widget_del Time timeWidget");
2367  sendToServer("widget_del Time topWidget");
2368  }
2369 
2370  sendToServer("screen_del Time");
2371 
2372  sendToServer("widget_del RecStatus textWidget1");
2373  sendToServer("widget_del RecStatus textWidget2");
2374  sendToServer("widget_del RecStatus textWidget3");
2375  sendToServer("widget_del RecStatus textWidget4");
2376  sendToServer("widget_del RecStatus progressBar");
2377 }
2378 
2380 {
2381  if (debug_level > 1)
2382  LOG(VB_GENERAL, LOG_INFO,
2383  "LCDProcClient: An LCD device is being snuffed out"
2384  "of existence (~LCDProcClient() was called)");
2385 
2386  if (m_socket)
2387  {
2388  delete m_socket;
2389  m_lcdReady = false;
2390  }
2391 
2392  delete m_lcdMenuItems;
2393 
2395 }
2396 
2398 {
2399  if (e->type() == MythEvent::MythEventMessage)
2400  {
2401  MythEvent *me = static_cast<MythEvent *>(e);
2402 
2403  if (me->Message().startsWith("RECORDING_LIST_CHANGE") ||
2404  me->Message() == "UPDATE_PROG_INFO")
2405  {
2406  if ( m_lcdShowRecstatus && !m_updateRecInfoTimer->isActive())
2407  {
2408  if (debug_level > 1)
2409  LOG(VB_GENERAL, LOG_INFO,
2410  "LCDProcClient: Received recording list change");
2411 
2412  // we can't query the backend from inside the customEvent
2413  // so fire the recording list update from a timer
2414  m_updateRecInfoTimer->start(500);
2415  }
2416  }
2417  }
2418 }
2419 
2421 {
2422  m_tunerList.clear();
2423  m_isRecording = false;
2424 
2426  {
2427  if (!gCoreContext->ConnectToMasterServer(false))
2428  {
2429  LOG(VB_GENERAL, LOG_ERR,
2430  "LCDProcClient: Cannot get recording status "
2431  "- is the master server running?\n\t\t\t"
2432  "Will retry in 30 seconds");
2433  QTimer::singleShot(30 * 1000, this, SLOT(updateRecordingList()));
2434 
2435  // If we can't get the recording status and we're showing
2436  // it, switch back to time. Maybe it would be even better
2437  // to show that the backend is unreachable ?
2438  if (m_activeScreen == "RecStatus")
2439  switchToTime();
2440  return;
2441  }
2442  }
2443 
2445 
2446  m_lcdTunerNo = 0;
2447 
2448  if (m_activeScreen == "Time" || m_activeScreen == "RecStatus")
2449  startTime();
2450 }
2451 /* 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 &)
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.
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)
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)
void switchToChannel(const QString &channum="", const QString &title="", const QString &subtitle="")
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
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
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
void switchToMenu(QList< LCDMenuItem > *menuItems, const QString &app_name="", bool popMenu=true)
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
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 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