MythTV  0.27pre
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
mythdialogs.cpp
Go to the documentation of this file.
1 
2 #include <iostream>
3 #include <algorithm>
4 using namespace std;
5 
6 #include <QCoreApplication>
7 #include <QCursor>
8 #include <QDialog>
9 #include <QDir>
10 #include <QLayout>
11 #include <QRegExp>
12 #include <QLabel>
13 #include <QPixmap>
14 #include <QKeyEvent>
15 #include <QFrame>
16 #include <QPaintEvent>
17 #include <QPainter>
18 #include <QProgressBar>
19 
20 #ifdef QWS
21 #include <qwindowsystem_qws.h>
22 #endif
23 
24 #include "uitypes.h"
25 #include "xmlparse.h"
26 #include "mythdialogs.h"
27 #include "lcddevice.h"
28 #include "mythdbcon.h"
29 #include "mythfontproperties.h"
30 #include "mythuihelper.h"
31 #include "mythlogging.h"
32 #include "mythcorecontext.h"
33 
34 #ifdef USING_MINGW
35 #undef LoadImage
36 #endif
37 
42 MythDialog::MythDialog(MythMainWindow *parent, const char *name, bool setsize)
43  : QFrame(parent), rescode(kDialogCodeAccepted)
44 {
45  setObjectName(name);
46  if (!parent)
47  {
48  LOG(VB_GENERAL, LOG_ALERT,
49  "Trying to create a dialog without a parent.");
50  return;
51  }
52 
53  in_loop = false;
54  MythUIHelper *ui = GetMythUI();
55 
58 
59  defaultBigFont = ui->GetBigFont();
62 
63  setFont(defaultMediumFont);
64 
65  if (setsize)
66  {
67  move(0, 0);
68  setFixedSize(QSize(screenwidth, screenheight));
69  GetMythUI()->ThemeWidget(this);
70  }
71 
72  setAutoFillBackground(true);
73 
74  parent->attach(this);
75  m_parent = parent;
76 }
77 
79 {
80  TeardownAll();
81 }
82 
84 {
85  hide();
86  TeardownAll();
88 }
89 
91 {
92  if (m_parent)
93  {
94  m_parent->detach(this);
95  m_parent = NULL;
96  }
97 }
98 
100 {
101 }
102 
104 {
105  return false;
106 }
107 
108 
109 
111 {
112  show();
113 }
114 
116 {
117  if ((r < kDialogCodeRejected) ||
118  ((kDialogCodeAccepted < r) && (r < kDialogCodeListStart)))
119  {
120  LOG(VB_GENERAL, LOG_ALERT,
121  QString("MythDialog::setResult(%1) "
122  "called with invalid DialogCode").arg(r));
123  }
124 
125  rescode = r;
126 }
127 
129 {
130  hide();
131  setResult((DialogCode) r);
132  close();
133 }
134 
136 {
137  if (i < 0)
138  {
139  LOG(VB_GENERAL, LOG_ALERT,
140  QString("MythDialog::AcceptItem(%1) "
141  "called with negative index").arg(i));
142  reject();
143  return;
144  }
145 
146  done((DialogCode)((int)kDialogCodeListStart + (int)i));
147 }
148 
150 {
151  return (int)code - (int)kDialogCodeListStart;
152 }
153 
155 {
156  done(Accepted);
157 }
158 
160 {
161  done(Rejected);
162 }
163 
165 {
166  if (in_loop)
167  {
168  LOG(VB_GENERAL, LOG_ALERT,
169  "MythDialog::exec: Recursive call detected.");
170  return kDialogCodeRejected;
171  }
172 
174 
175  Show();
176 
177  in_loop = true;
178 
179  QEventLoop eventLoop;
180  connect(this, SIGNAL(leaveModality()), &eventLoop, SLOT(quit()));
181  eventLoop.exec();
182 
183  DialogCode res = result();
184 
185  return res;
186 }
187 
189 {
190  if (isHidden())
191  return;
192 
193  // Reimplemented to exit a modal when the dialog is hidden.
194  QWidget::hide();
195  if (in_loop)
196  {
197  in_loop = false;
198  emit leaveModality();
199  }
200 }
201 
202 void MythDialog::keyPressEvent( QKeyEvent *e )
203 {
204  bool handled = false;
205  QStringList actions;
206 
207  handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
208 
209  for (int i = 0; i < actions.size() && !handled; i++)
210  {
211  QString action = actions[i];
212  handled = true;
213 
214  if (action == "ESCAPE")
215  reject();
216  else if (action == "UP" || action == "LEFT")
217  {
218  if (focusWidget() &&
219  (focusWidget()->focusPolicy() == Qt::StrongFocus ||
220  focusWidget()->focusPolicy() == Qt::WheelFocus))
221  {
222  }
223  else
224  focusNextPrevChild(false);
225  }
226  else if (action == "DOWN" || action == "RIGHT")
227  {
228  if (focusWidget() &&
229  (focusWidget()->focusPolicy() == Qt::StrongFocus ||
230  focusWidget()->focusPolicy() == Qt::WheelFocus))
231  {
232  }
233  else
234  focusNextPrevChild(true);
235  }
236  else if (action == "MENU")
237  emit menuButtonPressed();
238  else
239  handled = false;
240  }
241 }
242 
258  : MythDialog(parent, name, false)
259 {
260  float wmult, hmult;
261 
262  GetMythUI()->GetScreenSettings(wmult, hmult);
263 
264  setLineWidth(3);
265  setMidLineWidth(3);
266  setFrameShape(QFrame::Panel);
267  setFrameShadow(QFrame::Raised);
268  setPalette(parent->palette());
269  popupForegroundColor = palette().color(foregroundRole());
270  setFont(parent->font());
271 
272  hpadding = gCoreContext->GetNumSetting("PopupHeightPadding", 120);
273  wpadding = gCoreContext->GetNumSetting("PopupWidthPadding", 80);
274 
275  vbox = new QVBoxLayout(this);
276  vbox->setMargin((int)(10 * hmult));
277 
278  setAutoFillBackground(true);
279  setWindowFlags(Qt::FramelessWindowHint);
280 }
281 
282 MythPopupBox::MythPopupBox(MythMainWindow *parent, bool graphicPopup,
283  QColor popupForeground, QColor popupBackground,
284  QColor popupHighlight, const char *name)
285  : MythDialog(parent, name, false)
286 {
287  float wmult, hmult;
288 
289  GetMythUI()->GetScreenSettings(wmult, hmult);
290 
291  setLineWidth(3);
292  setMidLineWidth(3);
293  setFrameShape(QFrame::Panel);
294  setFrameShadow(QFrame::Raised);
295  setFrameStyle(QFrame::Box | QFrame::Plain);
296  setPalette(parent->palette());
297  setFont(parent->font());
298 
299  hpadding = gCoreContext->GetNumSetting("PopupHeightPadding", 120);
300  wpadding = gCoreContext->GetNumSetting("PopupWidthPadding", 80);
301 
302  vbox = new QVBoxLayout(this);
303  vbox->setMargin((int)(10 * hmult));
304 
305  if (!graphicPopup)
306  {
307  QPalette palette;
308  palette.setColor(backgroundRole(), popupBackground);
309  setPalette(palette);
310  }
311  else
312  GetMythUI()->ThemeWidget(this);
313 
314  QPalette palette;
315  palette.setColor(foregroundRole(), popupHighlight);
316  setPalette(palette);
317 
318  popupForegroundColor = popupForeground;
319  setAutoFillBackground(true);
320  setWindowFlags(Qt::FramelessWindowHint);
321 }
322 
323 
325 {
326  // -=>TODO: Temp fix... should re-evalutate/re-code.
327 
328  QList<QWidget *> objList = qFindChildren<QWidget *>(this);
329 
330  QWidget *pCurr = focusWidget();
331  QWidget *pNew = NULL;
332  int nCurrIdx = -1;
333  int nIdx;
334 
335  for (nIdx = 0; nIdx < objList.size(); ++nIdx )
336  {
337  if (objList[ nIdx ] == pCurr)
338  {
339  nCurrIdx = nIdx;
340  break;
341  }
342  }
343 
344  if (nCurrIdx == -1)
345  return false;
346 
347  nIdx = nCurrIdx;
348 
349  do
350  {
351  if (next)
352  {
353  ++nIdx;
354 
355  if (nIdx == objList.size())
356  nIdx = 0;
357  }
358  else
359  {
360  --nIdx;
361 
362  if (nIdx < 0)
363  nIdx = objList.size() -1;
364  }
365 
366  pNew = objList[ nIdx ];
367 
368  if (pNew && !pNew->focusProxy() && pNew->isVisibleTo( this ) &&
369  pNew->isEnabled() && (pNew->focusPolicy() != Qt::NoFocus))
370  {
371  pNew->setFocus();
372  return true;
373  }
374  }
375  while (nIdx != nCurrIdx);
376 
377  return false;
378 
379 #if 0
380  QFocusData *focusList = focusData();
381  QObjectList *objList = queryList(NULL,NULL,false,true);
382 
383  QWidget *startingPoint = focusList->home();
384  QWidget *candidate = NULL;
385 
386  QWidget *w = (next) ? focusList->prev() : focusList->next();
387 
388  int countdown = focusList->count();
389 
390  do
391  {
392  if (w && w != startingPoint && !w->focusProxy() &&
393  w->isVisibleTo(this) && w->isEnabled() &&
394  (objList->find((QObject *)w) != -1))
395  {
396  candidate = w;
397  }
398 
399  w = (next) ? focusList->prev() : focusList->next();
400  }
401  while (w && !(candidate && w == startingPoint) && (countdown-- > 0));
402 
403  if (!candidate)
404  return false;
405 
406  candidate->setFocus();
407  return true;
408 #endif
409 }
410 
411 void MythPopupBox::addWidget(QWidget *widget, bool setAppearance)
412 {
413  if (setAppearance == true)
414  {
415  widget->setPalette(palette());
416  widget->setFont(font());
417  }
418 
419  if (widget->metaObject()->className() == QString("QLabel"))
420  {
421  QPalette palette;
422  palette.setColor(widget->foregroundRole(), popupForegroundColor);
423  widget->setPalette(palette);
424  }
425 
426  vbox->addWidget(widget);
427 }
428 
429 QLabel *MythPopupBox::addLabel(QString caption, LabelSize size, bool wrap)
430 {
431  QLabel *label = new QLabel(caption, this);
432  switch (size)
433  {
434  case Large: label->setFont(defaultBigFont); break;
435  case Medium: label->setFont(defaultMediumFont); break;
436  case Small: label->setFont(defaultSmallFont); break;
437  }
438 
439  label->setMaximumWidth((int)m_parent->width() / 2);
440  if (wrap)
441  {
442  QChar::Direction text_dir = QChar::DirL;
443  // Get a char from within the string to determine direction.
444  if (caption.length())
445  text_dir = caption[0].direction();
446  Qt::Alignment align = (QChar::DirAL == text_dir) ?
447  Qt::AlignRight : Qt::AlignLeft;
448  label->setAlignment(align);
449  label->setWordWrap(true);
450  }
451 
452  label->setWordWrap(true);
453  addWidget(label, false);
454  return label;
455 }
456 
457 QAbstractButton *MythPopupBox::addButton(QString caption, QObject *target,
458  const char *slot)
459 {
460  if (!target)
461  {
462  target = this;
463  slot = SLOT(defaultButtonPressedHandler());
464  }
465 
466  MythPushButton *button = new MythPushButton(caption, this);
467  m_parent->connect(button, SIGNAL(pressed()), target, slot);
468  addWidget(button, false);
469  return button;
470 }
471 
472 void MythPopupBox::addLayout(QLayout *layout, int stretch)
473 {
474  vbox->addLayout(layout, stretch);
475 }
476 
477 void MythPopupBox::ShowPopup(QObject *target, const char *slot)
478 {
479  ShowPopupAtXY(-1, -1, target, slot);
480 }
481 
482 void MythPopupBox::ShowPopupAtXY(int destx, int desty,
483  QObject *target, const char *slot)
484 {
485  QList< QObject* > objlist = children();
486 
487  for (QList< QObject* >::Iterator it = objlist.begin();
488  it != objlist.end();
489  ++it )
490  {
491  QObject *objs = *it;
492 
493  if (objs->isWidgetType())
494  {
495  QWidget *widget = (QWidget *)objs;
496  widget->adjustSize();
497  }
498  }
499 
500  ensurePolished();
501 
502  int x = 0, y = 0, maxw = 0, poph = 0;
503 
504  for (QList< QObject* >::Iterator it = objlist.begin();
505  it != objlist.end();
506  ++it )
507  {
508  QObject *objs = *it;
509 
510  if (objs->isWidgetType())
511  {
512  QString objname = objs->objectName();
513  if (objname != "nopopsize")
514  {
515  // little extra padding for these guys
516  if (objs->metaObject()->className() ==
517  QString("MythListBox"))
518  {
519  poph += (int)(25 * hmult);
520  }
521 
522  QWidget *widget = (QWidget *)objs;
523  poph += widget->height();
524  if (widget->width() > maxw)
525  maxw = widget->width();
526  }
527  }
528  }
529 
530  poph += (int)(hpadding * hmult);
531  setMinimumHeight(poph);
532 
533  maxw += (int)(wpadding * wmult);
534 
535  int width = (int)(800 * wmult);
536  int height = (int)(600 * hmult);
537 
538  if (parentWidget())
539  {
540  width = parentWidget()->width();
541  height = parentWidget()->height();
542  }
543 
544  if (destx == -1)
545  x = (int)(width / 2) - (int)(maxw / 2);
546  else
547  x = destx;
548 
549  if (desty == -1)
550  y = (int)(height / 2) - (int)(poph / 2);
551  else
552  y = desty;
553 
554  if (poph + y > height)
555  y = height - poph - (int)(8 * hmult);
556 
557  setFixedSize(maxw, poph);
558  setGeometry(x, y, maxw, poph);
559 
560  if (target && slot)
561  connect(this, SIGNAL(popupDone(int)), target, slot);
562 
563  Show();
564 }
565 
566 void MythPopupBox::keyPressEvent(QKeyEvent *e)
567 {
568  bool handled = false;
569  QStringList actions;
570  handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
571 
572  for (int i = 0; i < actions.size() && !handled; i++)
573  {
574  QString action = actions[i];
575 
576  if (action == "ESCAPE")
577  {
578  reject();
579  handled = true;
580  }
581  }
582 
583  if (!handled)
585 }
586 
588 {
590  emit popupDone(rescode);
591 }
592 
594 {
597 }
598 
600 {
603 }
604 
605 DialogCode MythPopupBox::ExecPopup(QObject *target, const char *slot)
606 {
607  if (!target)
608  ShowPopup(this, SLOT(done(int)));
609  else
610  ShowPopup(target, slot);
611 
612  return exec();
613 }
614 
616  QObject *target, const char *slot)
617 {
618  if (!target)
619  ShowPopupAtXY(destx, desty, this, SLOT(done(int)));
620  else
621  ShowPopupAtXY(destx, desty, target, slot);
622 
623  return exec();
624 }
625 
627 {
628  QList< QObject* > objlist = children();
629 
630  int i = 0;
631  bool foundbutton = false;
632 
633  for (QList< QObject* >::Iterator it = objlist.begin();
634  it != objlist.end();
635  ++it )
636  {
637  QObject *objs = *it;
638 
639  if (objs->isWidgetType())
640  {
641  QWidget *widget = (QWidget *)objs;
642  if (widget->metaObject()->className() ==
643  QString("MythPushButton"))
644  {
645  if (widget->hasFocus())
646  {
647  foundbutton = true;
648  break;
649  }
650  i++;
651  }
652  }
653  }
654  if (foundbutton)
655  {
656  AcceptItem(i);
657  return;
658  }
659 
660  // this bit of code should always work but requires a cast
661  i = 0;
662  for (QList< QObject* >::Iterator it = objlist.begin();
663  it != objlist.end();
664  ++it )
665  {
666  QObject *objs = *it;
667 
668  if (objs->isWidgetType())
669  {
670  QWidget *widget = (QWidget *)objs;
671  if (widget->metaObject()->className() ==
672  QString("MythPushButton"))
673  {
674  MythPushButton *button = dynamic_cast<MythPushButton*>(widget);
675  if (button && button->isDown())
676  {
677  foundbutton = true;
678  break;
679  }
680  i++;
681  }
682  }
683  }
684  if (foundbutton)
685  {
686  AcceptItem(i);
687  return;
688  }
689 
690  LOG(VB_GENERAL, LOG_ALERT, "We should never get here!");
692 }
693 
695  MythMainWindow *parent,
696  const QString &title,
697  const QString &message,
698  QString button_msg)
699 {
700  if (button_msg.isEmpty())
701  button_msg = QObject::tr("OK");
702 
703  MythPopupBox *popup = new MythPopupBox(parent, title.toLatin1().constData());
704 
705  popup->addLabel(message, MythPopupBox::Medium, true);
706  QAbstractButton *okButton = popup->addButton(button_msg, popup, SLOT(accept()));
707  okButton->setFocus();
708  bool ret = (kDialogCodeAccepted == popup->ExecPopup());
709 
710  popup->hide();
711  popup->deleteLater();
712 
713  return ret;
714 }
715 
716 bool MythPopupBox::showGetTextPopup(MythMainWindow *parent, QString title,
717  QString message, QString& text)
718 {
719  MythPopupBox *popup = new MythPopupBox(parent, title.toLatin1().constData());
720 
721  popup->addLabel(message, Medium, true);
722 
723  MythRemoteLineEdit *textEdit =
724  new MythRemoteLineEdit(popup, "chooseEdit");
725 
726  textEdit->setText(text);
727  popup->addWidget(textEdit);
728 
729  popup->addButton(tr("OK"), popup, SLOT(accept()));
730  popup->addButton(tr("Cancel"), popup, SLOT(reject()));
731 
732  textEdit->setFocus();
733 
734  bool ok = (Accepted == popup->ExecPopup());
735  if (ok)
736  text = textEdit->text();
737 
738  popup->hide();
739  popup->deleteLater();
740 
741  return ok;
742 }
743 
745  MythMainWindow *parent,
746  const QString &title, const QString &message,
747  const QString &button1msg, const QString &button2msg,
748  DialogCode default_button)
749 {
750  QStringList buttonmsgs;
751  buttonmsgs += (button1msg.isEmpty()) ?
752  QString("Button 1") : button1msg;
753  buttonmsgs += (button2msg.isEmpty()) ?
754  QString("Button 2") : button2msg;
755  return ShowButtonPopup(
756  parent, title, message, buttonmsgs, default_button);
757 }
758 
760  MythMainWindow *parent,
761  const QString &title,
762  const QString &message,
763  const QStringList &buttonmsgs,
764  DialogCode default_button)
765 {
766  MythPopupBox *popup = new MythPopupBox(parent, title.toLatin1().constData());
767 
768  popup->addLabel(message, Medium, true);
769  popup->addLabel("");
770 
771  const int def = CalcItemIndex(default_button);
772  for (int i = 0; i < buttonmsgs.size(); i++ )
773  {
774  QAbstractButton *but = popup->addButton(buttonmsgs[i]);
775  if (def == i)
776  but->setFocus();
777  }
778 
779  DialogCode ret = popup->ExecPopup();
780 
781  popup->hide();
782  popup->deleteLater();
783 
784  return ret;
785 }
786 
788  const QString &message, int totalSteps,
789  bool cancelButton, const QObject *target, const char *slot)
790  : MythDialog(GetMythMainWindow(), "progress", false)
791 {
792  setObjectName("MythProgressDialog");
794  float wmult, hmult;
795 
796  GetMythUI()->GetScreenSettings(screenwidth, wmult, screenheight, hmult);
797 
798  setFont(GetMythUI()->GetMediumFont());
799 
800  GetMythUI()->ThemeWidget(this);
801 
802  int yoff = screenheight / 3;
803  int xoff = screenwidth / 10;
804  setGeometry(xoff, yoff, screenwidth - xoff * 2, yoff);
805  setFixedSize(QSize(screenwidth - xoff * 2, yoff));
806 
807  msglabel = new QLabel();
808  msglabel->setText(message);
809 
810  QVBoxLayout *vlayout = new QVBoxLayout();
811  vlayout->addWidget(msglabel);
812 
813  progress = new QProgressBar();
814  progress->setRange(0, totalSteps);
815 
816  QHBoxLayout *hlayout = new QHBoxLayout();
817  hlayout->addWidget(progress);
818 
819  if (cancelButton && slot && target)
820  {
821  MythPushButton *button = new MythPushButton(
822  QObject::tr("Cancel"), NULL);
823  button->setFocus();
824  hlayout->addWidget(button);
825  connect(button, SIGNAL(pressed()), target, slot);
826  }
827 
828  setTotalSteps(totalSteps);
829 
830  if (LCD *lcddev = LCD::Get())
831  {
832  QList<LCDTextItem> textItems;
833 
834  textItems.append(LCDTextItem(1, ALIGN_CENTERED, message, "Generic",
835  false));
836  lcddev->switchToGeneric(textItems);
837  }
838 
839  hlayout->setSpacing(5);
840 
841  vlayout->setMargin((int)(15 * wmult));
842  vlayout->setStretchFactor(msglabel, 5);
843 
844  QWidget *hbox = new QWidget();
845  hbox->setLayout(hlayout);
846  vlayout->addWidget(hbox);
847 
848  QFrame *vbox = new QFrame(this);
849  vbox->setObjectName(objectName() + "_vbox");
850  vbox->setLineWidth(3);
851  vbox->setMidLineWidth(3);
852  vbox->setFrameShape(QFrame::Panel);
853  vbox->setFrameShadow(QFrame::Raised);
854  vbox->setLayout(vlayout);
855 
856  QVBoxLayout *lay = new QVBoxLayout();
857  lay->addWidget(vbox);
858  setLayout(lay);
859 
860  show();
861 
862  qApp->processEvents();
863 }
864 
866 {
867 }
868 
870 {
871  hide();
873 }
874 
876 {
877  accept();
878 
879  LCD *lcddev = LCD::Get();
880  if (lcddev)
881  {
882  lcddev->switchToNothing();
883  lcddev->switchToTime();
884  }
885 }
886 
887 void MythProgressDialog::setProgress(int curprogress)
888 {
889  progress->setValue(curprogress);
890  if (curprogress % steps == 0)
891  {
892  qApp->processEvents();
893  if (LCD *lcddev = LCD::Get())
894  {
895  float fProgress = (float)curprogress / m_totalSteps;
896  lcddev->setGenericProgress(fProgress);
897  }
898  }
899 }
900 
901 void MythProgressDialog::setLabel(QString newlabel)
902 {
903  msglabel->setText(newlabel);
904 }
905 
907 {
908  bool handled = false;
909  QStringList actions;
910  handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
911 
912  for (int i = 0; i < actions.size() && !handled; i++)
913  {
914  QString action = actions[i];
915  if (action == "ESCAPE")
916  handled = true;
917  }
918 
919  if (!handled)
921 }
922 
924 {
925  m_totalSteps = totalSteps;
926  progress->setRange(0, totalSteps);
927  steps = totalSteps / 1000;
928  if (steps == 0)
929  steps = 1;
930 }
931 
933  const QString &window_name,
934  const QString &theme_filename,
935  const char *name,
936  bool setsize)
937  : MythDialog(parent, name, setsize)
938 {
939  setNoErase();
940 
941  theme = NULL;
942 
943  if (!loadThemedWindow(window_name, theme_filename))
944  {
945  QString msg = tr("Could not locate '%1' in theme '%2'."
946  "\n\nReturning to the previous menu.")
947  .arg(window_name).arg(theme_filename);
949  tr("Missing UI Element"), msg);
950  reject();
951  return;
952  }
953 }
954 
956  MythMainWindow *parent, const char* name, bool setsize) :
957  MythDialog(parent, name, setsize), widget_with_current_focus(NULL),
958  theme(NULL), context(-1)
959 {
960  setNoErase();
961 }
962 
963 bool MythThemedDialog::loadThemedWindow(QString window_name,
964  QString theme_filename)
965 {
966  if (theme)
967  delete theme;
968 
969  context = -1;
970  my_containers.clear();
972 
973  redrawRect = QRect(0, 0, 0, 0);
974 
975  theme = new XMLParse();
976  theme->SetWMult(wmult);
977  theme->SetHMult(hmult);
978  if (!theme->LoadTheme(xmldata, window_name, theme_filename))
979  {
980  return false;
981  }
982 
984 
985  //
986  // Auto-connect signals we know about
987  //
988 
989  // Loop over containers
990  QList<LayerSet*>::iterator an_it = my_containers.begin();
991  for (; an_it != my_containers.end(); ++an_it)
992  {
993  LayerSet *looper = *an_it;
994  // Loop over UITypes within each container
995  vector<UIType *> *all_ui_type_objects = looper->getAllTypes();
996  vector<UIType *>::iterator i = all_ui_type_objects->begin();
997  for (; i != all_ui_type_objects->end(); ++i)
998  {
999  UIType *type = (*i);
1000  connect(type, SIGNAL(requestUpdate()), this,
1001  SLOT(updateForeground()));
1002  connect(type, SIGNAL(requestUpdate(const QRect &)), this,
1003  SLOT(updateForeground(const QRect &)));
1004  connect(type, SIGNAL(requestRegionUpdate(const QRect &)), this,
1005  SLOT(updateForegroundRegion(const QRect &)));
1006  }
1007  }
1008 
1009  buildFocusList();
1010 
1011  updateBackground();
1012  initForeground();
1013 
1014  return true;
1015 }
1016 
1018 {
1019  //
1020  // Build a list of widgets that will take focus
1021  //
1022 
1023  focus_taking_widgets.clear();
1024 
1025 
1026  // Loop over containers
1027  QList<LayerSet*>::iterator another_it = my_containers.begin();
1028  for (; another_it != my_containers.end(); ++another_it)
1029  {
1030  LayerSet *looper = *another_it;
1031  // Loop over UITypes within each container
1032  vector<UIType *> *all_ui_type_objects = looper->getAllTypes();
1033  vector<UIType *>::iterator i = all_ui_type_objects->begin();
1034  for (; i != all_ui_type_objects->end(); ++i)
1035  {
1036  UIType *type = (*i);
1037  if (type->canTakeFocus() && !type->isHidden() &&
1038  (context == -1 || type->GetContext() == -1 ||
1039  context == type->GetContext()))
1040  {
1041  focus_taking_widgets.push_back(type);
1042  }
1043  }
1044  }
1045 
1046  return !focus_taking_widgets.empty();
1047 }
1048 
1050 {
1051  if (theme)
1052  {
1053  delete theme;
1054  theme = NULL;
1055  }
1056 }
1057 
1059 {
1060  if (theme)
1061  {
1062  delete theme;
1063  theme = NULL;
1064  }
1066 }
1067 
1068 void MythThemedDialog::loadWindow(QDomElement &element)
1069 {
1070  //
1071  // Parse all the child elements in the theme
1072  //
1073 
1074  for (QDomNode child = element.firstChild(); !child.isNull();
1075  child = child.nextSibling())
1076  {
1077  QDomElement e = child.toElement();
1078  if (!e.isNull())
1079  {
1080  if (e.tagName() == "font")
1081  {
1082  theme->parseFont(e);
1083  }
1084  else if (e.tagName() == "container")
1085  {
1086  parseContainer(e);
1087  }
1088  else
1089  {
1090  LOG(VB_GENERAL, LOG_ALERT,
1091  QString("MythThemedDialog::loadWindow(): Do not "
1092  "understand DOM Element: '%1'. Ignoring.")
1093  .arg(e.tagName()));
1094  }
1095  }
1096  }
1097 }
1098 
1099 void MythThemedDialog::parseContainer(QDomElement &element)
1100 {
1101  //
1102  // Have the them object parse the containers
1103  // but hold a pointer to each of them so
1104  // that we can iterate over them later
1105  //
1106 
1107  QRect area;
1108  QString name;
1109  int a_context;
1110  theme->parseContainer(element, name, a_context, area);
1111  if (name.length() < 1)
1112  {
1113  LOG(VB_GENERAL, LOG_ALERT,
1114  "Failed to parse a container. Ignoring.");
1115  return;
1116  }
1117 
1118  LayerSet *container_reference = theme->GetSet(name);
1119  my_containers.append(container_reference);
1120 }
1121 
1122 void MythThemedDialog::parseFont(QDomElement &element)
1123 {
1124  //
1125  // this is just here so you can re-implement the virtual
1126  // function and do something special if you like
1127  //
1128 
1129  theme->parseFont(element);
1130 }
1131 
1133 {
1135  updateForeground();
1136 }
1137 
1139 {
1140  //
1141  // Draw the background pixmap once
1142  //
1143 
1144  QPixmap bground(size());
1145  bground.fill(this, 0, 0);
1146 
1147  QPainter tmp(&bground);
1148 
1149  //
1150  // Ask the container holding anything
1151  // to do with the background to draw
1152  // itself on a pixmap
1153  //
1154 
1155  LayerSet *container = theme->GetSet("background");
1156 
1157  //
1158  // *IFF* there is a background, draw it
1159  //
1160  if (container)
1161  {
1162  container->Draw(&tmp, 0, context);
1163  tmp.end();
1164  }
1165 
1166  //
1167  // Copy that pixmap to the permanent one
1168  // and tell Qt about it
1169  //
1170 
1171  my_background = bground;
1172  QPalette palette;
1173  palette.setBrush(backgroundRole(), QBrush(my_background));
1174  setPalette(palette);
1175 }
1176 
1178 {
1179  QRect r = this->geometry();
1180  updateForeground(r);
1181 }
1182 
1183 QString ZeroSizedRect = QString("MythThemedDialog - Something is requesting"
1184 " a screen update of zero size. A widget probably has not done"
1185 " calculateScreeArea(). Will redraw the whole screen (inefficient!).");
1186 
1188 {
1189  QRect rect_to_update = r;
1190  if (r.width() == 0 || r.height() == 0)
1191  {
1192  LOG(VB_GENERAL, LOG_ALERT, ZeroSizedRect);
1193  rect_to_update = this->geometry();
1194  }
1195 
1196  redrawRect = redrawRect.unite(r);
1197 
1198  update(redrawRect);
1199 }
1200 
1202 {
1203  QRect rect_to_update = r;
1204  if (r.width() == 0 || r.height() == 0)
1205  {
1206  LOG(VB_GENERAL, LOG_ALERT, ZeroSizedRect);
1207  rect_to_update = this->geometry();
1208  }
1209 
1210  UpdateForegroundRect(rect_to_update);
1211 
1212  redrawRect = QRect(0, 0, 0, 0);
1213 }
1214 
1216 {
1217  // Note: DrawRegion is never actually called now. Instead
1218  // of controls (only UIListTreeType did it) implementing an
1219  // optimized paint, we rely on clipping regions.
1221 
1222  update(r);
1223 }
1224 
1225 void MythThemedDialog::UpdateForegroundRect(const QRect &inv_rect)
1226 {
1227  QPainter whole_dialog_painter(&my_foreground);
1228 
1229  // Updating the background portion isn't optional. The old
1230  // behavior left remnants during context transitions if
1231  // they happened outside active containers for the current
1232  // context.
1233  whole_dialog_painter.drawPixmap(inv_rect.topLeft(), my_background,
1234  inv_rect);
1235 
1236  QList<LayerSet*>::iterator an_it = my_containers.begin();
1237  for (; an_it != my_containers.end(); ++an_it)
1238  {
1239  LayerSet *looper = *an_it;
1240  QRect container_area = looper->GetAreaRect();
1241 
1242  //
1243  // Only paint if the container's area is valid
1244  // and it intersects with whatever Qt told us
1245  // needed to be repainted
1246  //
1247 
1248  const QRect intersect = inv_rect.intersect(container_area);
1249  int looper_context = looper->GetContext();
1250  if (container_area.isValid() &&
1251  (looper_context == context || looper_context == -1) &&
1252  intersect.isValid() &&
1253  looper->GetName().toLower() != "background")
1254  {
1255  //
1256  // Debugging
1257  //
1258 #if 0
1259  LOG(VB_GENERAL, LOG_DEBUG,
1260  QString("A container called \"%1\" said its "
1261  "area is %2,%3 to %4,%5")
1262  .arg(looper->GetName())
1263  .arg(container_area.left())
1264  .arg(container_area.top())
1265  .arg(container_area.left() + container_area.width())
1266  .arg(container_area.top() + container_area.height()));
1267 #endif
1268 
1269  //
1270  // Loop over the draworder layers
1271 
1272  whole_dialog_painter.save();
1273 
1274  whole_dialog_painter.setClipRect(intersect);
1275  whole_dialog_painter.translate(container_area.left(),
1276  container_area.top());
1277 
1278  for (int i = 0; i <= looper->getLayers(); ++i)
1279  {
1280  looper->Draw(&whole_dialog_painter, i, context);
1281  }
1282 
1283  whole_dialog_painter.restore();
1284  }
1285  }
1286 }
1287 
1288 void MythThemedDialog::paintEvent(QPaintEvent *e)
1289 {
1290  if (redrawRect.width() > 0 && redrawRect.height() > 0)
1292 
1293  { // Make sure QPainter is destructed before calling MythDialog's paint..
1294  QPainter p(this);
1295  p.drawPixmap(e->rect().topLeft(), my_foreground, e->rect());
1296  }
1298 }
1299 
1301 {
1303  {
1305  }
1306 
1307  vector<UIType*>::iterator an_it = focus_taking_widgets.begin();
1308  for (; an_it != focus_taking_widgets.end(); ++an_it)
1309  {
1310  UIType *looper = *an_it;
1311  if (looper->canTakeFocus())
1312  {
1313  widget_with_current_focus = looper;
1315  return true;
1316  }
1317  }
1318 
1319  return false;
1320 }
1321 
1323 {
1324  if (up_or_down)
1325  {
1326  bool reached_current = false;
1327 
1328  vector<UIType*>::iterator an_it = focus_taking_widgets.begin();
1329  for (; an_it != focus_taking_widgets.end(); ++an_it)
1330  {
1331  UIType *looper = *an_it;
1332  if (reached_current && looper->canTakeFocus())
1333  {
1335  widget_with_current_focus = looper;
1337  return true;
1338  }
1339 
1340  if (looper == widget_with_current_focus)
1341  {
1342  reached_current= true;
1343  }
1344  }
1345 
1346  if (assignFirstFocus())
1347  {
1348  return true;
1349  }
1350  return false;
1351  }
1352  else
1353  {
1354  bool reached_current = false;
1355 
1356  vector<UIType*>::reverse_iterator an_it = focus_taking_widgets.rbegin();
1357  for (; an_it != focus_taking_widgets.rend(); ++an_it)
1358  {
1359  UIType *looper = *an_it;
1360 
1361  if (reached_current && looper->canTakeFocus())
1362  {
1364  widget_with_current_focus = looper;
1366  return true;
1367  }
1368 
1369  if (looper == widget_with_current_focus)
1370  {
1371  reached_current= true;
1372  }
1373  }
1374 
1375  if (reached_current)
1376  {
1377  an_it = focus_taking_widgets.rbegin();
1378  for (; an_it != focus_taking_widgets.rend(); ++an_it)
1379  {
1380  UIType *looper = *an_it;
1381 
1382  if (looper->canTakeFocus())
1383  {
1385  widget_with_current_focus = looper;
1387  return true;
1388  }
1389  }
1390  }
1391  return false;
1392  }
1393  return false;
1394 }
1395 
1397 {
1399  {
1401  }
1402  else
1403  {
1404  LOG(VB_GENERAL, LOG_ALERT, "MythThemedDialog::activateCurrent() - "
1405  "there is no current widget!");
1406  }
1407 }
1408 
1409 namespace
1410 {
1411  template <typename T>
1412  T *GetUIType(MythThemedDialog *dialog, const QString &name)
1413  {
1414  UIType *sf = dialog->getUIObject(name);
1415  if (sf)
1416  {
1417  T *ret = dynamic_cast<T *>(sf);
1418  if (ret)
1419  return ret;
1420  }
1421  return 0;
1422  }
1423 };
1424 
1426 {
1427  //
1428  // Try and find the UIType target referenced
1429  // by "name".
1430  //
1431  // At some point, it would be nice to speed
1432  // this up with a map across all instantiated
1433  // UIType objects "owned" by this dialog
1434  //
1435 
1436  QList<LayerSet*>::iterator an_it = my_containers.begin();
1437  for (; an_it != my_containers.end(); ++an_it)
1438  {
1439  UIType *hunter = (*an_it)->GetType(name);
1440  if (hunter)
1441  return hunter;
1442  }
1443 
1444  return NULL;
1445 }
1446 
1448 {
1450  {
1452  }
1453  return NULL;
1454 }
1455 
1457 {
1458  // make sure this widget is in the list of widgets that can take focus
1459  vector<UIType*>::iterator it =
1461  focus_taking_widgets.end(), widget);
1462  if (it == focus_taking_widgets.end())
1463  return;
1464 
1467 
1468  widget_with_current_focus = widget;
1470 }
1471 
1473 {
1474  return GetUIType<UIKeyboardType>(this, name);
1475 }
1476 
1478 {
1479  QList<LayerSet*>::iterator an_it = my_containers.begin();
1480  for (; an_it != my_containers.end(); ++an_it)
1481  {
1482  if ((*an_it)->GetName() == name)
1483  return *an_it;
1484  }
1485 
1486  return NULL;
1487 }
1488 
1490 {
1491  fontProp* font = NULL;
1492  if (theme)
1493  font = theme->GetFont(name, true);
1494 
1495  return font;
1496 }