00001
00002 #include "mythscreentype.h"
00003
00004 #include <QCoreApplication>
00005 #include <QDomDocument>
00006 #include <QRunnable>
00007
00008 #include "mythcorecontext.h"
00009 #include "mythobservable.h"
00010 #include "mthreadpool.h"
00011
00012 #include "mythscreenstack.h"
00013 #include "mythmainwindow.h"
00014 #include "mythuihelper.h"
00015 #include "mythprogressdialog.h"
00016 #include "mythuigroup.h"
00017 #include "mythlogging.h"
00018
00019 QEvent::Type ScreenLoadCompletionEvent::kEventType =
00020 (QEvent::Type) QEvent::registerEventType();
00021
00022 class ScreenLoadTask : public QRunnable
00023 {
00024 public:
00025 ScreenLoadTask(MythScreenType *parent) : m_parent(parent) {}
00026
00027 private:
00028 void run()
00029 {
00030 if (m_parent)
00031 m_parent->LoadInForeground();
00032 }
00033
00034 MythScreenType *m_parent;
00035 };
00036
00037 MythScreenType::MythScreenType(MythScreenStack *parent, const QString &name,
00038 bool fullscreen)
00039 : MythUIType(parent, name)
00040 {
00041 m_FullScreen = fullscreen;
00042 m_CurrentFocusWidget = NULL;
00043
00044 m_ScreenStack = parent;
00045 m_BusyPopup = NULL;
00046 m_IsDeleting = false;
00047 m_IsLoading = false;
00048 m_IsLoaded = false;
00049 m_IsInitialized = false;
00050
00051
00052 m_Area = GetMythMainWindow()->GetUIScreenRect();
00053
00054
00055
00056 }
00057
00058 MythScreenType::MythScreenType(MythUIType *parent, const QString &name,
00059 bool fullscreen)
00060 : MythUIType(parent, name)
00061 {
00062 m_FullScreen = fullscreen;
00063 m_CurrentFocusWidget = NULL;
00064
00065 m_ScreenStack = NULL;
00066 m_BusyPopup = NULL;
00067 m_IsDeleting = false;
00068 m_IsLoading = false;
00069 m_IsLoaded = false;
00070 m_IsInitialized = false;
00071
00072 m_Area = GetMythMainWindow()->GetUIScreenRect();
00073
00074
00075
00076 }
00077
00078 MythScreenType::~MythScreenType()
00079 {
00080
00081
00082
00083 m_CurrentFocusWidget = NULL;
00084 emit Exiting();
00085 }
00086
00087 bool MythScreenType::IsFullscreen(void) const
00088 {
00089 return m_FullScreen;
00090 }
00091
00092 void MythScreenType::SetFullscreen(bool full)
00093 {
00094 m_FullScreen = full;
00095 }
00096
00097 MythUIType *MythScreenType::GetFocusWidget(void) const
00098 {
00099 return m_CurrentFocusWidget;
00100 }
00101
00102 bool MythScreenType::SetFocusWidget(MythUIType *widget)
00103 {
00104 if (!widget || !widget->IsVisible())
00105 {
00106 QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
00107 MythUIType *current;
00108
00109 while (it != m_FocusWidgetList.end())
00110 {
00111 current = *it;
00112
00113 if (current->CanTakeFocus() && current->IsVisible())
00114 {
00115 widget = current;
00116 break;
00117 }
00118 ++it;
00119 }
00120 }
00121
00122 if (!widget)
00123 return false;
00124
00125 MythUIText *helpText = dynamic_cast<MythUIText *>(GetChild("helptext"));
00126 if (helpText)
00127 helpText->Reset();
00128
00129 if (m_CurrentFocusWidget)
00130 m_CurrentFocusWidget->LoseFocus();
00131 m_CurrentFocusWidget = widget;
00132 m_CurrentFocusWidget->TakeFocus();
00133
00134 if (helpText && !widget->GetHelpText().isEmpty())
00135 helpText->SetText(widget->GetHelpText());
00136
00137 return true;
00138 }
00139
00140 bool MythScreenType::NextPrevWidgetFocus(bool up)
00141 {
00142 if (!m_CurrentFocusWidget || m_FocusWidgetList.isEmpty())
00143 return SetFocusWidget(NULL);
00144
00145 bool reachedCurrent = false;
00146 bool looped = false;
00147
00148 QMap<int, MythUIType *>::iterator it = m_FocusWidgetList.begin();
00149 MythUIType *current;
00150
00151
00152
00153 if (up)
00154 {
00155 while (it != m_FocusWidgetList.end())
00156 {
00157 current = *it;
00158
00159 if ((looped || reachedCurrent) &&
00160 current->IsVisible() && current->IsEnabled())
00161 return SetFocusWidget(current);
00162
00163 if (current == m_CurrentFocusWidget)
00164 reachedCurrent = true;
00165
00166 ++it;
00167
00168 if (it == m_FocusWidgetList.end())
00169 {
00170 if (looped)
00171 return false;
00172 else
00173 {
00174 looped = true;
00175 it = m_FocusWidgetList.begin();
00176 }
00177 }
00178 }
00179 }
00180 else
00181 {
00182 it = m_FocusWidgetList.end() - 1;
00183 while (it != m_FocusWidgetList.begin() - 1)
00184 {
00185 current = *it;
00186
00187 if ((looped || reachedCurrent) &&
00188 current->IsVisible() && current->IsEnabled())
00189 return SetFocusWidget(current);
00190
00191 if (current == m_CurrentFocusWidget)
00192 reachedCurrent = true;
00193
00194 --it;
00195
00196 if (it == m_FocusWidgetList.begin() - 1)
00197 {
00198 if (looped)
00199 return false;
00200 else
00201 {
00202 looped = true;
00203 it = m_FocusWidgetList.end() - 1;
00204 }
00205 }
00206 }
00207 }
00208
00209 return false;
00210 }
00211
00212 void MythScreenType::BuildFocusList(void)
00213 {
00214 m_FocusWidgetList.clear();
00215 m_CurrentFocusWidget = NULL;
00216
00217 AddFocusableChildrenToList(m_FocusWidgetList);
00218
00219 if (m_FocusWidgetList.size() > 0)
00220 SetFocusWidget();
00221 }
00222
00223 MythScreenStack *MythScreenType::GetScreenStack(void) const
00224 {
00225 return m_ScreenStack;
00226 }
00227
00228 void MythScreenType::aboutToHide(void)
00229 {
00230 if (!m_FullScreen)
00231 {
00232 if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
00233 {
00234
00235
00236 if (!m_SavedMask.isEmpty())
00237 GetMythMainWindow()->GetPaintWindow()->setMask(m_SavedMask);
00238 }
00239 }
00240
00241 ActivateAnimations(MythUIAnimation::AboutToHide);
00242 }
00243
00244 void MythScreenType::aboutToShow(void)
00245 {
00246 if (!m_FullScreen)
00247 {
00248 if (!GetMythMainWindow()->GetPaintWindow()->mask().isEmpty())
00249 {
00250
00251
00252 QRegion region = GetMythMainWindow()->GetPaintWindow()->mask();
00253 m_SavedMask = region;
00254 region = region.unite(QRegion(m_Area));
00255 GetMythMainWindow()->GetPaintWindow()->setMask(region);
00256 }
00257 }
00258
00259 ActivateAnimations(MythUIAnimation::AboutToShow);
00260 }
00261
00262 bool MythScreenType::IsDeleting(void) const
00263 {
00264 return m_IsDeleting;
00265 }
00266
00267 void MythScreenType::SetDeleting(bool deleting)
00268 {
00269 m_IsDeleting = deleting;
00270 }
00271
00272 bool MythScreenType::Create(void)
00273 {
00274 return true;
00275 }
00276
00287 void MythScreenType::Load(void)
00288 {
00289
00290 }
00291
00292 void MythScreenType::LoadInBackground(QString message)
00293 {
00294 m_IsLoading = true;
00295 m_ScreenStack->AllowReInit();
00296
00297 OpenBusyPopup(message);
00298
00299 ScreenLoadTask *loadTask = new ScreenLoadTask(this);
00300 MThreadPool::globalInstance()->start(loadTask, "ScreenLoad");
00301 }
00302
00303 void MythScreenType::LoadInForeground(void)
00304 {
00305 m_IsLoading = true;
00306 m_ScreenStack->AllowReInit();
00307 Load();
00308 m_IsLoaded = true;
00309 m_IsLoading = false;
00310 }
00311
00312 void MythScreenType::ReloadInBackground(void)
00313 {
00314 m_IsInitialized = false;
00315 LoadInBackground();
00316 }
00317
00318 void MythScreenType::OpenBusyPopup(QString message)
00319 {
00320 if (m_BusyPopup)
00321 return;
00322
00323 QString msg(tr("Loading..."));
00324 if (!message.isEmpty())
00325 msg = message;
00326
00327 MythScreenStack *popupStack =
00328 GetMythMainWindow()->GetStack("popup stack");
00329 m_BusyPopup =
00330 new MythUIBusyDialog(msg, popupStack, "mythscreentypebusydialog");
00331
00332 if (m_BusyPopup->Create())
00333 popupStack->AddScreen(m_BusyPopup, false);
00334 }
00335
00336 void MythScreenType::CloseBusyPopup(void)
00337 {
00338 if (m_BusyPopup)
00339 m_BusyPopup->Close();
00340 m_BusyPopup = NULL;
00341 }
00342
00343 void MythScreenType::SetBusyPopupMessage(const QString &message)
00344 {
00345 if (m_BusyPopup)
00346 m_BusyPopup->SetMessage(message);
00347 }
00348
00349 void MythScreenType::ResetBusyPopup(void)
00350 {
00351 if (m_BusyPopup)
00352 m_BusyPopup->Reset();
00353 }
00354
00358 bool MythScreenType::IsInitialized(void) const
00359 {
00360 return m_IsInitialized;
00361 }
00362
00363 void MythScreenType::doInit(void)
00364 {
00365 CloseBusyPopup();
00366 Init();
00367 m_IsInitialized = true;
00368 }
00369
00377 void MythScreenType::Init(void)
00378 {
00379
00380 }
00381
00382 void MythScreenType::Close(void)
00383 {
00384 CloseBusyPopup();
00385 if (GetScreenStack())
00386 GetScreenStack()->PopScreen(this);
00387 }
00388
00389 void MythScreenType::ShowMenu(void)
00390 {
00391
00392 }
00393
00394 static void DoSetTextFromMap(MythUIType *UItype, QHash<QString, QString> &infoMap)
00395 {
00396 QList<MythUIType *> *children = UItype->GetAllChildren();
00397
00398 MythUIText *textType;
00399
00400 QMutableListIterator<MythUIType *> i(*children);
00401 while (i.hasNext())
00402 {
00403 MythUIType *type = i.next();
00404 if (!type->IsVisible())
00405 continue;
00406
00407 textType = dynamic_cast<MythUIText *> (type);
00408 if (textType && infoMap.contains(textType->objectName()))
00409 textType->SetTextFromMap(infoMap);
00410
00411
00412 MythUIGroup *group = dynamic_cast<MythUIGroup *> (type);
00413 if (group)
00414 DoSetTextFromMap(type, infoMap);
00415 }
00416 }
00417
00418 void MythScreenType::SetTextFromMap(QHash<QString, QString> &infoMap)
00419 {
00420 DoSetTextFromMap((MythUIType*) this, infoMap);
00421 }
00422
00423 static void DoResetMap(MythUIType *UItype, QHash<QString, QString> &infoMap)
00424 {
00425 if (infoMap.isEmpty())
00426 return;
00427
00428 QList<MythUIType *> *children = UItype->GetAllChildren();
00429
00430 MythUIText *textType;
00431 QMutableListIterator<MythUIType *> i(*children);
00432 while (i.hasNext())
00433 {
00434 MythUIType *type = i.next();
00435 if (!type->IsVisible())
00436 continue;
00437
00438 textType = dynamic_cast<MythUIText *> (type);
00439 if (textType && infoMap.contains(textType->objectName()))
00440 textType->Reset();
00441
00442 MythUIGroup *group = dynamic_cast<MythUIGroup *> (type);
00443 if (group)
00444 DoResetMap(type, infoMap);
00445 }
00446 }
00447
00448 void MythScreenType::ResetMap(QHash<QString, QString> &infoMap)
00449 {
00450 DoResetMap(this, infoMap);
00451 }
00452
00453 bool MythScreenType::keyPressEvent(QKeyEvent *event)
00454 {
00455 if (m_CurrentFocusWidget && m_CurrentFocusWidget->keyPressEvent(event))
00456 return true;
00457
00458 bool handled = false;
00459 QStringList actions;
00460 handled = GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
00461
00462 for (int i = 0; i < actions.size() && !handled; i++)
00463 {
00464 QString action = actions[i];
00465 handled = true;
00466
00467 if (action == "LEFT" || action == "UP" || action == "PREVIOUS")
00468 NextPrevWidgetFocus(false);
00469 else if (action == "RIGHT" || action == "DOWN" || action == "NEXT")
00470 NextPrevWidgetFocus(true);
00471 else if (action == "ESCAPE")
00472 Close();
00473 else if (action == "MENU")
00474 ShowMenu();
00475 else if (action.startsWith("SYSEVENT"))
00476 gCoreContext->SendSystemEvent(QString("KEY_%1").arg(action.mid(8)));
00477 else if (action == ACTION_SCREENSHOT)
00478 GetMythMainWindow()->ScreenShot();
00479 else if (action == ACTION_TVPOWERON)
00480 GetMythMainWindow()->HandleTVPower(true);
00481 else if (action == ACTION_TVPOWEROFF)
00482 GetMythMainWindow()->HandleTVPower(false);
00483 else
00484 handled = false;
00485 }
00486
00487 return handled;
00488 }
00489
00490 bool MythScreenType::gestureEvent(MythGestureEvent *event)
00491 {
00492 bool handled = false;
00493 if (event->gesture() == MythGestureEvent::Click)
00494 {
00495 switch (event->GetButton())
00496 {
00497 case MythGestureEvent::RightButton :
00498 ShowMenu();
00499 handled = true;
00500 break;
00501 default :
00502 break;
00503 }
00504
00505 }
00506
00507 if (!handled)
00508 {
00509 MythUIType *clicked = GetChildAt(event->GetPosition());
00510 if (clicked && clicked->IsEnabled())
00511 {
00512 SetFocusWidget(clicked);
00513 if (clicked->gestureEvent(event))
00514 handled = true;
00515 }
00516 }
00517
00518 return handled;
00519 }
00520
00524 bool MythScreenType::ParseElement(
00525 const QString &filename, QDomElement &element, bool showWarnings)
00526 {
00527 if (element.tagName() == "area")
00528 {
00529 MythRect rect = parseRect(element, false);
00530 MythRect rectN = parseRect(element);
00531 QRect screenArea = GetMythMainWindow()->GetUIScreenRect();
00532
00533 if (rect.x() == -1)
00534 rectN.moveLeft((screenArea.width() - rectN.width()) / 2);
00535
00536 if (rect.y() == -1)
00537 rectN.moveTop((screenArea.height() - rectN.height()) / 2);
00538
00539 SetArea(rectN);
00540
00541 if (m_Area.width() < screenArea.width() ||
00542 m_Area.height() < screenArea.height())
00543 {
00544 m_FullScreen = false;
00545 }
00546 else
00547 {
00548 m_FullScreen = true;
00549 }
00550 }
00551 else
00552 {
00553 return MythUIType::ParseElement(filename, element, showWarnings);
00554 }
00555
00556 return true;
00557 }
00558
00562 void MythScreenType::CopyFrom(MythUIType *base)
00563 {
00564 MythScreenType *st = dynamic_cast<MythScreenType *>(base);
00565 if (!st)
00566 {
00567 LOG(VB_GENERAL, LOG_ERR, "ERROR, bad parsing");
00568 return;
00569 }
00570
00571 m_FullScreen = st->m_FullScreen;
00572 m_IsDeleting = false;
00573
00574 MythUIType::CopyFrom(base);
00575
00576 ConnectDependants(true);
00577
00578 BuildFocusList();
00579 };
00580
00587 void MythScreenType::CreateCopy(MythUIType *)
00588 {
00589 LOG(VB_GENERAL, LOG_ERR, "CreateCopy called on screentype - bad.");
00590 }
00591
00592 MythPainter* MythScreenType::GetPainter(void)
00593 {
00594 if (m_Painter)
00595 return m_Painter;
00596 if (m_ScreenStack)
00597 return m_ScreenStack->GetPainter();
00598 return GetMythPainter();
00599 }