lyx_mirror/src/lyxfr1.C

358 lines
7.9 KiB
C++
Raw Normal View History

/* This file is part of
* ======================================================
*
* LyX, The Document Processor
*
* Copyright 1995 Matthias Ettrich,
* Copyright 1995-1999 The LyX Team.
*
* ====================================================== */
#include <config.h>
#ifdef __GNUG__
#pragma implementation
#endif
#include "lyxfr1.h"
#include "lyxtext.h"
#include "LyXView.h"
#include "minibuffer.h"
#include "support/textutils.h"
// Returns the current selection. If nothing is selected or if the selection
// spans 2 paragraphs, an empty string is returned.
static
string GetCurrentSelectionAsString(LyXText * lt)
{
string sz;
LyXParagraph * par = lt->cursor.par;
if (lt->selection && lt->sel_cursor.par == par) {
// (selected) and (begin/end in same paragraph)
LyXParagraph::size_type pos =
lt->sel_start_cursor.pos;
LyXParagraph::size_type endpos =
lt->sel_end_cursor.pos;
bool fPrevIsSpace = false;
char ch;
while (pos < par->Last() && pos < endpos) {
ch = par->GetChar(pos);
//HB??: Maybe (ch <= ' ')
if ((ch == ' ') || (ch <= LyXParagraph::META_INSET)) {
// consecutive spaces --> 1 space char
if (fPrevIsSpace) {
++pos; // Next text pos
continue; // same search pos
}
sz += ' ';
fPrevIsSpace = true;
} else {
sz += ch;
fPrevIsSpace = false;
}
++pos;
}
}
return sz;
}
// If nothing selected, select the word at the cursor.
// Returns the current selection
static inline
string GetSelectionOrWordAtCursor(LyXText * lt)
{
lt->SelectWordWhenUnderCursor();
return GetCurrentSelectionAsString(lt);
}
// This is a copy of SetSelectionOverString from text.C
// It does the same, but uses only the length as a parameter
static inline
void SetSelectionOverLenChars(LyXText * lt, int len)
{
lt->sel_cursor = lt->cursor;
for (int i = 0; i < len; ++i)
lt->CursorRight();
lt->SetSelection();
}
//------------------------------
LyXFindReplace::LyXFindReplace()
: bv(0)
{}
LyXFindReplace::~LyXFindReplace()
{}
void LyXFindReplace::StartSearch(BufferView * b)
{
bv = b;
SF.StartSearch(this);
SF.replaceEnabled(!bv->buffer()->isReadonly());
searchForward = true;
if (SF.SearchString().empty())
SF.SetSearchString(GetSelectionOrWordAtCursor(bv->text));
}
// TODO?: the user can insert multiple spaces with this
// routine (1999-01-11, dnaber)
void LyXFindReplace::SearchReplaceCB()
{
if (!bv->available()) return;
if (bv->buffer()->isReadonly()) return;
// CutSelection cannot cut a single space, so we have to stop
// in order to avoid endless loop :-(
if (SF.SearchString().length() == 0
|| (SF.SearchString().length() == 1
&& SF.SearchString()[0] == ' ') ) {
WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
"nor an empty character."));
return;
}
string const replacestring = SF.ReplaceString();
bv->hideCursor();
bv->update(-2);
LyXText * ltCur = bv->text;
if (ltCur->selection) {
// clear the selection (if there is any)
bv->toggleSelection(false);
bv->text->
ReplaceSelectionWithString(replacestring.c_str());
bv->text->
SetSelectionOverString(replacestring.c_str());
bv->update(1);
}
// jump to next match:
SearchCB(searchForward);
}
// replaces all occurences of a string (1999-01-15, dnaber@mini.gt.owl.de)
void LyXFindReplace::SearchReplaceAllCB()
{
if (!bv->available()) return;
if (bv->buffer()->isReadonly()) return;
// CutSelection cannot cut a single space, so we have to stop
// in order to avoid endless loop :-(
if (SF.SearchString().length() == 0
|| (SF.SearchString().length() == 1
&& SF.SearchString()[0] == ' ') ) {
WriteAlert(_("Sorry!"), _("You cannot replace a single space, "
"nor an empty character."));
return;
}
string const replacestring = SF.ReplaceString();
bv->hideCursor();
// start at top
bv->text->ClearSelection();
bv->text->CursorTop();
int replace_count = 0;
LyXText * ltCur;
do {
ltCur = bv->text;
if (ltCur->selection) {
bv->update(-2);
bv->toggleSelection(false);
bv->text->
ReplaceSelectionWithString(replacestring.c_str());
bv->text->
SetSelectionOverString(replacestring.c_str());
bv->update(1);
++replace_count;
}
} while (SearchCB(true));
if( replace_count == 0 ) {
LyXBell();
bv->owner()->getMiniBuffer()->Set(
_("String not found!"));
} else {
if (replace_count == 1) {
bv->owner()->getMiniBuffer()->Set(
_("1 string has been replaced."));
} else {
string str = tostr(replace_count);
str += _(" strings have been replaced.");
bv->owner()->getMiniBuffer()->Set(str);
}
}
}
bool LyXFindReplace::SearchCB(bool fForward)
{
// store search direction
searchForward = fForward;
if (!bv->available())
return false;
bv->hideCursor();
bv->update(-2);
LyXText * ltCur = bv->text;
if (ltCur->selection)
ltCur->cursor = fForward ? ltCur->sel_end_cursor :
ltCur->sel_start_cursor;
iLenSelected = SF.SearchString().length();
bool result;
if (!SF.ValidSearchData() ||
(fForward ? SearchForward(ltCur) : SearchBackward(ltCur))) {
bv->update(-2);
// clear the selection (if there is any)
bv->toggleSelection();
bv->text->ClearSelection();
// set the new selection
SetSelectionOverLenChars(bv->text, iLenSelected);
bv->toggleSelection(false);
bv->owner()->getMiniBuffer()->Set(_("Found."));
result = true;
} else {
LyXBell();
bv->owner()->getMiniBuffer()->Set(_("String not found!"));
result = false;
}
if (bv->focus())
bv->showCursor();
return result;
}
// if the string can be found: return true and set the cursor to
// the new position
// (was: LyXText::SearchForward(char const* string) in text2.C )
bool LyXFindReplace::SearchForward(LyXText * lt)
{
LyXParagraph * par = lt->cursor.par;
LyXParagraph::size_type pos = lt->cursor.pos;
while (par && !IsSearchStringInText(par, pos)) {
if (pos < par->Last() - 1)
++pos;
else {
pos = 0;
par = par->Next();
}
}
if (par) {
lt->SetCursor(par, pos);
return true;
} else
return false;
}
// if the string can be found: return true and set the cursor to
// the new position
// (was: LyXText::SearchBackward(char const* string) in text2.C )
bool LyXFindReplace::SearchBackward(LyXText * lt)
{
LyXParagraph * par = lt->cursor.par;
int pos = lt->cursor.pos;
do {
if (pos > 0)
--pos;
else {
// We skip empty paragraphs (Asger)
do {
par = par->Previous();
if (par)
pos = par->Last() - 1;
} while (par && pos < 0);
}
} while (par && !IsSearchStringInText(par, pos));
if (par) {
lt->SetCursor(par, pos);
return true;
} else
return false;
}
/* Compares 2 char values.
return value is
> 0 if chSearch > ch2
= 0 if chSearch == ch2
< 0 if chSearch < ch2
*/
int LyXFindReplace::CompareChars(char chSearch, char chText) const
{
if (SF.CaseSensitive())
return (chSearch - chText);
return (toupper(chSearch) - toupper(chText));
}
// returns true if the search string is at the specified position
// (Copied from the original "LyXText::IsStringInText" in text2.C )
bool LyXFindReplace::IsSearchStringInText(LyXParagraph * par,
LyXParagraph::size_type pos) const
{
if (!par) return false;
char chSrch = 0;
char chText;
bool fPrevIsSpace = false;
int iText = 0;
string::size_type iSrch = 0;
while (pos + iText < par->Last() &&
iSrch < SF.SearchString().length()) {
chSrch = SF.SearchString()[iSrch];
chText = par->GetChar(pos+iText);
if (chText == ' ') {
if (fPrevIsSpace) {
++iText; // next Text pos
continue; // same search pos
}
fPrevIsSpace = true;
} else
fPrevIsSpace = false;
if (CompareChars(chSrch, chText) != 0)
break;
++iSrch;
++iText;
}
if (iSrch < SF.SearchString().length())
return false;
if (!SF.MatchWord()
|| ((pos <= 0 || !IsLetterCharOrDigit(par->GetChar(pos - 1)))
&& (pos + iText >= par->Last()
|| !IsLetterCharOrDigit(par->GetChar(pos + iText))))) {
iLenSelected = iText;
return true;
}
return false;
}