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