MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
mythscreentype.cpp
Go to the documentation of this file.
1 
2 #include "mythscreentype.h"
3 
4 #include <QCoreApplication>
5 #include <QDomDocument>
6 #include <QRunnable>
7 
8 #include "mythcorecontext.h"
9 #include "mythobservable.h"
10 #include "mthreadpool.h"
11 
12 #include "mythscreenstack.h"
13 #include "mythmainwindow.h"
14 #include "mythuihelper.h"
15 #include "mythprogressdialog.h"
16 #include "mythuigroup.h"
17 #include "mythlogging.h"
18 
20 {
21  public:
22  SemaphoreLocker(QSemaphore *lock) : m_lock(lock)
23  {
24  if (m_lock)
25  m_lock->acquire();
26  }
28  {
29  if (m_lock)
30  m_lock->release();
31  }
32  private:
33  QSemaphore *m_lock;
34 };
35 
37  (QEvent::Type) QEvent::registerEventType();
38 
39 class ScreenLoadTask : public QRunnable
40 {
41  public:
42  ScreenLoadTask(MythScreenType &parent) : m_parent(parent) {}
43 
44  private:
45  void run(void)
46  {
47  m_parent.Load();
48  m_parent.m_IsLoaded = true;
49  m_parent.m_IsLoading = false;
50  m_parent.m_LoadLock.release();
51  }
52 
54 };
55 
57  MythScreenStack *parent, const QString &name, bool fullscreen) :
58  MythUIType(parent, name), m_LoadLock(1)
59 {
60  m_FullScreen = fullscreen;
61  m_CurrentFocusWidget = NULL;
62 
63  m_ScreenStack = parent;
64  m_BusyPopup = NULL;
65  m_IsDeleting = false;
66  m_IsLoading = false;
67  m_IsLoaded = false;
68  m_IsInitialized = false;
69 
70  // Can be overridden, of course, but default to full sized.
72 
73  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
75  QString("SCREEN_TYPE CREATED %1").arg(name));
76 }
77 
79  MythUIType *parent, const QString &name, bool fullscreen) :
80  MythUIType(parent, name), m_LoadLock(1)
81 {
82  m_FullScreen = fullscreen;
83  m_CurrentFocusWidget = NULL;
84 
85  m_ScreenStack = NULL;
86  m_BusyPopup = NULL;
87  m_IsDeleting = false;
88  m_IsLoading = false;
89  m_IsLoaded = false;
90  m_IsInitialized = false;
91 
93 
94  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
96  QString("SCREEN_TYPE CREATED %1").arg(name));
97 }
98 
100 {
101  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
103  QString("SCREEN_TYPE DESTROYED %1").arg(objectName()));
104 
105  // locking ensures background screen load can finish running
106  SemaphoreLocker locker(&m_LoadLock);
107 
108  m_CurrentFocusWidget = NULL;
109  emit Exiting();
110 }
111 
113 {
114  return m_FullScreen;
115 }
116 
118 {
119  m_FullScreen = full;
120 }
121 
123 {
124  return m_CurrentFocusWidget;
125 }
126 
128 {
129  if (!widget || !widget->IsVisible())
130  {
131  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
133 
134  while (it != m_FocusWidgetList.end())
135  {
136  current = *it;
137 
138  if (current->CanTakeFocus() && current->IsVisible())
139  {
140  widget = current;
141  break;
142  }
143  ++it;
144  }
145  }
146 
147  if (!widget)
148  return false;
149 
150  if (m_CurrentFocusWidget == widget)
151  return true;
152 
153  MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
154  if (helpText)
155  helpText->Reset();
156 
159  m_CurrentFocusWidget = widget;
161 
162  if (helpText && !widget->GetHelpText().isEmpty())
163  helpText->SetText(widget->GetHelpText());
164 
165  return true;
166 }
167 
169 {
170  if (!m_CurrentFocusWidget || m_FocusWidgetList.isEmpty())
171  return SetFocusWidget(NULL);
172 
173  bool reachedCurrent = false;
174  bool looped = false;
175 
176  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
178 
179  // There is probably a more efficient way to do this, but the list
180  // is never going to be that big so it will do for now
181  if (up)
182  {
183  while (it != m_FocusWidgetList.end())
184  {
185  current = *it;
186 
187  if ((looped || reachedCurrent) &&
188  current->IsVisible() && current->IsEnabled())
189  return SetFocusWidget(current);
190 
191  if (current == m_CurrentFocusWidget)
192  reachedCurrent = true;
193 
194  ++it;
195 
196  if (it == m_FocusWidgetList.end())
197  {
198  if (looped)
199  return false;
200  else
201  {
202  looped = true;
203  it = m_FocusWidgetList.begin();
204  }
205  }
206  }
207  }
208  else
209  {
210  it = m_FocusWidgetList.end() - 1;
211  while (it != m_FocusWidgetList.begin() - 1)
212  {
213  current = *it;
214 
215  if ((looped || reachedCurrent) &&
216  current->IsVisible() && current->IsEnabled())
217  return SetFocusWidget(current);
218 
219  if (current == m_CurrentFocusWidget)
220  reachedCurrent = true;
221 
222  --it;
223 
224  if (it == m_FocusWidgetList.begin() - 1)
225  {
226  if (looped)
227  return false;
228  else
229  {
230  looped = true;
231  it = m_FocusWidgetList.end() - 1;
232  }
233  }
234  }
235  }
236 
237  return false;
238 }
239 
241 {
242  m_FocusWidgetList.clear();
243  m_CurrentFocusWidget = NULL;
244 
246 
247  if (m_FocusWidgetList.size() > 0)
248  SetFocusWidget();
249 }
250 
252 {
253  return m_ScreenStack;
254 }
255 
257 {
258  if (!m_FullScreen)
259  {
260  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
261  {
262  // remove this screen's area from the mask so any embedded video is
263  // shown which was covered by this screen
264  if (!m_SavedMask.isEmpty())
266  }
267  }
268 
270 }
271 
273 {
274  if (!m_FullScreen)
275  {
276  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
277  {
278  // add this screens area to the mask so any embedded video isn't
279  // shown in front of this screen
280  QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
281  m_SavedMask = region;
282  region = region.unite(QRegion(m_Area));
283  GetMythMainWindow()->GetPaintWindow()->setMask(region);
284  }
285  }
286 
288 }
289 
291 {
292  return m_IsDeleting;
293 }
294 
295 void MythScreenType::SetDeleting(bool deleting)
296 {
297  m_IsDeleting = deleting;
298 }
299 
301 {
302  return true;
303 }
304 
316 {
317  // Virtual
318 }
319 
320 void MythScreenType::LoadInBackground(QString message)
321 {
322  m_LoadLock.acquire();
323 
324  m_IsLoading = true;
325  m_IsLoaded = false;
326 
328 
329  OpenBusyPopup(message);
330 
331  ScreenLoadTask *loadTask = new ScreenLoadTask(*this);
332  MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
333 }
334 
336 {
337  SemaphoreLocker locker(&m_LoadLock);
338 
339  m_IsLoading = true;
340  m_IsLoaded = false;
341 
343  Load();
344  m_IsLoaded = true;
345  m_IsLoading = false;
346 }
347 
349 {
350  m_IsInitialized = false;
352 }
353 
354 void MythScreenType::OpenBusyPopup(QString message)
355 {
356  if (m_BusyPopup)
357  return;
358 
359  QString msg(tr("Loading..."));
360  if (!message.isEmpty())
361  msg = message;
362 
363  MythScreenStack *popupStack =
364  GetMythMainWindow()->GetStack("popup stack");
365  m_BusyPopup =
366  new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
367 
368  if (m_BusyPopup->Create())
369  popupStack->AddScreen(m_BusyPopup, false);
370 }
371 
373 {
374  if (m_BusyPopup)
375  m_BusyPopup->Close();
376  m_BusyPopup = NULL;
377 }
378 
379 void MythScreenType::SetBusyPopupMessage(const QString &message)
380 {
381  if (m_BusyPopup)
382  m_BusyPopup->SetMessage(message);
383 }
384 
386 {
387  if (m_BusyPopup)
388  m_BusyPopup->Reset();
389 }
390 
395 {
396  return m_IsInitialized;
397 }
398 
400 {
401  SemaphoreLocker locker(&m_LoadLock); // don't run while loading..
402 
403  CloseBusyPopup();
404  Init();
405  m_IsInitialized = true;
406 }
407 
416 {
417  // Virtual
418 }
419 
421 {
422  CloseBusyPopup();
423  if (GetScreenStack())
424  GetScreenStack()->PopScreen(this);
425 }
426 
428 {
429  // Virtual
430 }
431 
432 static void DoSetTextFromMap(MythUIType *UItype, QHash<QString, QString> &infoMap)
433 {
434  QList<MythUIType *> *children = UItype->GetAllChildren();
435 
436  MythUIText *textType;
437 
438  QMutableListIterator<MythUIType *> i(*children);
439  while (i.hasNext())
440  {
441  MythUIType *type = i.next();
442  if (!type->IsVisible())
443  continue;
444 
445  textType = dynamic_cast<MythUIText *> (type);
446  if (textType && infoMap.contains(textType->objectName()))
447  textType->SetTextFromMap(infoMap);
448 
449 
450  MythUIGroup *group = dynamic_cast<MythUIGroup *> (type);
451  if (group)
452  DoSetTextFromMap(type, infoMap);
453  }
454 }
455 
456 void MythScreenType::SetTextFromMap(QHash<QString, QString> &infoMap)
457 {
458  DoSetTextFromMap((MythUIType*) this, infoMap);
459 }
460 
461 static void DoResetMap(MythUIType *UItype, QHash<QString, QString> &infoMap)
462 {
463  if (infoMap.isEmpty())
464  return;
465 
466  QList<MythUIType *> *children = UItype->GetAllChildren();
467 
468  MythUIText *textType;
469  QMutableListIterator<MythUIType *> i(*children);
470  while (i.hasNext())
471  {
472  MythUIType *type = i.next();
473  if (!type->IsVisible())
474  continue;
475 
476  textType = dynamic_cast<MythUIText *> (type);
477  if (textType && infoMap.contains(textType->objectName()))
478  textType->Reset();
479 
480  MythUIGroup *group = dynamic_cast<MythUIGroup *> (type);
481  if (group)
482  DoResetMap(type, infoMap);
483  }
484 }
485 
486 void MythScreenType::ResetMap(QHash<QString, QString> &infoMap)
487 {
488  DoResetMap(this, infoMap);
489 }
490 
491 bool MythScreenType::keyPressEvent(QKeyEvent *event)
492 {
494  return true;
495 
496  bool handled = false;
497  QStringList actions;
498  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
499 
500  for (int i = 0; i < actions.size() && !handled; i++)
501  {
502  QString action = actions[i];
503  handled = true;
504 
505  if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
506  NextPrevWidgetFocus(false);
507  else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
508  NextPrevWidgetFocus(true);
509  else if (action == "ESCAPE")
510  Close();
511  else if (action == "MENU")
512  ShowMenu();
513  else if (action.startsWith("SYSEVENT"))
514  gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
515  else if (action == ACTION_SCREENSHOT)
517  else if (action == ACTION_TVPOWERON)
519  else if (action == ACTION_TVPOWEROFF)
521  else
522  handled = false;
523  }
524 
525  return handled;
526 }
527 
529 {
530  bool handled = false;
531  if (event->gesture() == MythGestureEvent::Click)
532  {
533  switch (event->GetButton())
534  {
536  ShowMenu();
537  handled = true;
538  break;
539  default :
540  break;
541  }
542 
543  }
544 
545  if (!handled)
546  {
547  MythUIType *clicked = GetChildAt(event->GetPosition());
548  if (clicked && clicked->IsEnabled())
549  {
550  SetFocusWidget(clicked);
551  if (clicked->gestureEvent(event))
552  handled = true;
553  }
554  }
555 
556  return handled;
557 }
558 
563  const QString &filename, QDomElement &element, bool showWarnings)
564 {
565  if (element.tagName() == "area")
566  {
567  MythRect rect = parseRect(element, false);
568  MythRect rectN = parseRect(element);
569  QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
570 
571  if (rect.x() == -1)
572  rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
573 
574  if (rect.y() == -1)
575  rectN.moveTop((screenArea.height() - rectN.height()) / 2);
576 
577  SetArea(rectN);
578 
579  if (m_Area.width() < screenArea.width() ||
580  m_Area.height() < screenArea.height())
581  {
582  m_FullScreen = false;
583  }
584  else
585  {
586  m_FullScreen = true;
587  }
588  }
589  else
590  {
591  return MythUIType::ParseElement(filename, element, showWarnings);
592  }
593 
594  return true;
595 }
596 
601 {
602  MythScreenType *st = dynamic_cast<MythScreenType *>(base);
603  if (!st)
604  {
605  LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
606  return;
607  }
608 
610  m_IsDeleting = false;
611 
612  MythUIType::CopyFrom(base);
613 
614  ConnectDependants(true);
615 
616  BuildFocusList();
617 };
618 
626 {
627  LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
628 }
629 
631 {
632  if (m_Painter)
633  return m_Painter;
634  if (m_ScreenStack)
635  return m_ScreenStack->GetPainter();
636  return GetMythPainter();
637 }