X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Fbufferlist.C;h=3f4477636478f3fe8f20590692be00d5112c1ee7;hb=e72ef278b8c4b4bc1b0009cb00a1a56c7b02d2e8;hp=fdfc33a96fecf9c39edc7458cf8bdab887ade94b;hpb=4ed68c1bc2007d6505cc2d82c66494f63d9de107;p=lyx.git diff --git a/src/bufferlist.C b/src/bufferlist.C index fdfc33a96f..3f44776364 100644 --- a/src/bufferlist.C +++ b/src/bufferlist.C @@ -3,10 +3,10 @@ * * LyX, The Document Word Processor * - * Copyright 1995 Matthias Ettrich - * Copyright 1995-1999 The LyX Team. + * Copyright 1995 Matthias Ettrich + * Copyright 1995-2000 The LyX Team. * - * This file is Copyright 1996-1999 + * This file is Copyright 1996-2000 * Lars Gullik Bjønnes * * ====================================================== @@ -17,27 +17,37 @@ #endif #include -#include -#include + +#include +#include + #include "bufferlist.h" #include "lyx_main.h" #include "minibuffer.h" #include "support/FileInfo.h" #include "support/filetools.h" +#include "support/lyxmanip.h" +#include "support/lyxfunctional.h" #include "lyx_gui_misc.h" #include "lastfiles.h" #include "debug.h" #include "lyxrc.h" -#include "lyxscreen.h" #include "lyxtext.h" #include "lyx_cb.h" +#include "bufferview_funcs.h" #include "gettext.h" #include "LyXView.h" +#include "vc-backend.h" +#include "TextCache.h" + +using std::vector; +using std::find; +using std::endl; +using std::find_if; +using std::for_each; +using std::mem_fun; extern BufferView * current_view; -extern void SmallUpdate(signed char); -extern void BeforeChange(); -extern int RunLinuxDoc(int, string const &); // // Class BufferStorage @@ -45,26 +55,25 @@ extern int RunLinuxDoc(int, string const &); void BufferStorage::release(Buffer * buf) { - for(Container::iterator it = container.begin(); - it != container.end(); ++it) { - if ((*it) == buf) { - Buffer * tmpbuf = (*it); - container.erase(it); - delete tmpbuf; - break; - } + Container::iterator it = find(container.begin(), container.end(), buf); + if (it != container.end()) { + // Make sure that we don't store a LyXText in + // the textcache that points to the buffer + // we just deleted. + Buffer * tmp = (*it); + container.erase(it); + textcache.removeAllWithBuffer(tmp); + delete tmp; } } -Buffer * BufferStorage::newBuffer(string const & s, - LyXRC * lyxrc, - bool ronly) +Buffer * BufferStorage::newBuffer(string const & s, bool ronly) { - Buffer * tmpbuf = new Buffer(s, lyxrc, ronly); + Buffer * tmpbuf = new Buffer(s, ronly); tmpbuf->params.useClassDefaults(); - lyxerr.debug() << "Assigning to buffer " - << container.size() + 1 << endl; + lyxerr[Debug::INFO] << "Assigning to buffer " + << container.size() << endl; container.push_back(tmpbuf); return tmpbuf; } @@ -75,46 +84,60 @@ Buffer * BufferStorage::newBuffer(string const & s, // BufferList::BufferList() -{ - _state = BufferList::OK; -} + : state_(BufferList::OK) +{} -bool BufferList::empty() +bool BufferList::empty() const { return bstore.empty(); } -extern void MenuWrite(Buffer *); - bool BufferList::QwriteAll() { bool askMoreConfirmation = false; string unsaved; - for(BufferStorage::iterator it = bstore.begin(); + for (BufferStorage::iterator it = bstore.begin(); it != bstore.end(); ++it) { if (!(*it)->isLyxClean()) { - switch(AskConfirmation(_("Changes in document:"), - MakeDisplayPath((*it)->fileName(), - 50), - _("Save document?"))) { - case 1: // Yes - MenuWrite((*it)); - break; - case 2: // No - askMoreConfirmation = true; - unsaved += MakeDisplayPath((*it)->fileName(), - 50); - unsaved += "\n"; - break; - case 3: // Cancel - return false; + string fname; + if ((*it)->isUnnamed()) + fname = OnlyFilename((*it)->fileName()); + else + fname = MakeDisplayPath((*it)->fileName(), 50); + bool reask = true; + while (reask) { + switch (AskConfirmation(_("Changes in document:"), + fname, + _("Save document?"))) { + case 1: // Yes + if ((*it)->isUnnamed()) + reask = !MenuWriteAs(current_view, (*it)); + else { + reask = !MenuWrite(current_view, (*it)); + } + break; + case 2: // No + // if we crash after this we could + // have no autosave file but I guess + // this is really inprobable (Jug) + if ((*it)->isUnnamed()) { + removeAutosaveFile((*it)->fileName()); + } + askMoreConfirmation = true; + unsaved += MakeDisplayPath(fname, 50); + unsaved += "\n"; + reask = false; + break; + case 3: // Cancel + return false; + } } } } if (askMoreConfirmation && - lyxrc->exit_confirmation && + lyxrc.exit_confirmation && !AskQuestion(_("Some documents were not saved:"), unsaved, _("Exit anyway?"))) { return false; @@ -124,154 +147,72 @@ bool BufferList::QwriteAll() } -// Should probably be moved to somewhere else: BufferView? LyXView? -bool BufferList::write(Buffer * buf, bool makeBackup) -{ - current_view->owner()->getMiniBuffer()->Set(_("Saving document"), - MakeDisplayPath(buf->fileName()), "..."); - - // We don't need autosaves in the immediate future. (Asger) - buf->resetAutosaveTimers(); - - // make a backup - if (makeBackup) { - string s = buf->fileName() + '~'; - // Rename is the wrong way of making a backup, - // this is the correct way. - /* truss cp fil fil2: - lstat("LyXVC3.lyx", 0xEFFFF898) Err#2 ENOENT - stat("LyXVC.lyx", 0xEFFFF688) = 0 - open("LyXVC.lyx", O_RDONLY) = 3 - open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4 - fstat(4, 0xEFFFF508) = 0 - fstat(3, 0xEFFFF508) = 0 - read(3, " # T h i s f i l e w".., 8192) = 5579 - write(4, " # T h i s f i l e w".., 5579) = 5579 - read(3, 0xEFFFD4A0, 8192) = 0 - close(4) = 0 - close(3) = 0 - chmod("LyXVC3.lyx", 0100644) = 0 - lseek(0, 0, SEEK_CUR) = 46440 - _exit(0) - */ - - // Should proabaly have some more error checking here. - // Should be cleaned up in 0.13, at least a bit. - // Doing it this way, also makes the inodes stay the same. - // This is still not a very good solution, in particular we - // might loose the owner of the backup. - FileInfo finfo(buf->fileName()); - if (finfo.exist()) { - mode_t fmode = finfo.getMode(); - struct utimbuf * times = new struct utimbuf; - - times->actime = finfo.getAccessTime(); - times->modtime = finfo.getModificationTime(); - long blksize = finfo.getBlockSize(); - lyxerr.debug() << "BlockSize: " << blksize << endl; - FilePtr fin(buf->fileName(), FilePtr::read); - FilePtr fout(s, FilePtr::truncate); - if (fin() && fout()) { - char * cbuf = new char[blksize+1]; - size_t c_read = 0; - size_t c_write = 0; - do { - c_read = fread(cbuf, 1, blksize, fin); - if (c_read != 0) - c_write = - fwrite(cbuf, 1, - c_read, fout); - } while (c_read); - fin.close(); - fout.close(); - chmod(s.c_str(), fmode); - - if (utime(s.c_str(), times)) { - lyxerr << "utime error." << endl; - } - delete [] cbuf; - } else { - lyxerr << "LyX was not able to make " - "backupcopy. Beware." << endl; - } - delete[] times; - } - } - - if (buf->writeFile(buf->fileName(), false)) { - buf->markLyxClean(); - - current_view->owner()->getMiniBuffer()-> - Set(_("Document saved as"), - MakeDisplayPath(buf->fileName())); - - // now delete the autosavefile - string a = OnlyPath(buf->fileName()); - a += '#'; - a += OnlyFilename(buf->fileName()); - a += '#'; - FileInfo fileinfo(a); - if (fileinfo.exist()) { - if (remove(a.c_str()) != 0) { - WriteFSAlert(_("Could not delete " - "auto-save file!"), a); - } - } - } else { - // Saving failed, so backup is not backup - if (makeBackup) { - string s = buf->fileName() + '~'; - rename(s.c_str(), buf->fileName().c_str()); - } - current_view->owner()->getMiniBuffer()->Set(_("Save failed!")); - return false; - } - - return true; -} - - void BufferList::closeAll() { - _state = BufferList::CLOSING; + state_ = BufferList::CLOSING; + // Since we are closing we can just as well delete all + // in the textcache this will also speed the closing/quiting up a bit. + textcache.clear(); + while (!bstore.empty()) { close(bstore.front()); } - _state = BufferList::OK; + state_ = BufferList::OK; } void BufferList::resize() { - for(BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { - (*it)->resize(); - } + for_each(bstore.begin(), bstore.end(), mem_fun(&Buffer::resize)); } bool BufferList::close(Buffer * buf) { - buf->InsetUnlock(); + // CHECK + // Trace back why we need to use buf->getUser here. + // Perhaps slight rewrite is in order? (Lgb) + if (buf->getUser()) buf->getUser()->insetUnlock(); if (buf->paragraph && !buf->isLyxClean() && !quitting) { - ProhibitInput(); - switch(AskConfirmation(_("Changes in document:"), - MakeDisplayPath(buf->fileName(), 50), - _("Save document?"))){ - case 1: // Yes - if (write(buf)) { - lastfiles->newFile(buf->fileName()); - } else { - AllowInput(); + if (buf->getUser()) + ProhibitInput(buf->getUser()); + string fname; + if (buf->isUnnamed()) + fname = OnlyFilename(buf->fileName()); + else + fname = MakeDisplayPath(buf->fileName(), 50); + bool reask = true; + while (reask) { + switch (AskConfirmation(_("Changes in document:"), + fname, + _("Save document?"))){ + case 1: // Yes + if (buf->isUnnamed()) + reask = !MenuWriteAs(current_view, buf); + else if (buf->save()) { + lastfiles->newFile(buf->fileName()); + reask = false; + } else { + if (buf->getUser()) + AllowInput(buf->getUser()); + return false; + } + break; + case 2: + if (buf->isUnnamed()) { + removeAutosaveFile(buf->fileName()); + } + reask = false; + break; + case 3: // Cancel + if (buf->getUser()) + AllowInput(buf->getUser()); return false; } - break; - case 3: // Cancel - AllowInput(); - return false; - } - AllowInput(); + } + if (buf->getUser()) + AllowInput(buf->getUser()); } bstore.release(buf); @@ -279,19 +220,12 @@ bool BufferList::close(Buffer * buf) } -void BufferList::makePup(int pup) - /* This should be changed to return a char const *const - in the same way as for lastfiles.[hC] - */ +vector const BufferList::getFileNames() const { - int ant = 0; - for(BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { - string relbuf = MakeDisplayPath((*it)->fileName(), 30); - fl_addtopup(pup, relbuf.c_str()); - ++ant; - } - if (ant == 0) fl_addtopup(pup, _("No Documents Open!%t")); + vector nvec; + std::copy(bstore.begin(), bstore.end(), + back_inserter_fun(nvec, &Buffer::fileName)); + return nvec; } @@ -302,34 +236,21 @@ Buffer * BufferList::first() } -Buffer * BufferList::getBuffer(int choice) +Buffer * BufferList::getBuffer(unsigned int choice) { if (choice >= bstore.size()) return 0; return bstore[choice]; } -void BufferList::updateInset(Inset * inset, bool mark_dirty) +int BufferList::unlockInset(UpdatableInset * inset) { + if (!inset) return 1; for (BufferStorage::iterator it = bstore.begin(); it != bstore.end(); ++it) { if ((*it)->getUser() - && (*it)->getUser()->text->UpdateInset(inset)) { - if (mark_dirty) - (*it)->markDirty(); - break; - } - } -} - - -int BufferList::unlockInset(UpdatableInset * inset) -{ - if (!inset) return 1; - for(BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { - if ((*it)->the_locking_inset == inset) { - (*it)->InsetUnlock(); + && (*it)->getUser()->theLockingInset() == inset) { + (*it)->getUser()->insetUnlock(); return 0; } } @@ -339,13 +260,12 @@ int BufferList::unlockInset(UpdatableInset * inset) void BufferList::updateIncludedTeXfiles(string const & mastertmpdir) { - for(BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { + for (BufferStorage::iterator it = bstore.begin(); + it != bstore.end(); ++it) { if (!(*it)->isDepClean(mastertmpdir)) { string writefile = mastertmpdir; writefile += '/'; - writefile += ChangeExtension((*it)->fileName(), - ".tex", true); + writefile += (*it)->getLatexName(); (*it)->makeLaTeXFile(writefile, mastertmpdir, false, true); (*it)->markDepClean(mastertmpdir); @@ -356,60 +276,67 @@ void BufferList::updateIncludedTeXfiles(string const & mastertmpdir) void BufferList::emergencyWriteAll() { - for (BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { - if (!(*it)->isLyxClean()) { - bool madeit = false; - - lyxerr <<_("lyx: Attempting to save" - " document ") - << (*it)->fileName() - << _(" as...") << endl; - - for (int i = 0; i < 3 && !madeit; ++i) { - string s; - - // We try to save three places: - // 1) Same place as document. - // 2) In HOME directory. - // 3) In "/tmp" directory. - if (i == 0) { - s = (*it)->fileName(); - } else if (i == 1) { - s = AddName(GetEnvPath("HOME"), - (*it)->fileName()); - } else { - // MakeAbsPath to prepend the current - // drive letter on OS/2 - s = AddName(MakeAbsPath("/tmp/"), - (*it)->fileName()); - } - s += ".emergency"; - - lyxerr << " " << i + 1 << ") " << s << endl; - - if ((*it)->writeFile(s, true)) { - (*it)->markLyxClean(); - lyxerr << _(" Save seems successful. " - "Phew.") << endl; - madeit = true; - } else if (i != 2) { - lyxerr << _(" Save failed! Trying...") - << endl; - } else { - lyxerr << _(" Save failed! Bummer. " - "Document is lost.") - << endl; - } - } + for_each(bstore.begin(), bstore.end(), + class_fun(*this, &BufferList::emergencyWrite)); +} + + +void BufferList::emergencyWrite(Buffer * buf) +{ + // No need to save if the buffer has not changed. + if (buf->isLyxClean()) return; + + lyxerr << fmt(_("lyx: Attempting to save document %s as..."), + buf->isUnnamed() ? OnlyFilename(buf->fileName()).c_str() + : buf->fileName().c_str()) << endl; + + // We try to save three places: + + // 1) Same place as document. Unless it is an unnamed doc. + if (!buf->isUnnamed()) { + string s = buf->fileName(); + s += ".emergency"; + lyxerr << " " << s << endl; + if (buf->writeFile(s, true)) { + buf->markLyxClean(); + lyxerr << _(" Save seems successful. Phew.") << endl; + return; + } else { + lyxerr << _(" Save failed! Trying...") << endl; } } + + // 2) In HOME directory. + string s = AddName(GetEnvPath("HOME"), buf->fileName()); + s += ".emergency"; + lyxerr << " " << s << endl; + if (buf->writeFile(s, true)) { + buf->markLyxClean(); + lyxerr << _(" Save seems successful. Phew.") << endl; + return; + } + + lyxerr << _(" Save failed! Trying...") << endl; + + // 3) In "/tmp" directory. + // MakeAbsPath to prepend the current + // drive letter on OS/2 + s = AddName(MakeAbsPath("/tmp/"), buf->fileName()); + s += ".emergency"; + lyxerr << " " << s << endl; + if (buf->writeFile(s, true)) { + buf->markLyxClean(); + lyxerr << _(" Save seems successful. Phew.") << endl; + return; + } + lyxerr << _(" Save failed! Bummer. Document is lost.") << endl; } + Buffer * BufferList::readFile(string const & s, bool ronly) { - Buffer * b = bstore.newBuffer(s, lyxrc, ronly); + Buffer * b = bstore.newBuffer(s, ronly); string ts = s; string e = OnlyPath(s); @@ -436,7 +363,7 @@ Buffer * BufferList::readFile(string const & s, bool ronly) use_emergency = true; } else { // Here, we should delete the emergency save - unlink(e.c_str()); + lyx::unlink(e); } } } @@ -459,7 +386,7 @@ Buffer * BufferList::readFile(string const & s, bool ronly) b->markDirty(); } else { // Here, we should delete the autosave - unlink(a.c_str()); + lyx::unlink(a); } } } @@ -476,38 +403,40 @@ Buffer * BufferList::readFile(string const & s, bool ronly) } -bool BufferList::exists(string const & s) +bool BufferList::exists(string const & s) const { - for (BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { - if ((*it)->fileName() == s) - return true; - } - return false; + return find_if(bstore.begin(), bstore.end(), + compare_memfun(&Buffer::fileName, s)) != bstore.end(); +} + + +bool BufferList::isLoaded(Buffer const * b) const +{ + BufferStorage::const_iterator cit = + find(bstore.begin(), bstore.end(), b); + return cit != bstore.end(); } Buffer * BufferList::getBuffer(string const & s) { - for(BufferStorage::iterator it = bstore.begin(); - it != bstore.end(); ++it) { - if ((*it)->fileName() == s) - return (*it); - } - return 0; + BufferStorage::iterator it = + find_if(bstore.begin(), bstore.end(), + compare_memfun(&Buffer::fileName, s)); + return it != bstore.end() ? (*it) : 0; } -Buffer * BufferList::newFile(string const & name, string tname) +Buffer * BufferList::newFile(string const & name, string tname, bool isNamed) { - /* get a free buffer */ - Buffer * b = bstore.newBuffer(name, lyxrc); + // get a free buffer + Buffer * b = bstore.newBuffer(name); // use defaults.lyx as a default template if it exists. if (tname.empty()) { tname = LibFileSearch("templates", "defaults.lyx"); } - if (!tname.empty() && IsLyXFilename(tname)){ + if (!tname.empty() && IsLyXFilename(tname)) { bool templateok = false; LyXLex lex(0, 0); lex.setFile(tname); @@ -522,12 +451,15 @@ Buffer * BufferList::newFile(string const & name, string tname) // no template, start with empty buffer b->paragraph = new LyXParagraph; } - } - else { // start with empty buffer + } else { // start with empty buffer b->paragraph = new LyXParagraph; } - b->markDirty(); + if (!lyxrc.new_ask_filename && !isNamed) { + b->setUnnamed(); + b->setFileName(name); + } + b->setReadonly(false); return b; @@ -537,28 +469,8 @@ Buffer * BufferList::newFile(string const & name, string tname) Buffer * BufferList::loadLyXFile(string const & filename, bool tolastfiles) { // make sure our path is absolute - string s = MakeAbsPath(filename); - - // Is this done too early? - // Is it LinuxDoc? - if (IsSGMLFilename(s)) { - FileInfo fi(s); - if (fi.exist() && fi.readable()) { - if (!RunLinuxDoc(-1, s)) { - s = ChangeExtension (s, ".lyx", false); - } else { // sgml2lyx failed - WriteAlert(_("Error!"), - _("Could not convert file"), s); - return 0; - } - } else { - // just change the extension and it will be - // handled like a regular lyx file that does - // not exist. - s = ChangeExtension(s, ".lyx", false); - } - } - + string const s = MakeAbsPath(filename); + // file already open? if (exists(s)) { if (AskQuestion(_("Document is already open:"), @@ -579,9 +491,11 @@ Buffer * BufferList::loadLyXFile(string const & filename, bool tolastfiles) bool ro = false; switch (IsFileWriteable(s)) { case 0: +#if 0 current_view->owner()->getMiniBuffer()-> - Set(_("File `")+MakeDisplayPath(s, 50)+ - _("' is read-only.")); + Set(_("File `") + MakeDisplayPath(s, 50) + + _("' is read-only.")); +#endif ro = true; // Fall through case 1: @@ -595,14 +509,20 @@ Buffer * BufferList::loadLyXFile(string const & filename, bool tolastfiles) if (LyXVC::file_not_found_hook(s)) { // Ask if the file should be checked out for // viewing/editing, if so: load it. - lyxerr << "Do you want to checkout?" << endl; + if (AskQuestion(_("Do you want to retrieve file under version control?"))) { + // How can we know _how_ to do the checkout? + // With the current VC support it has to be, + // a RCS file since CVS do not have special ,v files. + RCS::retrive(s); + return loadLyXFile(filename, tolastfiles); + } } if (AskQuestion(_("Cannot open specified file:"), MakeDisplayPath(s, 50), _("Create new document with this name?"))) { // Find a free buffer - b = newFile(s, string()); + b = newFile(s, string(), true); } break; }