MythTV  master
configuration.cpp
Go to the documentation of this file.
1 // Program Name: configuration.cpp
3 // Created : Feb. 12, 2007
4 //
5 // Purpose : Configuration file Class
6 //
7 // Copyright (c) 2007 David Blain <dblain@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see LICENSE for details
10 //
12 
13 #include "configuration.h"
14 
15 #include <unistd.h> // for fsync
16 
17 #include <iostream>
18 
19 #include <QDir>
20 #include <QFile>
21 #include <QTextStream>
22 
23 #include "mythlogging.h"
24 #include "mythdb.h"
25 #include "compat.h"
26 
27 
29 {
30  QString pathName = m_path + '/' + m_fileName;
31  QFile file(pathName);
32  return file.exists();
33 }
34 
36 {
37  QString pathName = m_path + '/' + m_fileName;
38 
39  LOG(VB_GENERAL, LOG_DEBUG, QString("Loading %1").arg(pathName));
40 
41  QFile file(pathName);
42 
43  if (file.exists() && !m_fileName.isEmpty()) // Ignore empty filenames
44  {
45 
46  if (!file.open(QIODevice::ReadOnly))
47  {
48  return false;
49  }
50 
51  QString error;
52  int line = 0;
53  int column = 0;
54  bool success = m_config.setContent(&file, false, &error, &line, &column);
55 
56  file.close();
57 
58  if (!success)
59  {
60  LOG(VB_GENERAL, LOG_ERR,
61  QString("Error parsing: %1 at line: %2 column: %3")
62  .arg(pathName, QString::number(line), QString::number(column)));
63 
64  LOG(VB_GENERAL, LOG_ERR, QString("Error Msg: %1").arg(error));
65  return false;
66  }
67 
68  m_rootNode = m_config.namedItem("Configuration");
69  }
70  else
71  {
72  m_rootNode = m_config.createElement("Configuration");
73  m_config.appendChild(m_rootNode);
74  }
75 
76  return true;
77 }
78 
80 {
81  if (m_fileName.isEmpty()) // Special case. No file is created
82  {
83  return true;
84  }
85 
86  QString pathName = m_path + '/' + m_fileName;
87  QString backupName = pathName + ".old";
88 
89  LOG(VB_GENERAL, LOG_DEBUG, QString("Saving %1").arg(pathName));
90 
91  QFile file(pathName + ".new");
92 
93  if (!file.exists())
94  {
95  QDir directory(m_path);
96  if (!directory.exists() && !directory.mkdir(m_path))
97  {
98  LOG(VB_GENERAL, LOG_ERR, QString("Could not create %1").arg(m_path));
99  return false;
100  }
101  }
102 
103  if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
104  {
105  LOG(VB_GENERAL, LOG_ERR, QString("Could not open settings file %1 for writing").arg(file.fileName()));
106  return false;
107  }
108 
109  {
110  QTextStream ts(&file);
111  m_config.save(ts, 2);
112  }
113 
114  file.flush();
115  fsync(file.handle());
116  file.close();
117 
118  bool success = true;
119  if (QFile::exists(pathName))
120  {
121  if (QFile::exists(backupName) && !QFile::remove(backupName)) // if true, rename will fail
122  {
123  LOG(VB_GENERAL, LOG_ERR, QString("Failed to remove '%1', cannot backup current settings").arg(backupName));
124  }
125  success = QFile::rename(pathName, backupName); // backup old settings in case it fails
126  }
127 
128  if (success) // no settings to overwrite or settings backed up successfully
129  {
130  success = file.rename(pathName); // move new settings into target location
131  if (success)
132  {
133  if (QFile::exists(backupName) && !QFile::remove(backupName))
134  {
135  LOG(VB_GENERAL, LOG_WARNING, QString("Failed to remove '%1'").arg(backupName));
136  }
137  }
138  else if (QFile::exists(backupName) && !QFile::rename(backupName, pathName)) // !success &&
139  {
140  LOG(VB_GENERAL, LOG_ERR, QString("Failed to rename (restore) '%1").arg(backupName));
141  }
142  }
143 
144  if (!success)
145  {
146  LOG(VB_GENERAL, LOG_ERR, QString("Could not save settings file %1").arg(pathName));
147  }
148 
149  return success;
150 }
151 
152 QDomNode XmlConfiguration::FindNode(const QString &setting, bool create)
153 {
154 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
155  QStringList path = setting.split('/', QString::SkipEmptyParts);
156 #else
157  QStringList path = setting.split('/', Qt::SkipEmptyParts);
158 #endif
159 
160  return FindNode(path, m_rootNode, create);
161 
162 }
163 
164 QDomNode XmlConfiguration::FindNode(QStringList &path, QDomNode &current, bool create)
165 {
166  if (path.empty())
167  {
168  return current;
169  }
170 
171  QString name = path.front();
172  path.pop_front();
173 
174  QDomNode child = current.namedItem(name);
175 
176  if (child.isNull())
177  {
178  if (!create)
179  {
180  path.clear();
181  }
182  else if (!current.isNull()) // && create
183  {
184  child = current.appendChild(m_config.createElement(name));
185  }
186  }
187 
188  return FindNode(path, child, create);
189 }
190 
191 QString XmlConfiguration::GetValue(const QString &setting)
192 {
193  QDomNode node = FindNode(setting, false);
194  QDomText textNode;
195  // -=>TODO: This Always assumes firstChild is a Text Node... should change
196  if (!node.isNull() && !(textNode = node.firstChild().toText()).isNull())
197  {
198  LOG(VB_GENERAL, LOG_DEBUG, QString("Got \"%1\" for \"%2\"").arg(textNode.nodeValue(), setting));
199 
200  return textNode.nodeValue();
201  }
202 
203  LOG(VB_GENERAL, LOG_DEBUG, QString("Using default for \"%1\"").arg(setting));
204  return {};
205 }
206 
207 void XmlConfiguration::SetValue(const QString &setting, const QString& value)
208 {
209  LOG(VB_GENERAL, LOG_DEBUG, QString("Setting \"%1\" to \"%2\"").arg(setting, value));
210 
211  QDomNode node = FindNode(setting, true);
212 
213  if (!node.isNull())
214  {
215  QDomText textNode;
216 
217  if (node.hasChildNodes())
218  {
219  // -=>TODO: This Always assumes only child is a Text Node... should change
220  textNode = node.firstChild().toText();
221  textNode.setNodeValue(value);
222  }
223  else
224  {
225  textNode = m_config.createTextNode(value);
226  node.appendChild(textNode);
227  }
228  }
229 }
230 
231 void XmlConfiguration::ClearValue(const QString &setting)
232 {
233  LOG(VB_GENERAL, LOG_DEBUG, QString("clearing %1").arg(setting));
234  QDomNode node = FindNode(setting, false);
235  if (!node.isNull())
236  {
237  QDomNode parent = node.parentNode();
238  parent.removeChild(node);
239  while (parent.childNodes().count() == 0)
240  {
241  QDomNode next_parent = parent.parentNode();
242  next_parent.removeChild(parent);
243  parent = next_parent;
244  }
245  }
246 }
XmlConfiguration::FileExists
bool FileExists()
Definition: configuration.cpp:28
error
static void error(const char *str,...)
Definition: vbi.cpp:36
mythdb.h
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
XmlConfiguration::m_rootNode
QDomNode m_rootNode
Definition: configuration.h:46
build_compdb.file
file
Definition: build_compdb.py:55
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
XmlConfiguration::ClearValue
void ClearValue(const QString &setting)
Definition: configuration.cpp:231
XmlConfiguration::m_path
QString m_path
Definition: configuration.h:42
XmlConfiguration::SetValue
void SetValue(const QString &setting, bool value)
Definition: configuration.h:93
XmlConfiguration::m_config
QDomDocument m_config
Definition: configuration.h:45
mythlogging.h
compat.h
XmlConfiguration::Save
bool Save()
Definition: configuration.cpp:79
XmlConfiguration::Load
bool Load()
Definition: configuration.cpp:35
XmlConfiguration::GetValue
QString GetValue(const QString &setting)
Definition: configuration.cpp:191
XmlConfiguration::m_fileName
QString m_fileName
Definition: configuration.h:43
XmlConfiguration::FindNode
QDomNode FindNode(const QString &setting, bool create)
Definition: configuration.cpp:152
configuration.h
fsync
#define fsync(FD)
Definition: compat.h:76