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