MythTV  0.26-pre
viewscheduled.cpp
Go to the documentation of this file.
00001 
00002 #include "viewscheduled.h"
00003 
00004 #include <QCoreApplication>
00005 
00006 #include "customedit.h"
00007 #include "recordinginfo.h"
00008 #include "tv_play.h"
00009 #include "recordingrule.h"
00010 #include "mythlogging.h"
00011 #include "mythcorecontext.h"
00012 #include "remoteutil.h"
00013 #include "mythuitext.h"
00014 #include "mythuistatetype.h"
00015 #include "mythuibuttonlist.h"
00016 #include "mythdialogbox.h"
00017 #include "mythmainwindow.h"
00018 
00019 void *ViewScheduled::RunViewScheduled(void *player, bool showTV)
00020 {
00021     MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
00022     ViewScheduled *vsb = new ViewScheduled(mainStack, static_cast<TV*>(player),
00023                                            showTV);
00024 
00025     if (vsb->Create())
00026         mainStack->AddScreen(vsb, (player == NULL));
00027     else
00028         delete vsb;
00029 
00030     return NULL;
00031 }
00032 
00033 ViewScheduled::ViewScheduled(MythScreenStack *parent, TV* player, bool showTV)
00034              : ScheduleCommon(parent, "ViewScheduled")
00035 {
00036     m_showAll = !gCoreContext->GetNumSetting("ViewSchedShowLevel", 0);
00037 
00038     m_player = player;
00039 
00040     m_inEvent = false;
00041     m_inFill = false;
00042     m_needFill = false;
00043 
00044     m_curcard  = 0;
00045     m_maxcard  = 0;
00046     m_curinput = 0;
00047     m_maxinput = 0;
00048 
00049     m_defaultGroup = QDate();
00050     m_currentGroup = m_defaultGroup;
00051 
00052     gCoreContext->addListener(this);
00053 }
00054 
00055 ViewScheduled::~ViewScheduled()
00056 {
00057     gCoreContext->removeListener(this);
00058     gCoreContext->SaveSetting("ViewSchedShowLevel", !m_showAll);
00059 
00060     // if we have a player, we need to tell we are done
00061     if (m_player)
00062     {
00063         QString message = QString("VIEWSCHEDULED_EXITING");
00064         qApp->postEvent(m_player, new MythEvent(message));
00065     }
00066 }
00067 
00068 bool ViewScheduled::Create()
00069 {
00070     if (!LoadWindowFromXML("schedule-ui.xml", "viewscheduled", this))
00071         return false;
00072 
00073     //if (m_player && m_player->IsRunning() && showTV)
00074 
00075     m_groupList     = dynamic_cast<MythUIButtonList *> (GetChild("groups"));
00076     m_schedulesList = dynamic_cast<MythUIButtonList *> (GetChild("schedules"));
00077 
00078     if (!m_schedulesList)
00079     {
00080         LOG(VB_GENERAL, LOG_ERR, "Theme is missing critical theme elements.");
00081         return false;
00082     }
00083 
00084     connect(m_schedulesList, SIGNAL(itemSelected(MythUIButtonListItem*)),
00085             SLOT(updateInfo(MythUIButtonListItem*)));
00086     connect(m_schedulesList, SIGNAL(itemClicked(MythUIButtonListItem*)),
00087             SLOT(selected(MythUIButtonListItem*)));
00088 
00089     m_schedulesList->SetLCDTitles(tr("Scheduled Recordings"),
00090                               "shortstarttimedate|channel|titlesubtitle|card");
00091     m_schedulesList->SetSearchFields("titlesubtitle");
00092 
00093     if (m_groupList)
00094     {
00095         connect(m_groupList, SIGNAL(itemSelected(MythUIButtonListItem*)),
00096                 SLOT(ChangeGroup(MythUIButtonListItem*)));
00097         connect(m_groupList, SIGNAL(itemClicked(MythUIButtonListItem*)),
00098                 SLOT(SwitchList()));
00099         m_groupList->SetLCDTitles(tr("Group List"), "");
00100     }
00101 
00102     BuildFocusList();
00103     LoadInBackground();
00104 
00105     EmbedTVWindow();
00106 
00107     return true;
00108 }
00109 
00110 void ViewScheduled::Load(void)
00111 {
00112     LoadFromScheduler(m_recList, m_conflictBool);
00113 }
00114 
00115 void ViewScheduled::Init()
00116 {
00117     LoadList(true);
00118 }
00119 
00120 void ViewScheduled::Close()
00121 {
00122     // don't fade the screen if we are returning to the player
00123     if (m_player)
00124         GetScreenStack()->PopScreen(this, false);
00125     else
00126         GetScreenStack()->PopScreen(this, true);
00127 }
00128 
00129 void ViewScheduled::SwitchList()
00130 {
00131     if (GetFocusWidget() == m_groupList)
00132         SetFocusWidget(m_schedulesList);
00133     else if (GetFocusWidget() == m_schedulesList)
00134         SetFocusWidget(m_groupList);
00135 }
00136 
00137 bool ViewScheduled::keyPressEvent(QKeyEvent *event)
00138 {
00139     // FIXME: Blackholes keypresses, not good
00140     if (m_inEvent)
00141         return true;
00142 
00143     m_inEvent = true;
00144 
00145     if (GetFocusWidget()->keyPressEvent(event))
00146     {
00147         m_inEvent = false;
00148         return true;
00149     }
00150 
00151     bool handled = false;
00152     QStringList actions;
00153     handled = GetMythMainWindow()->TranslateKeyPress("TV Frontend", event,
00154                                                      actions);
00155 
00156     for (int i = 0; i < actions.size() && !handled; i++)
00157     {
00158         QString action = actions[i];
00159         handled = true;
00160 
00161         if (action == "EDIT")
00162             edit();
00163         else if (action == "CUSTOMEDIT")
00164             customEdit();
00165         else if (action == "DELETE")
00166             deleteRule();
00167         else if (action == "UPCOMING")
00168             upcoming();
00169         else if (action == "VIEWSCHEDULED")
00170             upcomingScheduled();
00171         else if (action == "DETAILS" || action == "INFO")
00172             details();
00173         else if (action == "1")
00174             setShowAll(true);
00175         else if (action == "2")
00176             setShowAll(false);
00177         else if (action == "PREVVIEW" || action == "NEXTVIEW")
00178             setShowAll(!m_showAll);
00179         else if (action == "VIEWCARD")
00180             viewCards();
00181         else if (action == "VIEWINPUT")
00182             viewInputs();
00183         else
00184             handled = false;
00185     }
00186 
00187     if (m_needFill)
00188         LoadList();
00189 
00190     if (!handled && MythScreenType::keyPressEvent(event))
00191         handled = true;
00192 
00193     m_inEvent = false;
00194 
00195     return handled;
00196 }
00197 
00198 void ViewScheduled::ShowMenu(void)
00199 {
00200     QString label = tr("Options");
00201 
00202     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00203     MythDialogBox *menuPopup = new MythDialogBox(label, popupStack,
00204                                                  "menuPopup");
00205 
00206     if (menuPopup->Create())
00207     {
00208         menuPopup->SetReturnEvent(this, "menu");
00209 
00210         if (m_showAll)
00211             menuPopup->AddButton(tr("Show Important"));
00212         else
00213             menuPopup->AddButton(tr("Show All"));
00214         menuPopup->AddButton(tr("Program Details"));
00215         menuPopup->AddButton(tr("Upcoming by title"));
00216         menuPopup->AddButton(tr("Upcoming scheduled"));
00217         menuPopup->AddButton(tr("Custom Edit"));
00218         menuPopup->AddButton(tr("Delete Rule"));
00219         menuPopup->AddButton(tr("Show Cards"));
00220         menuPopup->AddButton(tr("Show Inputs"));
00221 
00222         popupStack->AddScreen(menuPopup);
00223     }
00224     else
00225     {
00226         delete menuPopup;
00227     }
00228 }
00229 
00230 void ViewScheduled::LoadList(bool useExistingData)
00231 {
00232     if (m_inFill)
00233         return;
00234 
00235     m_inFill = true;
00236 
00237     MythUIButtonListItem *currentItem = m_schedulesList->GetItemCurrent();
00238 
00239     QString callsign;
00240     QDateTime startts, recstartts;
00241 
00242     if (currentItem)
00243     {
00244         ProgramInfo *currentpginfo = qVariantValue<ProgramInfo*>
00245                                                     (currentItem->GetData());
00246         if (currentpginfo)
00247         {
00248             callsign   = currentpginfo->GetChannelSchedulingID();
00249             startts    = currentpginfo->GetScheduledStartTime();
00250             recstartts = currentpginfo->GetRecordingStartTime();
00251         }
00252     }
00253 
00254     QDateTime now = QDateTime::currentDateTime();
00255 
00256     QMap<int, int> toomanycounts;
00257 
00258     m_schedulesList->Reset();
00259     if (m_groupList)
00260         m_groupList->Reset();
00261 
00262     m_recgroupList.clear();
00263 
00264     if (!useExistingData)
00265         LoadFromScheduler(m_recList, m_conflictBool);
00266 
00267     ProgramList::iterator pit = m_recList.begin();
00268     QString currentDate;
00269     m_recgroupList[m_defaultGroup] = ProgramList(false);
00270     m_recgroupList[m_defaultGroup].setAutoDelete(false);
00271     while (pit != m_recList.end())
00272     {
00273         ProgramInfo *pginfo = *pit;
00274         const RecStatusType recstatus = pginfo->GetRecordingStatus();
00275         if ((pginfo->GetRecordingEndTime() >= now ||
00276              pginfo->GetScheduledEndTime() >= now) &&
00277             (m_showAll ||
00278              recstatus <= rsWillRecord ||
00279              recstatus == rsDontRecord ||
00280              (recstatus == rsTooManyRecordings &&
00281               ++toomanycounts[pginfo->GetRecordingRuleID()] <= 1) ||
00282              (recstatus > rsTooManyRecordings &&
00283               recstatus != rsRepeat &&
00284               recstatus != rsNeverRecord)))
00285         {
00286             m_cardref[pginfo->GetCardID()]++;
00287             if (pginfo->GetCardID() > m_maxcard)
00288                 m_maxcard = pginfo->GetCardID();
00289 
00290             m_inputref[pginfo->GetInputID()]++;
00291             if (pginfo->GetInputID() > m_maxinput)
00292                 m_maxinput = pginfo->GetInputID();
00293 
00294             QDate date = (pginfo->GetRecordingStartTime()).date();
00295             m_recgroupList[date].push_back(pginfo);
00296             m_recgroupList[date].setAutoDelete(false);
00297 
00298             m_recgroupList[m_defaultGroup].push_back(pginfo);
00299 
00300             ++pit;
00301         }
00302         else
00303         {
00304             pit = m_recList.erase(pit);
00305             continue;
00306         }
00307     }
00308 
00309     if (m_groupList)
00310     {
00311         QString label;
00312         QMap<QDate,ProgramList>::iterator dateit = m_recgroupList.begin();
00313         while (dateit != m_recgroupList.end())
00314         {
00315             if (dateit.key().isNull())
00316                 label = tr("All");
00317             else
00318                 label = MythDateToString(dateit.key(), kDateFull | kSimplify);
00319 
00320             new MythUIButtonListItem(m_groupList, label,
00321                                      qVariantFromValue(dateit.key()));
00322             ++dateit;
00323         }
00324         if (!m_recgroupList.contains(m_currentGroup))
00325             m_groupList->SetValueByData(qVariantFromValue(m_currentGroup));
00326     }
00327 
00328     FillList();
00329 
00330     // Restore position after a list update
00331     if (!callsign.isEmpty())
00332     {
00333         ProgramList plist;
00334 
00335         if (!m_recgroupList.contains(m_currentGroup))
00336             m_currentGroup = m_defaultGroup;
00337 
00338         plist = m_recgroupList[m_currentGroup];
00339 
00340         int listPos = ((int) plist.size()) - 1;
00341         int i;
00342         for (i = listPos; i >= 0; --i)
00343         {
00344             ProgramInfo *pginfo = plist[i];
00345             if (callsign == pginfo->GetChannelSchedulingID() &&
00346                 startts  == pginfo->GetScheduledStartTime())
00347             {
00348                 listPos = i;
00349                 break;
00350             }
00351             else if (recstartts <= pginfo->GetRecordingStartTime())
00352                 listPos = i;
00353         }
00354         m_schedulesList->SetItemCurrent(listPos);
00355     }
00356 
00357     m_inFill = false;
00358     m_needFill = false;
00359 }
00360 
00361 
00362 void ViewScheduled::ChangeGroup(MythUIButtonListItem* item)
00363 {
00364     if (!item || m_recList.empty())
00365         return;
00366 
00367     QDate group = qVariantValue<QDate>(item->GetData());
00368 
00369     m_currentGroup = group;
00370 
00371     if (!m_inFill)
00372         FillList();
00373 }
00374 
00375 void ViewScheduled::FillList()
00376 {
00377     m_schedulesList->Reset();
00378 
00379     MythUIText *norecordingText = dynamic_cast<MythUIText*>
00380                                                 (GetChild("norecordings_info"));
00381 
00382     if (norecordingText)
00383         norecordingText->SetVisible(m_recList.empty());
00384 
00385     if (m_recList.empty())
00386         return;
00387 
00388     ProgramList plist;
00389 
00390     if (!m_recgroupList.contains(m_currentGroup))
00391         m_currentGroup = m_defaultGroup;
00392 
00393     plist = m_recgroupList[m_currentGroup];
00394 
00395     ProgramList::iterator pit = plist.begin();
00396     while (pit != plist.end())
00397     {
00398         ProgramInfo *pginfo = *pit;
00399         if (!pginfo)
00400         {
00401             ++pit;
00402             continue;
00403         }
00404 
00405         QString state;
00406 
00407         const RecStatusType recstatus = pginfo->GetRecordingStatus();
00408         if (recstatus == rsRecording      ||
00409             recstatus == rsTuning         ||
00410             recstatus == rsOtherRecording ||
00411             recstatus == rsOtherTuning)
00412             state = "running";
00413         else if (recstatus == rsConflict  ||
00414                  recstatus == rsOffLine   ||
00415                  recstatus == rsTunerBusy ||
00416                  recstatus == rsFailed    ||
00417                  recstatus == rsAborted   ||
00418                  recstatus == rsMissed)
00419             state = "error";
00420         else if (recstatus == rsWillRecord ||
00421                  recstatus == rsOtherShowing)
00422         {
00423             if ((m_curcard == 0 && m_curinput == 0) ||
00424                 pginfo->GetCardID() == m_curcard ||
00425                 pginfo->GetInputID() == m_curinput)
00426             {
00427                 if (pginfo->GetRecordingPriority2() < 0)
00428                     state = "warning";
00429                 else
00430                     state = "normal";
00431             }
00432         }
00433         else if (recstatus == rsRepeat ||
00434                  recstatus == rsNeverRecord ||
00435                  recstatus == rsDontRecord ||
00436                  (recstatus != rsDontRecord &&
00437                   recstatus <= rsEarlierShowing))
00438             state = "disabled";
00439         else
00440             state = "warning";
00441 
00442         MythUIButtonListItem *item =
00443                                 new MythUIButtonListItem(m_schedulesList,"",
00444                                                     qVariantFromValue(pginfo));
00445 
00446         InfoMap infoMap;
00447         pginfo->ToMap(infoMap);
00448         item->SetTextFromMap(infoMap, state);
00449 
00450         QString rating = QString::number(pginfo->GetStars(10));
00451         item->DisplayState(rating, "ratingstate");
00452         item->DisplayState(state, "status");
00453 
00454         ++pit;
00455     }
00456 
00457     MythUIText *statusText = dynamic_cast<MythUIText*>(GetChild("status"));
00458     if (statusText)
00459     {
00460         if (m_conflictBool)
00461         {
00462             // Find first conflict and store in m_conflictDate field
00463             ProgramList::const_iterator it = plist.begin();
00464             for (; it != plist.end(); ++it)
00465             {
00466                 ProgramInfo &p = **it;
00467                 if (p.GetRecordingStatus() == rsConflict)
00468                 {
00469                     m_conflictDate = p.GetRecordingStartTime().date();
00470                     break;
00471                 }
00472             }
00473 
00474             // TODO: This can be templated instead of hardcoding
00475             //       Conflict/No Conflict
00476             QString cstring = QString(tr("Conflict %1"))
00477                                 .arg(MythDateToString(m_conflictDate,
00478                                                         kDateFull | kSimplify));
00479 
00480             statusText->SetText(cstring);
00481         }
00482         else
00483             statusText->SetText(tr("No Conflicts"));
00484     }
00485 
00486     MythUIText *filterText = dynamic_cast<MythUIText*>(GetChild("filter"));
00487     if (filterText)
00488     {
00489         if (m_showAll)
00490             filterText->SetText(tr("All"));
00491         else
00492             filterText->SetText(tr("Important"));
00493     }
00494 }
00495 
00496 void ViewScheduled::updateInfo(MythUIButtonListItem *item)
00497 {
00498     if (!item)
00499         return;
00500 
00501     ProgramInfo *pginfo = qVariantValue<ProgramInfo*> (item->GetData());
00502     if (pginfo)
00503     {
00504         InfoMap infoMap;
00505         pginfo->ToMap(infoMap);
00506         SetTextFromMap(infoMap);
00507 
00508         MythUIStateType *ratingState = dynamic_cast<MythUIStateType*>
00509                                                     (GetChild("ratingstate"));
00510         if (ratingState)
00511         {
00512             QString rating = QString::number(pginfo->GetStars(10));
00513             ratingState->DisplayState(rating);
00514         }
00515     }
00516 }
00517 
00518 void ViewScheduled::edit()
00519 {
00520     MythUIButtonListItem *item = m_schedulesList->GetItemCurrent();
00521 
00522     if (!item)
00523         return;
00524 
00525     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
00526     if (!pginfo)
00527         return;
00528 
00529     EditScheduled(pginfo);
00530 }
00531 
00532 void ViewScheduled::customEdit()
00533 {
00534     MythUIButtonListItem *item = m_schedulesList->GetItemCurrent();
00535 
00536     if (!item)
00537         return;
00538 
00539     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
00540     EditCustom(pginfo);
00541 }
00542 
00543 void ViewScheduled::deleteRule()
00544 {
00545     MythUIButtonListItem *item = m_schedulesList->GetItemCurrent();
00546 
00547     if (!item)
00548         return;
00549 
00550     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
00551     if (!pginfo)
00552         return;
00553 
00554     RecordingRule *record = new RecordingRule();
00555     if (!record->LoadByProgram(pginfo))
00556     {
00557         delete record;
00558         return;
00559     }
00560 
00561     QString message = tr("Delete '%1' %2 rule?").arg(record->m_title)
00562         .arg(toString(pginfo->GetRecordingRuleType()));
00563 
00564     MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
00565 
00566     MythConfirmationDialog *okPopup = new MythConfirmationDialog(popupStack,
00567                                                                  message, true);
00568 
00569     okPopup->SetReturnEvent(this, "deleterule");
00570     okPopup->SetData(qVariantFromValue(record));
00571 
00572     if (okPopup->Create())
00573         popupStack->AddScreen(okPopup);
00574     else
00575         delete okPopup;
00576 }
00577 
00578 void ViewScheduled::upcoming()
00579 {
00580     MythUIButtonListItem *item = m_schedulesList->GetItemCurrent();
00581     if (!item)
00582         return;
00583 
00584     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
00585 
00586     ShowUpcoming(pginfo);
00587 
00588     //FIXME:
00589     //EmbedTVWindow();
00590 }
00591 
00592 void ViewScheduled::upcomingScheduled()
00593 {
00594     MythUIButtonListItem *item = m_schedulesList->GetItemCurrent();
00595     if (!item)
00596         return;
00597 
00598     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
00599 
00600     ShowUpcomingScheduled(pginfo);
00601 
00602     //FIXME:
00603     //EmbedTVWindow();
00604 }
00605 
00606 void ViewScheduled::details()
00607 {
00608     MythUIButtonListItem *item = m_schedulesList->GetItemCurrent();
00609 
00610     if (!item)
00611         return;
00612 
00613     ProgramInfo *pginfo = qVariantValue<ProgramInfo*>(item->GetData());
00614     if (pginfo)
00615         ShowDetails(pginfo);
00616 
00617     EmbedTVWindow();
00618 }
00619 
00620 void ViewScheduled::selected(MythUIButtonListItem *item)
00621 {
00622     if (!item)
00623         return;
00624 
00625     ProgramInfo *pginfo = qVariantValue<ProgramInfo*> (item->GetData());
00626     if (!pginfo)
00627         return;
00628 
00629     EditRecording(pginfo);
00630 }
00631 
00632 void ViewScheduled::setShowAll(bool all)
00633 {
00634     m_showAll = all;
00635     m_needFill = true;
00636 }
00637 
00638 void ViewScheduled::viewCards()
00639 {
00640     m_curinput = 0;
00641     m_needFill = true;
00642 
00643     m_curcard++;
00644     while (m_curcard <= m_maxcard)
00645     {
00646         if (m_cardref[m_curcard] > 0)
00647             return;
00648         m_curcard++;
00649     }
00650     m_curcard = 0;
00651 }
00652 
00653 void ViewScheduled::viewInputs()
00654 {
00655     m_curcard = 0;
00656     m_needFill = true;
00657 
00658     m_curinput++;
00659     while (m_curinput <= m_maxinput)
00660     {
00661         if (m_inputref[m_curinput] > 0)
00662             return;
00663         m_curinput++;
00664     }
00665     m_curinput = 0;
00666 }
00667 
00668 void ViewScheduled::EmbedTVWindow(void)
00669 {
00670     if (m_player)
00671         m_player->StartEmbedding(QRect());
00672 }
00673 
00674 void ViewScheduled::customEvent(QEvent *event)
00675 {
00676     if ((MythEvent::Type)(event->type()) == MythEvent::MythEventMessage)
00677     {
00678         MythEvent *me = (MythEvent *)event;
00679         QString message = me->Message();
00680 
00681         if (message != "SCHEDULE_CHANGE")
00682             return;
00683 
00684         m_needFill = true;
00685 
00686         if (m_inEvent)
00687             return;
00688 
00689         m_inEvent = true;
00690 
00691         LoadList();
00692 
00693         m_inEvent = false;
00694     }
00695     else if (event->type() == DialogCompletionEvent::kEventType)
00696     {
00697         DialogCompletionEvent *dce = (DialogCompletionEvent*)(event);
00698 
00699         QString resultid   = dce->GetId();
00700         QString resulttext = dce->GetResultText();
00701         int     buttonnum  = dce->GetResult();
00702 
00703         if (resultid == "deleterule")
00704         {
00705             RecordingRule *record =
00706                 qVariantValue<RecordingRule *>(dce->GetData());
00707             if (record)
00708             {
00709                 if (buttonnum > 0)
00710                 {
00711                     if (!record->Delete())
00712                         LOG(VB_GENERAL, LOG_ERR,
00713                             "Failed to delete recording rule");
00714                 }
00715                 delete record;
00716             }
00717 
00718             EmbedTVWindow();
00719         }
00720         else if (resultid == "menu")
00721         {
00722             if (resulttext == tr("Show Important"))
00723             {
00724                 setShowAll(false);
00725             }
00726             else if (resulttext == tr("Show All"))
00727             {
00728                 setShowAll(true);
00729             }
00730             else if (resulttext == tr("Program Details"))
00731             {
00732                 details();
00733             }
00734             else if (resulttext == tr("Upcoming by title"))
00735             {
00736                 upcoming();
00737             }
00738             else if (resulttext == tr("Upcoming scheduled"))
00739             {
00740                 upcomingScheduled();
00741             }
00742             else if (resulttext == tr("Custom Edit"))
00743             {
00744                 customEdit();
00745             }
00746             else if (resulttext == tr("Delete Rule"))
00747             {
00748                 deleteRule();
00749             }
00750             else if (resulttext == tr("Show Cards"))
00751             {
00752                 viewCards();
00753             }
00754             else if (resulttext == tr("Show Inputs"))
00755             {
00756                 viewInputs();
00757             }
00758 
00759             if (m_needFill)
00760                 LoadList();
00761         }
00762         else
00763             ScheduleCommon::customEvent(event);
00764     }
00765 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends