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