Dear list, I think this will be my last version of the patch since it has everything I planned. Compared to my previous patch, it now
1. saves bookmarks to .lyx/session and load them automatically. Current implementation uses paragraph id, and I expect that to be changed later. 2. saves windows size (not position since some people do not like it) and restore it. (qt only) The patch has been large. Please apply it (to 1.4.x and/or 1.5) and allow more testing. Since the patch is not very intrusive, I would not expect big problems. load_session is turned on by default for test purposes. Please turn it off if it bothers you. Bo
Index: src/lyx_cb.C =================================================================== --- src/lyx_cb.C (revision 13495) +++ src/lyx_cb.C (working copy) @@ -22,7 +22,7 @@ #include "cursor.h" #include "debug.h" #include "gettext.h" -#include "lastfiles.h" +#include "session.h" #include "LaTeXFeatures.h" #include "lyx_main.h" #include "lyxlayout.h" @@ -101,7 +101,7 @@ bool MenuWrite(Buffer * buffer) { if (buffer->save()) { - LyX::ref().lastfiles().newFile(buffer->fileName()); + LyX::ref().session().addLastFile(buffer->fileName()); return true; } @@ -196,7 +196,7 @@ if (!noask && !bufferlist.quitWriteAll()) return; - LyX::cref().lastfiles().writeFile(lyxrc.lastfiles); + LyX::cref().session().writeFile(); } // Set a flag that we do quitting from the program, Index: src/bufferlist.C =================================================================== --- src/bufferlist.C (revision 13495) +++ src/bufferlist.C (working copy) @@ -17,7 +17,7 @@ #include "bufferparams.h" #include "debug.h" #include "gettext.h" -#include "lastfiles.h" +#include "session.h" #include "lyx_cb.h" #include "lyx_main.h" #include "output_latex.h" @@ -187,7 +187,7 @@ if (!WriteAs(buf)) return false; } else if (buf->save()) { - LyX::ref().lastfiles().newFile(buf->fileName()); + LyX::ref().session().addLastFile(buf->fileName()); } else { return false; } Index: src/BufferView_pimpl.C =================================================================== --- src/BufferView_pimpl.C (revision 13495) +++ src/BufferView_pimpl.C (working copy) @@ -42,7 +42,7 @@ #include "lyxfunc.h" #include "lyxtext.h" #include "lyxrc.h" -#include "lastfiles.h" +#include "session.h" #include "metricsinfo.h" #include "paragraph.h" #include "paragraph_funcs.h" @@ -169,6 +169,16 @@ .connect(boost::bind(&BufferView::Pimpl::cursorToggle, this)); cursor_timeout.start(); saved_positions.resize(saved_positions_num); + // load saved bookmarks, emtpy bookmarks will be returned + // if bookmark was not saved. + for (unsigned int i=1; i < saved_positions_num; ++i) { + string fname; + unsigned int id; + lyx::pos_type pos; + boost::tie(fname, id, pos) = LyX::ref().session().loadBookmark(i); + saved_positions[i] = Position( fname, id, pos ); + } + LyX::ref().session().clearBookmarks(); } @@ -293,9 +303,30 @@ setBuffer(b); bv_->showErrorList(_("Parse")); + + // scroll to the position when the file was last closed + if (lyxrc.use_lastfilepos) { + lyx::pit_type pit; + lyx::pos_type pos; + boost::tie(pit, pos) = LyX::ref().session().loadFilePosition(s); + // move to the beginning of that paragraph + // be careful since the file may have been externally changed ... + if ( static_cast<size_t>(pit) < b->paragraphs().size() ) { + // paragraphs is now RandomAccessList + // so simple paragraphs[pit] is not allowed. + ParIterator it = b->par_iterator_begin(); + ParIterator const end = b->par_iterator_end(); + for (; it != end; ++it) + if (it.pit() == pit) { + bv_->setCursor(makeDocIterator(it, pos)); + bv_->update(Update::FitCursor); + break; + } + } + } if (tolastfiles) - LyX::ref().lastfiles().newFile(b->fileName()); + LyX::ref().session().addLastFile(b->fileName()); return true; } @@ -331,6 +362,9 @@ // to this buffer later on. buffer_->saveCursor(cursor_.selectionBegin(), cursor_.selectionEnd()); + // current buffer is going to be switched-off, save cursor pos + LyX::ref().session().saveFilePosition(buffer_->fileName(), + boost::tie(cursor_.pit(), cursor_.pos()) ); } // If we are closing current buffer, switch to the first in @@ -810,6 +844,19 @@ return i < saved_positions_num && !saved_positions[i].filename.empty(); } +void BufferView::Pimpl::saveSavedPositions() +{ + // save bookmarks. It is better to use the pit interface + // but I do not know how to effectively convert between + // par_id and pit. + for (unsigned int i=1; i < saved_positions_num; ++i) { + // to preserve bookmark order, save invalid bookmarks as well + LyX::ref().session().saveBookmark( boost::tie( + saved_positions[i].filename, + saved_positions[i].par_id, + saved_positions[i].par_pos) ); + } +} void BufferView::Pimpl::switchKeyMap() { Index: src/BufferView_pimpl.h =================================================================== --- src/BufferView_pimpl.h (revision 13495) +++ src/BufferView_pimpl.h (working copy) @@ -95,6 +95,8 @@ void restorePosition(unsigned int i); /// bool isSavedPosition(unsigned int i); + /// save bookmarks to .lyx/session + void saveSavedPositions(); /// void switchKeyMap(); /// Index: src/session.C =================================================================== --- src/session.C (revision 0) +++ src/session.C (revision 0) @@ -0,0 +1,280 @@ +/** + * \file session.C + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Lars Gullik Bjønnes + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#include <config.h> + +#include "session.h" +#include "debug.h" +#include "support/package.h" +#include "support/filetools.h" + +#include <boost/filesystem/operations.hpp> + +#include <fstream> +#include <sstream> +#include <algorithm> +#include <iterator> + +using std::vector; +using std::getline; +using std::string; +using std::ifstream; +using std::ofstream; +using std::endl; +using std::istringstream; +using std::copy; +using std::find; +using std::ostream_iterator; + +namespace fs = boost::filesystem; +using lyx::support::AddName; +using lyx::support::package; + +namespace lyx{ + +string const sec_lastfiles = "[recent files]"; +string const sec_lastfilepos = "[cursor positions]"; +string const sec_lastopened = "[last opened files]"; +string const sec_bookmarks = "[bookmarks]"; +string const sec_misc = "[misc info]"; +int const id_lastfiles = 0; +int const id_lastfilepos = 1; +int const id_lastopened = 2; +int const id_bookmarks = 3; +int const id_misc = 4; + +Session::Session(unsigned int num) : + default_num_last_files(4), + absolute_max_last_files(100), + num_lastfilepos(100) +{ + setNumberOfLastFiles(num); + // locate the session file + // note that the session file name 'session' is hard-coded + session_file = AddName(package().user_support(), "session"); + // + readFile(); +} + +void Session::setNumberOfLastFiles(unsigned int no) +{ + if (0 < no && no <= absolute_max_last_files) + num_lastfiles = no; + else { + lyxerr << "LyX: lastfiles: too many files\n" + "\tdefault (=" << default_num_last_files + << ") used." << endl; + num_lastfiles = default_num_last_files; + } +} + +void Session::readFile() +{ + // we will not complain if we can't find session_file nor will + // we issue a warning. (Lgb) + ifstream ifs(session_file.c_str()); + string tmp; + int section=-1; + + // the following is currently not implemented very + // robustly. (Manually editing of the session file may crash lyx) + // + while (getline(ifs, tmp)) { + // ignore comments, empty line or line stats with ' ' + if (tmp[0] == '#' || tmp[0] == '\n' || tmp[0] == ' ') + continue; + // lastfiles section + if (tmp == sec_lastfiles) { + section = id_lastfiles; + continue; + } + else if (tmp == sec_lastfilepos) { + section = id_lastfilepos; + continue; + } + else if (tmp == sec_lastopened) { + section = id_lastopened; + continue; + } + else if (tmp == sec_bookmarks) { + section = id_bookmarks; + } + else if (tmp == sec_misc) { + section = id_misc; + continue; + } + // read lastfiles + else if (section == id_lastfiles) { + if (!fs::exists(tmp) || lastfiles.size() >= num_lastfiles) + continue; + lastfiles.push_back(tmp); + } + // read lastfilepos + else if (section == id_lastfilepos) { + // pos, file\n + lyx::pit_type pit; + lyx::pos_type pos; + string fname; + istringstream itmp(tmp); + itmp >> pit; + itmp.ignore(2); // ignore ", " + itmp >> pos; + itmp.ignore(2); // ignore ", " + itmp >> fname; + if (!fs::exists(fname) || lastfilepos.size() >= num_lastfilepos) + continue; + lastfilepos[fname] = boost::tie(pit, pos); + } + // read lastopened + else if (section == id_lastopened) { + // files + if (!fs::exists(tmp)) + continue; + lastopened.push_back(tmp); + } + // read bookmars + else if (section == id_bookmarks) { + // pos, file\n + unsigned int id; + lyx::pos_type pos; + string fname; + istringstream itmp(tmp); + itmp >> id; + itmp.ignore(2); // ignore ", " + itmp >> pos; + itmp.ignore(2); // ignore ", " + itmp >> fname; + // fname is allowed to be empty (for empty bookmark) + bookmarks.push_back(boost::tie(fname, id, pos)); + } + // read misc info + else if (section == id_misc) { + // would better yell if pos returns npos + string::size_type pos = tmp.find_first_of(" = "); + string key = tmp.substr(0, pos); + string value = tmp.substr(pos+3); + miscinfo[key] = value; + } + } + ifs.close(); +} + +void Session::writeFile() const +{ + ofstream ofs(session_file.c_str()); + if (ofs) { + // + ofs << "## Automatically generated lyx session file " << endl; + ofs << "## Editing this file manually may cause lyx to crash. " << endl; + // first section + ofs << endl << sec_lastfiles << endl; + copy(lastfiles.begin(), lastfiles.end(), + ostream_iterator<string>(ofs, "\n")); + // second section + ofs << endl << sec_lastfilepos << endl; + for (FilePosMap::const_iterator file = lastfilepos.begin(); + file != lastfilepos.end(); ++file) { + ofs << file->second.get<0>() << ", " + << file->second.get<1>() << ", " + << file->first << endl; + } + // third section + ofs << endl << sec_lastopened << endl; + copy(lastopened.begin(), lastopened.end(), + ostream_iterator<string>(ofs, "\n")); + // fourth section + ofs << endl << sec_bookmarks << endl; + for (BookmarkList::const_iterator bm = bookmarks.begin(); + bm != bookmarks.end(); ++bm) { + ofs << bm->get<1>() << ", " + << bm->get<2>() << ", " + << bm->get<0>() << endl; + } + // fifth section + ofs << endl << sec_misc << endl; + for (MiscInfo::const_iterator val = miscinfo.begin(); + val != miscinfo.end(); ++val) { + ofs << val->first << " = " << val->second << endl; + } + ofs.close(); + } else + lyxerr << "LyX: Warning: unable to save Session: " + << session_file << endl; +} + +void Session::addLastFile(string const & file) +{ + // If file already exist, delete it and reinsert at front. + LastFiles::iterator it = find(lastfiles.begin(), lastfiles.end(), file); + if (it != lastfiles.end()) + lastfiles.erase(it); + lastfiles.push_front(file); + if (lastfiles.size() > num_lastfiles) + lastfiles.pop_back(); +} + +void Session::saveFilePosition(string const & fname, FilePos pos ) +{ + lastfilepos[fname] = pos; +} + +Session::FilePos Session::loadFilePosition(string const & fname ) const +{ + FilePosMap::const_iterator entry = lastfilepos.find(fname); + // has position information, return it. + if( entry != lastfilepos.end() ) + return entry->second; + // not found, return the first paragraph + else + return 0; +} + +void Session::clearLastOpenedFiles() +{ + lastopened.clear(); +} + +void Session::setLastOpenedFiles(vector<string> const & files) +{ + lastopened = files; +} + +void Session::saveBookmark( Bookmark const & bookmark) +{ + bookmarks.push_back( bookmark ); +} + +Session::Bookmark const Session::loadBookmark(unsigned int idx) const +{ + // idx is 1 based + if ( idx == 0 || idx >= bookmarks.size() ) + return Bookmark("", 0, 0); + else + return bookmarks[idx-1]; +} + +void Session::saveMiscInfo(string const & key, string const & value) +{ + miscinfo[key] = value; +} + +string const Session::loadMiscInfo(string const & key, bool release) +{ + MiscInfo::const_iterator pos = miscinfo.find(key); + string value=""; + if (pos != miscinfo.end()) + value = pos->second; + if (release) + miscinfo.erase(key); + return value; +} + +} Index: src/lastfiles.C =================================================================== --- src/lastfiles.C (revision 13495) +++ src/lastfiles.C (working copy) @@ -1,99 +0,0 @@ -/** - * \file lastfiles.C - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Lars Gullik Bjønnes - * - * Full author contact details are available in file CREDITS. - */ - -#include <config.h> - -#include "lastfiles.h" -#include "debug.h" - -#include <boost/filesystem/operations.hpp> - -#include <algorithm> -#include <fstream> -#include <iterator> - -namespace fs = boost::filesystem; - -using std::copy; -using std::endl; -using std::find; -using std::getline; -using std::string; -using std::ifstream; -using std::ofstream; -using std::ostream_iterator; - - -LastFiles::LastFiles(string const & filename, bool st, unsigned int num) - : dostat(st) -{ - setNumberOfFiles(num); - readFile(filename); -} - - -void LastFiles::setNumberOfFiles(unsigned int no) -{ - if (0 < no && no <= ABSOLUTEMAXLASTFILES) - num_files = no; - else { - lyxerr << "LyX: lastfiles: too many files\n" - "\tdefault (=" << int(DEFAULTFILES) - << ") used." << endl; - num_files = DEFAULTFILES; - } -} - - -void LastFiles::readFile(string const & filename) -{ - // we will not complain if we can't find filename nor will - // we issue a warning. (Lgb) - ifstream ifs(filename.c_str()); - string tmp; - - while (getline(ifs, tmp) && files.size() < num_files) { - if (dostat && !fs::exists(tmp)) - continue; - files.push_back(tmp); - } -} - - -void LastFiles::writeFile(string const & filename) const -{ - ofstream ofs(filename.c_str()); - if (ofs) { - copy(files.begin(), files.end(), - ostream_iterator<string>(ofs, "\n")); - } else - lyxerr << "LyX: Warning: unable to save LastFiles: " - << filename << endl; -} - - -void LastFiles::newFile(string const & file) -{ - // If file already exist, delete it and reinsert at front. - Files::iterator it = find(files.begin(), files.end(), file); - if (it != files.end()) - files.erase(it); - files.push_front(file); - if (files.size() > num_files) - files.pop_back(); -} - - -string const LastFiles::operator[](unsigned int i) const -{ - if (i < files.size()) - return files[i]; - return string(); -} Index: src/lyxfunc.C =================================================================== --- src/lyxfunc.C (revision 13495) +++ src/lyxfunc.C (working copy) @@ -43,6 +43,8 @@ #include "kbmap.h" #include "language.h" #include "LColor.h" +#include "session.h" +#include "lyx_main.h" #include "lyx_cb.h" #include "LyXAction.h" #include "lyxfind.h" @@ -996,6 +998,15 @@ break; case LFUN_QUIT: + if (view()->available()) { + // save cursor Position for opened files to .lyx/session + LyX::ref().session().saveFilePosition(owner->buffer()->fileName(), + boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); + // save opened file name to .lyx/session + LyX::ref().session().setLastOpenedFiles( bufferlist.getFileNames()); + // save bookmarks to .lyx/session + view()->saveSavedPositions(); + } QuitLyX(argument == "force"); break; @@ -1880,6 +1891,9 @@ void LyXFunc::closeBuffer() { + // save current cursor position + LyX::ref().session().saveFilePosition(owner->buffer()->fileName(), + boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); if (bufferlist.close(owner->buffer(), true) && !quitting) { if (bufferlist.empty()) { // need this otherwise SEGV may occur while @@ -1966,6 +1980,8 @@ case LyXRC::RC_BIBTEX_COMMAND: case LyXRC::RC_BINDFILE: case LyXRC::RC_CHECKLASTFILES: + case LyXRC::RC_USELASTFILEPOS: + case LyXRC::RC_LOADSESSION: case LyXRC::RC_CHKTEX_COMMAND: case LyXRC::RC_CONVERTER: case LyXRC::RC_COPIER: @@ -2007,7 +2023,6 @@ case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS: case LyXRC::RC_LANGUAGE_PACKAGE: case LyXRC::RC_LANGUAGE_USE_BABEL: - case LyXRC::RC_LASTFILES: case LyXRC::RC_MAKE_BACKUP: case LyXRC::RC_MARK_FOREIGN_LANGUAGE: case LyXRC::RC_NUMLASTFILES: Index: src/frontends/gtk/GView.C =================================================================== --- src/frontends/gtk/GView.C (revision 13495) +++ src/frontends/gtk/GView.C (working copy) @@ -117,6 +117,14 @@ bool GView::on_delete_event(GdkEventAny * /*event*/) { + // FIXME + // for qt, this has been changed to the following code + // Similar change to the GTK frontend may be needed. + // + // trigger LFUN_QUIT instead of quit directly + // since LFUN_QUIT may have more cleanup stuff + // + // getLyXFunc().dispatch(FuncRequest(LFUN_QUIT)); QuitLyX(false); return true; } Index: src/frontends/qt2/lyx_gui.C =================================================================== --- src/frontends/qt2/lyx_gui.C (revision 13495) +++ src/frontends/qt2/lyx_gui.C (working copy) @@ -25,10 +25,12 @@ #include "lyxrc.h" #include "lyxserver.h" #include "lyxsocket.h" +#include "session.h" #include "graphics/LoaderQueue.h" #include "support/lstrings.h" +#include "support/convert.h" #include "support/os.h" #include "support/package.h" #include "debug.h" @@ -224,11 +226,28 @@ // initial geometry unsigned int width = 690; unsigned int height = 510; + // try to grab width/height saved from last session + string val = LyX::ref().session().loadMiscInfo("WindowWidth"); + if (val != "") + width = convert<unsigned int>(val); + val = LyX::ref().session().loadMiscInfo("WindowHeight"); + if (val != "") + height = convert<unsigned int>(val); boost::shared_ptr<QtView> view_ptr(new QtView(width, height)); LyX::ref().addLyXView(view_ptr); QtView & view = *view_ptr.get(); + + // moved to saved location (may or may not be a good idea) + // QPoint p = view.pos(); + // val = LyX::ref().session().loadMiscInfo("WindowPosX"); + // if (val != "") + // p.setX(convert<unsigned int>(val)); + // val = LyX::ref().session().loadMiscInfo("WindowPosY"); + // if (val != "") + // p.setY(convert<unsigned int>(val)); + // view.move(p); view.show(); view.init(); Index: src/frontends/qt2/QPrefs.C =================================================================== --- src/frontends/qt2/QPrefs.C (revision 13495) +++ src/frontends/qt2/QPrefs.C (working copy) @@ -35,7 +35,7 @@ #include "ui/QPrefIdentityModule.h" #include "debug.h" -#include "lastfiles.h" +#include "session.h" #include "LColor.h" #include "lyxfont.h" Index: src/frontends/qt2/QtView.C =================================================================== --- src/frontends/qt2/QtView.C (revision 13495) +++ src/frontends/qt2/QtView.C (working copy) @@ -13,12 +13,16 @@ #include "BufferView.h" #include "lyx_cb.h" +#include "lyx_main.h" +#include "session.h" #include "lyxfunc.h" #include "MenuBackend.h" +#include "funcrequest.h" #include "frontends/Toolbars.h" #include "support/filetools.h" +#include "support/convert.h" #include <boost/bind.hpp> @@ -155,7 +159,17 @@ void QtView::closeEvent(QCloseEvent *) { - QuitLyX(false); + // save windows size and position + LyX::ref().session().saveMiscInfo("WindowWidth", convert<string>(width())); + LyX::ref().session().saveMiscInfo("WindowHeight", convert<string>(height())); + // + // Some people do not like the idea of restoring windows pos + // LyX::ref().session().saveMiscInfo("WindowPosX", convert<string>(pos().x())); + // LyX::ref().session().saveMiscInfo("WindowPosY", convert<string>(pos().y())); + // + // trigger LFUN_QUIT instead of quit directly + // since LFUN_QUIT may have more cleanup stuff + getLyXFunc().dispatch(FuncRequest(LFUN_QUIT)); } Index: src/frontends/qt4/lyx_gui.C =================================================================== --- src/frontends/qt4/lyx_gui.C (revision 13495) +++ src/frontends/qt4/lyx_gui.C (working copy) @@ -218,6 +218,13 @@ // initial geometry unsigned int width = 690; unsigned int height = 510; + // try to grab width/height saved from last session + string val = LyX::ref().session().loadMiscInfo("WindowWidth"); + if (val != "") + width = convert<unsigned int>(val); + val = LyX::ref().session().loadMiscInfo("WindowHeight"); + if (val != "") + height = convert<unsigned int>(val); boost::shared_ptr<QtView> view_ptr(new QtView(width, height)); LyX::ref().addLyXView(view_ptr); Index: src/frontends/qt4/QPrefs.C =================================================================== --- src/frontends/qt4/QPrefs.C (revision 13495) +++ src/frontends/qt4/QPrefs.C (working copy) @@ -18,7 +18,6 @@ #include "qt_helpers.h" #include "debug.h" -#include "lastfiles.h" #include "LColor.h" #include "lyxfont.h" Index: src/frontends/qt4/QtView.C =================================================================== --- src/frontends/qt4/QtView.C (revision 13495) +++ src/frontends/qt4/QtView.C (working copy) @@ -14,8 +14,12 @@ #include "BufferView.h" #include "lyx_cb.h" +#include "lyx_main.h" +#include "session.h" #include "lyxfunc.h" #include "MenuBackend.h" +#include "funcrequest.h" +#include "funcrequest.h" #include "debug.h" @@ -23,6 +27,7 @@ #include "support/filetools.h" +#include "support/convert.h" #include <boost/bind.hpp> #include "QtView.h" @@ -173,7 +178,12 @@ void QtView::closeEvent(QCloseEvent *) { - QuitLyX(false); + // save windows size and position + LyX::ref().session().saveMiscInfo("WindowWidth", convert<string>(width())); + LyX::ref().session().saveMiscInfo("WindowHeight", convert<string>(height())); + // trigger LFUN_QUIT instead of quit directly + // since LFUN_QUIT may have more cleanup stuff + getLyXFunc().dispatch(FuncRequest(LFUN_QUIT)); } Index: src/frontends/qt4/QPrefsDialog.C =================================================================== --- src/frontends/qt4/QPrefsDialog.C (revision 13495) +++ src/frontends/qt4/QPrefsDialog.C (working copy) @@ -18,7 +18,7 @@ #include "qt_helpers.h" #include "debug.h" -#include "lastfiles.h" +#include "session.h" #include "LColor.h" #include "lyxfont.h" Index: src/frontends/xforms/XFormsView.C =================================================================== --- src/frontends/xforms/XFormsView.C (revision 13495) +++ src/frontends/xforms/XFormsView.C (working copy) @@ -173,6 +173,14 @@ // Callback for close main form from window manager int XFormsView::atCloseMainFormCB(FL_FORM *, void *) { + // FIXME + // for qt, this has been changed to the following code + // Similar change to the xform frontend may be needed. + // + // trigger LFUN_QUIT instead of quit directly + // since LFUN_QUIT may have more cleanup stuff + // + // getLyXFunc().dispatch(FuncRequest(LFUN_QUIT)); QuitLyX(false); return FL_IGNORE; } Index: src/frontends/xforms/FormPreferences.C =================================================================== --- src/frontends/xforms/FormPreferences.C (revision 13495) +++ src/frontends/xforms/FormPreferences.C (working copy) @@ -24,7 +24,7 @@ #include "controllers/helper_funcs.h" // getSecond #include "buffer.h" -#include "lastfiles.h" +#include "session.h" #include "LColor.h" #include "lyxfont.h" #include "frontends/lyx_gui.h" Index: src/Makefile.am =================================================================== --- src/Makefile.am (revision 13495) +++ src/Makefile.am (working copy) @@ -189,8 +189,8 @@ kbsequence.h \ language.C \ language.h \ - lastfiles.C \ - lastfiles.h \ + session.C \ + session.h \ layout.h \ lengthcommon.C \ lengthcommon.h \ Index: src/session.h =================================================================== --- src/session.h (revision 0) +++ src/session.h (revision 0) @@ -0,0 +1,172 @@ +// -*- C++ -*- +/** + * \file session.h + * This file is part of LyX, the document processor. + * Licence details can be found in the file COPYING. + * + * \author Lars Gullik Bjønnes + * \author Bo Peng + * + * Full author contact details are available in file CREDITS. + */ + +#ifndef SESSION_H +#define SESSION_H + +#include <support/types.h> +#include <boost/utility.hpp> + +#include <string> +#include <deque> +#include <vector> +#include <map> + +// used by at least frontends/qt2/QPref.C +const long maxlastfiles = 20; + +/** This session file maintains + 1. the latest documents loaded (lastfiles) + 2. cursor positions of files closed (lastfilepos) + 3. opened files when a lyx session is closed (lastopened) + 4. bookmarks + 5. general purpose misc info in the form of key/value pairs + */ +namespace lyx{ + +class Session : boost::noncopyable { + +public: + /// + typedef boost::tuple<lyx::pit_type, lyx::pos_type> FilePos; + /// + typedef std::map<std::string, FilePos> FilePosMap; + /// + typedef std::deque<std::string> LastFiles; + /// + typedef std::vector<std::string> LastOpened; + /// + typedef boost::tuple<std::string, unsigned int, lyx::pos_type> Bookmark; + /// + typedef std::vector<Bookmark> BookmarkList; + /// + typedef std::map<std::string, std::string> MiscInfo; + +public: + /** Read the session file. + @param num length of lastfiles + */ + explicit Session(unsigned int num = 4); + + /** Write the session file. + */ + void writeFile() const; + + /** Insert #file# into the lastfile dequeue. + This funtion inserts #file# into the last files list. If the file + already exists it is moved to the top of the list, else exist it + is placed on the top of the list. If the list is full the last + file in the list is popped from the end. + @param file the file to insert in the lastfile list. + */ + void addLastFile(std::string const & file); + + /** add cursor position to the fname entry in the filepos map + @param fname file entry for which to save position information + @param pos position of the cursor when the file is closed. + */ + void saveFilePosition(std::string const & fname, FilePos pos); + + /** clear lastopened file list + */ + void clearLastOpenedFiles(); + + /** set lastopened file list + @param files filenames of a list of opened files + */ + void setLastOpenedFiles(std::vector<std::string> const & files); + + /** load saved cursor position from the fname entry in the filepos map + @param fname file entry for which to load position information + */ + FilePos loadFilePosition(std::string const & fname) const; + + /// Return lastfiles container (deque) + LastFiles const lastFiles() const { return lastfiles; } + + /// Return lastopened container (vector) + LastOpened const lastOpenedFiles() const { return lastopened; } + + /** save a bookmark + @bookmark bookmark to be saved + */ + void saveBookmark( Bookmark const & bookmark); + + /** Return a saved bookmark. If idx is not valid, return an + empty bookmark. + @idx 1-based index to the bookmark list. + */ + Bookmark const loadBookmark(unsigned int idx) const; + + /** clear the bookmark list */ + void clearBookmarks() { bookmarks.clear(); } + + /** set miscellaneous info + @param key key of the value to store + @param value value, a string without newline ('\n') + */ + void saveMiscInfo(std::string const & key, std::string const & value); + + /** load miscellaneous info + @param key a key to extract value from the session file + @param release whether or not clear the value. Default to true + since most of such values are supposed to be used only once. + */ + std::string const loadMiscInfo(std::string const & key, bool release=true); + +private: + /// Default number of lastfiles. + unsigned int const default_num_last_files; + + /// Max number of lastfiles. + unsigned int const absolute_max_last_files; + + /// default number of lastfilepos to save */ + unsigned int const num_lastfilepos; + + /// file to save session, determined in the constructor. + std::string session_file; + + /// a list of lastfiles + LastFiles lastfiles; + + /// a list of bookmarks + BookmarkList bookmarks; + + /// a map to save misc info + MiscInfo miscinfo; + + /// number of files in the lastfiles list. + unsigned int num_lastfiles; + + /// a map of file positions + FilePosMap lastfilepos; + + /// a list of lastopened files + LastOpened lastopened; + + /** Read the session file. + Reads the #.lyx/session# at the beginning of the LyX session. + This will read the session file (usually #.lyx/session#). + @param file the file containing the session. + */ + void readFile(); + + /** Used by the constructor to set the number of stored last files. + @param num the number of lastfiles to set. + */ + void setNumberOfLastFiles(unsigned int num); +}; + +} + +#endif Index: src/lastfiles.h =================================================================== --- src/lastfiles.h (revision 13495) +++ src/lastfiles.h (working copy) @@ -1,105 +0,0 @@ -// -*- C++ -*- -/** - * \file lastfiles.h - * This file is part of LyX, the document processor. - * Licence details can be found in the file COPYING. - * - * \author Lars Gullik Bjønnes - * - * Full author contact details are available in file CREDITS. - */ - -#ifndef LASTFILES_H -#define LASTFILES_H - -#include <boost/utility.hpp> - -#include <deque> -#include <string> - -const long maxlastfiles = 20; - -/** The latest documents loaded. - * This class takes care of the last .lyx files used by the LyX user. It - * both reads and writes this information to a file. The number of files - * kept are user defined, but defaults to four. - */ -class LastFiles : boost::noncopyable { -public: - /// - typedef std::deque<std::string> Files; - - /// - typedef Files::const_iterator const_iterator; - - /** Read the lastfiles file. - @param file The file to read the lastfiles form. - @param dostat Whether to check for file existance. - @param num number of files to remember. - */ - explicit - LastFiles(std::string const & file, - bool dostat = true, unsigned int num = 4); - - /** Insert #file# into the list. - This funtion inserts #file# into the last files list. If the file - already exist it is moved to the top of the list, else exist it - is placed on the top of the list. If the list is full the last - file in the list is popped from the end. - @param file the file to insert in the list. - */ - void newFile(std::string const & file); - /** Writes the lastfiles table to disk. - Writes one file on each line, this way we can at least have - some special chars (e.g. space), but newline in filenames - are thus not allowed. - @param file the file we write the lastfiles list to. - */ - void writeFile(std::string const & file) const; - /** Return file #n# in the lastfiles list. - @param n number in the list to get - */ - std::string const operator[](unsigned int n) const; - /// Iterator to the beginning of the list. - Files::const_iterator begin() const { return files.begin(); } - /// Iterator to the end of the list. - Files::const_iterator end() const { return files.end(); } -private: - /** Local constants. - It is more portable among different C++ compilers to use - an enum instead of #int const XXX# - */ - enum local_constants { - /// Default number of lastfiles. - DEFAULTFILES = 4, - /** Max number of lastfiles. - There is no point in keeping more than this number - of files at the same time. However perhaps someday - someone finds use for more files and wants to - change it. Please do. But don't show the files in - a menu... - */ - ABSOLUTEMAXLASTFILES = 20 - }; - - /// a list of lastfiles - Files files; - /// number of files in the lastfiles list. - unsigned int num_files; - /// check for file existance or not. - bool dostat; - - /** Read the lastfiles file. - Reads the #.lyx_lastfiles# at the beginning of the LyX session. - This will read the lastfiles file (usually #.lyx_lastfiles#). It - will normally discard files that don't exist anymore, unless - LastFiles has been initialized with #dostat = false#. - @param file the file containing the lastfiles. - */ - void readFile(std::string const & file); - /** Used by the constructor to set the number of stored last files. - @param num the number of lastfiles to set. - */ - void setNumberOfFiles(unsigned int num); -}; -#endif Index: src/lyxrc.C =================================================================== --- src/lyxrc.C (revision 13495) +++ src/lyxrc.C (working copy) @@ -25,7 +25,7 @@ #include "converter.h" #include "format.h" #include "gettext.h" -#include "lastfiles.h" +#include "session.h" #include "LColor.h" #include "lyxlex.h" #include "lyxfont.h" @@ -104,7 +104,8 @@ { "\\language_global_options", LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS }, { "\\language_package", LyXRC::RC_LANGUAGE_PACKAGE }, { "\\language_use_babel", LyXRC::RC_LANGUAGE_USE_BABEL }, - { "\\lastfiles", LyXRC::RC_LASTFILES }, + { "\\use_lastfilepos", LyXRC::RC_USELASTFILEPOS }, + { "\\load_session", LyXRC::RC_LOADSESSION }, { "\\make_backup", LyXRC::RC_MAKE_BACKUP }, { "\\mark_foreign_language", LyXRC::RC_MARK_FOREIGN_LANGUAGE }, { "\\num_lastfiles", LyXRC::RC_NUMLASTFILES }, @@ -246,6 +247,8 @@ ascii_linelen = 65; num_lastfiles = maxlastfiles; check_lastfiles = true; + use_lastfilepos = true; + load_session = true; make_backup = true; backupdir_path.erase(); display_graphics = lyx::graphics::ColorDisplay; @@ -717,12 +720,18 @@ } break; - case RC_LASTFILES: + case RC_USELASTFILEPOS: if (lexrc.next()) { - lastfiles = ExpandPath(os::internal_path(lexrc.getString())); + use_lastfilepos = lexrc.getBool(); } break; + case RC_LOADSESSION: + if (lexrc.next()) { + load_session = lexrc.getBool(); + } + break; + case RC_NUMLASTFILES: if (lexrc.next()) { num_lastfiles = lexrc.getInteger(); @@ -1741,12 +1750,18 @@ string const path = os::external_path(document_path); os << "\\document_path \"" << path << "\"\n"; } - case RC_LASTFILES: + case RC_USELASTFILEPOS: if (ignore_system_lyxrc || - lastfiles != system_lyxrc.lastfiles) { - string const path = os::external_path(lastfiles); - os << "\\lastfiles \"" << path << "\"\n"; + use_lastfilepos != system_lyxrc.use_lastfilepos) { + os << "\\use_session " << convert<string>(use_lastfilepos) + << '\n'; } + case RC_LOADSESSION: + if (ignore_system_lyxrc || + load_session != system_lyxrc.load_session) { + os << "\\load_session " << convert<string>(load_session) + << "\n"; + } case RC_NUMLASTFILES: if (ignore_system_lyxrc || num_lastfiles != system_lyxrc.num_lastfiles) { @@ -2225,10 +2240,14 @@ str = _("De-select if you don't want babel to be used when the language of the document is the default language."); break; - case RC_LASTFILES: - str = _("The file where the last-files information should be stored."); + case RC_USELASTFILEPOS: + str = _("De-select if you do not want LyX to scroll to saved position."); break; + case RC_LOADSESSION: + str = _("De-select to prevent loading files opened from the last lyx session."); + break; + case RC_MAKE_BACKUP: str = _("De-select if you don't want LyX to create backup files."); break; Index: src/BufferView.C =================================================================== --- src/BufferView.C (revision 13495) +++ src/BufferView.C (working copy) @@ -188,6 +188,10 @@ return pimpl_->isSavedPosition(i); } +void BufferView::saveSavedPositions() +{ + return pimpl_->saveSavedPositions(); +} void BufferView::switchKeyMap() { Index: src/lyxrc.h =================================================================== --- src/lyxrc.h (revision 13495) +++ src/lyxrc.h (working copy) @@ -75,7 +75,8 @@ RC_LANGUAGE_GLOBAL_OPTIONS, RC_LANGUAGE_PACKAGE, RC_LANGUAGE_USE_BABEL, - RC_LASTFILES, + RC_USELASTFILEPOS, + RC_LOADSESSION, RC_MAKE_BACKUP, RC_MARK_FOREIGN_LANGUAGE, RC_NUMLASTFILES, @@ -227,10 +228,12 @@ bool auto_reset_options; /// bool check_lastfiles; - /// filename for lastfiles file - std::string lastfiles; /// maximal number of lastfiles unsigned int num_lastfiles; + /// whether or not go to saved position when opening a file + bool use_lastfilepos; + /// load files from last session automatically + bool load_session; /// shall a backup file be created bool make_backup; /// A directory for storing backup files Index: src/MenuBackend.C =================================================================== --- src/MenuBackend.C (revision 13495) +++ src/MenuBackend.C (working copy) @@ -30,7 +30,7 @@ #include "gettext.h" #include "importer.h" #include "kbmap.h" -#include "lastfiles.h" +#include "session.h" #include "LyXAction.h" #include "lyx_main.h" // for lastfiles #include "lyxfunc.h" @@ -428,13 +428,12 @@ void expandLastfiles(Menu & tomenu, LyXView const * view) { - LastFiles const & lastfiles = LyX::cref().lastfiles(); + lyx::Session::LastFiles const & lf = LyX::cref().session().lastFiles(); + lyx::Session::LastFiles::const_iterator lfit = lf.begin(); int ii = 1; - LastFiles::const_iterator lfit = lastfiles.begin(); - LastFiles::const_iterator end = lastfiles.end(); - for (; lfit != end && ii < 10; ++lfit, ++ii) { + for (; lfit != lf.end() && ii < 10; ++lfit, ++ii) { string const label = convert<string>(ii) + ". " + MakeDisplayPath((*lfit), 30) + '|' + convert<string>(ii); Index: src/BufferView.h =================================================================== --- src/BufferView.h (revision 13495) +++ src/BufferView.h (working copy) @@ -120,6 +120,8 @@ void restorePosition(unsigned int i); /// does the given bookmark have a saved position ? bool isSavedPosition(unsigned int i); + /// save bookmarks to .lyx/session + void saveSavedPositions(); /// return the current change at the cursor Change const getCurrentChange(); Index: src/lyx_main.C =================================================================== --- src/lyx_main.C (revision 13495) +++ src/lyx_main.C (working copy) @@ -28,7 +28,7 @@ #include "gettext.h" #include "kbmap.h" #include "language.h" -#include "lastfiles.h" +#include "session.h" #include "LColor.h" #include "lyxfunc.h" #include "lyxlex.h" @@ -163,17 +163,17 @@ {} -LastFiles & LyX::lastfiles() +lyx::Session & LyX::session() { - BOOST_ASSERT(lastfiles_.get()); - return *lastfiles_.get(); + BOOST_ASSERT(session_.get()); + return *session_.get(); } -LastFiles const & LyX::lastfiles() const +lyx::Session const & LyX::session() const { - BOOST_ASSERT(lastfiles_.get()); - return *lastfiles_.get(); + BOOST_ASSERT(session_.get()); + return *session_.get(); } @@ -238,6 +238,14 @@ if (first_start) files.push_back(i18nLibFileSearch("examples", "splash.lyx")); + // if a file is specified, I assume that user wants to edit *that* file + if (files.empty() && lyxrc.load_session) { + vector<string> const & lastopened = session_->lastOpenedFiles(); + files.insert(files.end(), lastopened.begin(), lastopened.end() ); + // clear this list to save a few bytes of RAM + session_->clearLastOpenedFiles(); + } + // Execute batch commands if available if (!batch_command.empty()) { @@ -425,10 +433,6 @@ "templates"); } - if (lyxrc.lastfiles.empty()) { - lyxrc.lastfiles = AddName(package().user_support(), "lastfiles"); - } - if (lyxrc.roman_font_name.empty()) lyxrc.roman_font_name = lyx_gui::roman_font_name(); if (lyxrc.sans_font_name.empty()) @@ -513,11 +517,8 @@ lyxerr << "LyX tmp dir: `" << package().temp_dir() << '\'' << endl; } - lyxerr[Debug::INIT] << "Reading lastfiles `" - << lyxrc.lastfiles << "'..." << endl; - lastfiles_.reset(new LastFiles(lyxrc.lastfiles, - lyxrc.check_lastfiles, - lyxrc.num_lastfiles)); + lyxerr[Debug::INIT] << "Reading session information '.lyx/session'..." << endl; + session_.reset(new lyx::Session(lyxrc.num_lastfiles)); } Index: src/lyx_main.h =================================================================== --- src/lyx_main.h (revision 13495) +++ src/lyx_main.h (working copy) @@ -24,9 +24,11 @@ class Buffer; class ErrorItem; class InsetBase; -class LastFiles; class LyXView; class kb_keymap; +namespace lyx { + class Session; +} /// initial startup @@ -39,8 +41,8 @@ /// in the case of failure void emergencyCleanup() const; - LastFiles & lastfiles(); - LastFiles const & lastfiles() const; + lyx::Session & session(); + lyx::Session const & session() const; void addLyXView(boost::shared_ptr<LyXView> const & lyxview); @@ -86,8 +88,8 @@ /// the parsed command line batch command if any std::string batch_command; - /// last files loaded - boost::scoped_ptr<LastFiles> lastfiles_; + /// lyx session, containing lastfiles, lastfilepos, and lastopened + boost::scoped_ptr<lyx::Session> session_; /// typedef std::list<boost::shared_ptr<LyXView> > ViewList; ViewList views_;