]> git.lyx.org Git - lyx.git/blobdiff - src/buffer.C
Fix natbib bug spotted by JMarc.
[lyx.git] / src / buffer.C
index 2197e6e9dfde884d3ea742afbfe3d35363e22cab..6a3c50a5d69ad9b8e3c3961b04405fe98a8279ba 100644 (file)
@@ -45,6 +45,7 @@
 #include "lyxtextclasslist.h"
 #include "sgml.h"
 #include "paragraph_funcs.h"
+#include "author.h"
 
 #include "frontends/LyXView.h"
 
@@ -97,6 +98,7 @@
 #include "support/FileInfo.h"
 #include "support/lyxmanip.h"
 #include "support/lyxalgo.h" // for lyx::count
+#include "support/lyxtime.h"
 
 #include <boost/bind.hpp>
 #include <boost/tuple/tuple.hpp>
@@ -148,13 +150,13 @@ extern BufferList bufferlist;
 
 namespace {
 
-const int LYX_FORMAT = 221;
+const int LYX_FORMAT = 222;
 
 } // namespace anon
 
 Buffer::Buffer(string const & file, bool ronly)
        : niceFile(true), lyx_clean(true), bak_clean(true),
-         unnamed(false), dep_clean(0), read_only(ronly),
+         unnamed(false), read_only(ronly),
          filename_(file), users(0)
 {
        lyxerr[Debug::INFO] << "Buffer::Buffer()" << endl;
@@ -165,6 +167,9 @@ Buffer::Buffer(string const & file, bool ronly)
        } else {
                tmppath.erase();
        }
+
+       // set initial author
+       authorlist.record(Author(lyxrc.user_name, lyxrc.user_email)); 
 }
 
 
@@ -245,6 +250,12 @@ void Buffer::setReadonly(bool flag)
 }
 
 
+AuthorList & Buffer::authors()
+{
+       return authorlist;
+}
+
+
 /// Update window titles of all users
 // Should work on a list
 void Buffer::updateTitles() const
@@ -282,6 +293,7 @@ string last_inset_read;
 #endif
 int unknown_layouts;
 int unknown_tokens;
+vector<int> author_ids;
 
 } // anon
 
@@ -293,11 +305,12 @@ int unknown_tokens;
 // changed to be public and have one parameter
 // if par = 0 normal behavior
 // else insert behavior
-// Returns false if "\the_end" is not read for formats >= 2.13. (Asger)
+// Returns false if "\the_end" is not read (Asger)
 bool Buffer::readLyXformat2(LyXLex & lex, Paragraph * par)
 {
        unknown_layouts = 0;
        unknown_tokens = 0;
+       author_ids.clear();
 
        int pos = 0;
        Paragraph::depth_type depth = 0;
@@ -390,6 +403,13 @@ bool Buffer::readLyXformat2(LyXLex & lex, Paragraph * par)
 }
 
 
+namespace {
+       // This stuff is, in the traditional LyX terminology, Super UGLY
+       // but this code is too b0rken to admit of a better solution yet
+       Change current_change;
+};
+
 bool
 Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
                                   Paragraph *& first_par,
@@ -408,7 +428,7 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
        if (token[0] != '\\') {
                for (string::const_iterator cit = token.begin();
                     cit != token.end(); ++cit) {
-                       par->insertChar(pos, (*cit), font);
+                       par->insertChar(pos, (*cit), font, current_change);
                        ++pos;
                }
        } else if (token == "\\layout") {
@@ -498,6 +518,8 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
                        else {
                                par = new Paragraph(par);
                                par->layout(params.getLyXTextClass().defaultLayout());
+                               if (params.tracking_changes)
+                                       par->trackChanges();
                        }
                        pos = 0;
                        par->layout(params.getLyXTextClass()[layoutname]);
@@ -576,9 +598,9 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
                                lex.next();
                                string const next_token = lex.getString();
                                if (next_token == "\\-") {
-                                       par->insertChar(pos, '-', font);
+                                       par->insertChar(pos, '-', font, current_change);
                                } else if (next_token == "~") {
-                                       par->insertChar(pos, ' ', font);
+                                       par->insertChar(pos, ' ', font, current_change);
                                } else {
                                        lex.printError("Token `$$Token' "
                                                       "is in free space "
@@ -589,16 +611,16 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
                } else {
                        Inset * inset = new InsetSpecialChar;
                        inset->read(this, lex);
-                       par->insertInset(pos, inset, font);
+                       par->insertInset(pos, inset, font, current_change);
                }
                ++pos;
        } else if (token == "\\i") {
                Inset * inset = new InsetLatexAccent;
                inset->read(this, lex);
-               par->insertInset(pos, inset, font);
+               par->insertInset(pos, inset, font, current_change);
                ++pos;
        } else if (token == "\\backslash") {
-               par->insertChar(pos, '\\', font);
+               par->insertChar(pos, '\\', font, current_change);
                ++pos;
        } else if (token == "\\begin_deeper") {
                ++depth;
@@ -621,13 +643,13 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
 #if USE_BOOST_FORMAT
                        Alert::alert(_("Textclass error"),
                                boost::io::str(boost::format(_("The document uses an unknown textclass \"%1$s\".")) % lex.getString()),
-                               _("LyX will not be able to produce output correctly."));
+                               _("-- substituting default."));
 #else
                        Alert::alert(
                                _("Textclass error"),
                                _("The document uses an unknown textclass ")
                                + lex.getString(),
-                               _("LyX will not be able to produce output correctly."));
+                               _("-- substituting default."));
 #endif
                        params.textclass = 0;
                }
@@ -641,12 +663,12 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
                        Alert::alert(_("Textclass Loading Error!"),
                                   boost::io::str(boost::format(_("Can't load textclass %1$s")) %
                                   params.getLyXTextClass().name()),
-                                  _("-- substituting default"));
+                                  _("-- substituting default."));
 #else
                        Alert::alert(_("Textclass Loading Error!"),
                                     _("Can't load textclass ")
                                     + params.getLyXTextClass().name(),
-                                    _("-- substituting default"));
+                                    _("-- substituting default."));
 #endif
                        params.textclass = 0;
                }
@@ -756,6 +778,21 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
        } else if (token == "\\use_numerical_citations") {
                lex.nextToken();
                params.use_numerical_citations = lex.getInteger();
+       } else if (token == "\\tracking_changes") {
+               lex.nextToken();
+               params.tracking_changes = lex.getInteger();
+               // mark the first paragraph
+               if (params.tracking_changes)
+                       par->trackChanges();
+       } else if (token == "\\author") {
+               lex.nextToken();
+               istringstream ss(lex.getString());
+               Author a;
+               ss >> a;
+               int aid(authorlist.record(a)); 
+               lyxerr << "aid is " << aid << endl;
+               lyxerr << "listed aid is " << author_ids.size() << endl;
+               author_ids.push_back(authorlist.record(a));
        } else if (token == "\\paperorientation") {
                int tmpret = lex.findToken(string_orientation);
                if (tmpret == -1)
@@ -929,16 +966,37 @@ Buffer::parseSingleLyXformat2Token(LyXLex & lex, Paragraph *& par,
                par->params().labelWidthString(lex.getString());
                // do not delete this token, it is still needed!
        } else if (token == "\\newline") {
-               par->insertChar(pos, Paragraph::META_NEWLINE, font);
+               par->insertChar(pos, Paragraph::META_NEWLINE, font, current_change);
                ++pos;
        } else if (token == "\\LyXTable") {
                Inset * inset = new InsetTabular(*this);
                inset->read(this, lex);
-               par->insertInset(pos, inset, font);
+               par->insertInset(pos, inset, font, current_change);
                ++pos;
        } else if (token == "\\hfill") {
-               par->insertChar(pos, Paragraph::META_HFILL, font);
+               par->insertChar(pos, Paragraph::META_HFILL, font, current_change);
                ++pos;
+       } else if (token == "\\change_unchanged") {
+               // Hack ! Needed for empty paragraphs :/
+               if (!pos)
+                       par->cleanChanges();
+               current_change = Change(Change::UNCHANGED);
+       } else if (token == "\\change_inserted") {
+               lex.nextToken();
+               istringstream istr(lex.getString());
+               int aid;
+               lyx::time_type ct;
+               istr >> aid;
+               istr >> ct;
+               current_change = Change(Change::INSERTED, author_ids[aid], ct);
+       } else if (token == "\\change_deleted") {
+               lex.nextToken();
+               istringstream istr(lex.getString());
+               int aid;
+               lyx::time_type ct;
+               istr >> aid;
+               istr >> ct;
+               current_change = Change(Change::DELETED, author_ids[aid], ct);
        } else if (token == "\\bibitem") {  // ale970302
                if (!par->bibkey) {
                        InsetCommandParams p("bibitem", "dummy");
@@ -1005,13 +1063,13 @@ void Buffer::insertStringAsLines(Paragraph *& par, pos_type & pos,
                } else if (*cit == '\t') {
                        if (!layout->free_spacing && !par->isFreeSpacing()) {
                                // tabs are like spaces here
-                               par->insertChar(pos, ' ', font);
+                               par->insertChar(pos, ' ', font, current_change);
                                ++pos;
                                space_inserted = true;
                        } else {
                                const pos_type nb = 8 - pos % 8;
                                for (pos_type a = 0; a < nb ; ++a) {
-                                       par->insertChar(pos, ' ', font);
+                                       par->insertChar(pos, ' ', font, current_change);
                                        ++pos;
                                }
                                space_inserted = true;
@@ -1155,7 +1213,7 @@ void Buffer::readInset(LyXLex & lex, Paragraph *& par,
        }
 
        if (inset) {
-               par->insertInset(pos, inset, font);
+               par->insertInset(pos, inset, font, current_change);
                ++pos;
        }
 }
@@ -1182,7 +1240,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, Paragraph * par)
                        } else if (file_format > LYX_FORMAT) {
                                // future format
                                Alert::alert(_("Warning!"),
-                                       _("The file was created with a newer version of"
+                                       _("The file was created with a newer version of "
                                        "LyX. This is likely to cause problems."));
 
                        } else if (file_format < LYX_FORMAT) {
@@ -1216,7 +1274,7 @@ bool Buffer::readFile(LyXLex & lex, string const & filename, Paragraph * par)
                                        istringstream is(STRCONV(ret.second));
                                        LyXLex tmplex(0, 0);
                                        tmplex.setStream(is);
-                                       return readFile(tmplex, string());
+                                       return readFile(tmplex, string(), par);
                                } else {
                                        // This code is reached if lyx2lyx failed (for
                                        // some reason) to change the file format of
@@ -1356,6 +1414,15 @@ bool Buffer::writeFile(string const & fname) const
        // now write out the buffer paramters.
        params.writeFile(ofs);
 
+       // if we're tracking, list all possible authors
+       if (params.tracking_changes) {
+               AuthorList::Authors::const_iterator it = authorlist.begin();
+               AuthorList::Authors::const_iterator end = authorlist.end();
+               for (; it != end; ++it) {
+                       ofs << "\\author " << it->second << "\n";
+               }
+       }
        Paragraph::depth_type depth = 0;
 
        // this will write out all the paragraphs
@@ -2096,6 +2163,15 @@ void Buffer::makeLaTeXFile(ostream & os,
 
                preamble += "\\makeatother\n";
 
+               // dvipost settings come after everything else
+               if (params.tracking_changes) {
+                       preamble += "\\dvipostlayout\n";
+                       preamble += "\\dvipost{osstart color push Red}\n";
+                       preamble += "\\dvipost{osend color pop}\n";
+                       preamble += "\\dvipost{cbstart color push Blue}\n";
+                       preamble += "\\dvipost{cbend color pop} \n";
+               }
+
                os << preamble;
 
                if (only_preamble)
@@ -3113,6 +3189,11 @@ void Buffer::validate(LaTeXFeatures & features) const
 {
        LyXTextClass const & tclass = params.getLyXTextClass();
 
+       if (params.tracking_changes) {
+               features.require("dvipost");
+               features.require("color");
+       }
        // AMS Style is at document level
        if (params.use_amsmath || tclass.provides(LyXTextClass::amsmath))
                features.require("amsmath");
@@ -3221,34 +3302,16 @@ vector<pair<string, string> > const Buffer::getBibkeyList() const
 
 bool Buffer::isDepClean(string const & name) const
 {
-       DEPCLEAN * item = dep_clean;
-       while (item && item->master != name)
-               item = item->next;
-       if (!item) return true;
-       return item->clean;
+       DepClean::const_iterator it = dep_clean_.find(name);
+       if (it == dep_clean_.end())
+               return true;
+       return it->second;
 }
 
 
 void Buffer::markDepClean(string const & name)
 {
-       if (!dep_clean) {
-               dep_clean = new DEPCLEAN;
-               dep_clean->clean = true;
-               dep_clean->master = name;
-               dep_clean->next = 0;
-       } else {
-               DEPCLEAN * item = dep_clean;
-               while (item && item->master != name)
-                       item = item->next;
-               if (item) {
-                       item->clean = true;
-               } else {
-                       item = new DEPCLEAN;
-                       item->clean = true;
-                       item->master = name;
-                       item->next = 0;
-               }
-       }
+       dep_clean_[name] = true;
 }
 
 
@@ -3455,10 +3518,12 @@ void Buffer::markDirty()
                updateTitles();
        }
        bak_clean = false;
-       DEPCLEAN * tmp = dep_clean;
-       while (tmp) {
-               tmp->clean = false;
-               tmp = tmp->next;
+
+       DepClean::iterator it = dep_clean_.begin();
+       DepClean::const_iterator const end = dep_clean_.end();
+
+       for (; it != end; ++it) {
+               it->second = false;
        }
 }