]> git.lyx.org Git - lyx.git/blob - src/Session.cpp
header cleanup
[lyx.git] / src / Session.cpp
1 /**
2  * \file Session.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Lars Gullik Bjønnes
7  * \author Bo Peng
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "Session.h"
15
16 #include "support/debug.h"
17 #include "support/filetools.h"
18 #include "support/Package.h"
19
20 #include <fstream>
21 #include <sstream>
22 #include <algorithm>
23 #include <iterator>
24
25 using namespace std;
26 using namespace lyx::support;
27
28 namespace {
29
30 string const sec_lastfiles = "[recent files]";
31 string const sec_lastfilepos = "[cursor positions]";
32 string const sec_lastopened = "[last opened files]";
33 string const sec_bookmarks = "[bookmarks]";
34 string const sec_session = "[session info]";
35 string const sec_toolbars = "[toolbars]";
36
37 } // anon namespace
38
39
40 namespace lyx {
41
42
43 LastFilesSection::LastFilesSection(unsigned int num) :
44         default_num_last_files(4),
45         absolute_max_last_files(100)
46 {
47         setNumberOfLastFiles(num);
48 }
49
50
51 void LastFilesSection::read(istream & is)
52 {
53         string tmp;
54         do {
55                 char c = is.peek();
56                 if (c == '[')
57                         break;
58                 getline(is, tmp);
59                 FileName const file(tmp);
60                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ' || !file.isAbsolute())
61                         continue;
62
63                 // read lastfiles
64                 if (file.exists() && !file.isDirectory()
65                     && lastfiles.size() < num_lastfiles)
66                         lastfiles.push_back(file);
67                 else
68                         LYXERR(Debug::INIT, "LyX: Warning: Ignore last file: " << tmp);
69         } while (is.good());
70 }
71
72
73 void LastFilesSection::write(ostream & os) const
74 {
75         os << '\n' << sec_lastfiles << '\n';
76         copy(lastfiles.begin(), lastfiles.end(),
77              ostream_iterator<FileName>(os, "\n"));
78 }
79
80
81 void LastFilesSection::add(FileName const & file)
82 {
83         // If file already exist, delete it and reinsert at front.
84         LastFiles::iterator it = find(lastfiles.begin(), lastfiles.end(), file);
85         if (it != lastfiles.end())
86                 lastfiles.erase(it);
87         lastfiles.push_front(file);
88         if (lastfiles.size() > num_lastfiles)
89                 lastfiles.pop_back();
90 }
91
92
93 void LastFilesSection::setNumberOfLastFiles(unsigned int no)
94 {
95         if (0 < no && no <= absolute_max_last_files)
96                 num_lastfiles = no;
97         else {
98                 LYXERR(Debug::INIT, "LyX: session: too many last files\n"
99                         << "\tdefault (=" << default_num_last_files << ") used.");
100                 num_lastfiles = default_num_last_files;
101         }
102 }
103
104
105 void LastOpenedSection::read(istream & is)
106 {
107         string tmp;
108         do {
109                 char c = is.peek();
110                 if (c == '[')
111                         break;
112                 getline(is, tmp);
113                 FileName const file(tmp);
114                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ' || !file.isAbsolute())
115                         continue;
116
117                 if (file.exists() && !file.isDirectory())
118                         lastopened.push_back(file);
119                 else
120                         LYXERR(Debug::INIT, "LyX: Warning: Ignore last opened file: " << tmp);
121         } while (is.good());
122 }
123
124
125 void LastOpenedSection::write(ostream & os) const
126 {
127         os << '\n' << sec_lastopened << '\n';
128         copy(lastopened.begin(), lastopened.end(),
129              ostream_iterator<FileName>(os, "\n"));
130 }
131
132
133 void LastOpenedSection::add(FileName const & file)
134 {
135         lastopened.push_back(file);
136 }
137
138
139 void LastOpenedSection::clear()
140 {
141         lastopened.clear();
142 }
143
144
145 void LastFilePosSection::read(istream & is)
146 {
147         string tmp;
148         do {
149                 char c = is.peek();
150                 if (c == '[')
151                         break;
152                 getline(is, tmp);
153                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
154                         continue;
155
156                 try {
157                         // read lastfilepos
158                         // pos, file\n
159                         FilePos filepos;
160                         string fname;
161                         istringstream itmp(tmp);
162                         itmp >> filepos.pit;
163                         itmp.ignore(2);  // ignore ", "
164                         itmp >> filepos.pos;
165                         itmp.ignore(2);  // ignore ", "
166                         getline(itmp, fname);
167                         FileName const file(fname);
168                         if (!file.isAbsolute())
169                                 continue;
170                         if (file.exists() && !file.isDirectory()
171                             && lastfilepos.size() < num_lastfilepos)
172                                 lastfilepos[file] = filepos;
173                         else
174                                 LYXERR(Debug::INIT, "LyX: Warning: Ignore pos of last file: " << fname);
175                 } catch (...) {
176                         LYXERR(Debug::INIT, "LyX: Warning: unknown pos of last file: " << tmp);
177                 }
178         } while (is.good());
179 }
180
181
182 void LastFilePosSection::write(ostream & os) const
183 {
184         os << '\n' << sec_lastfilepos << '\n';
185         for (FilePosMap::const_iterator file = lastfilepos.begin();
186                 file != lastfilepos.end(); ++file) {
187                 os << file->second.pit << ", " << file->second.pos << ", "
188                    << file->first << '\n';
189         }
190 }
191
192
193 void LastFilePosSection::save(FileName const & fname, FilePos const & pos)
194 {
195         lastfilepos[fname] = pos;
196 }
197
198
199 LastFilePosSection::FilePos LastFilePosSection::load(FileName const & fname) const
200 {
201         FilePosMap::const_iterator entry = lastfilepos.find(fname);
202         // Has position information, return it.
203         if (entry != lastfilepos.end())
204                 return entry->second;
205         // Not found, return the first paragraph
206         return FilePos();
207 }
208
209
210 void BookmarksSection::clear()
211 {
212         // keep bookmark[0], the temporary one
213         bookmarks.resize(1);
214         bookmarks.resize(max_bookmarks + 1);
215 }
216
217
218 void BookmarksSection::read(istream & is)
219 {
220         string tmp;
221         do {
222                 char c = is.peek();
223                 if (c == '[')
224                         break;
225                 getline(is, tmp);
226                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
227                         continue;
228
229                 try {
230                         // read bookmarks
231                         // idx, pit, pos, file\n
232                         unsigned int idx;
233                         pit_type pit;
234                         pos_type pos;
235                         string fname;
236                         istringstream itmp(tmp);
237                         itmp >> idx;
238                         itmp.ignore(2);  // ignore ", "
239                         itmp >> pit;
240                         itmp.ignore(2);  // ignore ", "
241                         itmp >> pos;
242                         itmp.ignore(2);  // ignore ", "
243                         getline(itmp, fname);
244                         FileName const file(fname);
245                         if (!file.isAbsolute())
246                                 continue;
247                         // only load valid bookmarks
248                         if (file.exists() && !file.isDirectory() && idx <= max_bookmarks)
249                                 bookmarks[idx] = Bookmark(file, pit, pos, 0, 0);
250                         else
251                                 LYXERR(Debug::INIT, "LyX: Warning: Ignore bookmark of file: " << fname);
252                 } catch (...) {
253                         LYXERR(Debug::INIT, "LyX: Warning: unknown Bookmark info: " << tmp);
254                 }
255         } while (is.good());
256 }
257
258
259 void BookmarksSection::write(ostream & os) const
260 {
261         os << '\n' << sec_bookmarks << '\n';
262         for (size_t i = 1; i <= max_bookmarks; ++i) {
263                 if (isValid(i))
264                         os << i << ", "
265                            << bookmarks[i].bottom_pit << ", "
266                            << bookmarks[i].bottom_pos << ", "
267                            << bookmarks[i].filename << '\n';
268         }
269 }
270
271
272 void BookmarksSection::save(FileName const & fname,
273         pit_type bottom_pit, pos_type bottom_pos,
274         int top_id, pos_type top_pos, unsigned int idx)
275 {
276         // silently ignore bookmarks when idx is out of range
277         if (idx <= max_bookmarks)
278                 bookmarks[idx] = Bookmark(fname, bottom_pit, bottom_pos, top_id, top_pos);
279 }
280
281
282 bool BookmarksSection::isValid(unsigned int i) const
283 {
284         return i <= max_bookmarks && !bookmarks[i].filename.empty();
285 }
286
287
288 BookmarksSection::Bookmark const & BookmarksSection::bookmark(unsigned int i) const
289 {
290         return bookmarks[i];
291 }
292
293
294 void ToolbarSection::read(istream & is)
295 {
296         string tmp;
297         do {
298                 char c = is.peek();
299                 if (c == '[')
300                         break;
301                 getline(is, tmp);
302                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
303                         continue;
304
305                 try {
306                         // Read session info, saved as key/value pairs
307                         // would better yell if pos returns npos
308                         size_t pos = tmp.find_first_of(" = ");
309                         // silently ignore lines without " = "
310                         if (pos != string::npos) {
311                                 ToolbarItem item;
312                                 item.key = tmp.substr(0, pos);
313                                 int state;
314                                 int location;
315                                 istringstream value(tmp.substr(pos + 3));
316                                 value >> state;
317                                 value >> location;
318                                 value >> item.info.posx;
319                                 value >> item.info.posy;
320                                 item.info.state = ToolbarInfo::State(state);
321                                 item.info.location = ToolbarInfo::Location(location);
322                                 toolbars.push_back(item);
323                         } else
324                                 LYXERR(Debug::INIT, "LyX: Warning: Ignore toolbar info: " << tmp);
325                 } catch (...) {
326                         LYXERR(Debug::INIT, "LyX: Warning: unknown Toolbar info: " << tmp);
327                 }
328         } while (is.good());
329         // sort the toolbars by location, line and position
330         sort(toolbars.begin(), toolbars.end());
331 }
332
333
334 void ToolbarSection::write(ostream & os) const
335 {
336         os << '\n' << sec_toolbars << '\n';
337         for (ToolbarList::const_iterator tb = toolbars.begin();
338                 tb != toolbars.end(); ++tb) {
339                 os << tb->key << " = "
340                   << static_cast<int>(tb->info.state) << " "
341                   << static_cast<int>(tb->info.location) << " "
342                   << tb->info.posx << " "
343                   << tb->info.posy << '\n';
344         }
345 }
346
347
348 ToolbarSection::ToolbarInfo & ToolbarSection::load(string const & name)
349 {
350         for (ToolbarList::iterator tb = toolbars.begin();
351                 tb != toolbars.end(); ++tb)
352                 if (tb->key == name)
353                         return tb->info;
354
355         // add a new item
356         ToolbarItem item;
357         item.key = name;
358         toolbars.push_back(item);
359         return toolbars.back().info;
360 }
361
362
363 bool operator<(ToolbarSection::ToolbarItem const & a, ToolbarSection::ToolbarItem const & b)
364 {
365         ToolbarSection::ToolbarInfo lhs = a.info;
366         ToolbarSection::ToolbarInfo rhs = b.info;
367         // on if before off
368         if (lhs.state != rhs.state)
369                 return static_cast<int>(lhs.state) < static_cast<int>(rhs.state);
370         // order of dock does not really matter
371         if (lhs.location != rhs.location)
372                 return static_cast<int>(lhs.location) < static_cast<int>(rhs.location);
373         // if the same dock, the order depends on position
374         if (lhs.location == ToolbarSection::ToolbarInfo::TOP ||
375                 lhs.location == ToolbarSection::ToolbarInfo::BOTTOM)
376                 return lhs.posy < rhs.posy || (lhs.posy == rhs.posy && lhs.posx < rhs.posx);
377         else if (lhs.location == ToolbarSection::ToolbarInfo::LEFT ||
378                 lhs.location == ToolbarSection::ToolbarInfo::RIGHT)
379                 return lhs.posx < rhs.posx || (lhs.posx == rhs.posx && lhs.posy < rhs.posy);
380         return true;
381 }
382
383
384 void SessionInfoSection::read(istream & is)
385 {
386         string tmp;
387         do {
388                 char c = is.peek();
389                 if (c == '[')
390                         break;
391                 getline(is, tmp);
392                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
393                         continue;
394
395                 try {
396                         // Read session info, saved as key/value pairs
397                         // would better yell if pos returns npos
398                         string::size_type pos = tmp.find_first_of(" = ");
399                         // silently ignore lines without " = "
400                         if (pos != string::npos) {
401                                 string key = tmp.substr(0, pos);
402                                 string value = tmp.substr(pos + 3);
403                                 sessioninfo[key] = value;
404                         } else
405                                 LYXERR(Debug::INIT, "LyX: Warning: Ignore session info: " << tmp);
406                 } catch (...) {
407                         LYXERR(Debug::INIT, "LyX: Warning: unknown Session info: " << tmp);
408                 }
409         } while (is.good());
410 }
411
412
413 void SessionInfoSection::write(ostream & os) const
414 {
415         os << '\n' << sec_session << '\n';
416         for (MiscInfo::const_iterator val = sessioninfo.begin();
417                 val != sessioninfo.end(); ++val) {
418                 os << val->first << " = " << val->second << '\n';
419         }
420 }
421
422
423 void SessionInfoSection::save(string const & key, string const & value)
424 {
425         sessioninfo[key] = value;
426 }
427
428
429 string const SessionInfoSection::load(string const & key, bool release)
430 {
431         MiscInfo::const_iterator pos = sessioninfo.find(key);
432         string value;
433         if (pos != sessioninfo.end())
434                 value = pos->second;
435         if (release)
436                 sessioninfo.erase(key);
437         return value;
438 }
439
440
441 Session::Session(unsigned int num) :
442         last_files(num)
443 {
444         // locate the session file
445         // note that the session file name 'session' is hard-coded
446         session_file = FileName(addName(package().user_support().absFilename(), "session"));
447         //
448         readFile();
449 }
450
451
452 void Session::readFile()
453 {
454         // we will not complain if we can't find session_file nor will
455         // we issue a warning. (Lgb)
456         ifstream is(session_file.toFilesystemEncoding().c_str());
457         string tmp;
458
459         while (getline(is, tmp)) {
460                 // Ignore comments, empty line or line stats with ' '
461                 if (tmp == "" || tmp[0] == '#' || tmp[0] == ' ')
462                         continue;
463
464                 // Determine section id
465                 if (tmp == sec_lastfiles)
466                         lastFiles().read(is);
467                 else if (tmp == sec_lastopened)
468                         lastOpened().read(is);
469                 else if (tmp == sec_lastfilepos)
470                         lastFilePos().read(is);
471                 else if (tmp == sec_bookmarks)
472                         bookmarks().read(is);
473                 else if (tmp == sec_toolbars)
474                         toolbars().read(is);
475                 else if (tmp == sec_session)
476                         sessionInfo().read(is);
477                 else
478                         LYXERR(Debug::INIT, "LyX: Warning: unknown Session section: " << tmp);
479         }
480 }
481
482
483 void Session::writeFile() const
484 {
485         ofstream os(session_file.toFilesystemEncoding().c_str());
486         if (os) {
487                 os << "## Automatically generated lyx session file \n"
488                     << "## Editing this file manually may cause lyx to crash.\n";
489
490                 lastFiles().write(os);
491                 lastOpened().write(os);
492                 lastFilePos().write(os);
493                 bookmarks().write(os);
494                 toolbars().write(os);
495                 sessionInfo().write(os);
496         } else
497                 LYXERR(Debug::INIT, "LyX: Warning: unable to save Session: "
498                        << session_file);
499 }
500
501 }