home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / lyx-0.13.2.tar.gz / lyx-0.13.2.tar / lyx-0.13.2 / src / bufferlist.C < prev    next >
C/C++ Source or Header  |  1998-04-23  |  15KB  |  662 lines

  1. /* This file is part of
  2.  * ======================================================
  3.  * 
  4.  *           LyX, The Document Word Processor
  5.  *
  6.  *        Copyright (C) 1995 Matthias Ettrich
  7.  *          Copyright (C) 1995-1998 The LyX Team. 
  8.  *
  9.  *           This file is Copyleft (C) 1996-1998
  10.  *           Lars Gullik Bj°nnes
  11.  *
  12.  *======================================================
  13.  */
  14.  
  15. #ifdef __GNUG__
  16. #pragma implementation
  17. #endif
  18.  
  19. #include <config.h>
  20. #include <sys/types.h>
  21. #include <utime.h>
  22. #include "bufferlist.h"
  23. #include "lyx_main.h"
  24. #include "minibuffer.h"
  25. #include "FileInfo.h"
  26. #include "filetools.h"
  27. #include "lyx_gui_misc.h"
  28. #include "lastfiles.h"
  29. #include "LyXView.h"
  30. #include "BufferView.h"
  31. #include "error.h"
  32. #include "lyxrc.h"
  33. #include "lyxscreen.h"
  34. #include "lyxtext.h"
  35. #include "lyx_cb.h"
  36. #include "gettext.h"
  37.  
  38. //     $Id: bufferlist.C,v 1.1.1.1 1998/04/23 16:02:48 larsbj Exp $    
  39.  
  40. #if !defined(lint) && !defined(WITH_WARNINGS)
  41. static char vcid[] = "$Id: bufferlist.C,v 1.1.1.1 1998/04/23 16:02:48 larsbj Exp $";
  42. #endif /* lint */
  43.  
  44. extern BufferView *current_view;
  45. extern MiniBuffer *minibuffer;
  46. extern void SmallUpdate(signed char);
  47. extern void BeforeChange();
  48. extern int RunLinuxDoc(int, LString const &);
  49.  
  50. //
  51. // Class BufferStorage
  52. //
  53.  
  54. BufferStorage::BufferStorage()
  55. {
  56.     // Initialize the buffer array
  57.     for (int i=NUMBER_OF_BUFFERS-1; i >=0; i--) {
  58.         buffer[i] = 0;
  59.     }    
  60. }
  61.  
  62.  
  63. bool BufferStorage::isEmpty()
  64. {
  65.     for (int i=NUMBER_OF_BUFFERS-1; i >=0; i--) {
  66.         if (buffer[i]) return false;
  67.     }
  68.     return true;
  69. }
  70.  
  71.  
  72. void BufferStorage::release(Buffer* buf)
  73. {
  74.     int i=0;
  75.     for (i=0; i<NUMBER_OF_BUFFERS; i++)
  76.         if (buffer[i] == buf) break;
  77.     Buffer *tmpbuf = buffer[i];
  78.     buffer[i] = 0;
  79.     delete tmpbuf;
  80. }
  81.  
  82.  
  83. Buffer* BufferStorage::newBuffer(LString const &s,
  84.                  LyXRC *lyxrc,
  85.                  bool ronly)
  86. {
  87.     int i=0;
  88.     while (i < NUMBER_OF_BUFFERS - 1
  89.            && buffer[i]) i++;
  90.     buffer[i] = new Buffer(s, lyxrc, ronly);
  91.     buffer[i]->params.useClassDefaults();
  92.     lyxerr.debug(LString("Assigning to buffer ") + i, Error::ANY);
  93.     return buffer[i];
  94. }
  95.  
  96.  
  97. //
  98. // Class BufferStrorage_Iter
  99. //
  100.  
  101. Buffer* BufferStorage_Iter::operator() ()
  102. {
  103.     int i=0;
  104.     for (i=index; i < BufferStorage::NUMBER_OF_BUFFERS; i++) {
  105.         if (cs->buffer[i]) {
  106.             index = i+1;
  107.             return cs->buffer[i];
  108.         }
  109.     }
  110.     return 0;    
  111. }
  112.  
  113.  
  114. Buffer* BufferStorage_Iter::operator[] (int a)
  115. {
  116.     // a is >=1
  117.     if (a<=0) return 0;
  118.     
  119.     int i=0;
  120.     while (a--) {
  121.         while(!cs->buffer[i++]);
  122.     }
  123.     if (i-1 < BufferStorage::NUMBER_OF_BUFFERS)
  124.         return cs->buffer[i-1];
  125.     return 0;    
  126. }
  127.  
  128.  
  129. //
  130. // Class BufferList
  131. //
  132. BufferList::BufferList()
  133. {
  134.     _state = BufferList::OK;
  135. }
  136.  
  137.  
  138. BufferList::~BufferList()
  139. {
  140.     // I am sure something should be done here too.
  141. }
  142.  
  143.  
  144. bool BufferList::isEmpty()
  145. {
  146.     return bstore.isEmpty();
  147. }
  148.  
  149. extern void MenuWrite(Buffer*);
  150.  
  151. bool BufferList::QwriteAll()
  152. {
  153.         bool askMoreConfirmation = false;
  154.         LString unsaved;
  155.     BufferStorage_Iter biter(bstore);
  156.     Buffer *b=0;
  157.     while ((b=biter())) {
  158.         if (!b->isLyxClean()) {
  159.             switch(AskConfirmation(_("Changes in document:"),
  160.                            MakeDisplayPath(b->filename,50),
  161.                            _("Save document?"))) {
  162.             case 1: // Yes
  163.                 MenuWrite(b);
  164.                 break;
  165.             case 2: // No
  166.                 askMoreConfirmation = true;
  167.                 unsaved += MakeDisplayPath(b->filename,50);
  168.                 unsaved += "\n";
  169.                                 break;
  170.             case 3: // Cancel
  171.                 return false;
  172.             }
  173.         }
  174.     }
  175.         if (askMoreConfirmation &&
  176.             lyxrc->exit_confirmation &&
  177.             !AskQuestion(_("Some documents were not saved:"),
  178.                          unsaved, _("Exit anyway?"))) {
  179.                 return false;
  180.         }
  181.  
  182.         return true;
  183. }
  184.  
  185.  
  186. // Should probably be moved to somewhere else: BufferView? LyXView?
  187. bool BufferList::write(Buffer *buf, bool makeBackup)
  188. {
  189.     minibuffer->Set(_("Saving document"),
  190.             MakeDisplayPath(buf->filename),"...");
  191.  
  192.     // We don't need autosaves in the immediate future. (Asger)
  193.     buf->resetAutosaveTimers();
  194.  
  195.     // make a backup
  196.     if (makeBackup) {
  197.         LString s = buf->filename + '~';
  198.         // Rename is the wrong way of making a backup,
  199.         // this is the correct way.
  200.         /* truss cp fil fil2:
  201.            lstat("LyXVC3.lyx", 0xEFFFF898)                 Err#2 ENOENT
  202.            stat("LyXVC.lyx", 0xEFFFF688)                   = 0
  203.            open("LyXVC.lyx", O_RDONLY)                     = 3
  204.            open("LyXVC3.lyx", O_WRONLY|O_CREAT|O_TRUNC, 0600) = 4
  205.            fstat(4, 0xEFFFF508)                            = 0
  206.            fstat(3, 0xEFFFF508)                            = 0
  207.            read(3, " # T h i s   f i l e   w".., 8192)     = 5579
  208.            write(4, " # T h i s   f i l e   w".., 5579)    = 5579
  209.            read(3, 0xEFFFD4A0, 8192)                       = 0
  210.            close(4)                                        = 0
  211.            close(3)                                        = 0
  212.            chmod("LyXVC3.lyx", 0100644)                    = 0
  213.            lseek(0, 0, SEEK_CUR)                           = 46440
  214.            _exit(0)
  215.          */
  216.  
  217.         // Should proabaly have some more error checking here.
  218.         // Should be cleaned up in 0.13, at least a bit.
  219.         // Doing it this way, also makes the inodes stay the same.
  220.         // This is still not a very good solution, in particular we
  221.         // might loose the owner of the backup.
  222.         FileInfo finfo(buf->filename);
  223.         if (finfo.exist()) {
  224.             mode_t fmode = finfo.getMode();
  225.  
  226.             struct utimbuf *times =
  227.                 (struct utimbuf*)new char[sizeof(struct utimbuf)];
  228.             times->actime = finfo.getAccessTime();
  229.             times->modtime = finfo.getModificationTime();
  230.             long blksize = finfo.getBlockSize();
  231.             lyxerr.debug(LString("BlockSize: ") + int(blksize));
  232.             FilePtr fin(buf->filename,FilePtr::read);
  233.             FilePtr fout(s,FilePtr::truncate);
  234.             if (fin() && fout()) {
  235.                 char * cbuf = new char[blksize+1];
  236.                 size_t c_read = 0;
  237.                 size_t c_write = 0;
  238.                 do {
  239.                     c_read = fread(cbuf, 1, blksize, fin);
  240.                     if (c_read != 0)
  241.                         c_write =
  242.                             fwrite(cbuf, 1, c_read, fout);
  243.                 } while (c_read);
  244.                 fin.close();
  245.                 fout.close();
  246.                 chmod(s.c_str(), fmode);
  247.                 
  248.                 if (utime(s.c_str(), times)) {
  249.                     lyxerr.print("utime error.");
  250.                 }
  251.                 delete [] cbuf;
  252.             } else {
  253.                 lyxerr.print("LyX was not able to make backupcopy. Beware.");
  254.             }
  255.             delete[] times;
  256.         }
  257.     }
  258.     
  259.     if (buf->writeFile(buf->filename,false)) {
  260.         buf->markLyxClean();
  261.  
  262.         minibuffer->Set(_("Document saved as"),
  263.                 MakeDisplayPath(buf->filename));
  264.  
  265.         // now delete the autosavefile
  266.         LString a = OnlyPath(buf->filename);
  267.         a += '#';
  268.         a += OnlyFilename(buf->filename);
  269.         a += '#';
  270.         FileInfo fileinfo(a);
  271.         if (fileinfo.exist()) {
  272.             if (remove(a.c_str()) != 0) {
  273.                 WriteFSAlert(_("Could not delete "
  274.                            "auto-save file!"), a);
  275.             }
  276.         }
  277.     } else {
  278.         // Saving failed, so backup is not backup
  279.         if (makeBackup) {
  280.             LString s = buf->filename + '~';
  281.             rename(s.c_str(), buf->filename.c_str());
  282.         }
  283.         minibuffer->Set(_("Save failed!"));
  284.         return false;
  285.     }
  286.  
  287.     return true;
  288. }
  289.  
  290.  
  291. void BufferList::closeAll()
  292. {
  293.     _state = BufferList::CLOSING;
  294.     
  295.     BufferStorage_Iter biter(bstore);
  296.     Buffer *b=0;
  297.     while ((b=biter())) {
  298.         close(b);
  299.     }
  300.     _state = BufferList::OK;
  301. }
  302.  
  303.  
  304. void BufferList::resize()
  305. {
  306.     BufferStorage_Iter biter(bstore);
  307.     Buffer *b=0;
  308.     while ((b=biter())) {
  309.         b->resize();
  310.     }
  311. }
  312.  
  313.  
  314. bool BufferList::close(Buffer *buf)
  315. {
  316.         buf->InsetUnlock();
  317.     
  318.     if (buf->paragraph && !buf->isLyxClean() && !quitting) {
  319.         ProhibitInput();
  320.                 switch(AskConfirmation(_("Changes in document:"),
  321.                               MakeDisplayPath(buf->filename,50),
  322.                                       _("Save document?"))){
  323.         case 1: // Yes
  324.             if (write(buf)) {
  325.                 lastfiles->newFile(buf->filename);
  326.             } else {
  327.                 AllowInput();
  328.                 return false;
  329.             }
  330.                         break;
  331.         case 3: // Cancel
  332.                         AllowInput();
  333.                         return false;
  334.                 }
  335.         AllowInput();
  336.     }
  337.  
  338.     bstore.release(buf);
  339.     return true;
  340. }
  341.  
  342.  
  343. void BufferList::makePup(int pup)
  344.     /* This should be changed to return a char const *const
  345.        in the same way as for lastfiles.[hC]
  346.        */
  347. {
  348.     int ant=0;
  349.     BufferStorage_Iter biter(bstore);
  350.     Buffer *b=0;
  351.     while ((b=biter())) {
  352.         LString relbuf = MakeDisplayPath(b->filename,30);
  353.         fl_addtopup(pup, relbuf.c_str());
  354.         ant++;
  355.     }
  356.     if (ant == 0) fl_addtopup(pup,_("No Documents Open!%t"));
  357. }
  358.  
  359.  
  360. Buffer* BufferList::first()
  361. {
  362.     BufferStorage_Iter biter(bstore);
  363.     return biter();
  364. }
  365.  
  366.  
  367. Buffer* BufferList::getBuffer(int choice)
  368. {
  369.     BufferStorage_Iter biter(bstore);
  370.     Buffer *b=0;
  371.     b = biter[choice];
  372.         
  373.     // Be careful, this could be 0.    
  374.     return b;
  375. }
  376.  
  377.  
  378. void BufferList::updateInset(Inset *inset, bool mark_dirty)
  379. {
  380.     BufferStorage_Iter biter(bstore);
  381.     Buffer *b=0;
  382.     while ((b=biter())) {
  383.         if (b->text && b->text->UpdateInset(inset)) {
  384.             if (mark_dirty)
  385.                 b->markDirty();
  386.             break;
  387.         }
  388.     }
  389. }
  390.  
  391.  
  392. int BufferList::unlockInset(UpdatableInset *inset)
  393. {
  394.     if (!inset) return 1;
  395.     
  396.     BufferStorage_Iter biter(bstore);
  397.     Buffer *b=0;
  398.     while ((b=biter())) {
  399.         if (b->the_locking_inset == inset) {
  400.             b->InsetUnlock();
  401.             return 0;
  402.         }
  403.     }
  404.     return 1;
  405. }
  406.  
  407.  
  408. void BufferList::updateIncludedTeXfiles(LString const & mastertmpdir)
  409. {
  410.     BufferStorage_Iter biter(bstore);
  411.     Buffer *b=0;
  412.     while ((b=biter())) {
  413.         if (!b->isDepClean(mastertmpdir)) {
  414.             LString writefile = mastertmpdir;
  415.             writefile += '/';
  416.             writefile += ChangeExtension(b->getFileName(), ".tex", true);
  417.             b->makeLaTeXFile(writefile,mastertmpdir,false,true);
  418.             b->markDepClean(mastertmpdir);
  419.         }
  420.     }
  421. }
  422.  
  423.  
  424. void BufferList::emergencyWriteAll()
  425. {
  426.     BufferStorage_Iter biter(bstore);
  427.     Buffer *b=0;
  428.     while ((b=biter())) {
  429.         if (!b->isLyxClean()) {
  430.             bool madeit=false;
  431.             
  432.             lyxerr.print(_("lyx: Attempting to save"
  433.                       " document ")
  434.                       + b->filename
  435.                       + _(" as..."));
  436.             
  437.             for (int i=0; i<3 && !madeit; i++) {
  438.                 LString s;
  439.                 
  440.                 // We try to save three places:
  441.                 // 1) Same place as document.
  442.                 // 2) In HOME directory.
  443.                 // 3) In "/tmp" directory.
  444.                 if (i==0) {
  445.                     s = b->filename;
  446.                 } else if (i==1) {
  447.                     s = AddName(getEnvPath("HOME"),
  448.                             b->filename);
  449.                 } else { // MakeAbsPath to prepend the current drive letter on OS/2
  450.                     s = AddName(MakeAbsPath("/tmp/"),
  451.                             b->filename);
  452.                 }
  453.                 s += ".emergency";
  454.                 
  455.                 lyxerr.print(LString("  ") + (i+1) + ") " + s);
  456.                 
  457.                 if (b->writeFile(s,true)) {
  458.                     b->markLyxClean();
  459.                     lyxerr.print(_("  Save seems succesful. Phew."));
  460.                     madeit = true;
  461.                 } else if (i != 2) {
  462.                     lyxerr.print(_("  Save failed! Trying..."));
  463.                 } else {
  464.                     lyxerr.print(_("  Save failed! Bummer. Document is lost."));
  465.                 }
  466.             }
  467.         }
  468.     }
  469. }
  470.  
  471.  
  472. Buffer* BufferList::readFile(LString const & s, bool ronly)
  473. {
  474.     Buffer *b = bstore.newBuffer(s, lyxrc, ronly);
  475.  
  476.     LString ts = s;
  477.     LString e = OnlyPath(s);
  478.     LString a = e;
  479.     // File information about normal file
  480.     FileInfo fileInfo2(s);
  481.  
  482.     // Check if emergency save file exists and is newer.
  483.     e += OnlyFilename(s) + ".emergency";
  484.     FileInfo fileInfoE(e);
  485.  
  486.     bool use_emergency = false;
  487.  
  488.     if (fileInfoE.exist() && fileInfo2.exist()) {
  489.         if (fileInfoE.getModificationTime()
  490.             > fileInfo2.getModificationTime()) {
  491.             if (AskQuestion(_("An emergency save of this document exists!"),
  492.                     MakeDisplayPath(s,50),
  493.                     _("Try to load that instead?"))) {
  494.                 ts = e;
  495.                 // the file is not saved if we load the
  496.                 // emergency file.
  497.                 b->markDirty();
  498.                 use_emergency = true;
  499.             }
  500.         }
  501.     }
  502.  
  503.     if (!use_emergency) {
  504.         // Now check if autosave file is newer.
  505.         a += '#';
  506.         a += OnlyFilename(s);
  507.         a += '#';
  508.         FileInfo fileInfoA(a);
  509.         if (fileInfoA.exist() && fileInfo2.exist()) {
  510.             if (fileInfoA.getModificationTime()
  511.                 > fileInfo2.getModificationTime()) {
  512.                 if (AskQuestion(_("Autosave file is newer."),
  513.                         MakeDisplayPath(s,50),
  514.                         _("Load that one instead?"))) {
  515.                     ts = a;
  516.                     // the file is not saved if we load the
  517.                     // autosave file.
  518.                     b->markDirty();
  519.                 }
  520.             }
  521.         }
  522.     }
  523.     // not sure if this is the correct place to begin LyXLex
  524.     LyXLex lex(NULL, 0);
  525.     lex.setFile(ts);
  526.     if (b->readFile(lex))
  527.         return b;
  528.     else {
  529.         bstore.release(b);
  530.         return 0;
  531.     }
  532. }
  533.  
  534.  
  535. bool BufferList::exists(LString const & s)
  536. {
  537.     BufferStorage_Iter biter(bstore);
  538.     Buffer *b=0;
  539.     while ((b=biter())) {
  540.         if (b->filename == s)
  541.             return true;
  542.     }
  543.     return false;
  544. }
  545.  
  546.  
  547. Buffer* BufferList::getBuffer(LString const &s)
  548. {
  549.     BufferStorage_Iter biter(bstore);
  550.     Buffer *b=0;
  551.     while ((b=biter())) {
  552.         if (b->filename ==s)
  553.             return b;
  554.     }
  555.     return 0;
  556. }
  557.  
  558.  
  559. Buffer* BufferList::newFile(LString const & name, LString tname)
  560. {
  561.     /* get a free buffer */ 
  562.     Buffer *b = bstore.newBuffer(name, lyxrc);
  563.  
  564.     // use defaults.lyx as a default template if it exists.
  565.     if (tname.empty()) {
  566.         tname = LibFileSearch("templates", "defaults.lyx");
  567.     }
  568.     if (!tname.empty() && IsLyXFilename(tname)){
  569.         bool templateok = false;
  570.         LyXLex lex(NULL,0);
  571.         lex.setFile(tname);
  572.         if (lex.IsOK()) {
  573.             if (b->readFile(lex)) {
  574.                 templateok = true;
  575.             }
  576.         }
  577.         if (!templateok) {
  578.             WriteAlert(_("Error!"),_("Unable to open template"), 
  579.                    MakeDisplayPath(tname));
  580.             // no template, start with empty buffer
  581.             b->paragraph = new LyXParagraph();
  582.         }
  583.     }
  584.     else {  // start with empty buffer
  585.         b->paragraph = new LyXParagraph();
  586.     }
  587.  
  588.     b->markDirty();
  589.     b->setReadonly(false);
  590.     
  591.     return b;
  592. }
  593.  
  594.  
  595. Buffer* BufferList::loadLyXFile(LString const & filename, bool tolastfiles)
  596. {
  597.     // make sure our path is absolute
  598.     LString s = MakeAbsPath(filename);
  599.     
  600.     // Is it LinuxDoc?
  601.     if (IsSGMLFilename(s)) {
  602.         if (!RunLinuxDoc(-1, s)) {
  603.             s = ChangeExtension (s, ".lyx", false);
  604.         }
  605.         else { // sgml2lyx failed
  606.             WriteAlert(_("Error!"),
  607.                    _("Could not convert file"),s);
  608.             return 0;
  609.         }
  610.     }
  611.  
  612.     // file already open?
  613.     if (exists(s)) {
  614.         if (AskQuestion(_("Document is already open:"), 
  615.                 MakeDisplayPath(s,50),
  616.                 _("Do you want to reload that document?"))) {
  617.             // Reload is accomplished by closing and then loading
  618.             if (!close(getBuffer(s))) {
  619.                 return 0;
  620.             }
  621.             // Fall through to new load. (Asger)
  622.         } else {
  623.             return 0;
  624.         }
  625.     }
  626.     Buffer *b=0;
  627.     bool ro = false;
  628.     switch (IsFileWriteable(s)) {
  629.     case 0:
  630.         minibuffer->Set(_("File `")+MakeDisplayPath(s,50)+
  631.                 _("' is read-only."));
  632.         ro = true;
  633.         // Fall through
  634.     case 1:
  635.         b=readFile(s, ro);
  636.         if (b) {
  637.             b->lyxvc.file_found_hook(s);
  638.         }
  639.         break; //fine- it's r/w
  640.     case -1:
  641.         // Here we probably should run
  642.         if (LyXVC::file_not_found_hook(s)) {
  643.             // Ask if the file should be checked out for
  644.             // viewing/editing, if so: load it.
  645.             lyxerr.print("Do you want to checkout?");
  646.         }
  647.         if (AskQuestion(_("Cannot open specified file:"), 
  648.                 MakeDisplayPath(s,50),
  649.                 _("Create new document with this name?")))
  650.             {
  651.             // Find a free buffer
  652.             b=newFile(s,LString());
  653.             }
  654.         break;
  655.     }
  656.  
  657.     if (b && tolastfiles)
  658.         lastfiles->newFile(b->getFileName());
  659.  
  660.     return b;
  661. }
  662.