MythTV  master
mythnotificationcenter.cpp
Go to the documentation of this file.
1 //
2 // mythnotificationcenter.cpp
3 // MythTV
4 //
5 // Created by Jean-Yves Avenard on 25/06/13.
6 // Copyright (c) 2013 Bubblestuff Pty Ltd. All rights reserved.
7 //
8 
9 // Qt headers
10 #include <QCoreApplication>
11 #include <QEvent>
12 #include <QObject>
13 #include <QThread>
14 #include <QTimer>
15 
16 // MythTV headers
17 #include "mythcorecontext.h"
18 #include "mythmainwindow.h"
19 
20 #include "mythnotificationcenter.h"
22 
23 #include "mythpainter.h"
24 #include "mythscreenstack.h"
25 #include "mythscreentype.h"
26 #include "mythuiimage.h"
27 #include "mythuitext.h"
28 #include "mythuiprogressbar.h"
29 #include "mythdate.h"
30 
31 #define LOC QString("NotificationCenter: ")
32 
33 #define HGAP 5
34 #define DEFAULT_DURATION 5000 // in ms
35 
37 
39  (QEvent::Type) QEvent::registerEventType();
40 
42 
44  bool deleteScreen)
45 {
46  if (!screen || screen->IsDeleting())
47  return;
48 
49  bool poppedFullscreen = screen->IsFullscreen();
50 
51  screen->aboutToHide();
52 
53  if (m_Children.isEmpty())
54  return;
55 
56  MythMainWindow *mainwindow = GetMythMainWindow();
57 
58  screen->setParent(nullptr);
59  if (allowFade && m_DoTransitions && !mainwindow->IsExitingToMain())
60  {
61  screen->SetFullscreen(false);
62  if (deleteScreen)
63  {
64  screen->SetDeleting(true);
65  m_ToDelete.push_back(screen);
66  }
67  screen->AdjustAlpha(1, -kFadeVal);
68  }
69  else
70  {
71  for (int i = 0; i < m_Children.size(); ++i)
72  {
73  if (m_Children.at(i) == screen)
74  {
75  m_Children.remove(i);
76  break;
77  }
78  }
79  if (deleteScreen)
80  screen->deleteLater();
81 
82  screen = nullptr;
83  }
84 
85  m_topScreen = nullptr;
86 
88 
89  // If we're fading it, we still want to draw it.
90  if (screen && !m_DrawOrder.contains(screen))
91  m_DrawOrder.push_back(screen);
92 
93  if (!m_Children.isEmpty())
94  {
95  QVector<MythScreenType *>::Iterator it;
96  for (it = m_DrawOrder.begin(); it != m_DrawOrder.end(); ++it)
97  {
98  if (*it != screen && !(*it)->IsDeleting())
99  {
100  m_topScreen = (*it);
101  (*it)->SetAlpha(255);
102  if (poppedFullscreen)
103  (*it)->aboutToShow();
104  }
105  }
106  }
107 
108  if (m_topScreen)
109  {
111  }
112  else
113  {
114  // Screen still needs to be redrawn if we have popped the last screen
115  // off the popup stack, or similar
116  if (mainwindow->GetMainStack())
117  {
118  MythScreenType *mainscreen = mainwindow->GetMainStack()->GetTopScreen();
119  if (mainscreen)
120  mainscreen->SetRedraw();
121  }
122  }
123 }
124 
126 {
127  if (m_Children.isEmpty())
128  return nullptr;
129  // The top screen is the only currently displayed first, if there's a
130  // fullscreen notification displayed, it's the last one
131  MythScreenType *top = m_Children.front();
132  QVector<MythScreenType *>::const_iterator it = m_Children.end() - 1;
133 
134  // loop from last to 2nd
135  for (; it != m_Children.begin(); --it)
136  {
137  MythNotificationScreen *s = dynamic_cast<MythNotificationScreen *>(*it);
138 
139  if (!s)
140  {
141  // if for whatever reason it's not a notification on our screen
142  // it will be dropped as we don't know how it appears
143  top = s;
144  continue;
145  }
146  if (s->m_fullscreen)
147  {
148  top = s;
149  break;
150  }
151  }
152  return top;
153 }
154 
156 
158  int id)
159  : MythScreenType(stack, "mythnotification"), m_id(id),
160  m_duration(-1), m_progress(-1.0), m_fullscreen(false),
161  m_added(false),
162  m_created(false), m_content(kNone), m_update(kAll),
163  m_type(MythNotification::New),
164  m_artworkImage(nullptr), m_titleText(nullptr), m_originText(nullptr),
165  m_descriptionText(nullptr), m_extraText(nullptr), m_progresstextText(nullptr),
166  m_progressBar(nullptr), m_errorState(nullptr), m_mediaState(nullptr),
167  m_index(0),
168  m_timer(new QTimer(this)),
169  m_visibility(MythNotification::kAll),
170  m_priority(MythNotification::kDefault),
171  m_refresh(true)
172 {
173  // Set timer if need be
175  connect(m_timer, SIGNAL(timeout()), this, SLOT(ProcessTimer()));
176 }
177 
179  MythNotification &notification)
180  : MythScreenType(stack, "mythnotification"), m_id(notification.GetId()),
181  m_duration(notification.GetDuration()), m_progress(-1.0),
182  m_fullscreen(false),
183  m_added(false), m_created(false), m_content(kNone),
184  m_update(kAll), m_type(MythNotification::New),
185  m_artworkImage(nullptr), m_titleText(nullptr), m_originText(nullptr),
186  m_descriptionText(nullptr), m_extraText(nullptr), m_progresstextText(nullptr),
187  m_progressBar(nullptr), m_errorState(nullptr), m_mediaState(nullptr),
188  m_index(0),
189  m_timer(new QTimer(this)),
190  m_visibility(MythNotification::kAll),
191  m_priority(MythNotification::kDefault),
192  m_refresh(true)
193 {
194  SetNotification(notification);
195  connect(m_timer, SIGNAL(timeout()), this, SLOT(ProcessTimer()));
196 }
197 
199  const MythNotificationScreen &s)
200  : MythScreenType(stack, "mythnotification"),
201  m_id(s.m_id),
202  m_image(s.m_image),
203  m_imagePath(s.m_imagePath),
204  m_title(s.m_title),
205  m_origin(s.m_origin),
206  m_description(s.m_description),
207  m_extra(s.m_extra),
208  m_duration(s.m_duration),
209  m_progress(s.m_progress),
210  m_progresstext(s.m_progresstext),
211  m_fullscreen(s.m_fullscreen),
212  m_added(false),
213  m_created(false),
214  m_content(s.m_content),
215  m_update(s.m_content), // so all fields are initialised regardless of notification type
216  m_type(s.m_type),
217  m_artworkImage(nullptr), m_titleText(nullptr), m_originText(nullptr),
218  m_descriptionText(nullptr), m_extraText(nullptr), m_progresstextText(nullptr),
219  m_progressBar(nullptr), m_errorState(nullptr), m_mediaState(nullptr),
220  m_creation(),
221  m_expiry(),
222  m_index(0),
223  m_position(),
224  m_timer(new QTimer(this)),
225  m_style(s.m_style),
226  m_visibility(MythNotification::kAll),
227  m_priority(MythNotification::kDefault),
228  m_refresh(true)
229 {
230  connect(m_timer, SIGNAL(timeout()), this, SLOT(ProcessTimer()));
231 }
232 
234 {
235  m_timer->stop();
236  LOG(VB_GUI, LOG_DEBUG, LOC + "MythNotificationScreen dtor");
237  // We can't rely on Exiting() default MythScreenType signal as
238  // by the time it is emitted, the destructor would have already been called
239  // making the members unusable
240  emit ScreenDeleted();
241 }
242 
244 {
245  bool update;
246  m_update = kNone;
247 
248  m_type = notification.type();
249 
254  {
255  m_update |= kImage;
256  update = false;
257  }
258  else if (m_type == MythNotification::Update)
259  {
260  update = true;
261  }
262  else
263  {
264  update = false;
265  }
266 
267  MythImageNotification *img =
268  dynamic_cast<MythImageNotification*>(&notification);
269  if (img)
270  {
271  QString path = img->GetImagePath();
272 
273  m_update |= kImage;
274 
275  if (path.isNull())
276  {
277  UpdateArtwork(img->GetImage());
278  }
279  else
280  {
281  UpdateArtwork(path);
282  }
283  }
284 
286  dynamic_cast<MythPlaybackNotification*>(&notification);
287  if (play)
288  {
289  UpdatePlayback(play->GetProgress(), play->GetProgressText());
290 
291  m_update |= kDuration;
292  }
293 
294  MythMediaNotification *media =
295  dynamic_cast<MythMediaNotification*>(&notification);
296  if (media && m_imagePath.isEmpty() && m_image.isNull())
297  {
298  m_update |= kNoArtwork;
299  }
300 
301  if (!notification.GetMetaData().isEmpty())
302  {
303  UpdateMetaData(notification.GetMetaData());
304  m_update |= kMetaData;
305  }
306  else if (!update)
307  {
308  // A new notification, will always update the metadata field
309  m_update |= kMetaData;
310  }
311 
312  if (!notification.GetStyle().isEmpty())
313  {
314  m_style = notification.GetStyle();
315  m_update |= kStyle;
316  }
317 
318  if (!update)
319  {
321  m_fullscreen = notification.GetFullScreen();
322  }
323 
324  m_duration = notification.GetDuration();
325  m_visibility = notification.GetVisibility();
326  if (!m_visibility)
327  {
328  // no visibility is all visibility to get around QVariant always making 0 the default
329  m_visibility = ~0;
330  }
331  m_priority = notification.GetPriority();
332 
333  // Set timer if need be
335 
336  // We need to re-run init
337  m_refresh = true;
338 }
339 
341 {
342  bool foundtheme = false;
343 
344  // Load the theme for this screen
345  // The xml file containing the screen definition is airplay-ui.xml in this
346  // example, the name of the screen in the xml is airplaypicture. This
347  // should make sense when you look at the xml below
348 
349  QString theme;
350  if (m_fullscreen)
351  {
352  theme = "notification-full";
353  }
354  else if (m_content & kImage)
355  {
356  theme = "notification-image";
357  }
358  else
359  {
360  theme = "notification";
361  }
362 
363  QString theme_attempt = theme + (m_style.isEmpty() ? "" : "-" + m_style);
364 
365  // See if we have an alternative theme available as defined in the notification
366  foundtheme = LoadWindowFromXML("notification-ui.xml", theme_attempt, this);
367  if (!foundtheme && theme_attempt != theme)
368  {
369  // if not, default to the main one
370  foundtheme = LoadWindowFromXML("notification-ui.xml", theme, this);
371  }
372 
373  if (!foundtheme) // If we cannot load the theme for any reason ...
374  return false;
375 
376  m_artworkImage = dynamic_cast<MythUIImage*>(GetChild("image"));
377  m_titleText = dynamic_cast<MythUIText*>(GetChild("title"));
378  m_originText = dynamic_cast<MythUIText*>(GetChild("origin"));
379  m_descriptionText = dynamic_cast<MythUIText*>(GetChild("description"));
380  m_extraText = dynamic_cast<MythUIText*>(GetChild("extra"));
381  m_progresstextText = dynamic_cast<MythUIText*>(GetChild("progress_text"));
382  m_progressBar = dynamic_cast<MythUIProgressBar*>(GetChild("progress"));
383  m_errorState = dynamic_cast<MythUIStateType*>(GetChild("errorstate"));
384  m_mediaState = dynamic_cast<MythUIStateType*>(GetChild("mediastate"));
385 
386  SetErrorState();
387 
388  if (m_mediaState && (m_update & kImage))
389  {
390  m_mediaState->DisplayState((m_content & kNoArtwork) ? "noartwork" : "ok");
391  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Create: Set media state to %1").arg((m_content & kNoArtwork) ? "noartwork" : "ok"));
392  }
393 
394  // store original position
396  m_created = true;
397 
399  {
400  // Visibility will be set automatically during video playback
401  // so can be ignored here
402  SetVisible(false);
403  }
404 
405  // We need to re-run init
406  m_refresh = true;
407 
408  return true;
409 }
410 
415 {
416  if (!m_refresh) // nothing got changed so far, return
417  return;
418 
419  AdjustYPosition();
420 
421  if (m_artworkImage && (m_update & kImage))
422  {
423  if (!m_imagePath.isNull())
424  {
425  // We have a path to the image, use it
427  m_artworkImage->Load();
428  }
429  else if (!m_image.isNull())
430  {
431  // We don't have a path to the image, but the image itself
433  img->Assign(m_image);
434  m_artworkImage->SetImage(img);
435  img->DecrRef();
436  }
437  else
438  {
439  // Will default to displaying whatever placeholder image is defined
440  // in the xml by the themer, means we can show _something_ rather than
441  // a big empty hole. Generally you always want to call Reset() in
442  // these circumstances
444  }
445  }
446 
447  if (m_update != kNone)
448  {
449  InfoMap tmap;
450 
451  tmap["title"] = m_title;
452  if (m_update & kImage)
453  {
454  tmap["image"] = m_imagePath;
455  }
456  tmap["origin"] = m_origin;
457  tmap["description"] = m_description;
458  tmap["extra"] = m_extra;
459  if (m_update & kDuration)
460  {
461  tmap["progress_text"] = m_progresstext;
462  tmap["progress"] = QString("%1").arg((int)(m_progress * 100));
463  }
464  SetTextFromMap(tmap);
465  }
466 
467  if (m_update & kMetaData)
468  {
469  if (m_titleText && m_title.isNull())
470  {
471  m_titleText->Reset();
472  }
473  if (m_originText && m_origin.isNull())
474  {
475  m_originText->Reset();
476  }
477  if (m_descriptionText && m_description.isNull())
478  {
480  }
481  if (m_extraText && m_extra.isNull())
482  {
483  m_extraText->Reset();
484  }
485  }
486 
487  if (m_update & kDuration)
488  {
489  if (m_progresstextText && m_progresstext.isEmpty())
490  {
492  }
493  if (m_progressBar)
494  {
495  if (m_progress >= 0)
496  {
498  m_progressBar->SetTotal(100);
500  }
501  else
502  {
503  // Same as above, calling Reset() allows for a sane, themer defined
504  //default to be displayed
505  m_progressBar->Reset();
506  }
507  }
508  }
509 
510  if (m_progressBar)
511  {
513 
514  }
515 
516  SetErrorState();
517 
518  if (m_mediaState && (m_update & kImage))
519  {
520  m_mediaState->DisplayState((m_update & kNoArtwork) ? "noartwork" : "ok");
521  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Init: Set media state to %1").arg((m_update & kNoArtwork) ? "noartwork" : "ok"));
522  }
523 
524  // No field will be refreshed the next time unless specified otherwise
525  m_update = kNone;
526 
527  if (GetScreenStack() && !m_added)
528  {
529  GetScreenStack()->AddScreen(this);
530  m_added = true;
531  }
532  m_refresh = false;
533 }
534 
536 {
537  if (!m_errorState)
538  return;
539 
540  const char *state;
541 
543  {
544  state = "error";
545  }
546  else if (m_type == MythNotification::Warning)
547  {
548  state = "warning";
549  }
550  else if (m_type == MythNotification::Check)
551  {
552  state = "check";
553  }
554  else if (m_type == MythNotification::Busy)
555  {
556  state = "busy";
557  }
558  else
559  {
560  state = "ok";
561  }
562  LOG(VB_GUI, LOG_DEBUG, LOC + QString("SetErrorState: Set error state to %1").arg(state));
563  m_errorState->DisplayState(state);
564 }
565 
570 void MythNotificationScreen::UpdateArtwork(const QImage &image)
571 {
572  m_image = image;
573  // We need to re-run init
574  m_refresh = true;
575 }
576 
581 void MythNotificationScreen::UpdateArtwork(const QString &image)
582 {
583  m_imagePath = image;
584  // We need to re-run init
585  m_refresh = true;
586 }
587 
595 {
596  QString tmp;
597 
598  tmp = data["minm"];
599  if (!(tmp.isNull() && (m_update & kMetaData)))
600  {
601  m_title = tmp;
602  }
603  tmp = data["asar"];
604  if (!(tmp.isNull() && (m_update & kMetaData)))
605  {
606  m_origin = tmp;
607  }
608  tmp = data["asal"];
609  if (!(tmp.isNull() && (m_update & kMetaData)))
610  {
611  m_description = tmp;
612  }
613  tmp = data["asfm"];
614  if (!(tmp.isNull() && (m_update & kMetaData)))
615  {
616  m_extra = tmp;
617  }
618  // We need to re-run init
619  m_refresh = true;
620 }
621 
626 void MythNotificationScreen::UpdatePlayback(float progress, const QString &text)
627 {
629  m_progresstext = text;
630  // We need to re-run init
631  m_refresh = true;
632 }
633 
638 {
639  // check if anything has changed
640  m_refresh = !(
641  m_id == s.m_id &&
642  m_image == s.m_image &&
643  m_imagePath == s.m_imagePath &&
644  m_title == s.m_title &&
645  m_origin == s.m_origin &&
647  m_extra == s.m_extra &&
648  m_duration == s.m_duration &&
649  m_progress == s.m_progress &&
651  m_content == s.m_content &&
652  m_fullscreen == s.m_fullscreen &&
653  m_expiry == s.m_expiry &&
654  m_index == s.m_index &&
655  m_style == s.m_style &&
656  m_visibility == s.m_visibility &&
657  m_priority == s.m_priority &&
658  m_type == s.m_type
659  );
660 
661  if (m_refresh)
662  {
663  m_id = s.m_id;
664  m_image = s.m_image;
666  m_title = s.m_title;
667  m_origin = s.m_origin;
669  m_extra = s.m_extra;
673  m_content = s.m_content;
675  m_expiry = s.m_expiry;
676  m_index = s.m_index;
677  m_style = s.m_style;
680  m_type = s.m_type;
681  }
682 
683  m_update = m_content; // so all fields are initialised regardless of notification type
684 }
685 
691 {
692  MythPoint point = m_position;
693  point.setY(m_position.getY().toInt() + (GetHeight() + HGAP) * m_index);
694 
695  if (point == GetPosition())
696  return;
697 
698  SetPosition(point);
699  // We need to re-run init
700  m_refresh = true;
701 }
702 
704 {
705  if (set)
706  {
707  m_index = by;
708  }
709  else
710  {
711  m_index += by;
712  }
713  AdjustYPosition();
714 }
715 
720 {
721  if (index != m_index)
722  {
723  m_refresh = true;
724  m_index = index;
725  }
726 }
727 
729 {
730  return GetArea().getHeight().toInt();
731 }
732 
734 {
735  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Screen id %1 \"%2\" expired")
736  .arg(m_id).arg(m_title));
737  // delete screen
738  GetScreenStack()->PopScreen(this, true, true);
739 }
740 
742 {
743  // only registered application can display non-expiring notification
744  if (m_id > 0 && s < 0)
745  return;
746 
747  int ms = s * 1000;
748  ms = ms <= DEFAULT_DURATION ? DEFAULT_DURATION : ms;
749 
750  if (!update)
751  {
753  }
754  m_expiry = MythDate::current().addMSecs(ms);
755 
756  m_timer->stop();
757  m_timer->setSingleShot(true);
758  m_timer->start(ms);
759  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Screen %1 expires at %2")
760  .arg(m_id).arg(m_expiry.toString("mm:ss")));
761 
762 }
763 
764 // Public event handling
766 {
767  QStringList actions;
768  bool handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
769 
770  for (int i = 0; i < actions.size() && !handled; i++)
771  {
772  QString action = actions[i];
773 
774  if (action == "ESCAPE")
775  {
776  if (MythDate::current() < m_creation.addMSecs(MIN_LIFE))
777  return true; // was updated less than 1s ago, ignore
778  }
779  }
780  if (!handled)
781  {
782  handled = MythScreenType::keyPressEvent(event);
783  }
784  return handled;
785 }
786 
788 
790  : m_currentId(0)
791 {
793  "mythnotificationcenter",
794  this);
796 }
797 
799 {
800  const bool isGuiThread =
801  QThread::currentThread() == QCoreApplication::instance()->thread();
802 
803  if (!isGuiThread)
804  {
805  LOG(VB_GENERAL, LOG_ERR, LOC + "Destructor not called from GUI thread");
806  }
807 
808  QMutexLocker lock(&m_lock);
809 
813 
814  // Delete all outstanding queued notifications
815  foreach(MythNotification *n, m_notifications)
816  {
817  delete n;
818  }
819  m_notifications.clear();
820 
821  delete m_screenStack;
823 }
824 
830 {
831  MythNotificationScreen *screen =
832  static_cast<MythNotificationScreen*>(sender());
833 
834  bool duefordeletion = m_deletedScreens.contains(screen);
835 
836  LOG(VB_GUI, LOG_DEBUG, LOC +
837  QString("ScreenDeleted: Entering (%1)").arg(duefordeletion));
838  // Check that screen wasn't about to be deleted
839  if (duefordeletion)
840  {
841  m_deletedScreens.removeAll(screen);
842  }
843 
844  int n = m_screens.indexOf(screen);
845  if (n >= 0)
846  {
847  int num = m_screens.removeAll(screen);
848  LOG(VB_GUI, LOG_DEBUG, LOC +
849  QString("%1 screen removed from screens list").arg(num));
851  }
852  else
853  {
854  LOG(VB_GUI, LOG_DEBUG, LOC +
855  QString("Screen[%1] not found in screens list").arg(screen->m_id));
856  }
857 
858  // remove the converted equivalent screen if any
859  if (m_converted.contains(screen))
860  {
861  delete m_converted[screen];
862  }
863  m_converted.remove(screen);
864 
865  // search if an application had registered for it
866  if (m_registrations.contains(screen->m_id))
867  {
868  if (!duefordeletion)
869  {
870  if (!m_screenStack)
871  {
872  // we're in the middle of being deleted
873  m_registrations.remove(screen->m_id);
874  m_unregistered.remove(screen->m_id);
875  }
876  else
877  {
878  // don't remove the id from the list, as the application is still registered
879  // re-create the screen
880  MythNotificationScreen *newscreen =
882  connect(newscreen, SIGNAL(ScreenDeleted()), this, SLOT(ScreenDeleted()));
883  m_registrations[screen->m_id] = newscreen;
884  // Screen was deleted, add it to suspended list
885  m_suspended.append(screen->m_id);
886  LOG(VB_GUI, LOG_DEBUG, LOC +
887  "ScreenDeleted: Suspending registered screen");
888  }
889  }
890  else
891  {
892  LOG(VB_GUI, LOG_DEBUG, LOC +
893  "ScreenDeleted: Deleting registered screen");
894  }
895  }
896 }
897 
899 {
900  m_screenStack = nullptr;
901 }
902 
903 bool NCPrivate::Queue(const MythNotification &notification)
904 {
905  QMutexLocker lock(&m_lock);
906 
907  int id = notification.GetId();
908  void *parent = notification.GetParent();
909 
910  MythNotification *tmp = static_cast<MythNotification*>(notification.clone());
911  if (id > 0)
912  {
913  // quick sanity check to ensure the right caller is attempting
914  // to register a notification
915  if (!m_registrations.contains(id) || m_clients[id] != parent)
916  {
917  LOG(VB_GENERAL, LOG_DEBUG, LOC +
918  QString("Queue: 0x%1, not registered for id (%2)")
919  .arg((size_t)parent, QT_POINTER_SIZE, 16)
920  .arg(id));
921  id = -1;
922  }
923  else
924  {
925  // check if notification card has been suspended, in which case
926  // refuse all notification updates
927  if (m_suspended.contains(id))
928  {
929  if (notification.type() == MythNotification::Update)
930  {
931  delete tmp;
932  return false;
933  }
934  // got something else than an update, remove it from the
935  // suspended list
936  m_suspended.removeAll(id);
937  }
938  }
939  }
940  m_notifications.append(tmp);
941 
942  // Tell the GUI thread we have new notifications to process
943  QCoreApplication::postEvent(
945 
946  return true;
947 }
948 
950 {
951  QMutexLocker lock(&m_lock);
952 
954 
955  foreach (MythNotification *n, m_notifications)
956  {
957  int id = n->GetId();
958  bool created = false;
959  MythNotificationScreen *screen = nullptr;
960 
961  if (id > 0)
962  {
963  screen = m_registrations[id];
964  }
965  if (!screen)
966  {
967  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Creating screen %1, \"%2\"")
968  .arg(id).arg(n->GetDescription()));
969 
970  // We have a registration, but no screen. Create one and display it
971  screen = CreateScreen(n);
972  if (!screen) // Reads screen definition from xml, and constructs screen
973  {
974  LOG(VB_GENERAL, LOG_ERR, LOC +
975  QString("ProcessQueue: couldn't create required screen"));
976  delete n;
977  continue; // something is wrong ; ignore
978  }
979  if (id > 0)
980  {
981  m_registrations[id] = screen;
982  }
983  created = true;
984  }
985  else
986  {
987  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Using screen %1, \"%2\"")
988  .arg(id).arg(screen->m_title));
989  screen->SetNotification(*n);
990  }
991 
992  // if the screen got allocated, but did't read theme yet, do it now
993  if (screen && !screen->m_created)
994  {
995  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Reloading screen %1, \"%2\"")
996  .arg(id).arg(screen->m_title));
997 
998 
999  if (!screen->Create())
1000  {
1001  delete screen;
1002  delete n;
1003  continue;
1004  }
1005  created = true;
1006  }
1007 
1008  if (created || !m_screens.contains(screen))
1009  {
1010  LOG(VB_GUI, LOG_DEBUG, LOC + QString("Inserting screen %1").arg(id));
1011 
1012  int pos = InsertScreen(screen);
1013  // adjust vertical positions
1014  RefreshScreenPosition(pos);
1015  }
1016 
1017  screen->doInit();
1018  delete n;
1019  }
1020  m_notifications.clear();
1021 
1023 }
1024 
1030 {
1031  MythNotificationScreen *screen;
1032 
1033  if (n)
1034  {
1035  screen = new MythNotificationScreen(m_screenStack, *n);
1036  }
1037  else
1038  {
1039  screen = new MythNotificationScreen(m_screenStack, id);
1040  }
1041 
1042  if (!screen->Create()) // Reads screen definition from xml, and constructs screen
1043  {
1044  // If we can't create the screen then we can't display it, so delete
1045  // and abort
1046  delete screen;
1047  return nullptr;
1048  }
1049  connect(screen, SIGNAL(ScreenDeleted()), this, SLOT(ScreenDeleted()));
1050  return screen;
1051 }
1052 
1053 int NCPrivate::Register(void *from)
1054 {
1055  QMutexLocker lock(&m_lock);
1056 
1057  if (!from)
1058  return -1;
1059 
1060  m_currentId++;
1061  m_registrations.insert(m_currentId, nullptr);
1062  m_clients.insert(m_currentId, from);
1063 
1064  return m_currentId;
1065 }
1066 
1067 void NCPrivate::UnRegister(void *from, int id, bool closeimemdiately)
1068 {
1069  QMutexLocker lock(&m_lock);
1070 
1071  if (!m_registrations.contains(id))
1072  {
1073  LOG(VB_GENERAL, LOG_ERR, LOC +
1074  QString("UnRegister: 0x%1, no such registration (%2)")
1075  .arg((size_t)from, QT_POINTER_SIZE, 16)
1076  .arg(id));
1077  return;
1078  }
1079 
1080  if (m_clients[id] != from)
1081  {
1082  LOG(VB_GENERAL, LOG_ERR, LOC +
1083  QString("UnRegister: 0x%1, not registered for id (%2")
1084  .arg((size_t)from, QT_POINTER_SIZE, 16)
1085  .arg(id));
1086  }
1087 
1088  // queue the de-registration
1089  m_unregistered[id] = closeimemdiately;
1090 
1091  m_clients.remove(id);
1092 
1093  // Tell the GUI thread we have something to process
1094  QCoreApplication::postEvent(
1096 }
1097 
1099 {
1100  QMap<int, MythNotificationScreen*>::iterator it = m_registrations.begin();
1101 
1102  for (; it != m_registrations.end(); ++it)
1103  {
1104  if (*it)
1105  {
1106  m_deletedScreens.append(*it);
1107  }
1108  }
1109  m_registrations.clear();
1110 }
1111 
1113 {
1114  // delete all screens waiting to be deleted
1115  while(!m_deletedScreens.isEmpty())
1116  {
1117  MythNotificationScreen *screen = m_deletedScreens.last();
1118  // we remove the screen from the list before deleting the screen
1119  // so the MythScreenType::Exiting() signal won't process it a second time
1120  m_deletedScreens.removeLast();
1121  if (m_screenStack == nullptr &&
1123  {
1124  // our screen stack got deleted already and all its children
1125  // would have been marked for deletion during the
1126  // ScreenStack destruction but not yet deleted as the event loop may
1127  // not be running; so we can leave the screen alone.
1128  // However for clarity, call deleteLater()
1129  // as it is safe to call deleteLater more than once
1130  screen->deleteLater();
1131  }
1132  else if (screen->GetScreenStack() == m_screenStack)
1133  {
1134  screen->GetScreenStack()->PopScreen(screen, true, true);
1135  }
1136  else if (screen->GetScreenStack() == nullptr)
1137  {
1138  // this screen was never added to a screen stack, delete it now
1139  delete screen;
1140  }
1141  }
1142 }
1143 
1145 {
1146  QMap<int,bool>::iterator it = m_unregistered.begin();
1147  bool needdelete = false;
1148 
1149  for (; it != m_unregistered.end(); ++it)
1150  {
1151  int id = it.key();
1152  bool closeimemdiately = it.value();
1153  MythNotificationScreen *screen = nullptr;
1154 
1155  if (m_registrations.contains(id))
1156  {
1157  screen = m_registrations[id];
1158  if (screen != nullptr && !m_suspended.contains(id))
1159  {
1160  // mark the screen for deletion if no timer is set
1161  if (screen->m_duration <= 0 || closeimemdiately)
1162  {
1163  m_deletedScreens.append(screen);
1164  needdelete = true;
1165  }
1166  }
1167  m_registrations.remove(id);
1168  }
1169 
1170  if (m_suspended.contains(id))
1171  {
1172  // screen had been suspended, delete suspended screen
1173  delete screen;
1174  m_suspended.removeAll(id);
1175  }
1176  }
1177  m_unregistered.clear();
1178 
1179  if (needdelete)
1180  {
1181  DeleteAllScreens();
1182  }
1183 }
1184 
1190 {
1191  QList<MythNotificationScreen*>::iterator it = m_screens.begin();
1192  QList<MythNotificationScreen*>::iterator itend = m_screens.end();
1193 
1194 // if (screen->m_id > 0)
1195 // {
1196 // // we want a permanent screen; add it after the existing one
1197 // for (; it != itend; ++it)
1198 // {
1199 // if ((*it)->m_id <= 0 ||
1200 // (*it)->m_id > screen->m_id)
1201 // break; // reached the temporary screens
1202 // }
1203 // // it points to where we want to insert item
1204 // }
1205 // else
1206  {
1207  it = itend;
1208  }
1209  it = m_screens.insert(it, screen);
1210 
1211  return it - m_screens.begin();
1212 }
1213 
1219 {
1220  QList<MythNotificationScreen*>::iterator it = m_screens.begin();
1221  QList<MythNotificationScreen*>::iterator itend = m_screens.end();
1222 
1223  for (; it != itend; ++it)
1224  {
1225  if (*it == screen)
1226  break;
1227  }
1228 
1229  if (it != itend)
1230  {
1231  it = m_screens.erase(it);
1232  }
1233 
1234  return it - m_screens.begin();
1235 }
1236 
1241 {
1242  QList<MythNotificationScreen*>::iterator it = m_screens.begin();
1243  QList<MythNotificationScreen*>::iterator itend = m_screens.end();
1244 
1245  int position = 0;
1246 
1247  for (; it != itend; ++it)
1248  {
1249  if ((*it)->IsVisible())
1250  {
1251  (*it)->AdjustIndex(position++, true);
1252  }
1253  else
1254  {
1255  (*it)->AdjustIndex(position, true);
1256  }
1257  if ((*it)->m_fullscreen)
1258  {
1259  position = 0;
1260  continue;
1261  }
1262  }
1263 }
1264 
1265 void NCPrivate::GetNotificationScreens(QList<MythScreenType*> &_screens)
1266 {
1267  QList<MythScreenType*> list;
1268  QVector<MythScreenType*> screens;
1269 
1270  if (!m_screenStack)
1271  return;
1272 
1274 
1275  QMutexLocker lock(&m_lock);
1276 
1277  m_screenStack->GetScreenList(screens);
1278 
1279  QVector<MythScreenType*>::const_iterator it = screens.begin();
1280  QVector<MythScreenType*>::const_iterator itend = screens.end();
1281 
1282  int position = 0;
1283  for (; it != itend; ++it)
1284  {
1285  MythNotificationScreen *screen =
1286  dynamic_cast<MythNotificationScreen*>(*it);
1287 
1288  if (screen)
1289  {
1290  if ((screen->m_visibility & MythNotification::kPlayback) == 0)
1291  continue;
1292 
1293  MythNotificationScreen *newscreen;
1294 
1295  if (!m_converted.contains(screen))
1296  {
1297  // screen hasn't been created, return it
1298  newscreen = new MythNotificationScreen(nullptr, *screen);
1299  // CreateScreen can never fail, no need to test return value
1300  m_converted[screen] = newscreen;
1301  }
1302  else
1303  {
1304  newscreen = m_converted[screen];
1305  // Copy new content in case it has changed
1306  newscreen->UpdateFrom(*screen);
1307  }
1308  newscreen->SetVisible(true);
1309  newscreen->SetIndex(position++);
1310  if (screen->m_fullscreen)
1311  {
1312  position = 0;
1313  }
1314  list.append(newscreen);
1315  }
1316  else
1317  {
1318  list.append(*it);
1319  }
1320  }
1321  _screens = list;
1322 }
1323 
1325 {
1326  return m_screens.size();
1327 }
1328 
1330 {
1331  return m_notifications.size();
1332 }
1333 
1335 {
1336  QMutexLocker lock(&m_lock);
1337 
1338  if (m_screens.isEmpty())
1339  return false;
1340 
1341  // The top screen is the only currently displayed first, if there's a
1342  // fullscreen notification displayed, it's the last one
1343  MythNotificationScreen *top = m_screens.front();
1344  QList<MythNotificationScreen *>::const_iterator it = m_screens.end() - 1;
1345 
1346  // loop from last to 2nd
1347  for (; it != m_screens.begin(); --it)
1348  {
1349  MythNotificationScreen *s = *it;
1350 
1351  if (s->m_fullscreen)
1352  {
1353  top = s;
1354  break;
1355  }
1356  }
1357 
1358  if (MythDate::current() < top->m_creation.addMSecs(MIN_LIFE))
1359  return false;
1360 
1361  // simulate time-out
1362  top->ProcessTimer();
1363  return true;
1364 }
1365 
1367 
1369 {
1370  return GetNotificationCenter();
1371 }
1372 
1374  : d(new NCPrivate())
1375 {
1376  const bool isGuiThread =
1377  QThread::currentThread() == QCoreApplication::instance()->thread();
1378 
1379  if (!isGuiThread)
1380  {
1381  LOG(VB_GENERAL, LOG_ERR, LOC + "Constructor not called from GUI thread");
1382  }
1383 }
1384 
1386 {
1387  const bool isGuiThread =
1388  QThread::currentThread() == QCoreApplication::instance()->thread();
1389 
1390  if (!isGuiThread)
1391  {
1392  LOG(VB_GENERAL, LOG_ERR, LOC + "Destructor not called from GUI thread");
1393  }
1394 
1395  delete d;
1396  d = nullptr;
1397 }
1398 
1400 {
1401  return d->Queue(notification);
1402 }
1403 
1405 {
1406  const bool isGuiThread =
1407  QThread::currentThread() == QCoreApplication::instance()->thread();
1408 
1409  if (!isGuiThread)
1410  {
1411  LOG(VB_GENERAL, LOG_ERR, LOC + "ProcessQueue not called from GUI thread");
1412  return;
1413  }
1414 
1415  d->ProcessQueue();
1416 }
1417 
1419 {
1420  return d->Register(from);
1421 }
1422 
1423 void MythNotificationCenter::UnRegister(void *from, int id, bool closeimemdiately)
1424 {
1425  d->UnRegister(from, id, closeimemdiately);
1426 }
1427 
1429 {
1430  const MythNotificationScreen *s =
1431  dynamic_cast<const MythNotificationScreen*>(screen);
1432 
1433  if (!s)
1434  return QDateTime();
1435  return s->m_expiry;
1436 }
1437 
1439 {
1440  const MythNotificationScreen *s =
1441  dynamic_cast<const MythNotificationScreen*>(screen);
1442 
1443  if (!s)
1444  return true;;
1445  return s->m_created;
1446 }
1447 
1448 void MythNotificationCenter::GetNotificationScreens(QList<MythScreenType*> &_screens)
1449 {
1450  d->GetNotificationScreens(_screens);
1451 }
1452 
1454 {
1456  dynamic_cast<MythNotificationScreen*>(screen);
1457 
1458  if (!s)
1459  return;
1460 
1461  if (s->m_created)
1462  {
1463  s->doInit();
1464  }
1465 }
1466 
1468 {
1469  return d->DisplayedNotifications();
1470 }
1471 
1473 {
1474  return d->QueuedNotifications();
1475 }
1476 
1478 {
1479  return d->RemoveFirst();
1480 }
1481 
1482 void ShowNotificationError(const QString &msg,
1483  const QString &from,
1484  const QString &detail,
1485  const VNMask visibility,
1486  const MythNotification::Priority priority)
1487 {
1488  ShowNotification(true, msg, from, detail,
1489  QString(), QString(), QString(), -1, -1, false,
1490  visibility, priority);
1491 }
1492 
1493 void ShowNotification(const QString &msg,
1494  const QString &from,
1495  const QString &detail,
1496  const VNMask visibility,
1497  const MythNotification::Priority priority)
1498 {
1499  ShowNotification(false, msg, from, detail,
1500  QString(), QString(), QString(), -1, -1, false,
1501  visibility, priority);
1502 }
1503 
1505  const QString &msg,
1506  const QString &origin,
1507  const QString &detail,
1508  const QString &image,
1509  const QString &extra,
1510  const QString &progress_text, float progress,
1511  int duration,
1512  bool fullscreen,
1513  const VNMask visibility,
1514  const MythNotification::Priority priority,
1515  const QString &style)
1516 {
1518  msg, origin, detail, image, extra, progress_text, progress,
1519  duration, fullscreen, visibility, priority, style);
1520 }
1521 
1522 void ShowNotification(MythNotification::Type type,
1523  const QString &msg,
1524  const QString &origin,
1525  const QString &detail,
1526  const QString &image,
1527  const QString &extra,
1528  const QString &progress_text, float progress,
1529  int duration,
1530  bool fullscreen,
1531  const VNMask visibility,
1532  const MythNotification::Priority priority,
1533  const QString &style)
1534 {
1535  if (!GetNotificationCenter())
1536  return;
1537 
1538  MythNotification *n;
1539  DMAP data;
1540 
1541  data["minm"] = msg;
1542  data["asar"] = origin.isNull() ? QCoreApplication::translate("(Common)",
1543  "MythTV") : origin;
1544  data["asal"] = detail;
1545  data["asfm"] = extra;
1546 
1547  if (type == MythNotification::Error ||
1551  {
1552  n = new MythNotification(type, data);
1553  if (!duration &&
1556  {
1557  // default duration for those type of notifications is 10s
1558  duration = 10;
1559  }
1560  }
1561  else
1562  {
1563  if (!image.isEmpty())
1564  {
1565  if (progress >= 0)
1566  {
1567  n = new MythMediaNotification(type,
1568  image, data,
1569  progress, progress_text);
1570  }
1571  else
1572  {
1573  n = new MythImageNotification(type, image, data);
1574  }
1575  }
1576  else if (progress >= 0)
1577  {
1579  progress, progress_text, data);
1580  }
1581  else
1582  {
1583  n = new MythNotification(type, data);
1584  }
1585  }
1586  n->SetDuration(duration);
1587  n->SetFullScreen(fullscreen);
1588  n->SetPriority(priority);
1589  n->SetVisibility(visibility);
1590  n->SetStyle(style);
1591 
1593  delete n;
1594 }
void AdjustIndex(int by, bool set=false)
MythScreenStack * GetScreenStack() const
void ScreenStackDeleted(void)
int DisplayedNotifications(void) const
Returns number of notifications currently displayed.
QVector< MythScreenType * > m_ToDelete
MythNotificationScreen * CreateScreen(MythNotification *notification, int id=-1)
CreateScreen will create a MythNotificationScreen instance.
MythNotificationScreenStack * m_screenStack
int GetId(void) const
MythNotification::Priority m_priority
void SetVisible(bool visible) override
void SetImage(MythImage *img)
Should not be used unless absolutely necessary since it bypasses the image caching and threaded loade...
void DeleteAllRegistrations(void)
QString GetDescription(void) const
bool keyPressEvent(QKeyEvent *event) override
Key event handler.
MythScreenType * m_topScreen
virtual MythPainter * GetPainter(void)
void UpdateMetaData(const DMAP &data)
Read some DMAP tag to extract title, artist, album and file format.
VERBOSE_PREAMBLE Most true
Definition: verbosedefs.h:91
#define DEFAULT_DURATION
bool TranslateKeyPress(const QString &context, QKeyEvent *e, QStringList &actions, bool allowJumps=true)
Get a list of actions for a keypress in the given context.
void DeleteUnregistered(void)
#define LOC
void ProcessQueue(void)
ProcessQueue will be called by the GUI event handler and will process all queued MythNotifications an...
MythScreenType * GetTopScreen(void) const override
void SetAlpha(int newalpha)
Definition: mythuitype.cpp:946
static void error(const char *str,...)
Definition: vbi.c:41
void SetRedraw(void)
Definition: mythuitype.cpp:318
int Register(void *from)
An application can register in which case it will be assigned a reusable screen, which can be modifie...
void UpdateArtwork(const QImage &image)
Update artwork image.
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:71
unsigned int VNMask
int GetDuration(void) const
Priority
Priority enum A notification can be given a priority.
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
bool IsFullscreen(void) const
int DisplayedNotifications(void) const
Returns number of notifications currently displayed.
void RefreshScreenPosition(int from=0)
Re-position screens on display.
void UnRegister(void *from, int id, bool closeimemdiately=false)
Unregister the client.
void SetSingleShotTimer(int s, bool update=false)
void AdjustYPosition(void)
Update Y position of the screen All children elements will be relocated.
MythScreenStack * GetMainStack()
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
void ScreenDeleted(void)
Remove screen from screens list.
static MythNotificationCenter * GetInstance(void)
returns the MythNotificationCenter singleton
static guint32 * tmp
Definition: goom_core.c:35
QString getHeight(void) const
Definition: mythrect.cpp:353
void SetIndex(int value)
set index, without recalculating coordinates
bool Load(bool allowLoadInBackground=true, bool forceStat=false)
Load the image(s), wraps ImageLoader::LoadImage()
void SetPosition(int x, int y)
Convenience method, calls SetPosition(const MythPoint&) Override that instead to change functionality...
Definition: mythuitype.cpp:541
void UpdateScreen(MythScreenType *screen)
Will call ::doInit() if the screen is a MythNotificationScreen and ::Create() has been called for it ...
static Type Warning
void GetNotificationScreens(QList< MythScreenType * > &screens)
Return the list of notification screens being currently displayed.
QVector< MythScreenType * > m_DrawOrder
void UnRegister(void *from, int id, bool closeimemdiately=false)
Unregister the client.
void DeleteAllScreens(void)
QString GetStyle(void) const
virtual void SetVisible(bool visible)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
void SetStyle(const QString &style)
contains an alternative notification style.
int InsertScreen(MythNotificationScreen *screen)
Insert screen into list of screens.
void SetDeleting(bool deleting)
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
QMap< int, MythNotificationScreen * > m_registrations
#define HGAP
virtual MythScreenType * GetTopScreen(void) const
Priority GetPriority(void) const
void SetPriority(Priority n)
For future use, not implemented at this stage.
void SetFullscreen(bool full)
void ShowNotification(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QDateTime ScreenExpiryTime(const MythScreenType *screen)
Return when the given screen is going to expire will return an invalid QDateTime if screen isn't a My...
static const uint16_t * d
virtual MythRect GetArea(void) const
If the object has a minimum area defined, return it, other wise return the default area.
Definition: mythuitype.cpp:885
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
MythNotificationScreenStack * m_originalScreenStack
void GetScreenList(QVector< MythScreenType * > &screens)
void SetDuration(int duration)
contains a duration during which the notification will be displayed for.
void ProcessQueue(void)
ProcessQueue will be called by the GUI event handler and will process all queued MythNotifications an...
bool ScreenCreated(const MythScreenType *screen)
Return true if ::Create() has been called on screen.
bool IsExitingToMain(void) const
void Reset(void) override
Reset the widget to it's original state, should not reset changes made by the theme.
Definition: mythuitext.cpp:116
void ShowNotificationError(const QString &msg, const QString &from, const QString &detail, const VNMask visibility, const MythNotification::Priority priority)
convenience utility to display error message as notification
void Reset(void) override
Reset the image back to the default defined in the theme.
virtual void SetTextFromMap(const InfoMap &infoMap)
bool Queue(const MythNotification &notification)
Queue a notification Queue() is thread-safe and can be called from anywhere.
int QueuedNotifications(void) const
Returns number of notifications currently queued.
MythEvent * clone(void) const override
QString GetImagePath(void) const
void Init(void) override
Update the various fields of a MythNotificationScreen.
QImage GetImage(void) const
QList< MythNotificationScreen * > m_deletedScreens
virtual void RecalculateDrawOrder(void)
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
bool RemoveFirst(void)
Will remove the oldest notification from the stack return true if a screen was removed; or false if n...
void AdjustAlpha(int mode, int alphachange, int minalpha=0, int maxalpha=255)
Definition: mythuitype.cpp:928
MythMainWindow * GetMythMainWindow(void)
void UpdateFrom(const MythNotificationScreen &s)
Copy metadata from another notification.
float GetProgress(void) const
int Register(void *from)
An application can register in which case it will be assigned a reusable screen, which can be modifie...
void setY(const QString &sY)
Definition: mythrect.cpp:515
bool keyPressEvent(QKeyEvent *) override
Key event handler.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
void GetNotificationScreens(QList< MythScreenType * > &screens)
Return the list of notification screens being currently displayed.
virtual void aboutToHide(void)
QVector< MythScreenType * > m_Children
QMap< int, void * > m_clients
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
virtual MythPoint GetPosition(void) const
Definition: mythuitype.cpp:567
int RemoveScreen(MythNotificationScreen *screen)
Remove screen from list of screens.
void SetFilename(const QString &filename)
Must be followed by a call to Load() to load the image.
QMap< int, bool > m_unregistered
void * GetParent(void) const
VNMask GetVisibility(void) const
bool DisplayState(const QString &name)
void PopScreen(MythScreenType *screen, bool allowFade=true, bool deleteScreen=true) override
QString GetProgressText(void) const
MythNotificationScreen(MythScreenStack *stack, int id=-1)
Wrapper around QPoint allowing us to handle percentage and other relative values for positioning in m...
Definition: mythrect.h:84
void SetFullScreen(bool f)
a notification may request to be displayed in full screen, this request may not be fullfilled should ...
QString getY(void) const
Definition: mythrect.cpp:541
Screen in which all other widgets are contained and rendered.
void Assign(const QImage &img)
Definition: mythimage.cpp:96
QList< MythNotificationScreen * > m_screens
QMap< MythNotificationScreen *, MythNotificationScreen * > m_converted
bool RemoveFirst(void)
Will remove the oldest notification from the stack return true if a screen was removed; or false if n...
bool IsDeleting(void) const
bool GetFullScreen(void) const
static Type Update
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
void UpdatePlayback(float progress, const QString &text)
Update playback position information.
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:155
QList< MythNotification * > m_notifications
QMap< QString, QString > DMAP
MythNotificationCenter * GetNotificationCenter(void)
void SetNotification(MythNotification &notification)
void SetVisibility(VNMask n)
define a bitmask of Visibility
DMAP GetMetaData(void) const
int QueuedNotifications(void) const
Returns number of notifications currently queued.