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
12#include "libmythbase/mythdb.h"
14
15#include "storagegroupeditor.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 const 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 {
106 delete confirmDelete;
107 }
108}
109
111{
112 if (doDelete)
113 {
114 bool is_master_host = gCoreContext->IsMasterHost();
116 QString sql = "DELETE FROM storagegroup "
117 "WHERE groupname = :NAME";
118 if (is_master_host)
119 {
120 // From the master host, delete the group completely (versus just
121 // local directory list) unless it's the Default group, then just
122 // delete remote overrides of the Default group
123 if (m_group == "Default")
124 sql.append(" AND hostname != :HOSTNAME");
125 }
126 else
127 {
128 // For non-master hosts, delete only the local override of the
129 // group directory list
130 sql.append(" AND hostname = :HOSTNAME");
131 }
132 sql.append(';');
133 query.prepare(sql);
134 query.bindValue(":NAME", m_group);
135 if (!is_master_host || (m_group == "Default"))
136 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
137 if (!query.exec())
138 MythDB::DBError("StorageGroupListEditor::doDelete", query);
139 }
140}
141
143 int id,
144 QString group) :
145 SimpleDBStorage(_user, "storagegroup", "dirname"),
146 m_id(id),
147 m_group(std::move(group))
148{
149}
150
152{
153 QString dirnameTag(":SETDIRNAME");
154
155 QString query("dirname = " + dirnameTag);
156
157 bindings.insert(dirnameTag, m_user->GetDBValue());
158
159 return query;
160}
161
163{
164 QString hostnameTag(":WHEREHOST");
165 QString idTag(":WHEREID");
166
167 QString query("hostname = " + hostnameTag + " AND id = " + idTag);
168
169 bindings.insert(hostnameTag, gCoreContext->GetHostName());
170 bindings.insert(idTag, m_id);
171
172 return query;
173}
174
177 m_id(id), m_group(group)
178{
179 SetTypeFilter(QDir::AllDirs | QDir::Drives);
180}
181
183{
184 delete GetStorage();
185}
186
188{
189 QStringList actions;
190 bool handled =
191 GetMythMainWindow()->TranslateKeyPress("Global", event, actions);
192 for (int i = 0; i < actions.size() && !handled; i++)
193 {
194 const QString& action = actions[i];
195
196 if (action == "DELETE")
197 {
198 handled = true;
200 }
201 }
202 return handled;
203}
204
206{
207 QString message =
208 tr("Remove '%1'\nDirectory From Storage Group?").arg(getValue());
209 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
210 auto *confirmDelete = new MythConfirmationDialog(popupStack, message, true);
211
212 if (confirmDelete->Create())
213 {
214 connect(confirmDelete, &MythConfirmationDialog::haveResult,
216 popupStack->AddScreen(confirmDelete);
217 }
218 else
219 {
220 delete confirmDelete;
221 }
222}
223
225{
226 if (doDelete)
227 {
229 query.prepare("DELETE FROM storagegroup "
230 "WHERE groupname = :NAME "
231 "AND dirname = :DIRNAME "
232 "AND hostname = :HOSTNAME;");
233 query.bindValue(":NAME", m_group);
234 query.bindValue(":DIRNAME", getValue());
235 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
236 if (query.exec())
237 getParent()->removeChild(this);
238 else
239 MythDB::DBError("StorageGroupEditor::DoDeleteSlot", query);
240 }
241}
242
244{
246
247 auto *button = new ButtonStandardSetting(tr("(Add New Directory)"));
249 addChild(button);
250
252 query.prepare("SELECT dirname, id FROM storagegroup "
253 "WHERE groupname = :NAME AND hostname = :HOSTNAME "
254 "ORDER BY id;");
255 query.bindValue(":NAME", m_group);
256 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
257 if (!query.exec() || !query.isActive())
258 MythDB::DBError("StorageGroupEditor::Load", query);
259 else
260 {
261 bool first = true;
262 QString dirname;
263 while (query.next())
264 {
265 /* The storagegroup.dirname column uses utf8_bin collation, so Qt
266 * uses QString::fromAscii() for toString(). Explicitly convert the
267 * value using QString::fromUtf8() to prevent corruption. */
268 dirname = QString::fromUtf8(query.value(0)
269 .toByteArray().constData());
270 if (first)
271 {
272 first = false;
273 }
274 addChild(new StorageGroupDirSetting(query.value(1).toInt(),
275 m_group));
276 }
277
278 if (!first)
279 {
280 SetLabel();
281 }
282 }
283
285}
286
288{
289 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
290
291 auto *settingdialog = new MythUIFileBrowser(popupStack, "");
292 settingdialog->SetTypeFilter(QDir::AllDirs | QDir::Drives);
293
294 if (settingdialog->Create())
295 {
296 settingdialog->SetReturnEvent(this, "editsetting");
297 popupStack->AddScreen(settingdialog);
298 }
299 else
300 {
301 delete settingdialog;
302 }
303}
304
306{
307 if (event->type() == DialogCompletionEvent::kEventType)
308 {
309 auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
310 if (dce == nullptr)
311 return;
312 QString resultid = dce->GetId();
313
314 if (resultid == "editsetting")
315 {
316 QString dirname = dce->GetResultText();
317
318 if (dirname.isEmpty())
319 return;
320
321 if (!dirname.endsWith("/"))
322 dirname.append("/");
323
325 query.prepare("INSERT INTO storagegroup (groupname, hostname, dirname) "
326 "VALUES (:NAME, :HOSTNAME, :DIRNAME);");
327 query.bindValue(":NAME", m_group);
328 query.bindValue(":DIRNAME", dirname);
329 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
330 if (!query.exec())
331 MythDB::DBError("StorageGroupEditor::customEvent", query);
332 else
333 {
334 SetLabel();
335 StandardSetting *directory =
336 new StorageGroupDirSetting(query.lastInsertId().toInt(),
337 m_group);
338 directory->setValue(dirname);
339 addChild(directory);
340 emit settingsChanged(this);
341 }
342 }
343 }
344}
345
346
347/****************************************************************************/
348
350{
352 setLabel(tr("Storage Groups (directories for new recordings)"));
353 else
354 setLabel(tr("Local Storage Groups (directories for new recordings)"));
355}
356
357void StorageGroupListEditor::AddSelection(const QString &label,
358 const QString &value)
359{
360 auto *button = new StorageGroupEditor(value);
361 button->setLabel(label);
362 addChild(button);
363}
364
366{
367 QStringList names;
368 QStringList masterNames;
369 bool createAddDefaultButton = false;
370 QVector< bool > createAddSpecialGroupButton( StorageGroup::kSpecialGroups.size() );
371 bool isMaster = gCoreContext->IsMasterHost();
372
374 query.prepare("SELECT distinct groupname "
375 "FROM storagegroup "
376 "WHERE hostname = :HOSTNAME "
377 "ORDER BY groupname;");
378 query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
379 if (!query.exec())
380 {
381 MythDB::DBError("StorageGroup::Load getting local group names",
382 query);
383 }
384 else
385 {
386 while (query.next())
387 names << query.value(0).toString();
388 }
389
390 query.prepare("SELECT distinct groupname "
391 "FROM storagegroup "
392 "ORDER BY groupname;");
393 if (!query.exec())
394 {
395 MythDB::DBError("StorageGroup::Load getting all group names",
396 query);
397 }
398 else
399 {
400 while (query.next())
401 masterNames << query.value(0).toString();
402 }
403
405
406 if (isMaster || names.contains("Default"))
407 {
408 AddSelection(tr("Default", "Default storage group"),
409 "Default");
410 }
411 else
412 {
413 createAddDefaultButton = true;
414 }
415
416 int curGroup = 0;
417 QString groupName;
418 while (curGroup < StorageGroup::kSpecialGroups.size())
419 {
420 groupName = StorageGroup::kSpecialGroups[curGroup];
421 if (names.contains(groupName))
422 {
423 addChild(new StorageGroupEditor(groupName));
424 createAddSpecialGroupButton[curGroup] = false;
425 }
426 else
427 {
428 createAddSpecialGroupButton[curGroup] = true;
429 }
430 curGroup++;
431 }
432
433 int curName = 0;
434 while (curName < names.size())
435 {
436 if ((names[curName] != "Default") &&
437 (!StorageGroup::kSpecialGroups.contains(names[curName])))
438 addChild(new StorageGroupEditor(names[curName]));
439 curName++;
440 }
441
442 if (createAddDefaultButton)
443 {
444 AddSelection(tr("(Create default group)"), "Default");
445 }
446
447 curGroup = 0;
448 while (curGroup < StorageGroup::kSpecialGroups.size())
449 {
450 groupName = StorageGroup::kSpecialGroups[curGroup];
451 if (createAddSpecialGroupButton[curGroup])
452 {
453 AddSelection(tr("(Create %1 group)")
454 .arg(QCoreApplication::translate("(StorageGroups)",
455 groupName.toLatin1().constData())),
456 groupName);
457 }
458 curGroup++;
459 }
460
461 if (isMaster)
462 {
463 auto *newGroup = new ButtonStandardSetting(tr("(Create new group)"));
465 addChild(newGroup);
466 }
467 else
468 {
469 curName = 0;
470 while (curName < masterNames.size())
471 {
472 if ((masterNames[curName] != "Default") &&
473 (!StorageGroup::kSpecialGroups.contains(masterNames[curName])) &&
474 (!names.contains(masterNames[curName])))
475 {
476 AddSelection(tr("(Create %1 group)")
477 .arg(masterNames[curName]),
478 masterNames[curName]);
479 }
480 curName++;
481 }
482 }
483
485}
486
487
489{
490 MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
491 auto *settingdialog = new MythTextInputDialog(popupStack,
492 tr("Enter the name of the new storage group"));
493
494 if (settingdialog->Create())
495 {
496 connect(settingdialog, &MythTextInputDialog::haveResult,
498 popupStack->AddScreen(settingdialog);
499 }
500 else
501 {
502 delete settingdialog;
503 }
504}
505
507{
508 auto *button = new StorageGroupEditor(name);
509 button->setLabel(name + tr(" Storage Group Directories"));
510 button->Load();
511 addChild(button);
512 emit settingsChanged(this);
513}
514
515/* vim: set expandtab tabstop=4 shiftwidth=4: */
StorageUser * m_user
Definition: mythstorage.h:50
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
static const Type kEventType
Definition: mythdialogbox.h:56
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:837
QVariant value(int i) const
Definition: mythdbcon.h:204
bool isActive(void) const
Definition: mythdbcon.h:215
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:618
void bindValue(const QString &placeholder, const QVariant &val)
Add a single binding.
Definition: mythdbcon.cpp:888
QVariant lastInsertId()
Return the id of the last inserted row.
Definition: mythdbcon.cpp:935
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:812
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:550
Dialog asking for user confirmation.
QString GetHostName(void)
bool IsMasterHost(void)
is this the same host as the master
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:226
bool TranslateKeyPress(const QString &Context, QKeyEvent *Event, QStringList &Actions, bool AllowJumps=true)
Get a list of actions for a keypress in the given context.
MythScreenStack * GetStack(const QString &Stackname)
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Dialog prompting the user to enter a text string.
void haveResult(QString)
void SetTypeFilter(QDir::Filters filter)
virtual void addChild(StandardSetting *child)
virtual void Load(void)
virtual void clearSettings()
void settingsChanged(StandardSetting *selectedSetting=nullptr)
StandardSetting * getParent() const
virtual void removeChild(StandardSetting *child)
virtual void setValue(const QString &newValue)
Storage * GetStorage(void) const
virtual bool keyPressEvent(QKeyEvent *event)
virtual QString getValue(void) const
virtual void setLabel(QString str)
StorageGroupDirSetting(int id, const QString &group)
void DoDeleteSlot(bool doDelete)
bool keyPressEvent(QKeyEvent *event) override
StorageGroupDirStorage(StorageUser *_user, int id, QString group)
QString GetWhereClause(MSqlBindings &bindings) const override
QString GetSetClause(MSqlBindings &bindings) const override
void customEvent(QEvent *event) override
void Load(void) override
StorageGroupEditor(QString group)
void DoDeleteSlot(bool doDelete)
bool keyPressEvent(QKeyEvent *event) override
bool canDelete(void) override
void Load(void) override
void CreateNewGroup(const QString &name)
void ShowNewGroupDialog(void) const
void AddSelection(const QString &label, const QString &value)
static const QStringList kSpecialGroups
Definition: storagegroup.h:46
virtual QString GetDBValue(void) const =0
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QMap< QString, QVariant > MSqlBindings
typedef for a map of string -> string bindings for generic queries.
Definition: mythdbcon.h:100
MythMainWindow * GetMythMainWindow(void)
STL namespace.