MythTV  0.28pre
 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 "mythuistatetype.h"
18 #include "mythlogging.h"
19 
21 {
22  public:
23  SemaphoreLocker(QSemaphore *lock) : m_lock(lock)
24  {
25  if (m_lock)
26  m_lock->acquire();
27  }
29  {
30  if (m_lock)
31  m_lock->release();
32  }
33  private:
34  QSemaphore *m_lock;
35 };
36 
38  (QEvent::Type) QEvent::registerEventType();
39 
40 class ScreenLoadTask : public QRunnable
41 {
42  public:
44 
45  private:
46  void run(void)
47  {
48  m_parent.Load();
49  m_parent.m_IsLoaded = true;
50  m_parent.m_IsLoading = false;
51  m_parent.m_LoadLock.release();
52  }
53 
55 };
56 
58  MythScreenStack *parent, const QString &name, bool fullscreen) :
59  MythUIComposite(parent, name), m_LoadLock(1)
60 {
61  m_FullScreen = fullscreen;
62  m_CurrentFocusWidget = NULL;
63 
65  m_BusyPopup = NULL;
66  m_IsDeleting = false;
67  m_IsLoading = false;
68  m_IsLoaded = false;
69  m_IsInitialized = false;
70 
71  // Can be overridden, of course, but default to full sized.
73 
74  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
76  QString("SCREEN_TYPE CREATED %1").arg(name));
77 }
78 
80  MythUIType *parent, const QString &name, bool fullscreen) :
81  MythUIComposite(parent, name), m_LoadLock(1)
82 {
83  m_FullScreen = fullscreen;
84  m_CurrentFocusWidget = NULL;
85 
86  m_ScreenStack = NULL;
87  m_BusyPopup = NULL;
88  m_IsDeleting = false;
89  m_IsLoading = false;
90  m_IsLoaded = false;
91  m_IsInitialized = false;
92 
94 
95  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
97  QString("SCREEN_TYPE CREATED %1").arg(name));
98 }
99 
101 {
102  if (QCoreApplication::applicationName() == MYTH_APPNAME_MYTHFRONTEND)
104  QString("SCREEN_TYPE DESTROYED %1").arg(objectName()));
105 
106  // locking ensures background screen load can finish running
107  SemaphoreLocker locker(&m_LoadLock);
108 
109  m_CurrentFocusWidget = NULL;
110  emit Exiting();
111 }
112 
114 {
115  return m_FullScreen;
116 }
117 
119 {
120  m_FullScreen = full;
121 }
122 
124 {
125  return m_CurrentFocusWidget;
126 }
127 
129 {
130  if (!widget || !widget->IsVisible())
131  {
132  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
134 
135  while (it != m_FocusWidgetList.end())
136  {
137  current = *it;
138 
139  if (current->CanTakeFocus() && current->IsVisible())
140  {
141  widget = current;
142  break;
143  }
144  ++it;
145  }
146  }
147 
148  if (!widget)
149  return false;
150 
151  if (m_CurrentFocusWidget == widget)
152  return true;
153 
154  MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
155  if (helpText)
156  helpText->Reset();
157 
160  m_CurrentFocusWidget = widget;
162 
163  if (helpText && !widget->GetHelpText().isEmpty())
164  helpText->SetText(widget->GetHelpText());
165 
166  return true;
167 }
168 
170 {
171  if (!m_CurrentFocusWidget || m_FocusWidgetList.isEmpty())
172  return SetFocusWidget(NULL);
173 
174  bool reachedCurrent = false;
175  bool looped = false;
176 
177  QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
179 
180  // There is probably a more efficient way to do this, but the list
181  // is never going to be that big so it will do for now
182  if (up)
183  {
184  while (it != m_FocusWidgetList.end())
185  {
186  current = *it;
187 
188  if ((looped || reachedCurrent) &&
189  current->IsVisible() && current->IsEnabled())
190  return SetFocusWidget(current);
191 
192  if (current == m_CurrentFocusWidget)
193  reachedCurrent = true;
194 
195  ++it;
196 
197  if (it == m_FocusWidgetList.end())
198  {
199  if (looped)
200  return false;
201  else
202  {
203  looped = true;
204  it = m_FocusWidgetList.begin();
205  }
206  }
207  }
208  }
209  else
210  {
211  it = m_FocusWidgetList.end() - 1;
212  while (it != m_FocusWidgetList.begin() - 1)
213  {
214  current = *it;
215 
216  if ((looped || reachedCurrent) &&
217  current->IsVisible() && current->IsEnabled())
218  return SetFocusWidget(current);
219 
220  if (current == m_CurrentFocusWidget)
221  reachedCurrent = true;
222 
223  --it;
224 
225  if (it == m_FocusWidgetList.begin() - 1)
226  {
227  if (looped)
228  return false;
229  else
230  {
231  looped = true;
232  it = m_FocusWidgetList.end() - 1;
233  }
234  }
235  }
236  }
237 
238  return false;
239 }
240 
242 {
243  m_FocusWidgetList.clear();
244  m_CurrentFocusWidget = NULL;
245 
247 
248  if (m_FocusWidgetList.size() > 0)
249  SetFocusWidget();
250 }
251 
253 {
254  return m_ScreenStack;
255 }
256 
258 {
259  if (!m_FullScreen)
260  {
261  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
262  {
263  // remove this screen's area from the mask so any embedded video is
264  // shown which was covered by this screen
265  if (!m_SavedMask.isEmpty())
267  }
268  }
269 
271 }
272 
274 {
275  if (!m_FullScreen)
276  {
277  if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
278  {
279  // add this screens area to the mask so any embedded video isn't
280  // shown in front of this screen
281  QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
282  m_SavedMask = region;
283  region = region.united(QRegion(m_Area));
284  GetMythMainWindow()->GetPaintWindow()->setMask(region);
285  }
286  }
287 
289 }
290 
292 {
293  return m_IsDeleting;
294 }
295 
296 void MythScreenType::SetDeleting(bool deleting)
297 {
298  m_IsDeleting = deleting;
299 }
300 
302 {
303  return true;
304 }
305 
317 {
318  // Virtual
319 }
320 
321 void MythScreenType::LoadInBackground(QString message)
322 {
323  m_LoadLock.acquire();
324 
325  m_IsLoading = true;
326  m_IsLoaded = false;
327 
329 
330  OpenBusyPopup(message);
331 
332  ScreenLoadTask *loadTask = new ScreenLoadTask(*this);
333  MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
334 }
335 
337 {
338  SemaphoreLocker locker(&m_LoadLock);
339 
340  m_IsLoading = true;
341  m_IsLoaded = false;
342 
344  Load();
345  m_IsLoaded = true;
346  m_IsLoading = false;
347 }
348 
350 {
351  m_IsInitialized = false;
353 }
354 
355 void MythScreenType::OpenBusyPopup(QString message)
356 {
357  if (m_BusyPopup)
358  return;
359 
360  QString msg(tr("Loading..."));
361  if (!message.isEmpty())
362  msg = message;
363 
364  MythScreenStack *popupStack =
365  GetMythMainWindow()->GetStack("popup stack");
366  m_BusyPopup =
367  new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
368 
369  if (m_BusyPopup->Create())
370  popupStack->AddScreen(m_BusyPopup, false);
371 }
372 
374 {
375  if (m_BusyPopup)
376  m_BusyPopup->Close();
377  m_BusyPopup = NULL;
378 }
379 
380 void MythScreenType::SetBusyPopupMessage(const QString &message)
381 {
382  if (m_BusyPopup)
383  m_BusyPopup->SetMessage(message);
384 }
385 
387 {
388  if (m_BusyPopup)
389  m_BusyPopup->Reset();
390 }
391 
396 {
397  return m_IsInitialized;
398 }
399 
401 {
402  SemaphoreLocker locker(&m_LoadLock); // don't run while loading..
403 
404  CloseBusyPopup();
405  Init();
406  m_IsInitialized = true;
407 }
408 
417 {
418  // Virtual
419 }
420 
422 {
423  CloseBusyPopup();
424  if (GetScreenStack())
425  GetScreenStack()->PopScreen(this);
426 }
427 
429 {
430  // Virtual
431 }
432 
433 bool MythScreenType::keyPressEvent(QKeyEvent *event)
434 {
436  return true;
437 
438  bool handled = false;
439  QStringList actions;
440  handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
441 
442  for (int i = 0; i < actions.size() && !handled; i++)
443  {
444  QString action = actions[i];
445  handled = true;
446 
447  if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
448  {
449  if (!NextPrevWidgetFocus(false))
450  handled = false;
451  }
452  else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
453  {
454  if (!NextPrevWidgetFocus(true))
455  handled = false;
456  }
457  else if (action == "ESCAPE")
458  Close();
459  else if (action == "MENU")
460  ShowMenu();
461  else if (action.startsWith("SYSEVENT"))
462  gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
463  else if (action == ACTION_SCREENSHOT)
465  else if (action == ACTION_TVPOWERON)
467  else if (action == ACTION_TVPOWEROFF)
469  else
470  handled = false;
471  }
472 
473  return handled;
474 }
475 
477 {
478  bool handled = false;
479  if (event->gesture() == MythGestureEvent::Click)
480  {
481  switch (event->GetButton())
482  {
484  ShowMenu();
485  handled = true;
486  break;
487  default :
488  break;
489  }
490 
491  }
492 
493  if (!handled)
494  {
495  MythUIType *clicked = GetChildAt(event->GetPosition());
496  if (clicked && clicked->IsEnabled())
497  {
498  SetFocusWidget(clicked);
499  if (clicked->gestureEvent(event))
500  handled = true;
501  }
502  }
503 
504  return handled;
505 }
506 
511  const QString &filename, QDomElement &element, bool showWarnings)
512 {
513  if (element.tagName() == "area")
514  {
515  MythRect rect = parseRect(element, false);
516  MythRect rectN = parseRect(element);
517  QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
518 
519  if (rect.x() == -1)
520  rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
521 
522  if (rect.y() == -1)
523  rectN.moveTop((screenArea.height() - rectN.height()) / 2);
524 
525  SetArea(rectN);
526 
527  if (m_Area.width() < screenArea.width() ||
528  m_Area.height() < screenArea.height())
529  {
530  m_FullScreen = false;
531  }
532  else
533  {
534  m_FullScreen = true;
535  }
536  }
537  else
538  {
539  return MythUIType::ParseElement(filename, element, showWarnings);
540  }
541 
542  return true;
543 }
544 
549 {
550  MythScreenType *st = dynamic_cast<MythScreenType *>(base);
551  if (!st)
552  {
553  LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
554  return;
555  }
556 
558  m_IsDeleting = false;
559 
560  MythUIType::CopyFrom(base);
561 
562  ConnectDependants(true);
563 
564  BuildFocusList();
565 };
566 
574 {
575  LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
576 }
577 
579 {
580  if (m_Painter)
581  return m_Painter;
582  if (m_ScreenStack)
583  return m_ScreenStack->GetPainter();
584  return GetMythPainter();
585 }