Ticket #4588: mythtv-move_storagegroup_to_libmyth.patch

File mythtv-move_storagegroup_to_libmyth.patch, 56.7 KB (added by sphery <mtdean@…>, 16 years ago)
  • libs/libmythtv/libmythtv.pro

     
    120120
    121121# Misc. needed by backend/frontend
    122122HEADERS += programinfo.h            proglist.h
    123 HEADERS += storagegroup.h
    124123HEADERS += RingBuffer.h             avfringbuffer.h
    125124HEADERS += ThreadedFileWriter.h     previouslist.h
    126125HEADERS += dbcheck.h                customedit.h
     
    141140HEADERS += importicons.h
    142141
    143142SOURCES += programinfo.cpp          proglist.cpp
    144 SOURCES += storagegroup.cpp
    145143SOURCES += RingBuffer.cpp           avfringbuffer.cpp
    146144SOURCES += ThreadedFileWriter.cpp   previouslist.cpp
    147145SOURCES += dbcheck.cpp              customedit.cpp
  • libs/libmythtv/storagegroup.h

     
    1 #ifndef _STORAGEGROUP_H
    2 #define _STORAGEGROUP_H
    3 
    4 #include <qstringlist.h>
    5 #include <qdeepcopy.h>
    6 
    7 #include "libmyth/settings.h"
    8 #include "libmyth/mythwidgets.h"
    9 
    10 class MPUBLIC StorageGroup: public ConfigurationWizard
    11 {
    12   public:
    13     StorageGroup(const QString group = "", const QString hostname = "");
    14 
    15     void    Init(const QString group = "Default",
    16                  const QString hostname = "");
    17 
    18     QString getName(void) const
    19         { return QDeepCopy<QString>(m_groupname); }
    20 
    21     QStringList GetDirList(void) const
    22         { return QDeepCopy<QStringList>(m_dirlist); }
    23 
    24     QString FindRecordingFile(QString filename);
    25     QString FindRecordingDir(QString filename);
    26 
    27     QString FindNextDirMostFree(void);
    28 
    29     static void CheckAllStorageGroupDirs(void);
    30 
    31     static const char *kDefaultStorageDir;
    32     static const QStringList kSpecialGroups;
    33 
    34     static QStringList getRecordingsGroups(void);
    35 
    36   private:
    37     QString      m_groupname;
    38     QString      m_hostname;
    39     QStringList  m_dirlist;
    40 };
    41 
    42 class MPUBLIC StorageGroupEditor :
    43     public QObject, public ConfigurationDialog
    44 {
    45     Q_OBJECT
    46   public:
    47     StorageGroupEditor(QString group);
    48     virtual DialogCode exec(void);
    49     virtual void load(void);
    50     virtual void save(void) { };
    51     virtual void save(QString) { };
    52     virtual MythDialog* dialogWidget(MythMainWindow* parent,
    53                                      const char* widgetname=0);
    54 
    55   protected slots:
    56     void open(QString name);
    57     void doDelete(void);
    58 
    59   protected:
    60     QString         m_group;
    61     ListBoxSetting *listbox;
    62     QString         lastValue;
    63 };
    64 
    65 class MPUBLIC StorageGroupListEditor :
    66     public QObject, public ConfigurationDialog
    67 {
    68     Q_OBJECT
    69   public:
    70     StorageGroupListEditor(void);
    71     virtual DialogCode exec(void);
    72     virtual void load(void);
    73     virtual void save(void) { };
    74     virtual void save(QString) { };
    75     virtual MythDialog* dialogWidget(MythMainWindow* parent,
    76                                      const char* widgetname=0);
    77 
    78   protected slots:
    79     void open(QString name);
    80     void doDelete(void);
    81 
    82   protected:
    83     ListBoxSetting *listbox;
    84     QString         lastValue;
    85 };
    86 
    87 #endif
    88 
    89 /* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmythtv/storagegroup.cpp

     
    1 #include <qdir.h>
    2 #include <qfile.h>
    3 #include <qregexp.h>
    4 
    5 #include "storagegroup.h"
    6 #include "libmyth/mythcontext.h"
    7 #include "libmyth/mythdbcon.h"
    8 #include "libmyth/util.h"
    9 
    10 #define LOC QString("SG(%1): ").arg(m_groupname)
    11 #define LOC_WARN QString("SG(%1) Warning: ").arg(m_groupname)
    12 #define LOC_ERR QString("SG(%1) Error: ").arg(m_groupname)
    13 
    14 const char *StorageGroup::kDefaultStorageDir = "/mnt/store";
    15 
    16 const QStringList StorageGroup::kSpecialGroups = QStringList()
    17     << "LiveTV"
    18 //    << "Thumbnails"
    19 //    << "DB Backups"
    20     ;
    21 
    22 /****************************************************************************/
    23 
    24 /** \brief StorageGroup constructor.
    25  *  \param group    storage group to search, blank will search all groups.
    26  *  \param hostname hostname where to search, blank will search all hosts'
    27  *                  directories, but only in local directory structure.
    28  *                  This is parameter is ignored if group is an empty string.
    29  */
    30 StorageGroup::StorageGroup(const QString group, const QString hostname) :
    31     m_groupname(QDeepCopy<QString>(group)),
    32     m_hostname(QDeepCopy<QString>(hostname))
    33 {
    34     m_dirlist.clear();
    35 
    36     Init(m_groupname, m_hostname);
    37 }
    38 
    39 void StorageGroup::Init(const QString group, const QString hostname)
    40 {
    41     QString dirname;
    42     MSqlQuery query(MSqlQuery::InitCon());
    43 
    44     m_groupname = QDeepCopy<QString>(group);
    45     m_hostname  = QDeepCopy<QString>(hostname);
    46     m_dirlist.clear();
    47 
    48     QString sql = "SELECT DISTINCT dirname "
    49                   "FROM storagegroup ";
    50 
    51     if (!m_groupname.isEmpty())
    52     {
    53         sql.append("WHERE groupname = :GROUP");
    54         if (!m_hostname.isEmpty())
    55             sql.append(" AND hostname = :HOSTNAME");
    56     }
    57 
    58     query.prepare(sql);
    59     query.bindValue(":GROUP", m_groupname);
    60     query.bindValue(":HOSTNAME", m_hostname);
    61 
    62     if (!query.exec() || !query.isActive())
    63         MythContext::DBError("StorageGroup::StorageGroup()", query);
    64     else if (!query.next())
    65     {
    66         if (group != "Default")
    67         {
    68             VERBOSE(VB_FILE, LOC +
    69                     QString("Unable to find storage group '%1', trying "
    70                             "'Default' group!").arg(m_groupname));
    71             Init("Default", m_hostname);
    72             return;
    73         }
    74         else if (!m_hostname.isEmpty())
    75         {
    76             VERBOSE(VB_FILE, LOC +
    77                     QString("Unable to find any directories for the local "
    78                             "Default storage group, trying directories in all "
    79                             "Default groups!").arg(m_groupname));
    80             Init("Default", "");
    81             return;
    82         }
    83     }
    84     else
    85     {
    86         do
    87         {
    88             dirname = query.value(0).toString();
    89             dirname.replace(QRegExp("^\\s*"), "");
    90             dirname.replace(QRegExp("\\s*$"), "");
    91             if (dirname.right(1) == "/")
    92                 dirname.remove(dirname.length() - 1, 1);
    93             m_dirlist << QDeepCopy<QString>(dirname);
    94         }
    95         while (query.next());
    96     }
    97 
    98     if (!m_dirlist.size())
    99     {
    100         QString msg = "Directory value for Default Storage Group is empty.  ";
    101         QString tmpDir = gContext->GetSetting("RecordFilePrefix");
    102         if (tmpDir != "")
    103         {
    104             msg += QString("Using old 'RecordFilePrefix' value of '%1'")
    105                            .arg(tmpDir);
    106         }
    107         else
    108         {
    109             tmpDir = kDefaultStorageDir;
    110             msg += QString("Using hardcoded default value of '%1'")
    111                            .arg(kDefaultStorageDir);
    112         }
    113         VERBOSE(VB_IMPORTANT, LOC_ERR + msg);
    114         m_dirlist << QDeepCopy<QString>(tmpDir);
    115     }
    116 }
    117 
    118 QString StorageGroup::FindRecordingFile(QString filename)
    119 {
    120     VERBOSE(VB_FILE, LOC + QString("FindRecordingFile: Searching for '%1'")
    121                                    .arg(filename));
    122 
    123     QString recDir = FindRecordingDir(filename);
    124     QString result = "";
    125    
    126     if (!recDir.isEmpty())
    127     {
    128         result = recDir + "/" + filename;
    129         VERBOSE(VB_FILE, LOC + QString("FindRecordingFile: Found '%1'")
    130                                        .arg(result));
    131     }
    132     else
    133     {
    134         VERBOSE(VB_FILE, LOC_ERR +
    135                 QString("FindRecordingFile: Unable to find '%1'!")
    136                         .arg(filename));
    137     }
    138 
    139     return result;
    140 }
    141 
    142 QString StorageGroup::FindRecordingDir(QString filename)
    143 {
    144     QString result = "";
    145     QFile checkFile("");
    146 
    147     unsigned int curDir = 0;
    148     while (curDir < m_dirlist.size())
    149     {
    150         QString testFile = m_dirlist[curDir] + "/" + filename;
    151         VERBOSE(VB_FILE, LOC + QString("FindRecordingDir: Checking '%1'")
    152                 .arg(m_dirlist[curDir]));
    153         checkFile.setName(testFile);
    154         if (checkFile.exists())
    155             return QDeepCopy<QString>(m_dirlist[curDir]);
    156 
    157         curDir++;
    158     }
    159 
    160     if (m_groupname.isEmpty())
    161     {
    162         // Not found in any dir, so try RecordFilePrefix if it exists
    163         QString tmpFile =
    164             gContext->GetSetting("RecordFilePrefix") + "/" + filename;
    165         checkFile.setName(tmpFile);
    166         if (checkFile.exists())
    167             result = tmpFile;
    168     }
    169     else if (m_groupname != "Default")
    170     {
    171         // Not found in current group so try Default
    172         StorageGroup sgroup("Default");
    173         QString tmpFile = sgroup.FindRecordingDir(filename);
    174         result = (tmpFile.isEmpty()) ? result : tmpFile;
    175     }
    176     else
    177     {
    178         // Not found in Default so try any dir
    179         StorageGroup sgroup;
    180         QString tmpFile = sgroup.FindRecordingDir(filename);
    181         result = (tmpFile.isEmpty()) ? result : tmpFile;
    182     }
    183 
    184     return QDeepCopy<QString>(result);
    185 }
    186 
    187 QString StorageGroup::FindNextDirMostFree(void)
    188 {
    189     QString nextDir = kDefaultStorageDir;
    190     long long nextDirFree = 0;
    191     long long thisDirTotal;
    192     long long thisDirUsed;
    193     long long thisDirFree;
    194 
    195     VERBOSE(VB_FILE, LOC + QString("FindNextDirMostFree: Starting'"));
    196 
    197     if (m_dirlist.size())
    198         nextDir = m_dirlist[0];
    199 
    200     QDir checkDir("");
    201     unsigned int curDir = 0;
    202     while (curDir < m_dirlist.size())
    203     {
    204         checkDir.setPath(m_dirlist[curDir]);
    205         if (!checkDir.exists())
    206         {
    207             VERBOSE(VB_IMPORTANT, LOC_ERR +
    208                     QString("FindNextDirMostFree: '%1' does not exist!")
    209                             .arg(nextDir));
    210             curDir++;
    211             continue;
    212         }
    213 
    214         thisDirFree = getDiskSpace(m_dirlist[curDir], thisDirTotal,
    215                                    thisDirUsed);
    216         VERBOSE(VB_FILE, LOC +
    217                 QString("FindNextDirMostFree: '%1' has %2 KiB free")
    218                         .arg(m_dirlist[curDir])
    219                         .arg(longLongToString(thisDirFree)));
    220 
    221         if (thisDirFree > nextDirFree)
    222         {
    223             nextDir     = m_dirlist[curDir];
    224             nextDirFree = thisDirFree;
    225         }
    226         curDir++;
    227     }
    228 
    229     VERBOSE(VB_FILE, LOC + QString("FindNextDirMostFree: Using '%1'")
    230                                    .arg(nextDir));
    231 
    232     return QDeepCopy<QString>(nextDir);
    233 }
    234 
    235 void StorageGroup::CheckAllStorageGroupDirs(void)
    236 {
    237     QString m_groupname;
    238     QString dirname;
    239     MSqlQuery query(MSqlQuery::InitCon());
    240 
    241     query.prepare("SELECT groupname, dirname "
    242                   "FROM storagegroup "
    243                   "WHERE hostname = :HOSTNAME;");
    244     query.bindValue(":HOSTNAME", gContext->GetHostName());
    245     if (!query.exec() || !query.isActive())
    246     {
    247         MythContext::DBError("StorageGroup::CheckAllStorageGroupDirs()", query);
    248         return;
    249     }
    250 
    251     VERBOSE(VB_FILE, LOC + "CheckAllStorageGroupDirs(): Checking All Storage "
    252             "Group directories");
    253 
    254     QFile testFile("");
    255     QDir testDir("");
    256     while (query.next())
    257     {
    258         m_groupname = query.value(0).toString();
    259         dirname = query.value(1).toString();
    260 
    261         dirname.replace(QRegExp("^\\s*"), "");
    262         dirname.replace(QRegExp("\\s*$"), "");
    263 
    264         VERBOSE(VB_FILE, LOC +
    265                 QString("Checking directory '%1' in group '%2'.")
    266                         .arg(dirname).arg(m_groupname));
    267 
    268         testDir.setPath(dirname);
    269         if (!testDir.exists())
    270         {
    271             VERBOSE(VB_FILE, LOC_WARN +
    272                     QString("Group '%1' references directory '%2' but this "
    273                             "directory does not exist.  This directory "
    274                             "will not be used on this server.")
    275                             .arg(m_groupname).arg(dirname));
    276         }
    277         else
    278         {
    279             testFile.setName(dirname + "/.test");
    280             if (testFile.open(IO_WriteOnly))
    281                 testFile.remove();
    282             else
    283                 VERBOSE(VB_IMPORTANT,
    284                         LOC_ERR +
    285                         QString("Group '%1' wants to use directory '%2', but "
    286                                 "this directory is not writeable.")
    287                                 .arg(m_groupname).arg(dirname));
    288         }
    289     }
    290 }
    291 
    292 QStringList StorageGroup::getRecordingsGroups(void)
    293 {
    294     QStringList groups;
    295 
    296     MSqlQuery query(MSqlQuery::InitCon());
    297 
    298     QString sql = "SELECT DISTINCT groupname "
    299                   "FROM storagegroup "
    300                   "WHERE groupname NOT IN (";
    301     for (QStringList::const_iterator it = StorageGroup::kSpecialGroups.begin();
    302          it != StorageGroup::kSpecialGroups.end(); ++it)
    303         sql.append(QString(" '%1',").arg(*it));
    304     sql = sql.left(sql.length() - 1);
    305     sql.append(" );");
    306 
    307     query.prepare(sql);
    308     if (query.exec() && query.isActive() && query.size() > 0)
    309         while (query.next())
    310             groups += QString::fromUtf8(query.value(0).toString());
    311 
    312     groups.sort();
    313 
    314     return QDeepCopy<QStringList>(groups);
    315 }
    316 
    317 /****************************************************************************/
    318 typedef enum {
    319     SGPopup_OK = 0,
    320     SGPopup_CANCEL,
    321     SGPopup_DELETE
    322 } SGPopupResult;
    323 
    324 class StorageGroupPopup
    325 {
    326   public:
    327     static SGPopupResult showPopup(MythMainWindow *parent, QString title,
    328                                    QString message, QString& text);
    329 };
    330 
    331 SGPopupResult StorageGroupPopup::showPopup(MythMainWindow *parent,
    332                                  QString title, QString message, QString& text)
    333 {
    334     MythPopupBox *popup = new MythPopupBox(parent, title);
    335     popup->addLabel(message);
    336 
    337     MythLineEdit *textEdit = new MythLineEdit(popup, "chooseEdit");
    338     textEdit->setText(text);
    339     popup->addWidget(textEdit);
    340 
    341     popup->addButton(QObject::tr("OK"),     popup, SLOT(accept()));
    342     popup->addButton(QObject::tr("Cancel"), popup, SLOT(reject()));
    343 
    344     textEdit->setFocus();
    345 
    346     bool ok = (MythDialog::Accepted == popup->ExecPopup());
    347     if (ok)
    348         text = QDeepCopy<QString>(textEdit->text());
    349 
    350     popup->hide();
    351     popup->deleteLater();
    352 
    353     return (ok) ? SGPopup_OK : SGPopup_CANCEL;
    354 }
    355 
    356 /****************************************************************************/
    357 
    358 StorageGroupEditor::StorageGroupEditor(QString group) :
    359     m_group(group), listbox(new ListBoxSetting(this)), lastValue("")
    360 {
    361     QString dispGroup = group;
    362 
    363     if (group == "Default")
    364         dispGroup = QObject::tr("Default");
    365     else if (StorageGroup::kSpecialGroups.contains(group))
    366         dispGroup = QObject::tr(group);
    367 
    368     if (gContext->GetSetting("MasterServerIP","master") ==
    369             gContext->GetSetting("BackendServerIP","me"))
    370     {
    371         listbox->setLabel(tr("'%1' Storage Group Directories").arg(dispGroup));
    372     }
    373     else
    374     {
    375         listbox->setLabel(tr("Local '%1' Storage Group Directories")
    376                              .arg(dispGroup));
    377     }
    378 
    379     addChild(listbox);
    380 }
    381 
    382 void StorageGroupEditor::open(QString name)
    383 {
    384     lastValue = name;
    385 
    386     if (name == "__CREATE_NEW_STORAGE_DIRECTORY__")
    387     {
    388         name = "";
    389         SGPopupResult result = StorageGroupPopup::showPopup(
    390             gContext->GetMainWindow(),
    391             tr("Add Storage Group Directory"),
    392             tr("Enter directory name or press SELECT to enter text via the "
    393                "On Screen Keyboard"), name);
    394         if (result == SGPopup_CANCEL)
    395             return;
    396 
    397         if (name.right(1) != "/")
    398             name.append("/");
    399 
    400         MSqlQuery query(MSqlQuery::InitCon());
    401         query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
    402                       "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
    403         query.bindValue(":NAME", m_group.utf8());
    404         query.bindValue(":DIRNAME", name.utf8());
    405         query.bindValue(":HOSTNAME", gContext->GetHostName());
    406         if (!query.exec())
    407             MythContext::DBError("StorageGroupEditor::open", query);
    408         else
    409             lastValue = name;
    410     } else {
    411         SGPopupResult result = StorageGroupPopup::showPopup(
    412             gContext->GetMainWindow(),
    413             tr("Edit Storage Group Directory"),
    414             tr("Enter directory name or press SELECT to enter text via the "
    415                "On Screen Keyboard"), name);
    416         if (result == SGPopup_CANCEL)
    417             return;
    418 
    419         if (name.right(1) != "/")
    420             name.append("/");
    421 
    422         MSqlQuery query(MSqlQuery::InitCon());
    423 
    424         query.prepare("DELETE FROM storagegroup "
    425                       "WHERE groupname = :NAME "
    426                           "AND dirname = :DIRNAME "
    427                           "AND hostname = :HOSTNAME;");
    428         query.bindValue(":NAME", m_group.utf8());
    429         query.bindValue(":DIRNAME", lastValue.utf8());
    430         query.bindValue(":HOSTNAME", gContext->GetHostName());
    431         if (!query.exec())
    432             MythContext::DBError("StorageGroupEditor::open", query);
    433 
    434         query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
    435                       "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
    436         query.bindValue(":NAME", m_group.utf8());
    437         query.bindValue(":DIRNAME", name.utf8());
    438         query.bindValue(":HOSTNAME", gContext->GetHostName());
    439         if (!query.exec())
    440             MythContext::DBError("StorageGroupEditor::open", query);
    441         else
    442             lastValue = name;
    443     }
    444 };
    445 
    446 void StorageGroupEditor::doDelete(void)
    447 {
    448     QString name = listbox->getValue();
    449     if (name == "__CREATE_NEW_STORAGE_DIRECTORY__")
    450         return;
    451 
    452     QString message =
    453         tr("Remove '%1'\nDirectory From Storage Group?").arg(name);
    454 
    455     DialogCode value = MythPopupBox::Show2ButtonPopup(
    456         gContext->GetMainWindow(), "", message,
    457         tr("Yes, remove directory"),
    458         tr("No, Don't remove directory"),
    459         kDialogCodeButton1);
    460 
    461     if (kDialogCodeButton0 == value)
    462     {
    463         MSqlQuery query(MSqlQuery::InitCon());
    464         query.prepare("DELETE FROM storagegroup "
    465                       "WHERE groupname = :NAME "
    466                           "AND dirname = :DIRNAME "
    467                           "AND hostname = :HOSTNAME;");
    468         query.bindValue(":NAME", m_group.utf8());
    469         query.bindValue(":DIRNAME", name.utf8());
    470         query.bindValue(":HOSTNAME", gContext->GetHostName());
    471         if (!query.exec())
    472             MythContext::DBError("StorageGroupEditor::doDelete", query);
    473 
    474         int lastIndex = listbox->getValueIndex(name);
    475         lastValue = "";
    476         load();
    477         listbox->setValue(lastIndex);
    478     }
    479 
    480     listbox->setFocus();
    481 }
    482 
    483 void StorageGroupEditor::load(void) {
    484     listbox->clearSelections();
    485 
    486     MSqlQuery query(MSqlQuery::InitCon());
    487     query.prepare("SELECT dirname, id FROM storagegroup "
    488                   "WHERE groupname = :NAME AND hostname = :HOSTNAME "
    489                   "ORDER BY id;");
    490     query.bindValue(":NAME", m_group.utf8());
    491     query.bindValue(":HOSTNAME", gContext->GetHostName());
    492     if (!query.exec() || !query.isActive())
    493         MythContext::DBError("StorageGroupEditor::doDelete", query);
    494     else
    495     {
    496         bool first = true;
    497         while (query.next())
    498         {
    499             if (first)
    500             {
    501                 lastValue = query.value(0).toString();
    502                 first = false;
    503             }
    504             listbox->addSelection(query.value(0).toString());
    505         }
    506     }
    507 
    508     listbox->addSelection(tr("(Add New Directory)"),
    509         "__CREATE_NEW_STORAGE_DIRECTORY__");
    510 
    511     listbox->setValue(lastValue);
    512 }
    513 
    514 DialogCode StorageGroupEditor::exec(void)
    515 {
    516     while (ConfigurationDialog::exec() == kDialogCodeAccepted)
    517         open(listbox->getValue());
    518 
    519     return kDialogCodeRejected;
    520 }
    521 
    522 MythDialog* StorageGroupEditor::dialogWidget(MythMainWindow* parent,
    523                                           const char* widgetName)
    524 {
    525     dialog = ConfigurationDialog::dialogWidget(parent, widgetName);
    526     connect(dialog, SIGNAL(menuButtonPressed()), this, SLOT(doDelete()));
    527     connect(dialog, SIGNAL(deleteButtonPressed()), this, SLOT(doDelete()));
    528     return dialog;
    529 }
    530 
    531 /****************************************************************************/
    532 
    533 StorageGroupListEditor::StorageGroupListEditor(void) :
    534     listbox(new ListBoxSetting(this)), lastValue("")
    535 {
    536     if (gContext->GetSetting("MasterServerIP","master") ==
    537             gContext->GetSetting("BackendServerIP","me"))
    538         listbox->setLabel(
    539             tr("Storage Groups (directories for new recordings)"));
    540     else
    541         listbox->setLabel(
    542             tr("Local Storage Groups (directories for new recordings)"));
    543 
    544     addChild(listbox);
    545 }
    546 
    547 void StorageGroupListEditor::open(QString name)
    548 {
    549     lastValue = name;
    550 
    551     if (name.left(28) == "__CREATE_NEW_STORAGE_GROUP__")
    552     {
    553         if (name.length() > 28)
    554         {
    555             name = name.mid(28);
    556         }
    557         else
    558         {
    559             name = "";
    560             SGPopupResult result = StorageGroupPopup::showPopup(
    561                 gContext->GetMainWindow(),
    562                 tr("Create New Storage Group"),
    563                 tr("Enter group name or press SELECT to enter text via the "
    564                    "On Screen Keyboard"), name);
    565             if (result == SGPopup_CANCEL)
    566                 return;
    567         }
    568     }
    569 
    570     if (!name.isEmpty())
    571     {
    572         StorageGroupEditor sgEditor(name);
    573         sgEditor.exec();
    574     }
    575 };
    576 
    577 void StorageGroupListEditor::doDelete(void)
    578 {
    579     QString name = listbox->getValue();
    580     if (name.left(28) == "__CREATE_NEW_STORAGE_GROUP__")
    581         return;
    582 
    583     if ((gContext->GetSetting("MasterServerIP","master") ==
    584          gContext->GetSetting("BackendServerIP","me")) &&
    585         (name == "Default"))
    586         return;
    587 
    588     QString dispGroup = name;
    589     if (name == "Default")
    590         dispGroup = QObject::tr("Default");
    591     else if (StorageGroup::kSpecialGroups.contains(name))
    592         dispGroup = QObject::tr(name);
    593 
    594     QString message = tr("Delete '%1' Storage Group?").arg(dispGroup);
    595 
    596     DialogCode value = MythPopupBox::Show2ButtonPopup(
    597         gContext->GetMainWindow(),
    598         "", message,
    599         tr("Yes, delete group"),
    600         tr("No, Don't delete group"), kDialogCodeButton1);
    601 
    602     if (kDialogCodeButton0 == value)
    603     {
    604         MSqlQuery query(MSqlQuery::InitCon());
    605         query.prepare("DELETE FROM storagegroup "
    606                       "WHERE groupname = :NAME AND hostname = :HOSTNAME;");
    607         query.bindValue(":NAME", name.utf8());
    608         query.bindValue(":HOSTNAME", gContext->GetHostName());
    609         if (!query.exec())
    610             MythContext::DBError("StorageGroupListEditor::doDelete", query);
    611 
    612         int lastIndex = listbox->getValueIndex(name);
    613         lastValue = "";
    614         load();
    615         listbox->setValue(lastIndex);
    616     }
    617 
    618     listbox->setFocus();
    619 }
    620 
    621 void StorageGroupListEditor::load(void)
    622 {
    623     QStringList names;
    624     QStringList masterNames;
    625     bool createAddDefaultButton = false;
    626     bool createAddSpecialGroupButton[StorageGroup::kSpecialGroups.size()];
    627     bool isMaster = (gContext->GetSetting("MasterServerIP","master") ==
    628                      gContext->GetSetting("BackendServerIP","me"));
    629 
    630     MSqlQuery query(MSqlQuery::InitCon());
    631     query.prepare("SELECT distinct groupname "
    632                   "FROM storagegroup "
    633                   "WHERE hostname = :HOSTNAME "
    634                   "ORDER BY groupname;");
    635     query.bindValue(":HOSTNAME", gContext->GetHostName());
    636     if (!query.exec())
    637         MythContext::DBError("StorageGroup::load getting local group names",
    638                              query);
    639     else
    640     {
    641         while (query.next())
    642             names << QString::fromUtf8(query.value(0).toString());
    643     }
    644 
    645     query.prepare("SELECT distinct groupname "
    646                   "FROM storagegroup "
    647                   "ORDER BY groupname;");
    648     if (!query.exec())
    649         MythContext::DBError("StorageGroup::load getting all group names",
    650                              query);
    651     else
    652     {
    653         while (query.next())
    654             masterNames << QString::fromUtf8(query.value(0).toString());
    655     }
    656 
    657     listbox->clearSelections();
    658 
    659     if (isMaster || names.contains("Default"))
    660     {
    661         listbox->addSelection(QObject::tr("Default"), "Default");
    662         lastValue = "Default";
    663     }
    664     else
    665         createAddDefaultButton = true;
    666 
    667     unsigned int curGroup = 0;
    668     QString groupName;
    669     while (curGroup < StorageGroup::kSpecialGroups.size())
    670     {
    671         groupName = StorageGroup::kSpecialGroups[curGroup];
    672         if (names.contains(groupName))
    673         {
    674             listbox->addSelection(QObject::tr(groupName), groupName);
    675             createAddSpecialGroupButton[curGroup] = false;
    676         }
    677         else
    678             createAddSpecialGroupButton[curGroup] = true;
    679         curGroup++;
    680     }
    681 
    682     unsigned int curName = 0;
    683     while (curName < names.size())
    684     {
    685         if ((names[curName] != "Default") &&
    686             (!StorageGroup::kSpecialGroups.contains(names[curName])))
    687             listbox->addSelection(names[curName]);
    688         curName++;
    689     }
    690 
    691     if (createAddDefaultButton)
    692     {
    693         listbox->addSelection(tr("(Create %1 group)").arg("Default"),
    694                               "Default");
    695         lastValue = "Default";
    696     }
    697 
    698     curGroup = 0;
    699     while (curGroup < StorageGroup::kSpecialGroups.size())
    700     {
    701         groupName = StorageGroup::kSpecialGroups[curGroup];
    702         if (createAddSpecialGroupButton[curGroup])
    703             listbox->addSelection(tr("(Create %1 group)").arg(groupName),
    704                 QString("__CREATE_NEW_STORAGE_GROUP__%1").arg(groupName));
    705         curGroup++;
    706     }
    707 
    708     if (isMaster)
    709         listbox->addSelection(tr("(Create %1 group)").arg("new"),
    710             "__CREATE_NEW_STORAGE_GROUP__");
    711     else
    712     {
    713         curName = 0;
    714         while (curName < masterNames.size())
    715         {
    716             if ((masterNames[curName] != "Default") &&
    717                 (!StorageGroup::kSpecialGroups.contains(masterNames[curName])) &&
    718                 (!names.contains(masterNames[curName])))
    719                 listbox->addSelection(tr("(Create %1 group)")
    720                                          .arg(masterNames[curName]),
    721                     "__CREATE_NEW_STORAGE_GROUP__" + masterNames[curName]);
    722             curName++;
    723         }
    724     }
    725 
    726     listbox->setValue(lastValue);
    727 }
    728 
    729 DialogCode StorageGroupListEditor::exec(void)
    730 {
    731     while (ConfigurationDialog::exec() == kDialogCodeAccepted)
    732         open(listbox->getValue());
    733 
    734     return kDialogCodeRejected;
    735 }
    736 
    737 MythDialog* StorageGroupListEditor::dialogWidget(MythMainWindow* parent,
    738                                           const char* widgetName)
    739 {
    740     dialog = ConfigurationDialog::dialogWidget(parent, widgetName);
    741     connect(dialog, SIGNAL(menuButtonPressed()), this, SLOT(doDelete()));
    742     connect(dialog, SIGNAL(deleteButtonPressed()), this, SLOT(doDelete()));
    743     return dialog;
    744 }
    745 
    746 /* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmyth/libmyth.pro

     
    2323HEADERS += screensaver.h screensaver-null.h settings.h themeinfo.h
    2424HEADERS += uilistbtntype.h uitypes.h util.h util-x11.h
    2525HEADERS += volumebase.h volumecontrol.h virtualkeyboard.h visual.h xmlparse.h
    26 HEADERS += mythhdd.h mythcdrom.h
     26HEADERS += mythhdd.h mythcdrom.h storagegroup.h
    2727HEADERS += compat.h
    2828
    2929SOURCES += audiooutput.cpp audiooutputbase.cpp audiooutputnull.cpp
     
    3939SOURCES += screensaver.cpp screensaver-null.cpp settings.cpp themeinfo.cpp
    4040SOURCES += uilistbtntype.cpp uitypes.cpp util.cpp util-x11.cpp
    4141SOURCES += volumebase.cpp volumecontrol.cpp virtualkeyboard.cpp xmlparse.cpp
    42 SOURCES += mythhdd.cpp mythcdrom.cpp
     42SOURCES += mythhdd.cpp mythcdrom.cpp storagegroup.cpp
    4343
    4444INCLUDEPATH += ../libmythsamplerate ../libmythsoundtouch ../.. ../ ./
    4545DEPENDPATH += ../libmythsamplerate ../libmythsoundtouch ../ ../libmythui
     
    6363inc.files += visual.h volumebase.h output.h langsettings.h qmdcodec.h
    6464inc.files += exitcodes.h mythconfig.h mythconfig.mak virtualkeyboard.h
    6565inc.files += mythevent.h mythobservable.h mythsocket.h
    66 inc.files += mythexp.h mythpluginapi.h compat.h
     66inc.files += mythexp.h mythpluginapi.h storagegroup.h compat.h
    6767inc.files += mythstorage.h mythconfigdialogs.h mythconfiggroups.h
    6868
    6969# Allow both #include <blah.h> and #include <libmyth/blah.h>
  • libs/libmyth/storagegroup.h

     
     1#ifndef _STORAGEGROUP_H
     2#define _STORAGEGROUP_H
     3
     4#include <qstringlist.h>
     5#include <qdeepcopy.h>
     6
     7#include "libmyth/settings.h"
     8#include "libmyth/mythwidgets.h"
     9
     10class MPUBLIC StorageGroup: public ConfigurationWizard
     11{
     12  public:
     13    StorageGroup(const QString group = "", const QString hostname = "");
     14
     15    void    Init(const QString group = "Default",
     16                 const QString hostname = "");
     17
     18    QString getName(void) const
     19        { return QDeepCopy<QString>(m_groupname); }
     20
     21    QStringList GetDirList(void) const
     22        { return QDeepCopy<QStringList>(m_dirlist); }
     23
     24    QString FindRecordingFile(QString filename);
     25    QString FindRecordingDir(QString filename);
     26
     27    QString FindNextDirMostFree(void);
     28
     29    static void CheckAllStorageGroupDirs(void);
     30
     31    static const char *kDefaultStorageDir;
     32    static const QStringList kSpecialGroups;
     33
     34    static QStringList getRecordingsGroups(void);
     35
     36  private:
     37    QString      m_groupname;
     38    QString      m_hostname;
     39    QStringList  m_dirlist;
     40};
     41
     42class MPUBLIC StorageGroupEditor :
     43    public QObject, public ConfigurationDialog
     44{
     45    Q_OBJECT
     46  public:
     47    StorageGroupEditor(QString group);
     48    virtual DialogCode exec(void);
     49    virtual void load(void);
     50    virtual void save(void) { };
     51    virtual void save(QString) { };
     52    virtual MythDialog* dialogWidget(MythMainWindow* parent,
     53                                     const char* widgetname=0);
     54
     55  protected slots:
     56    void open(QString name);
     57    void doDelete(void);
     58
     59  protected:
     60    QString         m_group;
     61    ListBoxSetting *listbox;
     62    QString         lastValue;
     63};
     64
     65class MPUBLIC StorageGroupListEditor :
     66    public QObject, public ConfigurationDialog
     67{
     68    Q_OBJECT
     69  public:
     70    StorageGroupListEditor(void);
     71    virtual DialogCode exec(void);
     72    virtual void load(void);
     73    virtual void save(void) { };
     74    virtual void save(QString) { };
     75    virtual MythDialog* dialogWidget(MythMainWindow* parent,
     76                                     const char* widgetname=0);
     77
     78  protected slots:
     79    void open(QString name);
     80    void doDelete(void);
     81
     82  protected:
     83    ListBoxSetting *listbox;
     84    QString         lastValue;
     85};
     86
     87#endif
     88
     89/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • libs/libmyth/storagegroup.cpp

     
     1#include <qdir.h>
     2#include <qfile.h>
     3#include <qregexp.h>
     4
     5#include "storagegroup.h"
     6#include "libmyth/mythcontext.h"
     7#include "libmyth/mythdbcon.h"
     8#include "libmyth/util.h"
     9
     10#define LOC QString("SG(%1): ").arg(m_groupname)
     11#define LOC_WARN QString("SG(%1) Warning: ").arg(m_groupname)
     12#define LOC_ERR QString("SG(%1) Error: ").arg(m_groupname)
     13
     14const char *StorageGroup::kDefaultStorageDir = "/mnt/store";
     15
     16const QStringList StorageGroup::kSpecialGroups = QStringList()
     17    << "LiveTV"
     18//    << "Thumbnails"
     19//    << "DB Backups"
     20    ;
     21
     22/****************************************************************************/
     23
     24/** \brief StorageGroup constructor.
     25 *  \param group    storage group to search, blank will search all groups.
     26 *  \param hostname hostname where to search, blank will search all hosts'
     27 *                  directories, but only in local directory structure.
     28 *                  This is parameter is ignored if group is an empty string.
     29 */
     30StorageGroup::StorageGroup(const QString group, const QString hostname) :
     31    m_groupname(QDeepCopy<QString>(group)),
     32    m_hostname(QDeepCopy<QString>(hostname))
     33{
     34    m_dirlist.clear();
     35
     36    Init(m_groupname, m_hostname);
     37}
     38
     39void StorageGroup::Init(const QString group, const QString hostname)
     40{
     41    QString dirname;
     42    MSqlQuery query(MSqlQuery::InitCon());
     43
     44    m_groupname = QDeepCopy<QString>(group);
     45    m_hostname  = QDeepCopy<QString>(hostname);
     46    m_dirlist.clear();
     47
     48    QString sql = "SELECT DISTINCT dirname "
     49                  "FROM storagegroup ";
     50
     51    if (!m_groupname.isEmpty())
     52    {
     53        sql.append("WHERE groupname = :GROUP");
     54        if (!m_hostname.isEmpty())
     55            sql.append(" AND hostname = :HOSTNAME");
     56    }
     57
     58    query.prepare(sql);
     59    query.bindValue(":GROUP", m_groupname);
     60    query.bindValue(":HOSTNAME", m_hostname);
     61
     62    if (!query.exec() || !query.isActive())
     63        MythContext::DBError("StorageGroup::StorageGroup()", query);
     64    else if (!query.next())
     65    {
     66        if (group != "Default")
     67        {
     68            VERBOSE(VB_FILE, LOC +
     69                    QString("Unable to find storage group '%1', trying "
     70                            "'Default' group!").arg(m_groupname));
     71            Init("Default", m_hostname);
     72            return;
     73        }
     74        else if (!m_hostname.isEmpty())
     75        {
     76            VERBOSE(VB_FILE, LOC +
     77                    QString("Unable to find any directories for the local "
     78                            "Default storage group, trying directories in all "
     79                            "Default groups!").arg(m_groupname));
     80            Init("Default", "");
     81            return;
     82        }
     83    }
     84    else
     85    {
     86        do
     87        {
     88            dirname = query.value(0).toString();
     89            dirname.replace(QRegExp("^\\s*"), "");
     90            dirname.replace(QRegExp("\\s*$"), "");
     91            if (dirname.right(1) == "/")
     92                dirname.remove(dirname.length() - 1, 1);
     93            m_dirlist << QDeepCopy<QString>(dirname);
     94        }
     95        while (query.next());
     96    }
     97
     98    if (!m_dirlist.size())
     99    {
     100        QString msg = "Directory value for Default Storage Group is empty.  ";
     101        QString tmpDir = gContext->GetSetting("RecordFilePrefix");
     102        if (tmpDir != "")
     103        {
     104            msg += QString("Using old 'RecordFilePrefix' value of '%1'")
     105                           .arg(tmpDir);
     106        }
     107        else
     108        {
     109            tmpDir = kDefaultStorageDir;
     110            msg += QString("Using hardcoded default value of '%1'")
     111                           .arg(kDefaultStorageDir);
     112        }
     113        VERBOSE(VB_IMPORTANT, LOC_ERR + msg);
     114        m_dirlist << QDeepCopy<QString>(tmpDir);
     115    }
     116}
     117
     118QString StorageGroup::FindRecordingFile(QString filename)
     119{
     120    VERBOSE(VB_FILE, LOC + QString("FindRecordingFile: Searching for '%1'")
     121                                   .arg(filename));
     122
     123    QString recDir = FindRecordingDir(filename);
     124    QString result = "";
     125   
     126    if (!recDir.isEmpty())
     127    {
     128        result = recDir + "/" + filename;
     129        VERBOSE(VB_FILE, LOC + QString("FindRecordingFile: Found '%1'")
     130                                       .arg(result));
     131    }
     132    else
     133    {
     134        VERBOSE(VB_FILE, LOC_ERR +
     135                QString("FindRecordingFile: Unable to find '%1'!")
     136                        .arg(filename));
     137    }
     138
     139    return result;
     140}
     141
     142QString StorageGroup::FindRecordingDir(QString filename)
     143{
     144    QString result = "";
     145    QFile checkFile("");
     146
     147    unsigned int curDir = 0;
     148    while (curDir < m_dirlist.size())
     149    {
     150        QString testFile = m_dirlist[curDir] + "/" + filename;
     151        VERBOSE(VB_FILE, LOC + QString("FindRecordingDir: Checking '%1'")
     152                .arg(m_dirlist[curDir]));
     153        checkFile.setName(testFile);
     154        if (checkFile.exists())
     155            return QDeepCopy<QString>(m_dirlist[curDir]);
     156
     157        curDir++;
     158    }
     159
     160    if (m_groupname.isEmpty())
     161    {
     162        // Not found in any dir, so try RecordFilePrefix if it exists
     163        QString tmpFile =
     164            gContext->GetSetting("RecordFilePrefix") + "/" + filename;
     165        checkFile.setName(tmpFile);
     166        if (checkFile.exists())
     167            result = tmpFile;
     168    }
     169    else if (m_groupname != "Default")
     170    {
     171        // Not found in current group so try Default
     172        StorageGroup sgroup("Default");
     173        QString tmpFile = sgroup.FindRecordingDir(filename);
     174        result = (tmpFile.isEmpty()) ? result : tmpFile;
     175    }
     176    else
     177    {
     178        // Not found in Default so try any dir
     179        StorageGroup sgroup;
     180        QString tmpFile = sgroup.FindRecordingDir(filename);
     181        result = (tmpFile.isEmpty()) ? result : tmpFile;
     182    }
     183
     184    return QDeepCopy<QString>(result);
     185}
     186
     187QString StorageGroup::FindNextDirMostFree(void)
     188{
     189    QString nextDir = kDefaultStorageDir;
     190    long long nextDirFree = 0;
     191    long long thisDirTotal;
     192    long long thisDirUsed;
     193    long long thisDirFree;
     194
     195    VERBOSE(VB_FILE, LOC + QString("FindNextDirMostFree: Starting'"));
     196
     197    if (m_dirlist.size())
     198        nextDir = m_dirlist[0];
     199
     200    QDir checkDir("");
     201    unsigned int curDir = 0;
     202    while (curDir < m_dirlist.size())
     203    {
     204        checkDir.setPath(m_dirlist[curDir]);
     205        if (!checkDir.exists())
     206        {
     207            VERBOSE(VB_IMPORTANT, LOC_ERR +
     208                    QString("FindNextDirMostFree: '%1' does not exist!")
     209                            .arg(nextDir));
     210            curDir++;
     211            continue;
     212        }
     213
     214        thisDirFree = getDiskSpace(m_dirlist[curDir], thisDirTotal,
     215                                   thisDirUsed);
     216        VERBOSE(VB_FILE, LOC +
     217                QString("FindNextDirMostFree: '%1' has %2 KiB free")
     218                        .arg(m_dirlist[curDir])
     219                        .arg(longLongToString(thisDirFree)));
     220
     221        if (thisDirFree > nextDirFree)
     222        {
     223            nextDir     = m_dirlist[curDir];
     224            nextDirFree = thisDirFree;
     225        }
     226        curDir++;
     227    }
     228
     229    VERBOSE(VB_FILE, LOC + QString("FindNextDirMostFree: Using '%1'")
     230                                   .arg(nextDir));
     231
     232    return QDeepCopy<QString>(nextDir);
     233}
     234
     235void StorageGroup::CheckAllStorageGroupDirs(void)
     236{
     237    QString m_groupname;
     238    QString dirname;
     239    MSqlQuery query(MSqlQuery::InitCon());
     240
     241    query.prepare("SELECT groupname, dirname "
     242                  "FROM storagegroup "
     243                  "WHERE hostname = :HOSTNAME;");
     244    query.bindValue(":HOSTNAME", gContext->GetHostName());
     245    if (!query.exec() || !query.isActive())
     246    {
     247        MythContext::DBError("StorageGroup::CheckAllStorageGroupDirs()", query);
     248        return;
     249    }
     250
     251    VERBOSE(VB_FILE, LOC + "CheckAllStorageGroupDirs(): Checking All Storage "
     252            "Group directories");
     253
     254    QFile testFile("");
     255    QDir testDir("");
     256    while (query.next())
     257    {
     258        m_groupname = query.value(0).toString();
     259        dirname = query.value(1).toString();
     260
     261        dirname.replace(QRegExp("^\\s*"), "");
     262        dirname.replace(QRegExp("\\s*$"), "");
     263
     264        VERBOSE(VB_FILE, LOC +
     265                QString("Checking directory '%1' in group '%2'.")
     266                        .arg(dirname).arg(m_groupname));
     267
     268        testDir.setPath(dirname);
     269        if (!testDir.exists())
     270        {
     271            VERBOSE(VB_FILE, LOC_WARN +
     272                    QString("Group '%1' references directory '%2' but this "
     273                            "directory does not exist.  This directory "
     274                            "will not be used on this server.")
     275                            .arg(m_groupname).arg(dirname));
     276        }
     277        else
     278        {
     279            testFile.setName(dirname + "/.test");
     280            if (testFile.open(IO_WriteOnly))
     281                testFile.remove();
     282            else
     283                VERBOSE(VB_IMPORTANT,
     284                        LOC_ERR +
     285                        QString("Group '%1' wants to use directory '%2', but "
     286                                "this directory is not writeable.")
     287                                .arg(m_groupname).arg(dirname));
     288        }
     289    }
     290}
     291
     292QStringList StorageGroup::getRecordingsGroups(void)
     293{
     294    QStringList groups;
     295
     296    MSqlQuery query(MSqlQuery::InitCon());
     297
     298    QString sql = "SELECT DISTINCT groupname "
     299                  "FROM storagegroup "
     300                  "WHERE groupname NOT IN (";
     301    for (QStringList::const_iterator it = StorageGroup::kSpecialGroups.begin();
     302         it != StorageGroup::kSpecialGroups.end(); ++it)
     303        sql.append(QString(" '%1',").arg(*it));
     304    sql = sql.left(sql.length() - 1);
     305    sql.append(" );");
     306
     307    query.prepare(sql);
     308    if (query.exec() && query.isActive() && query.size() > 0)
     309        while (query.next())
     310            groups += QString::fromUtf8(query.value(0).toString());
     311
     312    groups.sort();
     313
     314    return QDeepCopy<QStringList>(groups);
     315}
     316
     317/****************************************************************************/
     318typedef enum {
     319    SGPopup_OK = 0,
     320    SGPopup_CANCEL,
     321    SGPopup_DELETE
     322} SGPopupResult;
     323
     324class StorageGroupPopup
     325{
     326  public:
     327    static SGPopupResult showPopup(MythMainWindow *parent, QString title,
     328                                   QString message, QString& text);
     329};
     330
     331SGPopupResult StorageGroupPopup::showPopup(MythMainWindow *parent,
     332                                 QString title, QString message, QString& text)
     333{
     334    MythPopupBox *popup = new MythPopupBox(parent, title);
     335    popup->addLabel(message);
     336
     337    MythLineEdit *textEdit = new MythLineEdit(popup, "chooseEdit");
     338    textEdit->setText(text);
     339    popup->addWidget(textEdit);
     340
     341    popup->addButton(QObject::tr("OK"),     popup, SLOT(accept()));
     342    popup->addButton(QObject::tr("Cancel"), popup, SLOT(reject()));
     343
     344    textEdit->setFocus();
     345
     346    bool ok = (MythDialog::Accepted == popup->ExecPopup());
     347    if (ok)
     348        text = QDeepCopy<QString>(textEdit->text());
     349
     350    popup->hide();
     351    popup->deleteLater();
     352
     353    return (ok) ? SGPopup_OK : SGPopup_CANCEL;
     354}
     355
     356/****************************************************************************/
     357
     358StorageGroupEditor::StorageGroupEditor(QString group) :
     359    m_group(group), listbox(new ListBoxSetting(this)), lastValue("")
     360{
     361    QString dispGroup = group;
     362
     363    if (group == "Default")
     364        dispGroup = QObject::tr("Default");
     365    else if (StorageGroup::kSpecialGroups.contains(group))
     366        dispGroup = QObject::tr(group);
     367
     368    if (gContext->GetSetting("MasterServerIP","master") ==
     369            gContext->GetSetting("BackendServerIP","me"))
     370    {
     371        listbox->setLabel(tr("'%1' Storage Group Directories").arg(dispGroup));
     372    }
     373    else
     374    {
     375        listbox->setLabel(tr("Local '%1' Storage Group Directories")
     376                             .arg(dispGroup));
     377    }
     378
     379    addChild(listbox);
     380}
     381
     382void StorageGroupEditor::open(QString name)
     383{
     384    lastValue = name;
     385
     386    if (name == "__CREATE_NEW_STORAGE_DIRECTORY__")
     387    {
     388        name = "";
     389        SGPopupResult result = StorageGroupPopup::showPopup(
     390            gContext->GetMainWindow(),
     391            tr("Add Storage Group Directory"),
     392            tr("Enter directory name or press SELECT to enter text via the "
     393               "On Screen Keyboard"), name);
     394        if (result == SGPopup_CANCEL)
     395            return;
     396
     397        if (name.right(1) != "/")
     398            name.append("/");
     399
     400        MSqlQuery query(MSqlQuery::InitCon());
     401        query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
     402                      "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
     403        query.bindValue(":NAME", m_group.utf8());
     404        query.bindValue(":DIRNAME", name.utf8());
     405        query.bindValue(":HOSTNAME", gContext->GetHostName());
     406        if (!query.exec())
     407            MythContext::DBError("StorageGroupEditor::open", query);
     408        else
     409            lastValue = name;
     410    } else {
     411        SGPopupResult result = StorageGroupPopup::showPopup(
     412            gContext->GetMainWindow(),
     413            tr("Edit Storage Group Directory"),
     414            tr("Enter directory name or press SELECT to enter text via the "
     415               "On Screen Keyboard"), name);
     416        if (result == SGPopup_CANCEL)
     417            return;
     418
     419        if (name.right(1) != "/")
     420            name.append("/");
     421
     422        MSqlQuery query(MSqlQuery::InitCon());
     423
     424        query.prepare("DELETE FROM storagegroup "
     425                      "WHERE groupname = :NAME "
     426                          "AND dirname = :DIRNAME "
     427                          "AND hostname = :HOSTNAME;");
     428        query.bindValue(":NAME", m_group.utf8());
     429        query.bindValue(":DIRNAME", lastValue.utf8());
     430        query.bindValue(":HOSTNAME", gContext->GetHostName());
     431        if (!query.exec())
     432            MythContext::DBError("StorageGroupEditor::open", query);
     433
     434        query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
     435                      "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
     436        query.bindValue(":NAME", m_group.utf8());
     437        query.bindValue(":DIRNAME", name.utf8());
     438        query.bindValue(":HOSTNAME", gContext->GetHostName());
     439        if (!query.exec())
     440            MythContext::DBError("StorageGroupEditor::open", query);
     441        else
     442            lastValue = name;
     443    }
     444};
     445
     446void StorageGroupEditor::doDelete(void)
     447{
     448    QString name = listbox->getValue();
     449    if (name == "__CREATE_NEW_STORAGE_DIRECTORY__")
     450        return;
     451
     452    QString message =
     453        tr("Remove '%1'\nDirectory From Storage Group?").arg(name);
     454
     455    DialogCode value = MythPopupBox::Show2ButtonPopup(
     456        gContext->GetMainWindow(), "", message,
     457        tr("Yes, remove directory"),
     458        tr("No, Don't remove directory"),
     459        kDialogCodeButton1);
     460
     461    if (kDialogCodeButton0 == value)
     462    {
     463        MSqlQuery query(MSqlQuery::InitCon());
     464        query.prepare("DELETE FROM storagegroup "
     465                      "WHERE groupname = :NAME "
     466                          "AND dirname = :DIRNAME "
     467                          "AND hostname = :HOSTNAME;");
     468        query.bindValue(":NAME", m_group.utf8());
     469        query.bindValue(":DIRNAME", name.utf8());
     470        query.bindValue(":HOSTNAME", gContext->GetHostName());
     471        if (!query.exec())
     472            MythContext::DBError("StorageGroupEditor::doDelete", query);
     473
     474        int lastIndex = listbox->getValueIndex(name);
     475        lastValue = "";
     476        load();
     477        listbox->setValue(lastIndex);
     478    }
     479
     480    listbox->setFocus();
     481}
     482
     483void StorageGroupEditor::load(void) {
     484    listbox->clearSelections();
     485
     486    MSqlQuery query(MSqlQuery::InitCon());
     487    query.prepare("SELECT dirname, id FROM storagegroup "
     488                  "WHERE groupname = :NAME AND hostname = :HOSTNAME "
     489                  "ORDER BY id;");
     490    query.bindValue(":NAME", m_group.utf8());
     491    query.bindValue(":HOSTNAME", gContext->GetHostName());
     492    if (!query.exec() || !query.isActive())
     493        MythContext::DBError("StorageGroupEditor::doDelete", query);
     494    else
     495    {
     496        bool first = true;
     497        while (query.next())
     498        {
     499            if (first)
     500            {
     501                lastValue = query.value(0).toString();
     502                first = false;
     503            }
     504            listbox->addSelection(query.value(0).toString());
     505        }
     506    }
     507
     508    listbox->addSelection(tr("(Add New Directory)"),
     509        "__CREATE_NEW_STORAGE_DIRECTORY__");
     510
     511    listbox->setValue(lastValue);
     512}
     513
     514DialogCode StorageGroupEditor::exec(void)
     515{
     516    while (ConfigurationDialog::exec() == kDialogCodeAccepted)
     517        open(listbox->getValue());
     518
     519    return kDialogCodeRejected;
     520}
     521
     522MythDialog* StorageGroupEditor::dialogWidget(MythMainWindow* parent,
     523                                          const char* widgetName)
     524{
     525    dialog = ConfigurationDialog::dialogWidget(parent, widgetName);
     526    connect(dialog, SIGNAL(menuButtonPressed()), this, SLOT(doDelete()));
     527    connect(dialog, SIGNAL(deleteButtonPressed()), this, SLOT(doDelete()));
     528    return dialog;
     529}
     530
     531/****************************************************************************/
     532
     533StorageGroupListEditor::StorageGroupListEditor(void) :
     534    listbox(new ListBoxSetting(this)), lastValue("")
     535{
     536    if (gContext->GetSetting("MasterServerIP","master") ==
     537            gContext->GetSetting("BackendServerIP","me"))
     538        listbox->setLabel(
     539            tr("Storage Groups (directories for new recordings)"));
     540    else
     541        listbox->setLabel(
     542            tr("Local Storage Groups (directories for new recordings)"));
     543
     544    addChild(listbox);
     545}
     546
     547void StorageGroupListEditor::open(QString name)
     548{
     549    lastValue = name;
     550
     551    if (name.left(28) == "__CREATE_NEW_STORAGE_GROUP__")
     552    {
     553        if (name.length() > 28)
     554        {
     555            name = name.mid(28);
     556        }
     557        else
     558        {
     559            name = "";
     560            SGPopupResult result = StorageGroupPopup::showPopup(
     561                gContext->GetMainWindow(),
     562                tr("Create New Storage Group"),
     563                tr("Enter group name or press SELECT to enter text via the "
     564                   "On Screen Keyboard"), name);
     565            if (result == SGPopup_CANCEL)
     566                return;
     567        }
     568    }
     569
     570    if (!name.isEmpty())
     571    {
     572        StorageGroupEditor sgEditor(name);
     573        sgEditor.exec();
     574    }
     575};
     576
     577void StorageGroupListEditor::doDelete(void)
     578{
     579    QString name = listbox->getValue();
     580    if (name.left(28) == "__CREATE_NEW_STORAGE_GROUP__")
     581        return;
     582
     583    if ((gContext->GetSetting("MasterServerIP","master") ==
     584         gContext->GetSetting("BackendServerIP","me")) &&
     585        (name == "Default"))
     586        return;
     587
     588    QString dispGroup = name;
     589    if (name == "Default")
     590        dispGroup = QObject::tr("Default");
     591    else if (StorageGroup::kSpecialGroups.contains(name))
     592        dispGroup = QObject::tr(name);
     593
     594    QString message = tr("Delete '%1' Storage Group?").arg(dispGroup);
     595
     596    DialogCode value = MythPopupBox::Show2ButtonPopup(
     597        gContext->GetMainWindow(),
     598        "", message,
     599        tr("Yes, delete group"),
     600        tr("No, Don't delete group"), kDialogCodeButton1);
     601
     602    if (kDialogCodeButton0 == value)
     603    {
     604        MSqlQuery query(MSqlQuery::InitCon());
     605        query.prepare("DELETE FROM storagegroup "
     606                      "WHERE groupname = :NAME AND hostname = :HOSTNAME;");
     607        query.bindValue(":NAME", name.utf8());
     608        query.bindValue(":HOSTNAME", gContext->GetHostName());
     609        if (!query.exec())
     610            MythContext::DBError("StorageGroupListEditor::doDelete", query);
     611
     612        int lastIndex = listbox->getValueIndex(name);
     613        lastValue = "";
     614        load();
     615        listbox->setValue(lastIndex);
     616    }
     617
     618    listbox->setFocus();
     619}
     620
     621void StorageGroupListEditor::load(void)
     622{
     623    QStringList names;
     624    QStringList masterNames;
     625    bool createAddDefaultButton = false;
     626    bool createAddSpecialGroupButton[StorageGroup::kSpecialGroups.size()];
     627    bool isMaster = (gContext->GetSetting("MasterServerIP","master") ==
     628                     gContext->GetSetting("BackendServerIP","me"));
     629
     630    MSqlQuery query(MSqlQuery::InitCon());
     631    query.prepare("SELECT distinct groupname "
     632                  "FROM storagegroup "
     633                  "WHERE hostname = :HOSTNAME "
     634                  "ORDER BY groupname;");
     635    query.bindValue(":HOSTNAME", gContext->GetHostName());
     636    if (!query.exec())
     637        MythContext::DBError("StorageGroup::load getting local group names",
     638                             query);
     639    else
     640    {
     641        while (query.next())
     642            names << QString::fromUtf8(query.value(0).toString());
     643    }
     644
     645    query.prepare("SELECT distinct groupname "
     646                  "FROM storagegroup "
     647                  "ORDER BY groupname;");
     648    if (!query.exec())
     649        MythContext::DBError("StorageGroup::load getting all group names",
     650                             query);
     651    else
     652    {
     653        while (query.next())
     654            masterNames << QString::fromUtf8(query.value(0).toString());
     655    }
     656
     657    listbox->clearSelections();
     658
     659    if (isMaster || names.contains("Default"))
     660    {
     661        listbox->addSelection(QObject::tr("Default"), "Default");
     662        lastValue = "Default";
     663    }
     664    else
     665        createAddDefaultButton = true;
     666
     667    unsigned int curGroup = 0;
     668    QString groupName;
     669    while (curGroup < StorageGroup::kSpecialGroups.size())
     670    {
     671        groupName = StorageGroup::kSpecialGroups[curGroup];
     672        if (names.contains(groupName))
     673        {
     674            listbox->addSelection(QObject::tr(groupName), groupName);
     675            createAddSpecialGroupButton[curGroup] = false;
     676        }
     677        else
     678            createAddSpecialGroupButton[curGroup] = true;
     679        curGroup++;
     680    }
     681
     682    unsigned int curName = 0;
     683    while (curName < names.size())
     684    {
     685        if ((names[curName] != "Default") &&
     686            (!StorageGroup::kSpecialGroups.contains(names[curName])))
     687            listbox->addSelection(names[curName]);
     688        curName++;
     689    }
     690
     691    if (createAddDefaultButton)
     692    {
     693        listbox->addSelection(tr("(Create %1 group)").arg("Default"),
     694                              "Default");
     695        lastValue = "Default";
     696    }
     697
     698    curGroup = 0;
     699    while (curGroup < StorageGroup::kSpecialGroups.size())
     700    {
     701        groupName = StorageGroup::kSpecialGroups[curGroup];
     702        if (createAddSpecialGroupButton[curGroup])
     703            listbox->addSelection(tr("(Create %1 group)").arg(groupName),
     704                QString("__CREATE_NEW_STORAGE_GROUP__%1").arg(groupName));
     705        curGroup++;
     706    }
     707
     708    if (isMaster)
     709        listbox->addSelection(tr("(Create %1 group)").arg("new"),
     710            "__CREATE_NEW_STORAGE_GROUP__");
     711    else
     712    {
     713        curName = 0;
     714        while (curName < masterNames.size())
     715        {
     716            if ((masterNames[curName] != "Default") &&
     717                (!StorageGroup::kSpecialGroups.contains(masterNames[curName])) &&
     718                (!names.contains(masterNames[curName])))
     719                listbox->addSelection(tr("(Create %1 group)")
     720                                         .arg(masterNames[curName]),
     721                    "__CREATE_NEW_STORAGE_GROUP__" + masterNames[curName]);
     722            curName++;
     723        }
     724    }
     725
     726    listbox->setValue(lastValue);
     727}
     728
     729DialogCode StorageGroupListEditor::exec(void)
     730{
     731    while (ConfigurationDialog::exec() == kDialogCodeAccepted)
     732        open(listbox->getValue());
     733
     734    return kDialogCodeRejected;
     735}
     736
     737MythDialog* StorageGroupListEditor::dialogWidget(MythMainWindow* parent,
     738                                          const char* widgetName)
     739{
     740    dialog = ConfigurationDialog::dialogWidget(parent, widgetName);
     741    connect(dialog, SIGNAL(menuButtonPressed()), this, SLOT(doDelete()));
     742    connect(dialog, SIGNAL(deleteButtonPressed()), this, SLOT(doDelete()));
     743    return dialog;
     744}
     745
     746/* vim: set expandtab tabstop=4 shiftwidth=4: */
  • programs/mythbackend/autoexpire.cpp

     
    3131#include "libmyth/util.h"
    3232#include "libmythtv/remoteutil.h"
    3333#include "libmythtv/remoteencoder.h"
    34 #include "libmythtv/storagegroup.h"
     34#include "storagegroup.h"
    3535#include "encoderlink.h"
    3636#include "backendutil.h"
    3737#include "compat.h"
  • programs/mythbackend/main.cpp

     
    3939#include "libmythtv/programinfo.h"
    4040#include "libmythtv/dbcheck.h"
    4141#include "libmythtv/jobqueue.h"
    42 #include "libmythtv/storagegroup.h"
     42#include "storagegroup.h"
    4343#include "libmythtv/previewgenerator.h"
    4444
    4545#include "mediaserver.h"
  • programs/mythbackend/scheduler.cpp

     
    3434#include "libmyth/compat.h"
    3535#include "libmythtv/programinfo.h"
    3636#include "libmythtv/scheduledrecording.h"
    37 #include "libmythtv/storagegroup.h"
     37#include "storagegroup.h"
    3838#include "libmythtv/cardutil.h"
    3939
    4040#define LOC QString("Scheduler: ")
  • programs/mythtv-setup/main.cpp

     
    3030#include "libmythtv/videosource.h"
    3131#include "libmythtv/channeleditor.h"
    3232#include "libmythtv/remoteutil.h"
    33 #include "libmythtv/storagegroup.h"
     33#include "storagegroup.h"
    3434#include "backendsettings.h"
    3535#include "checksetup.h"
    3636