/* -*- 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 as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Or, point your browser to http://www.gnu.org/licenses/old-licenses/gpl-2.0.html The author can be reached at cwieninger@gmx.de The project's page is at http://winni.vdr-developer.org/epgsearch */ #include "menu_dirselect.h" #include "epgsearchext.h" #include "epgsearchcats.h" #include "epgsearchtools.h" set cMenuDirSelect::directorySet; cDirExts DirExts; cConfDDirExts ConfDDirExts; // --- cMenuDirItem --------------------------------------------------------- class cMenuDirItem : public cOsdItem { private: char* directory; public: cMenuDirItem(const char* text) : cOsdItem(text) { directory = strdup(text); } ~cMenuDirItem() { if (directory) free(directory); } virtual int Compare(const cListObject &ListObject) const; }; int cMenuDirItem::Compare(const cListObject &ListObject) const { const cMenuDirItem *p = (cMenuDirItem *)&ListObject; int hasVars1 = (strchr(directory, '%') != NULL ? 1 : 0); int hasVars2 = (strchr(p->directory, '%') != NULL ? 1 : 0); if (hasVars1 || hasVars2) { if (hasVars1 != hasVars2) return hasVars2 - hasVars1; else return strcasecmp(directory, p->directory); } else return strcasecmp(directory, p->directory); } // --- cMenuDirSelect --------------------------------------------------------- cMenuDirSelect::cMenuDirSelect(char* szDirectory) : cOsdMenu(tr("Select directory")) { SetMenuCategory(mcTimerEdit); Directory = szDirectory; yellow = NULL; MaxLevel = 1; CurLevel = 1; Load(); } cMenuDirSelect::~cMenuDirSelect() { if (yellow) free(yellow); } int cMenuDirSelect::Level(const char* szDir) { int iLevel = 1; if (strchr(szDir, '%')) // dirs with vars always have level 1 return 1; do { const char* pos = strchr(szDir, '~'); if (pos) { iLevel++; szDir = pos + 1; } else return iLevel; } while (true); return 1; } void cMenuDirSelect::AddDistinct(const char* szText) { int iLevel = Level(szText); MaxLevel = std::max(MaxLevel, iLevel); if (iLevel > CurLevel) // only show Items of the specified level, except those with vars return; for (int i = 0; i < Count(); i++) { const char* ItemText = Get(i)->Text(); char* itemtext = strdup(ItemText); char* sztext = strdup(szText); ToLower(itemtext); ToLower(sztext); if (itemtext && strlen(itemtext) > 0 && strcmp(sztext, itemtext) == 0) { free(itemtext); free(sztext); return; } free(itemtext); free(sztext); } Add(new cMenuDirItem(hk(szText))); } void cMenuDirSelect::CreateDirSet(bool extraDirs) { directorySet.clear(); // add distinct directories from current recordings { LOCK_RECORDINGS_READ; for (const cRecording *recording = Recordings->First(); recording; recording = Recordings->Next(recording)) { if (recording->HierarchyLevels() > 0) { char* dir = strdup(recording->Name()); // strip the trailing rec dir char* pos = strrchr(dir, '~'); if (pos) { *pos = 0; for (int iLevel = 0; iLevel < recording->HierarchyLevels(); iLevel++) { directorySet.insert(dir); char* pos = strrchr(dir, '~'); if (pos) *pos = 0; } } free(dir); } } } // give up Recordings Lock // add distinct directories from current timers { LOCK_TIMERS_READ; for (const cTimer *timer = Timers->First(); timer; timer = Timers->Next(timer)) { char* dir = strdup(timer->File()); // strip the trailing name dir char* pos = strrchr(dir, '~'); if (pos) { *pos = 0; do { directorySet.insert(dir); char* pos = strrchr(dir, '~'); if (pos) *pos = 0; else break; } while (true); } free(dir); } } // add distinct directories from folders.conf for (cNestedItem* item = Folders.First(); item; item = Folders.Next(item)) AddVDRFolders(item); if (extraDirs) { cMutexLock SearchExtsLock(&SearchExts); cSearchExt *searchExt = SearchExts.First(); // add distinct directories from existing search timers while (searchExt) { if (strlen(searchExt->directory) > 0) directorySet.insert(searchExt->directory); searchExt = SearchExts.Next(searchExt); } // add distinct directories from epgsearchdirs.conf DirExts.Load(AddDirectory(CONFIGDIR, "epgsearchdirs.conf"), true); cDirExt* DirExt = DirExts.First(); while (DirExt) { directorySet.insert(DirExt->Name()); DirExt = DirExts.Next(DirExt); } // add distinct directories from conf.d files DirExt = ConfDDirExts.First(); while (DirExt) { directorySet.insert(DirExt->Name()); DirExt = ConfDDirExts.Next(DirExt); } } } void cMenuDirSelect::AddVDRFolders(cNestedItem* folder, string parentDirectory) { if (folder == NULL) return; string folderDirectory = string((parentDirectory.size() == 0) ? "" : parentDirectory + "~") + folder->Text(); directorySet.insert(folderDirectory); if (folder->SubItems() == NULL) return; for (cNestedItem* subfolder = folder->SubItems()->First(); subfolder; subfolder = folder->SubItems()->Next(subfolder)) AddVDRFolders(subfolder, folderDirectory); } void cMenuDirSelect::Load() { int current = Current(); char* oldSelection = NULL; // save old selection for reselection if (current > -1) oldSelection = strdup(Get(current)->Text()); Clear(); CreateDirSet(); std::set::iterator it; for (it = directorySet.begin(); it != directorySet.end(); ++it) AddDistinct((*it).c_str()); Sort(); for (int i = 0; i < Count(); i++) { const char* text = Get(i)->Text(); if (oldSelection && strchr(text, '%') == NULL && strstr(text, oldSelection) == text) { // skip entries with variables SetCurrent(Get(i)); break; } } if (oldSelection) free(oldSelection); if (yellow) { free(yellow); yellow = NULL; } msprintf(&yellow, "%s %d", tr("Button$Level"), (CurLevel == MaxLevel ? 1 : CurLevel + 1)); SetHelp(NULL, NULL, MaxLevel == 1 ? NULL : yellow, tr("Button$Select")); Display(); } eOSState cMenuDirSelect::ProcessKey(eKeys Key) { eOSState state = cOsdMenu::ProcessKey(Key); if (state == osUnknown) { switch ((int)Key) { case kBlue|k_Repeat: case kYellow: if (++CurLevel > MaxLevel) CurLevel = 1; Load(); return osContinue; case kGreen: case kRed: return osContinue; case kBlue: case kOk: if (Count() > 0) strn0cpy(Directory, Get(Current())->Text(), MaxFileName); return osBack; default: break; } } return state; }