Version 0.0.6

This commit is contained in:
louis 2013-07-09 00:17:42 +02:00
parent 6da4b610d9
commit 2a7a011055
61 changed files with 5564 additions and 201 deletions

View File

@ -43,7 +43,8 @@ VDR Plugin 'tvguide' Revision History
- Added setup option to switch functionality of keys "Blue" and "OK"
- Setup option to hide schedules time display in horizontal EPG grids
Version 0.0.6
2013-07-08: Version 0.0.6
- added frame around scaled video picture
- added theme "keep it simple" (thanks @saman)
- display of additional EPG pictures in detailed epg view
- Introduction of "Search & Recording" Menu

View File

@ -21,6 +21,7 @@ LIBDIR = $(call PKGCFG,libdir)
LOCDIR = $(call PKGCFG,locdir)
PLGCFG = $(call PKGCFG,plgcfg)
VDRCONFDIR= $(call PKGCFG,configdir)
PLGRESDIR = $(call PKGCFG,resdir)/plugins/$(PLUGIN)
TMPDIR ?= /tmp
### The compiler options:
@ -100,6 +101,7 @@ i18n: $(I18Nmo) $(I18Npot)
install-i18n: $(I18Nmsgs)
### Targets:
$(SOFILE): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) $(LIBS) -o $@
@ -110,7 +112,11 @@ install-themes:
@mkdir -p $(DESTDIR)$(VDRCONFDIR)/themes
cp themes/* $(DESTDIR)$(VDRCONFDIR)/themes
install: install-lib install-i18n install-themes
install-icons:
mkdir -p $(DESTDIR)$(PLGRESDIR)/icons
cp -r icons/* $(DESTDIR)$(PLGRESDIR)/icons
install: install-lib install-i18n install-themes install-icons
dist: $(I18Npo) clean
@-rm -rf $(TMPDIR)/$(ARCHIVE)

View File

@ -5,6 +5,7 @@ cChannelColumn::cChannelColumn(int num, const cChannel *channel, cMyTime *myTime
this->num = num;
this->myTime = myTime;
hasTimer = channel->HasTimer();
hasSwitchTimer = SwitchTimers.ChannelInSwitchList(channel);
schedulesLock = new cSchedulesLock(false, 100);
header = NULL;
}
@ -339,6 +340,22 @@ cGrid *cChannelColumn::addDummyGrid(time_t start, time_t end, cGrid *firstGrid,
return dummy;
}
void cChannelColumn::SetTimers() {
hasTimer = channel->HasTimer();
hasSwitchTimer = SwitchTimers.ChannelInSwitchList(channel);
for (cGrid *grid = grids.First(); grid; grid = grids.Next(grid)) {
bool gridHadTimer = grid->HasTimer();
grid->SetTimer();
if (gridHadTimer != grid->HasTimer())
grid->SetDirty();
bool gridHadSwitchTimer = grid->HasSwitchTimer();
grid->SetSwitchTimer();
if (gridHadSwitchTimer != grid->HasSwitchTimer())
grid->SetDirty();
grid->Draw();
}
}
void cChannelColumn::dumpGrids() {
esyslog("tvguide: ------Channel %s: %d entires ---------", channel->Name(), grids.Count());
int i=1;

View File

@ -16,6 +16,7 @@ private:
cSchedulesLock *schedulesLock;
const cSchedules *schedules;
bool hasTimer;
bool hasSwitchTimer;
cGrid *addEpgGrid(const cEvent *event, cGrid *firstGrid, bool color);
cGrid *addDummyGrid(time_t start, time_t end, cGrid *firstGrid, bool color);
public:
@ -42,8 +43,11 @@ public:
void ClearOutdatedEnd();
int GetNum() {return num;};
void SetNum(int num) {this->num = num;};
void setTimer() {hasTimer = true;};
void setTimer() {hasTimer = channel->HasTimer();};
bool HasTimer() { return hasTimer; };
void setSwitchTimer() {hasSwitchTimer = SwitchTimers.ChannelInSwitchList(channel);};
bool HasSwitchTimer() { return hasSwitchTimer; };
void SetTimers();
void clearGrids();
void dumpGrids();
};

View File

@ -81,6 +81,8 @@ cTvguideConfig::cTvguideConfig() {
FontGridHorizontalSmallDelta = 0;
FontTimeLineDateHorizontalDelta = 0;
FontTimeLineTimeHorizontalDelta = 0;
FontRecMenuItemDelta = 0;
FontRecMenuItemSmallDelta = 0;
//Common Fonts
FontButton = NULL;
FontDetailView = NULL;
@ -102,7 +104,9 @@ cTvguideConfig::cTvguideConfig() {
FontGridHorizontalSmall = NULL;
FontTimeLineDateHorizontal = NULL;
FontTimeLineTimeHorizontal = NULL;
//Fonts for RecMenu
FontRecMenuItem = NULL;
FontRecMenuItemSmall = NULL;
timeFormat = 1;
themeIndex = 4;
useBlending = 2;
@ -133,6 +137,8 @@ cTvguideConfig::~cTvguideConfig() {
delete FontGridHorizontalSmall;
delete FontTimeLineDateHorizontal;
delete FontTimeLineTimeHorizontal;
delete FontRecMenuItem;
delete FontRecMenuItemSmall;
}
void cTvguideConfig::setDynamicValues(int width, int height) {
@ -207,7 +213,9 @@ void cTvguideConfig::SetFonts(void){
FontGridHorizontalSmall = cFont::CreateFont(*fontname, rowHeight/4 + FontGridHorizontalSmallDelta);
FontTimeLineDateHorizontal = cFont::CreateFont(*fontname, timeLineHeight/2 + 5 + FontTimeLineDateHorizontalDelta);
FontTimeLineTimeHorizontal = cFont::CreateFont(*fontname, timeLineHeight/2 + FontTimeLineTimeHorizontalDelta);
//Fonts for RecMenu
FontRecMenuItem = cFont::CreateFont(*fontname, osdHeight/30 + FontRecMenuItemDelta);
FontRecMenuItemSmall = cFont::CreateFont(*fontname, osdHeight/40 + FontRecMenuItemSmallDelta);
}
void cTvguideConfig::SetBlending(void) {
@ -228,6 +236,10 @@ void cTvguideConfig::SetImagesPath(cString path) {
epgImagePath = path;
}
void cTvguideConfig::SetIconsPath(cString path) {
iconPath = path;
}
void cTvguideConfig::loadTheme() {
cThemes themes;
themes.Load(*cString("tvguide"));
@ -295,6 +307,8 @@ bool cTvguideConfig::SetupParse(const char *Name, const char *Value) {
else if (strcmp(Name, "FontGridHorizontalSmallDelta") == 0) FontGridHorizontalSmallDelta = atoi(Value);
else if (strcmp(Name, "FontTimeLineDateHorizontalDelta") == 0) FontTimeLineDateHorizontalDelta = atoi(Value);
else if (strcmp(Name, "FontTimeLineTimeHorizontalDelta") == 0) FontTimeLineTimeHorizontalDelta = atoi(Value);
else if (strcmp(Name, "FontRecMenuItemDelta") == 0) FontRecMenuItemDelta = atoi(Value);
else if (strcmp(Name, "FontRecMenuItemSmallDelta") == 0) FontRecMenuItemSmallDelta = atoi(Value);
else if (strcmp(Name, "displayRerunsDetailEPGView") == 0) displayRerunsDetailEPGView = atoi(Value);
else if (strcmp(Name, "numReruns") == 0) numReruns = atoi(Value);
else if (strcmp(Name, "useSubtitleRerun") == 0) useSubtitleRerun = atoi(Value);

View File

@ -10,6 +10,7 @@ class cTvguideConfig {
~cTvguideConfig();
void SetLogoPath(cString path);
void SetImagesPath(cString path);
void SetIconsPath(cString path);
void SetBlending(void);
int showMainMenuEntry;
int osdWidth;
@ -61,6 +62,7 @@ class cTvguideConfig {
int epgImageWidthLarge;
int epgImageHeightLarge;
cString epgImagePath;
cString iconPath;
int fontIndex;
const char *fontNameDefault;
int FontButtonDelta;
@ -83,6 +85,8 @@ class cTvguideConfig {
int FontGridHorizontalSmallDelta;
int FontTimeLineDateHorizontalDelta;
int FontTimeLineTimeHorizontalDelta;
int FontRecMenuItemDelta;
int FontRecMenuItemSmallDelta;
const cFont *FontChannelHeader;
const cFont *FontChannelHeaderHorizontal;
const cFont *FontChannelGroups;
@ -103,6 +107,8 @@ class cTvguideConfig {
const cFont *FontDetailHeader;
const cFont *FontMessageBox;
const cFont *FontMessageBoxLarge;
const cFont *FontRecMenuItem;
const cFont *FontRecMenuItemSmall;
int timeFormat;
int themeIndex;
int useBlending;

View File

@ -2,12 +2,9 @@
#include <sstream>
#include "detailview.h"
cDetailView::cDetailView(cGrid *grid) {
this->grid = grid;
this->event = grid->GetEvent();
cDetailView::cDetailView(const cEvent *event) {
this->event = event;
imgScrollBar = NULL;
FrameTime = 40; // ms
FadeTime = 500; // ms
borderWidth = 100; //px
scrollBarWidth = 40;
headerHeight = max (40 + 3 * tvguideConfig.FontDetailHeader->Height(), // border + 3 Lines
@ -48,24 +45,18 @@ bool cDetailView::setContentDrawportHeight() {
void cDetailView::createPixmaps() {
header = new cStyledPixmap(osdManager.requestPixmap(5, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null));
header->SetAlpha(0);
headerLogo = osdManager.requestPixmap(6, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null);
headerLogo->Fill(clrTransparent);
headerLogo->SetAlpha(0);
headerBack = osdManager.requestPixmap(4, cRect(borderWidth, borderWidth, tvguideConfig.osdWidth - 2*borderWidth, headerHeight), cRect::Null);
headerBack->SetAlpha(0);
headerBack->Fill(clrBlack);
header->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending));
content = osdManager.requestPixmap(5, cRect(borderWidth, borderWidth + headerHeight, tvguideConfig.osdWidth - 2*borderWidth - scrollBarWidth, tvguideConfig.osdHeight-2*borderWidth-headerHeight),
cRect(0,0, tvguideConfig.osdWidth - 2*borderWidth - scrollBarWidth, max(heightContent, tvguideConfig.osdHeight-2*borderWidth-headerHeight)));
content->SetAlpha(0);
header->setColor(theme.Color(clrHeader), theme.Color(clrHeaderBlending));
scrollBar = osdManager.requestPixmap(5, cRect(tvguideConfig.osdWidth-borderWidth-scrollBarWidth, borderWidth + headerHeight, scrollBarWidth, tvguideConfig.osdHeight-2*borderWidth-headerHeight));
scrollBar->SetAlpha(0);
footer = osdManager.requestPixmap(5, cRect(borderWidth, borderWidth + headerHeight + content->ViewPort().Height(), tvguideConfig.osdWidth - 2*borderWidth, 3));
footer->SetAlpha(0);
footer->Fill(theme.Color(clrBorder));
}
@ -79,7 +70,8 @@ void cDetailView::drawHeader() {
cImageLoader imgLoader;
bool logoDrawn = false;
if (!tvguideConfig.hideChannelLogos) {
if (imgLoader.LoadLogo(grid->column->getChannel()->Name(), logoWidth, logoHeight)) {
cString channelName = Channels.GetByChannelID(event->ChannelID())->Name();
if (imgLoader.LoadLogo(*channelName, logoWidth, logoHeight)) {
cImage logo = imgLoader.GetImage();
headerLogo->DrawImage(cPoint(10, (header->Height() - logoHeight)/2), logo);
logoDrawn = true;
@ -293,28 +285,21 @@ void cDetailView::drawEPGPictures(int height) {
}
}
void cDetailView::Action(void) {
drawHeader();
drawContent();
drawScrollbar();
uint64_t Start = cTimeMs::Now();
while (true) {
uint64_t Now = cTimeMs::Now();
cPixmap::Lock();
double t = min(double(Now - Start) / FadeTime, 1.0);
int Alpha = t * ALPHA_OPAQUE;
header->SetAlpha(Alpha);
headerBack->SetAlpha(Alpha);
headerLogo->SetAlpha(Alpha);
content->SetAlpha(Alpha);
scrollBar->SetAlpha(Alpha);
footer->SetAlpha(Alpha);
eOSState cDetailView::ProcessKey(eKeys Key) {
eOSState state = osContinue;
switch (Key & ~k_Repeat) {
case kUp:
scrollUp();
osdManager.flush();
cPixmap::Unlock();
int Delta = cTimeMs::Now() - Now;
if (Delta < FrameTime)
cCondWait::SleepMs(FrameTime - Delta);
if ((Now - Start) > FadeTime)
break;
case kDown:
scrollDown();
osdManager.flush();
break;
case kOk:
case kBack:
state = osEnd;
break;
}
return state;
}

View File

@ -5,9 +5,8 @@
class cEpgGrid;
class cDetailView : public cThread {
class cDetailView {
private:
cGrid *grid;
cStyledPixmap *header;
cPixmap *headerLogo;
cPixmap *headerBack;
@ -16,8 +15,6 @@ private:
cPixmap *footer;
const cEvent *event;
cImage *imgScrollBar;
int FrameTime;
int FadeTime;
cTextWrapper description;
cTextWrapper reruns;
int borderWidth;
@ -29,19 +26,19 @@ private:
int numEPGPics;
bool contentScrollable;
void loadReruns(void);
void drawHeader();
void drawContent();
void drawScrollbar();
int heightEPGPics(void);
void drawEPGPictures(int height);
cImage *createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend);
virtual void Action(void);
public:
cDetailView(cGrid *grid);
cDetailView(const cEvent *event);
virtual ~cDetailView(void);
void createPixmaps();
void drawHeader();
void drawContent();
void drawScrollbar();
void scrollUp();
void scrollDown();
eOSState ProcessKey(eKeys Key);
};
#endif //__TVGUIDE_DETAILVIEW_H

View File

@ -5,6 +5,7 @@ cDummyGrid::cDummyGrid(cChannelColumn *c, time_t start, time_t end) : cGrid(c) {
this->end = end;
strText = tr("No EPG Information available");
dummy = true;
hasTimer = false;
}
cDummyGrid::~cDummyGrid(void) {

View File

@ -7,6 +7,9 @@ cEpgGrid::cEpgGrid(cChannelColumn *c, const cEvent *event) : cGrid(c) {
hasTimer = false;
if (column->HasTimer())
hasTimer = event->HasTimer();
hasSwitchTimer = false;
if (column->HasSwitchTimer())
hasSwitchTimer = SwitchTimers.EventInSwitchList(event);
dummy = false;
}
@ -89,8 +92,6 @@ void cEpgGrid::drawText() {
pixmap->DrawText(cPoint(borderWidth, borderWidth + offset + i*textHeight), extText->GetLine(i), colorText, colorTextBack, tvguideConfig.FontGridSmall);
}
}
if (hasTimer)
drawRecIcon();
} else if (tvguideConfig.displayMode == eHorizontal) {
if (Width()/tvguideConfig.minutePixel < 10) {
int titleY = (tvguideConfig.rowHeight - tvguideConfig.FontGridHorizontal->Height())/2;
@ -107,14 +108,21 @@ void cEpgGrid::drawText() {
}
pixmap->DrawText(cPoint(borderWidth, titleY), *strTitle, colorText, colorTextBack, tvguideConfig.FontGridHorizontal);
}
if (hasSwitchTimer)
drawIcon("Switch", theme.Color(clrButtonYellow));
if (hasTimer)
drawIcon("REC", theme.Color(clrButtonRed));
}
void cEpgGrid::drawRecIcon() {
cString recIconText("REC");
int width = tvguideConfig.FontGrid->Width(*recIconText)+2*borderWidth;
int height = tvguideConfig.FontGrid->Height()+10;
pixmap->DrawRectangle( cRect(Width() - width - borderWidth, Height() - height - borderWidth, width, height), theme.Color(clrButtonRed));
pixmap->DrawText(cPoint(Width() - width, Height() - height - borderWidth/2), *recIconText, theme.Color(clrFont), theme.Color(clrButtonRed), tvguideConfig.FontGrid);
void cEpgGrid::drawIcon(cString iconText, tColor color) {
const cFont *font = (tvguideConfig.displayMode == eVertical)
?tvguideConfig.FontGrid
:tvguideConfig.FontGridHorizontalSmall;
int textWidth = font->Width(*iconText)+2*borderWidth;
int textHeight = font->Height()+10;
pixmap->DrawRectangle( cRect(Width() - textWidth - borderWidth, Height() - textHeight - borderWidth, textWidth, textHeight), color);
pixmap->DrawText(cPoint(Width() - textWidth, Height() - textHeight - borderWidth/2), *iconText, theme.Color(clrFont), color, font);
}
cString cEpgGrid::getTimeString(void) {

View File

@ -8,9 +8,8 @@ private:
const cEvent *event;
cTextWrapper *extText;
cString timeString;
bool hasTimer;
void drawText();
void drawRecIcon();
void drawIcon(cString iconText, tColor color);
time_t Duration(void) { return event->Duration(); };
public:
cEpgGrid(cChannelColumn *c, const cEvent *event);
@ -21,7 +20,8 @@ public:
const cEvent *GetEvent() {return event;};
time_t StartTime() { return event->StartTime(); };
time_t EndTime() { return event->EndTime(); };
void setTimer() {hasTimer = true;};
void SetTimer() {hasTimer = event->HasTimer();};
void SetSwitchTimer() {hasSwitchTimer = SwitchTimers.EventInSwitchList(event);};
cString getTimeString(void);
void debug();
};

View File

@ -38,7 +38,7 @@ void cFooter::DrawButton(const char *text, tColor color, tColor borderColor, int
}
void cFooter::drawRedButton() {
cString text(tr("Set Timer"));
cString text(tr("Search & Rec"));
DrawButton(*text, theme.Color(clrButtonRed), theme.Color(clrButtonRedBorder), 0);
}

7
grid.h
View File

@ -12,6 +12,8 @@ protected:
bool isColor1;
bool active;
bool dirty;
bool hasTimer;
bool hasSwitchTimer;
bool intersects(cGrid *neighbor);
virtual time_t Duration(void) {};
virtual void drawText(void) {};
@ -37,10 +39,13 @@ public:
virtual void SetStartTime(time_t start) {};
virtual void SetEndTime(time_t end) {};
int calcOverlap(cGrid *neighbor);
virtual void setTimer() {};
virtual void SetTimer() {};
virtual void SetSwitchTimer() {};
virtual cString getText(void) { return cString("");};
virtual cString getTimeString(void) { return cString("");};
bool Active(void) { return active; };
bool HasTimer() {return hasTimer;};
bool HasSwitchTimer() {return hasSwitchTimer;};
bool isDummy() { return dummy; };
virtual void debug() {};
};

View File

@ -24,8 +24,8 @@ void cHeaderGrid::createBackground(int num) {
width = tvguideConfig.channelHeaderWidth;
height = tvguideConfig.rowHeight;
}
pixmap = osdManager.requestPixmap(2, cRect(x, y, width, height));
pixmapLogo = osdManager.requestPixmap(3, cRect(x, y, width, height));
pixmap = osdManager.requestPixmap(1, cRect(x, y, width, height));
pixmapLogo = osdManager.requestPixmap(2, cRect(x, y, width, height));
if ((!pixmap) || (!pixmapLogo)){
return;
}

BIN
icons/arrow_left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

BIN
icons/arrow_right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

BIN
icons/delete_active.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
icons/delete_inactive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/edit_active.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
icons/edit_inactive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
icons/icon_backspace.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
icons/icon_del_ins.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
icons/icon_shift.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
icons/info_active.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
icons/info_inactive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

BIN
icons/no.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
icons/record_active.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
icons/record_inactive.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

BIN
icons/yes.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -59,8 +59,19 @@ bool cImageLoader::LoadAdditionalEPGImage(cString name) {
return true;
}
bool cImageLoader::LoadIcon(const char *cIcon, int size) {
if (size==0)
return false;
bool success = false;
success = LoadImage(cString(cIcon), tvguideConfig.iconPath, "png");
if (!success)
return false;
buffer.sample(Geometry(size, size));
return true;
}
bool cImageLoader::DrawBackground(tColor back, tColor blend, int width, int height) {
if ((width < 1) || (height < 1))
if ((width < 1) || (height < 1) || (width > 1920) || (height > 1080))
return false;
Color Back = Argb2Color(back);
Color Blend = Argb2Color(blend);

View File

@ -17,6 +17,7 @@ public:
bool LoadLogo(const char *logo, int width, int height);
bool LoadEPGImage(int eventID);
bool LoadAdditionalEPGImage(cString name);
bool LoadIcon(const char *cIcon, int size);
bool DrawBackground(tColor back, tColor blend, int width, int height);
private:
Image buffer;

View File

@ -1,6 +1,3 @@
#include <string>
#include <sstream>
#ifndef __TVGUIDE_OSDMANAGER_H
#define __TVGUIDE_OSDMANAGER_H
@ -56,31 +53,3 @@ void cOsdManager::releasePixmap(cPixmap *pixmap) {
return;
osd->DestroyPixmap(pixmap);
}
static std::string CutText(std::string text, int width, const cFont *font) {
if (width <= font->Size())
return text.c_str();
if (font->Width(text.c_str()) < width)
return text.c_str();
cTextWrapper twText;
twText.Set(text.c_str(), font, width);
std::string cuttedTextNative = twText.GetLine(0);
std::stringstream sstrText;
sstrText << cuttedTextNative << "...";
std::string cuttedText = sstrText.str();
int actWidth = font->Width(cuttedText.c_str());
if (actWidth > width) {
int overlap = actWidth - width;
int charWidth = font->Width(".");
if (charWidth == 0)
charWidth = 1;
int cutChars = overlap / charWidth;
if (cutChars > 0) {
cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
std::stringstream sstrText2;
sstrText2 << cuttedTextNative << "...";
cuttedText = sstrText2.str();
}
}
return cuttedText;
}

View File

@ -3,7 +3,7 @@ msgid ""
msgstr ""
"Project-Id-Version: vdr-tvguide 0.0.1\n"
"Report-Msgid-Bugs-To: <see README>\n"
"POT-Creation-Date: 2013-06-03 09:00+0200\n"
"POT-Creation-Date: 2013-07-07 13:43+0200\n"
"PO-Revision-Date: 2012-08-25 17:49+0200\n"
"Last-Translator: Horst\n"
"Language-Team: \n"
@ -21,8 +21,8 @@ msgstr "Wiederholungen dieser Sendung"
msgid "No EPG Information available"
msgstr "Keine EPG Daten verfügbar"
msgid "Set Timer"
msgstr "Aufnehmen"
msgid "Search & Rec"
msgstr "Search & Rec"
msgid "Channels back"
msgstr "Kanäle zurück"
@ -36,6 +36,336 @@ msgstr "Umschalten"
msgid "Detailed EPG"
msgstr "Detailiertes EPG"
msgid "Transp."
msgstr "Transp."
msgid "Timer Conflict"
msgstr "Timer Konflikt"
msgid "all Channels"
msgstr "alle Kanäle"
msgid "unknown channel"
msgstr "unbekannter Kanal"
msgid "Duration"
msgstr "Dauer"
msgid "min"
msgstr "min"
msgid "recorded at"
msgstr "aufgenommen am"
msgid "from"
msgstr "von"
msgid "Instant Record"
msgstr "Sofortaufnahme"
msgid "Delete Timer"
msgstr "Timer löschen"
msgid "Edit Timer"
msgstr "Timer bearbeiten"
msgid "Create Series Timer"
msgstr "Serientimer anlegen"
msgid "Create Search Timer"
msgstr "Suchtimer anlegen"
msgid "Create Switch Timer"
msgstr "Umschalttimer anlegen"
msgid "Delete Switch Timer"
msgstr "Umschalttimer löschen"
msgid "Search"
msgstr "Suchen"
msgid "Search in Recordings"
msgstr "In Aufnahmen suchen"
msgid "Check for Timer Conflicts"
msgstr "Auf Timerkoflikte prüfen"
msgid "Timer created"
msgstr "Timer angelegt"
msgid "Timer NOT created"
msgstr "Timer NICHT angelegt"
msgid "OK"
msgstr "OK"
msgid "Timer deleted"
msgstr "Timer gelöscht"
msgid "Timer"
msgstr "Timer"
msgid "still recording - really delete?"
msgstr "Aufzeichnung läuft - wirklich löschen?"
msgid "Yes"
msgstr "Ja"
msgid "No"
msgstr "Nein"
msgid "One"
msgstr "Ein"
msgid "detected"
msgstr "gefunden"
msgid "Timer Conflicts"
msgstr "Timerkonflikte"
msgid "Show conflict"
msgstr "Konflikt zeigen"
msgid "timers involved"
msgstr "Timer beteiligt"
msgid "Ignore Conflicts"
msgstr "Konflikte ignorieren"
msgid "Ignore Conflict"
msgstr "Konflikt ignorieren"
msgid "No Timer Conflicts found"
msgstr "Keine Timerkonflikte gefunden"
msgid "Close"
msgstr "Schließen"
msgid "Timer Active"
msgstr "Timer aktiv"
msgid "Priority"
msgstr "Priorität"
msgid "Lifetime"
msgstr "Lebensdauer"
msgid "Day"
msgstr "Tag"
msgid "Timer start time"
msgstr "Timer Start Zeit"
msgid "Timer stop time"
msgstr "Timer Stop Zeit"
msgid "Save"
msgstr "Speichern"
msgid "Cancel"
msgstr "Abbrechen"
msgid "Create Series Timer based on"
msgstr "Serientimer anlegen basierend auf"
msgid "Channel"
msgstr "Kanal"
msgid "Series Timer start time"
msgstr "Serientimer Start Zeit"
msgid "Series Timer stop time"
msgstr "Serientimer Stop Zeit"
msgid "Days to record"
msgstr "Tage"
msgid "Day to start"
msgstr "Beginnen am"
msgid "Create Timer"
msgstr "Timer anlegen"
msgid "Series Timer created"
msgstr "Serientimer angelegt"
msgid "Start"
msgstr "Start"
msgid "Stop"
msgstr "Stop"
msgid "Configure Search Timer based on"
msgstr "Suchtimer konfigurieren basierend auf"
msgid "Search Expression:"
msgstr "Suchausdruck:"
msgid "Continue"
msgstr "Weiter"
msgid "Configure Search Timer for Search String"
msgstr "Suchtimer konfigurieren für Suchbegriff"
msgid "Manually configure Options"
msgstr "Optionen manuell konfigurieren"
msgid "Use Template"
msgstr "Template benutzen"
msgid "Creating Search Timer"
msgstr "Suchtimer anlegen"
msgid "Search Term"
msgstr "Suchbegriff"
msgid "Using Template"
msgstr "Template"
msgid "Display Results for Search Timer"
msgstr "Ergebnisse für Suchtimer anzeigen"
msgid "Use other Template"
msgstr "Anderes Template benutzen"
msgid "Configure Search Timer Options for Search String"
msgstr "Suchtimer Optionen konfigurieren für Suchbegriff"
msgid "whole term must appear"
msgstr "vollständiger Ausdruck"
msgid "all terms must exist"
msgstr "alle Worte"
msgid "one term must exist"
msgstr "ein Wort"
msgid "exact match"
msgstr "exakt"
msgid "regular expression"
msgstr "Regulärer Ausdruck"
msgid "Search Mode"
msgstr "Suchmodus"
msgid "Use Title"
msgstr "Titel benutzen"
msgid "Use Subtitle"
msgstr "Untertitel benutzen"
msgid "Use Description"
msgstr "Beschreibung benutzen"
msgid "Limit Channels"
msgstr "Kanäle einschränken"
msgid "Start Channel"
msgstr "Startkanal"
msgid "Stop Channel"
msgstr "Stopkanal"
msgid "Use Time"
msgstr "Zeit benutzen"
msgid "Start after"
msgstr "Beginn nach"
msgid "Start before"
msgstr "Beginn vor"
msgid "search results for Search Timer"
msgstr "Treffer für Suchtimer"
msgid "search result for Search Timer"
msgstr "Treffer für Suchtimer"
msgid "Nothing found for Search String"
msgstr "Keine Treffer für Suchbegriff"
msgid "Search Timer sucessfully created."
msgstr "Suchtimer erfolgreich angelegt"
msgid "Search Timer update initialised"
msgstr "Suchtimer update initialisiert"
msgid "Search Timer NOT sucessfully created"
msgstr "Suchtimer NICHT erfolgreich angelegt"
msgid "Configure Options for Switchtimer"
msgstr "Optionen für Umschalttimer konfigurieren"
msgid "Minutes before switching"
msgstr "Minuten vor umschalten"
msgid "switch"
msgstr "umschalten"
msgid "announce only"
msgstr "nur ankündigen"
msgid "ask for switch"
msgstr "vor umschalten fragen"
msgid "Switch Mode"
msgstr "Umschaltmodus"
msgid "Create"
msgstr "Anlegen"
msgid "Switch Timer sucessfully created"
msgstr "Umschalttimer erfolgreich angelegt"
msgid "Switch Timer NOT sucessfully created"
msgstr "Umschalttimer NICHT erfolgreich angelegt"
msgid "Switch Timer deleted"
msgstr "Umschalttimer gelöscht"
msgid "Show Search Options"
msgstr "Suchoptionen anzeigen"
msgid "Perform Search"
msgstr "Suche ausführen"
msgid "Channel to Search"
msgstr "Suche auf Kanal"
msgid "Search in title"
msgstr "In Titel suchen"
msgid "Search in Subtitle"
msgstr "In Untertitel suchen"
msgid "Search in Description"
msgstr "In Beschreibung suchen"
msgid "search results for"
msgstr "Suchergebnisse für"
msgid "search result for"
msgstr "Suchergebnis für"
msgid "Adapt Search"
msgstr "Suche anpassen"
msgid "Found"
msgstr " "
msgid "recording"
msgstr "Aufnahme gefunden"
msgid "recordings"
msgstr "Aufnahmen gefunden"
msgid "for"
msgstr "für"
msgid "No recordings found for"
msgstr "Keine Aufnahmen gefunden für"
msgid "General Settings"
msgstr "Allgemeine Einstellungen"
@ -234,8 +564,8 @@ msgstr "Zeitleiste Datum Schriftgröße"
msgid "Timeline Time Font Size"
msgstr "Zeitleiste Zeit Schriftgröße"
msgid "Timer not set! There is already a timer for this item."
msgstr "Timer wurde nicht gesetzt! Es existiert bereits ein Timer für diese Sendung"
msgid "Search & Recording Menu Font Size"
msgstr "Suchen & Aufnehmen Menu Schriftgröße"
msgid "Timer set"
msgstr "Timer gesetzt"
msgid "Search & Recording Menu Small Font Size"
msgstr "Suchen & Aufnehmen Menu kleine Schriftgröße"

598
recmanager.c Normal file
View File

@ -0,0 +1,598 @@
#include <string>
#include <vector>
#include "recmanager.h"
static int CompareRecording(const void *p1, const void *p2) {
return (int)((*(cRecording **)p1)->Start() - (*(cRecording **)p2)->Start());
}
bool TVGuideTimerConflict::timerInvolved(int involvedID) {
int numConflicts = timerIDs.size();
for (int i=0; i<numConflicts; i++) {
if (timerIDs[i] == involvedID)
return true;
}
return false;
}
cRecManager::cRecManager(void) {
epgSearchPlugin = NULL;
epgSearchAvailable = false;
}
cRecManager::~cRecManager(void) {
}
void cRecManager::SetEPGSearchPlugin(void) {
epgSearchPlugin = cPluginManager::GetPlugin("epgsearch");
if (epgSearchPlugin) {
epgSearchAvailable = true;
}
}
cTimer *cRecManager::createTimer(const cEvent *event) {
cTimer *timer = new cTimer(event);
Timers.Add(timer);
Timers.SetModified();
isyslog("timer %s added (active)", *timer->ToDescr());
return timer;
}
void cRecManager::DeleteTimer(const cEvent *event) {
cTimer *t = Timers.GetMatch(event);
if (!t)
return;
DeleteTimer(t);
}
void cRecManager::DeleteTimer(int timerID) {
cTimer *t = Timers.Get(timerID);
if (!t)
return;
DeleteTimer(t);
}
void cRecManager::DeleteTimer(cTimer *timer) {
if (timer->Recording()) {
timer->Skip();
cRecordControls::Process(time(NULL));
}
isyslog("timer %s deleted", *timer->ToDescr());
Timers.Del(timer, true);
Timers.SetModified();
}
void cRecManager::SaveTimer(cTimer *timer, cRecMenu *menu) {
if (!timer)
return;
bool active = menu->GetBoolValue(1);
int prio = menu->GetIntValue(2);
int lifetime = menu->GetIntValue(3);
time_t day = menu->GetTimeValue(4);
int start = menu->GetIntValue(5);
int stop = menu->GetIntValue(6);
timer->SetDay(day);
timer->SetStart(start);
timer->SetStop(stop);
timer->SetPriority(prio);
timer->SetLifetime(lifetime);
if (timer->HasFlags(tfActive) && !active)
timer->ClrFlags(tfActive);
else if (!timer->HasFlags(tfActive) && active)
timer->SetFlags(tfActive);
timer->SetEventFromSchedule();
Timers.SetModified();
}
bool cRecManager::IsRecorded(const cEvent *event) {
cTimer *timer = Timers.GetMatch(event);
if (!timer)
return false;
return timer->Recording();
}
std::vector<TVGuideTimerConflict> cRecManager::CheckTimerConflict(void) {
/* TIMERCONFLICT FORMAT:
The result list looks like this for example when we have 2 timer conflicts at one time:
1190232780:152|30|50#152#45:45|10|50#152#45
'1190232780' is the time of the conflict in seconds since 1970-01-01.
It's followed by list of timers that have a conflict at this time:
'152|30|50#1 int editTimer(cTimer *timer, bool active, int prio, int start, int stop);
52#45' is the description of the first conflicting timer. Here:
'152' is VDR's timer id of this timer as returned from VDR's LSTT command
'30' is the percentage of recording that would be done (0...100)
'50#152#45' is the list of concurrent timers at this conflict
'45|10|50#152#45' describes the next conflict
*/
std::vector<TVGuideTimerConflict> results;
if (!epgSearchAvailable)
return results;
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
std::list<std::string> conflicts = epgSearch->handler->TimerConflictList();
int numConflicts = conflicts.size();
if (numConflicts > 0) {
for (std::list<std::string>::iterator it=conflicts.begin(); it != conflicts.end(); ++it) {
TVGuideTimerConflict sConflict;
splitstring s(it->c_str());
std::vector<std::string> flds = s.split(':');
if (flds.size() < 2)
continue;
sConflict.time = atoi(flds[0].c_str());
splitstring s2(flds[1].c_str());
std::vector<std::string> flds2 = s2.split('|');
if (flds2.size() < 3)
continue;
sConflict.timerID = atoi(flds2[0].c_str());
sConflict.percentPossible = atoi(flds2[1].c_str());
splitstring s3(flds2[2].c_str());
std::vector<std::string> flds3 = s3.split('#');
std::vector<int> timerIDs;
for (int k = 0; k < flds3.size(); k++) {
timerIDs.push_back(atoi(flds3[k].c_str()) - 1);
}
sConflict.timerIDs = timerIDs;
results.push_back(sConflict);
}
}
}
delete epgSearch;
int numConflicts = results.size();
time_t startTime = 0;
time_t endTime = 0;
for (int i=0; i < numConflicts; i++) {
cTimeInterval *unionSet = NULL;
int numTimers = results[i].timerIDs.size();
for (int j=0; j < numTimers; j++) {
const cTimer *timer = Timers.Get(results[i].timerIDs[j]);
if (timer) {
if (!unionSet) {
unionSet = new cTimeInterval(timer->StartTime(), timer->StopTime());
} else {
cTimeInterval *timerInterval = new cTimeInterval(timer->StartTime(), timer->StopTime());
cTimeInterval *newUnion = unionSet->Union(timerInterval);
delete unionSet;
delete timerInterval;
unionSet = newUnion;
}
}
}
results[i].timeStart = unionSet->Start();
results[i].timeStop = unionSet->Stop();
delete unionSet;
cTimeInterval *intersect = NULL;
for (int j=0; j < numTimers; j++) {
const cTimer *timer = Timers.Get(results[i].timerIDs[j]);
if (timer) {
if (!intersect) {
intersect = new cTimeInterval(timer->StartTime(), timer->StopTime());
} else {
cTimeInterval *timerInterval = new cTimeInterval(timer->StartTime(), timer->StopTime());
cTimeInterval *newIntersect = intersect->Intersect(timerInterval);
if (newIntersect) {
delete intersect;
intersect = newIntersect;
}
delete timerInterval;
}
}
}
results[i].overlapStart = intersect->Start();
results[i].overlapStop = intersect->Stop();
delete intersect;
}
return results;
}
cTimer *cRecManager::CreateSeriesTimer(cRecMenu *menu) {
bool active = menu->GetBoolValue(1);
int channelNumber = menu->GetIntValue(2);
int start = menu->GetIntValue(3);
int stop = menu->GetIntValue(4);
int weekdays = menu->GetIntValue(5);
time_t tday = menu->GetTimeValue(6);
int prio = menu->GetIntValue(7);
int lifetime = menu->GetIntValue(8);
cChannel *channel = Channels.GetByNumber(channelNumber);
cTimer *seriesTimer = new cTimer(false, false, channel);
seriesTimer->SetDay(tday);
seriesTimer->SetStart(start);
seriesTimer->SetStop(stop);
seriesTimer->SetPriority(prio);
seriesTimer->SetLifetime(lifetime);
seriesTimer->SetWeekDays(weekdays);
seriesTimer->SetFile("TITLE EPISODE");
if (active)
seriesTimer->SetFlags(tfActive);
else
seriesTimer->SetFlags(tfNone);
seriesTimer->SetEventFromSchedule();
Timers.Add(seriesTimer);
Timers.SetModified();
return seriesTimer;
}
std::vector<TVGuideEPGSearchTemplate> cRecManager::ReadEPGSearchTemplates(void) {
cString ConfigDir = cPlugin::ConfigDirectory("epgsearch");
cString epgsearchConf = "epgsearchtemplates.conf";
cString fileName = AddDirectory(*ConfigDir, *epgsearchConf);
std::vector<TVGuideEPGSearchTemplate> epgTemplates;
if (access(fileName, F_OK) == 0) {
FILE *f = fopen(fileName, "r");
if (f) {
char *s;
cReadLine ReadLine;
while ((s = ReadLine.Read(f)) != NULL) {
char *p = strchr(s, '#');
if (p)
*p = 0;
stripspace(s);
try {
if (!isempty(s)) {
std::string templ = s;
int posID = templ.find_first_of(":");
int posName = templ.find_first_of(":", posID+1);
std::string name = templ.substr(posID+1, posName - posID - 1);
std::string templValue = templ.substr(posName);
TVGuideEPGSearchTemplate tmp;
tmp.name = name;
tmp.templValue = templValue;
epgTemplates.push_back(tmp);
}
} catch (...){}
}
}
}
return epgTemplates;
}
std::string cRecManager::BuildEPGSearchString(cString searchString, std::string templValue) {
std::stringstream searchTimerString;
searchTimerString << "0:";
searchTimerString << *searchString;
searchTimerString << templValue;
return searchTimerString.str();
}
std::string cRecManager::BuildEPGSearchString(cString searchString, cRecMenu *menu) {
int searchMode = menu->GetIntValue(0);
bool useTitle = menu->GetBoolValue(1);
bool useSubTitle = menu->GetBoolValue(2);
bool useDescription = menu->GetBoolValue(3);
bool limitChannels = menu->GetBoolValue(4);
int startChannel = -1;
int stopChannel = -1;
if (limitChannels) {
startChannel = menu->GetIntValue(5);
stopChannel = menu->GetIntValue(6);
}
int after = 0;
int before = 0;
bool limitTime = (limitChannels)?menu->GetBoolValue(7):menu->GetBoolValue(5);
if (limitTime) {
after = (limitChannels)?menu->GetIntValue(8):menu->GetIntValue(6);
before = (limitChannels)?menu->GetIntValue(9):menu->GetIntValue(7);
}
std::stringstream searchTimerString;
//1 - unique search timer id
searchTimerString << "0:";
//2 - the search term
searchTimerString << *searchString;
//3 - use time? 0/1
//4 - start time in HHMM
//5 - stop time in HHMM
if (limitTime) {
searchTimerString << ":1:" << after << ":" << before << ":";
} else {
searchTimerString << ":0:::";
}
//6 - use channel? 0 = no, 1 = Interval, 2 = Channel group, 3 = FTA only
//7 - if 'use channel' = 1 then channel id[|channel id] in VDR format,
// one entry or min/max entry separated with |, if 'use channel' = 2
// then the channel group name
if (limitChannels) {
searchTimerString << "1:";
cChannel *startChan = Channels.GetByNumber(startChannel);
cChannel *stopChan = Channels.GetByNumber(stopChannel);
searchTimerString << *(startChan->GetChannelID().ToString());
searchTimerString << "|";
searchTimerString << *(stopChan->GetChannelID().ToString()) << ":";
} else {
searchTimerString << "0::";
}
//8 - match case? 0/1
searchTimerString << ":0";
/*9 - search mode:
0 - the whole term must appear as substring
1 - all single terms (delimiters are blank,',', ';', '|' or '~')
must exist as substrings.
2 - at least one term (delimiters are blank, ',', ';', '|' or '~')
must exist as substring.
3 - matches exactly
4 - regular expression */
searchTimerString << searchMode << ":";
//10 - use title? 0/1
if (useTitle)
searchTimerString << "1:";
else
searchTimerString << "0:";
//11 - use subtitle? 0/1
if (useSubTitle)
searchTimerString << "1:";
else
searchTimerString << "0:";
// 12 - use description? 0/1
if (useDescription)
searchTimerString << "1:";
else
searchTimerString << "0:";
//13 - use duration? 0/1
//14 - min duration in hhmm
//15 - max duration in hhmm
searchTimerString << "0:::";
//16 - use as search timer? 0/1
searchTimerString << "1:";
//17 - use day of week? 0/1
//18 - day of week (0 = Sunday, 1 = Monday...;
// -1 Sunday, -2 Monday, -4 Tuesday, ...; -7 Sun, Mon, Tue)
searchTimerString << "0::";
//19 - use series recording? 0/1
searchTimerString << "1:";
//20 - directory for recording
searchTimerString << ":";
//21 - priority of recording
//22 - lifetime of recording
searchTimerString << "99:99:";
//23 - time margin for start in minutes
//24 - time margin for stop in minutes
searchTimerString << "5:5:";
//25 - use VPS? 0/1
searchTimerString << "0:";
/*26 - action:
0 = create a timer
1 = announce only via OSD (no timer)
2 = switch only (no timer)
3 = announce via OSD and switch (no timer)
4 = announce via mail*/
searchTimerString << "0:";
/*27 - use extended EPG info? 0/1
28 - extended EPG info values. This entry has the following format
(delimiter is '|' for each category, '#' separates id and value):
1 - the id of the extended EPG info category as specified in
epgsearchcats.conf
2 - the value of the extended EPG info category
(a ':' will be translated to "!^colon^!", e.g. in "16:9") */
searchTimerString << "0::";
/*29 - avoid repeats? 0/1
30 - allowed repeats
31 - compare title when testing for a repeat? 0/1
32 - compare subtitle when testing for a repeat? 0/1/2
0 - no
1 - yes
2 - yes, if present
33 - compare description when testing for a repeat? 0/1
34 - compare extended EPG info when testing for a repeat?
This entry is a bit field of the category IDs.
35 - accepts repeats only within x days */
searchTimerString << "1:1:1:2:1:::";
/*36 - delete a recording automatically after x days
37 - but keep this number of recordings anyway
38 - minutes before switch (if action = 2)
39 - pause if x recordings already exist
40 - blacklist usage mode (0 none, 1 selection, 2 all)
41 - selected blacklist IDs separated with '|'
42 - fuzzy tolerance value for fuzzy searching
43 - use this search in favorites menu (0 no, 1 yes)
44 - id of a menu search template
45 - auto deletion mode (0 don't delete search timer, 1 delete after given
count of recordings, 2 delete after given days after first recording)
46 - count of recordings after which to delete the search timer
47 - count of days after the first recording after which to delete the search
timer
48 - first day where the search timer is active (see parameter 16)
49 - last day where the search timer is active (see parameter 16)
50 - ignore missing EPG categories? 0/1
51 - unmute sound if off when used as switch timer
52 - percentage of match when comparing the summary of two events (with 'avoid repeats')
53 - HEX representation of the content descriptors, each descriptor ID is represented with 2 chars
54 - compare date when testing for a repeat? (0=no, 1=same day, 2=same week, 3=same month) */
searchTimerString << "0::::0:::0::0:::::::::0";
//esyslog("tvguide: epgsearch String: %s", searchTimerString.str().c_str());
return searchTimerString.str();
}
const cEvent **cRecManager::PerformSearchTimerSearch(std::string epgSearchString, int &numResults) {
if (!epgSearchAvailable)
return NULL;
const cEvent **searchResults = NULL;
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
std::list<std::string> results = epgSearch->handler->QuerySearch(epgSearchString);
numResults = results.size();
if (numResults > 0) {
searchResults = new const cEvent *[numResults];
cSchedulesLock *schedulesLock;
const cSchedules *schedules;
schedules = cSchedules::Schedules(*schedulesLock);
const cEvent *event = NULL;
int index=0;
for (std::list<std::string>::iterator it=results.begin(); it != results.end(); ++it) {
try {
splitstring s(it->c_str());
std::vector<std::string> flds = s.split(':', 1);
int eventID = atoi(flds[1].c_str());
std::string channelID = flds[7];
tChannelID chanID = tChannelID::FromString(channelID.c_str());
cChannel *channel = Channels.GetByChannelID(chanID);
if (channel) {
const cSchedule *Schedule = NULL;
Schedule = schedules->GetSchedule(channel);
event = Schedule->GetEvent(eventID);
if (event) {
searchResults[index] = event;
} else
return NULL;
} else
return NULL;
index++;
} catch (...){}
}
}
}
return searchResults;
}
const cEvent **cRecManager::PerformSearch(cRecMenu *menu, bool withOptions, int &numResults) {
if (epgSearchAvailable) {
cString searchString = menu->GetStringValue(1);
Epgsearch_searchresults_v1_0 data;
data.query = (char *)*searchString;
int mode = 0;
int channelNr = 0;
bool useTitle = true;
bool useSubTitle = true;
bool useDescription = false;
if (withOptions) {
mode = menu->GetIntValue(2);
channelNr = menu->GetIntValue(3);
useTitle = menu->GetBoolValue(4);
useSubTitle = menu->GetBoolValue(5);
useDescription = menu->GetBoolValue(6);
}
data.mode = mode;
data.channelNr = channelNr;
data.useTitle = useTitle;
data.useSubTitle = useSubTitle;
data.useDescription = useDescription;
if (epgSearchPlugin->Service("Epgsearch-searchresults-v1.0", &data)) {
cList<Epgsearch_searchresults_v1_0::cServiceSearchResult> *list = data.pResultList;
int numElements = list->Count();
const cEvent **searchResults = NULL;
if (numElements > 0) {
searchResults = new const cEvent *[numElements];
numResults = numElements;
int index = 0;
for (Epgsearch_searchresults_v1_0::cServiceSearchResult *r = list->First(); r ; r = list->Next(r)) {
searchResults[index] = r->event;
index++;
}
}
delete list;
return searchResults;
}
}
return NULL;
}
int cRecManager::CreateSearchTimer(std::string epgSearchString) {
int timerID = -1;
if (!epgSearchAvailable)
return timerID;
Epgsearch_services_v1_1 *epgSearch = new Epgsearch_services_v1_1;
if (epgSearchPlugin->Service("Epgsearch-services-v1.1", epgSearch)) {
timerID = epgSearch->handler->AddSearchTimer(epgSearchString);
}
return timerID;
}
void cRecManager::UpdateSearchTimers(void) {
if (epgSearchAvailable) {
Epgsearch_updatesearchtimers_v1_0 data;
data.showMessage = false;
epgSearchPlugin->Service("Epgsearch-updatesearchtimers-v1.0", &data);
}
}
// announceOnly: 0 = switch, 1 = announce only, 2 = ask for switch
bool cRecManager::CreateSwitchTimer(const cEvent *event, cRecMenu *menu) {
int switchMinsBefore = menu->GetIntValue(1);
int announceOnly = menu->GetIntValue(2);
if (epgSearchAvailable) {
Epgsearch_switchtimer_v1_0 data;
data.event = event;
data.mode = 1;
data.switchMinsBefore = switchMinsBefore;
data.announceOnly = announceOnly;
data.success = false;
epgSearchPlugin->Service("Epgsearch-switchtimer-v1.0", &data);
cSwitchTimer *t = new cSwitchTimer(event);
SwitchTimers.Add(t);
return data.success;
}
return false;
}
void cRecManager::DeleteSwitchTimer(const cEvent *event) {
SwitchTimers.DeleteSwitchTimer(event);
if (epgSearchAvailable) {
Epgsearch_switchtimer_v1_0 data;
data.event = event;
data.mode = 2;
data.switchMinsBefore = 0;
data.announceOnly = 0;
data.success = false;
epgSearchPlugin->Service("Epgsearch-switchtimer-v1.0", &data);
}
}
cRecording **cRecManager::SearchForRecordings(cString searchString, int &numResults) {
cRecording **matchingRecordings = NULL;
int num = 0;
numResults = 0;
for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
std::string s1 = recording->Name();
std::string s2 = *searchString;
if (s1.empty() || s2.empty()) continue;
// tolerance for fuzzy searching: 90% of the shorter text length, but at least 1
int tolerance = std::max(1, (int)std::min(s1.size(), s2.size()) / 10);
bool match = FindIgnoreCase(s1, s2) >= 0 || FindIgnoreCase(s2, s1) >= 0;
if (!match) {
AFUZZY af = { NULL, NULL, NULL, NULL, NULL, NULL, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
if (s1.size() > 32) s1 = s1.substr(0, 32);
afuzzy_init(s1.c_str(), tolerance, 0, &af);
/* Checking substring */
int res = afuzzy_checkSUB(s2.c_str(), &af);
afuzzy_free(&af);
match = (res > 0);
}
if (!match) {
AFUZZY af = { NULL, NULL, NULL, NULL, NULL, NULL, { 0 }, { 0 }, 0, 0, 0, 0, 0, 0 };
if (s2.size() > 32) s2 = s2.substr(0, 32);
afuzzy_init(s2.c_str(), tolerance, 0, &af);
/* Checking substring */
int res = afuzzy_checkSUB(s1.c_str(), &af);
afuzzy_free(&af);
match = (res > 0);
}
if (match) {
matchingRecordings = (cRecording **)realloc(matchingRecordings, (num + 1) * sizeof(cRecording *));
matchingRecordings[num++] = recording;
}
}
if (num > 0) {
qsort(matchingRecordings, num, sizeof(cRecording *), CompareRecording);
numResults = num;
return matchingRecordings;
}
return NULL;
}

53
recmanager.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef __TVGUIDE_RECMMANAGER_H
#define __TVGUIDE_RECMMANAGER_H
class TVGuideTimerConflict {
public:
time_t time;
time_t timeStart;
time_t timeStop;
time_t overlapStart;
time_t overlapStop;
int percentPossible;
int timerID;
std::vector<int> timerIDs;
bool timerInvolved(int involvedID);
};
struct TVGuideEPGSearchTemplate {
public:
std::string name;
std::string templValue;
};
// --- cRecManager -------------------------------------------------------------
class cRecManager {
private:
cPlugin *epgSearchPlugin;
bool epgSearchAvailable;
void DeleteTimer(cTimer *timer);
public:
cRecManager (void);
void SetEPGSearchPlugin(void);
bool EpgSearchAvailable(void) {return epgSearchAvailable;};
cTimer *createTimer(const cEvent *event);
void DeleteTimer(const cEvent *event);
void DeleteTimer(int timerID);
void SaveTimer(cTimer *timer, cRecMenu *menu);
bool IsRecorded(const cEvent *event);
std::vector<TVGuideTimerConflict> CheckTimerConflict(void);
cTimer *CreateSeriesTimer(cRecMenu *menu);
std::string BuildEPGSearchString(cString searchString, cRecMenu *menu);
std::string BuildEPGSearchString(cString searchString, std::string templValue);
const cEvent **PerformSearchTimerSearch(std::string epgSearchString, int &numResults);
const cEvent **PerformSearch(cRecMenu *menu, bool withOptions, int &numResults);
std::vector<TVGuideEPGSearchTemplate> ReadEPGSearchTemplates(void);
int CreateSearchTimer(std::string epgSearchString);
void UpdateSearchTimers(void);
bool CreateSwitchTimer(const cEvent *event, cRecMenu *menu);
void DeleteSwitchTimer(const cEvent *event);
cRecording **SearchForRecordings(cString searchString, int &numResults);
virtual ~cRecManager (void);
};
#endif //__TVGUIDE_RECMMANAGER_H

525
recmenu.c Normal file
View File

@ -0,0 +1,525 @@
#include "recmenu.h"
// --- cRecMenu -------------------------------------------------------------
cRecMenu::cRecMenu(void) {
border = 10;
height = 2*border;
headerHeight = 0;
footerHeight = 0;
scrollHeight = 0;
scrollItemHeight = 0;
scrollable = false;
scrollbarWidth = 3 * border;
pixmapScrollBar = NULL;
imgScrollBar = NULL;
startIndex = 0;
stopIndex = 0;
numItems = 0;
header = NULL;
footer = NULL;
}
cRecMenu::~cRecMenu(void) {
if (header)
delete header;
menuItems.Clear();
if (footer)
delete footer;
if (pixmapScrollBar)
osdManager.releasePixmap(pixmapScrollBar);
if (imgScrollBar)
delete imgScrollBar;
}
void cRecMenu::SetWidthPercent(int percentOSDWidth) {
width = tvguideConfig.osdWidth * percentOSDWidth / 100;
x = (tvguideConfig.osdWidth - width) / 2;
}
void cRecMenu::SetWidthPixel(int pixel) {
width = pixel;
x = (tvguideConfig.osdWidth - width) / 2;
}
int cRecMenu::CalculateOptimalWidth(void) {
int optWidth = 0;
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
int itemWidth = item->GetWidth();
if (itemWidth > optWidth)
optWidth = itemWidth;
}
return optWidth;
}
void cRecMenu::AddMenuItem(cRecMenuItem *item, cRecMenuItem *before) {
if (!before)
menuItems.Add(item);
else
menuItems.Ins(item, before);
}
void cRecMenu::AddMenuItemScroll(cRecMenuItem *item) {
scrollHeight += item->GetHeight();
stopIndex++;
numItems++;
if (scrollItemHeight == 0)
scrollItemHeight = item->GetHeight();
menuItems.Add(item);
}
bool cRecMenu::CheckHeight(void) {
int nextHeight = headerHeight + footerHeight + scrollHeight + 2*border + 150;
if (nextHeight > tvguideConfig.osdHeight) {
scrollable = true;
return false;
}
return true;
}
void cRecMenu::CalculateHeight(void) {
height = 2*border;
if (header)
height += headerHeight;
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
height += item->GetHeight();
}
if (footer)
height += footerHeight;
y = (tvguideConfig.osdHeight - height) / 2;
if (scrollable) {
width += scrollbarWidth + border;
}
}
void cRecMenu::CreatePixmap(void) {
pixmap = osdManager.requestPixmap(3, cRect(x, y, width, height));
if (scrollable) {
int scrollBarX = x + width - scrollbarWidth - border;
int scrollBarY = y + border + headerHeight;
int scrollBarHeight = height - headerHeight - footerHeight - 2 * border;
pixmapScrollBar = osdManager.requestPixmap(4, cRect(scrollBarX, scrollBarY, scrollbarWidth, scrollBarHeight));
}
}
void cRecMenu::SetFooter(cRecMenuItem *footer) {
this->footer = footer;
footerHeight = footer->GetHeight();
height += footerHeight;
}
void cRecMenu::SetHeader(cRecMenuItem *header) {
this->header = header;
headerHeight = header->GetHeight();
height += headerHeight;
}
cRecMenuItem *cRecMenu::GetActiveMenuItem(void) {
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
if (item->isActive())
return item;
}
if (footer && footer->isActive())
return footer;
return NULL;
}
int cRecMenu::GetActive(bool withOffset) {
int numActive = withOffset?startIndex:0;
int i = 0;
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
if (item->isActive()) {
numActive += i;
break;
}
i++;
}
return numActive;
}
bool cRecMenu::ActivatePrev(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!scrollable && footer && footer->isActive()) {
Activate(footer, menuItems.Last());
return true;
} else if (activeItem) {
cRecMenuItem *prev = NULL;
for (cRecMenuItem *item = menuItems.Prev(activeItem); item; item = menuItems.Prev(item)) {
if (item->isSelectable()) {
prev = item;
break;
}
}
if (prev) {
Activate(activeItem , prev);
return true;
}
}
return false;
}
bool cRecMenu::ActivateNext(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (activeItem) {
cRecMenuItem *next = NULL;
for (cRecMenuItem *item = menuItems.Next(activeItem); item; item = menuItems.Next(item)) {
if (item->isSelectable()) {
next = item;
break;
}
}
if (next) {
Activate(activeItem , next);
return true;
} else if (!scrollable && footer && footer->isSelectable()) {
Activate(activeItem , footer);
return true;
}
}
return false;
}
void cRecMenu::Activate(cRecMenuItem *itemOld, cRecMenuItem *item) {
itemOld->setInactive();
itemOld->setBackground();
itemOld->Draw();
item->setActive();
item->setBackground();
item->Draw();
}
void cRecMenu::ScrollUp(void) {
if (footer && footer->isActive()) {
Activate(footer, menuItems.Last());
} else {
//get perv x items
int numNewItems = numItems / 2;
int numAdded = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(startIndex-1)) {
AddMenuItem(newItem, menuItems.First());
menuItems.Del(menuItems.Last(), true);
stopIndex--;
startIndex--;
numAdded++;
if (numAdded >= numNewItems)
break;
}
if (numAdded != 0) {
Arrange(true);
Display(true);
ActivatePrev();
}
}
}
void cRecMenu::ScrollDown(void) {
//get next x items
int numNewItems = numItems / 2;
int numAdded = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(stopIndex)) {
menuItems.Add(newItem);
menuItems.Del(menuItems.First(), true);
stopIndex++;
startIndex++;
numAdded++;
if (numAdded >= numNewItems)
break;
}
if (numAdded != 0) {
Arrange(true);
Display(true);
ActivateNext();
} else {
//last item reached, activate footer
if (footer) {
cRecMenuItem *activeItem = GetActiveMenuItem();
Activate(activeItem , footer);
}
}
}
void cRecMenu::JumpBegin(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!scrollable) {
cRecMenuItem *firstSelectable= NULL;
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
if (item->isSelectable()) {
firstSelectable = item;
break;
}
}
if (activeItem && firstSelectable) {
Activate(activeItem , firstSelectable);
}
} else {
activeItem->setInactive();
activeItem->setBackground();
if (footer)
footer->Draw();
menuItems.Clear();
int currentItem = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(currentItem)) {
AddMenuItem(newItem);
currentItem++;
if (currentItem >= numItems)
break;
}
Arrange(true);
startIndex = 0;
stopIndex = numItems-1;
menuItems.First()->setActive();
menuItems.First()->setBackground();
menuItems.First()->Draw();
Display(true);
}
}
void cRecMenu::JumpEnd(void) {
cRecMenuItem *activeItem = GetActiveMenuItem();
if (!activeItem)
return;
if (!scrollable) {
cRecMenuItem *lastSelectable= NULL;
if (footer && footer->isSelectable()) {
lastSelectable = footer;
} else {
for (cRecMenuItem *item = menuItems.Last(); item; item = menuItems.Prev(item)) {
if (item->isSelectable()) {
lastSelectable = item;
break;
}
}
}
if (lastSelectable) {
Activate(activeItem , lastSelectable);
}
} else {
activeItem->setInactive();
activeItem->setBackground();
menuItems.Clear();
int totalNumItems = GetTotalNumMenuItems();
int currentItem = totalNumItems-1;
int itemsAdded = 0;
cRecMenuItem *newItem = NULL;
while (newItem = GetMenuItem(currentItem)) {
AddMenuItem(newItem, menuItems.First());
currentItem--;
itemsAdded++;
if (itemsAdded >= numItems)
break;
}
Arrange(true);
stopIndex = totalNumItems;
startIndex = stopIndex - numItems;
if (footer) {
footer->setActive();
footer->setBackground();
footer->Draw();
} else {
menuItems.Last()->setActive();
menuItems.Last()->setBackground();
menuItems.Last()->Draw();
}
Display(true);
}
}
void cRecMenu::Arrange(bool scroll) {
int xElement = x + border;
int yElement = y + border;
int widthElement = width - 2 * border;
if (scrollable)
widthElement -= scrollbarWidth + border;
if (header) {
if (!scroll) {
header->SetGeometry(xElement, yElement, widthElement);
header->SetPixmaps();
}
yElement += header->GetHeight();
}
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
item->SetGeometry(xElement, yElement, widthElement);
item->SetPixmaps();
yElement += item->GetHeight();
}
if (footer && !scroll) {
footer->SetGeometry(xElement, yElement, widthElement);
footer->SetPixmaps();
}
}
void cRecMenu::Display(bool scroll) {
pixmap->Fill(theme.Color(clrBackground));
drawBorder();
if (header && !scroll) {
header->setBackground();
header->Draw();
}
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
item->setBackground();
item->Draw();
}
if (footer && !scroll) {
footer->setBackground();
footer->Draw();
}
if (scrollable)
DrawScrollBar();
}
void cRecMenu::Hide(void) {
pixmap->SetLayer(-1);
if (pixmapScrollBar)
pixmapScrollBar->SetLayer(-1);
if (header)
header->Hide();
if (footer)
footer->Hide();
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
item->Hide();
}
}
void cRecMenu::Show(void) {
pixmap->SetLayer(3);
if (pixmapScrollBar)
pixmapScrollBar->SetLayer(3);
if (header)
header->Show();
if (footer)
footer->Show();
for (cRecMenuItem *item = menuItems.First(); item; item = menuItems.Next(item)) {
item->Show();
}
}
void cRecMenu::DrawScrollBar(void) {
pixmapScrollBar->Fill(theme.Color(clrBorder));
pixmapScrollBar->DrawRectangle(cRect(2,2,pixmapScrollBar->ViewPort().Width()-4, pixmapScrollBar->ViewPort().Height() - 4), theme.Color(clrBackground));
int totalNumItems = GetTotalNumMenuItems();
if (imgScrollBar == NULL) {
int scrollBarImgHeight = (pixmapScrollBar->ViewPort().Height() - 8) * numItems / totalNumItems;
imgScrollBar = createScrollbar(pixmapScrollBar->ViewPort().Width()-8, scrollBarImgHeight, theme.Color(clrHighlight), theme.Color(clrHighlightBlending));
}
int offset = (pixmapScrollBar->ViewPort().Height() - 8) * startIndex / totalNumItems;
pixmapScrollBar->DrawImage(cPoint(4, 2 + offset), *imgScrollBar);
}
int cRecMenu::GetIntValue(int itemNumber) {
cRecMenuItem *item = NULL;
item = menuItems.Get(itemNumber);
if (item) {
return item->GetIntValue();
}
return -1;
}
time_t cRecMenu::GetTimeValue(int itemNumber) {
cRecMenuItem *item = NULL;
item = menuItems.Get(itemNumber);
if (item) {
return item->GetTimeValue();
}
return 0;
}
bool cRecMenu::GetBoolValue(int itemNumber) {
cRecMenuItem *item = NULL;
item = menuItems.Get(itemNumber);
if (item) {
return item->GetBoolValue();
}
return false;
}
cString cRecMenu::GetStringValue(int itemNumber) {
cRecMenuItem *item = NULL;
item = menuItems.Get(itemNumber);
if (item) {
return item->GetStringValue();
}
return cString("");
}
const cEvent *cRecMenu::GetEventValue(int itemNumber) {
cRecMenuItem *item = NULL;
item = menuItems.Get(itemNumber);
if (item) {
return item->GetEventValue();
}
return NULL;
}
eRecMenuState cRecMenu::ProcessKey(eKeys Key) {
cRecMenuItem *activeItem = GetActiveMenuItem();
eRecMenuState state = rmsContinue;
if (!activeItem)
return state;
state = activeItem->ProcessKey(Key);
if (state == rmsRefresh) {
CreateMenuItems();
Display();
} else if (state == rmsNotConsumed) {
switch (Key & ~k_Repeat) {
case kUp:
if (!ActivatePrev() && scrollable)
ScrollUp();
state = rmsConsumed;
break;
case kDown:
if (!ActivateNext() && scrollable)
ScrollDown();
state = rmsConsumed;
break;
case kLeft:
JumpBegin();
state = rmsConsumed;
break;
case kRight:
JumpEnd();
state = rmsConsumed;
break;
default:
break;
}
}
return state;
}
cImage *cRecMenu::createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend) {
cImage *image = new cImage(cSize(width, height));
image->Fill(clrBgr);
if (tvguideConfig.useBlending) {
int numSteps = 64;
int alphaStep = 0x03;
if (height < 30)
return image;
else if (height < 100) {
numSteps = 32;
alphaStep = 0x06;
}
int stepY = 0.5*height / numSteps;
if (stepY == 0)
stepY = 1;
int alpha = 0x40;
tColor clr;
for (int i = 0; i<numSteps; i++) {
clr = AlphaBlend(clrBgr, clrBlend, alpha);
for (int y = i*stepY; y < (i+1)*stepY; y++) {
for (int x=0; x<width; x++) {
image->SetPixel(cPoint(x,y), clr);
}
}
alpha += alphaStep;
}
}
return image;
}

61
recmenu.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef __TVGUIDE_RECMENU_H
#define __TVGUIDE_RECMENU_H
// --- cRecMenu -------------------------------------------------------------
class cRecMenu : public cStyledPixmap {
protected:
int x, y;
int width, height;
int headerHeight, footerHeight;
int scrollHeight;
int scrollItemHeight;
int scrollbarWidth;
cPixmap *pixmapScrollBar;
cImage *imgScrollBar;
int border;
bool scrollable;
int numItems;
int startIndex, stopIndex;
cRecMenuItem *header;
cRecMenuItem *footer;
cList<cRecMenuItem> menuItems;
void SetWidthPercent(int percentOSDWidth);
void SetWidthPixel(int pixel);
int CalculateOptimalWidth(void);
bool CheckHeight(void);
void CalculateHeight(void);
void CreatePixmap(void);
void SetHeader(cRecMenuItem *header);
void SetFooter(cRecMenuItem *footer);
void AddMenuItemScroll(cRecMenuItem *item);
void AddMenuItem(cRecMenuItem *item, cRecMenuItem *before = NULL);
cRecMenuItem *GetActiveMenuItem(void);
bool ActivateNext(void);
bool ActivatePrev(void);
void Activate(cRecMenuItem *itemOld, cRecMenuItem *item);
void ScrollUp(void);
void ScrollDown(void);
void JumpBegin(void);
void JumpEnd(void);
void DrawScrollBar(void);
cImage *createScrollbar(int width, int height, tColor clrBgr, tColor clrBlend);
void Arrange(bool scroll = false);
virtual cRecMenuItem *GetMenuItem(int number) { return NULL; };
virtual int GetTotalNumMenuItems(void) { return 0; };
virtual void CreateMenuItems(void) {};
public:
cRecMenu(void);
virtual ~cRecMenu(void);
void Display(bool scroll = false);
void Hide(void);
void Show(void);
int GetActive(bool withOffset);
int GetIntValue(int itemNumber);
time_t GetTimeValue(int itemNumber);
bool GetBoolValue(int itemNumber);
cString GetStringValue(int itemNumber);
const cEvent *GetEventValue(int itemNumber);
eRecMenuState ProcessKey(eKeys Key);
};
#endif //__TVGUIDE_RECMENU_H

2016
recmenuitem.c Normal file

File diff suppressed because it is too large Load Diff

465
recmenuitem.h Normal file
View File

@ -0,0 +1,465 @@
#ifndef __TVGUIDE_RECMENUITEM_H
#define __TVGUIDE_RECMENUITEM_H
#define AUTO_ADVANCE_TIMEOUT 1500
enum eRecMenuState {
rmsConsumed,
rmsNotConsumed,
rmsRefresh,
rmsContinue,
rmsClose,
rmsInstantRecord,
rmsIgnoreTimerConflict,
rmsDeleteTimerConflictMenu,
rmsEditTimerConflictMenu,
rmsSaveTimerConflictMenu,
rmsTimerConflictShowInfo,
rmsDeleteTimer,
rmsDeleteTimerConfirmation,
rmsEditTimer,
rmsSaveTimer,
rmsSearch,
rmsSearchWithOptions,
rmsSearchPerform,
rmsSearchShowInfo,
rmsSearchRecord,
rmsSearchRecordConfirm,
rmsSearchNothingFoundConfirm,
rmsSeriesTimer,
rmsSeriesTimerCreate,
rmsSearchTimer,
rmsSearchTimerOptions,
rmsSearchTimerOptionsReload,
rmsSearchTimerUseTemplate,
rmsSearchTimerOptionsManually,
rmsSearchTimerTestManually,
rmsSearchTimerTestTemplate,
rmsSearchTimerNothingFoundConfirm,
rmsSearchTimerCreateManually,
rmsSearchTimerCreateTemplate,
rmsSwitchTimer,
rmsSwitchTimerCreate,
rmsSwitchTimerDelete,
rmsRecordingSearch,
rmsRecordingSearchResult,
rmsTimerConflict,
rmsTimerConflicts,
rmsDisabled,
};
enum eDependend {
eGreater,
eLower,
};
// --- cRecMenuItem -------------------------------------------------------------
class cRecMenuItem : public cListObject, public cStyledPixmap {
protected:
int x, y;
int width, height;
bool selectable;
bool active;
bool drawn;
eRecMenuState action;
tColor colorText;
tColor colorTextBack;
const cFont *font;
const cFont *fontSmall;
public:
cRecMenuItem(void);
virtual ~cRecMenuItem(void);
void SetGeometry(int x, int y, int width);
virtual void SetPixmaps(void);
virtual int GetHeight(void) { return height; };
virtual int GetWidth(void) { return 0; };
virtual void CalculateHeight(int textWidth) {};
void setActive(void) { this->active = true; }
void setInactive(void) { this->active = false; }
bool isSelectable(void) { return selectable; }
bool isActive(void) { return active; }
virtual void setBackground(void);
virtual void Draw(void) {};
virtual void Hide(void) { pixmap->SetLayer(-1);};
virtual void Show(void) { pixmap->SetLayer(4);};
virtual int GetIntValue(void) { return -1; };
virtual time_t GetTimeValue(void) { return 0; };
virtual bool GetBoolValue(void) { return false; };
virtual cString GetStringValue(void) { return cString(""); };
virtual const cEvent *GetEventValue(void) { return NULL; };
virtual eRecMenuState ProcessKey(eKeys Key) { return rmsNotConsumed; };
};
// --- cRecMenuItemButton -------------------------------------------------------
class cRecMenuItemButton : public cRecMenuItem {
private:
cString text;
bool halfWidth;
public:
cRecMenuItemButton(const char *text, eRecMenuState action, bool active, bool halfWidth = false);
virtual ~cRecMenuItemButton(void);
int GetWidth(void);
void SetPixmaps(void);
void Draw(void);
eRecMenuState ProcessKey(eKeys Key);
};
// --- cRecMenuItemButtonYesNo -------------------------------------------------------
class cRecMenuItemButtonYesNo : public cRecMenuItem {
private:
cString textYes;
cString textNo;
eRecMenuState actionNo;
bool yesActive;
cStyledPixmap *pixmapNo;
tColor colorTextNo;
public:
cRecMenuItemButtonYesNo(cString textYes,
cString textNo,
eRecMenuState actionYes,
eRecMenuState actionNo,
bool active);
virtual ~cRecMenuItemButtonYesNo(void);
void SetPixmaps(void);
void setBackground(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
};
// --- cRecMenuItemInfo -------------------------------------------------------
class cRecMenuItemInfo : public cRecMenuItem {
private:
cString text;
cTextWrapper wrapper;
int border;
public:
cRecMenuItemInfo(const char *text);
virtual ~cRecMenuItemInfo(void);
void setBackground(void);
void CalculateHeight(int textWidth);
void Draw(void);
};
// --- cRecMenuItemInt -------------------------------------------------------
class cRecMenuItemInt : public cRecMenuItem {
private:
cString text;
int currentVal;
int minVal;
int maxVal;
cPixmap *pixmapVal;
bool fresh;
void DrawValue(void);
public:
cRecMenuItemInt(cString text,
int initialVal,
int minVal,
int maxVal,
bool active);
virtual ~cRecMenuItemInt(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
void setBackground(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
int GetIntValue(void) { return currentVal; };
};
// --- cRecMenuItemBool -------------------------------------------------------
class cRecMenuItemBool : public cRecMenuItem {
private:
cString text;
bool yes;
cPixmap *pixmapVal;
bool refresh;
void DrawValue(void);
public:
cRecMenuItemBool(cString text,
bool initialVal,
bool refresh,
bool active);
virtual ~cRecMenuItemBool(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
bool GetBoolValue(void) { return yes; };
};
// --- cRecMenuItemSelect -------------------------------------------------------
class cRecMenuItemSelect : public cRecMenuItem {
private:
cString text;
int currentVal;
const char * const *strings;
int numValues;
cPixmap *pixmapVal;
void DrawValue(void);
public:
cRecMenuItemSelect(cString text,
const char * const *Strings,
int initialVal,
int numValues,
bool active);
virtual ~cRecMenuItemSelect(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
int GetIntValue(void) { return currentVal; };
cString GetStringValue(void) { return strings[currentVal]; };
};
// --- cRecMenuItemText -------------------------------------------------------
class cRecMenuItemText : public cRecMenuItem {
private:
cString title;
char *value;
int length;
const char *allowed;
int pos, offset;
bool insert, newchar, uppercase;
int lengthUtf8;
uint *valueUtf8;
uint *allowedUtf8;
uint *charMapUtf8;
uint *currentCharUtf8;
eKeys lastKey;
cTimeMs autoAdvanceTimeout;
cPixmap *pixmapVal;
cStyledPixmap *pixmapKeyboard;
cPixmap *pixmapKeyboardHighlight;
cPixmap *pixmapKeyboardIcons;
int keyboardWidth;
int gridWidth;
int gridHeight;
int keyboardHeight;
bool keyboardDrawn;
uint *IsAllowed(uint c);
void AdvancePos(void);
uint Inc(uint c, bool Up);
void Type(uint c);
void Insert(void);
void Delete(void);
void EnterEditMode(void);
void LeaveEditMode(bool SaveValue = false);
bool InEditMode(void) { return valueUtf8 != NULL; };
void SetText(void);
void ActivateKeyboard(void);
void DeactivateKeyboard(void);
void HighlightSMSKey(int num);
void ClearSMSKey(void);
char *GetSMSKeys(int num);
void DrawValue(char *newValue);
public:
cRecMenuItemText(cString title,
char *initialVal,
int length,
bool active);
virtual ~cRecMenuItemText(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
void setBackground(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
cString GetStringValue(void) { return value; };
};
// --- cRecMenuItemTime -------------------------------------------------------
class cRecMenuItemTime : public cRecMenuItem {
private:
cString text;
int value;
int mm;
int hh;
int pos;
bool fresh;
cPixmap *pixmapVal;
void DrawValue(void);
public:
cRecMenuItemTime(cString text,
int initialVal,
bool active);
virtual ~cRecMenuItemTime(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
int GetIntValue(void) { return value; };
};
// --- cRecMenuItemDay -------------------------------------------------------
class cRecMenuItemDay : public cRecMenuItem {
private:
cString text;
time_t currentVal;
cPixmap *pixmapVal;
void DrawValue(void);
public:
cRecMenuItemDay(cString text,
time_t initialVal,
bool active);
virtual ~cRecMenuItemDay(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
time_t GetTimeValue(void) { return currentVal; };
};
// --- cRecMenuItemTimer -------------------------------------------------------
class cRecMenuItemTimer : public cRecMenuItem {
private:
const cTimer *timer;
eRecMenuState action2;
eRecMenuState action3;
int iconActive;
cPixmap *pixmapIcons;
cPixmap *pixmapStatus;
time_t conflictStart;
time_t conflictStop;
time_t overlapStart;
time_t overlapStop;
int DrawIcons(void);
void DrawTimerConflict(void);
public:
cRecMenuItemTimer(const cTimer *timer,
eRecMenuState action1,
eRecMenuState action2,
eRecMenuState action3,
time_t conflictStart,
time_t conflictStop,
time_t overlapStart,
time_t overlapStop,
bool active);
virtual ~cRecMenuItemTimer(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
};
// --- cRecMenuItemTimerConflictHeader -------------------------------------------------------
class cRecMenuItemTimerConflictHeader: public cRecMenuItem {
private:
cPixmap *pixmapStatus;
time_t conflictStart;
time_t conflictStop;
time_t overlapStart;
time_t overlapStop;
public:
cRecMenuItemTimerConflictHeader(time_t conflictStart,
time_t conflictStop,
time_t overlapStart,
time_t overlapStop);
virtual ~cRecMenuItemTimerConflictHeader(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
void setBackground(void);
void Draw(void);
};
// --- cRecMenuItemEvent -------------------------------------------------------
class cRecMenuItemEvent : public cRecMenuItem {
private:
const cEvent *event;
eRecMenuState action2;
int iconActive;
cPixmap *pixmapText;
cPixmap *pixmapIcons;
int DrawIcons(void);
public:
cRecMenuItemEvent(const cEvent *event,
eRecMenuState action1,
eRecMenuState action2,
bool active);
virtual ~cRecMenuItemEvent(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
const cEvent *GetEventValue(void) { return event; };
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
};
// --- cRecMenuItemChannelChooser -------------------------------------------------------
class cRecMenuItemChannelChooser : public cRecMenuItem {
private:
cString text;
cChannel *channel;
int channelNumber;
bool initialChannelSet;
bool fresh;
cPixmap *pixmapChannel;
void DrawValue(void);
public:
cRecMenuItemChannelChooser (cString text,
cChannel *initialChannel,
bool active);
virtual ~cRecMenuItemChannelChooser(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
int GetIntValue(void);
};
// --- cRecMenuItemDayChooser -------------------------------------------------------
class cRecMenuItemDayChooser : public cRecMenuItem {
private:
cString text;
int weekdays;
std::string days;
int daysX;
int daysY;
int daysSize;
int selectedDay;
cPixmap *pixmapWeekdays;
cPixmap *pixmapWeekdaysSelect;
void SetSizes(void);
void DrawDays(void);
void DrawHighlight(int day);
void ToggleDay(void);
bool WeekDaySet(unsigned day);
public:
cRecMenuItemDayChooser (cString text,
int weekdays,
bool active);
virtual ~cRecMenuItemDayChooser(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
void setBackground(void);
eRecMenuState ProcessKey(eKeys Key);
void Draw(void);
int GetIntValue(void) { return weekdays;} ;
};
// --- cRecMenuItemRecording -------------------------------------------------------
class cRecMenuItemRecording : public cRecMenuItem {
private:
cRecording *recording;
cPixmap *pixmapText;
public:
cRecMenuItemRecording(cRecording *recording, bool active);
virtual ~cRecMenuItemRecording(void);
void SetPixmaps(void);
void Hide(void);
void Show(void);
void Draw(void);
};
#endif //__TVGUIDE_RECMENUITEM_H

521
recmenumanager.c Normal file
View File

@ -0,0 +1,521 @@
#include "recmenumanager.h"
cRecMenuManager::cRecMenuManager(void) {
active = false;
activeMenu = NULL;
activeMenuBuffer = NULL;
recManager = new cRecManager();
recManager->SetEPGSearchPlugin();
instantRecord = false;
currentConflict = -1;
templateID = -1;
timer = NULL;
searchWithOptions = false;
detailViewActive = false;
}
cRecMenuManager::~cRecMenuManager(void) {
if (activeMenu) {
active = false;
delete activeMenu;
activeMenu = NULL;
}
delete recManager;
}
void cRecMenuManager::Start(const cEvent *event) {
active = true;
activeMenuBuffer = NULL;
instantRecord = false;
currentConflict = -1;
templateID = -1;
timer = NULL;
searchWithOptions = false;
detailViewActive = false;
SetBackground();
this->event = event;
activeMenu = new cRecMenuMain(recManager->EpgSearchAvailable(), event->HasTimer(), SwitchTimers.EventInSwitchList(event));
activeMenu->Display();
osdManager.flush();
}
void cRecMenuManager::Close(void) {
event = NULL;
active = false;
if (activeMenu) {
delete activeMenu;
activeMenu = NULL;
}
DeleteBackground();
}
void cRecMenuManager::SetBackground(void) {
int backgroundWidth = tvguideConfig.osdWidth;
int backgroundHeight = tvguideConfig.osdHeight;
pixmapBackground = osdManager.requestPixmap(3, cRect(0, 0, backgroundWidth, backgroundHeight));
pixmapBackground->Fill(theme.Color(clrRecMenuBackground));
if (tvguideConfig.scaleVideo) {
int tvHeight = tvguideConfig.statusHeaderHeight;
int tvWidth = tvHeight * 16 / 9;
int tvX = tvguideConfig.osdWidth - tvWidth;
pixmapBackground->DrawRectangle(cRect(tvX, 0, tvWidth, tvHeight), clrTransparent);
}
}
void cRecMenuManager::DeleteBackground(void) {
osdManager.releasePixmap(pixmapBackground);
}
eOSState cRecMenuManager::StateMachine(eRecMenuState nextState) {
eOSState state = osContinue;
switch (nextState) {
/*
* --------- INSTANT RECORDING ---------------------------
*/
case rmsInstantRecord: {
//Creating timer for active Event
//if no conflict, confirm and exit
instantRecord = true;
delete activeMenu;
cTimer *timer = recManager->createTimer(event);
if (!displayTimerConflict(timer)) {
activeMenu = new cRecMenuConfirmTimer(event);
activeMenu->Display();
}
break; }
case rmsIgnoreTimerConflict:
//Confirming created Timer
if (instantRecord) {
delete activeMenu;
activeMenu = new cRecMenuConfirmTimer(event);
activeMenu->Display();
} else {
state = osEnd;
Close();
}
break;
case rmsTimerConflictShowInfo: {
int timerIndex = activeMenu->GetActive(true);
int timerID = conflictList[currentConflict].timerIDs[timerIndex];
cTimer *t = Timers.Get(timerID);
if (t) {
const cEvent *ev = t->Event();
if (ev) {
activeMenu->Hide();
detailView = new cDetailView(ev);
detailView->drawHeader();
detailView->drawContent();
detailView->drawScrollbar();
detailViewActive = true;
}
}
break;}
case rmsDeleteTimerConflictMenu: {
//delete timer out of current timer conflict
//active menu: cRecMenuTimerConflict
int timerIndex = activeMenu->GetActive(true);
int timerID = conflictList[currentConflict].timerIDs[timerIndex];
recManager->DeleteTimer(timerID);
delete activeMenu;
if (!displayTimerConflict(timerID)) {
activeMenu = new cRecMenuConfirmTimer(event);
activeMenu->Display();
}
break; }
case rmsEditTimerConflictMenu: {
//edit timer out of current timer conflict
//active menu: cRecMenuTimerConflict
int activeItem = activeMenu->GetActive(true);
int timerID = conflictList[currentConflict].timerIDs[activeItem];
timer = Timers.Get(timerID);
if (timer) {
delete activeMenu;
activeMenu = new cRecMenuEditTimer(timer, rmsSaveTimerConflictMenu);
activeMenu->Display();
}
break; }
case rmsSaveTimerConflictMenu: {
//save timer from current timer conflict
recManager->SaveTimer(timer, activeMenu);
delete activeMenu;
if (!displayTimerConflict(timer)) {
activeMenu = new cRecMenuConfirmTimer(event);
activeMenu->Display();
}
break; }
case rmsDeleteTimer:
//delete timer for active event
delete activeMenu;
if (recManager->IsRecorded(event)) {
activeMenu = new cRecMenuAskDeleteTimer(event);
} else {
recManager->DeleteTimer(event);
activeMenu = new cRecMenuConfirmDeleteTimer(event);
}
activeMenu->Display();
break;
case rmsDeleteTimerConfirmation:
//delete running timer for active event
recManager->DeleteTimer(event);
delete activeMenu;
activeMenu = new cRecMenuConfirmDeleteTimer(event);
activeMenu->Display();
break;
case rmsEditTimer: {
//edit timer for active event
timer = Timers.GetMatch(event);
if (timer) {
delete activeMenu;
activeMenu = new cRecMenuEditTimer(timer, rmsSaveTimer);
activeMenu->Display();
}
break; }
case rmsSaveTimer: {
//save timer for active event
recManager->SaveTimer(timer, activeMenu);
state = osEnd;
Close();
break; }
/*
* --------- SERIES TIMER ---------------------------------
*/
case rmsSeriesTimer: {
delete activeMenu;
cChannel *channel = Channels.GetByChannelID(event->ChannelID());
activeMenu = new cRecMenuSeriesTimer(channel, event);
activeMenu->Display();
break; }
case rmsSeriesTimerCreate: {
cTimer *seriesTimer = recManager->CreateSeriesTimer(activeMenu);
delete activeMenu;
activeMenu = new cRecMenuConfirmSeriesTimer(seriesTimer);
activeMenu->Display();
break; }
/*
* --------- SEARCH TIMER ---------------------------------
*/
case rmsSearchTimer:
delete activeMenu;
activeMenu = new cRecMenuSearchTimer(event);
activeMenu->Display();
break;
case rmsSearchTimerOptions: {
searchString = *activeMenu->GetStringValue(1);
delete activeMenu;
if (isempty(*searchString)) {
activeMenu = new cRecMenuSearchTimer(event);
} else {
epgSearchTemplates = recManager->ReadEPGSearchTemplates();
int numTemplates = epgSearchTemplates.size();
if (numTemplates > 0) {
activeMenu = new cRecMenuSearchTimerTemplates(searchString, epgSearchTemplates);
} else {
activeMenu = new cRecMenuSearchTimerOptions(searchString);
}
}
activeMenu->Display();
break; }
case rmsSearchTimerOptionsReload: {
int numTemplates = epgSearchTemplates.size();
delete activeMenu;
activeMenu = new cRecMenuSearchTimerTemplates(searchString, epgSearchTemplates);
activeMenu->Display();
break; }
case rmsSearchTimerUseTemplate: {
templateID = activeMenu->GetActive(true) - 1;
delete activeMenu;
activeMenu = new cRecMenuSearchTimerTemplatesCreate(searchString, epgSearchTemplates[templateID].name.c_str());
activeMenu->Display();
break; }
case rmsSearchTimerOptionsManually:
delete activeMenu;
activeMenu = new cRecMenuSearchTimerOptions(searchString);
activeMenu->Display();
break;
case rmsSearchTimerTestTemplate: {
std::string epgSearchString = recManager->BuildEPGSearchString(searchString, epgSearchTemplates[templateID].templValue);
int numSearchResults = 0;
const cEvent **searchResult = recManager->PerformSearchTimerSearch(epgSearchString, numSearchResults);
if (searchResult) {
activeMenuBuffer = activeMenu;
activeMenuBuffer->Hide();
activeMenu = new cRecMenuSearchTimerResults(searchString, searchResult, numSearchResults, epgSearchTemplates[templateID].name);
activeMenu->Display();
} else {
activeMenuBuffer = activeMenu;
activeMenuBuffer->Hide();
activeMenu = new cRecMenuSearchTimerNothingFound(searchString, epgSearchTemplates[templateID].name);
activeMenu->Display();
}
break; }
case rmsSearchTimerTestManually: {
std::string epgSearchString = recManager->BuildEPGSearchString(searchString, activeMenu);
int numSearchResults = 0;
const cEvent **searchResult = recManager->PerformSearchTimerSearch(epgSearchString, numSearchResults);
if (searchResult) {
activeMenuBuffer = activeMenu;
activeMenuBuffer->Hide();
activeMenu = new cRecMenuSearchTimerResults(searchString, searchResult, numSearchResults, "");
activeMenu->Display();
} else {
activeMenuBuffer = activeMenu;
activeMenuBuffer->Hide();
activeMenu = new cRecMenuSearchTimerNothingFound(searchString, "");
activeMenu->Display();
}
break; }
case rmsSearchTimerNothingFoundConfirm:
delete activeMenu;
activeMenu = activeMenuBuffer;
activeMenuBuffer = NULL;
activeMenu->Show();
break;
case rmsSearchTimerCreateManually:
case rmsSearchTimerCreateTemplate: {
std::string epgSearchString;
if (nextState == rmsSearchTimerCreateManually) {
epgSearchString = recManager->BuildEPGSearchString(searchString, activeMenu);
} else if (nextState = rmsSearchTimerCreateTemplate) {
epgSearchString = recManager->BuildEPGSearchString(searchString, epgSearchTemplates[templateID].templValue);
}
bool success = createSearchTimer(epgSearchString);
delete activeMenu;
activeMenu = new cRecMenuSearchTimerCreateConfirm(success);
activeMenu->Display();
break; }
/*
* --------- SWITCH TIMER ---------------------------------
*/
case rmsSwitchTimer:
delete activeMenu;
activeMenu = new cRecMenuSwitchTimer();
activeMenu->Display();
break;
case rmsSwitchTimerCreate: {
bool success = recManager->CreateSwitchTimer(event, activeMenu);
delete activeMenu;
activeMenu = new cRecMenuSwitchTimerConfirm(success);
activeMenu->Display();
break; }
case rmsSwitchTimerDelete:
recManager->DeleteSwitchTimer(event);
delete activeMenu;
activeMenu = new cRecMenuSwitchTimerDelete();
activeMenu->Display();
break;
/*
* --------- RECORDINGS SEARCH ---------------------------------
*/
case rmsRecordingSearch:
delete activeMenu;
activeMenu = new cRecMenuRecordingSearch(event);
activeMenu->Display();
break;
case rmsRecordingSearchResult: {
searchString = activeMenu->GetStringValue(1);
delete activeMenu;
if (isempty(*searchString)) {
activeMenu = new cRecMenuRecordingSearch(event);
} else {
int numSearchResults = 0;
cRecording **searchResult = recManager->SearchForRecordings(searchString, numSearchResults);
if (numSearchResults == 0) {
activeMenu = new cRecMenuRecordingSearchNotFound(searchString);
} else {
activeMenu = new cRecMenuRecordingSearchResults(searchString, searchResult, numSearchResults);
}
}
activeMenu->Display();
break; }
/*
* --------- SEARCH ---------------------------------
*/
case rmsSearch:
delete activeMenu;
activeMenu = new cRecMenuSearch(event);
activeMenu->Display();
searchWithOptions = false;
break;
case rmsSearchWithOptions: {
cString searchString = activeMenu->GetStringValue(1);
delete activeMenu;
if (isempty(*searchString)) {
activeMenu = new cRecMenuSearch(event);
} else {
activeMenu = new cRecMenuSearch(event, *searchString);
searchWithOptions = true;
}
activeMenu->Display();
break; }
case rmsSearchPerform: {
cString searchString = activeMenu->GetStringValue(1);
if (isempty(*searchString)) {
delete activeMenu;
activeMenu = new cRecMenuSearch(event);
} else {
int numSearchResults = 0;
const cEvent **searchResult = recManager->PerformSearch(activeMenu, searchWithOptions, numSearchResults);
if (searchResult) {
delete activeMenu;
activeMenu = new cRecMenuSearchResults(searchString, searchResult, numSearchResults);
} else {
activeMenuBuffer = activeMenu;
activeMenuBuffer->Hide();
activeMenu = new cRecMenuSearchNothingFound(searchString);
}
}
activeMenu->Display();
break; }
case rmsSearchNothingFoundConfirm:
delete activeMenu;
activeMenu = activeMenuBuffer;
activeMenuBuffer = NULL;
activeMenu->Show();
break;
case rmsSearchShowInfo: {
const cEvent *ev = activeMenu->GetEventValue(activeMenu->GetActive(false));
if (ev) {
activeMenu->Hide();
detailView = new cDetailView(ev);
detailView->drawHeader();
detailView->drawContent();
detailView->drawScrollbar();
detailViewActive = true;
}
break;}
case rmsSearchRecord: {
const cEvent *ev = activeMenu->GetEventValue(activeMenu->GetActive(false));
cTimer *timer = recManager->createTimer(ev);
activeMenuBuffer = activeMenu;
activeMenuBuffer->Hide();
activeMenu = new cRecMenuSearchConfirmTimer(ev);
activeMenu->Display();
break;}
case rmsSearchRecordConfirm:
delete activeMenu;
activeMenu = activeMenuBuffer;
activeMenuBuffer = NULL;
activeMenu->Show();
break;
/*
* --------- CHECK FOR TIMER CONFLICTS ---------------------------------
*/
case rmsTimerConflicts: {
//Show timer conflict
//active menu: cRecMenuTimerConflicts
conflictList = recManager->CheckTimerConflict();
delete activeMenu;
int numConflicts = conflictList.size();
if (numConflicts > 0) {
activeMenu = new cRecMenuTimerConflicts(conflictList);
} else {
activeMenu = new cRecMenuNoTimerConflict();
}
activeMenu->Display();
break; }
case rmsTimerConflict:
//Show timer conflict
//active menu: cRecMenuTimerConflicts
currentConflict = activeMenu->GetActive(true);
delete activeMenu;
activeMenu = new cRecMenuTimerConflict(conflictList[currentConflict]);
activeMenu->Display();
break;
/*
* --------- COMMON ---------------------------------
*/
case rmsClose: {
if (activeMenuBuffer == NULL) {
state = osEnd;
Close();
} else {
delete activeMenu;
activeMenu = activeMenuBuffer;
activeMenuBuffer = NULL;
activeMenu->Show();
state = osContinue;
}
break; }
default:
break;
}
return state;
}
bool cRecMenuManager::displayTimerConflict(cTimer *timer) {
int timerID = 0;
for (cTimer *t = Timers.First(); t; t = Timers.Next(t)) {
if (t == timer)
return displayTimerConflict(timerID);
timerID++;
}
return false;
}
bool cRecMenuManager::displayTimerConflict(int timerID) {
conflictList = recManager->CheckTimerConflict();
int numConflicts = conflictList.size();
int showTimerConflict = -1;
if (numConflicts > 0) {
for (int i=0; i<numConflicts; i++) {
if (conflictList[i].timerInvolved(timerID)) {
showTimerConflict = i;
break;
}
}
}
if (showTimerConflict > -1) {
currentConflict = showTimerConflict;
activeMenu = new cRecMenuTimerConflict(conflictList[currentConflict]);
activeMenu->Display();
return true;
}
return false;
}
bool cRecMenuManager::createSearchTimer(std::string epgSearchString) {
int newTimerID = recManager->CreateSearchTimer(epgSearchString);
bool success = false;
if (newTimerID > -1) {
recManager->UpdateSearchTimers();
success = true;
}
return success;
}
eOSState cRecMenuManager::ProcessKey(eKeys Key) {
eOSState state = osContinue;
eRecMenuState nextState = rmsContinue;
if (!activeMenu)
return state;
if (detailViewActive) {
state = detailView->ProcessKey(Key);
if (state == osEnd) {
delete detailView;
detailView = NULL;
detailViewActive = false;
activeMenu->Show();
state = osContinue;
}
} else {
nextState = activeMenu->ProcessKey(Key);
if ((nextState == rmsClose) || ((nextState == rmsNotConsumed)&&(Key == kBack))){
if (activeMenuBuffer == NULL) {
state = osEnd;
Close();
} else {
delete activeMenu;
activeMenu = activeMenuBuffer;
activeMenuBuffer = NULL;
activeMenu->Show();
state = osContinue;
osdManager.flush();
}
return state;
}
state = StateMachine(nextState);
}
osdManager.flush();
return state;
}

38
recmenumanager.h Normal file
View File

@ -0,0 +1,38 @@
#ifndef __TVGUIDE_RECMENUMANAGER_H
#define __TVGUIDE_RECMENUMANAGER_H
// --- cRecMenuManager -------------------------------------------------------------
class cRecMenuManager {
private:
bool active;
cRecMenu *activeMenu;
cRecMenu *activeMenuBuffer;
const cEvent *event;
cRecManager *recManager;
std::vector<TVGuideTimerConflict> conflictList;
std::vector<TVGuideEPGSearchTemplate> epgSearchTemplates;
bool instantRecord;
int currentConflict;
int templateID;
bool searchWithOptions;
cTimer *timer;
cString searchString;
cDetailView *detailView;
cPixmap *pixmapBackground;
bool detailViewActive;
void SetBackground(void);
void DeleteBackground(void);
bool displayTimerConflict(cTimer *timer);
bool displayTimerConflict(int timerID);
bool createSearchTimer(std::string epgSearchString);
public:
cRecMenuManager(void);
virtual ~cRecMenuManager(void);
bool isActive(void) { return active; };
void Start(const cEvent *event);
void Close(void);
eOSState StateMachine(eRecMenuState nextState);
eOSState ProcessKey(eKeys Key);
};
#endif //__TVGUIDE_RECMENUMANAGER_H

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2004-2007 Christian Wieninger
/* -*- c++ -*-
Copyright (C) 2004-2013 Christian Wieninger
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
@ -24,10 +24,6 @@ The project's page is at http://winni.vdr-developer.org/epgsearch
#ifndef EPGSEARCHSERVICES_INC
#define EPGSEARCHSERVICES_INC
// Added by Andreas Mair (mail _AT_ andreas _DOT_ vdr-developer _DOT_ org)
#define EPGSEARCH_SEARCHRESULTS_SERVICE_STRING_ID "Epgsearch-searchresults-v1.0"
#define EPGSEARCH_LASTCONFLICTINFO_SERVICE_STRING_ID "Epgsearch-lastconflictinfo-v1.0"
#include <string>
#include <list>
#include <memory>
@ -59,6 +55,13 @@ struct Epgsearch_exttimeredit_v1_0
cOsdMenu* pTimerMenu; // pointer to the menu of results
};
// Data structure for service "Epgsearch-enablesearchtimers-v1.0"
struct Epgsearch_enablesearchtimers_v1_0
{
// in
bool enable; // enable search timer thread?
};
// Data structure for service "Epgsearch-updatesearchtimers-v1.0"
struct Epgsearch_updatesearchtimers_v1_0
{
@ -119,7 +122,7 @@ struct Epgsearch_switchtimer_v1_0
{
// in
const cEvent* event;
int mode; // mode (0=query existance, 1=add/modify, 2=delete)
int mode; // mode (0=query existence, 1=add/modify, 2=delete)
// in/out
int switchMinsBefore;
int announceOnly;
@ -164,4 +167,36 @@ struct Epgsearch_services_v1_0
std::auto_ptr<cServiceHandler> handler;
};
// Data structures for service "Epgsearch-services-v1.1"
class cServiceHandler_v1_1 : public cServiceHandler
{
public:
// Get timer conflicts
virtual std::list<std::string> TimerConflictList(bool relOnly=false) = 0;
// Check if a conflict check is advised
virtual bool IsConflictCheckAdvised() = 0;
};
struct Epgsearch_services_v1_1
{
// in/out
std::auto_ptr<cServiceHandler_v1_1> handler;
};
// Data structures for service "Epgsearch-services-v1.2"
class cServiceHandler_v1_2 : public cServiceHandler_v1_1
{
public:
// List of all recording directories used in recordings, timers (and optionally search timers or in epgsearchdirs.conf)
virtual std::set<std::string> ShortDirectoryList() = 0;
// Evaluate an expression against an event
virtual std::string Evaluate(const std::string& expr, const cEvent* event) = 0;
};
struct Epgsearch_services_v1_2
{
// in/out
std::auto_ptr<cServiceHandler_v1_2> handler;
};
#endif

View File

@ -102,6 +102,8 @@ void cTvguideSetup::Store(void) {
SetupStore("FontGridHorizontalSmallDelta", tvguideConfig.FontGridHorizontalSmallDelta);
SetupStore("FontTimeLineDateHorizontalDelta", tvguideConfig.FontTimeLineDateHorizontalDelta);
SetupStore("FontTimeLineTimeHorizontalDelta", tvguideConfig.FontTimeLineTimeHorizontalDelta);
SetupStore("FontRecMenuItemDelta", tvguideConfig.FontRecMenuItemDelta);
SetupStore("FontRecMenuItemSmallDelta", tvguideConfig.FontRecMenuItemSmallDelta);
SetupStore("displayRerunsDetailEPGView", tvguideConfig.displayRerunsDetailEPGView);
SetupStore("numReruns", tvguideConfig.numReruns);
SetupStore("useSubtitleRerun", tvguideConfig.useSubtitleRerun);
@ -302,6 +304,8 @@ void cMenuSetupFont::Set(void) {
Add(new cMenuEditIntItem(tr("Timeline Time Font Size"), &tmpTvguideConfig->FontTimeLineTimeHorizontalDelta, -30, 30));
}
Add(new cMenuEditIntItem(tr("Search & Recording Menu Font Size"), &tmpTvguideConfig->FontRecMenuItemDelta, -30, 30));
Add(new cMenuEditIntItem(tr("Search & Recording Menu Small Font Size"), &tmpTvguideConfig->FontRecMenuItemSmallDelta, -30, 30));
SetCurrent(Get(currentItem));
Display();

View File

@ -132,3 +132,11 @@ void cStyledPixmap::DrawImage(const cPoint &Point, const cImage &Image) {
void cStyledPixmap::DrawRectangle(const cRect &Rect, tColor Color) {
pixmap->DrawRectangle(Rect,Color);
}
void cStyledPixmap::DrawEllipse(const cRect &Rect, tColor Color, int Quadrant) {
pixmap->DrawEllipse(Rect,Color,Quadrant);
}
void cStyledPixmap::SetViewPort(const cRect &Rect) {
pixmap->SetViewPort(Rect);
}

View File

@ -25,9 +25,12 @@ public:
void drawRoundedCorners(int width, int height, int radius);
void setColor(tColor color, tColor colorBlending) {this->color = color; this->colorBlending = colorBlending;};
void SetAlpha(int alpha) {pixmap->SetAlpha(alpha);};
void SetLayer(int layer) {pixmap->SetLayer(layer);};
void DrawText(const cPoint &Point, const char *s, tColor ColorFg, tColor ColorBg, const cFont *Font);
void DrawImage(const cPoint &Point, const cImage &Image);
void DrawRectangle(const cRect &Rect, tColor Color);
void DrawEllipse(const cRect &Rect, tColor Color, int Quadrant);
void SetViewPort(const cRect &Rect);
int Width() {return pixmap->ViewPort().Width();};
int Height() {return pixmap->ViewPort().Height();};
};

109
switchtimer.c Normal file
View File

@ -0,0 +1,109 @@
#include "switchtimer.h"
cSwitchTimers SwitchTimers;
// -- cSwitchTimer -----------------------------------------------------------------
cSwitchTimer::cSwitchTimer(void) {
}
cSwitchTimer::cSwitchTimer(const cEvent* Event) {
eventID = 0;
startTime = 0;
if (Event) {
eventID = Event->EventID();
channelID = Event->ChannelID();
startTime = Event->StartTime();
}
}
bool cSwitchTimer::Parse(const char *s) {
char *line;
char *pos;
char *pos_next;
int parameter = 1;
int valuelen;
#define MAXVALUELEN (10 * MaxFileName)
char value[MAXVALUELEN];
startTime=0;
pos = line = strdup(s);
pos_next = pos + strlen(pos);
if (*pos_next == '\n') *pos_next = 0;
while (*pos) {
while (*pos == ' ')
pos++;
if (*pos) {
if (*pos != ':') {
pos_next = strchr(pos, ':');
if (!pos_next)
pos_next = pos + strlen(pos);
valuelen = pos_next - pos + 1;
if (valuelen > MAXVALUELEN)
valuelen = MAXVALUELEN;
strn0cpy(value, pos, valuelen);
pos = pos_next;
switch (parameter) {
case 1:
channelID = tChannelID::FromString(value);
break;
case 2:
eventID = atoi(value);
break;
case 3:
startTime = atol(value);
break;
default:
break;
}
}
parameter++;
}
if (*pos)
pos++;
}
free(line);
return (parameter >= 3) ? true : false;
}
bool cSwitchTimers::EventInSwitchList(const cEvent* event) {
if (!event) return false;
cMutexLock SwitchTimersLock(this);
cSwitchTimer* switchTimer = SwitchTimers.First();
while (switchTimer) {
if (switchTimer->eventID == event->EventID())
return true;
switchTimer = SwitchTimers.Next(switchTimer);
}
return false;
}
bool cSwitchTimers::ChannelInSwitchList(const cChannel* channel) {
if (!channel) return false;
cMutexLock SwitchTimersLock(this);
cSwitchTimer* switchTimer = SwitchTimers.First();
while (switchTimer) {
if (switchTimer->channelID == channel->GetChannelID())
return true;
switchTimer = SwitchTimers.Next(switchTimer);
}
return false;
}
void cSwitchTimers::DeleteSwitchTimer(const cEvent *event) {
if (!event) return;
cMutexLock SwitchTimersLock(this);
cSwitchTimer* switchTimer = SwitchTimers.First();
cSwitchTimer* delTimer = NULL;
while (switchTimer) {
if (switchTimer->eventID == event->EventID()) {
delTimer = switchTimer;
break;
}
switchTimer = SwitchTimers.Next(switchTimer);
}
if (delTimer) {
SwitchTimers.Del(delTimer, true);
}
}

30
switchtimer.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef __TVGUIDE_SWITCHTIMER_H
#define __TVGUIDE_SWITCHTIMER_H
#include <vdr/plugin.h>
class cSwitchTimer : public cListObject
{
public:
tEventID eventID;
time_t startTime;
tChannelID channelID;
cSwitchTimer(void);
cSwitchTimer(const cEvent* Event);
bool Parse(const char *s);
};
class cSwitchTimers : public cConfig<cSwitchTimer>, public cMutex
{
public:
cSwitchTimers(void) {}
~cSwitchTimers(void) {}
bool EventInSwitchList(const cEvent* event);
bool ChannelInSwitchList(const cChannel* channel);
void DeleteSwitchTimer(const cEvent *event);
};
extern cSwitchTimers SwitchTimers;
#endif //__TVGUIDE_SWITCHTIMER_H

View File

@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 44FFFFFF
clrRecMenuTextBack = FF000000
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000000
clrRecMenuKeyboardBorder = FFFFFFFF
clrRecMenuKeyboardHigh = 40BB0000

View File

@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 44FFFFFF
clrRecMenuTextBack = FF000000
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000000
clrRecMenuKeyboardBorder = FFFFFFFF
clrRecMenuKeyboardHigh = 40BB0000

View File

@ -26,3 +26,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 44FFFFFF
clrRecMenuTextBack = FF000000
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000000
clrRecMenuKeyboardBorder = BB555555
clrRecMenuKeyboardHigh = 40BB0000

View File

@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 44FFFFFF
clrRecMenuTextBack = FF000000
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000000
clrRecMenuKeyboardBorder = FF003DF5
clrRecMenuKeyboardHigh = 40BB0000

View File

@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 44FFFFFF
clrRecMenuTextBack = FF000000
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000000
clrRecMenuKeyboardBorder = FF660000
clrRecMenuKeyboardHigh = 40BB0000

View File

@ -30,3 +30,15 @@ clrButtonYellowBorder = FFBBBB00
clrButtonBlue = 990000BB
clrButtonBlueBorder = FF0000BB
clrButtonBlend = DD000000
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 44FFFFFF
clrRecMenuTextBack = FF000000
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000000
clrRecMenuKeyboardBorder = EE006600
clrRecMenuKeyboardHigh = 40BB0000

View File

@ -25,3 +25,18 @@ clrButtonYellow = FFBBBB00
clrButtonYellowBorder = FFBBBB00
clrButtonBlue = FF0000BB
clrButtonBlueBorder = FF0000BB
clrRecMenuBackground = AA000000
clrRecMenuTimerConflictBackground = FFCCCCCC
clrRecMenuTimerConflictBar = FF222222
clrRecMenuTimerConflictOverlap = AAFF0000
clrRecMenuDayActive = FF00FF00
clrRecMenuDayInactive = FFFF0000
clrRecMenuDayHighlight = 77000000
clrRecMenuTextBack = FF3C3C3C
clrRecMenuTextActiveBack = FF404749
clrRecMenuKeyboardBack = FF000044
clrRecMenuKeyboardBorder = FF3C3C3C
clrRecMenuKeyboardHigh = 55FFFFFF
clrButtonRedKeyboard = FFBB0000
clrButtonGreenKeyboard = FF00BB00
clrButtonYellowKeyboard = FFBBBB00

View File

@ -3,11 +3,11 @@
cTimeLine::cTimeLine(cMyTime *myTime) {
this->myTime = myTime;
if (tvguideConfig.displayMode == eVertical) {
dateViewer = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0,
dateViewer = new cStyledPixmap(osdManager.requestPixmap(1, cRect(0,
tvguideConfig.statusHeaderHeight,
tvguideConfig.timeLineWidth,
tvguideConfig.channelHeaderHeight + tvguideConfig.channelGroupsHeight)));
timeline = osdManager.requestPixmap(2, cRect(0,
timeline = osdManager.requestPixmap(1, cRect(0,
tvguideConfig.statusHeaderHeight + tvguideConfig.channelHeaderHeight + tvguideConfig.channelGroupsHeight,
tvguideConfig.timeLineWidth,
tvguideConfig.osdHeight - tvguideConfig.statusHeaderHeight - tvguideConfig.channelHeaderHeight - tvguideConfig.channelGroupsHeight - tvguideConfig.footerHeight)
@ -16,11 +16,11 @@ cTimeLine::cTimeLine(cMyTime *myTime) {
tvguideConfig.timeLineWidth,
1440*tvguideConfig.minutePixel));
} else if (tvguideConfig.displayMode == eHorizontal) {
dateViewer = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0,
dateViewer = new cStyledPixmap(osdManager.requestPixmap(1, cRect(0,
tvguideConfig.statusHeaderHeight,
tvguideConfig.channelHeaderWidth + tvguideConfig.channelGroupsWidth,
tvguideConfig.timeLineHeight)));
timeline = osdManager.requestPixmap(2, cRect(tvguideConfig.channelHeaderWidth + tvguideConfig.channelGroupsWidth,
timeline = osdManager.requestPixmap(1, cRect(tvguideConfig.channelHeaderWidth + tvguideConfig.channelGroupsWidth,
tvguideConfig.statusHeaderHeight,
tvguideConfig.osdWidth - tvguideConfig.channelHeaderWidth - tvguideConfig.channelGroupsWidth,
tvguideConfig.timeLineHeight)
@ -29,7 +29,7 @@ cTimeLine::cTimeLine(cMyTime *myTime) {
1440*tvguideConfig.minutePixel,
tvguideConfig.timeLineWidth));
}
clock = new cStyledPixmap(osdManager.requestPixmap(3, cRect(0,
clock = new cStyledPixmap(osdManager.requestPixmap(1, cRect(0,
tvguideConfig.osdHeight- tvguideConfig.footerHeight,
tvguideConfig.timeLineWidth,
tvguideConfig.footerHeight-9)));

46
timer.c
View File

@ -120,3 +120,49 @@ time_t cMyTime::GetRounded() {
void cMyTime::debug() {
esyslog("t: %s, tStart: %s, tEnd: %s", *TimeString(t), *TimeString(tStart), *TimeString(tEnd));
}
// --- cTimeInterval -------------------------------------------------------------
cTimeInterval::cTimeInterval(time_t start, time_t stop) {
this->start = start;
this->stop = stop;
}
cTimeInterval::~cTimeInterval(void) {
}
cTimeInterval *cTimeInterval::Intersect(cTimeInterval *interval) {
time_t startIntersect, stopIntersect;
if ((stop <= interval->Start()) || (interval->Stop() <= start)) {
return NULL;
}
if (start <= interval->Start()) {
startIntersect = interval->Start();
} else {
startIntersect = start;
}
if (stop <= interval->Stop()) {
stopIntersect = stop;
} else {
stopIntersect = interval->Stop();
}
return new cTimeInterval(startIntersect, stopIntersect);
}
cTimeInterval *cTimeInterval::Union(cTimeInterval *interval) {
time_t startUnion, stopUnion;
if (start <= interval->Start()) {
startUnion = start;
} else {
startUnion = interval->Start();
}
if (stop <= interval->Stop()) {
stopUnion = interval->Stop();
} else {
stopUnion = stop;
}
return new cTimeInterval(startUnion, stopUnion);
}

15
timer.h
View File

@ -30,4 +30,19 @@ class cMyTime {
void debug();
};
// --- cTimeInterval -------------------------------------------------------------
class cTimeInterval {
private:
time_t start;
time_t stop;
public:
cTimeInterval(time_t start, time_t stop);
virtual ~cTimeInterval(void);
time_t Start(void) { return start; };
time_t Stop(void) { return stop; };
cTimeInterval *Intersect(cTimeInterval *interval);
cTimeInterval *Union(cTimeInterval *interval);
};
#endif //__TVGUIDE_TIMER_H

370
tools.c Normal file
View File

@ -0,0 +1,370 @@
#include <string>
#include <vector>
#include <sstream>
/****************************************************************************************
* CUTTEXT
****************************************************************************************/
static std::string CutText(std::string text, int width, const cFont *font) {
if (width <= font->Size())
return text.c_str();
if (font->Width(text.c_str()) < width)
return text.c_str();
cTextWrapper twText;
twText.Set(text.c_str(), font, width);
std::string cuttedTextNative = twText.GetLine(0);
std::stringstream sstrText;
sstrText << cuttedTextNative << "...";
std::string cuttedText = sstrText.str();
int actWidth = font->Width(cuttedText.c_str());
if (actWidth > width) {
int overlap = actWidth - width;
int charWidth = font->Width(".");
if (charWidth == 0)
charWidth = 1;
int cutChars = overlap / charWidth;
if (cutChars > 0) {
cuttedTextNative = cuttedTextNative.substr(0, cuttedTextNative.length() - cutChars);
std::stringstream sstrText2;
sstrText2 << cuttedTextNative << "...";
cuttedText = sstrText2.str();
}
}
return cuttedText;
}
/****************************************************************************************
* SPLTSTRING
****************************************************************************************/
class splitstring : public std::string {
std::vector<std::string> flds;
public:
splitstring(const char *s) : std::string(s) { };
std::vector<std::string>& split(char delim, int rep=0);
};
// split: receives a char delimiter; returns a vector of strings
// By default ignores repeated delimiters, unless argument rep == 1.
std::vector<std::string>& splitstring::split(char delim, int rep) {
if (!flds.empty()) flds.clear(); // empty vector if necessary
std::string work = data();
std::string buf = "";
int i = 0;
while (i < work.length()) {
if (work[i] != delim)
buf += work[i];
else if (rep == 1) {
flds.push_back(buf);
buf = "";
} else if (buf.length() > 0) {
flds.push_back(buf);
buf = "";
}
i++;
}
if (!buf.empty())
flds.push_back(buf);
return flds;
}
/****************************************************************************************
* FINDIGNORECASE
****************************************************************************************/
int FindIgnoreCase(const std::string& expr, const std::string& query)
{
const char *p = expr.c_str();
const char *r = strcasestr(p, query.c_str());
if (!r)
return -1;
return r - p;
}
/****************************************************************************************
* FUZZYSEARCH
****************************************************************************************/
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef _AFUZZY_H
#define _AFUZZY_H
// source from:
/*
Leonid Boitsov 2002. (itman@narod.ru)
C version of Stas Namin.
This code is a GPL software and is distributed under GNU
public licence without any warranty.
*/
typedef unsigned int Uint;
#define MaxPatSize (sizeof(Uint) * 8)
typedef struct
{
Uint *R,
*R1,
*RP,
*S,
*RI;
Uint *FilterS;
int Map[256];
int FilterMap[256];
int k;
Uint mask_ok;
Uint filter_ok;
Uint filter_shift;
int r_size;
int FilterSet;
} AFUZZY;
void afuzzy_init(const char *p, int kerr, int UseFilter, AFUZZY *fuzzy);
void afuzzy_free(AFUZZY *fuzzy);
int afuzzy_checkSUB(const char *t, AFUZZY *fuzzy);
#endif
static int afuzzy_checkFLT(const char *t, AFUZZY *fuzzy);
/******************************************************************************
FUNCTION afuzzy_init()
Initialization of the fuzzy search routine. This applies to the consequent
calls of the afuzzy_CheckRTR (whole string matching) and afuzzy_CheckSUB
(substring match) routines. afuzzy_init() should be called for each
new pattern or error length. The search is case sensitive
ARGUMENTS:
p Pattern
kerr Number of possible errors. Shouldn't exceed pattern length
UseFilter Use agrep filter algorithm that speeds up search.
fuzzy pointer to the structure that will be later passes to Check*
(the first 6 elements should be NULLs for the first call)
RETURN VALUE:
none
ALGORITHM
see. the article on agrep algorithms.
The only change is accounting transpositions as one edit operation .
******************************************************************************/
void afuzzy_init(const char *p, int kerr, int UseFilter, AFUZZY *fuzzy)
{
int cnt, p_len, i, j, l, d, m, dd;
char PatFilter[sizeof(Uint)*8 + 1];
fuzzy->k = kerr;
m = strlen(p);
fuzzy->FilterSet = 0;
memset(fuzzy->Map, 0 , sizeof(fuzzy->Map) );
if (fuzzy->S)
free(fuzzy->S);
if (fuzzy->R)
free(fuzzy->R);
if (fuzzy->R1)
free(fuzzy->R1);
if (fuzzy->RP)
free(fuzzy->RP);
if (fuzzy->RI)
free(fuzzy->RI);
if (fuzzy->FilterS)
free(fuzzy->FilterS);
fuzzy->FilterS = NULL;
fuzzy->S = (Uint *)calloc(m + 1, sizeof(Uint));
fuzzy->R = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
fuzzy->R1 = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
fuzzy->RI = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
fuzzy->RP = (Uint *)calloc(fuzzy->k + 1, sizeof(Uint));
for (i = 0, cnt = 0; i < m; i++)
{
l = fuzzy->Map[(unsigned char)p[i]];
if (!l)
{
l = fuzzy->Map[(unsigned char)p[i]] = ++cnt;
fuzzy->S[l] = 0;
}
fuzzy->S[l] |= 1 << i;
}
for (d = 0; d <= fuzzy->k; d++)
fuzzy->RI[d] = (1 << d) - 1;
fuzzy->mask_ok = (1 << (m - 1));
fuzzy->r_size = sizeof(Uint) * (fuzzy->k + 1);
p_len = m;
if (p_len > (int) sizeof(Uint)*8)
p_len = (int) sizeof(Uint)*8;
/* If k is zero then no filter is needed! */
if (fuzzy->k && (p_len >= 2*(fuzzy->k + 1)) )
{
if (UseFilter)
{
fuzzy->FilterSet = 1;
memset(fuzzy->FilterMap, 0 , sizeof(fuzzy->FilterMap) );
fuzzy->FilterS = (Uint *)calloc(m + 1, sizeof(Uint));
/* Not let's fill the interleaved pattern */
dd = p_len / (fuzzy->k + 1);
p_len = dd * (fuzzy->k + 1);
for (i = 0, cnt = 0; i < dd; i++)
for (j = 0; j < fuzzy->k + 1; j++, cnt++)
PatFilter[cnt] = (unsigned char)p[j*dd + i];
PatFilter[p_len] = 0;
for (i = 0, cnt = 0; i < p_len; i++)
{
l = fuzzy->FilterMap[(unsigned char)PatFilter[i]];
if (!l)
{
l = fuzzy->FilterMap[(unsigned char)PatFilter[i]] = ++cnt;
fuzzy->FilterS[l] = 0;
}
fuzzy->FilterS[l] |= 1 << i;
}
fuzzy->filter_ok = 0;
for (i = p_len - fuzzy->k - 1; i <= p_len - 1; i++) /* k+1 times */
fuzzy->filter_ok |= 1 << i;
/* k+1 first bits set to 1 */
fuzzy->filter_shift = (1 << (fuzzy->k + 2)) - 1;
}
}
}
/******************************************************************************
FUNCTION afuzzy_free()
Cleaning up after previous afuzzy_init() call.
ARGUMENTS:
fuzzy pointer to the afuzzy parameters structure
RETURN VALUE:
none
******************************************************************************/
void afuzzy_free(AFUZZY *fuzzy)
{
if (fuzzy->S)
{
free(fuzzy->S);
fuzzy->S = NULL;
}
if (fuzzy->R)
{
free(fuzzy->R);
fuzzy->R = NULL;
}
if (fuzzy->R1)
{
free(fuzzy->R1);
fuzzy->R1 = NULL;
}
if (fuzzy->RP)
{
free(fuzzy->RP);
fuzzy->RP = NULL;
}
if (fuzzy->RI)
{
free(fuzzy->RI);
fuzzy->RI = NULL;
}
if (fuzzy->FilterS)
{
free(fuzzy->FilterS);
fuzzy->FilterS = NULL;
}
}
/******************************************************************************
FUNCTION afuzzy_CheckSUB()
Perform a fuzzy pattern substring matching. afuzzy_init() should be
called previously to initialize the pattern and error length.
Positive result means that some part of the string given matches the
pattern with no more than afuzzy->k errors (1 error = 1 letter
replacement or transposition)
ARGUMENTS:
t the string to test
fuzzy pointer to the afuzzy parameters structure
RETURN VALUE:
0 - no match
> 0 - strings match
ALGORITHM
????????????????
******************************************************************************/
int afuzzy_checkSUB(const char *t, AFUZZY *fuzzy)
{
register char c;
register int j, d;
/* For eficciency this case should be little bit optimized */
if (!fuzzy->k)
{
Uint R = 0, R1;
for (j = 0; (c = t[j]) != '\0'; j++)
{
R1 = ( ((R<<1) | 1) & fuzzy->S[fuzzy->Map[(unsigned char)c]]);
R = R1;
if (R1 & fuzzy->mask_ok)
return 1;
} /* end for (register int j = 0 ... */
return 0;
}
if (fuzzy->FilterSet && !afuzzy_checkFLT(t, fuzzy))
return 0;
memcpy(fuzzy->R, fuzzy->RI, fuzzy->r_size); /* R = RI */
for (j = 0; (c = t[j]); j++)
{
for (d = 0; d <= fuzzy->k; d++)
{
fuzzy->R1[d] = (((fuzzy->R[d]<<1) | 1) &
fuzzy->S[fuzzy->Map[(unsigned char)c]]);
if (d > 0)
fuzzy->R1[d] |= ((fuzzy->R[d-1] | fuzzy->R1[d-1])<<1) | 1 |
fuzzy->R[d-1];
}
if (fuzzy->R1[fuzzy->k] & fuzzy->mask_ok)
return j;
memcpy(fuzzy->R, fuzzy->R1, fuzzy->r_size);
} /* end for (register int j = 0 ... */
return 0;
}
static int afuzzy_checkFLT(const char *t, AFUZZY *fuzzy)
{
register Uint FilterR = 0;
register Uint FilterR1;
register int j;
for (j = 0; t[j] != '\0'; j++)
{
FilterR1 = ( ((FilterR<<(fuzzy->k+1)) | fuzzy->filter_shift) &
fuzzy->FilterS[fuzzy->FilterMap[(unsigned char)t[j]]]);
if (FilterR1 & fuzzy->filter_ok)
return 1;
FilterR = FilterR1;
} /* end for (register int j = 0 ... */
return 0;
}

View File

@ -11,6 +11,7 @@
#include <vdr/osd.h>
#include <vdr/plugin.h>
#include <vdr/device.h>
#include <vdr/menu.h>
#include "tvguideosd.c"
@ -20,7 +21,7 @@
static const char *VERSION = "0.0.5";
static const char *VERSION = "0.0.6";
static const char *DESCRIPTION = "A fancy 2d EPG Viewer";
static const char *MAINMENUENTRY = "Tvguide";
@ -28,6 +29,7 @@ class cPluginTvguide : public cPlugin {
private:
bool logoPathSet;
bool imagesPathSet;
bool iconsPathSet;
public:
cPluginTvguide(void);
virtual ~cPluginTvguide();
@ -58,6 +60,7 @@ cPluginTvguide::cPluginTvguide(void)
// VDR OBJECTS TO EXIST OR PRODUCE ANY OUTPUT!
logoPathSet = false;
imagesPathSet = false;
iconsPathSet = false;
}
cPluginTvguide::~cPluginTvguide()
@ -124,6 +127,13 @@ bool cPluginTvguide::Start(void)
tvguideConfig.SetImagesPath(path);
logoPathSet = true;
}
if (!iconsPathSet) {
cString path = cString::sprintf("%s/icons/", cPlugin::ConfigDirectory(PLUGIN_NAME_I18N));
tvguideConfig.SetIconsPath(path);
iconsPathSet = true;
}
return true;
}

View File

@ -37,6 +37,21 @@ THEME_CLR(theme, clrButtonYellowBorder, 0xFFBBBB00);
THEME_CLR(theme, clrButtonBlue, 0x990000BB);
THEME_CLR(theme, clrButtonBlueBorder, 0xFF0000BB);
THEME_CLR(theme, clrButtonBlend, 0xDD000000);
THEME_CLR(theme, clrRecMenuBackground, 0xB0000000);
THEME_CLR(theme, clrRecMenuTimerConflictBackground, 0xFFCCCCCC);
THEME_CLR(theme, clrRecMenuTimerConflictBar, 0xFF222222);
THEME_CLR(theme, clrRecMenuTimerConflictOverlap, 0xAAFF0000);
THEME_CLR(theme, clrRecMenuDayActive, 0xFF00FF00);
THEME_CLR(theme, clrRecMenuDayInactive, 0xFFFF0000);
THEME_CLR(theme, clrRecMenuDayHighlight, 0x44FFFFFF);
THEME_CLR(theme, clrRecMenuTextBack, 0xFF000000);
THEME_CLR(theme, clrRecMenuTextActiveBack, 0xFF404749);
THEME_CLR(theme, clrRecMenuKeyboardBack, 0xFF000000);
THEME_CLR(theme, clrRecMenuKeyboardBorder, clrWhite);
THEME_CLR(theme, clrRecMenuKeyboardHigh, 0x55FFFFFF);
THEME_CLR(theme, clrButtonRedKeyboard, 0xFFBB0000);
THEME_CLR(theme, clrButtonGreenKeyboard, 0xFF00BB00);
THEME_CLR(theme, clrButtonYellowKeyboard, 0xFFBBBB00);
#include "config.c"
cTvguideConfig tvguideConfig;
@ -44,11 +59,12 @@ cTvguideConfig tvguideConfig;
#include "osdmanager.c"
cOsdManager osdManager;
#include "tools.c"
#include "switchtimer.c"
#include "setup.c"
#include "imageloader.c"
#include "styledpixmap.c"
#include "timer.c"
#include "messagebox.c"
#include "timeline.c"
#include "grid.c"
#include "headergrid.c"
@ -60,6 +76,11 @@ cOsdManager osdManager;
#include "channelgroup.c"
#include "channelgroups.c"
#include "footer.c"
#include "recmenuitem.c"
#include "recmenu.c"
#include "recmanager.c"
#include "recmenus.c"
#include "recmenumanager.c"
#include "tvguideosd.h"
#include <stdlib.h>
@ -69,6 +90,7 @@ cTvGuideOsd::cTvGuideOsd(void) {
detailViewActive = false;
activeGrid = NULL;
timeLine = NULL;
recMenuManager = NULL;
}
cTvGuideOsd::~cTvGuideOsd() {
@ -82,7 +104,7 @@ cTvGuideOsd::~cTvGuideOsd() {
delete timeLine;
delete channelGroups;
delete footer;
cMessageBox::Destroy();
delete recMenuManager;
osdManager.deleteOsd();
}
@ -97,6 +119,12 @@ void cTvGuideOsd::Show(void) {
osdManager.setBackground();
myTime = new cMyTime();
myTime->Now();
SwitchTimers.Load(AddDirectory(cPlugin::ConfigDirectory("epgsearch"), "epgsearchswitchtimers.conf"));
cSwitchTimer *st = NULL;
for (st = SwitchTimers.First(); st; st = SwitchTimers.Next(st)) {
esyslog("tvguide: switchtimer eventID %d time %ld", st->eventID, st->startTime);
}
recMenuManager = new cRecMenuManager();
drawOsd();
}
esyslog("tvguide: Rendering took %d ms", int(cTimeMs::Now()-start));
@ -392,37 +420,25 @@ void cTvGuideOsd::processKeyUp() {
if (!activeGrid) {
return;
}
if (detailViewActive) {
detailView->scrollUp();
osdManager.flush();
} else {
if (tvguideConfig.displayMode == eVertical) {
timeBack();
} else if (tvguideConfig.displayMode == eHorizontal) {
channelBack();
}
}
}
void cTvGuideOsd::processKeyDown() {
if (!activeGrid) {
return;
}
if (detailViewActive) {
detailView->scrollDown();
osdManager.flush();
} else {
if (tvguideConfig.displayMode == eVertical) {
timeForward();
} else if (tvguideConfig.displayMode == eHorizontal) {
channelForward();
}
}
}
void cTvGuideOsd::processKeyLeft() {
if (detailViewActive)
return;
if (activeGrid == NULL)
return;
if (tvguideConfig.displayMode == eVertical) {
@ -433,8 +449,6 @@ void cTvGuideOsd::processKeyLeft() {
}
void cTvGuideOsd::processKeyRight() {
if (detailViewActive)
return;
if (activeGrid == NULL)
return;
if (tvguideConfig.displayMode == eVertical) {
@ -447,26 +461,7 @@ void cTvGuideOsd::processKeyRight() {
void cTvGuideOsd::processKeyRed() {
if ((activeGrid == NULL) || activeGrid->isDummy())
return;
cTimer *timer = new cTimer(activeGrid->GetEvent());
cTimer *t = Timers.GetTimer(timer);
cString msg;
if (t) {
isyslog("timer %s already exists", *timer->ToDescr());
delete timer;
msg = cString::sprintf(tr("Timer not set! There is already a timer for this item."));
} else {
Timers.Add(timer);
Timers.SetModified();
msg = cString::sprintf("%s:\n%s (%s) %s - %s", tr("Timer set"), activeGrid->GetEvent()->Title(), timer->Channel()->Name(), *DayDateTime(timer->StartTime()), *TimeString(timer->StopTime()));
timer->SetEvent(activeGrid->GetEvent());
activeGrid->setTimer();
activeGrid->column->setTimer();
activeGrid->SetDirty();
activeGrid->Draw();
osdManager.flush();
isyslog("timer %s added (active)", *timer->ToDescr());
}
cMessageBox::Start(4000, msg);
recMenuManager->Start(activeGrid->GetEvent());
}
void cTvGuideOsd::processKeyGreen() {
@ -547,7 +542,7 @@ eOSState cTvGuideOsd::processKeyBlue() {
}
eOSState cTvGuideOsd::processKeyOk() {
if ((tvguideConfig.blueKeyMode == 0) || detailViewActive ) {
if (tvguideConfig.blueKeyMode == 0) {
DetailedEPG();
} else if (tvguideConfig.blueKeyMode == 1) {
return ChannelSwitch();
@ -567,17 +562,13 @@ eOSState cTvGuideOsd::ChannelSwitch() {
}
void cTvGuideOsd::DetailedEPG() {
if (detailViewActive) {
delete detailView;
detailView = NULL;
detailViewActive = false;
osdManager.flush();
} else {
if (!activeGrid->isDummy()) {
detailViewActive = true;
detailView = new cDetailView(activeGrid);
detailView->Start();
}
detailView = new cDetailView(activeGrid->GetEvent());
detailView->drawHeader();
detailView->drawContent();
detailView->drawScrollbar();
osdManager.flush();
}
}
@ -646,11 +637,32 @@ void cTvGuideOsd::processKey9() {
osdManager.flush();
}
void cTvGuideOsd::SetTimers() {
for (cChannelColumn *column = columns.First(); column; column = columns.Next(column)) {
column->SetTimers();
}
}
eOSState cTvGuideOsd::ProcessKey(eKeys Key) {
eOSState state = cOsdObject::ProcessKey(Key);
if (state == osUnknown) {
eOSState state = osContinue;
cPixmap::Lock();
if (recMenuManager->isActive()) {
state = recMenuManager->ProcessKey(Key);
if (state == osEnd) {
SetTimers();
osdManager.flush();
}
state = osContinue;
} else if (detailViewActive) {
state = detailView->ProcessKey(Key);
if (state == osEnd) {
delete detailView;
detailView = NULL;
detailViewActive = false;
osdManager.flush();
state = osContinue;
}
} else {
switch (Key & ~k_Repeat) {
case kUp: processKeyUp(); break;
case kDown: processKeyDown(); break;
@ -670,8 +682,8 @@ eOSState cTvGuideOsd::ProcessKey(eKeys Key) {
case k9: processKey9(); break;
default: break;
}
cPixmap::Unlock();
}
cPixmap::Unlock();
return state;
}

View File

@ -13,6 +13,7 @@ private:
cTimeLine *timeLine;
cChannelGroups *channelGroups;
cFooter *footer;
cRecMenuManager *recMenuManager;
bool detailViewActive;
void drawOsd();
void readChannels(const cChannel *channelStart);
@ -42,6 +43,7 @@ private:
void ScrollBack();
eOSState ChannelSwitch();
void DetailedEPG();
void SetTimers();
void dump();
public:
cTvGuideOsd(void);