The big change tracking patch. Changes from posted version :

1) abstract time_t into lyx::time_type
2) abstrace struct passwd into support/userinfo
3) make authorlist a per-buffer property instead of global

I will look at the paragraph breaking soon, in the meantime I opened a bug on bugzilla.


git-svn-id: svn://svn.lyx.org/lyx/lyx-devel/trunk@6074 a592a061-630c-0410-9148-cb99ea01b6c8
This commit is contained in:
John Levon 2003-02-08 19:18:01 +00:00
parent 2b08bb805b
commit ae87b94515
86 changed files with 3258 additions and 291 deletions

View File

@ -1,3 +1,11 @@
2003-02-08 John Levon <levon@movementarian.org>
* chkconfig.ltx: look for dvipost package
* configure.m4: look for and prefer pplatex
* ui/default.ui: Add change tracking menu items
2003-02-07 Tomasz Luczak <tlu@technodat.com.pl>
* kbd/polski.kmap: new keymap, which assumes that you have a

View File

@ -225,6 +225,7 @@
\TestPackage{varioref}
\TestPackage{prettyref}
\TestPackage{natbib}
\TestPackage{dvipost}
% The test for the graphics package is slightly more involved...
\newcommand\groption{dvips}

View File

@ -199,7 +199,7 @@ fi
rm -f chklatex.ltx chklatex.log])dnl
dnl
# Search LaTeX2e
SEARCH_PROG([for a LaTeX2e program],LATEX,latex latex2e,CHECKLATEX2E,dnl
SEARCH_PROG([for a LaTeX2e program],LATEX,pplatex latex2e latex,CHECKLATEX2E,dnl
[lyx_check_config=no])
latex_to_dvi=$LATEX
test -z "$latex_to_dvi" && latex_to_dvi="none"

View File

@ -80,6 +80,7 @@ Menuset
Item "Check TeX|h" "buffer-chktex"
Item "Remove All Error Boxes|E" "error-remove-all"
Item "Open/Close float|l" "inset-toggle"
Submenu "Change tracking|h" "edit_change"
Separator
Item "Preferences...|P" "dialog-preferences"
Item "Reconfigure|R" "reconfigure"
@ -292,6 +293,12 @@ Menuset
Item "ASCII as Paragraphs...|P" "file-insert-ascii-para"
End
Menu "edit_change"
Item "Track changes|T" "track-changes"
Item "Merge changes ...|M" "merge-changes"
Item "Accept all changes|A" "accept-all-changes"
Item "Reject all changes|R" "reject-all-changes"
End
#
# LAYOUT MENU
#

View File

@ -1,19 +1,17 @@
src/BufferView.C
src/BufferView_pimpl.C
src/Chktex.C
src/CutAndPaste.C
src/LColor.C
src/LaTeX.C
src/LyXAction.C
src/MenuBackend.C
src/buffer.C
src/bufferlist.C
src/BufferView.C
src/bufferview_funcs.C
src/BufferView_pimpl.C
src/Chktex.C
src/converter.C
src/CutAndPaste.bak.C
src/CutAndPaste.C
src/debug.C
src/exporter.C
src/frontends/LyXView.C
src/frontends/controllers/biblio.C
src/frontends/controllers/ButtonController.h
src/frontends/controllers/character.C
src/frontends/controllers/ControlAboutlyx.C
src/frontends/controllers/ControlBibtex.C
src/frontends/controllers/ControlCharacter.C
@ -29,13 +27,13 @@ src/frontends/controllers/ControlSearch.C
src/frontends/controllers/ControlSpellchecker.C
src/frontends/controllers/ControlThesaurus.C
src/frontends/controllers/ControlVCLog.C
src/frontends/controllers/biblio.C
src/frontends/controllers/character.C
src/frontends/controllers/frnt_lang.C
src/frontends/controllers/helper_funcs.C
src/frontends/gnome/GLog.C
src/frontends/LyXView.C
src/frontends/qt2/Alert_pimpl.C
src/frontends/qt2/FileDialog.C
src/frontends/qt2/lengthcombo.C
src/frontends/qt2/QAbout.C
src/frontends/qt2/QBibitem.C
src/frontends/qt2/QBibtex.C
@ -47,8 +45,8 @@ src/frontends/qt2/QCommandBuffer.C
src/frontends/qt2/QDelimiterDialog.C
src/frontends/qt2/QDocument.C
src/frontends/qt2/QDocumentDialog.C
src/frontends/qt2/QERT.C
src/frontends/qt2/QError.C
src/frontends/qt2/QERT.C
src/frontends/qt2/QExternal.C
src/frontends/qt2/QExternalDialog.C
src/frontends/qt2/QFloat.C
@ -56,8 +54,8 @@ src/frontends/qt2/QGraphics.C
src/frontends/qt2/QGraphicsDialog.C
src/frontends/qt2/QInclude.C
src/frontends/qt2/QIndex.C
src/frontends/qt2/QLPrintDialog.C
src/frontends/qt2/QLog.C
src/frontends/qt2/QLPrintDialog.C
src/frontends/qt2/QMathDialog.C
src/frontends/qt2/QMathMatrixDialog.C
src/frontends/qt2/QMinipage.C
@ -75,23 +73,24 @@ src/frontends/qt2/QTabularCreate.C
src/frontends/qt2/QTexinfo.C
src/frontends/qt2/QThesaurus.C
src/frontends/qt2/QToc.C
src/frontends/qt2/QtView.C
src/frontends/qt2/QURL.C
src/frontends/qt2/QVCLog.C
src/frontends/qt2/QWrap.C
src/frontends/qt2/QtView.C
src/frontends/qt2/lengthcombo.C
src/frontends/xforms/Alert_pimpl.C
src/frontends/xforms/ColorHandler.C
src/frontends/xforms/combox.C
src/frontends/xforms/FileDialog.C
src/frontends/xforms/FormAboutlyx.C
src/frontends/xforms/FormBase.C
src/frontends/xforms/FormBibitem.C
src/frontends/xforms/FormBibtex.C
src/frontends/xforms/FormChanges.C
src/frontends/xforms/FormCharacter.C
src/frontends/xforms/FormCitation.C
src/frontends/xforms/FormDocument.C
src/frontends/xforms/FormERT.C
src/frontends/xforms/FormError.C
src/frontends/xforms/FormERT.C
src/frontends/xforms/FormExternal.C
src/frontends/xforms/FormFiledialog.C
src/frontends/xforms/FormFloat.C
@ -124,15 +123,14 @@ src/frontends/xforms/FormToc.C
src/frontends/xforms/FormUrl.C
src/frontends/xforms/FormVCLog.C
src/frontends/xforms/FormWrap.C
src/frontends/xforms/Menubar_pimpl.C
src/frontends/xforms/XMiniBuffer.C
src/frontends/xforms/combox.C
src/frontends/xforms/input_validators.C
src/frontends/xforms/Menubar_pimpl.C
src/frontends/xforms/xforms_helpers.C
src/frontends/xforms/XMiniBuffer.C
src/gettext.h
src/importer.C
src/insets/inset.C
src/insets/insetbib.C
src/insets/inset.C
src/insets/insetcaption.C
src/insets/inseterror.C
src/insets/insetert.C
@ -159,12 +157,15 @@ src/insets/inseturl.C
src/insets/insetwrap.C
src/kbsequence.C
src/language.C
src/LaTeX.C
src/LColor.C
src/lengthcommon.C
src/LyXAction.C
src/lyx_cb.C
src/lyx_main.C
src/lyxfind.C
src/lyxfont.C
src/lyxfunc.C
src/lyx_main.C
src/lyxrc.C
src/lyxtextclasslist.C
src/lyxvc.C
@ -173,9 +174,11 @@ src/mathed/formulamacro.C
src/mathed/math_hullinset.C
src/mathed/math_parboxinset.C
src/mathed/ref_inset.C
src/MenuBackend.C
src/paragraph.C
src/support/filetools.C
src/tabular.C
src/text.C
src/text2.C
src/text3.C
src/text.C
src/ext_l10n.h

View File

@ -29,6 +29,7 @@
#include "lyxlex.h"
#include "lyxtext.h"
#include "undo_funcs.h"
#include "changes.h"
#include "frontends/Alert.h"
#include "frontends/Dialogs.h"
@ -154,6 +155,12 @@ bool BufferView::available() const
}
Change const BufferView::getCurrentChange()
{
return pimpl_->getCurrentChange();
}
void BufferView::beforeChange(LyXText * text)
{
pimpl_->beforeChange(text);
@ -664,7 +671,7 @@ void BufferView::replaceWord(string const & replacestring)
toggleSelection(false);
tt->replaceSelectionWithString(this, replacestring);
tt->setSelectionOverString(this, replacestring);
tt->setSelectionRange(this, replacestring.length());
// Go back so that replacement string is also spellchecked
for (string::size_type i = 0; i < replacestring.length() + 1; ++i) {

View File

@ -21,6 +21,7 @@
#include <boost/utility.hpp>
class Change;
class LyXView;
class LyXText;
class TeXErrors;
@ -108,6 +109,9 @@ public:
/// does the given bookmark have a saved position ?
bool isSavedPosition(unsigned int i);
/// return the current change at the cursor
Change const getCurrentChange();
/**
* This holds the mapping between buffer paragraphs and screen rows.
* This should be private...but not yet. (Lgb)

View File

@ -41,6 +41,8 @@
#include "ParagraphParameters.h"
#include "undo_funcs.h"
#include "funcrequest.h"
#include "iterators.h"
#include "lyxfind.h"
#include "insets/insetbib.h"
#include "insets/insettext.h"
@ -624,6 +626,21 @@ bool BufferView::Pimpl::available() const
}
Change const BufferView::Pimpl::getCurrentChange()
{
if (!bv_->buffer()->params.tracking_changes)
return Change(Change::UNCHANGED);
LyXText * t(bv_->getLyXText());
if (!t->selection.set())
return Change(Change::UNCHANGED);
LyXCursor const & cur(t->selection.start);
return cur.par()->lookupChangeFull(cur.pos());
}
void BufferView::Pimpl::beforeChange(LyXText * text)
{
toggleSelection();
@ -915,6 +932,43 @@ void BufferView::Pimpl::MenuInsertLyXFile(string const & filen)
}
void BufferView::Pimpl::trackChanges()
{
Buffer * buf(bv_->buffer());
bool const tracking(buf->params.tracking_changes);
if (!tracking) {
ParIterator const end = buf->par_iterator_end();
for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) {
(*it)->trackChanges();
}
buf->params.tracking_changes = true;
// we cannot allow undos beyond the freeze point
buf->undostack.clear();
} else {
bv_->update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
bv_->text->setCursor(bv_, &(*buf->paragraphs.begin()), 0);
#warning changes FIXME
//moveCursorUpdate(false);
bool found = lyxfind::findNextChange(bv_);
if (found) {
owner_->getDialogs().showMergeChanges();
return;
}
ParIterator const end = buf->par_iterator_end();
for (ParIterator it = buf->par_iterator_begin(); it != end; ++it) {
(*it)->untrackChanges();
}
buf->params.tracking_changes = false;
}
buf->redostack.clear();
}
bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
{
lyxerr[Debug::ACTION] << "BufferView::Pimpl::Dispatch:"
@ -1249,6 +1303,56 @@ bool BufferView::Pimpl::dispatch(FuncRequest const & ev)
}
break;
case LFUN_TRACK_CHANGES:
trackChanges();
break;
case LFUN_MERGE_CHANGES:
owner_->getDialogs().showMergeChanges();
break;
case LFUN_ACCEPT_ALL_CHANGES: {
bv_->update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
bv_->text->setCursor(bv_, &(*bv_->buffer()->paragraphs.begin()), 0);
#warning FIXME changes
//moveCursorUpdate(false);
while (lyxfind::findNextChange(bv_)) {
bv_->getLyXText()->acceptChange(bv_);
}
update(bv_->text,
BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
break;
}
case LFUN_REJECT_ALL_CHANGES: {
bv_->update(bv_->text, BufferView::SELECT | BufferView::FITCUR);
bv_->text->setCursor(bv_, &(*bv_->buffer()->paragraphs.begin()), 0);
#warning FIXME changes
//moveCursorUpdate(false);
while (lyxfind::findNextChange(bv_)) {
bv_->getLyXText()->rejectChange(bv_);
}
update(bv_->text,
BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
break;
}
case LFUN_ACCEPT_CHANGE: {
bv_->getLyXText()->acceptChange(bv_);
update(bv_->text,
BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
break;
}
case LFUN_REJECT_CHANGE: {
bv_->getLyXText()->rejectChange(bv_);
update(bv_->text,
BufferView::SELECT | BufferView::FITCUR | BufferView::CHANGE);
break;
}
case LFUN_UNKNOWN_ACTION:
ev.errorMessage(N_("Unknown function!"));
break;

View File

@ -23,6 +23,7 @@
#pragma interface
#endif
class Change;
class LyXView;
class WorkArea;
class LyXScreen;
@ -74,6 +75,8 @@ struct BufferView::Pimpl : public boost::signals::trackable {
void cursorToggle();
///
bool available() const;
/// get the change at the cursor position
Change const getCurrentChange();
///
void beforeChange(LyXText *);
///
@ -103,6 +106,9 @@ struct BufferView::Pimpl : public boost::signals::trackable {
///
bool dispatch(FuncRequest const & ev);
private:
/// track changes for the document
void trackChanges();
///
friend class BufferView;

View File

@ -1,3 +1,95 @@
2003-02-08 John Levon <levon@movementarian.org>
* lyxfind.C:
* lyxtext.h:
* text2.C:
* BufferView.C: change setSelectionOverString() to setSelectionRange()
and pass the size in explicitly
* BufferView_pimpl.h:
* BufferView_pimpl.C:
* BufferView.h:
* BufferView.C: add getCurrentChange()
* BufferView_pimpl.h:
* BufferView_pimpl.C: handle change lfuns
* CutAndPaste.C: merge the cut and copy code. Rework the cut code
for changes. Mark pasted paragraphs as new.
* support/lyxtime.h:
* support/lyxtime.C:
* DepTable.C: abstract time_t as lyx::time_type
* LColor.h:
* LColor.C: add colours for new text, deleted text, changebars
* LaTeXFeatures.C: add dvipost as a simple feature. Make the color
package use "usenames" option.
* commandtags.h:
* lyxfunc.C:
* LyXAction.C: add change lfuns
* Makefile.am:
* author.h:
* author.C: author handling
* buffer.h:
* buffer.C: add a per-buffer author list, with first entry as
current author. Handle new .lyx tokens for change tracking. Output
author list to .lyx file. Output dvipost stuff to .tex preamble.
Bump lyx format to 222.
* bufferlist.h:
* bufferlist.C: add setCurrentAuthor() to reset current author details
in all buffers.
* bufferparams.h:
* bufferparams.C: add param for tracking
* bufferview_funcs.C: output change info in minibuffer
* Makefile.am:
* changes.h:
* changes.C: add change-tracking structure
* debug.h:
* debug.C: add CHANGES debug flag
* lyxfind.h:
* lyxfind.C: add code for finding the next change piece
* lyxrc.h:
* lyxrc.C: add user_name and user_email
* lyxrow.h:
* lyxrow.C: add a metric for the top of the text line
* lyxtext.h:
* text.C: implement accept/rejectChange()
* lyxtext.h:
* text.C: paint changebars. Paint new/deleted text in the chosen colours.
Strike through deleted text.
* paragraph.h:
* paragraph.C:
* paragraph_pimpl.h:
* paragraph_pimpl.C: output change markers in .lyx and .tex. Pass in the current change
to the insert functions. Rework erase to mark text as deleted, adding
an eraseIntern() and a range-based erase(). Implement
per-paragraph change lookup and accept/reject.
* paragraph_funcs.C: Fixup paste for change tracking.
* tabular.C: mark added row/columns as new.
* text.C: fix rowLast() to never return -1. Don't allow spellchecking of deleted
text. Track transpose changes. Don't allow paragraph break or merge where appropriate.
* text2.C: leave cursor at end of selection after a cut.
2003-02-07 Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>
* text.C (getLengthMarkerHeight):

View File

@ -14,7 +14,6 @@
#endif
#include "CutAndPaste.h"
//#include "debug.h"
#include "BufferView.h"
#include "buffer.h"
#include "paragraph.h"
@ -26,11 +25,13 @@
#include "lyxtextclasslist.h"
#include "undo_funcs.h"
#include "paragraph_funcs.h"
#include "debug.h"
#include "insets/inseterror.h"
#include "BoostFormat.h"
using std::endl;
using std::pair;
using lyx::pos_type;
using lyx::textclass_type;
@ -58,6 +59,7 @@ extern BufferView * current_view;
namespace {
// FIXME: stupid name
Paragraph * buf = 0;
textclass_type textclass = 0;
@ -90,77 +92,89 @@ bool CutAndPaste::cutSelection(Paragraph * startpar, Paragraph ** endpar,
if (!startpar || (start > startpar->size()))
return false;
if (realcut)
DeleteBuffer();
textclass = tc;
if (!(*endpar) || startpar == (*endpar)) {
// only within one paragraph
if (realcut) {
buf = new Paragraph;
buf->layout(startpar->layout());
copySelection(startpar, *endpar, start, end, tc);
}
pos_type i = start;
if (end > startpar->size())
end = startpar->size();
for (; i < end; ++i) {
if (realcut)
startpar->copyIntoMinibuffer(*current_view->buffer(),
start);
startpar->erase(start);
if (realcut)
buf->insertFromMinibuffer(buf->size());
if (!endpar || startpar == *endpar) {
if (startpar->erase(start, end)) {
// Some chars were erased, go to start to be safe
end = start;
}
end = start - 1;
} else {
// more than one paragraph
breakParagraphConservative(current_view->buffer()->params,
*endpar,
end);
*endpar = (*endpar)->next();
return true;
}
bool actually_erased = false;
// clear end/begin fragments of the first/last par in selection
actually_erased |= (startpar)->erase(start, startpar->size());
if ((*endpar)->erase(0, end)) {
actually_erased = true;
end = 0;
breakParagraphConservative(current_view->buffer()->params,
startpar,
start);
// store the selection
if (realcut) {
buf = startpar->next();
buf->previous(0);
} else {
startpar->next()->previous(0);
}
(*endpar)->previous()->next(0);
// cut the selection
startpar->next(*endpar);
// Loop through the deleted pars if any, erasing as needed
(*endpar)->previous(startpar);
Paragraph * pit = startpar->next();
while (1) {
// *endpar can be 0
if (!pit)
break;
Paragraph * next = pit->next();
// "erase" the contents of the par
if (pit != *endpar) {
actually_erased |= pit->erase(0, pit->size());
// remove the par if it's now empty
if (actually_erased) {
pit->previous()->next(pit->next());
if (next) {
next->previous(pit->previous());
}
lyxerr << "deleting pit " << pit << endl;
delete pit;
}
}
if (pit == *endpar)
break;
pit = next;
}
#if 0 // FIXME: why for cut but not copy ?
// the cut selection should begin with standard layout
if (realcut) {
buf->params().clear();
buf->bibkey = 0;
buf->layout(current_view->buffer()->params.getLyXTextClass().defaultLayout());
buf->layout(textclasslist[buffer->params.textclass].defaultLayoutName());
}
#endif
if (!startpar->next())
return true;
Buffer * buffer = current_view->buffer();
if (doclear) {
startpar->next()->stripLeadingSpaces();
}
if (!actually_erased)
return true;
// paste the paragraphs again, if possible
if (doclear)
startpar->next()->stripLeadingSpaces();
if (startpar->hasSameLayout(startpar->next()) ||
startpar->next()->empty()) {
mergeParagraph(current_view->buffer()->params, startpar);
(*endpar) = startpar; // this because endpar gets deleted here!
}
// this paragraph's are of noone's owner!
Paragraph * p = buf;
while (p) {
p->setInsetOwner(0);
p = p->next();
}
mergeParagraph(buffer->params, startpar);
// this because endpar gets deleted here!
(*endpar) = startpar;
}
return true;
}
@ -192,6 +206,7 @@ bool CutAndPaste::copySelection(Paragraph * startpar, Paragraph * endpar,
Paragraph * tmppar = startpar;
buf = new Paragraph(*tmppar, false);
Paragraph * tmppar2 = buf;
tmppar2->cleanChanges();
while (tmppar != endpar
&& tmppar->next()) {
@ -199,6 +214,8 @@ bool CutAndPaste::copySelection(Paragraph * startpar, Paragraph * endpar,
tmppar2->next(new Paragraph(*tmppar, false));
tmppar2->next()->previous(tmppar2);
tmppar2 = tmppar2->next();
// reset change info
tmppar2->cleanChanges();
}
tmppar2->next(0);
@ -349,9 +366,7 @@ bool CutAndPaste::pasteSelection(Paragraph ** par, Paragraph ** endpar,
// if necessary
if (((*par)->size() > pos) || !(*par)->next()) {
breakParagraphConservative(
current_view->buffer()->params,
*par,
pos);
current_view->buffer()->params, *par, pos);
paste_the_end = true;
}
// set the end for redoing later
@ -375,10 +390,10 @@ bool CutAndPaste::pasteSelection(Paragraph ** par, Paragraph ** endpar,
if (lastbuffer->next() && paste_the_end) {
if (lastbuffer->next()->hasSameLayout(lastbuffer)) {
mergeParagraph(current_view->buffer()->params, lastbuffer);
} else if (lastbuffer->next()->empty()) {
} else if (!lastbuffer->next()->size()) {
lastbuffer->next()->makeSameLayout(lastbuffer);
mergeParagraph(current_view->buffer()->params, lastbuffer);
} else if (lastbuffer->empty()) {
} else if (!lastbuffer->size()) {
lastbuffer->makeSameLayout(lastbuffer->next());
mergeParagraph(current_view->buffer()->params, lastbuffer);
} else

View File

@ -24,7 +24,7 @@ class LyXTextClass;
///
class CutAndPaste {
public:
///
/// realcut == false is we actually want a delete
static
bool cutSelection(Paragraph * startpar, Paragraph ** endpar,
int start, int & end, char tc, bool doclear = false,

View File

@ -24,6 +24,7 @@
#include "support/lyxlib.h"
#include "support/filetools.h"
#include "support/lstrings.h"
#include "support/lyxtime.h"
#include <sys/types.h>
#include <sys/stat.h>
@ -79,7 +80,7 @@ void DepTable::insert(string const & fi, bool upd)
void DepTable::update()
{
lyxerr[Debug::DEPEND] << "Updating DepTable..." << endl;
time_t start_time = time(0);
lyx::time_type const start_time = lyx::current_time();
DepList::iterator itr = deplist.begin();
while (itr != deplist.end()) {
@ -114,7 +115,7 @@ void DepTable::update()
}
++itr;
}
time_t time_sec = time(0) - start_time;
lyx::time_type const time_sec = lyx::current_time() - start_time;
lyxerr[Debug::DEPEND] << "Finished updating DepTable ("
<< time_sec << " sec)." << endl;
}

View File

@ -84,6 +84,9 @@ LColor::LColor()
{ error, N_("LaTeX error"), "error", "Red", "error" },
{ eolmarker, N_("end-of-line marker"), "eolmarker", "Brown", "eolmarker" },
{ appendixline, N_("appendix line"), "appendixline", "Brown", "appendixline" },
{ changebar, N_("change bar"), "changebar", "Blue", "changebar" },
{ strikeout, N_("Deleted text"), "strikeout", "Red", "strikeout" },
{ newtext, N_("Added text"), "newtext", "Blue", "newtext" },
{ added_space, N_("added space markers"), "added_space", "Brown", "added_space" },
{ topline, N_("top/bottom line"), "topline", "Brown", "topline" },
{ tabularline, N_("tabular line"), "tabularline", "black",

View File

@ -137,6 +137,12 @@ public:
added_space,
/// Appendix line color
appendixline,
/// changebar color
changebar,
/// strike-out color
strikeout,
/// added text color
newtext,
/// Top and bottom line color
topline,
/// Table line color

View File

@ -174,10 +174,11 @@ char const * simplefeatures[] = {
"varioref",
"prettyref",
"float",
"wasy"
"wasy",
"dvipost"
};
const int nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
int const nb_simplefeatures = sizeof(simplefeatures) / sizeof(char const *);
}
@ -210,10 +211,11 @@ string const LaTeXFeatures::getPackages() const
// color.sty
if (isRequired("color")) {
if (params.graphicsDriver == "default")
packages << "\\usepackage{color}\n";
packages << "\\usepackage[usenames]{color}\n";
else
packages << "\\usepackage["
<< params.graphicsDriver
<< ",usenames"
<< "]{color}\n";
}

View File

@ -413,6 +413,12 @@ void LyXAction::init()
{ LFUN_FORKS_KILL, "kill-forks",
N_("Kill the forked process with this PID"), NoBuffer },
{ LFUN_TOOLTIPS_TOGGLE, "toggle-tooltips", "", NoBuffer },
{ LFUN_TRACK_CHANGES, "track-changes", N_("Begin tracking changes"), Noop },
{ LFUN_MERGE_CHANGES, "merge-changes", N_("Merge changes"), Noop },
{ LFUN_ACCEPT_CHANGE, "accept-change", N_("Accept selected change"), Noop },
{ LFUN_REJECT_CHANGE, "reject-change", N_("Reject selected change"), Noop },
{ LFUN_ACCEPT_ALL_CHANGES, "accept-all-changes", N_("Accept all changes"), Noop },
{ LFUN_REJECT_ALL_CHANGES, "reject-all-changes", N_("Reject all changes"), Noop },
{ LFUN_NOACTION, "", "", Noop }
};

View File

@ -87,6 +87,8 @@ lyx_SOURCES = \
ToolbarDefaults.C \
ToolbarDefaults.h \
WordLangTuple.h \
author.C \
author.h \
boost.C \
boost-inst.C \
box.h \
@ -100,6 +102,8 @@ lyx_SOURCES = \
bufferparams.h \
bufferview_funcs.C \
bufferview_funcs.h \
changes.C \
changes.h \
chset.C \
chset.h \
commandtags.h \

94
src/author.C Normal file
View File

@ -0,0 +1,94 @@
/**
* \file author.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#include <config.h>
#include "author.h"
#include "debug.h"
#include "support/LAssert.h"
#include "support/LOstream.h"
#include "support/LIstream.h"
#include "support/lstrings.h"
using std::endl;
namespace {
int cur_id;
}
bool operator==(Author const & l, Author const & r)
{
return l.name() == r.name() && l.email() == r.email();
}
std::ostream & operator<<(std::ostream & os, Author const & a)
{
os << "\"" << a.name() << "\" " << a.email();
return os;
}
std::istream & operator>>(std::istream & is, Author & a)
{
string s;
getline(is, s);
a.name_ = trim(token(s, '\"', 1));
a.email_ = trim(token(s, '\"', 2));
lyxerr << "Read name " << a.name_ << " email " << a.email_ << endl;
return is;
}
int AuthorList::record(Author const & a)
{
Authors::const_iterator it(authors_.begin());
Authors::const_iterator itend(authors_.end());
for (; it != itend; ++it) {
if (it->second == a)
return it->first;
}
lyxerr[Debug::CHANGES] << "Adding author " << a << endl;
authors_[cur_id++] = a;
return cur_id - 1;
}
void AuthorList::record(int id, Author const & a)
{
lyx::Assert(id < authors_.size());
authors_[id] = a;
}
Author const & AuthorList::get(int id)
{
Authors::const_iterator it(authors_.find(id));
lyx::Assert(it != authors_.end());
return it->second;
}
AuthorList::Authors::const_iterator AuthorList::begin() const
{
return authors_.begin();
}
AuthorList::Authors::const_iterator AuthorList::end() const
{
return authors_.end();
}

67
src/author.h Normal file
View File

@ -0,0 +1,67 @@
/**
* \file author.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#ifndef AUTHOR_H
#define AUTHOR_H
#include <map>
#include <iosfwd>
#include "LString.h"
class Author {
public:
Author() {}
Author(string n, string e)
: name_(n), email_(e) {}
string const name() const {
return name_;
}
string const email() const {
return email_;
}
friend std::istream & operator>>(std::istream & os, Author & a);
private:
string name_;
string email_;
};
class AuthorList {
public:
int record(Author const & a);
void record(int id, Author const & a);
Author const & get(int id);
typedef std::map<int, Author> Authors;
Authors::const_iterator begin() const;
Authors::const_iterator end() const;
private:
Authors authors_;
};
bool operator==(Author const & l, Author const & r);
std::ostream & operator<<(std::ostream & os, Author const & a);
std::istream & operator>>(std::istream & os, Author & a);
#endif // AUTHOR_H

View 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,7 +150,7 @@ extern BufferList bufferlist;
namespace {
const int LYX_FORMAT = 221;
const int LYX_FORMAT = 222;
} // namespace anon
@ -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
@ -298,6 +310,7 @@ 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;
@ -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;
}
}
@ -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");

View File

@ -26,6 +26,7 @@
#include "texrow.h"
#include "ParagraphList.h"
#include "paragraph.h"
#include "author.h"
#include <boost/shared_ptr.hpp>
@ -302,7 +303,14 @@ public:
/// Used when typesetting to place errorboxes.
TexRow texrow;
/// the author list for the document
AuthorList & authors();
private:
/// the author list
AuthorList authorlist;
/// is save needed
mutable bool lyx_clean;

View File

@ -569,3 +569,13 @@ Buffer * BufferList::loadLyXFile(string const & filename, bool tolastfiles)
return b;
}
void BufferList::setCurrentAuthor(string const & name, string const & email)
{
BufferStorage::iterator it = bstore.begin();
BufferStorage::iterator end = bstore.end();
for (; it != end; ++it) {
(*it)->authors().record(0, Author(name, email));
}
}

View File

@ -160,6 +160,10 @@ public:
Buffer * getBuffer(string const &);
/// returns a pointer to the buffer with the given number.
Buffer * getBuffer(unsigned int);
/// reset current author for all buffers
void setCurrentAuthor(string const & name, string const & email);
private:
/// ask to save a buffer on quit
bool qwriteOne(Buffer * buf, string const & fname,

View File

@ -54,6 +54,7 @@ BufferParams::BufferParams()
use_amsmath = false;
use_natbib = false;
use_numerical_citations = false;
tracking_changes = false;
secnumdepth = 3;
tocdepth = 3;
language = default_language;
@ -178,6 +179,8 @@ void BufferParams::writeFile(ostream & os) const
}
}
}
os << "\\tracking_changes " << tracking_changes << "\n";
}

View File

@ -214,6 +214,8 @@ public:
bool use_natbib;
///
bool use_numerical_citations;
/// revision tracking for this buffer ?
bool tracking_changes;
/// Time ago we agreed that this was a buffer property [ale990407]
string parentname;
private:

View File

@ -25,6 +25,8 @@
#include "language.h"
#include "gettext.h"
#include "ParagraphParameters.h"
#include "author.h"
#include "changes.h"
#include "frontends/Alert.h"
@ -148,12 +150,30 @@ string const currentState(BufferView * bv)
ostringstream state;
if (!bv->available())
return "";
return string();
LyXText * text = bv->getLyXText();
Buffer * buffer = bv->buffer();
LyXCursor const & c(text->cursor);
bool const show_change = buffer->params.tracking_changes
&& c.pos() != c.par()->size()
&& c.par()->lookupChange(c.pos()) != Change::UNCHANGED;
if (show_change) {
Change change(c.par()->lookupChangeFull(c.pos()));
Author const & a(bv->buffer()->authors().get(change.author));
state << _("Change: ") << a.name();
if (!a.email().empty()) {
state << " (" << a.email() << ")";
}
if (change.changetime)
state << _(" at ") << ctime(&change.changetime);
state << " : ";
}
// I think we should only show changes from the default
// font. (Asger)
LyXText * text = bv->getLyXText();
Buffer * buffer = bv->buffer();
LyXFont font = text->real_current_font;
LyXFont const & defaultfont =
buffer->params.getLyXTextClass().defaultfont();

526
src/changes.C Normal file
View File

@ -0,0 +1,526 @@
/**
* \file changes.C
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* Record changes in a paragraph.
*
* \author John Levon <levon@movementarian.org>
*/
#include <config.h>
#include "changes.h"
#include "debug.h"
#include "author.h"
#include "support/LAssert.h"
#include "support/LOstream.h"
using std::vector;
using std::endl;
using lyx::pos_type;
bool operator==(Change const & l, Change const & r)
{
return l.type == r.type && l.author == r.author
&& l.changetime == r.changetime;
}
bool operator!=(Change const & l, Change const & r)
{
return !(l == r);
}
bool operator==(Changes::Range const & r1, Changes::Range const & r2)
{
return r1.start == r2.start && r1.end == r2.end;
}
bool operator!=(Changes::Range const & r1, Changes::Range const & r2)
{
return !(r1 == r2);
}
bool Changes::Range::contains(Range const & r) const
{
return r.start >= start && r.end <= end;
}
bool Changes::Range::contained(Range const & r) const
{
return r.contains(*this);
}
bool Changes::Range::contains(pos_type pos) const
{
return pos >= start && pos < end;
}
bool Changes::Range::loose_contains(pos_type pos) const
{
return pos >= start && pos <= end;
}
bool Changes::Range::intersects(Range const & r) const
{
return contained(r) || contains(r)
|| contains(r.start) || contains(r.end);
}
Changes::Changes(Change::Type type)
: empty_type_(type)
{
}
Changes::~Changes()
{
}
Changes::Changes(Changes const & c)
{
table_ = c.table_;
}
void Changes::record(Change change, pos_type pos)
{
lyxerr[Debug::CHANGES] << "record " << change.type
<< " at pos " << pos << " with total "
<< table_.size() << " changes." << endl;
switch (change.type) {
case Change::INSERTED:
add(change, pos);
break;
case Change::DELETED:
del(change, pos);
break;
case Change::UNCHANGED:
set(Change::UNCHANGED, pos);
break;
}
}
void Changes::set(Change change, pos_type pos)
{
set(change, pos, pos + 1);
}
void Changes::set(Change::Type type, pos_type pos)
{
set(type, pos, pos + 1);
}
void Changes::set(Change::Type type, pos_type start, pos_type end)
{
set(Change(type), start, end);
}
void Changes::set(Change change, pos_type start, pos_type end)
{
ChangeTable::iterator it = table_.begin();
lyxerr[Debug::CHANGES] << "changeset of " << change.type
<< " author " << change.author << " time " << change.changetime
<< " in range " << start << "," << end << endl;
Range const new_range(start, end);
// remove all sub-ranges
for (; it != table_.end();) {
if (new_range != it->range && it->range.contained(new_range)) {
lyxerr[Debug::CHANGES] << "Removing subrange "
<< it->range.start << "," << it->range.end << endl;
it = table_.erase(it);
} else {
++it;
}
}
it = table_.begin();
ChangeTable::iterator itend = table_.end();
// find a super-range
for (; it != itend; ++it) {
if (it->range.contains(new_range))
break;
}
if (it == itend) {
lyxerr[Debug::CHANGES] << "Inserting change at end" << endl;
table_.push_back(ChangeRange(start, end, change));
merge();
return;
}
if (change.type == it->change.type) {
lyxerr[Debug::CHANGES] << "Change set already." << endl;
it->change = change;
return;
}
ChangeRange c(*it);
lyxerr[Debug::CHANGES] << "Using change of type " << c.change.type
<< " over " << c.range.start << "," << c.range.end << endl;
// split head
if (c.range.start < start) {
it = table_.insert(it, ChangeRange(c.range.start, start, c.change));
lyxerr[Debug::CHANGES] << "Splitting head of type " << c.change.type
<< " over " << c.range.start << "," << start << endl;
++it;
}
// reset this as new type
it->range.start = start;
it->range.end = end;
it->change = change;
lyxerr[Debug::CHANGES] << "Resetting to new change" << endl;
// split tail
if (c.range.end > end) {
++it;
table_.insert(it, ChangeRange(end, c.range.end, c.change));
lyxerr[Debug::CHANGES] << "Splitting tail of type " << c.change.type
<< " over " << end << "," << c.range.end << endl;
}
check();
merge();
}
void Changes::erase(pos_type pos)
{
ChangeTable::iterator it = table_.begin();
ChangeTable::iterator end = table_.end();
bool found = false;
for (; it != end; ++it) {
Range & range(it->range);
lyxerr[Debug::CHANGES] << "era:Range of type " << it->change.type << " is "
<< it->range.start << "," << it->range.end << endl;
if (range.contains(pos)) {
found = true;
--range.end;
continue;
}
if (found) {
--range.start;
--range.end;
}
}
check();
merge();
}
void Changes::del(Change change, ChangeTable::size_type pos)
{
// this case happens when building from .lyx
if (table_.empty()) {
set(change, pos);
return;
}
ChangeTable::iterator it = table_.begin();
for (; it != table_.end(); ++it) {
Range & range(it->range);
if (range.contains(pos)) {
if (it->change.type != Change::INSERTED) {
set(change, pos);
} else {
erase(pos);
}
break;
} else if (range.loose_contains(pos) && it + 1 == table_.end()) {
// this case happens when building from .lyx
set(change, pos);
break;
}
}
}
void Changes::add(Change change, ChangeTable::size_type pos)
{
ChangeTable::iterator it = table_.begin();
ChangeTable::iterator end = table_.end();
bool found = false;
for (; it != end; ++it) {
Range & range(it->range);
if (!found && range.loose_contains(pos)) {
found = true;
lyxerr[Debug::CHANGES] << "Found range of "
<< range.start << "," << range.end << endl;
++range.end;
continue;
}
if (found) {
++range.start;
++range.end;
}
}
set(change, pos);
}
Change const Changes::lookupFull(pos_type pos) const
{
if (!table_.size()) {
lyxerr[Debug::CHANGES] << "Empty, type is " << empty_type_ << endl;
return Change(empty_type_);
}
ChangeTable::const_iterator it = table_.begin();
ChangeTable::const_iterator end = table_.end();
for (; it != end; ++it) {
if (it->range.contains(pos))
return it->change;
}
check();
lyx::Assert(0);
return Change(Change::UNCHANGED);
}
Change::Type Changes::lookup(pos_type pos) const
{
if (!table_.size()) {
lyxerr[Debug::CHANGES] << "Empty, type is " << empty_type_ << endl;
return empty_type_;
}
ChangeTable::const_iterator it = table_.begin();
ChangeTable::const_iterator end = table_.end();
for (; it != end; ++it) {
if (it->range.contains(pos))
return it->change.type;
}
check();
lyx::Assert(0);
return Change::UNCHANGED;
}
bool Changes::isChange(pos_type start, pos_type end) const
{
if (!table_.size()) {
lyxerr[Debug::CHANGES] << "Empty, type is " << empty_type_ << endl;
return empty_type_ != Change::UNCHANGED;
}
ChangeTable::const_iterator it = table_.begin();
ChangeTable::const_iterator itend = table_.end();
for (; it != itend; ++it) {
lyxerr[Debug::CHANGES] << "Looking for " << start << ","
<< end << " in " << it->range.start << ","
<< it->range.end << "of type " << it->change.type << endl;
if (it->range.intersects(Range(start, end))
&& it->change.type != Change::UNCHANGED) {
lyxerr[Debug::CHANGES] << "Found intersection of "
<< start << "," << end << " with "
<< it->range.start << "," << it->range.end
<< " of type " << it->change.type << endl;
return true;
}
}
return false;
}
bool Changes::isChangeEdited(lyx::pos_type start, lyx::pos_type end) const
{
if (!table_.size()) {
lyxerr[Debug::CHANGES] << "Empty, type is " << empty_type_ << endl;
return empty_type_ != Change::INSERTED;
}
ChangeTable::const_iterator it = table_.begin();
ChangeTable::const_iterator itend = table_.end();
for (; it != itend; ++it) {
if (it->range.intersects(Range(start, end ? end - 1 : 0))
&& it->change.type != Change::INSERTED) {
return true;
}
}
return false;
}
void Changes::merge()
{
lyxerr[Debug::CHANGES] << "Starting merge" << endl;
ChangeTable::iterator it = table_.begin();
while (it != table_.end()) {
lyxerr[Debug::CHANGES] << "Range of type " << it->change.type << " is "
<< it->range.start << "," << it->range.end << endl;
if (it->range.start == it->range.end) {
lyxerr[Debug::CHANGES] << "Removing empty range for pos "
<< it->range.start << endl;
table_.erase(it);
// start again
it = table_.begin();
continue;
}
if (it + 1 == table_.end())
break;
if (it->change == (it + 1)->change) {
lyxerr[Debug::CHANGES] << "Merging equal ranges "
<< it->range.start << "," << it->range.end
<< " and " << (it + 1)->range.start << ","
<< (it + 1)->range.end << endl;
(it + 1)->range.start = it->range.start;
table_.erase(it);
// start again
it = table_.begin();
continue;
}
++it;
}
lyxerr[Debug::CHANGES] << "Merge ended" << endl;
check();
}
void Changes::check() const
{
ChangeTable::const_iterator it = table_.begin();
ChangeTable::const_iterator end = table_.end();
bool dont_assert(true);
lyxerr[Debug::CHANGES] << "Changelist:" << endl;
for (; it != end; ++it) {
lyxerr[Debug::CHANGES] << "Range of type " << it->change.type << " is "
<< it->range.start << "," << it->range.end << " author "
<< it->change.author << " time " << it->change.changetime << endl;
if (it + 1 == end)
break;
Range const & range(it->range);
Range const & next((it + 1)->range);
if (range.end != next.start)
dont_assert = false;
}
lyxerr[Debug::CHANGES] << "End" << endl;
lyx::Assert(dont_assert);
}
int Changes::latexMarkChange(std::ostream & os, Change::Type old, Change::Type change)
{
if (old == change)
return 0;
string const start("\\changestart{}");
string const end("\\changeend{}");
string const son("\\overstrikeon{}");
string const soff("\\overstrikeoff{}");
int column = 0;
if (old == Change::DELETED) {
os << soff;
column += soff.length();
}
switch (change) {
case Change::UNCHANGED:
os << end;
column += end.length();
break;
case Change::DELETED:
if (old == Change::UNCHANGED) {
os << start;
column += start.length();
}
os << son;
column += son.length();
break;
case Change::INSERTED:
if (old == Change::UNCHANGED) {
os << start;
column += start.length();
}
break;
}
return column;
}
void Changes::lyxMarkChange(std::ostream & os, int & column, lyx::time_type curtime,
Change const & old, Change const & change)
{
if (old == change)
return;
column = 0;
switch (change.type) {
case Change::UNCHANGED:
os << "\n\\change_unchanged\n";
break;
case Change::DELETED: {
lyx::time_type t(change.changetime);
if (!t)
t = curtime;
os << "\n\\change_deleted " << change.author
<< " " << t << "\n";
break;
}
case Change::INSERTED:
lyx::time_type t(change.changetime);
if (!t)
t = curtime;
os << "\n\\change_inserted " << change.author
<< " " << t << "\n";
break;
}
}

150
src/changes.h Normal file
View File

@ -0,0 +1,150 @@
/**
* \file changes.h
* Copyright 2002 the LyX Team
* Read the file COPYING
*
* Record changes in a paragraph.
*
* \author John Levon <levon@movementarian.org>
*/
#ifndef CHANGES_H
#define CHANGES_H
#include "support/types.h"
#include "support/lyxtime.h"
#include <vector>
#include <iosfwd>
#include <ctime>
struct Change {
/// the type of change
enum Type {
UNCHANGED, // no change
INSERTED, // new text
DELETED // deleted text
};
Change(Type t = UNCHANGED, int a = 0, lyx::time_type ct = 0)
: type(t), author(a), changetime(ct) {}
Type type;
int author;
lyx::time_type changetime;
};
bool operator==(Change const & l, Change const & r);
bool operator!=(Change const & l, Change const & r);
class Changes {
public:
Changes(Change::Type type);
~Changes();
Changes(Changes const &);
/// reset "default" change type (for empty pars)
void reset(Change::Type type) {
empty_type_ = type;
}
/// set the position to the given change
void set(Change change, lyx::pos_type pos);
/// set the position to the given change
void set(Change::Type, lyx::pos_type pos);
/// set the range to the given change
void set(Change::Type, lyx::pos_type start, lyx::pos_type end);
/// set the range to the given change
void set(Change, lyx::pos_type start, lyx::pos_type end);
/// mark the given change and adjust
void record(Change, lyx::pos_type pos);
/// return the change type at the given position
Change::Type lookup(lyx::pos_type pos) const;
/// return the change at the given position
Change const lookupFull(lyx::pos_type pos) const;
/// return true if there is a change in the given range
bool isChange(lyx::pos_type start, lyx::pos_type end) const;
/// return true if there is a deleted or unchanged range contained
bool isChangeEdited(lyx::pos_type start, lyx::pos_type end) const;
/// remove the given entry
void erase(lyx::pos_type pos);
/// output latex to mark a transition between two changetypes
/// returns length of text outputted
static int latexMarkChange(std::ostream & os, Change::Type old, Change::Type change);
/// output .lyx file format for transitions between changes
static void lyxMarkChange(std::ostream & os, int & column,
lyx::time_type curtime, Change const & old, Change const & change);
private:
struct Range {
Range(lyx::pos_type s, lyx::pos_type e)
: start(s), end(e) {}
// does this range contain r ?
bool contains(Range const & r) const;
// does this range contain pos ?
bool contains(lyx::pos_type pos) const;
// does this range contain pos, or can it be appended ?
bool loose_contains(lyx::pos_type pos) const;
// is this range contained within r ?
bool contained(Range const & r) const;
// do the ranges intersect ?
bool intersects(Range const & r) const;
lyx::pos_type start;
lyx::pos_type end;
};
friend bool operator==(Range const & r1, Range const & r2);
friend bool operator!=(Range const & r1, Range const & r2);
struct ChangeRange {
ChangeRange(lyx::pos_type s, lyx::pos_type e, Change c)
: range(Range(s, e)), change(c) {}
Range range;
Change change;
};
typedef std::vector<ChangeRange> ChangeTable;
/// our table of changes
ChangeTable table_;
/// change type for an empty paragraph
Change::Type empty_type_;
/// handle a delete
void del(Change change, ChangeTable::size_type pos);
/// handle an add
void add(Change change, ChangeTable::size_type pos);
/// merge neighbouring ranges
void merge();
/// consistency check
void check() const;
};
#endif // CHANGES_H

View File

@ -290,6 +290,12 @@ enum kb_action {
LFUN_MOUSE_TRIPLE, // André 9 Aug 2002
LFUN_EDIT, // André 16 Aug 2002
LFUN_INSET_WRAP, // Dekel 7 Apr 2002
LFUN_TRACK_CHANGES, // Levon 20021001 (cool date !)
LFUN_MERGE_CHANGES, // Levon 20021016
LFUN_ACCEPT_CHANGE, // Levon 20021016
LFUN_REJECT_CHANGE, // Levon 20021016
LFUN_ACCEPT_ALL_CHANGES, // Levon 20021016
LFUN_REJECT_ALL_CHANGES, // Levon 20021016
LFUN_LASTACTION /* this marks the end of the table */
};

View File

@ -58,6 +58,7 @@ error_item errorTags[] = {
{ Debug::WORKAREA, "workarea", N_("Workarea events")},
{ Debug::INSETTEXT, "insettext", N_("Insettext/tabular messages")},
{ Debug::GRAPHICS, "graphics", N_("Graphics conversion and loading")},
{ Debug::CHANGES, "changes", N_("Change tracking")},
{ Debug::ANY, "any", N_("All debugging messages")}
};
@ -73,7 +74,7 @@ Debug::type const Debug::ANY = Debug::type(
Debug::MATHED | Debug::FONT | Debug::TCLASS | Debug::LYXVC |
Debug::LYXSERVER | Debug::ROFF | Debug::ACTION | Debug::LYXLEX |
Debug::DEPEND | Debug::INSETS | Debug::FILES | Debug::WORKAREA |
Debug::INSETTEXT | Debug::GRAPHICS);
Debug::INSETTEXT | Debug::GRAPHICS | Debug::CHANGES);
Debug::type Debug::value(string const & val)

View File

@ -72,7 +72,9 @@ struct Debug {
///
INSETTEXT = (1 << 20),
///
GRAPHICS = (1 << 21)
GRAPHICS = (1 << 21),
/// change tracking
CHANGES = (1 << 22)
};
///
static type const ANY;

View File

@ -1,3 +1,7 @@
2003-02-08 John Levon <levon@movementarian.org>
* Dialogs.h: add showMergeChanges()
2003-01-11 Juergen Spitzmueller <j.spitzmueller@gmx.de>
* FileDialog.h: implement opendir (browse directory) [bug 824]

View File

@ -126,6 +126,8 @@ public:
void showLogFile();
/// display the top-level maths panel
void showMathPanel();
/// show the merge changes dialog
void showMergeChanges();
///
void showMinipage(InsetMinipage *);
///

View File

@ -1,3 +1,12 @@
2003-02-08 John Levon <levon@movementarian.org>
* Makefile.am:
* ControlChanges.h:
* ControlChanges.C: add merge changes dialog
* ControlPrefs.h:
* ControlPrefs.C: add setCurrentAuthor()
2003-01-31 Angus Leeming <leeming@lyx.org>
* ViewBase.h: add an isVisible() pure virtual method.

View File

@ -0,0 +1,82 @@
/**
* \file ControlChanges.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#include <config.h>
#ifdef __GNUG__
#pragma implementation
#endif
#include "ViewBase.h"
#include "ButtonControllerBase.h"
#include "ControlChanges.h"
#include "frontends/Dialogs.h"
#include "frontends/LyXView.h"
#include "buffer.h"
#include "lyxfind.h"
#include "lyxfunc.h"
#include "debug.h"
#include "BufferView.h"
#include "support/lstrings.h"
#include "funcrequest.h"
#include "author.h"
ControlChanges::ControlChanges(LyXView & lv, Dialogs & d)
: ControlDialogBD(lv, d)
{
}
void ControlChanges::find()
{
lyxfind::findNextChange(bufferview());
}
string const ControlChanges::getChangeDate()
{
Change c(bufferview()->getCurrentChange());
if (c.type == Change::UNCHANGED || !c.changetime)
return string();
return ctime(&c.changetime);
}
string const ControlChanges::getChangeAuthor()
{
Change c(bufferview()->getCurrentChange());
if (c.type == Change::UNCHANGED)
return string();
Author const & a(bufferview()->buffer()->authors().get(c.author));
string author(a.name());
if (!a.email().empty()) {
author += " (";
author += a.email() + ")";
}
return author;
}
void ControlChanges::accept()
{
lv_.dispatch(FuncRequest(LFUN_ACCEPT_CHANGE));
lyxfind::findNextChange(bufferview());
}
void ControlChanges::reject()
{
lv_.dispatch(FuncRequest(LFUN_REJECT_CHANGE));
lyxfind::findNextChange(bufferview());
}

View File

@ -0,0 +1,49 @@
// -*- C++ -*-
/**
* \file ControlChanges.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#ifndef CONTROLCHANGES_H
#define CONTROLCHANGES_H
#ifdef __GNUG__
#pragma interface
#endif
#include "ControlDialog_impl.h"
#include "LString.h"
/**
* A controller for the merge changes dialog.
*/
class ControlChanges : public ControlDialogBD {
public:
ControlChanges(LyXView &, Dialogs &);
/// find the next merge chunk and highlight it
void find();
/// return date of change
string const getChangeDate();
/// return author of change
string const getChangeAuthor();
/// accept the current merge
void accept();
/// reject the current merge
void reject();
private:
/// not needed.
virtual void apply() {}
};
#endif // CONTROLCHANGES_H

View File

@ -20,6 +20,7 @@
#include "ViewBase.h"
#include "frontends/LyXView.h"
#include "bufferlist.h"
#include "helper_funcs.h"
#include "gettext.h"
#include "support/filetools.h"
@ -29,6 +30,7 @@
extern string system_lyxdir;
extern string user_lyxdir;
extern BufferList bufferlist;
using std::endl;
using std::pair;
@ -153,3 +155,9 @@ void ControlPrefs::setFormats(Formats const & form)
{
formats = form;
}
void ControlPrefs::setCurrentAuthor()
{
bufferlist.setCurrentAuthor(rc_.user_name, rc_.user_email);
}

View File

@ -66,6 +66,9 @@ public:
/// set global formats
void setFormats(Formats const & form);
/// reset the details for the current author for all buffers
void setCurrentAuthor();
private:
/// get current lyxrc
virtual void setParams();

View File

@ -31,6 +31,8 @@ libcontrollers_la_SOURCES= \
ControlButtons.h \
ControlCharacter.C \
ControlCharacter.h \
ControlChanges.C \
ControlChanges.h \
ControlCitation.C \
ControlCitation.h \
ControlCommand.C \

View File

@ -1,3 +1,18 @@
2003-02-08 John Levon <levon@movementarian.org>
* Makefile.am:
* forms/Makefile.am:
* forms/form_changes.fd:
* Dialogs.C:
* Dialogs2.C:
* Dialogs_impl.h:
* FormChanges.h:
* FormChanges.C: add changes dialog
* FormPreferences.h:
* FormPreferences.C:
* forms/form_preferences.fd: add Identity prefs
2003-01-31 Michael Schmitt <michael.schmitt@teststep.org>
* FormDocument.C:

View File

@ -48,6 +48,7 @@ Dialogs::Impl::Impl(LyXView & lv, Dialogs & d)
: aboutlyx(lv, d),
bibitem(lv, d),
bibtex(lv, d),
changes(lv, d),
character(lv, d),
citation(lv, d),
document(lv, d),

View File

@ -37,6 +37,12 @@ void Dialogs::showBibtex(InsetCommand * ic)
}
void Dialogs::showMergeChanges()
{
pimpl_->changes.controller().show();
}
void Dialogs::showCharacter()
{
pimpl_->character.controller().show();

View File

@ -37,6 +37,10 @@
#include "FormBrowser.h"
#include "forms/form_browser.h"
#include "ControlChanges.h"
#include "FormChanges.h"
#include "forms/form_changes.h"
#include "ControlCharacter.h"
#include "FormCharacter.h"
#include "forms/form_character.h"
@ -170,6 +174,9 @@ BibitemDialog;
typedef GUI<ControlBibtex, FormBibtex, NoRepeatedApplyReadOnlyPolicy, xformsBC>
BibtexDialog;
typedef GUI<ControlChanges, FormChanges, NoRepeatedApplyReadOnlyPolicy, xformsBC>
ChangesDialog;
typedef GUI<ControlCharacter, FormCharacter, OkApplyCancelReadOnlyPolicy, xformsBC>
CharacterDialog;
@ -271,6 +278,7 @@ struct Dialogs::Impl {
AboutlyxDialog aboutlyx;
BibitemDialog bibitem;
BibtexDialog bibtex;
ChangesDialog changes;
CharacterDialog character;
CitationDialog citation;
DocumentDialog document;

View File

@ -0,0 +1,81 @@
/**
* \file FormChanges.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#include <config.h>
#ifdef __GNUG__
#pragma implementation
#endif
#include "xformsBC.h"
#include "ControlChanges.h"
#include "FormChanges.h"
#include "forms/form_changes.h"
#include FORMS_H_LOCATION
typedef FormCB<ControlChanges, FormDB<FD_changes> > base_class;
FormChanges::FormChanges()
: base_class(_("LyX: Merge changes"))
{}
void FormChanges::build()
{
dialog_.reset(build_changes(this));
bc().setCancel(dialog_->button_close);
bc().addReadOnly(dialog_->button_accept);
bc().addReadOnly(dialog_->button_reject);
}
void FormChanges::update()
{
fl_set_object_label(dialog_->author, "");
fl_set_object_label(dialog_->date, "");
// FIXME: enable/disable accept/reject
}
ButtonPolicy::SMInput FormChanges::input(FL_OBJECT * obj, long)
{
if (obj == dialog_->button_accept) {
controller().accept();
return ButtonPolicy::SMI_VALID;
}
if (obj == dialog_->button_reject) {
controller().reject();
return ButtonPolicy::SMI_VALID;
}
if (obj != dialog_->button_next)
return ButtonPolicy::SMI_VALID;
controller().find();
string author(controller().getChangeAuthor());
string date(controller().getChangeDate());
if (!date.empty()) {
date = _("Changed at : ") + date;
}
if (!author.empty()) {
author = _("Change made by : ") + author;
}
fl_set_object_label(dialog_->author, author.c_str());
fl_set_object_label(dialog_->date, date.c_str());
// Yes, this is needed.
fl_redraw_form(form());
return ButtonPolicy::SMI_VALID;
}

View File

@ -0,0 +1,43 @@
// -*- C++ -*-
/**
* \file FormChanges.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#ifndef FORMCHANGES_H
#define FORMCHANGES_H
#ifdef __GNUG__
#pragma interface
#endif
#include "FormBase.h"
class ControlChanges;
struct FD_changes;
/**
* This class provides an XForms implementation of the Merge Changes Dialog.
*/
class FormChanges : public FormCB<ControlChanges, FormDB<FD_changes> > {
public:
FormChanges();
private:
/// not needed.
virtual void apply() {}
/// Build the dialog
virtual void build();
/// update the dialog
virtual void update();
/// Filter the inputs
virtual ButtonPolicy::SMInput input(FL_OBJECT *, long);
};
#endif // FORMCHANGES_H

View File

@ -36,6 +36,7 @@
#include "LColor.h"
#include "Lsstream.h"
#include "funcrequest.h"
#include "author.h"
#include "support/lyxfunctional.h"
#include "support/lyxmanip.h"
@ -97,8 +98,9 @@ FormPreferences::FormPreferences()
: base_class(_("Preferences"), false),
colors_(*this), converters_(*this), inputs_misc_(*this),
formats_(*this), interface_(*this), language_(*this),
lnf_misc_(*this), outputs_misc_(*this), paths_(*this),
printer_(*this), screen_fonts_(*this), spelloptions_(*this)
lnf_misc_(*this), identity_(*this), outputs_misc_(*this),
paths_(*this), printer_(*this), screen_fonts_(*this),
spelloptions_(*this)
{
}
@ -175,6 +177,7 @@ void FormPreferences::build()
interface_.build();
language_.build();
lnf_misc_.build();
identity_.build();
outputs_misc_.build();
paths_.build();
printer_.build();
@ -212,6 +215,9 @@ void FormPreferences::build()
fl_addto_tabfolder(look_n_feel_tab_->tabfolder_inner,
_("Misc"),
lnf_misc_.dialog()->form);
fl_addto_tabfolder(look_n_feel_tab_->tabfolder_inner,
_("Identity"),
identity_.dialog()->form);
// then build converters
fl_addto_tabfolder(converters_tab_->tabfolder_inner,
@ -277,6 +283,7 @@ void FormPreferences::apply()
interface_.apply(rc);
language_.apply(rc);
lnf_misc_.apply(rc);
identity_.apply(rc);
outputs_misc_.apply(rc);
paths_.apply(rc);
printer_.apply(rc);
@ -371,6 +378,7 @@ void FormPreferences::update()
interface_.update(rc);
language_.update(rc);
lnf_misc_.update(rc);
identity_.update(rc);
outputs_misc_.update(rc);
paths_.update(rc);
printer_.update(rc);
@ -1424,6 +1432,40 @@ bool FormPreferences::Formats::Input()
}
FormPreferences::Identity::Identity(FormPreferences & p)
: parent_(p)
{}
FD_preferences_identity const * FormPreferences::Identity::dialog()
{
return dialog_.get();
}
void FormPreferences::Identity::apply(LyXRC & rc) const
{
rc.user_name = fl_get_input(dialog_->input_user_name);
rc.user_email = fl_get_input(dialog_->input_user_email);
parent_.controller().setCurrentAuthor();
}
void FormPreferences::Identity::build()
{
dialog_.reset(build_preferences_identity(&parent_));
fl_set_input_return(dialog_->input_user_name, FL_RETURN_CHANGED);
fl_set_input_return(dialog_->input_user_email, FL_RETURN_CHANGED);
}
void FormPreferences::Identity::update(LyXRC const & rc)
{
fl_set_input(dialog_->input_user_name, rc.user_name.c_str());
fl_set_input(dialog_->input_user_email, rc.user_email.c_str());
}
FormPreferences::InputsMisc::InputsMisc(FormPreferences & p)
: parent_(p)
{}

View File

@ -41,6 +41,7 @@ struct FD_preferences_inputs_misc;
struct FD_preferences_interface;
struct FD_preferences_language;
struct FD_preferences_lnf_misc;
struct FD_preferences_identity;
struct FD_preferences_inner_tab;
struct FD_preferences_outputs_misc;
struct FD_preferences_paths;
@ -336,6 +337,29 @@ private:
///
friend class LnFmisc;
class Identity {
public:
///
Identity(FormPreferences & p);
///
FD_preferences_identity const * dialog();
///
void apply(LyXRC & rc) const;
///
void build();
///
string const feedback(FL_OBJECT const * const) const;
///
void update(LyXRC const & rc);
private:
///
FormPreferences & parent_;
///
boost::scoped_ptr<FD_preferences_identity> dialog_;
};
friend class Identity;
///
class OutputsMisc {
public:
@ -485,6 +509,8 @@ private:
///
LnFmisc lnf_misc_;
///
Identity identity_;
///
OutputsMisc outputs_misc_;
///
Paths paths_;

View File

@ -66,6 +66,8 @@ libxforms_la_SOURCES = \
FormBibtex.h \
FormBrowser.C \
FormBrowser.h \
FormChanges.C \
FormChanges.h \
FormCharacter.C \
FormCharacter.h \
FormCitation.C \

View File

@ -11,6 +11,7 @@ SRCS = form_aboutlyx.fd \
form_bibitem.fd \
form_bibtex.fd \
form_browser.fd \
form_changes.fd \
form_character.fd \
form_citation.fd \
form_document.fd \

View File

@ -0,0 +1,160 @@
Magic: 13000
Internal Form Definition File
(do not change)
Number of forms: 1
Unit of measure: FL_COORD_PIXEL
=============== FORM ===============
Name: form_changes
Width: 400
Height: 190
Number of Objects: 8
--------------------
class: FL_BOX
type: UP_BOX
box: 0 0 400 190
boxtype: FL_UP_BOX
colors: FL_COL1 FL_COL1
alignment: FL_ALIGN_CENTER
style: FL_NORMAL_STYLE
size: FL_DEFAULT_SIZE
lcol: FL_BLACK
label:
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name:
callback:
argument:
--------------------
class: FL_BUTTON
type: NORMAL_BUTTON
box: 270 110 120 30
boxtype: FL_UP_BOX
colors: FL_COL1 FL_COL1
alignment: FL_ALIGN_CENTER
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: Reject change|#R
shortcut:
resize: FL_RESIZE_NONE
gravity: FL_SouthEast FL_SouthEast
name: button_reject
callback: C_FormBaseInputCB
argument: 0
--------------------
class: FL_BUTTON
type: NORMAL_BUTTON
box: 10 110 100 30
boxtype: FL_UP_BOX
colors: FL_COL1 FL_COL1
alignment: FL_ALIGN_CENTER
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: Next change|#N
shortcut:
resize: FL_RESIZE_NONE
gravity: FL_SouthEast FL_SouthEast
name: button_next
callback: C_FormBaseInputCB
argument: 0
--------------------
class: FL_BUTTON
type: NORMAL_BUTTON
box: 130 110 120 30
boxtype: FL_UP_BOX
colors: FL_COL1 FL_COL1
alignment: FL_ALIGN_CENTER
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: Accept change|#A
shortcut:
resize: FL_RESIZE_NONE
gravity: FL_SouthEast FL_SouthEast
name: button_accept
callback: C_FormBaseInputCB
argument: 0
--------------------
class: FL_BUTTON
type: NORMAL_BUTTON
box: 310 150 80 30
boxtype: FL_UP_BOX
colors: FL_COL1 FL_COL1
alignment: FL_ALIGN_CENTER
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: Close|^[
shortcut:
resize: FL_RESIZE_NONE
gravity: FL_SouthEast FL_SouthEast
name: button_close
callback: C_FormBaseCancelCB
argument: 0
--------------------
class: FL_TEXT
type: NORMAL_TEXT
box: 10 10 150 20
boxtype: FL_FLAT_BOX
colors: FL_COL1 FL_MCOL
alignment: FL_ALIGN_LEFT|FL_ALIGN_INSIDE
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: Accept change ?
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name:
callback:
argument:
--------------------
class: FL_TEXT
type: NORMAL_TEXT
box: 10 40 380 30
boxtype: FL_NO_BOX
colors: FL_COL1 FL_MCOL
alignment: FL_ALIGN_LEFT|FL_ALIGN_INSIDE
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: text
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name: author
callback:
argument:
--------------------
class: FL_TEXT
type: NORMAL_TEXT
box: 10 70 380 30
boxtype: FL_NO_BOX
colors: FL_COL1 FL_MCOL
alignment: FL_ALIGN_LEFT|FL_ALIGN_INSIDE
style: FL_NORMAL_STYLE
size: FL_NORMAL_SIZE
lcol: FL_BLACK
label: text
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name: date
callback:
argument:
==============================
--------------------

View File

@ -3,7 +3,7 @@ Magic: 13000
Internal Form Definition File
(do not change)
Number of forms: 14
Number of forms: 15
Unit of measure: FL_COORD_PIXEL
SnapGrid: 5
@ -1222,6 +1222,66 @@ name: choice_display
callback: C_FormBaseInputCB
argument: 0
=============== FORM ===============
Name: form_preferences_identity
Width: 450
Height: 350
Number of Objects: 3
--------------------
class: FL_BOX
type: FLAT_BOX
box: 0 0 450 350
boxtype: FL_FLAT_BOX
colors: FL_COL1 FL_COL1
alignment: FL_ALIGN_CENTER
style: FL_NORMAL_STYLE
size: FL_DEFAULT_SIZE
lcol: FL_BLACK
label:
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name:
callback:
argument:
--------------------
class: FL_INPUT
type: NORMAL_INPUT
box: 125 25 220 35
boxtype: FL_DOWN_BOX
colors: FL_COL1 FL_MCOL
alignment: FL_ALIGN_LEFT
style: FL_NORMAL_STYLE
size: FL_DEFAULT_SIZE
lcol: FL_BLACK
label: Real name : |#R
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name: input_user_name
callback: C_FormBaseInputCB
argument: 0
--------------------
class: FL_INPUT
type: NORMAL_INPUT
box: 125 80 220 35
boxtype: FL_DOWN_BOX
colors: FL_COL1 FL_MCOL
alignment: FL_ALIGN_LEFT
style: FL_NORMAL_STYLE
size: FL_DEFAULT_SIZE
lcol: FL_BLACK
label: Email address : |#E
shortcut:
resize: FL_RESIZE_ALL
gravity: FL_NoGravity FL_NoGravity
name: input_user_email
callback: C_FormBaseInputCB
argument: 0
=============== FORM ===============
Name: form_preferences_spelloptions
Width: 450

View File

@ -1,3 +1,20 @@
2003-02-08 John Levon <levon@movementarian.org>
* inset.h:
* inset.C:
* insetcollapsable.h:
* insetcollapsable.C:
* insettabular.h:
* insettabular.C:
* insettext.h:
* insettext.C:
add nextChange(). Make allowSpellcheck() const. Add markErased().
* insetert.C: ignore deleted text
* insettabular.C: make sure to keep change tracking working
properly.
2003-01-20 Michael Schmitt <michael.schmitt@teststep.org>
* insetert.C:

View File

@ -361,6 +361,14 @@ UpdatableInset::selectNextWordToSpellcheck(BufferView *bv, float & value) const
}
bool UpdatableInset::nextChange(BufferView * bv, lyx::pos_type &)
{
// we have to unlock ourself in this function by default!
bv->unlockInset(const_cast<UpdatableInset *>(this));
return false;
}
bool UpdatableInset::searchForward(BufferView * bv, string const &,
bool, bool)
{

View File

@ -23,6 +23,7 @@
#include "LString.h"
#include "LColor.h"
#include "frontends/mouse_state.h"
#include "support/types.h"
class LyXFont;
class BufferView;
@ -335,7 +336,7 @@ public:
///
// needed for spellchecking text
///
virtual bool allowSpellcheck() { return false; }
virtual bool allowSpellcheck() const { return false; }
// should this inset be handled like a normal charater
virtual bool isChar() const { return false; }
@ -361,6 +362,9 @@ public:
minipage somewhere, it will be the width of this minipage */
virtual int latexTextWidth(BufferView *) const;
/// mark the inset contents as erased (for change tracking)
virtual void markErased() {}
/** Adds a LaTeX snippet to the Preview Loader for transformation
* into a bitmap image. Does not start the laoding process.
*
@ -519,16 +523,20 @@ public:
///
// needed for spellchecking text
///
virtual bool allowSpellcheck() { return false; }
virtual bool allowSpellcheck() const { return false; }
///
virtual WordLangTuple const
selectNextWordToSpellcheck(BufferView *, float & value) const;
///
virtual void selectSelectedWord(BufferView *) { return; }
virtual void selectSelectedWord(BufferView *) {}
///
virtual void toggleSelection(BufferView *, bool /*kill_selection*/) {
return;
}
/// find the next change in the inset
virtual bool nextChange(BufferView * bv, lyx::pos_type & length);
///
// needed for search/replace functionality
///

View File

@ -669,6 +669,24 @@ void InsetCollapsable::setLabel(string const & l) const
}
void InsetCollapsable::markErased()
{
inset.markErased();
}
bool InsetCollapsable::nextChange(BufferView * bv, lyx::pos_type & length)
{
bool found = inset.nextChange(bv, length);
if (first_after_edit && !found)
close(bv);
else if (!found)
first_after_edit = false;
return found;
}
bool InsetCollapsable::searchForward(BufferView * bv, string const & str,
bool cs, bool mw)
{

View File

@ -169,7 +169,7 @@ public:
///
void close(BufferView *) const;
///
bool allowSpellcheck() { return inset.allowSpellcheck(); }
bool allowSpellcheck() const { return inset.allowSpellcheck(); }
///
WordLangTuple const
selectNextWordToSpellcheck(BufferView *, float &) const;
@ -181,6 +181,11 @@ public:
void toggleSelection(BufferView * bv, bool kill_selection) {
inset.toggleSelection(bv, kill_selection);
}
void markErased();
bool nextChange(BufferView * bv, lyx::pos_type & length);
///
bool searchForward(BufferView * bv, string const & str,
bool = true, bool = false);

View File

@ -351,6 +351,10 @@ int InsetERT::latex(Buffer const *, ostream & os, bool /*fragile*/,
while (par) {
pos_type siz = par->size();
for (pos_type i = 0; i < siz; ++i) {
// ignore all struck out text
if (isDeletedText(par, i))
continue;
Paragraph::value_type c = par->getChar(i);
switch (c) {
case Paragraph::META_NEWLINE:

View File

@ -105,7 +105,7 @@ public:
///
void close(BufferView *) const;
///
bool allowSpellcheck() { return false; }
bool allowSpellcheck() const { return false; }
WordLangTuple const
selectNextWordToSpellcheck(BufferView *, float &) const;

View File

@ -1171,7 +1171,7 @@ Inset::RESULT InsetTabular::localDispatch(FuncRequest const & cmd)
setUndo(bv, Undo::DELETE,
bv->text->cursor.par(),
bv->text->cursor.par()->next());
cutSelection();
cutSelection(bv->buffer()->params);
updateLocal(bv, INIT, true);
break;
case LFUN_COPY:
@ -2577,13 +2577,14 @@ bool InsetTabular::pasteSelection(BufferView * bv)
*(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
tabular->GetCellInset(n2)->setOwner(this);
tabular->GetCellInset(n2)->deleteLyXText(bv);
tabular->GetCellInset(n2)->markNew();
}
}
return true;
}
bool InsetTabular::cutSelection()
bool InsetTabular::cutSelection(BufferParams const & bp)
{
if (!hasSelection())
return false;
@ -2606,7 +2607,7 @@ bool InsetTabular::cutSelection()
}
for (int i = sel_row_start; i <= sel_row_end; ++i) {
for (int j = sel_col_start; j <= sel_col_end; ++j) {
tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear();
tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear(bp.tracking_changes);
}
}
return true;
@ -2788,6 +2789,46 @@ void InsetTabular::toggleSelection(BufferView * bv, bool kill_selection)
}
void InsetTabular::markErased()
{
int cell = 0;
while (!tabular->IsLastCell(cell)) {
++cell;
InsetText * inset = tabular->GetCellInset(cell);
inset->markErased();
}
}
bool InsetTabular::nextChange(BufferView * bv, lyx::pos_type & length)
{
if (the_locking_inset) {
if (the_locking_inset->nextChange(bv, length)) {
updateLocal(bv, CELL, false);
return true;
}
if (tabular->IsLastCell(actcell))
return false;
++actcell;
}
InsetText * inset = tabular->GetCellInset(actcell);
if (inset->nextChange(bv, length)) {
updateLocal(bv, FULL, false);
return true;
}
while (!tabular->IsLastCell(actcell)) {
++actcell;
inset = tabular->GetCellInset(actcell);
if (inset->nextChange(bv, length)) {
updateLocal(bv, FULL, false);
return true;
}
}
return false;
}
bool InsetTabular::searchForward(BufferView * bv, string const & str,
bool cs, bool mw)
{
@ -2911,12 +2952,14 @@ bool InsetTabular::insertAsciiString(BufferView * bv, string const & buf,
ocol = actcol;
row = actrow;
}
string::size_type op = 0;
int cells = loctab->GetNumberOfCells();
p = 0;
cols = ocol;
rows = loctab->rows();
int const columns = loctab->columns();
while ((cell < cells) && (p < len) && (row < rows) &&
(p = buf.find_first_of("\t\n", p)) != string::npos)
{

View File

@ -63,6 +63,7 @@ class LyXLex;
class Painter;
class BufferView;
class Buffer;
class BufferParams;
class Paragraph;
class InsetTabular : public UpdatableInset {
@ -208,7 +209,7 @@ public:
///
LyXCursor const & cursor(BufferView *) const;
///
bool allowSpellcheck() { return true; }
bool allowSpellcheck() const { return true; }
///
WordLangTuple const
selectNextWordToSpellcheck(BufferView *, float & value) const;
@ -216,6 +217,11 @@ public:
void selectSelectedWord(BufferView *);
///
void toggleSelection(BufferView *, bool kill_selection);
void markErased();
/// find next change
bool nextChange(BufferView *, lyx::pos_type & length);
///
bool searchForward(BufferView *, string const &,
bool = true, bool = false);
@ -316,7 +322,7 @@ private:
///
bool pasteSelection(BufferView *);
///
bool cutSelection();
bool cutSelection(BufferParams const & bp);
///
bool isRightToLeft(BufferView *);
///

View File

@ -146,6 +146,8 @@ InsetText::InsetText(BufferParams const & bp)
{
paragraphs.set(new Paragraph);
paragraphs.begin()->layout(bp.getLyXTextClass().defaultLayout());
if (bp.tracking_changes)
paragraphs.begin()->trackChanges();
init();
}
@ -208,8 +210,18 @@ InsetText::~InsetText()
}
void InsetText::clear()
void InsetText::clear(bool just_mark_erased)
{
if (just_mark_erased) {
ParagraphList::iterator it = paragraphs.begin();
ParagraphList::iterator end = paragraphs.end();
for (; it != end; ++it) {
it->markErased();
}
need_update = FULL;
return;
}
// This is a gross hack...
LyXLayout_ptr old_layout = paragraphs.begin()->layout();
@ -255,7 +267,10 @@ void InsetText::read(Buffer const * buf, LyXLex & lex)
Paragraph::depth_type depth = 0;
LyXFont font(LyXFont::ALL_INHERIT);
clear();
clear(false);
if (buf->params.tracking_changes)
paragraphs.begin()->trackChanges();
while (lex.isOK()) {
lex.nextToken();
@ -2129,9 +2144,24 @@ void InsetText::setParagraphData(Paragraph * p, bool same_id)
}
void InsetText::markNew(bool track_changes)
{
ParagraphList::iterator pit = paragraphs.begin();
ParagraphList::iterator pend = paragraphs.end();
for (; pit != pend; ++pit) {
if (track_changes) {
pit->trackChanges();
} else {
// no-op when not tracking
pit->cleanChanges();
}
}
}
void InsetText::setText(string const & data, LyXFont const & font)
{
clear();
clear(false);
for (unsigned int i = 0; i < data.length(); ++i)
paragraphs.begin()->insertChar(i, data[i], font);
reinitLyXText();
@ -2659,6 +2689,36 @@ void InsetText::toggleSelection(BufferView * bv, bool kill_selection)
}
bool InsetText::nextChange(BufferView * bv, lyx::pos_type & length)
{
bool clear = false;
if (!lt) {
lt = getLyXText(bv);
clear = true;
}
if (the_locking_inset) {
if (the_locking_inset->nextChange(bv, length))
return true;
lt->cursorRight(bv, true);
}
lyxfind::SearchResult result =
lyxfind::findNextChange(bv, lt, length);
if (result == lyxfind::SR_FOUND) {
LyXCursor cur = lt->cursor;
bv->unlockInset(bv->theLockingInset());
if (bv->lockInset(this))
locked = true;
lt->cursor = cur;
lt->setSelectionRange(bv, length);
updateLocal(bv, SELECTION, false);
}
if (clear)
lt = 0;
return result != lyxfind::SR_NOT_FOUND;
}
bool InsetText::searchForward(BufferView * bv, string const & str,
bool cs, bool mw)
{
@ -2681,7 +2741,7 @@ bool InsetText::searchForward(BufferView * bv, string const & str,
if (bv->lockInset(this))
locked = true;
lt->cursor = cur;
lt->setSelectionOverString(bv, str);
lt->setSelectionRange(bv, str.length());
updateLocal(bv, SELECTION, false);
}
if (clear)
@ -2716,7 +2776,7 @@ bool InsetText::searchBackward(BufferView * bv, string const & str,
if (bv->lockInset(this))
locked = true;
lt->cursor = cur;
lt->setSelectionOverString(bv, str);
lt->setSelectionRange(bv, str.length());
updateLocal(bv, SELECTION, false);
}
if (clear)
@ -2776,12 +2836,16 @@ void InsetText::appendParagraphs(BufferParams const & bparams,
Paragraph * buf;
Paragraph * tmpbuf = newpar;
Paragraph * lastbuffer = buf = new Paragraph(*tmpbuf, false);
if (bparams.tracking_changes)
buf->cleanChanges();
while (tmpbuf->next()) {
tmpbuf = tmpbuf->next();
lastbuffer->next(new Paragraph(*tmpbuf, false));
lastbuffer->next()->previous(lastbuffer);
lastbuffer = lastbuffer->next();
if (bparams.tracking_changes)
lastbuffer->cleanChanges();
}
lastbuffer = &*(paragraphs.begin());
while (lastbuffer->next())

View File

@ -82,8 +82,8 @@ public:
Inset * clone(Buffer const &, bool same_id = false) const;
///
InsetText & operator=(InsetText const & it);
///
void clear();
/// empty inset to empty par, or just mark as erased
void clear(bool just_mark_erased);
///
void read(Buffer const *, LyXLex &);
///
@ -220,7 +220,7 @@ public:
///
void paragraph(Paragraph *);
///
bool allowSpellcheck() { return true; }
bool allowSpellcheck() const { return true; }
///
WordLangTuple const
selectNextWordToSpellcheck(BufferView *, float & value) const;
@ -228,6 +228,20 @@ public:
void selectSelectedWord(BufferView *);
///
void toggleSelection(BufferView *, bool kill_selection);
/// mark as erased for change tracking
void markErased() { clear(true); };
/**
* Mark as new. Used when pasting in tabular, and adding rows
* or columns. Note that pasting will ensure that tracking already
* happens, and this just resets the changes for the copied text,
* whereas for row/col add, we need to start tracking changes
* for the (empty) paragraph contained.
*/
void markNew(bool track_changes = false);
/// find next change
bool nextChange(BufferView *, lyx::pos_type & length);
///
bool searchForward(BufferView *, string const &,
bool = true, bool = false);
@ -238,8 +252,9 @@ public:
bool checkInsertChar(LyXFont &);
///
void getDrawFont(LyXFont &) const;
///
void appendParagraphs(BufferParams const & bparams, Paragraph *);
/// append text onto the existing text
void appendParagraphs(BufferParams const & bp, Paragraph *);
///
void addPreview(grfx::PreviewLoader &) const;

View File

@ -16,8 +16,10 @@
#include "debug.h"
#include "gettext.h"
#include "insets/insettext.h"
#include "changes.h"
using lyx::pos_type;
using std::endl;
namespace lyxfind {
@ -97,7 +99,7 @@ int LyXReplace(BufferView * bv,
bv->update(text, BufferView::SELECT|BufferView::FITCUR);
bv->toggleSelection(false);
text->replaceSelectionWithString(bv, replacestr);
text->setSelectionOverString(bv, replacestr);
text->setSelectionRange(bv, replacestr.length());
bv->update(text, BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
++replace_count;
}
@ -156,7 +158,7 @@ bool LyXFind(BufferView * bv,
if (result == SR_FOUND) {
bv->unlockInset(bv->theLockingInset());
bv->update(text, BufferView::SELECT|BufferView::FITCUR);
text->setSelectionOverString(bv, searchstr);
text->setSelectionRange(bv, searchstr.length());
bv->toggleSelection(false);
bv->update(text, BufferView::SELECT|BufferView::FITCUR);
} else if (result == SR_NOT_FOUND) {
@ -312,4 +314,128 @@ SearchResult SearchBackward(BufferView * bv, LyXText * text,
}
}
SearchResult nextChange(BufferView * bv, LyXText * text, pos_type & length)
{
Paragraph * par = text->cursor.par();
pos_type pos = text->cursor.pos();
Paragraph * prev_par = par;
UpdatableInset * inset;
while (par) {
if ((!par->size() || pos != par->size())
&& par->lookupChange(pos) != Change::UNCHANGED)
break;
if (par->isInset(pos) &&
(inset = (UpdatableInset *)par->getInset(pos)) &&
(inset->isTextInset())) {
if (inset->nextChange(bv, length))
return SR_FOUND_NOUPDATE;
}
++pos;
if (pos >= par->size()) {
prev_par = par;
par = par->next();
pos = 0;
}
}
if (par) {
text->setCursor(bv, par, pos);
Change orig_change = par->lookupChangeFull(pos);
pos_type end = pos;
for (; end != par->size(); ++end) {
Change change = par->lookupChangeFull(end);
if (change != orig_change) {
// slight UI optimisation: for replacements, we get
// text like : _old_new. Consider that as one change.
if (!(orig_change.type == Change::DELETED &&
change.type == Change::INSERTED))
break;
}
}
length = end - pos;
return SR_FOUND;
} else {
// make sure we end up at the end of the text,
// not the start point of the last search
text->setCursor(bv, prev_par, prev_par->size());
return SR_NOT_FOUND;
}
}
SearchResult findNextChange(BufferView * bv, LyXText * text, pos_type & length)
{
if (text->selection.set())
text->cursor = text->selection.end;
bv->toggleSelection();
text->clearSelection();
return nextChange(bv, text, length);
}
bool findNextChange(BufferView * bv)
{
if (!bv->available())
return false;
bv->hideCursor();
bv->update(bv->getLyXText(), BufferView::SELECT | BufferView::FITCUR);
pos_type length;
if (bv->theLockingInset()) {
bool found = bv->theLockingInset()->nextChange(bv, length);
// We found the stuff inside the inset so we don't have to
// do anything as the inset did all the update for us!
if (found)
return true;
// We now are in the main text but if we did a forward
// search we have to put the cursor behind the inset.
bv->text->cursorRight(bv, true);
}
// If we arrive here we are in the main text again so we
// just start searching from the root LyXText at the position
// we are!
LyXText * text = bv->text;
if (text->selection.set())
text->cursor = text->selection.end;
bv->toggleSelection();
text->clearSelection();
SearchResult result = nextChange(bv, text, length);
lyxerr << "Result is " << result << endl;
bool found = true;
// If we found the cursor inside an inset we will get back
// SR_FOUND_NOUPDATE and we don't have to do anything as the
// inset did it already.
if (result == SR_FOUND) {
bv->unlockInset(bv->theLockingInset());
bv->update(text, BufferView::SELECT|BufferView::FITCUR);
text->setSelectionRange(bv, length);
bv->toggleSelection(false);
bv->update(text, BufferView::SELECT|BufferView::FITCUR);
} else if (result == SR_NOT_FOUND) {
bv->unlockInset(bv->theLockingInset());
bv->update(text, BufferView::SELECT|BufferView::FITCUR);
found = false;
}
return found;
}
} // end lyxfind namespace

View File

@ -7,6 +7,7 @@
#endif
#include "LString.h"
#include "support/types.h"
class BufferView;
class LyXText;
@ -49,5 +50,13 @@ SearchResult LyXFind(BufferView *, LyXText * text,
string const & searchstr, bool forward,
bool casesens = true, bool matchwrd = false);
/// find the next change in the buffer
bool findNextChange(BufferView * bv);
SearchResult findNextChange(BufferView * bv, LyXText * text, lyx::pos_type & length);
SearchResult nextChange(BufferView * bv, LyXText * text, lyx::pos_type & length);
} // end namespace LyXFind
#endif
#endif // LYXFIND_H

View File

@ -462,6 +462,13 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & ev) const
disable = !view()->
isSavedPosition(strToUnsignedInt(ev.argument));
break;
case LFUN_MERGE_CHANGES:
case LFUN_ACCEPT_CHANGE:
case LFUN_REJECT_CHANGE:
case LFUN_ACCEPT_ALL_CHANGES:
case LFUN_REJECT_ALL_CHANGES:
disable = !buf->params.tracking_changes;
break;
case LFUN_INSET_TOGGLE: {
LyXText * lt = view()->getLyXText();
disable = !(isEditableInset(lt->getInset())
@ -624,6 +631,9 @@ FuncStatus LyXFunc::getStatus(FuncRequest const & ev) const
if (ev.argument == buf->fileName())
flag.setOnOff(true);
break;
case LFUN_TRACK_CHANGES:
flag.setOnOff(buf->params.tracking_changes);
break;
default:
break;
}

View File

@ -1,12 +1,10 @@
/* This file is part of
* ======================================================
/**
* \file lyxrc.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* LyX, The Document Processor
*
* Copyright 1995 Matthias Ettrich
* Copyright 1995-2001 The LyX Team.
*
* ====================================================== */
* Full author contact details are available in file CREDITS
*/
#include <config.h>
@ -27,6 +25,8 @@
#include "intl.h"
#include "support/path.h"
#include "support/filetools.h"
#include "support/LAssert.h"
#include "support/userinfo.h"
#include "converter.h"
#include "gettext.h"
#include "lyxlex.h"
@ -148,6 +148,8 @@ keyword_item lyxrcTags[] = {
{ "\\use_pspell", LyXRC::RC_USE_PSPELL },
#endif
{ "\\use_tempdir", LyXRC::RC_USETEMPDIR },
{ "\\user_email", LyXRC::RC_USER_EMAIL },
{ "\\user_name", LyXRC::RC_USER_NAME },
{ "\\view_dvi_paper_option", LyXRC::RC_VIEWDVI_PAPEROPTION },
{ "\\viewer" ,LyXRC::RC_VIEWER},
{ "\\wheel_jump", LyXRC::RC_WHEEL_JUMP }
@ -264,6 +266,13 @@ void LyXRC::setDefaults() {
// should be moved from the LyXRC class).
use_gui = true;
pdf_mode = false;
user_name = lyx::user_name();
user_email = lyx::user_email();
if (user_email.empty())
user_email = _("email address unknown");
}
@ -1094,6 +1103,16 @@ int LyXRC::read(string const & filename)
}
break;
case RC_USER_NAME:
if (lexrc.next())
user_name = lexrc.getString();
break;
case RC_USER_EMAIL:
if (lexrc.next())
user_email = lexrc.getString();
break;
case RC_LAST: break; // this is just a dummy
}
}
@ -1261,6 +1280,12 @@ void LyXRC::output(ostream & os) const
<< '\n';
}
case RC_USER_NAME:
os << "\\user_name \"" << user_name << "\"\n";
case RC_USER_EMAIL:
os << "\\user_email " << user_email << "\n";
case RC_SHOW_BANNER:
if (show_banner != system_lyxrc.show_banner) {
os << "\\show_banner " << tostr(show_banner) << '\n';
@ -1798,6 +1823,7 @@ void LyXRC::output(ostream & os) const
if (!converters.getConverter(cit->from, cit->to))
os << "\\converter \"" << cit->from
<< "\" \"" << cit->to << "\" \"\" \"\"\n";
}
os.flush();
}

View File

@ -1,13 +1,11 @@
// -*- C++ -*-
/* This file is part of
* ======================================================
/**
* \file lyxrc.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* LyX, The Document Processor
*
* Copyright 1995 Matthias Ettrich
* Copyright 1995-2001 The LyX Team.
*
* ====================================================== */
* Full author contact details are available in file CREDITS
*/
#ifndef LYXRC_H
#define LYXRC_H
@ -127,6 +125,8 @@ enum LyXRCTags {
#ifdef USE_PSPELL
RC_USE_PSPELL,
#endif
RC_USER_NAME,
RC_USER_EMAIL,
RC_LAST
};
@ -357,6 +357,10 @@ enum LyXRCTags {
bool preview_hashed_labels;
///
float preview_scale_factor;
/// user name
string user_name;
/// user email
string user_email;
private:
/// Is a bind file already (or currently) read?

View File

@ -83,6 +83,18 @@ unsigned short Row::ascent_of_text() const
}
void Row::top_of_text(unsigned int top)
{
top_of_text_ = top;
}
unsigned int Row::top_of_text() const
{
return top_of_text_;
}
void Row::baseline(unsigned int b)
{
baseline_ = b;

View File

@ -53,6 +53,10 @@ public:
///
unsigned short ascent_of_text() const;
///
void top_of_text(unsigned int top);
///
unsigned int top_of_text() const;
///
void baseline(unsigned int b);
///
unsigned int baseline() const;
@ -76,8 +80,10 @@ private:
unsigned short height_;
///
unsigned int width_;
///
/// ascent from baseline including prelude space
unsigned short ascent_of_text_;
/// the top of the real text in the row
unsigned int top_of_text_;
///
unsigned int baseline_;
///

View File

@ -281,6 +281,12 @@ public:
/// returns the inset at cursor (if it exists), 0 otherwise
Inset * getInset() const;
/// accept selected change
void acceptChange(BufferView * bv);
/// reject selected change
void rejectChange(BufferView * bv);
/** 'selects" the next word, where the cursor is not in
and returns this word as string. THe cursor will be moved
to the beginning of this word.
@ -408,10 +414,11 @@ public:
/* these things are for search and replace */
/** sets the selection over the number of characters of string,
no check!!
/**
* Sets the selection from the current cursor position to length
* characters to the right. No safety checks.
*/
void setSelectionOverString(BufferView *, string const & str);
void setSelectionRange(BufferView *, lyx::pos_type length);
/** simple replacing. The font of the first selected character
is used
@ -574,6 +581,9 @@ private:
/// paint the selection background
void paintRowSelection(DrawRowParams & p);
/// paint change bar
void paintChangeBar(DrawRowParams & p);
/// paint appendix marker
void paintRowAppendix(DrawRowParams & p);

View File

@ -28,6 +28,7 @@
#include "encoding.h"
#include "ParameterStruct.h"
#include "gettext.h"
#include "changes.h"
#include "insets/insetbib.h"
#include "insets/insetoptarg.h"
@ -42,6 +43,7 @@
#include <algorithm>
#include <fstream>
#include <csignal>
#include <ctime>
using std::ostream;
using std::endl;
@ -242,6 +244,9 @@ void Paragraph::write(Buffer const * buf, ostream & os,
LyXFont font1(LyXFont::ALL_INHERIT, bparams.language);
Change running_change = Change(Change::UNCHANGED);
lyx::time_type const curtime(lyx::current_time());
int column = 0;
for (pos_type i = 0; i < size(); ++i) {
if (!i) {
@ -249,6 +254,10 @@ void Paragraph::write(Buffer const * buf, ostream & os,
column = 0;
}
Change change = pimpl_->lookupChangeFull(i);
Changes::lyxMarkChange(os, column, curtime, running_change, change);
running_change = change;
// Write font changes
LyXFont font2 = getFontSettings(bparams, i);
if (font2 != font1) {
@ -312,6 +321,15 @@ void Paragraph::write(Buffer const * buf, ostream & os,
break;
}
}
// to make reading work properly
if (!size()) {
running_change = pimpl_->lookupChange(0);
Changes::lyxMarkChange(os, column, curtime,
Change(Change::UNCHANGED), running_change);
}
Changes::lyxMarkChange(os, column, curtime,
running_change, Change(Change::UNCHANGED));
}
@ -389,6 +407,12 @@ void Paragraph::erase(pos_type pos)
}
bool Paragraph::erase(pos_type start, pos_type end)
{
return pimpl_->erase(start, end);
}
bool Paragraph::checkInsertChar(LyXFont & font)
{
if (pimpl_->inset_owner)
@ -405,9 +429,9 @@ void Paragraph::insertChar(pos_type pos, Paragraph::value_type c)
void Paragraph::insertChar(pos_type pos, Paragraph::value_type c,
LyXFont const & font)
LyXFont const & font, Change change)
{
pimpl_->insertChar(pos, c, font);
pimpl_->insertChar(pos, c, font, change);
}
@ -418,9 +442,9 @@ void Paragraph::insertInset(pos_type pos, Inset * inset)
}
void Paragraph::insertInset(pos_type pos, Inset * inset, LyXFont const & font)
void Paragraph::insertInset(pos_type pos, Inset * inset, LyXFont const & font, Change change)
{
pimpl_->insertInset(pos, inset, font);
pimpl_->insertInset(pos, inset, font, change);
}
@ -736,7 +760,7 @@ int Paragraph::stripLeadingSpaces()
int i = 0;
while (!empty() && (isNewline(0) || isLineSeparator(0))) {
erase(0);
pimpl_->eraseIntern(0);
++i;
}
@ -1358,6 +1382,8 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf,
// Do we have an open font change?
bool open_font = false;
Change::Type running_change = Change::UNCHANGED;
texrow.start(this, 0);
// if the paragraph is empty, the loop will not be entered at all
@ -1445,6 +1471,11 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf,
open_font = true;
}
Change::Type change = pimpl_->lookupChange(i);
column += Changes::latexMarkChange(os, running_change, change);
running_change = change;
if (c == Paragraph::META_NEWLINE) {
// newlines are handled differently here than
// the default in SimpleTeXSpecialChars().
@ -1474,10 +1505,14 @@ bool Paragraph::simpleTeXOnePar(Buffer const * buf,
os, texrow, moving_arg,
font, running_font,
basefont, open_font,
running_change,
*style, i, column, c);
}
}
column += Changes::latexMarkChange(os,
running_change, Change::UNCHANGED);
// If we have an open font definition, we have to close it
if (open_font) {
#ifdef FIXED_LANGUAGE_END_DETECTION
@ -1808,6 +1843,68 @@ void Paragraph::setContentsFromPar(Paragraph * par)
}
void Paragraph::trackChanges(Change::Type type)
{
pimpl_->trackChanges(type);
}
void Paragraph::untrackChanges()
{
pimpl_->untrackChanges();
}
void Paragraph::cleanChanges()
{
pimpl_->cleanChanges();
}
Change::Type Paragraph::lookupChange(lyx::pos_type pos) const
{
lyx::Assert(!size() || pos < size());
return pimpl_->lookupChange(pos);
}
Change const Paragraph::lookupChangeFull(lyx::pos_type pos) const
{
lyx::Assert(!size() || pos < size());
return pimpl_->lookupChangeFull(pos);
}
bool Paragraph::isChanged(pos_type start, pos_type end) const
{
return pimpl_->isChanged(start, end);
}
bool Paragraph::isChangeEdited(pos_type start, pos_type end) const
{
return pimpl_->isChangeEdited(start, end);
}
void Paragraph::markErased()
{
pimpl_->markErased();
}
void Paragraph::acceptChange(pos_type start, pos_type end)
{
return pimpl_->acceptChange(start, end);
}
void Paragraph::rejectChange(pos_type start, pos_type end)
{
return pimpl_->rejectChange(start, end);
}
lyx::pos_type Paragraph::size() const
{
return pimpl_->size();

View File

@ -20,6 +20,7 @@
#include "insets/inset.h" // Just for Inset::Code
#include "support/types.h"
#include "changes.h"
#include "LString.h"
@ -165,6 +166,36 @@ public:
///
Paragraph const * next() const;
/// initialise tracking for this par
void trackChanges(Change::Type = Change::UNCHANGED);
/// stop tracking
void untrackChanges();
/// set entire paragraph to new text for change tracking
void cleanChanges();
/// look up change type at given pos
Change::Type lookupChange(lyx::pos_type pos) const;
/// look up change at given pos
Change const lookupChangeFull(lyx::pos_type pos) const;
/// is there a change within the given range ?
bool isChanged(lyx::pos_type start, lyx::pos_type end) const;
/// is there a non-addition in this range ?
bool isChangeEdited(lyx::pos_type start, lyx::pos_type end) const;
/// accept change
void acceptChange(lyx::pos_type start, lyx::pos_type end);
/// reject change
void rejectChange(lyx::pos_type start, lyx::pos_type end);
/// mark whole par as erased
void markErased();
///
void previous(Paragraph *);
///
@ -197,9 +228,13 @@ public:
depth_type getMaxDepthAfter() const;
///
void applyLayout(LyXLayout_ptr const & new_layout);
///
/// erase the char at the given position
void erase(lyx::pos_type pos);
/** Get unistantiated font setting. Returns the difference
/// erase the given range. Returns true if actually erased.
bool erase(lyx::pos_type start, lyx::pos_type end);
/** Get uninstantiated font setting. Returns the difference
between the characters font and the layoutfont.
This is what is stored in the fonttable
*/
@ -234,13 +269,13 @@ public:
///
void insertChar(lyx::pos_type pos, value_type c);
///
void insertChar(lyx::pos_type pos, value_type c, LyXFont const &);
void insertChar(lyx::pos_type pos, value_type c, LyXFont const &, Change change = Change(Change::INSERTED));
///
bool checkInsertChar(LyXFont &);
///
void insertInset(lyx::pos_type pos, Inset * inset);
///
void insertInset(lyx::pos_type pos, Inset * inset, LyXFont const &);
void insertInset(lyx::pos_type pos, Inset * inset, LyXFont const &, Change change = Change(Change::INSERTED));
///
bool insetAllowed(Inset::Code code);
///
@ -294,6 +329,9 @@ public:
///
//Counters & counters();
friend void breakParagraph(BufferParams const & bparams,
Paragraph * par, lyx::pos_type pos, int flag);
private:
///
LyXLayout_ptr layout_;
@ -312,4 +350,16 @@ private:
Pimpl * pimpl_;
};
#endif
inline bool isInsertedText(Paragraph const * par, lyx::pos_type pos)
{
return par->lookupChange(pos) == Change::INSERTED;
}
inline bool isDeletedText(Paragraph const * par, lyx::pos_type pos)
{
return par->lookupChange(pos) == Change::DELETED;
}
#endif // PARAGRAPH_H

View File

@ -11,6 +11,7 @@
#include <config.h>
#include "paragraph_funcs.h"
#include "paragraph_pimpl.h"
#include "buffer.h"
#include "ParagraphParameters.h"
#include "lyxtextclasslist.h"
@ -34,6 +35,9 @@ void breakParagraph(BufferParams const & bparams,
// remember to set the inset_owner
tmp->setInsetOwner(par->inInset());
if (bparams.tracking_changes)
tmp->trackChanges();
// this is an idea for a more userfriendly layout handling, I will
// see what the users say
@ -73,13 +77,17 @@ void breakParagraph(BufferParams const & bparams,
pos_type pos_end = par->size() - 1;
pos_type i = pos;
pos_type j = pos;
for (; i <= pos_end; ++i) {
Change::Type change(par->lookupChange(i));
par->cutIntoMinibuffer(bparams, i);
if (tmp->insertFromMinibuffer(j - pos))
if (tmp->insertFromMinibuffer(j - pos)) {
tmp->pimpl_->setChange(j - pos, change);
++j;
}
}
for (i = pos_end; i >= pos; --i) {
par->erase(i);
par->pimpl_->eraseIntern(i);
}
}
@ -102,6 +110,15 @@ void breakParagraph(BufferParams const & bparams,
par->setLabelWidthString(tmp->params().labelWidthString());
par->params().depth(tmp->params().depth());
}
// subtle, but needed to get empty pars working right
if (bparams.tracking_changes) {
if (!par->size()) {
par->cleanChanges();
} else if (!tmp->size()) {
tmp->cleanChanges();
}
}
}

View File

@ -74,12 +74,16 @@ Paragraph::Pimpl::Pimpl(Pimpl const & p, Paragraph * owner, bool same_ids)
id_ = p.id_;
else
id_ = paragraph_id++;
if (p.tracking())
changes_.reset(new Changes(*p.changes_.get()));
}
void Paragraph::Pimpl::clear()
{
text.clear();
#warning changes ?
}
@ -87,6 +91,166 @@ void Paragraph::Pimpl::setContentsFromPar(Paragraph const * par)
{
lyx::Assert(par);
text = par->pimpl_->text;
if (par->pimpl_->tracking()) {
changes_.reset(new Changes(*(par->pimpl_->changes_.get())));
}
}
void Paragraph::Pimpl::trackChanges(Change::Type type)
{
if (tracking()) {
lyxerr[Debug::CHANGES] << "already tracking for par " << id_ << endl;
return;
}
lyxerr[Debug::CHANGES] << "track changes for par "
<< id_ << " type " << type << endl;
changes_.reset(new Changes(type));
changes_->set(type, 0, size());
}
void Paragraph::Pimpl::untrackChanges()
{
changes_.reset(0);
}
void Paragraph::Pimpl::cleanChanges()
{
// if we're not tracking, we don't want to reset...
if (!tracking())
return;
changes_.reset(new Changes(Change::INSERTED));
changes_->set(Change::INSERTED, 0, size());
}
bool Paragraph::Pimpl::isChanged(pos_type start, pos_type end) const
{
if (!tracking())
return false;
return changes_->isChange(start, end);
}
bool Paragraph::Pimpl::isChangeEdited(pos_type start, pos_type end) const
{
if (!tracking())
return false;
return changes_->isChangeEdited(start, end);
}
void Paragraph::Pimpl::setChange(pos_type pos, Change::Type type)
{
if (!tracking())
return;
changes_->set(type, pos);
}
Change::Type Paragraph::Pimpl::lookupChange(pos_type pos) const
{
if (!tracking())
return Change::UNCHANGED;
return changes_->lookup(pos);
}
Change const Paragraph::Pimpl::lookupChangeFull(pos_type pos) const
{
if (!tracking())
return Change(Change::UNCHANGED);
return changes_->lookupFull(pos);
}
void Paragraph::Pimpl::markErased()
{
lyx::Assert(tracking());
// FIXME: we should actually remove INSERTED chars.
// difficult because owning insettexts/tabulars need
// to update themselves when rows etc. change
changes_->set(Change::DELETED, 0, size());
changes_->reset(Change::DELETED);
}
void Paragraph::Pimpl::acceptChange(pos_type start, pos_type end)
{
if (!tracking())
return;
if (!size()) {
changes_.reset(new Changes(Change::UNCHANGED));
return;
}
lyxerr << "acceptchange" << endl;
pos_type i = start;
for (; i < end; ++i) {
switch (lookupChange(i)) {
case Change::UNCHANGED:
break;
case Change::INSERTED:
changes_->set(Change::UNCHANGED, i);
break;
case Change::DELETED:
eraseIntern(i);
changes_->erase(i);
--end;
--i;
break;
}
}
lyxerr << "endacceptchange" << endl;
changes_->reset(Change::UNCHANGED);
}
void Paragraph::Pimpl::rejectChange(pos_type start, pos_type end)
{
if (!tracking())
return;
if (!size()) {
changes_.reset(new Changes(Change::UNCHANGED));
return;
}
pos_type i = start;
for (; i < end; ++i) {
switch (lookupChange(i)) {
case Change::UNCHANGED:
break;
case Change::INSERTED:
eraseIntern(i);
changes_->erase(i);
--end;
--i;
break;
case Change::DELETED:
changes_->set(Change::UNCHANGED, i);
break;
}
}
changes_->reset(Change::UNCHANGED);
}
@ -109,15 +273,20 @@ Paragraph::value_type Paragraph::Pimpl::getChar(pos_type pos) const
void Paragraph::Pimpl::setChar(pos_type pos, value_type c)
{
#warning changes
text[pos] = c;
}
void Paragraph::Pimpl::insertChar(pos_type pos, value_type c,
LyXFont const & font)
LyXFont const & font, Change change)
{
lyx::Assert(pos <= size());
if (tracking()) {
changes_->record(change, pos);
}
// This is actually very common when parsing buffers (and
// maybe inserting ascii text)
if (pos == size()) {
@ -147,12 +316,12 @@ void Paragraph::Pimpl::insertChar(pos_type pos, value_type c,
void Paragraph::Pimpl::insertInset(pos_type pos,
Inset * inset, LyXFont const & font)
Inset * inset, LyXFont const & font, Change change)
{
lyx::Assert(inset);
lyx::Assert(pos <= size());
insertChar(pos, META_INSET, font);
insertChar(pos, META_INSET, font, change);
lyx::Assert(text[pos] == META_INSET);
// Add a new entry in the insetlist.
@ -164,9 +333,31 @@ void Paragraph::Pimpl::insertInset(pos_type pos,
}
void Paragraph::Pimpl::erase(pos_type pos)
bool Paragraph::Pimpl::erasePos(pos_type pos)
{
lyx::Assert(pos < size());
if (tracking()) {
Change::Type changetype(changes_->lookup(pos));
changes_->record(Change(Change::DELETED), pos);
// only allow the actual removal if it was /new/ text
if (changetype != Change::INSERTED) {
if (text[pos] == Paragraph::META_INSET) {
Inset * i(owner_->getInset(pos));
i->markErased();
}
return false;
}
}
eraseIntern(pos);
return true;
}
void Paragraph::Pimpl::eraseIntern(pos_type pos)
{
// if it is an inset, delete the inset entry
if (text[pos] == Paragraph::META_INSET) {
owner_->insetlist.erase(pos);
@ -209,6 +400,30 @@ void Paragraph::Pimpl::erase(pos_type pos)
}
void Paragraph::Pimpl::erase(pos_type pos)
{
erasePos(pos);
}
bool Paragraph::Pimpl::erase(pos_type start, pos_type end)
{
pos_type i = start;
pos_type count = end - start;
bool any_erased = false;
while (count) {
if (!erasePos(i)) {
++i;
} else {
any_erased = true;
}
--count;
}
return any_erased;
}
void Paragraph::Pimpl::simpleTeXBlanks(ostream & os, TexRow & texrow,
pos_type const i,
unsigned int & column,
@ -279,6 +494,7 @@ void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
LyXFont & running_font,
LyXFont & basefont,
bool & open_font,
Change::Type & running_change,
LyXLayout const & style,
pos_type & i,
unsigned int & column,
@ -294,7 +510,17 @@ void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
switch (c) {
case Paragraph::META_INSET: {
Inset * inset = owner_->getInset(i);
if (inset) {
// FIXME: remove this check
if (!inset)
break;
if (inset->isTextInset()) {
column += Changes::latexMarkChange(os, running_change,
Change::UNCHANGED);
running_change = Change::UNCHANGED;
}
bool close = false;
int const len = os.tellp();
//ostream::pos_type const len = os.tellp();
@ -339,7 +565,6 @@ void Paragraph::Pimpl::simpleTeXSpecialChars(Buffer const * buf,
column += int(os.tellp()) - len;
}
}
}
break;
case Paragraph::META_NEWLINE:

View File

@ -1,13 +1,9 @@
// -*- C++ -*-
/* This file is part of
* ======================================================
*
* LyX, The Document Processor
*
* Copyright 1995 Matthias Ettrich
* Copyright 1995-2001 The LyX Team.
*
* ====================================================== */
/**
* \file paragraph_pimpl.h
* Copyright 1995-2002 the LyX Team
* Read the file COPYING
*/
#ifndef PARAGRAPH_PIMPL_H
#define PARAGRAPH_PIMPL_H
@ -18,8 +14,11 @@
#include "paragraph.h"
#include "ParagraphParameters.h"
#include "changes.h"
#include "counters.h"
#include <boost/scoped_ptr.hpp>
class LyXLayout;
struct Paragraph::Pimpl {
@ -42,16 +41,52 @@ struct Paragraph::Pimpl {
void clear();
///
void setContentsFromPar(Paragraph const * par);
/// set tracking mode
void trackChanges(Change::Type type = Change::UNCHANGED);
/// stop tracking
void untrackChanges();
/// set all text as new for change mode
void cleanChanges();
/// look up change type at given pos
Change::Type lookupChange(lyx::pos_type pos) const;
/// look up change at given pos
Change const lookupChangeFull(lyx::pos_type pos) const;
/// is there a change in the given range ?
bool isChanged(lyx::pos_type start, lyx::pos_type end) const;
/// is there a non-addition in this range ?
bool isChangeEdited(lyx::pos_type start, lyx::pos_type end) const;
/// set change at pos
void setChange(lyx::pos_type pos, Change::Type type);
/// mark as erased
void markErased();
/// accept change
void acceptChange(lyx::pos_type start, lyx::pos_type end);
/// reject change
void rejectChange(lyx::pos_type start, lyx::pos_type end);
/// are we tracking changes ?
bool tracking() const {
return changes_.get();
}
///
value_type getChar(lyx::pos_type pos) const;
///
void setChar(lyx::pos_type pos, value_type c);
///
void insertChar(lyx::pos_type pos, value_type c, LyXFont const & font);
///
void insertInset(lyx::pos_type pos, Inset * inset, LyXFont const & font);
void insertChar(lyx::pos_type pos, value_type c, LyXFont const & font, Change change = Change(Change::INSERTED));
///
void insertInset(lyx::pos_type pos, Inset * inset, LyXFont const & font, Change change = Change(Change::INSERTED));
/// definite erase
void eraseIntern(lyx::pos_type pos);
/// erase the given position
void erase(lyx::pos_type pos);
/// erase the given range
bool erase(lyx::pos_type start, lyx::pos_type end);
///
LyXFont const realizeFont(LyXFont const & font,
BufferParams const & bparams) const;
@ -115,6 +150,7 @@ struct Paragraph::Pimpl {
typedef std::vector<FontTable> FontList;
///
FontList fontlist;
///
Paragraph * TeXDeeper(Buffer const *, BufferParams const &,
std::ostream &, TexRow & texrow);
@ -130,6 +166,7 @@ struct Paragraph::Pimpl {
bool moving_arg,
LyXFont & font, LyXFont & running_font,
LyXFont & basefont, bool & open_font,
Change::Type & running_change,
LyXLayout const & style,
lyx::pos_type & i,
unsigned int & column, value_type const c);
@ -148,9 +185,15 @@ struct Paragraph::Pimpl {
ParagraphParameters params;
private:
/// erase at the given position. Returns true if it was actually erased
bool erasePos(lyx::pos_type pos);
/// match a string against a particular point in the paragraph
bool isTextAt(string const & str, lyx::pos_type pos) const;
/// for recording and looking up changes in revision tracking mode
boost::scoped_ptr<Changes> changes_;
/// Who owns us?
Paragraph * owner_;
///

View File

@ -1,3 +1,13 @@
2003-02-08 John Levon <levon@movementarian.org>
* Makefile.am:
* lyxtime.h:
* lyxtime.C: add typedef for time_t, add current_time
* Makefile.am:
* userinfo.h:
* userinfo.C: add
2002-12-04 Jean-Marc Lasgouttes <Jean-Marc.Lasgouttes@inria.fr>
* filetools.C (getExtFromContents): remove detection of epsi

View File

@ -43,6 +43,8 @@ libsupport_la_SOURCES = \
lyxfunctional.h \
lyxlib.h \
lyxmanip.h \
lyxtime.C \
lyxtime.h \
$(LYXSTRING) lyxsum.C \
mkdir.C \
nt_defines.h \
@ -58,6 +60,8 @@ libsupport_la_SOURCES = \
sstream.h \
systemcall.C \
systemcall.h \
userinfo.C \
userinfo.h \
tempname.C \
textutils.h \
translator.h \

22
src/support/lyxtime.C Normal file
View File

@ -0,0 +1,22 @@
/**
* \file lyxtime.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#include <config.h>
#include "lyxtime.h"
namespace lyx {
time_type current_time()
{
return time(0);
}
} // namespace lyx

25
src/support/lyxtime.h Normal file
View File

@ -0,0 +1,25 @@
// -*- C++ -*-
/**
* \file lyxtime.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#ifndef LYXTIME_H
#define LYXTIME_H
#include <time.h>
namespace lyx {
typedef time_t time_type;
time_type current_time();
}; // namespace lyx
#endif // LYXTIME_H

44
src/support/userinfo.C Normal file
View File

@ -0,0 +1,44 @@
/**
* \file userinfo.C
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#include <config.h>
#include "userinfo.h"
#include "LAssert.h"
#include "filetools.h"
#include <pwd.h>
#include <unistd.h>
#include <sys/types.h>
namespace lyx {
string const user_name()
{
struct passwd * pw(getpwuid(geteuid()));
lyx::Assert(pw);
string name = pw->pw_gecos;
if (name.empty())
name = pw->pw_name;
return name;
}
string const user_email()
{
string email = GetEnv("EMAIL_ADDRESS");
if (email.empty())
email = GetEnv("EMAIL");
return email;
}
} // namespace lyx

27
src/support/userinfo.h Normal file
View File

@ -0,0 +1,27 @@
// -*- C++ -*-
/**
* \file userinfo.h
* This file is part of LyX, the document processor.
* Licence details can be found in the file COPYING.
*
* \author John Levon
*
* Full author contact details are available in file CREDITS
*/
#ifndef USERINFO_H
#define USERINFO_H
#include "LString.h"
namespace lyx {
/// return the current user's real name
string const user_name();
/// return the current user's e-mail address
string const user_email();
}; // namespace lyx
#endif // USERINFO_H

View File

@ -270,7 +270,9 @@ void LyXTabular::AppendRow(BufferParams const & bp, int cell)
cell_info = c_info;
++row;
for (int j = 0; j < columns_; ++j) {
cell_info[row][j].inset.clear();
cell_info[row][j].inset.clear(false);
if (bp.tracking_changes)
cell_info[row][j].inset.markNew(true);
}
#endif
Reinit();
@ -321,8 +323,9 @@ void LyXTabular::AppendColumn(BufferParams const & bp, int cell)
cell_info = c_info;
//++column;
for (int i = 0; i < rows_; ++i) {
//cell_info[i][column].inset.clear();
cell_info[i][column + 1].inset.clear();
cell_info[i][column + 1].inset.clear(false);
if (bp.tracking_changes)
cell_info[i][column + 1].inset.markNew(true);
}
Reinit();
}
@ -1555,7 +1558,7 @@ void LyXTabular::SetMultiColumn(Buffer const * buffer, int cell, int number)
cellinfo_of_cell(cell+i)->multicolumn = CELL_PART_OF_MULTICOLUMN;
cellinfo_of_cell(cell)->inset.appendParagraphs(buffer->params,
cellinfo_of_cell(cell+i)->inset.paragraph());
cellinfo_of_cell(cell+i)->inset.clear();
cellinfo_of_cell(cell+i)->inset.clear(false);
}
#else
for (number--; number > 0; --number) {

View File

@ -50,7 +50,12 @@ using lyx::pos_type;
namespace {
/// top, right, bottom pixel margin
int const PAPER_MARGIN = 20;
/// margin for changebar
int const CHANGEBAR_MARGIN = 10;
/// left margin
int const LEFT_MARGIN = PAPER_MARGIN + CHANGEBAR_MARGIN;
} // namespace anon
@ -245,6 +250,9 @@ int LyXText::singleWidth(BufferView * bview, Paragraph * par,
// Returns the paragraph position of the last character in the specified row
pos_type LyXText::rowLast(Row const * row) const
{
if (!row->par()->size())
return 0;
if (!row->next() || row->next()->par() != row->par()) {
return row->par()->size() - 1;
} else {
@ -533,7 +541,7 @@ void LyXText::drawForeignMark(DrawRowParams & p, float const orig_x, LyXFont con
if (orig_font.language() == p.bv->buffer()->params.language)
return;
int const y = p.yo + p.row->height() - 1;
int const y = p.yo + p.row->baseline() + 1;
p.pain->line(int(orig_x), y, int(p.x), y, LColor::language);
}
@ -609,7 +617,7 @@ void LyXText::drawChars(DrawRowParams & p, pos_type & vpos,
{
pos_type pos = vis2log(vpos);
pos_type const last = rowLastPrintable(p.row);
LyXFont const & orig_font = getFont(p.bv->buffer(), p.row->par(), pos);
LyXFont orig_font(getFont(p.bv->buffer(), p.row->par(), pos));
// first character
string str;
@ -618,6 +626,10 @@ void LyXText::drawChars(DrawRowParams & p, pos_type & vpos,
unsigned char c = str[0];
str[0] = transformChar(c, p.row->par(), pos);
}
bool prev_struckout(isDeletedText(p.row->par(), pos));
bool prev_newtext(isInsertedText(p.row->par(), pos));
++vpos;
// collect as much similar chars as we can
@ -627,6 +639,12 @@ void LyXText::drawChars(DrawRowParams & p, pos_type & vpos,
if (!IsPrintableNonspace(c))
break;
if (prev_struckout != isDeletedText(p.row->par(), pos))
break;
if (prev_newtext != isInsertedText(p.row->par(), pos))
break;
if (arabic && Encodings::IsComposeChar_arabic(c))
break;
if (hebrew && Encodings::IsComposeChar_hebrew(c))
@ -641,6 +659,12 @@ void LyXText::drawChars(DrawRowParams & p, pos_type & vpos,
++vpos;
}
if (prev_struckout) {
orig_font.setColor(LColor::strikeout);
} else if (prev_newtext) {
orig_font.setColor(LColor::newtext);
}
// Draw text and set the new x position
p.pain->text(int(p.x), p.yo + p.row->baseline(), str, orig_font);
p.x += font_metrics::width(str, orig_font);
@ -702,7 +726,7 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const
if ((row->par()->getChar(row->pos()) == Paragraph::META_INSET) &&
(ins=row->par()->getInset(row->pos())) &&
(ins->needFullRow() || ins->display()))
return PAPER_MARGIN;
return LEFT_MARGIN;
LyXTextClass const & tclass =
bview->buffer()->params.getLyXTextClass();
@ -710,7 +734,7 @@ int LyXText::leftMargin(BufferView * bview, Row const * row) const
string parindent = layout->parindent;
int x = PAPER_MARGIN;
int x = LEFT_MARGIN;
x += font_metrics::signedWidth(tclass.leftmargin(), tclass.defaultfont());
@ -1312,8 +1336,8 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row_ptr) const
LyXLayout_ptr const & layout = firstpar->layout();
// as max get the first character of this row then it can increes but not
// decrees the height. Just some point to start with so we don't have to
// as max get the first character of this row then it can increase but not
// decrease the height. Just some point to start with so we don't have to
// do the assignment below too often.
LyXFont font = getFont(bview->buffer(), par, row_ptr->pos());
LyXFont::FONT_SIZE const tmpsize = font.size();
@ -1578,6 +1602,9 @@ void LyXText::setHeightOfRow(BufferView * bview, Row * row_ptr) const
row_ptr->baseline(maxasc + labeladdon);
height += row_ptr->height();
row_ptr->top_of_text(row_ptr->baseline() - font_metrics::maxAscent(font));
float x = 0;
if (layout->margintype != MARGIN_RIGHT_ADDRESS_BOX) {
float dummy;
@ -1722,6 +1749,11 @@ void LyXText::breakAgainOneRow(BufferView * bview, Row * row)
void LyXText::breakParagraph(BufferView * bview, char keep_layout)
{
// allow only if at start or end, or all previous is new text
if (cursor.pos() && cursor.pos() != cursor.par()->size()
&& cursor.par()->isChangeEdited(0, cursor.pos()))
return;
LyXTextClass const & tclass =
bview->buffer()->params.getLyXTextClass();
LyXLayout_ptr const & layout = cursor.par()->layout();
@ -2386,6 +2418,48 @@ bool LyXText::selectWordWhenUnderCursor(BufferView * bview,
}
void LyXText::acceptChange(BufferView * bv)
{
if (!selection.set() && cursor.par()->size())
return;
bv->hideCursor();
if (selection.start.par() == selection.end.par()) {
LyXCursor & startc = selection.start;
LyXCursor & endc = selection.end;
setUndo(bv, Undo::INSERT, startc.par(), startc.par()->next());
startc.par()->acceptChange(startc.pos(), endc.pos());
finishUndo();
clearSelection();
redoParagraphs(bv, startc, startc.par()->next());
setCursorIntern(bv, startc.par(), 0);
}
#warning handle multi par selection
}
void LyXText::rejectChange(BufferView * bv)
{
if (!selection.set() && cursor.par()->size())
return;
bv->hideCursor();
if (selection.start.par() == selection.end.par()) {
LyXCursor & startc = selection.start;
LyXCursor & endc = selection.end;
setUndo(bv, Undo::INSERT, startc.par(), startc.par()->next());
startc.par()->rejectChange(startc.pos(), endc.pos());
finishUndo();
clearSelection();
redoParagraphs(bv, startc, startc.par()->next());
setCursorIntern(bv, startc.par(), 0);
}
#warning handle multi par selection
}
// This function is only used by the spellchecker for NextWord().
// It doesn't handle LYX_ACCENTs and probably never will.
WordLangTuple const
@ -2419,24 +2493,32 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const
}
// Now, skip until we have real text (will jump paragraphs)
while ((cursor.par()->size() > cursor.pos()
&& (!cursor.par()->isLetter(cursor.pos()))
&& (!cursor.par()->isInset(cursor.pos()) ||
!cursor.par()->getInset(cursor.pos())->allowSpellcheck()))
|| (cursor.par()->size() == cursor.pos()
&& cursor.par()->next()))
{
if (cursor.pos() == cursor.par()->size()) {
cursor.par(cursor.par()->next());
while (1) {
Paragraph * cpar(cursor.par());
pos_type const cpos(cursor.pos());
if (cpos == cpar->size()) {
if (cpar->next()) {
cursor.par(cpar->next());
cursor.pos(0);
} else
cursor.pos(cursor.pos() + 1);
continue;
}
break;
}
bool const is_bad_inset(cpar->isInset(cpos)
&& !cpar->getInset(cpos)->allowSpellcheck());
if (cpar->isLetter(cpos) && !isDeletedText(cpar, cpos)
&& !is_bad_inset)
break;
cursor.pos(cpos + 1);
}
// now check if we hit an inset so it has to be a inset containing text!
if (cursor.pos() < cursor.par()->size() &&
cursor.par()->isInset(cursor.pos()))
{
cursor.par()->isInset(cursor.pos())) {
// lock the inset!
cursor.par()->getInset(cursor.pos())->edit(bview);
// now call us again to do the above trick
@ -2459,7 +2541,8 @@ LyXText::selectNextWordToSpellcheck(BufferView * bview, float & value) const
// and find the end of the word (insets like optional hyphens
// and ligature break are part of a word)
while (cursor.pos() < cursor.par()->size()
&& (cursor.par()->isLetter(cursor.pos())))
&& cursor.par()->isLetter(cursor.pos())
&& !isDeletedText(cursor.par(), cursor.pos()))
cursor.pos(cursor.pos() + 1);
// Finally, we copy the word to a string and return it
@ -2624,6 +2707,7 @@ void LyXText::changeRegionCase(BufferView * bview,
break;
}
}
#warning changes
par->setChar(pos, c);
checkParagraph(bview, par, pos);
@ -2647,23 +2731,31 @@ void LyXText::transposeChars(BufferView & bview)
// First decide if it is possible to transpose at all
// We are at the beginning of a paragraph.
if (tmppos == 0) return;
if (tmppos == 0 || tmppos == tmppar->size())
return;
// We are at the end of a paragraph.
if (tmppos == tmppar->size() - 1) return;
if (isDeletedText(tmppar, tmppos - 1)
|| isDeletedText(tmppar, tmppos))
return;
unsigned char c1 = tmppar->getChar(tmppos);
unsigned char c2 = tmppar->getChar(tmppos - 1);
if (c1 != Paragraph::META_INSET
&& c2 != Paragraph::META_INSET) {
tmppar->setChar(tmppos, c2);
tmppar->setChar(tmppos - 1, c1);
}
// We should have an implementation that handles insets
// as well, but that will have to come later. (Lgb)
checkParagraph(const_cast<BufferView*>(&bview), tmppar, tmppos);
if (c1 == Paragraph::META_INSET || c2 == Paragraph::META_INSET)
return;
bool const erased = tmppar->erase(tmppos - 1, tmppos + 1);
pos_type const ipos(erased ? tmppos - 1 : tmppos + 1);
tmppar->insertChar(ipos, c1);
tmppar->insertChar(ipos + 1, c2);
/* fugly */
BufferView * bv(const_cast<BufferView*>(&bview));
checkParagraph(bv, tmppar, tmppos);
}
@ -2717,6 +2809,10 @@ void LyXText::backspace(BufferView * bview)
// The cursor is at the beginning of a paragraph,
// so the the backspace will collapse two paragraphs into one.
// but it's not allowed unless it's new
if (cursor.par()->isChangeEdited(0, cursor.par()->size()))
return;
// we may paste some paragraphs
// is it an empty paragraph?
@ -3188,6 +3284,23 @@ void LyXText::paintRowSelection(DrawRowParams & p)
}
void LyXText::paintChangeBar(DrawRowParams & p)
{
pos_type const start = p.row->pos();
pos_type const end = rowLastPrintable(p.row);
if (!p.row->par()->isChanged(start, end))
return;
int const height = (p.row->next()
? p.row->height() + p.row->next()->top_of_text()
: p.row->baseline());
p.pain->fillRectangle(4, p.yo, 5,
height, LColor::changebar);
}
void LyXText::paintRowAppendix(DrawRowParams & p)
{
// FIXME: can be just p.width ?
@ -3216,7 +3329,10 @@ void LyXText::paintRowDepthBar(DrawRowParams & p)
next_depth = p.row->next()->par()->getDepth();
for (Paragraph::depth_type i = 1; i <= depth; ++i) {
int const x = (PAPER_MARGIN / 5) * i + p.xo;
int x = (PAPER_MARGIN / 5) * i + p.xo;
// only consider the changebar space if we're drawing outer left
if (!p.xo)
x += CHANGEBAR_MARGIN;
int const h = p.yo + p.row->height() - 1 - (i - next_depth - 1) * 3;
p.pain->line(x, p.yo, x, h, LColor::depthbar);
@ -3572,7 +3688,7 @@ void LyXText::paintLastRow(DrawRowParams & p)
LyXFont const font = getLabelFont(buffer, par);
int const size = int(0.75 * font_metrics::maxAscent(font));
int const y = (p.yo + p.row->baseline()) - size;
int x = is_rtl ? PAPER_MARGIN : ww - PAPER_MARGIN - size;
int x = is_rtl ? LEFT_MARGIN : ww - PAPER_MARGIN - size;
if (p.row->fill() <= size)
x += (size - p.row->fill() + 1) * (is_rtl ? -1 : 1);
@ -3622,16 +3738,42 @@ void LyXText::paintRowText(DrawRowParams & p)
LyXLayout_ptr const & layout = par->layout();
bool running_strikeout = false;
bool is_struckout = false;
float last_strikeout_x = 0.0;
pos_type vpos = p.row->pos();
while (vpos <= last) {
if (p.x > p.bv->workWidth())
break;
pos_type pos = vis2log(vpos);
if (p.x + singleWidth(p.bv, par, pos) < 0) {
p.x += singleWidth(p.bv, par, pos);
++vpos;
continue;
}
is_struckout = isDeletedText(par, pos);
if (is_struckout && !running_strikeout) {
running_strikeout = true;
last_strikeout_x = p.x;
}
bool const highly_editable_inset = par->isInset(pos)
&& isHighlyEditableInset(par->getInset(pos));
// if we reach the end of a struck out range, paint it
// we also don't paint across things like tables
if (running_strikeout && (highly_editable_inset || !is_struckout)) {
int const middle = p.yo + p.row->top_of_text()
+ ((p.row->baseline() - p.row->top_of_text()) / 2);
p.pain->line(int(last_strikeout_x), middle, int(p.x), middle,
LColor::strikeout, Painter::line_solid, Painter::line_thin);
running_strikeout = false;
}
if (main_body > 0 && pos == main_body - 1) {
int const lwidth = font_metrics::width(layout->labelsep,
getLabelFont(buffer, par));
@ -3681,6 +3823,15 @@ void LyXText::paintRowText(DrawRowParams & p)
break;
}
}
// if we reach the end of a struck out range, paint it
if (running_strikeout) {
int const middle = p.yo + p.row->top_of_text()
+ ((p.row->baseline() - p.row->top_of_text()) / 2);
p.pain->line(int(last_strikeout_x), middle, int(p.x), middle,
LColor::strikeout, Painter::line_solid, Painter::line_thin);
running_strikeout = false;
}
}
@ -3725,6 +3876,9 @@ void LyXText::getVisibleRow(BufferView * bv, int y_offset, int x_offset,
// environment depth brackets
paintRowDepthBar(p);
// changebar
paintChangeBar(p);
// draw any stuff wanted for a first row of a paragraph
if (!row->pos()) {
paintFirstRow(p);
@ -3778,6 +3932,12 @@ LyXText::getColumnNearX(BufferView * bview, Row * row, int & x,
!row->par()->isLineSeparator(main_body - 1)))
main_body = 0;
// check for empty row
if (!row->par()->size()) {
x = int(tmpx);
return 0;
}
while (vc <= last && tmpx <= x) {
c = vis2log(vc);
last_tmpx = tmpx;
@ -3822,9 +3982,7 @@ LyXText::getColumnNearX(BufferView * bview, Row * row, int & x,
: false; // If lastrow is false, we don't need to compute
// the value of rtl.
if (row->pos() > last) // Row is empty?
c = row->pos();
else if (lastrow &&
if (lastrow &&
((rtl && left_side && vc == row->pos() && x < tmpx - 5) ||
(!rtl && !left_side && vc == last + 1 && x > tmpx + 5)))
c = last + 1;

View File

@ -1493,7 +1493,8 @@ void LyXText::cutSelection(BufferView * bview, bool doclear, bool realcut)
// cutSelection can invalidate the cursor so we need to set
// it anew. (Lgb)
cursor = selection.start;
// we prefer the end for when tracking changes
cursor = selection.end;
// need a valid cursor. (Lgb)
clearSelection();
@ -1557,14 +1558,13 @@ void LyXText::pasteSelection(BufferView * bview)
}
// sets the selection over the number of characters of string, no check!!
void LyXText::setSelectionOverString(BufferView * bview, string const & str)
void LyXText::setSelectionRange(BufferView * bview, lyx::pos_type length)
{
if (str.empty())
if (!length)
return;
selection.cursor = cursor;
for (string::size_type i = 0; i < str.length(); ++i)
while (length--)
cursorRight(bview);
setSelection(bview);
}
@ -1801,7 +1801,11 @@ void LyXText::setCursor(BufferView * bview, LyXCursor & cur, Paragraph * par,
pos_type last = rowLastPrintable(old_row);
if (pos > last + 1) {
// None of these should happen, but we're scaredy-cats
if (pos > par->size()) {
pos = 0;
cur.pos(0);
} else if (pos > last + 1) {
// This shouldn't happen.
pos = last + 1;
cur.pos(pos);