Fix bug #6058: Change tracking and versioning.

Computes a hash value for the authors when using change tracking.

Text.cpp, BufferParams.h, Author.h:
  Change unsigned int to int because the hash values can be negative.

lyx2lyx:
  Allow to convert negative author_ids.

See also: r30756.

git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@36134 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
Vincent van Ravesteijn 2010-11-05 18:25:29 +00:00
parent fb64f0e1af
commit f226c9d3fc
7 changed files with 47 additions and 39 deletions

View File

@ -6,6 +6,13 @@ changes happened in particular if possible.
The good example would be 2010-01-10 entry.
-----------------------
2010-10-23 Vincent van Ravesteijn <vfr@lyx.org>
* Format incremented to 405: author hash numbers
The authors that are used in change tracking are
now identified in the file by a number that represents
the hash value of the name and email. In this way
collaboration using version control leads to way less
merge conflicts.
2010-10-13 Richard Heck <rgheck@comcast.net>
* Format incremented to 404: refstyle support

View File

@ -771,7 +771,7 @@ def revert_author_id(document):
" Remove the author_id from the \\author definition "
i = 0
anum = 0
rx = re.compile(r'(\\author)\s+(\d+)\s+(\".*\")\s*(.*)$')
rx = re.compile(r'(\\author)\s+([-\d]+)\s+(\".*\")\s*(.*)$')
idmap = dict()
while True:
@ -2013,10 +2013,12 @@ convert = [[346, []],
[401, []],
[402, [convert_bibtex_clearpage]],
[403, [convert_flexnames]],
[404, [convert_prettyref]]
[404, [convert_prettyref]],
[405, []]
]
revert = [[403, [revert_refstyle]],
revert = [[404, []],
[403, [revert_refstyle]],
[402, [revert_flexnames]],
[401, []],
[400, [revert_diagram]],

View File

@ -12,9 +12,8 @@
#include "Author.h"
#include "support/lstrings.h"
#include "support/lassert.h"
#include "support/lstrings.h"
#include <algorithm>
#include <istream>
@ -24,6 +23,24 @@ using namespace lyx::support;
namespace lyx {
static int computeHash(docstring const & name,
docstring const & email)
{
string const full_author_string = to_ascii(name + email);
// Bernstein's hash function
unsigned int hash = 5381;
for (unsigned int i = 0; i < full_author_string.length(); ++i)
hash = ((hash << 5) + hash) + unsigned int(full_author_string[i]);
return int(hash);
}
Author::Author(docstring const & name, docstring const & email)
: name_(name), email_(email), used_(true)
{
buffer_id_ = computeHash(name_, email_);
}
bool operator==(Author const & l, Author const & r)
{
@ -65,18 +82,18 @@ AuthorList::AuthorList()
int AuthorList::record(Author const & a)
{
// If we record an author which equals the current
// author, we copy the buffer_id, so that it will
// keep the same id in the file.
if (authors_.size() > 0 && a == authors_[0])
authors_[0].setBufferId(a.buffer_id());
Authors::const_iterator it(authors_.begin());
Authors::const_iterator itend(authors_.end());
for (int i = 0; it != itend; ++it, ++i) {
if (*it == a) {
if (it->buffer_id() == 0)
// The current author is internally represented as
// author 0, but it appears he has already an id.
it->setBufferId(a.buffer_id());
if (*it == a)
return i;
}
}
authors_.push_back(a);
return last_id_++;
}
@ -129,24 +146,6 @@ ostream & operator<<(ostream & os, AuthorList const & a) {
AuthorList::Authors::const_iterator a_it = sorted.begin();
AuthorList::Authors::const_iterator a_end = sorted.end();
// Find the buffer id for the current author (internal id 0),
// if he doesn't have a buffer_id yet.
if (sorted.get(0).buffer_id() == 0) {
unsigned int cur_id = 1;
for (; a_it != a_end; ++a_it) {
if (a_it->buffer_id() == cur_id)
++cur_id;
else if (a_it->buffer_id() > cur_id) {
break;
}
}
// Set the id in both the original authorlist,
// as in the copy.
a.get(0).setBufferId(cur_id);
sorted.get(0).setBufferId(cur_id);
sorted.sort();
}
for (a_it = sorted.begin(); a_it != a_end; ++a_it) {
if (a_it->used())
os << "\\author " << *a_it << "\n";

View File

@ -24,16 +24,15 @@ public:
///
Author() {}
///
Author(docstring const & name, docstring const & email)
: name_(name), email_(email), used_(true), buffer_id_(0) {}
Author(docstring const & name, docstring const & email);
///
docstring name() const { return name_; }
///
docstring email() const { return email_; }
///
unsigned int buffer_id() const { return buffer_id_; }
int buffer_id() const { return buffer_id_; }
///
void setBufferId(unsigned int buffer_id) const { buffer_id_ = buffer_id; }
void setBufferId(int buffer_id) const { buffer_id_ = buffer_id; }
///
void setUsed(bool u) const { used_ = u; }
///
@ -49,7 +48,7 @@ private:
///
mutable bool used_;
/// The id of the author in the lyx-file
mutable unsigned int buffer_id_;
mutable int buffer_id_;
};

View File

@ -128,7 +128,7 @@ namespace {
// Do not remove the comment below, so we get merge conflict in
// independent branches. Instead add your own.
int const LYX_FORMAT = 404; // rgh: refstyle
int const LYX_FORMAT = 405; // vfr: author hash
typedef map<string, bool> DepClean;
typedef map<docstring, pair<InsetLabel const *, Buffer::References> > RefCache;

View File

@ -340,7 +340,8 @@ public:
AuthorList const & authors() const;
/// map of the file's author IDs to AuthorList indexes
std::map<unsigned int, int> author_map;
typedef std::map<int, int> AuthorMap;
AuthorMap author_map;
/// the buffer's font encoding
std::string const font_encoding() const;
///

View File

@ -456,10 +456,10 @@ void Text::readParToken(Paragraph & par, Lexer & lex,
} else if (token == "\\change_inserted" || token == "\\change_deleted") {
lex.eatLine();
istringstream is(lex.getString());
unsigned int aid;
int aid;
time_t ct;
is >> aid >> ct;
map<unsigned int, int> const & am = bp.author_map;
BufferParams::AuthorMap const & am = bp.author_map;
if (am.find(aid) == am.end()) {
errorList.push_back(ErrorItem(_("Change tracking error"),
bformat(_("Unknown author index for change: %1$d\n"), aid),