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  QStringList path = setting.split('/', Qt::SkipEmptyParts);
155  return FindNode(path, m_rootNode, create);
156 }
157 
158 QDomNode XmlConfiguration::FindNode(QStringList &path, QDomNode &current, bool create)
159 {
160  if (path.empty())
161  {
162  return current;
163  }
164 
165  QString name = path.front();
166  path.pop_front();
167 
168  QDomNode child = current.namedItem(name);
169 
170  if (child.isNull())
171  {
172  if (!create)
173  {
174  path.clear();
175  }
176  else if (!current.isNull()) // && create
177  {
178  child = current.appendChild(m_config.createElement(name));
179  }
180  }
181 
182  return FindNode(path, child, create);
183 }
184 
185 QString XmlConfiguration::GetValue(const QString &setting)
186 {
187  QDomNode node = FindNode(setting, false);
188  QDomText textNode;
189  // -=>TODO: This Always assumes firstChild is a Text Node... should change
190  if (!node.isNull())
191  {
192  textNode = node.firstChild().toText();
193  if (!textNode.isNull())
194  {
195  LOG(VB_GENERAL, LOG_DEBUG, QString("Got \"%1\" for \"%2\"").arg(textNode.nodeValue(), setting));
196 
197  return textNode.nodeValue();
198  }
199  }
200 
201  LOG(VB_GENERAL, LOG_DEBUG, QString("Using default for \"%1\"").arg(setting));
202  return {};
203 }
204 
205 void XmlConfiguration::SetValue(const QString &setting, const QString& value)
206 {
207  LOG(VB_GENERAL, LOG_DEBUG, QString("Setting \"%1\" to \"%2\"").arg(setting, value));
208 
209  QDomNode node = FindNode(setting, true);
210 
211  if (!node.isNull())
212  {
213  QDomText textNode;
214 
215  if (node.hasChildNodes())
216  {
217  // -=>TODO: This Always assumes only child is a Text Node... should change
218  textNode = node.firstChild().toText();
219  textNode.setNodeValue(value);
220  }
221  else
222  {
223  textNode = m_config.createTextNode(value);
224  node.appendChild(textNode);
225  }
226  }
227 }
228 
229 void XmlConfiguration::ClearValue(const QString &setting)
230 {
231  LOG(VB_GENERAL, LOG_DEBUG, QString("clearing %1").arg(setting));
232  QDomNode node = FindNode(setting, false);
233  if (!node.isNull())
234  {
235  QDomNode parent = node.parentNode();
236  parent.removeChild(node);
237  while (parent.childNodes().count() == 0)
238  {
239  QDomNode next_parent = parent.parentNode();
240  next_parent.removeChild(parent);
241  parent = next_parent;
242  }
243  }
244 }
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:229
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:185
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