]> git.lyx.org Git - lyx.git/blob - src/Author.cpp
Avoid full metrics computation with Update:FitCursor
[lyx.git] / src / Author.cpp
1 /**
2  * \file Author.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "Author.h"
14
15 #include "support/convert.h"
16 #include "support/gettext.h"
17 #include "support/lassert.h"
18 #include "support/lstrings.h"
19
20 #include <algorithm>
21 #include <istream>
22
23 using namespace std;
24 using namespace lyx::support;
25
26 namespace lyx {
27
28 static int computeHash(docstring const & name,
29         docstring const & email)
30 {
31         string const full_author_string = to_utf8(name + email);
32         // Bernstein's hash function
33         unsigned int hash = 5381;
34         for (char c : full_author_string)
35                 hash = ((hash << 5) + hash) + (unsigned int)c;
36         return int(hash);
37 }
38
39
40 Author::Author(docstring const & name, docstring const & email, docstring const & initials)
41         : name_(name), email_(email), initials_(initials), used_(true),
42           buffer_id_(computeHash(name, email))
43 {}
44
45
46 Author::Author(int buffer_id)
47         : name_(convert<docstring>(buffer_id)), email_(docstring()), initials_(docstring()), used_(false),
48           buffer_id_(buffer_id)
49 {}
50
51
52 docstring Author::nameAndEmail() const
53 {
54         if (email().empty())
55                 return name();
56         return bformat(_("%1$s[[name]] (%2$s[[email]])"), name(), email());
57 }
58
59
60 bool Author::valid() const
61 {
62         //this cannot be equal if the buffer_id was produced by the hash function.
63         return name_ != convert<docstring>(buffer_id_);
64 }
65
66
67 bool operator==(Author const & l, Author const & r)
68 {
69         return l.name() == r.name() && l.email() == r.email() && l.initials() == r.initials();
70 }
71
72
73 ostream & operator<<(ostream & os, Author const & a)
74 {
75         // FIXME UNICODE
76         os << a.buffer_id_ << " \"" << to_utf8(a.name_) << "\"";
77         if (!a.email_.empty())
78                 os << " " << to_utf8(a.email_);
79
80         return os;
81 }
82
83
84 istream & operator>>(istream & is, Author & a)
85 {
86         string s;
87         is >> a.buffer_id_;
88         getline(is, s);
89         // FIXME UNICODE
90         a.name_ = from_utf8(trim(token(s, '\"', 1)));
91         a.email_ = from_utf8(trim(token(s, '\"', 2)));
92         return is;
93 }
94
95
96 bool author_smaller(Author const & lhs, Author const & rhs)
97 {
98         return lhs.bufferId() < rhs.bufferId();
99 }
100
101
102 AuthorList::AuthorList()
103 {}
104
105
106 int AuthorList::record(Author const & a)
107 {
108         bool const valid = a.valid();
109         // If we record an author which equals the current
110         // author, we copy the buffer_id, so that it will
111         // keep the same id in the file.
112         if (valid && !authors_.empty() && a == authors_[0])
113                 authors_[0].setBufferId(a.bufferId());
114
115         Authors::const_iterator it = authors_.begin();
116         Authors::const_iterator const beg = it;
117         Authors::const_iterator const end = authors_.end();
118         for (; it != end; ++it) {
119                 if (valid && *it == a)
120                         return it - beg;
121                 if (it->bufferId() == a.bufferId()) {
122                         int const id = it - beg;
123                         if (!it->valid()) {
124                                 // we need to handle the case of a valid author being registered
125                                 // after an invalid one. For instance, because "buffer-reload"
126                                 // does not clear the buffer's author list.
127                                 record(id, a);
128                         }
129                         return id;
130                 }
131         }
132         authors_.push_back(a);
133         return authors_.size() - 1;
134 }
135
136
137 void AuthorList::record(int id, Author const & a)
138 {
139         LBUFERR(unsigned(id) < authors_.size());
140         authors_[id] = a;
141 }
142
143
144 void AuthorList::recordCurrentAuthor(Author const & a)
145 {
146         // current author has id 0
147         record(0, a);
148 }
149
150
151 Author const & AuthorList::get(int id) const
152 {
153         LASSERT(id < (int)authors_.size() , return authors_[0]);
154         return authors_[id];
155 }
156
157
158 AuthorList::Authors::const_iterator AuthorList::begin() const
159 {
160         return authors_.begin();
161 }
162
163
164 AuthorList::Authors::const_iterator AuthorList::end() const
165 {
166         return authors_.end();
167 }
168
169
170 void AuthorList::sort()
171 {
172         std::sort(authors_.begin(), authors_.end(), author_smaller);
173 }
174
175
176 ostream & operator<<(ostream & os, AuthorList const & a)
177 {
178         // Copy the authorlist, because we don't want to sort the original
179         AuthorList sorted = a;
180         sorted.sort();
181         for (auto const & aut : sorted) {
182                 if (aut.used() && aut.valid())
183                         os << "\\author " << aut << "\n";
184         }
185         return os;
186 }
187
188
189 } // namespace lyx