mirror of
https://git.lyx.org/repos/lyx.git
synced 2024-12-25 05:55:34 +00:00
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:
parent
2b08bb805b
commit
ae87b94515
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
@ -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 }
|
||||
};
|
||||
|
||||
|
@ -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
94
src/author.C
Normal 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
67
src/author.h
Normal 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
|
107
src/buffer.C
107
src/buffer.C
@ -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");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
526
src/changes.C
Normal 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
150
src/changes.h
Normal 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
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -72,7 +72,9 @@ struct Debug {
|
||||
///
|
||||
INSETTEXT = (1 << 20),
|
||||
///
|
||||
GRAPHICS = (1 << 21)
|
||||
GRAPHICS = (1 << 21),
|
||||
/// change tracking
|
||||
CHANGES = (1 << 22)
|
||||
};
|
||||
///
|
||||
static type const ANY;
|
||||
|
@ -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]
|
||||
|
@ -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 *);
|
||||
///
|
||||
|
@ -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.
|
||||
|
82
src/frontends/controllers/ControlChanges.C
Normal file
82
src/frontends/controllers/ControlChanges.C
Normal 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());
|
||||
}
|
49
src/frontends/controllers/ControlChanges.h
Normal file
49
src/frontends/controllers/ControlChanges.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -31,6 +31,8 @@ libcontrollers_la_SOURCES= \
|
||||
ControlButtons.h \
|
||||
ControlCharacter.C \
|
||||
ControlCharacter.h \
|
||||
ControlChanges.C \
|
||||
ControlChanges.h \
|
||||
ControlCitation.C \
|
||||
ControlCitation.h \
|
||||
ControlCommand.C \
|
||||
|
@ -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:
|
||||
|
@ -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),
|
||||
|
@ -37,6 +37,12 @@ void Dialogs::showBibtex(InsetCommand * ic)
|
||||
}
|
||||
|
||||
|
||||
void Dialogs::showMergeChanges()
|
||||
{
|
||||
pimpl_->changes.controller().show();
|
||||
}
|
||||
|
||||
|
||||
void Dialogs::showCharacter()
|
||||
{
|
||||
pimpl_->character.controller().show();
|
||||
|
@ -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;
|
||||
|
81
src/frontends/xforms/FormChanges.C
Normal file
81
src/frontends/xforms/FormChanges.C
Normal 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;
|
||||
}
|
43
src/frontends/xforms/FormChanges.h
Normal file
43
src/frontends/xforms/FormChanges.h
Normal 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
|
@ -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)
|
||||
{}
|
||||
|
@ -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_;
|
||||
|
@ -66,6 +66,8 @@ libxforms_la_SOURCES = \
|
||||
FormBibtex.h \
|
||||
FormBrowser.C \
|
||||
FormBrowser.h \
|
||||
FormChanges.C \
|
||||
FormChanges.h \
|
||||
FormCharacter.C \
|
||||
FormCharacter.h \
|
||||
FormCitation.C \
|
||||
|
@ -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 \
|
||||
|
160
src/frontends/xforms/forms/form_changes.fd
Normal file
160
src/frontends/xforms/forms/form_changes.fd
Normal 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:
|
||||
|
||||
==============================
|
||||
--------------------
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
///
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -105,7 +105,7 @@ public:
|
||||
///
|
||||
void close(BufferView *) const;
|
||||
///
|
||||
bool allowSpellcheck() { return false; }
|
||||
bool allowSpellcheck() const { return false; }
|
||||
|
||||
WordLangTuple const
|
||||
selectNextWordToSpellcheck(BufferView *, float &) const;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 *);
|
||||
///
|
||||
|
@ -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())
|
||||
|
@ -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;
|
||||
|
||||
|
130
src/lyxfind.C
130
src/lyxfind.C
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
42
src/lyxrc.C
42
src/lyxrc.C
@ -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();
|
||||
}
|
||||
|
20
src/lyxrc.h
20
src/lyxrc.h
@ -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?
|
||||
|
12
src/lyxrow.C
12
src/lyxrow.C
@ -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;
|
||||
|
@ -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_;
|
||||
///
|
||||
|
@ -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);
|
||||
|
||||
|
107
src/paragraph.C
107
src/paragraph.C
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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_;
|
||||
///
|
||||
|
@ -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
|
||||
|
@ -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
22
src/support/lyxtime.C
Normal 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
25
src/support/lyxtime.h
Normal 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
44
src/support/userinfo.C
Normal 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
27
src/support/userinfo.h
Normal 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
|
@ -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) {
|
||||
|
228
src/text.C
228
src/text.C
@ -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;
|
||||
|
16
src/text2.C
16
src/text2.C
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user