2 * Copyright (C) 2006 Ronald Lamprecht
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 #include "StateManager.hh"
23 #include "DOMErrorReporter.hh"
24 #include "DOMSchemaResolver.hh"
25 #include "LocalToXML.hh"
28 #include "Utf8ToXML.hh"
30 #include "XMLtoLocal.hh"
31 #include "XMLtoUtf8.hh"
32 #include "ecl_system.hh"
33 #include "gui/ErrorMenu.hh"
37 #include <xercesc/dom/DOM.hpp>
38 #include <xercesc/util/XMLDouble.hpp>
39 #include <xercesc/util/XMLString.hpp>
40 #include <xercesc/util/XMLUniDefs.hpp>
41 #include <xercesc/util/PlatformUtils.hpp>
42 #include <xercesc/util/XercesVersion.hpp>
43 #if _XERCES_VERSION < 30000
44 #include <xercesc/framework/LocalFileFormatTarget.hpp>
49 using namespace enigma
;
50 XERCES_CPP_NAMESPACE_USE
53 StateManager
*StateManager::theSingleton
= 0;
55 StateManager
* StateManager::instance() {
56 if (theSingleton
== 0) {
57 theSingleton
= new StateManager();
62 StateManager::StateManager() {
63 std::string statePath
;
64 std::string errMessage
;
66 if (!app
.resourceFS
->findFile( "state.xml" , statePath
)) {
67 if (!app
.systemFS
->findFile( "schemas/state.xml" , statePath
)) {
68 throw XFrontend("Cannot load application state template!");
73 std::ostringstream errStream
;
74 app
.domParserErrorHandler
->resetErrors();
75 app
.domParserErrorHandler
->reportToOstream(&errStream
);
76 app
.domParserSchemaResolver
->resetResolver();
77 app
.domParserSchemaResolver
->addSchemaId("state.xsd","state.xsd");
79 doc
= app
.domParser
->parseURI(statePath
.c_str());
80 if (doc
!= NULL
&& !app
.domParserErrorHandler
->getSawErrors()) {
81 propertiesElem
= dynamic_cast<DOMElement
*>(doc
->getElementsByTagName(
82 Utf8ToXML("properties").x_str())->item(0));
83 groupsElem
= dynamic_cast<DOMElement
*>(doc
->getElementsByTagName(
84 Utf8ToXML("groups").x_str())->item(0));
85 groupList
= groupsElem
->getElementsByTagName(
86 Utf8ToXML("group").x_str());
87 indicesElem
= dynamic_cast<DOMElement
*>(doc
->getElementsByTagName(
88 Utf8ToXML("indices").x_str())->item(0));
89 indexList
= indicesElem
->getElementsByTagName(
90 Utf8ToXML("index").x_str());
91 levelsElem
= dynamic_cast<DOMElement
*>(doc
->getElementsByTagName(
92 Utf8ToXML("levels").x_str())->item(0));
94 if(app
.domParserErrorHandler
->getSawErrors()) {
95 errMessage
= errStream
.str();
97 app
.domParserErrorHandler
->reportToNull(); // do not report to errStream any more
100 errMessage
= "Unexpected XML Exception on load of state\n";
102 if (!errMessage
.empty()) {
103 throw XFrontend("Cannot load application state file: " + statePath
+
104 "\nError: " + errMessage
);
108 StateManager::~StateManager() {
113 bool StateManager::save() {
115 std::string errMessage
;
120 int count
= getInt("Count");
121 setProperty("Count", ++count
);
123 stripIgnorableWhitespace(doc
->getDocumentElement());
124 std::string path
= app
.userPath
+ "/state.xml";
125 std::string pathBackup
= app
.userPath
+ "/backup/state.xml";
127 // backup state every 10th save
129 std::remove((pathBackup
+ "~2").c_str());
130 std::remove((path
+ "~2").c_str()); // 1.00 bakups
131 if (ecl::FileExists(path
+ "~1")) {
132 if (std::difftime(ecl::FileModTime(path
+ "~1"),
133 ecl::FileModTime(pathBackup
+ "~1")) > 0) {
134 // backup 1 from 1.00 is newer than backup 1 on backup path
135 if (Copyfile(path
+ "~1", pathBackup
+ "~2"))
136 std::remove((path
+ "~1").c_str()); // 1.00 bakup
138 // just in case off previous copy failure
139 std::rename((pathBackup
+ "~1").c_str(), (pathBackup
+ "~2").c_str());
140 std::remove((path
+ "~1").c_str()); // 1.00 bakup
143 std::rename((pathBackup
+ "~1").c_str(), (pathBackup
+ "~2").c_str());
145 Copyfile(path
, pathBackup
+ "~1");
149 #if _XERCES_VERSION >= 30000
150 result
= app
.domSer
->writeToURI(doc
, LocalToXML(& path
).x_str());
152 XMLFormatTarget
*myFormTarget
= new LocalFileFormatTarget(path
.c_str());
153 result
= app
.domSer
->writeNode(myFormTarget
, *doc
);
154 delete myFormTarget
; // flush
156 } catch (const XMLException
& toCatch
) {
157 errMessage
= std::string("Exception on save of state: \n") +
158 XMLtoUtf8(toCatch
.getMessage()).c_str() + "\n";
160 } catch (const DOMException
& toCatch
) {
161 errMessage
= std::string("Exception on save of state: \n") +
162 XMLtoUtf8(toCatch
.getMessage()).c_str() + "\n";
165 errMessage
= "Unexpected exception on save of state\n" ;
171 // restore backup in case of error
172 if (Copyfile(pathBackup
+ "~1", path
)) {
173 std::remove((pathBackup
+ "~1").c_str());
174 std::rename((pathBackup
+ "~2").c_str(), (pathBackup
+ "~1").c_str());
177 cerr
<< XMLtoLocal(Utf8ToXML(errMessage
.c_str()).x_str()).c_str();
178 gui::ErrorMenu
m(errMessage
, N_("Continue"));
181 Log
<< "State save o.k.\n";
186 void StateManager::shutdown() {
193 void StateManager::getGroupNames(std::vector
<std::string
> *names
) {
194 for (int i
= 0, l
= groupList
-> getLength(); i
< l
; i
++) {
195 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
196 names
->push_back(XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str());
200 std::string
StateManager::getGroupSelectedIndex(std::string groupName
) {
201 for (int i
= 0, l
= groupList
-> getLength(); i
< l
; i
++) {
202 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
203 if (groupName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str())
204 return XMLtoUtf8(group
->getAttribute(Utf8ToXML("curindex").x_str())).c_str();
209 std::string
StateManager::getGroupSelectedColumn(std::string groupName
) {
210 for (int i
= 0, l
= groupList
-> getLength(); i
< l
; i
++) {
211 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
212 if (groupName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str())
213 return XMLtoUtf8(group
->getAttribute(Utf8ToXML("curcolumn").x_str())).c_str();
218 void StateManager::setGroupSelectedIndex(std::string groupName
, std::string indexName
) {
219 for (int i
= 0, l
= groupList
-> getLength(); i
< l
; i
++) {
220 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
221 if (groupName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
222 group
->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName
).x_str());
228 void StateManager::setGroupSelectedColumn(std::string groupName
, std::string column
) {
229 for (int i
= 0, l
= groupList
-> getLength(); i
< l
; i
++) {
230 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
231 if (groupName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
232 group
->setAttribute(Utf8ToXML("curcolumn").x_str(), Utf8ToXML(column
).x_str());
238 void StateManager::addGroup(std::string groupName
, std::string indexName
, int column
) {
239 // check if group exists - update attributes only
240 for (int i
= 0, l
= groupList
->getLength(); i
< l
; i
++) {
241 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
242 if (groupName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
243 group
->setAttribute(Utf8ToXML("curcolumn").x_str(),
244 Utf8ToXML(ecl::strf("%d",column
)).x_str());
245 group
->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName
).x_str());
249 // if group does not exist add a new element
250 DOMElement
* group
= doc
->createElement (Utf8ToXML("group").x_str());
251 group
->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(groupName
).x_str());
252 group
->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName
).x_str());
253 group
->setAttribute(Utf8ToXML("curcolumn").x_str(),
254 Utf8ToXML(ecl::strf("%d",column
)).x_str());
255 groupsElem
->appendChild(group
);
258 void StateManager::insertGroup(int pos
, std::string groupName
,
259 std::string indexName
, std::string column
) {
260 DOMElement
* group
= doc
->createElement (Utf8ToXML("group").x_str());
261 group
->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(groupName
).x_str());
262 group
->setAttribute(Utf8ToXML("curindex").x_str(), Utf8ToXML(indexName
).x_str());
263 group
->setAttribute(Utf8ToXML("curcolumn").x_str(), Utf8ToXML(column
).x_str());
264 if (pos
< 0 || pos
>= groupList
->getLength())
265 groupsElem
->appendChild(group
);
267 DOMElement
* nextGroup
= dynamic_cast<DOMElement
*>(groupList
->item(pos
));
268 groupsElem
->insertBefore(group
, nextGroup
);
272 void StateManager::deleteGroup(std::string groupName
) {
273 for (int i
= 0, l
= groupList
->getLength(); i
< l
; i
++) {
274 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
275 if (groupName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
276 groupsElem
->removeChild(group
);
282 void StateManager::renameGroup(std::string oldName
, std::string newName
) {
283 // rename group element
284 for (int i
= 0, l
= groupList
->getLength(); i
< l
; i
++) {
285 DOMElement
* group
= dynamic_cast<DOMElement
*>(groupList
->item(i
));
286 if (oldName
== XMLtoUtf8(group
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
287 group
->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(newName
).x_str());
294 void StateManager::addIndex(std::string indexName
, std::string
&groupName
,
295 double &location
, int &curpos
, int &curfirst
) {
296 // check if index exists - get user attributes
297 for (int i
= 0, l
= indexList
-> getLength(); i
< l
; i
++) {
298 DOMElement
* index
= dynamic_cast<DOMElement
*>(indexList
->item(i
));
299 if (indexName
== XMLtoUtf8(index
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
300 groupName
= XMLtoUtf8(index
->getAttribute(Utf8ToXML("group").x_str())).c_str();
301 XMLDouble
* result
= new XMLDouble(index
->getAttribute(Utf8ToXML("location").x_str()));
302 location
= result
->getValue();
304 curpos
= XMLString::parseInt(index
->getAttribute(Utf8ToXML("curposition").x_str()));
305 curfirst
= XMLString::parseInt(index
->getAttribute(Utf8ToXML("curfirst").x_str()));
309 // if index does not exist add a new element with default values
310 DOMElement
* index
= doc
->createElement (Utf8ToXML("index").x_str());
311 index
->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(indexName
).x_str());
312 index
->setAttribute(Utf8ToXML("group").x_str(), Utf8ToXML(groupName
).x_str());
313 index
->setAttribute(Utf8ToXML("location").x_str(), Utf8ToXML(ecl::strf("%g",location
)).x_str());
314 index
->setAttribute(Utf8ToXML("curfirst").x_str(), Utf8ToXML(ecl::strf("%d",0)).x_str());
315 index
->setAttribute(Utf8ToXML("curposition").x_str(), Utf8ToXML(ecl::strf("%d",0)).x_str());
316 indicesElem
->appendChild(index
);
319 void StateManager::setIndexName(std::string oldName
, std::string newName
) {
320 // search index and set attribute
321 for (int i
= 0, l
= indexList
-> getLength(); i
< l
; i
++) {
322 DOMElement
* index
= dynamic_cast<DOMElement
*>(indexList
->item(i
));
323 if (oldName
== XMLtoUtf8(index
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
324 index
->setAttribute(Utf8ToXML("title").x_str(), Utf8ToXML(newName
).x_str());
330 void StateManager::setIndexLocation(std::string indexName
, double location
) {
331 // search index and set attribute
332 for (int i
= 0, l
= indexList
-> getLength(); i
< l
; i
++) {
333 DOMElement
* index
= dynamic_cast<DOMElement
*>(indexList
->item(i
));
334 if (indexName
== XMLtoUtf8(index
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
335 index
->setAttribute(Utf8ToXML("location").x_str(), Utf8ToXML(ecl::strf("%.15g",location
)).x_str());
341 void StateManager::setIndexCurpos(std::string indexName
, int curpos
) {
342 // search index and set attribute
343 for (int i
= 0, l
= indexList
-> getLength(); i
< l
; i
++) {
344 DOMElement
* index
= dynamic_cast<DOMElement
*>(indexList
->item(i
));
345 if (indexName
== XMLtoUtf8(index
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
346 index
->setAttribute(Utf8ToXML("curposition").x_str(), Utf8ToXML(ecl::strf("%d",curpos
)).x_str());
352 void StateManager::setIndexCurfirst(std::string indexName
, int curfirst
) {
353 // search index and set attribute
354 for (int i
= 0, l
= indexList
-> getLength(); i
< l
; i
++) {
355 DOMElement
* index
= dynamic_cast<DOMElement
*>(indexList
->item(i
));
356 if (indexName
== XMLtoUtf8(index
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
357 index
->setAttribute(Utf8ToXML("curfirst").x_str(), Utf8ToXML(ecl::strf("%d",curfirst
)).x_str());
363 void StateManager::setIndexGroup(std::string indexName
, std::string groupName
) {
364 // search index and set attribute
365 for (int i
= 0, l
= indexList
-> getLength(); i
< l
; i
++) {
366 DOMElement
* index
= dynamic_cast<DOMElement
*>(indexList
->item(i
));
367 if (indexName
== XMLtoUtf8(index
->getAttribute(Utf8ToXML("title").x_str())).c_str()) {
368 index
->setAttribute(Utf8ToXML("group").x_str(), Utf8ToXML(groupName
).x_str());
375 std::string
StateManager::getAnnotation(std::string id
) {
376 DOMElement
* level
= getLevel(id
);
378 return XMLtoUtf8(level
->getAttribute(Utf8ToXML("annotation").x_str())).c_str();
383 void StateManager::setAnnotation(std::string id
, std::string annotation
) {
384 DOMElement
* level
= getLevel(id
);
386 level
= doc
->createElement (Utf8ToXML("level").x_str());
387 level
->setAttribute(Utf8ToXML("id").x_str(), Utf8ToXML(id
).x_str());
388 levelsElem
->appendChild(level
);
390 level
->setAttribute(Utf8ToXML("annotation").x_str(), Utf8ToXML(annotation
).x_str());
393 DOMElement
* StateManager::getLevel(std::string id
) {
394 XMLCh
* xmlId
= XMLString::replicate(Utf8ToXML(id
).x_str());
395 bool levelFound
= false;
397 DOMNodeList
* levelList
= levelsElem
->getElementsByTagName(Utf8ToXML("level").x_str());
398 for (int i
= 0, l
= levelList
-> getLength(); i
< l
&& !levelFound
; i
++) {
399 level
= dynamic_cast<DOMElement
*>(levelList
->item(i
));
400 if (XMLString::equals(xmlId
,
401 level
->getAttribute(Utf8ToXML("id").x_str()))) {
405 XMLString::release(&xmlId
);
406 return levelFound
? level
: NULL
;
408 } // namespace enigma