1 /////////////////////////////////////////////////////////////////////////////
3 // This program is free software; you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation; either version 2 of the License, or (at
6 // your option) any later version.
8 // This program is distributed in the hope that it will be useful, but
9 // WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 // GNU General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16 /////////////////////////////////////////////////////////////////////////////
18 * @file ProjectFile.cpp
20 * @brief Implementation file for ProjectFile class.
22 // ID line follows -- this is updated by CVS
23 // $Id: ProjectFile.cpp 7081 2010-01-01 20:33:30Z kimmov $
25 #include "ProjectFile.h"
27 #include <Poco/SAX/InputSource.h>
28 #include <Poco/XML/XMLWriter.h>
29 #include <Poco/DOM/AutoPtr.h>
30 #include <Poco/DOM/Document.h>
31 #include <Poco/DOM/DOMParser.h>
32 #include <Poco/DOM/DOMWriter.h>
33 #include <Poco/DOM/NodeIterator.h>
34 #include <Poco/DOM/NodeFilter.h>
35 #include <Poco/DOM/Text.h>
36 #include <Poco/Exception.h>
37 #include "UnicodeString.h"
41 using Poco::XML::InputSource;
42 using Poco::XML::DOMParser;
43 using Poco::XML::DOMWriter;
44 using Poco::XML::Document;
45 using Poco::XML::Element;
46 using Poco::XML::NodeFilter;
47 using Poco::XML::NodeIterator;
48 using Poco::XML::Node;
49 using Poco::XML::Text;
50 using Poco::XML::XMLWriter;
54 // Constants for xml element names
55 const char Root_element_name[] = "project";
56 const char Paths_element_name[] = "paths";
57 const char Left_element_name[] = "left";
58 const char Middle_element_name[] = "middle";
59 const char Right_element_name[] = "right";
60 const char Filter_element_name[] = "filter";
61 const char Subfolders_element_name[] = "subfolders";
62 const char Left_ro_element_name[] = "left-readonly";
63 const char Middle_ro_element_name[] = "middle-readonly";
64 const char Right_ro_element_name[] = "right-readonly";
67 /** @brief File extension for path files */
68 const String ProjectFile::PROJECTFILE_EXT = UTF82T("WinMerge");
71 * @brief Standard constructor.
73 ProjectFile::ProjectFile()
78 , m_bHasSubfolders(false)
80 , m_bLeftReadOnly(false)
81 , m_bMiddleReadOnly(false)
82 , m_bRightReadOnly(false)
87 * @brief Open given path-file and read data from it to member variables.
88 * @param [in] path Path to project file.
89 * @param [out] sError Error string if error happened.
90 * @return true if reading succeeded, false if error happened.
92 bool ProjectFile::Read(const String& path)
95 parser.setFeature(DOMParser::FEATURE_FILTER_WHITESPACE, true);
96 AutoPtr<Document> tree = parser.parse(T2UTF8(path));
99 Element* root = GetRootElement(tree.get());
102 // Currently our content is paths, so expect
103 // having paths in valid project file!
104 if (!GetPathsData(root))
111 * @brief Return project file XML's root element.
112 * @param [in] tree XML tree we got from the parser.
113 * @return Root element pointer.
115 Element* ProjectFile::GetRootElement(const Document * tree)
119 // Make sure we have correct root element
120 Element *root = dynamic_cast<Element *>(tree->firstChild());
121 if (root->nodeName() != Root_element_name)
127 * @brief Reads the paths data from the XML data.
128 * This function reads the paths data inside given element in XML data.
129 * @param [in] parent Parent element for the paths data.
130 * @return true if pathdata was found from the file.
132 bool ProjectFile::GetPathsData(const Element * parent)
137 Node* paths = parent->firstChild();
138 if (!paths || paths->nodeName() != Paths_element_name)
141 NodeIterator it(paths, NodeFilter::SHOW_ELEMENT);
142 Node* pNode = it.nextNode();
145 std::string nodename = pNode->nodeName();
146 if (nodename == Left_element_name)
148 m_paths.SetLeft(UTF82T(pNode->innerText()).c_str());
151 else if (nodename == Middle_element_name)
153 m_paths.SetMiddle(UTF82T(pNode->innerText()).c_str());
156 else if (nodename == Right_element_name)
158 m_paths.SetRight(UTF82T(pNode->innerText()).c_str());
161 else if (nodename == Filter_element_name)
163 m_filter = UTF82T(pNode->innerText());
166 else if (nodename == Subfolders_element_name)
168 m_subfolders = atoi(pNode->innerText().c_str());
169 m_bHasSubfolders = true;
171 else if (nodename == Left_ro_element_name)
173 m_bLeftReadOnly = atoi(pNode->innerText().c_str()) != 0;
175 else if (nodename == Middle_ro_element_name)
177 m_bMiddleReadOnly = atoi(pNode->innerText().c_str()) != 0;
179 else if (nodename == Right_ro_element_name)
181 m_bRightReadOnly = atoi(pNode->innerText().c_str()) != 0;
183 pNode = it.nextNode();
189 * @brief Save data from member variables to path-file.
190 * @param [in] path Path to project file.
191 * @param [out] sError Error string if error happened.
192 * @return true if saving succeeded, false if error happened.
194 bool ProjectFile::Save(const String& path) const
196 AutoPtr<Document> doc = new Document();
197 AutoPtr<Element> root = doc->createElement(Root_element_name);
200 doc->appendChild(root);
201 AutoPtr<Element> paths = AddPathsElement(root);
204 AddPathsContent(paths);
207 writer.setOptions(XMLWriter::WRITE_XML_DECLARATION | XMLWriter::PRETTY_PRINT);
208 writer.writeNode(T2UTF8(path), doc);
214 * @brief Add paths element into XML tree.
215 * @param [in] parent Parent element for the paths element.
216 * @return pointer to added paths element.
218 Element* ProjectFile::AddPathsElement(Element * parent) const
220 Element *element = parent->ownerDocument()->createElement(Paths_element_name);
221 parent->appendChild(element);
225 static Element *createElement(const Document *doc, const std::string& tagname, const std::string& content)
227 Element *element = doc->createElement(tagname);
228 AutoPtr<Text> text = doc->createTextNode(content);
229 element->appendChild(text);
234 * @brief Add paths data to the XML tree.
235 * This function adds our paths data to the XML tree.
236 * @param [in] parent Parent element for paths data.
237 * @return true if we succeeded, false otherwise.
239 bool ProjectFile::AddPathsContent(Element * parent) const
241 Document *doc = parent->ownerDocument();
242 AutoPtr<Element> element;
244 if (!m_paths.GetLeft().empty())
246 element = createElement(doc, Left_element_name, T2UTF8(m_paths.GetLeft()));
247 parent->appendChild(element);
250 if (!m_paths.GetMiddle().empty())
252 element = createElement(doc, Middle_element_name, T2UTF8(m_paths.GetMiddle()));
253 parent->appendChild(element);
256 if (!m_paths.GetRight().empty())
258 element = createElement(doc, Right_element_name, T2UTF8(m_paths.GetRight()));
259 parent->appendChild(element);
262 if (!m_filter.empty())
264 element = createElement(doc, Filter_element_name, T2UTF8(m_filter));
265 parent->appendChild(element);
268 element = createElement(doc, Subfolders_element_name, m_subfolders != 0 ? "1" : "0");
269 parent->appendChild(element);
271 element = createElement(doc, Left_ro_element_name, m_bLeftReadOnly ? "1" : "0");
272 parent->appendChild(element);
274 if (!m_paths.GetMiddle().empty())
276 element = createElement(doc, Middle_ro_element_name, m_bMiddleReadOnly ? "1" : "0");
277 parent->appendChild(element);
280 element = createElement(doc, Right_ro_element_name, m_bRightReadOnly ? "1" : "0");
281 parent->appendChild(element);
287 * @brief Returns if left path is defined in project file.
288 * @return true if project file has left path.
290 bool ProjectFile::HasLeft() const
296 * @brief Returns if middle path is defined.
298 bool ProjectFile::HasMiddle() const
304 * @brief Returns if right path is defined in project file.
305 * @return true if project file has right path.
307 bool ProjectFile::HasRight() const
313 * @brief Returns if filter is defined in project file.
314 * @return true if project file has filter.
316 bool ProjectFile::HasFilter() const
322 * @brief Returns if subfolder is defined in projectfile.
323 * @return true if project file has subfolder definition.
325 bool ProjectFile::HasSubfolders() const
327 return m_bHasSubfolders;
331 * @brief Returns left path.
332 * @param [out] pReadOnly true if readonly was specified for path.
335 String ProjectFile::GetLeft(bool * pReadOnly /*=NULL*/) const
338 *pReadOnly = m_bLeftReadOnly;
339 return m_paths.GetLeft();
343 * @brief Returns if left path is specified read-only.
344 * @return true if left path is read-only, false otherwise.
346 bool ProjectFile::GetLeftReadOnly() const
348 return m_bLeftReadOnly;
352 * @brief Set left path, returns old left path.
353 * @param [in] sLeft Left path.
354 * @param [in] bReadOnly Will path be recorded read-only?
356 void ProjectFile::SetLeft(const String& sLeft, const bool * pReadOnly /*=NULL*/)
358 m_paths.SetLeft(sLeft.c_str(), false);
360 m_bLeftReadOnly = *pReadOnly;
364 * @brief Returns middle path.
365 * @param [out] pReadOnly true if readonly was specified for path.
367 String ProjectFile::GetMiddle(bool * pReadOnly /*=NULL*/) const
370 *pReadOnly = m_bMiddleReadOnly;
371 return m_paths.GetMiddle();
375 * @brief Returns if middle path is specified read-only.
377 bool ProjectFile::GetMiddleReadOnly() const
379 return m_bMiddleReadOnly;
383 * @brief Set middle path, returns old middle path.
384 * @param [in] sMiddle Middle path.
385 * @param [in] bReadOnly Will path be recorded read-only?
387 void ProjectFile::SetMiddle(const String& sMiddle, const bool * pReadOnly /*=NULL*/)
389 m_paths.SetMiddle(sMiddle.c_str(), false);
391 m_bMiddleReadOnly = *pReadOnly;
397 * @brief Returns right path.
398 * @param [out] pReadOnly true if readonly was specified for path.
399 * @return Right path.
401 String ProjectFile::GetRight(bool * pReadOnly /*=NULL*/) const
404 *pReadOnly = m_bRightReadOnly;
405 return m_paths.GetRight();
409 * @brief Returns if right path is specified read-only.
410 * @return true if right path is read-only, false otherwise.
412 bool ProjectFile::GetRightReadOnly() const
414 return m_bRightReadOnly;
418 * @brief Set right path, returns old right path.
419 * @param [in] sRight Right path.
420 * @param [in] bReadOnly Will path be recorded read-only?
422 void ProjectFile::SetRight(const String& sRight, const bool * pReadOnly /*=NULL*/)
424 m_paths.SetRight(sRight.c_str(), false);
426 m_bRightReadOnly = *pReadOnly;
430 * @brief Returns filter.
431 * @return Filter string.
433 String ProjectFile::GetFilter() const
440 * @param [in] sFilter New filter string to set.
442 void ProjectFile::SetFilter(const String& sFilter)
448 * @brief Returns subfolder included -setting.
449 * @return != 0 if subfolders are included.
451 int ProjectFile::GetSubfolders() const
457 * @brief set subfolder.
458 * @param [in] iSubfolder New value for subfolder inclusion.
460 void ProjectFile::SetSubfolders(int iSubfolder)
462 m_subfolders = iSubfolder ? 1 : 0;
468 * @param [in] files Files in project
469 * @param [in] bSubFolders If true subfolders included (recursive compare)
471 void ProjectFile::SetPaths(const PathContext& files, bool bSubfolders)
474 m_subfolders = bSubfolders;
478 * @brief Returns left and right paths and recursive from project file
480 * @param [out] files Files in project
481 * @param [out] bSubFolders If true subfolders included (recursive compare)
483 void ProjectFile::GetPaths(PathContext& files, bool & bSubfolders) const
487 bSubfolders = (GetSubfolders() == 1);