MythTV  0.26-pre
mythdialogs.cpp
Go to the documentation of this file.
00001 
00002 #include <iostream>
00003 #include <algorithm>
00004 using namespace std;
00005 
00006 #include <QCoreApplication>
00007 #include <QCursor>
00008 #include <QDialog>
00009 #include <QDir>
00010 #include <QLayout>
00011 #include <QRegExp>
00012 #include <QLabel>
00013 #include <QPixmap>
00014 #include <QKeyEvent>
00015 #include <QFrame>
00016 #include <QPaintEvent>
00017 #include <QPainter>
00018 #include <QProgressBar>
00019 
00020 #ifdef QWS
00021 #include <qwindowsystem_qws.h>
00022 #endif
00023 
00024 #include "uitypes.h"
00025 #include "xmlparse.h"
00026 #include "mythdialogs.h"
00027 #include "lcddevice.h"
00028 #include "mythdbcon.h"
00029 #include "mythfontproperties.h"
00030 #include "mythuihelper.h"
00031 #include "mythlogging.h"
00032 #include "mythcorecontext.h"
00033 
00034 #ifdef USING_MINGW
00035 #undef LoadImage
00036 #endif
00037 
00042 MythDialog::MythDialog(MythMainWindow *parent, const char *name, bool setsize)
00043     : QFrame(parent), rescode(kDialogCodeAccepted)
00044 {
00045     setObjectName(name);
00046     if (!parent)
00047     {
00048         LOG(VB_GENERAL, LOG_ALERT,
00049                  "Trying to create a dialog without a parent.");
00050         return;
00051     }
00052 
00053     in_loop = false;
00054     MythUIHelper *ui = GetMythUI();
00055 
00056     ui->GetScreenSettings(xbase, screenwidth, wmult,
00057                           ybase, screenheight, hmult);
00058 
00059     defaultBigFont = ui->GetBigFont();
00060     defaultMediumFont = ui->GetMediumFont();
00061     defaultSmallFont = ui->GetSmallFont();
00062 
00063     setFont(defaultMediumFont);
00064 
00065     if (setsize)
00066     {
00067         move(0, 0);
00068         setFixedSize(QSize(screenwidth, screenheight));
00069         GetMythUI()->ThemeWidget(this);
00070     }
00071 
00072     setAutoFillBackground(true);
00073 
00074     parent->attach(this);
00075     m_parent = parent;
00076 }
00077 
00078 MythDialog::~MythDialog()
00079 {
00080     TeardownAll();
00081 }
00082 
00083 void MythDialog::deleteLater(void)
00084 {
00085     hide();
00086     TeardownAll();
00087     QFrame::deleteLater();
00088 }
00089 
00090 void MythDialog::TeardownAll(void)
00091 {
00092     if (m_parent)
00093     {
00094         m_parent->detach(this);
00095         m_parent = NULL;
00096     }
00097 }
00098 
00099 void MythDialog::setNoErase(void)
00100 {
00101 }
00102 
00103 bool MythDialog::onMediaEvent(MythMediaDevice*)
00104 {
00105     return false;
00106 }
00107 
00108 
00109 
00110 void MythDialog::Show(void)
00111 {
00112     show();
00113 }
00114 
00115 void MythDialog::setResult(DialogCode r)
00116 {
00117     if ((r < kDialogCodeRejected) ||
00118         ((kDialogCodeAccepted < r) && (r < kDialogCodeListStart)))
00119     {
00120         LOG(VB_GENERAL, LOG_ALERT,
00121                  QString("MythDialog::setResult(%1) "
00122                          "called with invalid DialogCode").arg(r));
00123     }
00124 
00125     rescode = r;
00126 }
00127 
00128 void MythDialog::done(int r)
00129 {
00130     hide();
00131     setResult((DialogCode) r);
00132     close();
00133 }
00134 
00135 void MythDialog::AcceptItem(int i)
00136 {
00137     if (i < 0)
00138     {
00139         LOG(VB_GENERAL, LOG_ALERT,
00140                  QString("MythDialog::AcceptItem(%1) "
00141                          "called with negative index").arg(i));
00142         reject();
00143         return;
00144     }
00145 
00146     done((DialogCode)((int)kDialogCodeListStart + (int)i));
00147 }
00148 
00149 int MythDialog::CalcItemIndex(DialogCode code)
00150 {
00151     return (int)code - (int)kDialogCodeListStart;
00152 }
00153 
00154 void MythDialog::accept()
00155 {
00156     done(Accepted);
00157 }
00158 
00159 void MythDialog::reject()
00160 {
00161     done(Rejected);
00162 }
00163 
00164 DialogCode MythDialog::exec(void)
00165 {
00166     if (in_loop)
00167     {
00168         LOG(VB_GENERAL, LOG_ALERT,
00169                  "MythDialog::exec: Recursive call detected.");
00170         return kDialogCodeRejected;
00171     }
00172 
00173     setResult(kDialogCodeRejected);
00174 
00175     Show();
00176 
00177     in_loop = true;
00178 
00179     QEventLoop eventLoop;
00180     connect(this, SIGNAL(leaveModality()), &eventLoop, SLOT(quit()));
00181     eventLoop.exec();
00182 
00183     DialogCode res = result();
00184 
00185     return res;
00186 }
00187 
00188 void MythDialog::hide(void)
00189 {
00190     if (isHidden())
00191         return;
00192 
00193     // Reimplemented to exit a modal when the dialog is hidden.
00194     QWidget::hide();
00195     if (in_loop)
00196     {
00197         in_loop = false;
00198         emit leaveModality();
00199     }
00200 }
00201 
00202 void MythDialog::keyPressEvent( QKeyEvent *e )
00203 {
00204     bool handled = false;
00205     QStringList actions;
00206 
00207     handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
00208 
00209     for (int i = 0; i < actions.size() && !handled; i++)
00210     {
00211         QString action = actions[i];
00212         handled = true;
00213 
00214         if (action == "ESCAPE")
00215             reject();
00216         else if (action == "UP" || action == "LEFT")
00217         {
00218             if (focusWidget() &&
00219                 (focusWidget()->focusPolicy() == Qt::StrongFocus ||
00220                     focusWidget()->focusPolicy() == Qt::WheelFocus))
00221             {
00222             }
00223             else
00224                 focusNextPrevChild(false);
00225         }
00226         else if (action == "DOWN" || action == "RIGHT")
00227         {
00228             if (focusWidget() &&
00229                 (focusWidget()->focusPolicy() == Qt::StrongFocus ||
00230                     focusWidget()->focusPolicy() == Qt::WheelFocus))
00231             {
00232             }
00233             else
00234                 focusNextPrevChild(true);
00235         }
00236         else if (action == "MENU")
00237             emit menuButtonPressed();
00238         else
00239             handled = false;
00240     }
00241 }
00242 
00257 MythPopupBox::MythPopupBox(MythMainWindow *parent, const char *name)
00258             : MythDialog(parent, name, false)
00259 {
00260     float wmult, hmult;
00261 
00262     GetMythUI()->GetScreenSettings(wmult, hmult);
00263 
00264     setLineWidth(3);
00265     setMidLineWidth(3);
00266     setFrameShape(QFrame::Panel);
00267     setFrameShadow(QFrame::Raised);
00268     setPalette(parent->palette());
00269     popupForegroundColor = palette().color(foregroundRole());
00270     setFont(parent->font());
00271 
00272     hpadding = gCoreContext->GetNumSetting("PopupHeightPadding", 120);
00273     wpadding = gCoreContext->GetNumSetting("PopupWidthPadding", 80);
00274 
00275     vbox = new QVBoxLayout(this);
00276     vbox->setMargin((int)(10 * hmult));
00277 
00278     setAutoFillBackground(true);
00279     setWindowFlags(Qt::FramelessWindowHint);
00280 }
00281 
00282 MythPopupBox::MythPopupBox(MythMainWindow *parent, bool graphicPopup,
00283                            QColor popupForeground, QColor popupBackground,
00284                            QColor popupHighlight, const char *name)
00285             : MythDialog(parent, name, false)
00286 {
00287     float wmult, hmult;
00288 
00289     GetMythUI()->GetScreenSettings(wmult, hmult);
00290 
00291     setLineWidth(3);
00292     setMidLineWidth(3);
00293     setFrameShape(QFrame::Panel);
00294     setFrameShadow(QFrame::Raised);
00295     setFrameStyle(QFrame::Box | QFrame::Plain);
00296     setPalette(parent->palette());
00297     setFont(parent->font());
00298 
00299     hpadding = gCoreContext->GetNumSetting("PopupHeightPadding", 120);
00300     wpadding = gCoreContext->GetNumSetting("PopupWidthPadding", 80);
00301 
00302     vbox = new QVBoxLayout(this);
00303     vbox->setMargin((int)(10 * hmult));
00304 
00305     if (!graphicPopup)
00306     {
00307         QPalette palette;
00308         palette.setColor(backgroundRole(), popupBackground);
00309         setPalette(palette);
00310     }
00311     else
00312         GetMythUI()->ThemeWidget(this);
00313 
00314     QPalette palette;
00315     palette.setColor(foregroundRole(), popupHighlight);
00316     setPalette(palette);
00317 
00318     popupForegroundColor = popupForeground;
00319     setAutoFillBackground(true);
00320     setWindowFlags(Qt::FramelessWindowHint);
00321 }
00322 
00323 
00324 bool MythPopupBox::focusNextPrevChild(bool next)
00325 {
00326     // -=>TODO: Temp fix... should re-evalutate/re-code.
00327 
00328     QList<QWidget *> objList = qFindChildren<QWidget *>(this);
00329 
00330     QWidget *pCurr    = focusWidget();
00331     QWidget *pNew     = NULL;
00332     int      nCurrIdx = -1;
00333     int      nIdx;
00334 
00335     for (nIdx = 0; nIdx < objList.size(); ++nIdx )
00336     {
00337         if (objList[ nIdx ] == pCurr)
00338         {
00339             nCurrIdx = nIdx;
00340             break;
00341         }
00342     }
00343 
00344     if (nCurrIdx == -1)
00345         return false;
00346 
00347     nIdx = nCurrIdx;
00348 
00349     do
00350     {
00351         if (next)
00352         {
00353             ++nIdx;
00354 
00355             if (nIdx == objList.size())
00356                 nIdx = 0;
00357         }
00358         else
00359         {
00360             --nIdx;
00361 
00362             if (nIdx < 0)
00363                 nIdx = objList.size() -1;
00364         }
00365 
00366         pNew = objList[ nIdx ];
00367 
00368         if (pNew && !pNew->focusProxy() && pNew->isVisibleTo( this ) &&
00369             pNew->isEnabled() && (pNew->focusPolicy() != Qt::NoFocus))
00370         {
00371             pNew->setFocus();
00372             return true;
00373         }
00374     }
00375     while (nIdx != nCurrIdx);
00376 
00377     return false;
00378 
00379 #if 0
00380     QFocusData *focusList = focusData();
00381     QObjectList *objList = queryList(NULL,NULL,false,true);
00382 
00383     QWidget *startingPoint = focusList->home();
00384     QWidget *candidate = NULL;
00385 
00386     QWidget *w = (next) ? focusList->prev() : focusList->next();
00387 
00388     int countdown = focusList->count();
00389 
00390     do
00391     {
00392         if (w && w != startingPoint && !w->focusProxy() &&
00393             w->isVisibleTo(this) && w->isEnabled() &&
00394             (objList->find((QObject *)w) != -1))
00395         {
00396             candidate = w;
00397         }
00398 
00399         w = (next) ? focusList->prev() : focusList->next();
00400     }
00401     while (w && !(candidate && w == startingPoint) && (countdown-- > 0));
00402 
00403     if (!candidate)
00404         return false;
00405 
00406     candidate->setFocus();
00407     return true;
00408 #endif
00409 }
00410 
00411 void MythPopupBox::addWidget(QWidget *widget, bool setAppearance)
00412 {
00413     if (setAppearance == true)
00414     {
00415          widget->setPalette(palette());
00416          widget->setFont(font());
00417     }
00418 
00419     if (widget->metaObject()->className() == QString("QLabel"))
00420     {
00421         QPalette palette;
00422         palette.setColor(widget->foregroundRole(), popupForegroundColor);
00423         widget->setPalette(palette);
00424     }
00425 
00426     vbox->addWidget(widget);
00427 }
00428 
00429 QLabel *MythPopupBox::addLabel(QString caption, LabelSize size, bool wrap)
00430 {
00431     QLabel *label = new QLabel(caption, this);
00432     switch (size)
00433     {
00434         case Large: label->setFont(defaultBigFont); break;
00435         case Medium: label->setFont(defaultMediumFont); break;
00436         case Small: label->setFont(defaultSmallFont); break;
00437     }
00438 
00439     label->setMaximumWidth((int)m_parent->width() / 2);
00440     if (wrap)
00441     {
00442         QChar::Direction text_dir = QChar::DirL;
00443         // Get a char from within the string to determine direction.
00444         if (caption.length())
00445             text_dir = caption[0].direction();
00446         Qt::Alignment align = (QChar::DirAL == text_dir) ?
00447             Qt::AlignRight : Qt::AlignLeft;
00448         label->setAlignment(align);
00449         label->setWordWrap(true);
00450     }
00451 
00452     label->setWordWrap(true);
00453     addWidget(label, false);
00454     return label;
00455 }
00456 
00457 QAbstractButton *MythPopupBox::addButton(QString caption, QObject *target,
00458                                  const char *slot)
00459 {
00460     if (!target)
00461     {
00462         target = this;
00463         slot = SLOT(defaultButtonPressedHandler());
00464     }
00465 
00466     MythPushButton *button = new MythPushButton(caption, this);
00467     m_parent->connect(button, SIGNAL(pressed()), target, slot);
00468     addWidget(button, false);
00469     return button;
00470 }
00471 
00472 void MythPopupBox::addLayout(QLayout *layout, int stretch)
00473 {
00474     vbox->addLayout(layout, stretch);
00475 }
00476 
00477 void MythPopupBox::ShowPopup(QObject *target, const char *slot)
00478 {
00479     ShowPopupAtXY(-1, -1, target, slot);
00480 }
00481 
00482 void MythPopupBox::ShowPopupAtXY(int destx, int desty,
00483                                  QObject *target, const char *slot)
00484 {
00485     QList< QObject* > objlist = children();
00486 
00487     for (QList< QObject* >::Iterator it  = objlist.begin();
00488                                      it != objlist.end();
00489                                    ++it )
00490     {
00491         QObject *objs = *it;
00492 
00493         if (objs->isWidgetType())
00494         {
00495             QWidget *widget = (QWidget *)objs;
00496             widget->adjustSize();
00497         }
00498     }
00499 
00500     ensurePolished();
00501 
00502     int x = 0, y = 0, maxw = 0, poph = 0;
00503 
00504     for (QList< QObject* >::Iterator it  = objlist.begin();
00505                                      it != objlist.end();
00506                                    ++it )
00507     {
00508         QObject *objs = *it;
00509 
00510         if (objs->isWidgetType())
00511         {
00512             QString objname = objs->objectName();
00513             if (objname != "nopopsize")
00514             {
00515                 // little extra padding for these guys
00516                 if (objs->metaObject()->className() ==
00517                     QString("MythListBox"))
00518                 {
00519                     poph += (int)(25 * hmult);
00520                 }
00521 
00522                 QWidget *widget = (QWidget *)objs;
00523                 poph += widget->height();
00524                 if (widget->width() > maxw)
00525                     maxw = widget->width();
00526             }
00527         }
00528     }
00529 
00530     poph += (int)(hpadding * hmult);
00531     setMinimumHeight(poph);
00532 
00533     maxw += (int)(wpadding * wmult);
00534 
00535     int width = (int)(800 * wmult);
00536     int height = (int)(600 * hmult);
00537 
00538     if (parentWidget())
00539     {
00540         width = parentWidget()->width();
00541         height = parentWidget()->height();
00542     }
00543 
00544     if (destx == -1)
00545         x = (int)(width / 2) - (int)(maxw / 2);
00546     else
00547         x = destx;
00548 
00549     if (desty == -1)
00550         y = (int)(height / 2) - (int)(poph / 2);
00551     else
00552         y = desty;
00553 
00554     if (poph + y > height)
00555         y = height - poph - (int)(8 * hmult);
00556 
00557     setFixedSize(maxw, poph);
00558     setGeometry(x, y, maxw, poph);
00559 
00560     if (target && slot)
00561         connect(this, SIGNAL(popupDone(int)), target, slot);
00562 
00563     Show();
00564 }
00565 
00566 void MythPopupBox::keyPressEvent(QKeyEvent *e)
00567 {
00568     bool handled = false;
00569     QStringList actions;
00570     handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
00571 
00572     for (int i = 0; i < actions.size() && !handled; i++)
00573     {
00574         QString action = actions[i];
00575 
00576         if (action == "ESCAPE")
00577         {
00578             reject();
00579             handled = true;
00580         }
00581     }
00582 
00583     if (!handled)
00584         MythDialog::keyPressEvent(e);
00585 }
00586 
00587 void MythPopupBox::AcceptItem(int i)
00588 {
00589     MythDialog::AcceptItem(i);
00590     emit popupDone(rescode);
00591 }
00592 
00593 void MythPopupBox::accept(void)
00594 {
00595     MythDialog::done(MythDialog::Accepted);
00596     emit popupDone(MythDialog::Accepted);
00597 }
00598 
00599 void MythPopupBox::reject(void)
00600 {
00601     MythDialog::done(MythDialog::Rejected);
00602     emit popupDone(MythDialog::Rejected);
00603 }
00604 
00605 DialogCode MythPopupBox::ExecPopup(QObject *target, const char *slot)
00606 {
00607     if (!target)
00608         ShowPopup(this, SLOT(done(int)));
00609     else
00610         ShowPopup(target, slot);
00611 
00612     return exec();
00613 }
00614 
00615 DialogCode MythPopupBox::ExecPopupAtXY(int destx, int desty,
00616                                        QObject *target, const char *slot)
00617 {
00618     if (!target)
00619         ShowPopupAtXY(destx, desty, this, SLOT(done(int)));
00620     else
00621         ShowPopupAtXY(destx, desty, target, slot);
00622 
00623     return exec();
00624 }
00625 
00626 void MythPopupBox::defaultButtonPressedHandler(void)
00627 {
00628     QList< QObject* > objlist = children();
00629 
00630     int i = 0;
00631     bool foundbutton = false;
00632 
00633     for (QList< QObject* >::Iterator it  = objlist.begin();
00634                                      it != objlist.end();
00635                                    ++it )
00636     {
00637         QObject *objs = *it;
00638 
00639         if (objs->isWidgetType())
00640         {
00641             QWidget *widget = (QWidget *)objs;
00642             if (widget->metaObject()->className() ==
00643                 QString("MythPushButton"))
00644             {
00645                 if (widget->hasFocus())
00646                 {
00647                     foundbutton = true;
00648                     break;
00649                 }
00650                 i++;
00651             }
00652         }
00653     }
00654     if (foundbutton)
00655     {
00656         AcceptItem(i);
00657         return;
00658     }
00659 
00660     // this bit of code should always work but requires a cast
00661     i = 0;
00662     for (QList< QObject* >::Iterator it  = objlist.begin();
00663                                      it != objlist.end();
00664                                    ++it )
00665     {
00666         QObject *objs = *it;
00667 
00668         if (objs->isWidgetType())
00669         {
00670             QWidget *widget = (QWidget *)objs;
00671             if (widget->metaObject()->className() ==
00672                 QString("MythPushButton"))
00673             {
00674                 MythPushButton *button = dynamic_cast<MythPushButton*>(widget);
00675                 if (button && button->isDown())
00676                 {
00677                     foundbutton = true;
00678                     break;
00679                 }
00680                 i++;
00681             }
00682         }
00683     }
00684     if (foundbutton)
00685     {
00686         AcceptItem(i);
00687         return;
00688     }
00689 
00690     LOG(VB_GENERAL, LOG_ALERT, "We should never get here!");
00691     done(kDialogCodeRejected);
00692 }
00693 
00694 bool MythPopupBox::showOkPopup(
00695     MythMainWindow *parent,
00696     const QString  &title,
00697     const QString  &message,
00698     QString         button_msg)
00699 {
00700     if (button_msg.isEmpty())
00701         button_msg = QObject::tr("OK");
00702 
00703     MythPopupBox *popup = new MythPopupBox(parent, title.toAscii().constData());
00704 
00705     popup->addLabel(message, MythPopupBox::Medium, true);
00706     QAbstractButton *okButton = popup->addButton(button_msg, popup, SLOT(accept()));
00707     okButton->setFocus();
00708     bool ret = (kDialogCodeAccepted == popup->ExecPopup());
00709 
00710     popup->hide();
00711     popup->deleteLater();
00712 
00713     return ret;
00714 }
00715 
00716 bool MythPopupBox::showGetTextPopup(MythMainWindow *parent, QString title,
00717                                     QString message, QString& text)
00718 {
00719     MythPopupBox *popup = new MythPopupBox(parent, title.toAscii().constData());
00720 
00721     popup->addLabel(message, Medium, true);
00722 
00723     MythRemoteLineEdit *textEdit =
00724         new MythRemoteLineEdit(popup, "chooseEdit");
00725 
00726     textEdit->setText(text);
00727     popup->addWidget(textEdit);
00728 
00729     popup->addButton(tr("OK"),     popup, SLOT(accept()));
00730     popup->addButton(tr("Cancel"), popup, SLOT(reject()));
00731 
00732     textEdit->setFocus();
00733 
00734     bool ok = (Accepted == popup->ExecPopup());
00735     if (ok)
00736         text = textEdit->text();
00737 
00738     popup->hide();
00739     popup->deleteLater();
00740 
00741     return ok;
00742 }
00743 
00744 DialogCode MythPopupBox::Show2ButtonPopup(
00745     MythMainWindow *parent,
00746     const QString &title, const QString &message,
00747     const QString &button1msg, const QString &button2msg,
00748     DialogCode default_button)
00749 {
00750     QStringList buttonmsgs;
00751     buttonmsgs += (button1msg.isEmpty()) ?
00752         QString("Button 1") : button1msg;
00753     buttonmsgs += (button2msg.isEmpty()) ?
00754         QString("Button 2") : button2msg;
00755     return ShowButtonPopup(
00756         parent, title, message, buttonmsgs, default_button);
00757 }
00758 
00759 DialogCode MythPopupBox::ShowButtonPopup(
00760     MythMainWindow    *parent,
00761     const QString     &title,
00762     const QString     &message,
00763     const QStringList &buttonmsgs,
00764     DialogCode         default_button)
00765 {
00766     MythPopupBox *popup = new MythPopupBox(parent, title.toAscii().constData());
00767 
00768     popup->addLabel(message, Medium, true);
00769     popup->addLabel("");
00770 
00771     const int def = CalcItemIndex(default_button);
00772     for (int i = 0; i < buttonmsgs.size(); i++ )
00773     {
00774         QAbstractButton *but = popup->addButton(buttonmsgs[i]);
00775         if (def == i)
00776             but->setFocus();
00777     }
00778 
00779     DialogCode ret = popup->ExecPopup();
00780 
00781     popup->hide();
00782     popup->deleteLater();
00783 
00784     return ret;
00785 }
00786 
00787 MythProgressDialog::MythProgressDialog(
00788     const QString &message, int totalSteps,
00789     bool cancelButton, const QObject *target, const char *slot)
00790     : MythDialog(GetMythMainWindow(), "progress", false)
00791 {
00792     setObjectName("MythProgressDialog");
00793     int screenwidth, screenheight;
00794     float wmult, hmult;
00795 
00796     GetMythUI()->GetScreenSettings(screenwidth, wmult, screenheight, hmult);
00797 
00798     setFont(GetMythUI()->GetMediumFont());
00799 
00800     GetMythUI()->ThemeWidget(this);
00801 
00802     int yoff = screenheight / 3;
00803     int xoff = screenwidth / 10;
00804     setGeometry(xoff, yoff, screenwidth - xoff * 2, yoff);
00805     setFixedSize(QSize(screenwidth - xoff * 2, yoff));
00806 
00807     msglabel = new QLabel();
00808     msglabel->setText(message);
00809 
00810     QVBoxLayout *vlayout = new QVBoxLayout();
00811     vlayout->addWidget(msglabel);
00812 
00813     progress = new QProgressBar();
00814     progress->setRange(0, totalSteps);
00815 
00816     QHBoxLayout *hlayout = new QHBoxLayout();
00817     hlayout->addWidget(progress);
00818 
00819     if (cancelButton && slot && target)
00820     {
00821         MythPushButton *button = new MythPushButton(
00822             QObject::tr("Cancel"), NULL);
00823         button->setFocus();
00824         hlayout->addWidget(button);
00825         connect(button, SIGNAL(pressed()), target, slot);
00826     }
00827 
00828     setTotalSteps(totalSteps);
00829 
00830     if (LCD *lcddev = LCD::Get())
00831     {
00832         QList<LCDTextItem> textItems;
00833 
00834         textItems.append(LCDTextItem(1, ALIGN_CENTERED, message, "Generic",
00835                                      false));
00836         lcddev->switchToGeneric(textItems);
00837     }
00838 
00839     hlayout->setSpacing(5);
00840 
00841     vlayout->setMargin((int)(15 * wmult));
00842     vlayout->setStretchFactor(msglabel, 5);
00843 
00844     QWidget *hbox = new QWidget();
00845     hbox->setLayout(hlayout);
00846     vlayout->addWidget(hbox);
00847 
00848     QFrame *vbox = new QFrame(this);
00849     vbox->setObjectName(objectName() + "_vbox");
00850     vbox->setLineWidth(3);
00851     vbox->setMidLineWidth(3);
00852     vbox->setFrameShape(QFrame::Panel);
00853     vbox->setFrameShadow(QFrame::Raised);
00854     vbox->setLayout(vlayout);
00855 
00856     QVBoxLayout *lay = new QVBoxLayout();
00857     lay->addWidget(vbox);
00858     setLayout(lay);
00859 
00860     show();
00861 
00862     qApp->processEvents();
00863 }
00864 
00865 MythProgressDialog::~MythProgressDialog()
00866 {
00867 }
00868 
00869 void MythProgressDialog::deleteLater(void)
00870 {
00871     hide();
00872     MythDialog::deleteLater();
00873 }
00874 
00875 void MythProgressDialog::Close(void)
00876 {
00877     accept();
00878 
00879     LCD *lcddev = LCD::Get();
00880     if (lcddev)
00881     {
00882         lcddev->switchToNothing();
00883         lcddev->switchToTime();
00884     }
00885 }
00886 
00887 void MythProgressDialog::setProgress(int curprogress)
00888 {
00889     progress->setValue(curprogress);
00890     if (curprogress % steps == 0)
00891     {
00892         qApp->processEvents();
00893         if (LCD *lcddev = LCD::Get())
00894         {
00895             float fProgress = (float)curprogress / m_totalSteps;
00896             lcddev->setGenericProgress(fProgress);
00897         }
00898     }
00899 }
00900 
00901 void MythProgressDialog::setLabel(QString newlabel)
00902 {
00903     msglabel->setText(newlabel);
00904 }
00905 
00906 void MythProgressDialog::keyPressEvent(QKeyEvent *e)
00907 {
00908     bool handled = false;
00909     QStringList actions;
00910     handled = GetMythMainWindow()->TranslateKeyPress("qt", e, actions);
00911 
00912     for (int i = 0; i < actions.size() && !handled; i++)
00913     {
00914         QString action = actions[i];
00915         if (action == "ESCAPE")
00916             handled = true;
00917     }
00918 
00919     if (!handled)
00920         MythDialog::keyPressEvent(e);
00921 }
00922 
00923 void MythProgressDialog::setTotalSteps(int totalSteps)
00924 {
00925     m_totalSteps = totalSteps;
00926     progress->setRange(0, totalSteps);
00927     steps = totalSteps / 1000;
00928     if (steps == 0)
00929         steps = 1;
00930 }
00931 
00932 MythThemedDialog::MythThemedDialog(MythMainWindow *parent,
00933                                    const QString  &window_name,
00934                                    const QString  &theme_filename,
00935                                    const char     *name,
00936                                    bool            setsize)
00937                 : MythDialog(parent, name, setsize)
00938 {
00939     setNoErase();
00940 
00941     theme = NULL;
00942 
00943     if (!loadThemedWindow(window_name, theme_filename))
00944     {
00945         QString msg =
00946             QString(tr("Could not locate '%1' in theme '%2'."
00947                        "\n\nReturning to the previous menu."))
00948             .arg(window_name).arg(theme_filename);
00949         MythPopupBox::showOkPopup(GetMythMainWindow(),
00950                                   tr("Missing UI Element"), msg);
00951         reject();
00952         return;
00953     }
00954 }
00955 
00956 MythThemedDialog::MythThemedDialog(
00957     MythMainWindow *parent, const char* name, bool setsize) :
00958     MythDialog(parent, name, setsize), widget_with_current_focus(NULL),
00959     theme(NULL), context(-1)
00960 {
00961     setNoErase();
00962 }
00963 
00964 bool MythThemedDialog::loadThemedWindow(QString window_name,
00965                                         QString theme_filename)
00966 {
00967     if (theme)
00968         delete theme;
00969 
00970     context = -1;
00971     my_containers.clear();
00972     widget_with_current_focus = NULL;
00973 
00974     redrawRect = QRect(0, 0, 0, 0);
00975 
00976     theme = new XMLParse();
00977     theme->SetWMult(wmult);
00978     theme->SetHMult(hmult);
00979     if (!theme->LoadTheme(xmldata, window_name, theme_filename))
00980     {
00981         return false;
00982     }
00983 
00984     loadWindow(xmldata);
00985 
00986     //
00987     //  Auto-connect signals we know about
00988     //
00989 
00990     //  Loop over containers
00991     QList<LayerSet*>::iterator an_it = my_containers.begin();
00992     for (; an_it != my_containers.end(); ++an_it)
00993     {
00994         LayerSet *looper = *an_it;
00995         //  Loop over UITypes within each container
00996         vector<UIType *> *all_ui_type_objects = looper->getAllTypes();
00997         vector<UIType *>::iterator i = all_ui_type_objects->begin();
00998         for (; i != all_ui_type_objects->end(); ++i)
00999         {
01000             UIType *type = (*i);
01001             connect(type, SIGNAL(requestUpdate()), this,
01002                     SLOT(updateForeground()));
01003             connect(type, SIGNAL(requestUpdate(const QRect &)), this,
01004                     SLOT(updateForeground(const QRect &)));
01005             connect(type, SIGNAL(requestRegionUpdate(const QRect &)), this,
01006                     SLOT(updateForegroundRegion(const QRect &)));
01007         }
01008     }
01009 
01010     buildFocusList();
01011 
01012     updateBackground();
01013     initForeground();
01014 
01015     return true;
01016 }
01017 
01018 bool MythThemedDialog::buildFocusList()
01019 {
01020     //
01021     //  Build a list of widgets that will take focus
01022     //
01023 
01024     focus_taking_widgets.clear();
01025 
01026 
01027     //  Loop over containers
01028     QList<LayerSet*>::iterator another_it = my_containers.begin();
01029     for (; another_it != my_containers.end(); ++another_it)
01030     {
01031         LayerSet *looper = *another_it;
01032         //  Loop over UITypes within each container
01033         vector<UIType *> *all_ui_type_objects = looper->getAllTypes();
01034         vector<UIType *>::iterator i = all_ui_type_objects->begin();
01035         for (; i != all_ui_type_objects->end(); ++i)
01036         {
01037             UIType *type = (*i);
01038             if (type->canTakeFocus() && !type->isHidden() &&
01039                 (context == -1 || type->GetContext() == -1 ||
01040                  context == type->GetContext()))
01041             {
01042                 focus_taking_widgets.push_back(type);
01043             }
01044         }
01045     }
01046 
01047     return !focus_taking_widgets.empty();
01048 }
01049 
01050 MythThemedDialog::~MythThemedDialog()
01051 {
01052     if (theme)
01053     {
01054         delete theme;
01055         theme = NULL;
01056     }
01057 }
01058 
01059 void MythThemedDialog::deleteLater(void)
01060 {
01061     if (theme)
01062     {
01063         delete theme;
01064         theme = NULL;
01065     }
01066     MythDialog::deleteLater();
01067 }
01068 
01069 void MythThemedDialog::loadWindow(QDomElement &element)
01070 {
01071     //
01072     //  Parse all the child elements in the theme
01073     //
01074 
01075     for (QDomNode child = element.firstChild(); !child.isNull();
01076          child = child.nextSibling())
01077     {
01078         QDomElement e = child.toElement();
01079         if (!e.isNull())
01080         {
01081             if (e.tagName() == "font")
01082             {
01083                 theme->parseFont(e);
01084             }
01085             else if (e.tagName() == "container")
01086             {
01087                 parseContainer(e);
01088             }
01089             else
01090             {
01091                 LOG(VB_GENERAL, LOG_ALERT,
01092                          QString("MythThemedDialog::loadWindow(): Do not "
01093                                  "understand DOM Element: '%1'. Ignoring.")
01094                              .arg(e.tagName()));
01095             }
01096         }
01097     }
01098 }
01099 
01100 void MythThemedDialog::parseContainer(QDomElement &element)
01101 {
01102     //
01103     //  Have the them object parse the containers
01104     //  but hold a pointer to each of them so
01105     //  that we can iterate over them later
01106     //
01107 
01108     QRect area;
01109     QString name;
01110     int a_context;
01111     theme->parseContainer(element, name, a_context, area);
01112     if (name.length() < 1)
01113     {
01114         LOG(VB_GENERAL, LOG_ALERT,
01115                  "Failed to parse a container. Ignoring.");
01116         return;
01117     }
01118 
01119     LayerSet *container_reference = theme->GetSet(name);
01120     my_containers.append(container_reference);
01121 }
01122 
01123 void MythThemedDialog::parseFont(QDomElement &element)
01124 {
01125     //
01126     //  this is just here so you can re-implement the virtual
01127     //  function and do something special if you like
01128     //
01129 
01130     theme->parseFont(element);
01131 }
01132 
01133 void MythThemedDialog::initForeground()
01134 {
01135     my_foreground = my_background;
01136     updateForeground();
01137 }
01138 
01139 void MythThemedDialog::updateBackground()
01140 {
01141     //
01142     //  Draw the background pixmap once
01143     //
01144 
01145     QPixmap bground(size());
01146     bground.fill(this, 0, 0);
01147 
01148     QPainter tmp(&bground);
01149 
01150     //
01151     //  Ask the container holding anything
01152     //  to do with the background to draw
01153     //  itself on a pixmap
01154     //
01155 
01156     LayerSet *container = theme->GetSet("background");
01157 
01158     //
01159     //  *IFF* there is a background, draw it
01160     //
01161     if (container)
01162     {
01163         container->Draw(&tmp, 0, context);
01164         tmp.end();
01165     }
01166 
01167     //
01168     //  Copy that pixmap to the permanent one
01169     //  and tell Qt about it
01170     //
01171 
01172     my_background = bground;
01173     QPalette palette;
01174     palette.setBrush(backgroundRole(), QBrush(my_background));
01175     setPalette(palette);
01176 }
01177 
01178 void MythThemedDialog::updateForeground()
01179 {
01180     QRect r = this->geometry();
01181     updateForeground(r);
01182 }
01183 
01184 QString ZeroSizedRect = QString("MythThemedDialog - Something is requesting"
01185 " a screen update of zero size. A widget probably has not done"
01186 " calculateScreeArea(). Will redraw the whole screen (inefficient!).");
01187 
01188 void MythThemedDialog::updateForeground(const QRect &r)
01189 {
01190     QRect rect_to_update = r;
01191     if (r.width() == 0 || r.height() == 0)
01192     {
01193         LOG(VB_GENERAL, LOG_ALERT, ZeroSizedRect);
01194         rect_to_update = this->geometry();
01195     }
01196 
01197     redrawRect = redrawRect.unite(r);
01198 
01199     update(redrawRect);
01200 }
01201 
01202 void MythThemedDialog::ReallyUpdateForeground(const QRect &r)
01203 {
01204     QRect rect_to_update = r;
01205     if (r.width() == 0 || r.height() == 0)
01206     {
01207         LOG(VB_GENERAL, LOG_ALERT, ZeroSizedRect);
01208         rect_to_update = this->geometry();
01209     }
01210 
01211     UpdateForegroundRect(rect_to_update);
01212 
01213     redrawRect = QRect(0, 0, 0, 0);
01214 }
01215 
01216 void MythThemedDialog::updateForegroundRegion(const QRect &r)
01217 {
01218     // Note: DrawRegion is never actually called now. Instead
01219     // of controls (only UIListTreeType did it) implementing an
01220     // optimized paint, we rely on clipping regions.
01221     UpdateForegroundRect(r);
01222 
01223     update(r);
01224 }
01225 
01226 void MythThemedDialog::UpdateForegroundRect(const QRect &inv_rect)
01227 {
01228     QPainter whole_dialog_painter(&my_foreground);
01229 
01230     // Updating the background portion isn't optional. The old
01231     // behavior left remnants during context transitions if
01232     // they happened outside active containers for the current
01233     // context.
01234     whole_dialog_painter.drawPixmap(inv_rect.topLeft(), my_background,
01235                                     inv_rect);
01236 
01237     QList<LayerSet*>::iterator an_it = my_containers.begin();
01238     for (; an_it != my_containers.end(); ++an_it)
01239     {
01240         LayerSet *looper = *an_it;
01241         QRect container_area = looper->GetAreaRect();
01242 
01243         //
01244         //  Only paint if the container's area is valid
01245         //  and it intersects with whatever Qt told us
01246         //  needed to be repainted
01247         //
01248 
01249         const QRect intersect = inv_rect.intersect(container_area);
01250         int looper_context = looper->GetContext();
01251         if (container_area.isValid() &&
01252             (looper_context == context || looper_context == -1) &&
01253             intersect.isValid() &&
01254             looper->GetName().toLower() != "background")
01255         {
01256             //
01257             //  Debugging
01258             //
01259 #if 0
01260             LOG(VB_GENERAL, LOG_DEBUG,
01261                      QString("A container called \"%1\" said its "
01262                              "area is %2,%3 to %4,%5")
01263                 .arg(looper->GetName())
01264                 .arg(container_area.left())
01265                 .arg(container_area.top())
01266                 .arg(container_area.left() + container_area.width())
01267                 .arg(container_area.top() + container_area.height()));
01268 #endif
01269 
01270             //
01271             //  Loop over the draworder layers
01272 
01273             whole_dialog_painter.save();
01274 
01275             whole_dialog_painter.setClipRect(intersect);
01276             whole_dialog_painter.translate(container_area.left(),
01277                                            container_area.top());
01278 
01279             for (int i = 0; i <= looper->getLayers(); ++i)
01280             {
01281                 looper->Draw(&whole_dialog_painter, i, context);
01282             }
01283 
01284             whole_dialog_painter.restore();
01285         }
01286     }
01287 }
01288 
01289 void MythThemedDialog::paintEvent(QPaintEvent *e)
01290 {
01291     if (redrawRect.width() > 0 && redrawRect.height() > 0)
01292         ReallyUpdateForeground(redrawRect);
01293 
01294     { // Make sure QPainter is destructed before calling MythDialog's paint..
01295         QPainter p(this);
01296         p.drawPixmap(e->rect().topLeft(), my_foreground, e->rect());
01297     }
01298     MythDialog::paintEvent(e);
01299 }
01300 
01301 bool MythThemedDialog::assignFirstFocus()
01302 {
01303     if (widget_with_current_focus)
01304     {
01305         widget_with_current_focus->looseFocus();
01306     }
01307 
01308     vector<UIType*>::iterator an_it = focus_taking_widgets.begin();
01309     for (; an_it != focus_taking_widgets.end(); ++an_it)
01310     {
01311         UIType *looper = *an_it;
01312         if (looper->canTakeFocus())
01313         {
01314             widget_with_current_focus = looper;
01315             widget_with_current_focus->takeFocus();
01316             return true;
01317         }
01318     }
01319 
01320     return false;
01321 }
01322 
01323 bool MythThemedDialog::nextPrevWidgetFocus(bool up_or_down)
01324 {
01325     if (up_or_down)
01326     {
01327         bool reached_current = false;
01328 
01329         vector<UIType*>::iterator an_it = focus_taking_widgets.begin();
01330         for (; an_it != focus_taking_widgets.end(); ++an_it)
01331         {
01332             UIType *looper = *an_it;
01333             if (reached_current && looper->canTakeFocus())
01334             {
01335                 widget_with_current_focus->looseFocus();
01336                 widget_with_current_focus = looper;
01337                 widget_with_current_focus->takeFocus();
01338                 return true;
01339             }
01340 
01341             if (looper == widget_with_current_focus)
01342             {
01343                 reached_current= true;
01344             }
01345         }
01346 
01347         if (assignFirstFocus())
01348         {
01349             return true;
01350         }
01351         return false;
01352     }
01353     else
01354     {
01355         bool reached_current = false;
01356 
01357         vector<UIType*>::reverse_iterator an_it = focus_taking_widgets.rbegin();
01358         for (; an_it != focus_taking_widgets.rend(); ++an_it)
01359         {
01360             UIType *looper = *an_it;
01361 
01362             if (reached_current && looper->canTakeFocus())
01363             {
01364                 widget_with_current_focus->looseFocus();
01365                 widget_with_current_focus = looper;
01366                 widget_with_current_focus->takeFocus();
01367                 return true;
01368             }
01369 
01370             if (looper == widget_with_current_focus)
01371             {
01372                 reached_current= true;
01373             }
01374         }
01375 
01376         if (reached_current)
01377         {
01378             an_it = focus_taking_widgets.rbegin();
01379             for (; an_it != focus_taking_widgets.rend(); ++an_it)
01380             {
01381                 UIType *looper = *an_it;
01382 
01383                 if (looper->canTakeFocus())
01384                 {
01385                     widget_with_current_focus->looseFocus();
01386                     widget_with_current_focus = looper;
01387                     widget_with_current_focus->takeFocus();
01388                     return true;
01389                 }
01390             }
01391         }
01392         return false;
01393     }
01394     return false;
01395 }
01396 
01397 void MythThemedDialog::activateCurrent()
01398 {
01399     if (widget_with_current_focus)
01400     {
01401         widget_with_current_focus->activate();
01402     }
01403     else
01404     {
01405         LOG(VB_GENERAL, LOG_ALERT, "MythThemedDialog::activateCurrent() - "
01406                                         "there is no current widget!");
01407     }
01408 }
01409 
01410 namespace
01411 {
01412     template <typename T>
01413     T *GetUIType(MythThemedDialog *dialog, const QString &name)
01414     {
01415         UIType *sf = dialog->getUIObject(name);
01416         if (sf)
01417         {
01418             T *ret = dynamic_cast<T *>(sf);
01419             if (ret)
01420                 return ret;
01421         }
01422         return 0;
01423     }
01424 };
01425 
01426 UIType* MythThemedDialog::getUIObject(const QString &name)
01427 {
01428     //
01429     //  Try and find the UIType target referenced
01430     //  by "name".
01431     //
01432     //  At some point, it would be nice to speed
01433     //  this up with a map across all instantiated
01434     //  UIType objects "owned" by this dialog
01435     //
01436 
01437     QList<LayerSet*>::iterator an_it = my_containers.begin();
01438     for (; an_it != my_containers.end(); ++an_it)
01439     {
01440         UIType *hunter = (*an_it)->GetType(name);
01441         if (hunter)
01442             return hunter;
01443     }
01444 
01445     return NULL;
01446 }
01447 
01448 UIType* MythThemedDialog::getCurrentFocusWidget()
01449 {
01450     if (widget_with_current_focus)
01451     {
01452         return widget_with_current_focus;
01453     }
01454     return NULL;
01455 }
01456 
01457 void MythThemedDialog::setCurrentFocusWidget(UIType* widget)
01458 {
01459     // make sure this widget is in the list of widgets that can take focus
01460     vector<UIType*>::iterator it =
01461         std::find(focus_taking_widgets.begin(),
01462                   focus_taking_widgets.end(), widget);
01463     if (it == focus_taking_widgets.end())
01464         return;
01465 
01466     if (widget_with_current_focus)
01467         widget_with_current_focus->looseFocus();
01468 
01469     widget_with_current_focus = widget;
01470     widget_with_current_focus->takeFocus();
01471 }
01472 
01473 UIKeyboardType *MythThemedDialog::getUIKeyboardType(const QString &name)
01474 {
01475     return GetUIType<UIKeyboardType>(this, name);
01476 }
01477 
01478 LayerSet *MythThemedDialog::getContainer(const QString &name)
01479 {
01480     QList<LayerSet*>::iterator an_it = my_containers.begin();
01481     for (; an_it != my_containers.end(); ++an_it)
01482     {
01483         if ((*an_it)->GetName() == name)
01484             return *an_it;
01485     }
01486 
01487     return NULL;
01488 }
01489 
01490 fontProp* MythThemedDialog::getFont(const QString &name)
01491 {
01492     fontProp* font = NULL;
01493     if (theme)
01494         font = theme->GetFont(name, true);
01495 
01496     return font;
01497 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends