* Class Change has a changetime field that specifies the exact time at which
* a specific change was made. The change time is used as a guidance for the
* user while editing his document. Presently, it is not considered for LaTeX
- * export. To avoid that every keystroke results in a separate change, a
- * tolerance interval of 5 minutes is used. That means if there are two adjacent
- * changes that only differ in their change time with abs(ct1 - ct2) < 300 sec,
- * they will be merged (and the later change time is preserved).
- * Technically, the check for equality (or similarity) is made in operator==(...).
- * The merging of similar changes happens in method merge().
+ * export.
+ * When merging two adjacent changes, the changetime is not considered,
+ * only the equality of the change type and author is checked (in method
+ * isSimilarTo(...)). If two changes are in fact merged (in method merge()),
+ * the later change time is preserved.
*/
+bool Change::isSimilarTo(Change const & change)
+{
+ if (type != change.type) {
+ return false;
+ }
+
+ if (type == Change::UNCHANGED) {
+ return true;
+ }
+
+ return author == change.author;
+}
+
+
bool operator==(Change const & l, Change const & r)
{
if (l.type != r.type) {
return false;
}
+ // two changes of type UNCHANGED are always equal
if (l.type == Change::UNCHANGED) {
return true;
}
-
- return l.author == r.author
- // both changes made within 5 minutes?
- && abs(static_cast<int>(l.changetime - r.changetime)) < 300;
+
+ return l.author == r.author &&
+ l.changetime == r.changetime;
}
}
-bool Changes::Range::contains(Range const & r) const
-{
- return r.start >= start && r.end <= end;
-}
-
-
-bool Changes::Range::contains(pos_type const pos) const
-{
- return pos >= start && pos < end;
-}
-
-
bool Changes::Range::intersects(Range const & r) const
{
return r.start < end && r.end > start; // end itself is not in the range!
void Changes::set(Change const & change, pos_type const start, pos_type const end)
{
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << "setting change (type: " << change.type
+ if (change.type != Change::UNCHANGED) {
+ LYXERR(Debug::CHANGES) << "setting change (type: " << change.type
<< ", author: " << change.author << ", time: " << change.changetime
<< ") in range (" << start << ", " << end << ")" << endl;
}
if (it->range.end > start) {
pos_type oldEnd = it->range.end;
it->range.end = start;
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " cutting tail of type " << it->change.type
- << " resulting in range (" << it->range.start << ", "
- << it->range.end << ")" << endl;
- }
+
+ LYXERR(Debug::CHANGES) << " cutting tail of type " << it->change.type
+ << " resulting in range (" << it->range.start << ", "
+ << it->range.end << ")" << endl;
+
++it;
if (oldEnd >= end) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " inserting tail in range ("
- << end << ", " << oldEnd << ")" << endl;
- }
+ LYXERR(Debug::CHANGES) << " inserting tail in range ("
+ << end << ", " << oldEnd << ")" << endl;
it = table_.insert(it, ChangeRange((it-1)->change, Range(end, oldEnd)));
}
continue;
}
if (change.type != Change::UNCHANGED) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " inserting change" << endl;
- }
+ LYXERR(Debug::CHANGES) << " inserting change" << endl;
it = table_.insert(it, ChangeRange(change, Range(start, end)));
++it;
}
for (; it != table_.end(); ) {
// new change 'contains' existing change
if (newRange.contains(it->range)) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " removing subrange ("
- << it->range.start << ", " << it->range.end << ")" << endl;
- }
+ LYXERR(Debug::CHANGES) << " removing subrange ("
+ << it->range.start << ", " << it->range.end << ")" << endl;
it = table_.erase(it);
continue;
}
// new change intersects with existing change
it->range.start = end;
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " cutting head of type "
- << it->change.type << " resulting in range ("
- << end << ", " << it->range.end << ")" << endl;
- }
+ LYXERR(Debug::CHANGES) << " cutting head of type "
+ << it->change.type << " resulting in range ("
+ << end << ", " << it->range.end << ")" << endl;
break; // no need for another iteration
}
void Changes::erase(pos_type const pos)
{
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << "Erasing change at position " << pos << endl;
- }
+ LYXERR(Debug::CHANGES) << "Erasing change at position " << pos << endl;
ChangeTable::iterator it = table_.begin();
ChangeTable::iterator end = table_.end();
void Changes::insert(Change const & change, lyx::pos_type pos)
{
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << "Inserting change of type " << change.type
+ if (change.type != Change::UNCHANGED) {
+ LYXERR(Debug::CHANGES) << "Inserting change of type " << change.type
<< " at position " << pos << endl;
}
}
-Change const Changes::lookup(pos_type const pos) const
+Change const & Changes::lookup(pos_type const pos) const
{
- if (table_.empty()) {
- return Change(Change::UNCHANGED);
- }
+ static Change const noChange = Change(Change::UNCHANGED);
+
ChangeTable::const_iterator it = table_.begin();
ChangeTable::const_iterator const end = table_.end();
return it->change;
}
- return Change(Change::UNCHANGED);
+ return noChange;
}
for (; it != itend; ++it) {
if (it->range.intersects(Range(start, end))) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << "found intersection of range ("
- << start << ", " << end << ") with ("
- << it->range.start << ", " << it->range.end
- << ") of type " << it->change.type << endl;
- }
+ LYXERR(Debug::CHANGES) << "found intersection of range ("
+ << start << ", " << end << ") with ("
+ << it->range.start << ", " << it->range.end
+ << ") of type " << it->change.type << endl;
return true;
}
}
void Changes::merge()
{
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << "merging changes..." << endl;
- }
-
ChangeTable::iterator it = table_.begin();
while (it != table_.end()) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " found change of type " << it->change.type
- << " and range (" << it->range.start << ", " << it->range.end
- << ")" << endl;
- }
+ LYXERR(Debug::CHANGES) << "found change of type " << it->change.type
+ << " and range (" << it->range.start << ", " << it->range.end
+ << ")" << endl;
if (it->range.start == it->range.end) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " removing empty range for pos "
- << it->range.start << endl;
- }
+ LYXERR(Debug::CHANGES) << "removing empty range for pos "
+ << it->range.start << endl;
table_.erase(it);
// start again
if (it + 1 == table_.end())
break;
- if (it->change == (it + 1)->change && it->range.end == (it + 1)->range.start) {
- if (lyxerr.debugging(Debug::CHANGES)) {
- lyxerr[Debug::CHANGES] << " merging ranges (" << it->range.start << ", "
- << it->range.end << ") and (" << (it + 1)->range.start << ", "
- << (it + 1)->range.end << ")" << endl;
- }
+ if (it->change.isSimilarTo((it + 1)->change) && it->range.end == (it + 1)->range.start) {
+ LYXERR(Debug::CHANGES) << "merging ranges (" << it->range.start << ", "
+ << it->range.end << ") and (" << (it + 1)->range.start << ", "
+ << (it + 1)->range.end << ")" << endl;
+
(it + 1)->range.start = it->range.start;
(it + 1)->change.changetime = max(it->change.changetime,
(it + 1)->change.changetime);