MythTV  master
storagegroupeditor.cpp
Go to the documentation of this file.
1 // Qt headers
2 #include <QCoreApplication>
3 #include <QDir>
4 #include <QFile>
5 #include <QUrl>
6 #include <QVector>
7 #include <utility>
8 
9 // MythTV headers
10 #include "storagegroupeditor.h"
11 #include "mythcorecontext.h"
12 #include "mythdb.h"
13 #include "mythlogging.h"
14 #include "mythdate.h"
15 #include "mythuifilebrowser.h"
16 
17 #define LOC QString("SGE(%1): ").arg(m_groupname)
18 
19 /****************************************************************************/
20 
22  m_group(std::move(group))
23 {
24  SetLabel();
25 }
26 
28 {
29  QString dispGroup = m_group;
30 
31  if (m_group == "Default")
32  dispGroup = tr("Default", "Default storage group");
33  else if (StorageGroup::kSpecialGroups.contains(m_group))
34  dispGroup = QCoreApplication::translate("(StorageGroups)",
35  m_group.toLatin1().constData());
36 
38  {
39  setLabel(tr("'%1' Storage Group Directories").arg(dispGroup));
40  }
41  else
42  {
43  setLabel(tr("Local '%1' Storage Group Directories").arg(dispGroup));
44  }
45 }
46 
48 {
49  QStringList actions;
50  bool handled =
51  GetMythMainWindow()->TranslateKeyPress("Global", e, actions);
52  for (int i = 0; i < actions.size() && !handled; i++)
53  {
54  QString action = actions[i];
55 
56  if (action == "DELETE")
57  {
58  handled = true;
60  }
61  }
62  if (handled)
63  return handled;
65 }
66 
68 {
69  return true;
70 }
71 
73 {
74  bool is_master_host = gCoreContext->IsMasterHost();
75 
76  QString dispGroup = m_group;
77  if (m_group == "Default")
78  dispGroup = tr("Default", "Default storage group");
79  else if (StorageGroup::kSpecialGroups.contains(m_group))
80  dispGroup = QCoreApplication::translate("(StorageGroups)",
81  m_group.toLatin1().constData());
82 
83  QString message = tr("Delete '%1' Storage Group?").arg(dispGroup);
84  if (is_master_host)
85  {
86  if (m_group == "Default")
87  {
88  message = tr("Delete '%1' Storage Group?\n(from remote hosts)").arg(dispGroup);
89  }
90  else
91  {
92  message = tr("Delete '%1' Storage Group?\n(from all hosts)").arg(dispGroup);
93  }
94  }
95 
96  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
97  auto *confirmDelete = new MythConfirmationDialog(popupStack, message, true);
98  if (confirmDelete->Create())
99  {
100  connect(confirmDelete, &MythConfirmationDialog::haveResult,
102  popupStack->AddScreen(confirmDelete);
103  }
104  else
105  delete confirmDelete;
106 }
107 
109 {
110  if (doDelete)
111  {
112  bool is_master_host = gCoreContext->IsMasterHost();
114  QString sql = "DELETE FROM storagegroup "
115  "WHERE groupname = :NAME";
116  if (is_master_host)
117  {
118  // From the master host, delete the group completely (versus just
119  // local directory list) unless it's the Default group, then just
120  // delete remote overrides of the Default group
121  if (m_group == "Default")
122  sql.append(" AND hostname != :HOSTNAME");
123  }
124  else
125  {
126  // For non-master hosts, delete only the local override of the
127  // group directory list
128  sql.append(" AND hostname = :HOSTNAME");
129  }
130  sql.append(';');
131  query.prepare(sql);
132  query.bindValue(":NAME", m_group);
133  if (!is_master_host || (m_group == "Default"))
134  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
135  if (!query.exec())
136  MythDB::DBError("StorageGroupListEditor::doDelete", query);
137  }
138 }
139 
141  int id,
142  QString group) :
143  SimpleDBStorage(_user, "storagegroup", "dirname"),
144  m_id(id),
145  m_group(std::move(group))
146 {
147 }
148 
150 {
151  QString dirnameTag(":SETDIRNAME");
152 
153  QString query("dirname = " + dirnameTag);
154 
155  bindings.insert(dirnameTag, m_user->GetDBValue());
156 
157  return query;
158 }
159 
161 {
162  QString hostnameTag(":WHEREHOST");
163  QString idTag(":WHEREID");
164 
165  QString query("hostname = " + hostnameTag + " AND id = " + idTag);
166 
167  bindings.insert(hostnameTag, gCoreContext->GetHostName());
168  bindings.insert(idTag, m_id);
169 
170  return query;
171 }
172 
173 StorageGroupDirSetting::StorageGroupDirSetting(int id, const QString &group) :
174  MythUIFileBrowserSetting(new StorageGroupDirStorage(this, id, group)),
175  m_id(id), m_group(group)
176 {
177  SetTypeFilter(QDir::AllDirs | QDir::Drives);
178 }
179 
181 {
182  QStringList actions;
183  bool handled =
184  GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
185  for (int i = 0; i < actions.size() && !handled; i++)
186  {
187  QString action = actions[i];
188 
189  if (action == "DELETE")
190  {
191  handled = true;
193  }
194  }
195  return handled;
196 }
197 
199 {
200  QString message =
201  tr("Remove '%1'\nDirectory From Storage Group?").arg(getValue());
202  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
203  auto *confirmDelete = new MythConfirmationDialog(popupStack, message, true);
204 
205  if (confirmDelete->Create())
206  {
207  connect(confirmDelete, &MythConfirmationDialog::haveResult,
209  popupStack->AddScreen(confirmDelete);
210  }
211  else
212  delete confirmDelete;
213 }
214 
216 {
217  if (doDelete)
218  {
220  query.prepare("DELETE FROM storagegroup "
221  "WHERE groupname = :NAME "
222  "AND dirname = :DIRNAME "
223  "AND hostname = :HOSTNAME;");
224  query.bindValue(":NAME", m_group);
225  query.bindValue(":DIRNAME", getValue());
226  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
227  if (query.exec())
228  getParent()->removeChild(this);
229  else
230  MythDB::DBError("StorageGroupEditor::DoDeleteSlot", query);
231  }
232 }
233 
235 {
236  clearSettings();
237 
238  auto *button = new ButtonStandardSetting(tr("(Add New Directory)"));
240  addChild(button);
241 
243  query.prepare("SELECT dirname, id FROM storagegroup "
244  "WHERE groupname = :NAME AND hostname = :HOSTNAME "
245  "ORDER BY id;");
246  query.bindValue(":NAME", m_group);
247  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
248  if (!query.exec() || !query.isActive())
249  MythDB::DBError("StorageGroupEditor::Load", query);
250  else
251  {
252  bool first = true;
253  QString dirname;
254  while (query.next())
255  {
256  /* The storagegroup.dirname column uses utf8_bin collation, so Qt
257  * uses QString::fromAscii() for toString(). Explicitly convert the
258  * value using QString::fromUtf8() to prevent corruption. */
259  dirname = QString::fromUtf8(query.value(0)
260  .toByteArray().constData());
261  if (first)
262  {
263  first = false;
264  }
266  m_group));
267  }
268 
269  if (!first)
270  {
271  SetLabel();
272  }
273  }
274 
276 }
277 
279 {
280  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
281 
282  auto *settingdialog = new MythUIFileBrowser(popupStack, "");
283  settingdialog->SetTypeFilter(QDir::AllDirs | QDir::Drives);
284 
285  if (settingdialog->Create())
286  {
287  settingdialog->SetReturnEvent(this, "editsetting");
288  popupStack->AddScreen(settingdialog);
289  }
290  else
291  delete settingdialog;
292 }
293 
295 {
296  if (event->type() == DialogCompletionEvent::kEventType)
297  {
298  auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
299  if (dce == nullptr)
300  return;
301  QString resultid = dce->GetId();
302 
303  if (resultid == "editsetting")
304  {
305  QString dirname = dce->GetResultText();
306 
307  if (dirname.isEmpty())
308  return;
309 
310  if (!dirname.endsWith("/"))
311  dirname.append("/");
312 
314  query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
315  "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
316  query.bindValue(":NAME", m_group);
317  query.bindValue(":DIRNAME", dirname);
318  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
319  if (!query.exec())
320  MythDB::DBError("StorageGroupEditor::customEvent", query);
321  else
322  {
323  SetLabel();
324  StandardSetting *directory =
326  m_group);
327  directory->setValue(dirname);
328  addChild(directory);
329  emit settingsChanged(this);
330  }
331  }
332  }
333 }
334 
335 
336 /****************************************************************************/
337 
339 {
340  if (gCoreContext->IsMasterHost())
341  setLabel(tr("Storage Groups (directories for new recordings)"));
342  else
343  setLabel(tr("Local Storage Groups (directories for new recordings)"));
344 }
345 
346 void StorageGroupListEditor::AddSelection(const QString &label,
347  const QString &value)
348 {
349  auto *button = new StorageGroupEditor(value);
350  button->setLabel(label);
351  addChild(button);
352 }
353 
355 {
356  QStringList names;
357  QStringList masterNames;
358  bool createAddDefaultButton = false;
359  QVector< bool > createAddSpecialGroupButton( StorageGroup::kSpecialGroups.size() );
360  bool isMaster = gCoreContext->IsMasterHost();
361 
363  query.prepare("SELECT distinct groupname "
364  "FROM storagegroup "
365  "WHERE hostname = :HOSTNAME "
366  "ORDER BY groupname;");
367  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
368  if (!query.exec())
369  {
370  MythDB::DBError("StorageGroup::Load getting local group names",
371  query);
372  }
373  else
374  {
375  while (query.next())
376  names << query.value(0).toString();
377  }
378 
379  query.prepare("SELECT distinct groupname "
380  "FROM storagegroup "
381  "ORDER BY groupname;");
382  if (!query.exec())
383  {
384  MythDB::DBError("StorageGroup::Load getting all group names",
385  query);
386  }
387  else
388  {
389  while (query.next())
390  masterNames << query.value(0).toString();
391  }
392 
393  clearSettings();
394 
395  if (isMaster || names.contains("Default"))
396  {
397  AddSelection(tr("Default", "Default storage group"),
398  "Default");
399  }
400  else
401  createAddDefaultButton = true;
402 
403  int curGroup = 0;
404  QString groupName;
405  while (curGroup < StorageGroup::kSpecialGroups.size())
406  {
407  groupName = StorageGroup::kSpecialGroups[curGroup];
408  if (names.contains(groupName))
409  {
410  addChild(new StorageGroupEditor(groupName));
411  createAddSpecialGroupButton[curGroup] = false;
412  }
413  else
414  createAddSpecialGroupButton[curGroup] = true;
415  curGroup++;
416  }
417 
418  int curName = 0;
419  while (curName < names.size())
420  {
421  if ((names[curName] != "Default") &&
422  (!StorageGroup::kSpecialGroups.contains(names[curName])))
423  addChild(new StorageGroupEditor(names[curName]));
424  curName++;
425  }
426 
427  if (createAddDefaultButton)
428  {
429  AddSelection(tr("(Create default group)"), "Default");
430  }
431 
432  curGroup = 0;
433  while (curGroup < StorageGroup::kSpecialGroups.size())
434  {
435  groupName = StorageGroup::kSpecialGroups[curGroup];
436  if (createAddSpecialGroupButton[curGroup])
437  {
438  AddSelection(tr("(Create %1 group)")
439  .arg(QCoreApplication::translate("(StorageGroups)",
440  groupName.toLatin1().constData())),
441  groupName);
442  }
443  curGroup++;
444  }
445 
446  if (isMaster)
447  {
448  auto *newGroup = new ButtonStandardSetting(tr("(Create new group)"));
450  addChild(newGroup);
451  }
452  else
453  {
454  curName = 0;
455  while (curName < masterNames.size())
456  {
457  if ((masterNames[curName] != "Default") &&
458  (!StorageGroup::kSpecialGroups.contains(masterNames[curName])) &&
459  (!names.contains(masterNames[curName])))
460  {
461  AddSelection(tr("(Create %1 group)")
462  .arg(masterNames[curName]),
463  masterNames[curName]);
464  }
465  curName++;
466  }
467  }
468 
470 }
471 
472 
474 {
475  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
476  auto *settingdialog = new MythTextInputDialog(popupStack,
477  tr("Enter the name of the new storage group"));
478 
479  if (settingdialog->Create())
480  {
481  connect(settingdialog, &MythTextInputDialog::haveResult,
483  popupStack->AddScreen(settingdialog);
484  }
485  else
486  {
487  delete settingdialog;
488  }
489 }
490 
491 void StorageGroupListEditor::CreateNewGroup(const QString& name)
492 {
493  auto *button = new StorageGroupEditor(name);
494  button->setLabel(name + tr(" Storage Group Directories"));
495  button->Load();
496  addChild(button);
497  emit settingsChanged(this);
498 }
499 
500 /* vim: set expandtab tabstop=4 shiftwidth=4: */
MSqlBindings
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
Definition: mythdbcon.h:97
MSqlQuery::isActive
bool isActive(void) const
Definition: mythdbcon.h:203
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:783
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:124
StorageGroupEditor
Definition: storagegroupeditor.h:8
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1420
doDelete
bool doDelete
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:638
StandardSetting::setValue
virtual void setValue(const QString &newValue)
Definition: standardsettings.cpp:169
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:52
StorageGroupListEditor::Load
void Load(void) override
Definition: storagegroupeditor.cpp:354
storagegroupeditor.h
mythdb.h
DBStorage::m_user
StorageUser * m_user
Definition: mythstorage.h:50
StorageGroupDirSetting::StorageGroupDirSetting
StorageGroupDirSetting(int id, const QString &group)
Definition: storagegroupeditor.cpp:173
StorageGroupDirStorage::StorageGroupDirStorage
StorageGroupDirStorage(StorageUser *_user, int id, QString group)
Definition: storagegroupeditor.cpp:140
ButtonStandardSetting
Definition: standardsettings.h:450
DialogCompletionEvent::kEventType
static Type kEventType
Definition: mythdialogbox.h:57
MSqlQuery::lastInsertId
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:888
MythConfirmationDialog::haveResult
void haveResult(bool)
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:197
MythScreenStack
Definition: mythscreenstack.h:16
arg
arg(title).arg(filename).arg(doDelete))
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
StorageGroupDirStorage::m_id
int m_id
Definition: storagegroupeditor.h:53
StandardSetting::clearSettings
virtual void clearSettings()
Definition: standardsettings.cpp:159
StorageUser::GetDBValue
virtual QString GetDBValue(void) const =0
StorageGroupDirStorage::GetWhereClause
QString GetWhereClause(MSqlBindings &bindings) const override
Definition: storagegroupeditor.cpp:160
StorageGroupDirSetting::DoDeleteSlot
void DoDeleteSlot(bool doDelete)
Definition: storagegroupeditor.cpp:215
StorageGroupEditor::canDelete
bool canDelete(void) override
Definition: storagegroupeditor.cpp:67
SimpleDBStorage
Definition: mythstorage.h:55
MythTextInputDialog::haveResult
void haveResult(QString)
StorageGroupListEditor::AddSelection
void AddSelection(const QString &label, const QString &value)
Definition: storagegroupeditor.cpp:346
ButtonStandardSetting::clicked
void clicked()
StandardSetting::settingsChanged
void settingsChanged(StandardSetting *selectedSetting=nullptr)
StorageGroupDirStorage
Definition: storagegroupeditor.h:43
StandardSetting::addChild
virtual void addChild(StandardSetting *child)
Definition: standardsettings.cpp:70
mythdate.h
mythlogging.h
StorageGroupEditor::StorageGroupEditor
StorageGroupEditor(QString group)
Definition: storagegroupeditor.cpp:21
MythMainWindow::TranslateKeyPress
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
Definition: mythmainwindow.cpp:1116
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
StandardSetting::getParent
StandardSetting * getParent() const
Definition: standardsettings.h:49
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:178
StorageGroupEditor::ShowDeleteDialog
void ShowDeleteDialog()
Definition: storagegroupeditor.cpp:72
StorageGroupDirSetting::m_group
QString m_group
Definition: storagegroupeditor.h:73
StandardSetting::Load
virtual void Load(void)
Definition: standardsettings.cpp:214
StorageGroupEditor::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Definition: storagegroupeditor.cpp:47
mythuifilebrowser.h
StandardSetting::getValue
virtual QString getValue(void) const
Definition: standardsettings.h:52
StandardSetting::keyPressEvent
virtual bool keyPressEvent(QKeyEvent *event)
Definition: standardsettings.cpp:85
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:60
MythUIFileBrowser
Definition: mythuifilebrowser.h:80
StorageGroupDirSetting::keyPressEvent
bool keyPressEvent(QKeyEvent *event) override
Definition: storagegroupeditor.cpp:180
MythUIFileBrowserSetting::SetTypeFilter
void SetTypeFilter(QDir::Filters filter)
Definition: standardsettings.h:195
StorageGroupEditor::DoDeleteSlot
void DoDeleteSlot(bool doDelete)
Definition: storagegroupeditor.cpp:108
StandardSetting::setLabel
virtual void setLabel(QString str)
Definition: standardsettings.h:34
MythUIFileBrowserSetting
Definition: standardsettings.h:187
MythConfirmationDialog
Dialog asking for user confirmation. Ok and optional Cancel button.
Definition: mythdialogbox.h:271
mythcorecontext.h
StorageGroupEditor::Load
void Load(void) override
Definition: storagegroupeditor.cpp:234
StorageGroupEditor::m_group
QString m_group
Definition: storagegroupeditor.h:26
StandardSetting::removeChild
virtual void removeChild(StandardSetting *child)
Definition: standardsettings.cpp:79
MSqlQuery::bindValue
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:864
std
Definition: mythchrono.h:23
StorageGroupDirSetting::ShowDeleteDialog
void ShowDeleteDialog()
Definition: storagegroupeditor.cpp:198
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
StorageGroup::kSpecialGroups
static const QStringList kSpecialGroups
Definition: storagegroup.h:46
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
build_compdb.action
action
Definition: build_compdb.py:9
StorageGroupEditor::customEvent
void customEvent(QEvent *event) override
Definition: storagegroupeditor.cpp:294
StorageGroupDirStorage::GetSetClause
QString GetSetClause(MSqlBindings &bindings) const override
Definition: storagegroupeditor.cpp:149
StorageGroupEditor::SetLabel
void SetLabel(void)
Definition: storagegroupeditor.cpp:27
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:322
StandardSetting
Definition: standardsettings.h:29
StorageGroupDirSetting
Definition: storagegroupeditor.h:57
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:858
MythCoreContext::IsMasterHost
bool IsMasterHost(void)
is this the same host as the master
Definition: mythcorecontext.cpp:679
StorageGroupListEditor::CreateNewGroup
void CreateNewGroup(const QString &name)
Definition: storagegroupeditor.cpp:491
MythTextInputDialog
Dialog prompting the user to enter a text string.
Definition: mythdialogbox.h:313
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
query
MSqlQuery query(MSqlQuery::InitCon())
StorageGroupListEditor::ShowNewGroupDialog
void ShowNewGroupDialog(void) const
Definition: storagegroupeditor.cpp:473
StorageGroupListEditor::StorageGroupListEditor
StorageGroupListEditor(void)
Definition: storagegroupeditor.cpp:338
StorageGroupEditor::ShowFileBrowser
void ShowFileBrowser(void)
Definition: storagegroupeditor.cpp:278
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:808
StorageUser
Definition: mythstorage.h:15