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