vdr-plugin-skindesigner/views/displaymenudetailview.c

872 lines
39 KiB
C

#include "displaymenudetailview.h"
#include "../libcore/helpers.h"
#include "../services/scraper2vdr.h"
#include "../services/epgsearch.h"
cDisplayMenuDetailView::cDisplayMenuDetailView(cTemplateView *tmplDetailView) : cView(tmplDetailView) {
event = NULL;
recording = NULL;
text = NULL;
detailViewInit = true;
isPluginTextView = false;
currentTmplTab = NULL;
tabView = NULL;
}
cDisplayMenuDetailView::~cDisplayMenuDetailView() {
CancelSave();
if (tabView)
delete tabView;
}
void cDisplayMenuDetailView::SetPluginTokens(map<string,string> *plugStringTokens, map<string,int> *plugIntTokens, map<string,vector<map<string,string> > > *plugLoopTokens) {
for (map<string,string>::iterator it = plugStringTokens->begin(); it != plugStringTokens->end(); it++) {
stringTokens.insert(pair<string,string>(it->first, it->second));
}
for (map<string,int>::iterator it = plugIntTokens->begin(); it != plugIntTokens->end(); it++) {
intTokens.insert(pair<string,int>(it->first, it->second));
}
for(map<string,vector<map<string,string> > >::iterator it = plugLoopTokens->begin(); it != plugLoopTokens->end(); it++) {
loopTokens.insert(pair<string,vector<map<string,string> > >(it->first, it->second));
}
isPluginTextView = true;
}
void cDisplayMenuDetailView::Clear(void) {
ClearViewElement(veDetailHeader);
ClearViewElement(veScrollbar);
ClearViewElement(veTabLabels);
}
void cDisplayMenuDetailView::Render(void) {
if (detailViewInit) {
DrawHeader();
DoFlush();
SetTokens();
InitTabs();
currentTmplTab = *atIt;
detailViewInit = false;
}
if (!tabView) {
tabView = new cDisplayMenuTabView(currentTmplTab);
tabView->SetTokens(&intTokens, &stringTokens, &loopTokens);
tabView->CreateTab();
tabView->Start();
}
DrawScrollbar();
DrawTabLabels();
}
void cDisplayMenuDetailView::KeyLeft(void) {
if (activeTabs.size() > 1) {
currentTmplTab = GetPrevTab();
delete tabView;
tabView = NULL;
Render();
DoFlush();
} else {
bool scrolled = tabView->KeyLeft();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
}
void cDisplayMenuDetailView::KeyRight(void) {
if (activeTabs.size() > 1) {
currentTmplTab = GetNextTab();
delete tabView;
tabView = NULL;
Render();
DoFlush();
} else {
bool scrolled = tabView->KeyRight();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
}
void cDisplayMenuDetailView::KeyUp(void) {
if (!tabView)
return;
bool scrolled = tabView->KeyUp();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
void cDisplayMenuDetailView::KeyDown(void) {
if (!tabView)
return;
bool scrolled = tabView->KeyDown();
if (scrolled) {
DrawScrollbar();
DoFlush();
}
}
void cDisplayMenuDetailView::SetTokens(void) {
if (event) {
stringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
stringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
stringTokens.insert(pair<string,string>("description", event->Description() ? event->Description() : ""));
stringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
stringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
time_t startTime = event->StartTime();
stringTokens.insert(pair<string,string>("day", *WeekDayName(startTime)));
stringTokens.insert(pair<string,string>("date", *ShortDateString(startTime)));
struct tm * sStartTime = localtime(&startTime);
intTokens.insert(pair<string, int>("year", sStartTime->tm_year + 1900));
intTokens.insert(pair<string, int>("daynumeric", sStartTime->tm_mday));
intTokens.insert(pair<string, int>("month", sStartTime->tm_mon+1));
string channelID = *(event->ChannelID().ToString());
stringTokens.insert(pair<string,string>("channelid", channelID));
intTokens.insert(pair<string, int>("channellogoexists", imgCache->LogoExists(channelID)));
bool isRunning = false;
time_t now = time(NULL);
if ((now >= event->StartTime()) && (now <= event->EndTime()))
isRunning = true;
intTokens.insert(pair<string,int>("running", isRunning));
if (isRunning) {
intTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
} else {
intTokens.insert(pair<string,int>("elapsed", 0));
}
intTokens.insert(pair<string,int>("duration", event->Duration() / 60));
intTokens.insert(pair<string,int>("durationhours", event->Duration() / 3600));
stringTokens.insert(pair<string,string>("durationminutes", *cString::sprintf("%.2d", (event->Duration() / 60)%60)));
if (event->Vps())
stringTokens.insert(pair<string,string>("vps", *event->GetVpsString()));
else
stringTokens.insert(pair<string,string>("vps", ""));
vector< map< string, string > > reruns;
bool hasReruns = LoadReruns(&reruns);
loopTokens.insert(pair<string, vector< map< string, string > > >("reruns", reruns));
intTokens.insert(pair<string,int>("hasreruns", hasReruns));
SetScraperTokens(event, recording, stringTokens, intTokens, loopTokens);
SetEpgPictures(event->EventID());
} else if (recording) {
string name = recording->Name() ? recording->Name() : "";
stringTokens.insert(pair<string,string>("name", name));
intTokens.insert(pair<string,int>("cutted", recording->IsEdited()));
const cRecordingInfo *info = recording->Info();
if (info) {
stringTokens.insert(pair<string,string>("epgname", info->Title() ? info->Title() : name));
stringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
stringTokens.insert(pair<string,string>("description", info->Description() ? info->Description() : ""));
const cEvent *event = info->GetEvent();
if (event) {
string recDate = *(event->GetDateString());
string recTime = *(event->GetTimeString());
if (recDate.find("1970") != string::npos) {
time_t start = recording->Start();
recDate = *DateString(start);
recTime = *TimeString(start);
}
stringTokens.insert(pair<string,string>("date", recDate.c_str()));
stringTokens.insert(pair<string,string>("time", recTime.c_str()));
time_t startTime = event->StartTime();
struct tm * sStartTime = localtime(&startTime);
intTokens.insert(pair<string, int>("year", sStartTime->tm_year + 1900));
intTokens.insert(pair<string, int>("daynumeric", sStartTime->tm_mday));
intTokens.insert(pair<string, int>("month", sStartTime->tm_mon+1));
int duration = event->Duration() / 60;
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
intTokens.insert(pair<string,int>("duration", recDuration));
intTokens.insert(pair<string,int>("durationhours", recDuration / 60));
stringTokens.insert(pair<string,string>("durationminutes", *cString::sprintf("%.2d", recDuration%60)));
intTokens.insert(pair<string,int>("durationevent", duration));
intTokens.insert(pair<string,int>("durationeventhours", duration / 60));
stringTokens.insert(pair<string,string>("durationeventminutes", *cString::sprintf("%.2d", duration%60)));
}
} else {
stringTokens.insert(pair<string,string>("epgname", ""));
stringTokens.insert(pair<string,string>("shorttext", ""));
stringTokens.insert(pair<string,string>("description", ""));
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
stringTokens.insert(pair<string,string>("date", ""));
stringTokens.insert(pair<string,string>("time", ""));
intTokens.insert(pair<string,int>("duration", recDuration));
intTokens.insert(pair<string,int>("durationhours", recDuration / 60));
stringTokens.insert(pair<string,string>("durationminutes", *cString::sprintf("%.2d", recDuration%60)));
intTokens.insert(pair<string,int>("durationevent", 0));
intTokens.insert(pair<string,int>("durationeventhours", 0));
stringTokens.insert(pair<string,string>("durationeventminutes", ""));
}
LoadRecordingInformation();
SetScraperTokens(event, recording, stringTokens, intTokens, loopTokens);
SetRecordingImages(recording->FileName());
} else if (text) {
stringTokens.insert(pair<string,string>("text", text));
} else {
intTokens.insert(pair<string,int>("running", false));
intTokens.insert(pair<string,int>("hasreruns", false));
}
}
void cDisplayMenuDetailView::InitTabs(void) {
tmplView->InitViewTabIterator();
cTemplateViewTab *tmplTab = NULL;
while(tmplTab = tmplView->GetNextViewTab()) {
tmplTab->ParseDynamicParameters(&intTokens, true);
tmplTab->ClearDynamicFunctionParameters();
tmplTab->ParseDynamicFunctionParameters(&stringTokens, &intTokens);
if (tmplTab->DoExecute()) {
activeTabs.push_back(tmplTab);
}
}
atIt = activeTabs.begin();
}
bool cDisplayMenuDetailView::LoadReruns(vector< map< string, string > > *reruns) {
if (!event)
return false;
cPlugin *epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
if (!epgSearchPlugin)
return false;
if (isempty(event->Title()))
return false;
int maxNumReruns = config.rerunAmount;
int rerunDistance = config.rerunDistance * 3600;
int rerunNaxChannel = config.rerunMaxChannel;
Epgsearch_searchresults_v1_0 data;
string strQuery = (event->Title()) ? event->Title() : "";
data.query = (char *)strQuery.c_str();
data.mode = 0;
data.channelNr = 0;
data.useTitle = true;
data.useSubTitle = true;
data.useDescription = false;
bool foundRerun = false;
if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
cList<Epgsearch_searchresults_v1_0::cServiceSearchResult>* list = data.pResultList;
if (list && (list->Count() > 1)) {
foundRerun = true;
int i = 0;
for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r && i < maxNumReruns; r = list->Next(r)) {
time_t eventStart = event->StartTime();
time_t rerunStart = r->event->StartTime();
cChannel *channel = Channels.GetByChannelID(r->event->ChannelID(), true, true);
//check for identical event
if ((event->ChannelID() == r->event->ChannelID()) && (eventStart == rerunStart))
continue;
//check for timely distance
if (rerunDistance > 0) {
if (rerunStart - eventStart < rerunDistance) {
continue;
}
}
//check for maxchannel
if (rerunNaxChannel > 0) {
if (channel && channel->Number() > rerunNaxChannel) {
continue;
}
}
i++;
map< string, string > rerun;
rerun.insert(pair<string, string>("reruns[title]", r->event->Title() ? r->event->Title() : ""));
rerun.insert(pair<string, string>("reruns[shorttext]", r->event->ShortText() ? r->event->ShortText() : ""));
rerun.insert(pair<string, string>("reruns[start]", *(r->event->GetTimeString())));
rerun.insert(pair<string, string>("reruns[start]", *(r->event->GetTimeString())));
rerun.insert(pair<string, string>("reruns[stop]", *(r->event->GetEndTimeString())));
rerun.insert(pair<string, string>("reruns[date]", *ShortDateString(r->event->StartTime())));
rerun.insert(pair<string, string>("reruns[day]", *WeekDayName(r->event->StartTime())));
string channelID = *(r->event->ChannelID().ToString());
rerun.insert(pair<string, string>("reruns[channelid]", channelID));
bool logoExists = imgCache->LogoExists(channelID);
rerun.insert(pair<string, string>("reruns[channellogoexists]", logoExists ? "1" : "0"));
if (channel) {
stringstream channelNumber;
channelNumber << channel->Number();
rerun.insert(pair<string, string>("reruns[channelname]", channel->ShortName(true)));
rerun.insert(pair<string, string>("reruns[channelnumber]", channelNumber.str()));
} else {
rerun.insert(pair<string, string>("reruns[channelname]", ""));
rerun.insert(pair<string, string>("reruns[channelnumber]", ""));
}
reruns->push_back(rerun);
}
delete list;
}
}
return foundRerun;
}
void cDisplayMenuDetailView::LoadRecordingInformation(void) {
const cRecordingInfo *Info = recording->Info();
if (!Info)
return;
unsigned long long nRecSize = -1;
unsigned long long nFileSize[1000];
nFileSize[0] = 0;
int i = 0;
struct stat filebuf;
cString filename;
int rc = 0;
do {
if (recording->IsPesRecording())
filename = cString::sprintf("%s/%03d.vdr", recording->FileName(), ++i);
else
filename = cString::sprintf("%s/%05d.ts", recording->FileName(), ++i);
rc = stat(filename, &filebuf);
if (rc == 0)
nFileSize[i] = nFileSize[i-1] + filebuf.st_size;
else
if (ENOENT != errno) {
nRecSize = -1;
}
} while (i <= 999 && !rc);
nRecSize = nFileSize[i-1];
cMarks marks;
bool fHasMarks = marks.Load(recording->FileName(), recording->FramesPerSecond(), recording->IsPesRecording()) && marks.Count();
cIndexFile *index = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
int nCutLength = 0;
long nCutInFrame = 0;
unsigned long long nRecSizeCut = nRecSize < 0 ? -1 : 0;
unsigned long long nCutInOffset = 0;
if (fHasMarks && index) {
uint16_t FileNumber;
off_t FileOffset;
bool fCutIn = true;
cMark *mark = marks.First();
while (mark) {
int pos = mark->Position();
index->Get(pos, &FileNumber, &FileOffset); //TODO: will disc spin up?
if (fCutIn) {
nCutInFrame = pos;
fCutIn = false;
if (nRecSize >= 0)
nCutInOffset = nFileSize[FileNumber-1] + FileOffset;
} else {
nCutLength += pos - nCutInFrame;
fCutIn = true;
if (nRecSize >= 0)
nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
}
cMark *nextmark = marks.Next(mark);
mark = nextmark;
}
if (!fCutIn) {
nCutLength += index->Last() - nCutInFrame;
index->Get(index->Last() - 1, &FileNumber, &FileOffset);
if (nRecSize >= 0)
nRecSizeCut += nFileSize[FileNumber-1] + FileOffset - nCutInOffset;
}
}
if (nRecSize < 0) {
if ((nRecSize = ReadSizeVdr(recording->FileName())) < 0) {
nRecSize = DirSizeMB(recording->FileName());
}
}
if (nRecSize >= 0) {
cString strRecSize = "";
cString strRecSizeCut = "";
if (fHasMarks) {
if (nRecSize > MEGABYTE(1023)) {
strRecSize = cString::sprintf("%.2f GB", (float)nRecSize / MEGABYTE(1024));
strRecSizeCut = cString::sprintf("%.2f GB", (float)nRecSizeCut / MEGABYTE(1024));
} else {
strRecSize = cString::sprintf("%lld MB", nRecSize / MEGABYTE(1));
strRecSizeCut = cString::sprintf("%lld MB", nRecSizeCut / MEGABYTE(1));
}
} else {
if (nRecSize > MEGABYTE(1023)) {
strRecSize = cString::sprintf("%.2f GB", (float)nRecSize / MEGABYTE(1024));
strRecSizeCut = strRecSize;
} else {
strRecSize = cString::sprintf("%lld MB", nRecSize / MEGABYTE(1));
strRecSizeCut = strRecSize;
}
}
stringTokens.insert(pair<string,string>("recordingsize", *strRecSize));
stringTokens.insert(pair<string,string>("recordingsizecutted", *strRecSizeCut));
} else {
stringTokens.insert(pair<string,string>("recordingsize", ""));
stringTokens.insert(pair<string,string>("recordingsizecutted", ""));
}
cChannel *channel = Channels.GetByChannelID(Info->ChannelID());
if (channel) {
stringTokens.insert(pair<string,string>("recchannelname", channel->Name()));
stringTokens.insert(pair<string,string>("recchannelid", *channel->GetChannelID().ToString()));
intTokens.insert(pair<string,int>("recchannelnumber", channel->Number()));
} else {
stringTokens.insert(pair<string,string>("recchannelname", ""));
stringTokens.insert(pair<string,string>("recchannelid", ""));
intTokens.insert(pair<string,int>("recchannelnumber", 0));
}
if (index) {
int nLastIndex = index->Last();
if (nLastIndex) {
string strLength = *IndexToHMSF(nLastIndex, false, recording->FramesPerSecond());
string strLengthCutted = "";
if (fHasMarks) {
strLengthCutted = *IndexToHMSF(nCutLength, false, recording->FramesPerSecond());
} else {
strLengthCutted = strLength;
}
string strBitrate = *cString::sprintf("%.2f MBit/s", (float)nRecSize / nLastIndex * recording->FramesPerSecond() * 8 / MEGABYTE(1));
stringTokens.insert(pair<string,string>("recordinglength", strLength));
stringTokens.insert(pair<string,string>("recordinglengthcutted", strLengthCutted));
stringTokens.insert(pair<string,string>("recordingbitrate", strBitrate));
}
delete index;
}
string recFormat = recording->IsPesRecording() ? "PES" : "TS";
stringTokens.insert(pair<string,string>("recordingformat", recFormat));
bool searchTimerFound = false;
if (Info) {
const char *aux = NULL;
aux = Info->Aux();
if (aux) {
string strAux = aux;
string auxEpgsearch = StripXmlTag(strAux, "epgsearch");
if (!auxEpgsearch.empty()) {
string searchTimer = StripXmlTag(auxEpgsearch, "searchtimer");
if (!searchTimer.empty()) {
stringTokens.insert(pair<string,string>("searchtimer", searchTimer));
searchTimerFound = true;
}
}
}
}
if (!searchTimerFound)
stringTokens.insert(pair<string,string>("searchtimer", "n.a."));
}
string cDisplayMenuDetailView::StripXmlTag(string &Line, const char *Tag) {
// set the search strings
stringstream strStart, strStop;
strStart << "<" << Tag << ">";
strStop << "</" << Tag << ">";
// find the strings
string::size_type locStart = Line.find(strStart.str());
string::size_type locStop = Line.find(strStop.str());
if (locStart == string::npos || locStop == string::npos)
return "";
// extract relevant text
int pos = locStart + strStart.str().size();
int len = locStop - pos;
return len < 0 ? "" : Line.substr(pos, len);
}
int cDisplayMenuDetailView::ReadSizeVdr(const char *strPath) {
int dirSize = -1;
char buffer[20];
char *strFilename = NULL;
if (-1 != asprintf(&strFilename, "%s/size.vdr", strPath)) {
struct stat st;
if (stat(strFilename, &st) == 0) {
int fd = open(strFilename, O_RDONLY);
if (fd >= 0) {
if (safe_read(fd, &buffer, sizeof(buffer)) >= 0) {
dirSize = atoi(buffer);
}
close(fd);
}
}
free(strFilename);
}
return dirSize;
}
void cDisplayMenuDetailView::SetEpgPictures(int eventId) {
for (int i=0; i<3; i++) {
stringstream picName;
picName << eventId << "_" << i;
bool epgPicAvailable = FileExists(*config.epgImagePath, picName.str(), "jpg");
stringstream available;
stringstream path;
available << "epgpic" << i+1 << "avaialble";
path << "epgpic" << i+1 << "path";
if (epgPicAvailable) {
intTokens.insert(pair<string,int>(available.str(), true));
stringTokens.insert(pair<string,string>(path.str(), *cString::sprintf("%s%s.jpg", *config.epgImagePath, picName.str().c_str())));
} else {
intTokens.insert(pair<string,int>(available.str(), false));
stringTokens.insert(pair<string,string>(path.str(), ""));
}
}
}
void cDisplayMenuDetailView::SetRecordingImages(const char *recPath) {
if (!recPath) {
intTokens.insert(pair<string,int>("recimg1avaialble", false));
intTokens.insert(pair<string,int>("recimg2avaialble", false));
intTokens.insert(pair<string,int>("recimg3avaialble", false));
stringTokens.insert(pair<string,string>("recimg1path", ""));
stringTokens.insert(pair<string,string>("recimg2path", ""));
stringTokens.insert(pair<string,string>("recimg3path", ""));
return;
}
string path = recPath;
DIR *dirHandle;
struct dirent *dirEntry;
dirHandle = opendir(recPath);
if (!dirHandle) {
intTokens.insert(pair<string,int>("recimg1avaialble", false));
intTokens.insert(pair<string,int>("recimg2avaialble", false));
intTokens.insert(pair<string,int>("recimg3avaialble", false));
stringTokens.insert(pair<string,string>("recimg1path", ""));
stringTokens.insert(pair<string,string>("recimg2path", ""));
stringTokens.insert(pair<string,string>("recimg3path", ""));
return;
}
int picsFound = 0;
while ( 0 != (dirEntry = readdir(dirHandle))) {
if (endswith(dirEntry->d_name, "jpg")) {
string fileName = dirEntry->d_name;
stringstream available;
available << "recimg" << picsFound+1 << "avaialble";
stringstream path;
path << "recimg" << picsFound+1 << "path";
intTokens.insert(pair<string,int>(available.str(), true));
stringTokens.insert(pair<string,string>(path.str(), *cString::sprintf("%s/%s", recPath, fileName.c_str())));
picsFound++;
}
if (picsFound == 3) {
break;
}
}
for (int i=picsFound; i<3; i++) {
stringstream available;
available << "recimg" << i+1 << "avaialble";
stringstream path;
path << "recimg" << i+1 << "path";
intTokens.insert(pair<string,int>(available.str(), false));
stringTokens.insert(pair<string,string>(path.str(), ""));
}
closedir(dirHandle);
}
void cDisplayMenuDetailView::DrawHeader(void) {
map < string, string > headerStringTokens;
map < string, int > headerIntTokens;
if (event || recording) {
static cPlugin *pScraper = GetScraperPlugin();
if (!pScraper) {
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
} else {
ScraperGetEventType getType;
getType.event = event;
getType.recording = recording;
if (!pScraper->Service("GetEventType", &getType)) {
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
} else {
if (getType.type == tMovie) {
cMovie movie;
movie.movieId = getType.movieId;
pScraper->Service("GetMovie", &movie);
headerIntTokens.insert(pair<string,int>("ismovie", true));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", true));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
headerStringTokens.insert(pair<string,string>("posterpath", movie.poster.path));
headerIntTokens.insert(pair<string,int>("posterwidth", movie.poster.width));
headerIntTokens.insert(pair<string,int>("posterheight", movie.poster.height));
} else if (getType.type == tSeries) {
cSeries series;
series.seriesId = getType.seriesId;
series.episodeId = getType.episodeId;
pScraper->Service("GetSeries", &series);
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", true));
vector<cTvMedia>::iterator poster = series.posters.begin();
if (poster != series.posters.end()) {
headerIntTokens.insert(pair<string,int>("posterwidth", (*poster).width));
headerIntTokens.insert(pair<string,int>("posterheight", (*poster).height));
headerStringTokens.insert(pair<string,string>("posterpath", (*poster).path));
headerIntTokens.insert(pair<string,int>("posteravailable", true));
} else {
headerIntTokens.insert(pair<string,int>("posterwidth", 0));
headerIntTokens.insert(pair<string,int>("posterheight", 0));
headerStringTokens.insert(pair<string,string>("posterpath", ""));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
}
vector<cTvMedia>::iterator banner = series.banners.begin();
if (banner != series.banners.end()) {
headerIntTokens.insert(pair<string,int>("bannerwidth", (*banner).width));
headerIntTokens.insert(pair<string,int>("bannerheight", (*banner).height));
headerStringTokens.insert(pair<string,string>("bannerpath", (*banner).path));
headerIntTokens.insert(pair<string,int>("banneravailable", true));
} else {
headerIntTokens.insert(pair<string,int>("bannerwidth", 0));
headerIntTokens.insert(pair<string,int>("bannerheight", 0));
headerStringTokens.insert(pair<string,string>("bannerpath", ""));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
}
} else {
headerIntTokens.insert(pair<string,int>("ismovie", false));
headerIntTokens.insert(pair<string,int>("isseries", false));
headerIntTokens.insert(pair<string,int>("posteravailable", false));
headerIntTokens.insert(pair<string,int>("banneravailable", false));
}
}
}
}
if (event) {
headerStringTokens.insert(pair<string,string>("title", event->Title() ? event->Title() : ""));
headerStringTokens.insert(pair<string,string>("shorttext", event->ShortText() ? event->ShortText() : ""));
headerStringTokens.insert(pair<string,string>("start", *(event->GetTimeString())));
headerStringTokens.insert(pair<string,string>("stop", *(event->GetEndTimeString())));
time_t startTime = event->StartTime();
headerStringTokens.insert(pair<string,string>("day", *WeekDayName(startTime)));
headerStringTokens.insert(pair<string,string>("date", *ShortDateString(startTime)));
struct tm * sStartTime = localtime(&startTime);
headerIntTokens.insert(pair<string, int>("year", sStartTime->tm_year + 1900));
headerIntTokens.insert(pair<string, int>("daynumeric", sStartTime->tm_mday));
headerIntTokens.insert(pair<string, int>("month", sStartTime->tm_mon+1));
const cChannel *channel = Channels.GetByChannelID(event->ChannelID());
if (channel) {
headerStringTokens.insert(pair<string,string>("channelname", channel->Name() ? channel->Name() : ""));
headerIntTokens.insert(pair<string, int>("channelnumber", channel->Number()));
} else {
headerStringTokens.insert(pair<string,string>("channelname", ""));
headerIntTokens.insert(pair<string, int>("channelnumber", 0));
}
string channelID = *(channel->GetChannelID().ToString());
headerStringTokens.insert(pair<string,string>("channelid", channelID));
headerIntTokens.insert(pair<string, int>("channellogoexists", imgCache->LogoExists(channelID)));
bool isRunning = false;
time_t now = time(NULL);
if ((now >= event->StartTime()) && (now <= event->EndTime()))
isRunning = true;
headerIntTokens.insert(pair<string,int>("running", isRunning));
if (isRunning) {
headerIntTokens.insert(pair<string,int>("elapsed", (now - event->StartTime())/60));
} else {
headerIntTokens.insert(pair<string,int>("elapsed", 0));
}
headerIntTokens.insert(pair<string,int>("duration", event->Duration() / 60));
headerIntTokens.insert(pair<string,int>("durationhours", event->Duration() / 3600));
headerStringTokens.insert(pair<string,string>("durationminutes", *cString::sprintf("%.2d", (event->Duration() / 60)%60)));
if (event->Vps())
headerStringTokens.insert(pair<string,string>("vps", *event->GetVpsString()));
else
headerStringTokens.insert(pair<string,string>("vps", ""));
stringstream epgImageName;
epgImageName << event->EventID();
bool epgPicAvailable = FileExists(*config.epgImagePath, epgImageName.str(), "jpg");
if (epgPicAvailable) {
headerIntTokens.insert(pair<string,int>("epgpicavailable", true));
headerStringTokens.insert(pair<string,string>("epgpicpath", *cString::sprintf("%s%s.jpg", *config.epgImagePath, epgImageName.str().c_str())));
} else {
epgImageName << "_0";
epgPicAvailable = FileExists(*config.epgImagePath, epgImageName.str(), "jpg");
if (epgPicAvailable) {
headerIntTokens.insert(pair<string,int>("epgpicavailable", true));
headerStringTokens.insert(pair<string,string>("epgpicpath", *cString::sprintf("%s%s.jpg", *config.epgImagePath, epgImageName.str().c_str())));
} else {
headerIntTokens.insert(pair<string,int>("epgpicavailable", false));
headerStringTokens.insert(pair<string,string>("epgpicpath", ""));
}
}
DrawViewElement(veDetailHeader, &headerStringTokens, &headerIntTokens);
return;
} else if (recording) {
string name = recording->Name() ? recording->Name() : "";
headerStringTokens.insert(pair<string,string>("name", name));
const cRecordingInfo *info = recording->Info();
if (info) {
headerStringTokens.insert(pair<string,string>("epgname", info->Title() ? info->Title() : name));
headerStringTokens.insert(pair<string,string>("shorttext", info->ShortText() ? info->ShortText() : ""));
const cEvent *event = info->GetEvent();
if (event) {
string recDate = *(event->GetDateString());
string recTime = *(event->GetTimeString());
if (recDate.find("1970") != string::npos) {
time_t start = recording->Start();
recDate = *DateString(start);
recTime = *TimeString(start);
}
int duration = event->Duration() / 60;
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
headerStringTokens.insert(pair<string,string>("date", recDate.c_str()));
headerStringTokens.insert(pair<string,string>("time", recTime.c_str()));
time_t startTime = event->StartTime();
struct tm * sStartTime = localtime(&startTime);
headerIntTokens.insert(pair<string, int>("year", sStartTime->tm_year + 1900));
headerIntTokens.insert(pair<string, int>("daynumeric", sStartTime->tm_mday));
headerIntTokens.insert(pair<string, int>("month", sStartTime->tm_mon+1));
headerIntTokens.insert(pair<string,int>("duration", recDuration));
headerIntTokens.insert(pair<string,int>("durationhours", recDuration / 60));
headerStringTokens.insert(pair<string,string>("durationminutes", *cString::sprintf("%.2d", recDuration%60)));
headerIntTokens.insert(pair<string,int>("durationevent", duration));
headerIntTokens.insert(pair<string,int>("durationeventhours", duration / 60));
headerStringTokens.insert(pair<string,string>("durationeventminutes", *cString::sprintf("%.2d", duration%60)));
}
cChannel *channel = Channels.GetByChannelID(info->ChannelID());
if (channel) {
headerStringTokens.insert(pair<string,string>("recchannelname", channel->Name()));
headerStringTokens.insert(pair<string,string>("recchannelid", *channel->GetChannelID().ToString()));
headerIntTokens.insert(pair<string,int>("recchannelnumber", channel->Number()));
} else {
headerStringTokens.insert(pair<string,string>("recchannelname", ""));
headerStringTokens.insert(pair<string,string>("recchannelid", ""));
headerIntTokens.insert(pair<string,int>("recchannelnumber", 0));
}
} else {
headerStringTokens.insert(pair<string,string>("shorttext", ""));
int recDuration = recording->LengthInSeconds();
recDuration = (recDuration>0)?(recDuration / 60):0;
headerStringTokens.insert(pair<string,string>("date", ""));
headerStringTokens.insert(pair<string,string>("time", ""));
headerIntTokens.insert(pair<string,int>("duration", recDuration));
headerIntTokens.insert(pair<string,int>("durationhours", recDuration / 60));
headerStringTokens.insert(pair<string,string>("durationminutes", *cString::sprintf("%.2d", recDuration%60)));
headerIntTokens.insert(pair<string,int>("durationevent", 0));
headerIntTokens.insert(pair<string,int>("durationeventhours", 0));
headerStringTokens.insert(pair<string,string>("durationeventminutes", ""));
headerStringTokens.insert(pair<string,string>("recchannelname", ""));
headerStringTokens.insert(pair<string,string>("recchannelid", ""));
headerIntTokens.insert(pair<string,int>("recchannelnumber", 0));
}
string recImage = "";
string path = recording->FileName() ? recording->FileName() : "";
string extension = ".jpg";
if (FirstFileInFolder(path, extension, recImage)) {
headerIntTokens.insert(pair<string,int>("recimgavailable", true));
headerStringTokens.insert(pair<string,string>("recimgpath", *cString::sprintf("%s/%s", path.c_str(), recImage.c_str())));
} else {
headerIntTokens.insert(pair<string,int>("recimgavailable", false));
headerStringTokens.insert(pair<string,string>("recimgpath", ""));
}
DrawViewElement(veDetailHeader, &headerStringTokens, &headerIntTokens);
return;
}
if (isPluginTextView) {
DrawViewElement(veDetailHeader, &stringTokens, &intTokens);
}
}
void cDisplayMenuDetailView::DrawScrollbar(void) {
map < string, string > scrollbarStringTokens;
map < string, int > scrollbarIntTokens;
int barTop = 0;
int barHeight = 0;
tabView->GetScrollbarPosition(barTop, barHeight);
scrollbarIntTokens.insert(pair<string,int>("height", barHeight));
scrollbarIntTokens.insert(pair<string,int>("offset", barTop));
ClearViewElement(veScrollbar);
DrawViewElement(veScrollbar, &scrollbarStringTokens, &scrollbarIntTokens);
}
void cDisplayMenuDetailView::DrawTabLabels(void) {
if (!ExecuteViewElement(veTabLabels)) {
return;
}
map < string, string > labelStringTokens;
map < string, int > labelIntTokens;
map < string, vector< map< string, string > > > labelLoopTokens;
string labelPrev = "";
string labelPrevTemp = "";
string labelCurrent = "";
string labelNext = "";
bool wasCurrent = false;
vector< map< string, string > > tabLabels;
for (list<cTemplateViewTab*>::iterator it = activeTabs.begin(); it != activeTabs.end(); it++) {
cTemplateViewTab *tab = *it;
map< string, string > tabLabel;
tabLabel.insert(pair< string, string >("tabs[title]", tab->GetName()));
if (wasCurrent) {
labelNext = tab->GetName();
}
if (tab == currentTmplTab) {
wasCurrent = true;
labelCurrent = tab->GetName();
labelPrev = labelPrevTemp;
tabLabel.insert(pair< string, string >("tabs[current]", "1"));
} else {
wasCurrent = false;
tabLabel.insert(pair< string, string >("tabs[current]", "0"));
}
labelPrevTemp = tab->GetName();
tabLabels.push_back(tabLabel);
}
if (labelNext.size() == 0 && activeTabs.size() > 0) {
cTemplateViewTab *firstTab = activeTabs.front();
labelNext = firstTab->GetName();
}
if (labelPrev.size() == 0 && activeTabs.size() > 0) {
cTemplateViewTab *lastTab = activeTabs.back();
labelPrev = lastTab->GetName();
}
labelStringTokens.insert(pair< string, string >("currenttab", labelCurrent));
labelStringTokens.insert(pair< string, string >("nexttab", labelNext));
labelStringTokens.insert(pair< string, string >("prevtab", labelPrev));
labelLoopTokens.insert(pair< string, vector< map< string, string > > >("tabs", tabLabels));
ClearViewElement(veTabLabels);
DrawViewElement(veTabLabels, &labelStringTokens, &labelIntTokens, &labelLoopTokens);
}
cTemplateViewTab *cDisplayMenuDetailView::GetPrevTab(void) {
if (atIt == activeTabs.begin()) {
atIt = activeTabs.end();
}
atIt--;
return *atIt;
}
cTemplateViewTab *cDisplayMenuDetailView::GetNextTab(void) {
atIt++;
if (atIt == activeTabs.end()) {
atIt = activeTabs.begin();
}
return *atIt;
}