1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

The 'Recordings' menu now displays a hierarchical structure

This commit is contained in:
Klaus Schmidinger 2002-01-20 14:05:28 +01:00
parent e1ab9c1dac
commit fd839aae7b
11 changed files with 306 additions and 64 deletions

View File

@ -879,7 +879,7 @@ Video Disk Recorder Revision History
- Fixed DVD audio sync problems (thanks to Andreas Schultz).
- Fixed external AC3 replay for DVDs (thanks to Andreas Schultz).
2002-01-13: Version 0.99pre2
2002-01-20: Version 0.99pre2
- Fixed setting the OSD size in the 'Confirm' interface call (thanks to
Deti Fliegl).
@ -896,3 +896,7 @@ Video Disk Recorder Revision History
Carsten Koch).
- No longer requiring 'libncurses' if compiling without DEBUG_OSD=1 and
REMOTE=KBD (thanks to Lauri Pesonen).
- The "Recordings" menu now displays a hierarchical structure if there are
subdirectories for the recordings. This can be controlled through the
"RecordingDirs" parameter in the "Setup" menu.
See "MANUAL/Replaying a Recording" for details.

10
MANUAL
View File

@ -159,6 +159,13 @@ Video Disk Recorder User's Manual
All recordings are listed in the "Recordings" menu. Browse through the
list with the "Up" and "Down" button and press "Ok" (or the "Red" button)
to start playback. New recordings are marked with an '*'.
If the Setup parameter RecordingDirs has been set and there are recordings
from periodic timers organized in a subdirectory structure, only the
directory is displayed and it can be opened by pressing "Ok" (or the "Red"
button). A directory entry displays the total number of recordings within
that directory (and any possible subdirectory thereof) as well as the total
number of new recordings (as opposed to a recording's entry, which displays
the date and time of the recording).
Playback can be stopped via the "Main" menu by selecting "Stop replaying",
or by pressing the "Blue" button outside the menu.
A previously stopped playback session can be resumed by pressing the "Blue"
@ -439,6 +446,9 @@ Video Disk Recorder User's Manual
0 = don't use the 'Subtitle'
1 = use it (and create subdirectories)
RecordingDirs = 1 Turns displaying the Recordings menu as a hierarchical
directory structure on or off.
VideoFormat = 0 The video format (or aspect ratio) of the tv set in use.
0 = 4:3
1 = 16:9

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.c 1.76 2001/10/20 13:09:38 kls Exp $
* $Id: config.c 1.77 2002/01/19 16:06:42 kls Exp $
*/
#include "config.h"
@ -807,6 +807,7 @@ cSetup::cSetup(void)
DefaultPriority = 50;
DefaultLifetime = 50;
UseSubtitle = 1;
RecordingDirs = 1;
VideoFormat = VIDEO_FORMAT_4_3;
ChannelInfoPos = 0;
OSDwidth = 52;
@ -848,6 +849,7 @@ bool cSetup::Parse(char *s)
else if (!strcasecmp(Name, "DefaultPriority")) DefaultPriority = atoi(Value);
else if (!strcasecmp(Name, "DefaultLifetime")) DefaultLifetime = atoi(Value);
else if (!strcasecmp(Name, "UseSubtitle")) UseSubtitle = atoi(Value);
else if (!strcasecmp(Name, "RecordingDirs")) RecordingDirs = atoi(Value);
else if (!strcasecmp(Name, "VideoFormat")) VideoFormat = atoi(Value);
else if (!strcasecmp(Name, "ChannelInfoPos")) ChannelInfoPos = atoi(Value);
else if (!strcasecmp(Name, "OSDwidth")) OSDwidth = atoi(Value);
@ -924,6 +926,7 @@ bool cSetup::Save(const char *FileName)
fprintf(f, "DefaultPriority = %d\n", DefaultPriority);
fprintf(f, "DefaultLifetime = %d\n", DefaultLifetime);
fprintf(f, "UseSubtitle = %d\n", UseSubtitle);
fprintf(f, "RecordingDirs = %d\n", RecordingDirs);
fprintf(f, "VideoFormat = %d\n", VideoFormat);
fprintf(f, "ChannelInfoPos = %d\n", ChannelInfoPos);
fprintf(f, "OSDwidth = %d\n", OSDwidth);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: config.h 1.87 2001/12/01 12:00:37 kls Exp $
* $Id: config.h 1.88 2002/01/19 16:06:53 kls Exp $
*/
#ifndef __CONFIG_H
@ -292,6 +292,7 @@ public:
int PrimaryLimit;
int DefaultPriority, DefaultLifetime;
int UseSubtitle;
int RecordingDirs;
int VideoFormat;
int ChannelInfoPos;
int OSDwidth, OSDheight;

29
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: i18n.c 1.45 2001/10/28 16:04:58 kls Exp $
* $Id: i18n.c 1.46 2002/01/19 16:25:33 kls Exp $
*
* Slovenian translations provided by Miha Setina <mihasetina@softhome.net>
* Italian translations provided by Alberto Carraro <bertocar@tin.it>
@ -285,6 +285,15 @@ const tPhrase Phrases[] = {
"Résumé",
"Sammendrag",
},
{ "Open",
"Öffnen",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "Switch",
"Umschalten",
"Preklopi",
@ -631,6 +640,15 @@ const tPhrase Phrases[] = {
"Enregistrement en cours!",
"Timer gjør opptak!",
},
{ "Error while accessing recording!",
"Fehler beim ansprechen der Aufzeichnung!",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "Error while deleting recording!",
"Fehler beim Löschen der Aufzeichnung!",
"Napaka pri odstranjevanju posnetka!",
@ -884,6 +902,15 @@ const tPhrase Phrases[] = {
"", // TODO
"", // TODO
},
{ "RecordingDirs",
"Aufn. Verzeichnisse",
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
"", // TODO
},
{ "VideoFormat",
"Video Format",
"", // TODO

187
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.c 1.142 2002/01/13 16:18:40 kls Exp $
* $Id: menu.c 1.143 2002/01/20 14:01:40 kls Exp $
*/
#include "menu.h"
@ -1494,46 +1494,155 @@ eOSState cMenuSchedule::ProcessKey(eKeys Key)
// --- cMenuRecordingItem ----------------------------------------------------
class cMenuRecordingItem : public cOsdItem {
private:
char *fileName;
char *name;
int totalEntries, newEntries;
public:
cRecording *recording;
cMenuRecordingItem(cRecording *Recording);
virtual void Set(void);
cMenuRecordingItem(cRecording *Recording, int Level);
~cMenuRecordingItem();
void IncrementCounter(bool New);
const char *Name(void) { return name; }
const char *FileName(void) { return fileName; }
bool IsDirectory(void) { return name != NULL; }
};
cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording)
cMenuRecordingItem::cMenuRecordingItem(cRecording *Recording, int Level)
{
recording = Recording;
Set();
fileName = strdup(Recording->FileName());
name = NULL;
totalEntries = newEntries = 0;
SetText(Recording->Title('\t', true, Level));
if (*Text() == '\t')
name = strdup(Text() + 2); // 'Text() + 2' to skip the two '\t'
}
void cMenuRecordingItem::Set(void)
cMenuRecordingItem::~cMenuRecordingItem()
{
SetText(recording->Title('\t', true));
delete fileName;
delete name;
}
void cMenuRecordingItem::IncrementCounter(bool New)
{
totalEntries++;
if (New)
newEntries++;
char *buffer = NULL;
asprintf(&buffer, "%d\t%d\t%s", totalEntries, newEntries, name);
SetText(buffer, false);
}
// --- cMenuRecordings -------------------------------------------------------
cMenuRecordings::cMenuRecordings(void)
:cOsdMenu(tr("Recordings"), 6, 6)
cRecordings cMenuRecordings::Recordings;
int cMenuRecordings::helpKeys = -1;
cMenuRecordings::cMenuRecordings(const char *Base, int Level, bool OpenSubMenus)
:cOsdMenu(Base ? Base : tr("Recordings"), 6, 6)
{
if (Recordings.Load()) {
const char *lastReplayed = cReplayControl::LastReplayed();
cRecording *recording = Recordings.First();
while (recording) {
Add(new cMenuRecordingItem(recording), lastReplayed && strcmp(lastReplayed, recording->FileName()) == 0);
recording = Recordings.Next(recording);
}
base = Base ? strdup(Base) : NULL;
level = Setup.RecordingDirs ? Level : -1;
if (Base || Recordings.Load()) {
const char *LastReplayed = cReplayControl::LastReplayed();
cMenuRecordingItem *LastItem = NULL;
char *LastItemText = NULL;
for (cRecording *recording = Recordings.First(); recording; recording = Recordings.Next(recording)) {
if (!Base || strstr(recording->Name(), Base) == recording->Name()) {
cMenuRecordingItem *Item = new cMenuRecordingItem(recording, level);
if (*Item->Text() && (!LastItem || strcmp(Item->Text(), LastItemText) != 0)) {
Add(Item);
LastItem = Item;
delete LastItemText;
LastItemText = strdup(LastItem->Text()); // must use a copy because of the counters!
}
else
delete Item;
if (LastItem) {
if (LastReplayed && strcmp(LastReplayed, recording->FileName()) == 0)
SetCurrent(LastItem);
if (LastItem->IsDirectory())
LastItem->IncrementCounter(recording->IsNew());
}
}
}
delete LastItemText;
if (Current() < 0)
SetCurrent(First());
else if (OpenSubMenus && Open(true))
return;
}
SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), tr("Summary"));
Display();
SetHelpKeys();
}
cMenuRecordings::~cMenuRecordings()
{
delete base;
}
void cMenuRecordings::SetHelpKeys(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
int NewHelpKeys = helpKeys;
if (ri) {
if (ri->IsDirectory())
NewHelpKeys = 1;
else {
NewHelpKeys = 2;
cRecording *recording = GetRecording(ri);
if (recording && recording->Summary())
NewHelpKeys = 3;
}
}
if (NewHelpKeys != helpKeys) {
switch (NewHelpKeys) {
case 0: SetHelp(NULL); break;
case 1: SetHelp(tr("Open")); break;
case 2:
case 3: SetHelp(tr("Play"), tr("Rewind"), tr("Delete"), NewHelpKeys == 3 ? tr("Summary") : NULL);
}
helpKeys = NewHelpKeys;
}
}
cRecording *cMenuRecordings::GetRecording(cMenuRecordingItem *Item)
{
cRecording *recording = Recordings.GetByName(Item->FileName());
if (!recording)
Interface->Error(tr("Error while accessing recording!"));
return recording;
}
bool cMenuRecordings::Open(bool OpenSubMenus)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri && ri->IsDirectory()) {
const char *t = ri->Name();
char *buffer = NULL;
if (base) {
asprintf(&buffer, "%s~%s", base, t);
t = buffer;
}
AddSubMenu(new cMenuRecordings(t, level + 1, OpenSubMenus));
delete buffer;
return true;
}
return false;
}
eOSState cMenuRecordings::Play(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
cReplayControl::SetRecording(ri->recording->FileName(), ri->recording->Title());
return osReplay;
if (ri->IsDirectory())
Open();
else {
cRecording *recording = GetRecording(ri);
if (recording) {
cReplayControl::SetRecording(recording->FileName(), recording->Title());
return osReplay;
}
}
}
return osContinue;
}
@ -1541,9 +1650,9 @@ eOSState cMenuRecordings::Play(void)
eOSState cMenuRecordings::Rewind(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
if (ri && !ri->IsDirectory()) {
cDvbApi::PrimaryDvbApi->StopReplay(); // must do this first to be able to rewind the currently replayed recording
cResumeFile ResumeFile(ri->recording->FileName());
cResumeFile ResumeFile(ri->FileName());
ResumeFile.Delete();
return Play();
}
@ -1553,17 +1662,21 @@ eOSState cMenuRecordings::Rewind(void)
eOSState cMenuRecordings::Del(void)
{
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri) {
if (ri && !ri->IsDirectory()) {
//XXX what if this recording's file is currently in use???
//XXX if (!ti->recording) {
if (Interface->Confirm(tr("Delete recording?"))) {
if (ri->recording->Delete()) {
cReplayControl::ClearLastReplayed(ri->recording->FileName());
cOsdMenu::Del(Current());
Display();
cRecording *recording = GetRecording(ri);
if (recording) {
if (recording->Delete()) {
cReplayControl::ClearLastReplayed(ri->FileName());
cOsdMenu::Del(Current());
Recordings.Del(recording);
Display();
}
else
Interface->Error(tr("Error while deleting recording!"));
}
else
Interface->Error(tr("Error while deleting recording!"));
}
//XXX }
//XXX else
@ -1577,8 +1690,11 @@ eOSState cMenuRecordings::Summary(void)
if (HasSubMenu() || Count() == 0)
return osContinue;
cMenuRecordingItem *ri = (cMenuRecordingItem *)Get(Current());
if (ri && ri->recording->Summary() && *ri->recording->Summary())
return AddSubMenu(new cMenuText(tr("Summary"), ri->recording->Summary()));
if (ri && !ri->IsDirectory()) {
cRecording *recording = GetRecording(ri);
if (recording && recording->Summary() && *recording->Summary())
return AddSubMenu(new cMenuText(tr("Summary"), recording->Summary()));
}
return osContinue;
}
@ -1597,6 +1713,8 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
default: break;
}
}
if (!HasSubMenu() && Key != kNone)
SetHelpKeys();
return state;
}
@ -1719,6 +1837,7 @@ void cMenuSetup::Set(void)
Add(new cMenuEditIntItem( tr("DefaultPriority"), &data.DefaultPriority, 0, MAXPRIORITY));
Add(new cMenuEditIntItem( tr("DefaultLifetime"), &data.DefaultLifetime, 0, MAXLIFETIME));
Add(new cMenuEditBoolItem(tr("UseSubtitle"), &data.UseSubtitle));
Add(new cMenuEditBoolItem(tr("RecordingDirs"), &data.RecordingDirs));
Add(new cMenuEditBoolItem(tr("VideoFormat"), &data.VideoFormat, "4:3", "16:9"));
Add(new cMenuEditBoolItem(tr("ChannelInfoPos"), &data.ChannelInfoPos, tr("bottom"), tr("top")));
Add(new cMenuEditIntItem( tr("OSDwidth"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH));
@ -1871,7 +1990,7 @@ cMenuMain::cMenuMain(bool Replaying, eOSState State)
// Initial submenus:
switch (State) {
case osRecordings: AddSubMenu(new cMenuRecordings); break;
case osRecordings: AddSubMenu(new cMenuRecordings(NULL, 0, true)); break;
#ifdef DVDSUPPORT
case osDVD: AddSubMenu(new cMenuDVD); break;
#endif //DVDSUPPORT

15
menu.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: menu.h 1.34 2001/10/28 15:21:04 kls Exp $
* $Id: menu.h 1.35 2002/01/20 13:38:34 kls Exp $
*/
#ifndef _MENU_H
@ -55,15 +55,24 @@ public:
};
#endif //DVDSUPPORT
class cMenuRecordingItem;
class cMenuRecordings : public cOsdMenu {
private:
cRecordings Recordings;
static cRecordings Recordings;
char *base;
int level;
static int helpKeys;
void SetHelpKeys(void);
cRecording *GetRecording(cMenuRecordingItem *Item);
bool Open(bool OpenSubMenus = false);
eOSState Play(void);
eOSState Rewind(void);
eOSState Del(void);
eOSState Summary(void);
public:
cMenuRecordings(void);
cMenuRecordings(const char *Base = NULL, int Level = 0, bool OpenSubMenus = false);
~cMenuRecordings();
virtual eOSState ProcessKey(eKeys Key);
};

11
osd.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.c 1.18 2001/08/25 13:15:16 kls Exp $
* $Id: osd.c 1.19 2002/01/20 11:13:22 kls Exp $
*/
#include "osd.h"
@ -150,6 +150,10 @@ void cOsdMenu::Add(cOsdItem *Item, bool Current)
void cOsdMenu::Display(void)
{
if (subMenu) {
subMenu->Display();
return;
}
visible = true;
Interface->Clear();
Interface->SetCols(cols);
@ -179,6 +183,11 @@ void cOsdMenu::Display(void)
Interface->Status(status);
}
void cOsdMenu::SetCurrent(cOsdItem *Item)
{
current = Item ? Item->Index() : -1;
}
void cOsdMenu::RefreshCurrent(void)
{
cOsdItem *item = Get(current);

3
osd.h
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: osd.h 1.24 2001/08/25 12:56:46 kls Exp $
* $Id: osd.h 1.25 2002/01/20 10:42:14 kls Exp $
*/
#ifndef __OSD_H
@ -83,6 +83,7 @@ protected:
bool visible;
virtual void Clear(void);
bool SpecialItem(int idx);
void SetCurrent(cOsdItem *Item);
void RefreshCurrent(void);
void DisplayCurrent(bool Current);
void CursorUp(void);

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.c 1.42 2001/10/20 10:28:28 kls Exp $
* $Id: recording.c 1.43 2002/01/20 12:14:25 kls Exp $
*/
#include "recording.h"
@ -184,6 +184,8 @@ void cResumeFile::Delete(void)
// --- cRecording ------------------------------------------------------------
#define RESUME_NOT_INITIALIZED (-2)
struct tCharExchange { char a; char b; };
tCharExchange CharExchange[] = {
{ '~', '/' },
@ -213,6 +215,7 @@ char *ExchangeChars(char *s, bool ToFileSystem)
cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary)
{
resume = RESUME_NOT_INITIALIZED;
titleBuffer = NULL;
sortBuffer = NULL;
fileName = NULL;
@ -242,6 +245,7 @@ cRecording::cRecording(cTimer *Timer, const char *Subtitle, const char *Summary)
cRecording::cRecording(const char *FileName)
{
resume = RESUME_NOT_INITIALIZED;
titleBuffer = NULL;
sortBuffer = NULL;
fileName = strdup(FileName);
@ -342,6 +346,15 @@ char *cRecording::SortName(void)
return sortBuffer;
}
int cRecording::GetResume(void)
{
if (resume == RESUME_NOT_INITIALIZED) {
cResumeFile ResumeFile(FileName());
resume = ResumeFile.Read();
}
return resume;
}
bool cRecording::operator< (const cListObject &ListObject)
{
cRecording *r = (cRecording *)&ListObject;
@ -360,27 +373,47 @@ const char *cRecording::FileName(void)
return fileName;
}
const char *cRecording::Title(char Delimiter, bool NewIndicator)
const char *cRecording::Title(char Delimiter, bool NewIndicator, int Level)
{
char New = ' ';
if (NewIndicator) {
cResumeFile ResumeFile(FileName());
if (ResumeFile.Read() <= 0)
New = '*';
}
char New = NewIndicator && IsNew() ? '*' : ' ';
delete titleBuffer;
titleBuffer = NULL;
struct tm tm_r;
struct tm *t = localtime_r(&start, &tm_r);
asprintf(&titleBuffer, "%02d.%02d%c%02d:%02d%c%c%s",
t->tm_mday,
t->tm_mon + 1,
Delimiter,
t->tm_hour,
t->tm_min,
New,
Delimiter,
name);
if (Level < 0 || Level == HierarchyLevels()) {
struct tm tm_r;
struct tm *t = localtime_r(&start, &tm_r);
const char *s;
if (Level > 0 && (s = strrchr(name, '~')) != NULL)
s++;
else
s = name;
asprintf(&titleBuffer, "%02d.%02d%c%02d:%02d%c%c%s",
t->tm_mday,
t->tm_mon + 1,
Delimiter,
t->tm_hour,
t->tm_min,
New,
Delimiter,
s);
}
else if (Level < HierarchyLevels()) {
const char *s = name;
const char *p = s;
while (*++s) {
if (*s == '~') {
if (Level--)
p = s + 1;
else
break;
}
}
titleBuffer = new char[s - p + 3];
*titleBuffer = Delimiter;
*(titleBuffer + 1) = Delimiter;
strn0cpy(titleBuffer + 2, p, s - p + 1);
}
else
return "";
return titleBuffer;
}
@ -395,6 +428,17 @@ const char *cRecording::PrefixFileName(char Prefix)
return NULL;
}
int cRecording::HierarchyLevels(void)
{
const char *s = name;
int level = 0;
while (*++s) {
if (*s == '~')
level++;
}
return level;
}
bool cRecording::WriteSummary(void)
{
if (summary) {
@ -461,6 +505,15 @@ bool cRecordings::Load(bool Deleted)
return result;
}
cRecording *cRecordings::GetByName(const char *FileName)
{
for (cRecording *recording = First(); recording; recording = Next(recording)) {
if (strcmp(recording->FileName(), FileName) == 0)
return recording;
}
return NULL;
}
// --- cMark -----------------------------------------------------------------
char *cMark::buffer = NULL;

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and
* how to reach the author.
*
* $Id: recording.h 1.18 2001/10/07 10:38:56 kls Exp $
* $Id: recording.h 1.19 2002/01/20 11:35:32 kls Exp $
*/
#ifndef __RECORDING_H
@ -31,6 +31,7 @@ public:
class cRecording : public cListObject {
friend class cRecordings;
private:
int resume;
char *titleBuffer;
char *sortBuffer;
char *fileName;
@ -38,6 +39,7 @@ private:
char *summary;
char *StripEpisodeName(char *s);
char *SortName(void);
int GetResume(void);
public:
time_t start;
int priority;
@ -46,10 +48,13 @@ public:
cRecording(const char *FileName);
~cRecording();
virtual bool operator< (const cListObject &ListObject);
const char *Name(void) { return name; }
const char *FileName(void);
const char *Title(char Delimiter = ' ', bool NewIndicator = false);
const char *Title(char Delimiter = ' ', bool NewIndicator = false, int Level = -1);
const char *Summary(void) { return summary; }
const char *PrefixFileName(char Prefix);
int HierarchyLevels(void);
bool IsNew(void) { return GetResume() <= 0; }
bool WriteSummary(void);
bool Delete(void);
// Changes the file name so that it will no longer be visible in the "Recordings" menu
@ -62,6 +67,7 @@ public:
class cRecordings : public cList<cRecording> {
public:
bool Load(bool Deleted = false);
cRecording *GetByName(const char *FileName);
};
class cMark : public cListObject {