OSDN Git Service

- Remove MFC dependency
[winmerge-jp/winmerge-jp.git] / Src / ProjectFile.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 //    License (GPLv2+):
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.
7 //    
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.
12 //
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 /////////////////////////////////////////////////////////////////////////////
17 /** 
18  * @file  ProjectFile.cpp
19  *
20  * @brief Implementation file for ProjectFile class.
21  */
22 // ID line follows -- this is updated by CVS
23 // $Id: ProjectFile.cpp 7081 2010-01-01 20:33:30Z kimmov $
24
25 #include "ProjectFile.h"
26
27 #include <stack>
28 #include <string>
29 #include <Poco/FileStream.h>
30 #include <Poco/XML/XMLWriter.h>
31 #include <Poco/SAX/SAXParser.h>
32 #include <Poco/SAX/ContentHandler.h>
33 #include <Poco/Exception.h>
34 #include "UnicodeString.h"
35 #include "unicoder.h"
36
37 using Poco::FileStream;
38 using Poco::XML::SAXParser;
39 using Poco::XML::ContentHandler;
40 using Poco::XML::Locator;
41 using Poco::XML::XMLWriter;
42 using Poco::XML::XMLChar;
43 using Poco::XML::XMLString;
44 using Poco::XML::Attributes;
45 using Poco::Exception;
46 using ucr::toTString;
47 using ucr::toUTF8;
48
49 // Constants for xml element names
50 const char Root_element_name[] = "project";
51 const char Paths_element_name[] = "paths";
52 const char Left_element_name[] = "left";
53 const char Middle_element_name[] = "middle";
54 const char Right_element_name[] = "right";
55 const char Filter_element_name[] = "filter";
56 const char Subfolders_element_name[] = "subfolders";
57 const char Left_ro_element_name[] = "left-readonly";
58 const char Middle_ro_element_name[] = "middle-readonly";
59 const char Right_ro_element_name[] = "right-readonly";
60
61 namespace
62 {
63
64 String xmlch2tstr(const XMLChar *ch, int length)
65 {
66         return toTString(std::string(ch, length));
67 }
68
69 void writeElement(XMLWriter& writer, const std::string& tagname, const std::string& characters)
70 {
71         writer.startElement("", "", tagname);
72         writer.characters(characters);
73         writer.endElement("", "", tagname);
74 }
75
76 }
77
78 class ProjectFileHandler: public ContentHandler
79 {
80 public:
81         ProjectFileHandler(ProjectFile *pProject) : m_pProject(pProject) {}
82
83         void setDocumentLocator(const Locator* loc) {}
84         void startDocument() {}
85         void endDocument() {}
86         void startElement(const XMLString& uri, const XMLString& localName, const XMLString& qname, const Attributes& attributes)
87         {
88                 m_stack.push(localName);
89         }
90         void endElement(const XMLString& uri, const XMLString& localName, const XMLString& qname)
91         {
92                 m_stack.pop();
93         }
94         void characters(const XMLChar ch[], int start, int length)
95         {
96                 if (m_stack.size() != 3)
97                         return;
98
99                 const std::string& nodename = m_stack.top();
100                 if (nodename == Left_element_name)
101                 {
102                         m_pProject->m_paths.SetLeft(xmlch2tstr(ch + start, length));
103                         m_pProject->m_bHasLeft = true;
104                 }
105                 else if (nodename == Middle_element_name)
106                 {
107                         m_pProject->m_paths.SetMiddle(xmlch2tstr(ch + start, length));
108                         m_pProject->m_bHasMiddle = true;
109                 }
110                 else if (nodename == Right_element_name)
111                 {
112                         m_pProject->m_paths.SetRight(xmlch2tstr(ch + start, length));
113                         m_pProject->m_bHasRight = true;
114                 }
115                 else if (nodename == Filter_element_name)
116                 {
117                         m_pProject->m_filter = xmlch2tstr(ch + start, length);
118                         m_pProject->m_bHasFilter = true;
119                 }
120                 else if (nodename == Subfolders_element_name)
121                 {
122                         m_pProject->m_subfolders = atoi(std::string(ch + start, length).c_str());
123                         m_pProject->m_bHasSubfolders = true;
124                 }
125                 else if (nodename == Left_ro_element_name)
126                 {
127                         m_pProject->m_bLeftReadOnly = atoi(std::string(ch + start, length).c_str()) != 0;
128                 }
129                 else if (nodename == Middle_ro_element_name)
130                 {
131                         m_pProject->m_bMiddleReadOnly = atoi(std::string(ch +  start, length).c_str()) != 0;
132                 }
133                 else if (nodename == Right_ro_element_name)
134                 {
135                         m_pProject->m_bRightReadOnly = atoi(std::string(ch + start, length).c_str()) != 0;
136                 }
137         }
138         void ignorableWhitespace(const XMLChar ch[], int start, int length)     {}
139         void processingInstruction(const XMLString& target, const XMLString& data) {}
140         void startPrefixMapping(const XMLString& prefix, const XMLString& uri) {}
141         void endPrefixMapping(const XMLString& prefix) {}
142         void skippedEntity(const XMLString& name) {}
143
144 private:
145         ProjectFile *m_pProject;
146         std::stack<std::string> m_stack;
147 };
148
149 /** @brief File extension for path files */
150 const String ProjectFile::PROJECTFILE_EXT = toTString("WinMerge");
151
152 /** 
153  * @brief Standard constructor.
154  */
155  ProjectFile::ProjectFile()
156 : m_bHasLeft(false)
157 , m_bHasMiddle(false)
158 , m_bHasRight(false)
159 , m_bHasFilter(false)
160 , m_bHasSubfolders(false)
161 , m_subfolders(-1)
162 , m_bLeftReadOnly(false)
163 , m_bMiddleReadOnly(false)
164 , m_bRightReadOnly(false)
165 {
166 }
167
168 /** 
169  * @brief Open given path-file and read data from it to member variables.
170  * @param [in] path Path to project file.
171  * @param [out] sError Error string if error happened.
172  * @return true if reading succeeded, false if error happened.
173  */
174 bool ProjectFile::Read(const String& path)
175 {
176         ProjectFileHandler handler(this);
177         SAXParser parser;
178         parser.setContentHandler(&handler);
179         parser.parse(toUTF8(path));
180         return true;
181 }
182
183 /** 
184  * @brief Save data from member variables to path-file.
185  * @param [in] path Path to project file.
186  * @param [out] sError Error string if error happened.
187  * @return true if saving succeeded, false if error happened.
188  */
189 bool ProjectFile::Save(const String& path) const
190 {
191         FileStream out(toUTF8(path));
192         XMLWriter writer(out, XMLWriter::WRITE_XML_DECLARATION | XMLWriter::PRETTY_PRINT);
193         writer.startDocument();
194         writer.startElement("", "", Root_element_name);
195         {
196                 writer.startElement("", "", Paths_element_name);
197                 {
198                         if (!m_paths.GetLeft().empty())
199                                 writeElement(writer, Left_element_name, toUTF8(m_paths.GetLeft()));
200                         if (!m_paths.GetMiddle().empty())
201                                 writeElement(writer, Middle_element_name, toUTF8(m_paths.GetMiddle()));
202                         if (!m_paths.GetRight().empty())
203                                 writeElement(writer, Right_element_name, toUTF8(m_paths.GetRight()));
204                         if (!m_filter.empty())
205                                 writeElement(writer, Filter_element_name, toUTF8(m_filter));
206                         writeElement(writer, Subfolders_element_name, m_subfolders != 0 ? "1" : "0");
207                         writeElement(writer, Left_ro_element_name, m_bLeftReadOnly ? "1" : "0");
208                         if (!m_paths.GetMiddle().empty())
209                                 writeElement(writer, Middle_ro_element_name, m_bMiddleReadOnly ? "1" : "0");
210                         writeElement(writer, Right_ro_element_name, m_bRightReadOnly ? "1" : "0");
211                 }
212                 writer.endElement("", "", Paths_element_name);
213         }
214         writer.endElement("", "", Root_element_name);
215         writer.endDocument();
216         return true;
217 }
218
219 /** 
220  * @brief Returns if left path is defined in project file.
221  * @return true if project file has left path.
222  */
223 bool ProjectFile::HasLeft() const
224 {
225         return m_bHasLeft;
226 }
227
228 /** 
229  * @brief Returns if middle path is defined.
230  */
231 bool ProjectFile::HasMiddle() const
232 {
233         return m_bHasMiddle;
234 }
235
236 /** 
237  * @brief Returns if right path is defined in project file.
238  * @return true if project file has right path.
239  */
240 bool ProjectFile::HasRight() const
241 {
242         return m_bHasRight;
243 }
244
245 /** 
246  * @brief Returns if filter is defined in project file.
247  * @return true if project file has filter.
248  */
249 bool ProjectFile::HasFilter() const
250 {
251         return m_bHasFilter;
252 }
253
254 /** 
255  * @brief Returns if subfolder is defined in projectfile.
256  * @return true if project file has subfolder definition.
257  */
258 bool ProjectFile::HasSubfolders() const
259 {
260         return m_bHasSubfolders;
261 }
262
263 /** 
264  * @brief Returns left path.
265  * @param [out] pReadOnly true if readonly was specified for path.
266  * @return Left path.
267  */
268 String ProjectFile::GetLeft(bool * pReadOnly /*=NULL*/) const
269 {
270         if (pReadOnly)
271                 *pReadOnly = m_bLeftReadOnly;
272         return m_paths.GetLeft();
273 }
274
275 /** 
276  * @brief Returns if left path is specified read-only.
277  * @return true if left path is read-only, false otherwise.
278  */
279 bool ProjectFile::GetLeftReadOnly() const
280 {
281         return m_bLeftReadOnly;
282 }
283
284 /** 
285  * @brief Set left path, returns old left path.
286  * @param [in] sLeft Left path.
287  * @param [in] bReadOnly Will path be recorded read-only?
288  */
289 void ProjectFile::SetLeft(const String& sLeft, const bool * pReadOnly /*=NULL*/)
290 {
291         m_paths.SetLeft(sLeft, false);
292         if (pReadOnly)
293                 m_bLeftReadOnly = *pReadOnly;
294 }
295
296 /** 
297  * @brief Returns middle path.
298  * @param [out] pReadOnly true if readonly was specified for path.
299  */
300 String ProjectFile::GetMiddle(bool * pReadOnly /*=NULL*/) const
301 {
302         if (pReadOnly)
303                 *pReadOnly = m_bMiddleReadOnly;
304         return m_paths.GetMiddle();
305 }
306
307 /** 
308  * @brief Returns if middle path is specified read-only.
309  */
310 bool ProjectFile::GetMiddleReadOnly() const
311 {
312         return m_bMiddleReadOnly;
313 }
314
315 /** 
316  * @brief Set middle path, returns old middle path.
317  * @param [in] sMiddle Middle path.
318  * @param [in] bReadOnly Will path be recorded read-only?
319  */
320 void ProjectFile::SetMiddle(const String& sMiddle, const bool * pReadOnly /*=NULL*/)
321 {
322         m_paths.SetMiddle(sMiddle, false);
323         if (pReadOnly)
324                 m_bMiddleReadOnly = *pReadOnly;
325
326         return;
327 }
328
329 /** 
330  * @brief Returns right path.
331  * @param [out] pReadOnly true if readonly was specified for path.
332  * @return Right path.
333  */
334 String ProjectFile::GetRight(bool * pReadOnly /*=NULL*/) const
335 {
336         if (pReadOnly)
337                 *pReadOnly = m_bRightReadOnly;
338         return m_paths.GetRight();
339 }
340
341 /** 
342  * @brief Returns if right path is specified read-only.
343  * @return true if right path is read-only, false otherwise.
344  */
345 bool ProjectFile::GetRightReadOnly() const
346 {
347         return m_bRightReadOnly;
348 }
349
350 /** 
351  * @brief Set right path, returns old right path.
352  * @param [in] sRight Right path.
353  * @param [in] bReadOnly Will path be recorded read-only?
354  */
355 void ProjectFile::SetRight(const String& sRight, const bool * pReadOnly /*=NULL*/)
356 {
357         m_paths.SetRight(sRight, false);
358         if (pReadOnly)
359                 m_bRightReadOnly = *pReadOnly;
360 }
361
362 /** 
363  * @brief Returns filter.
364  * @return Filter string.
365  */
366 String ProjectFile::GetFilter() const
367 {
368         return m_filter;
369 }
370
371 /** 
372  * @brief Set filter.
373  * @param [in] sFilter New filter string to set.
374  */
375 void ProjectFile::SetFilter(const String& sFilter)
376 {
377         m_filter = sFilter;
378 }
379
380 /** 
381  * @brief Returns subfolder included -setting.
382  * @return != 0 if subfolders are included.
383  */
384 int ProjectFile::GetSubfolders() const
385 {
386         return m_subfolders;
387 }
388
389 /** 
390  * @brief set subfolder.
391  * @param [in] iSubfolder New value for subfolder inclusion.
392  */
393 void ProjectFile::SetSubfolders(int iSubfolder)
394 {
395         m_subfolders = iSubfolder ? 1 : 0;
396 }
397
398 /** 
399  * @brief 
400  *
401  * @param [in] files Files in project
402  * @param [in] bSubFolders If true subfolders included (recursive compare)
403  */
404 void ProjectFile::SetPaths(const PathContext& files, bool bSubfolders)
405 {
406         m_paths = files;
407         m_subfolders = bSubfolders;
408 }
409
410 /** 
411  * @brief Returns left and right paths and recursive from project file
412  * 
413  * @param [out] files Files in project
414  * @param [out] bSubFolders If true subfolders included (recursive compare)
415  */
416 void ProjectFile::GetPaths(PathContext& files, bool & bSubfolders) const
417 {
418         files = m_paths;
419         if (HasSubfolders())
420                 bSubfolders = (GetSubfolders() == 1);
421 }