Page 1 of 1

Deleting a range

Posted: Fri Oct 31, 2014 7:44 pm
by Alvaro
Hi, in search query I put "delete lines" and I choosed Search for all terms, but nothing helped me.
My question is how can I delete more then one line following this steps:
Suppose a text:

reserved word(i)
text
text
text
reserved word(f)

I would like to select a range starting at reserved word(i) until reserved word(f) and delete all lines in this range.

I tryed this, but returned an error, could you help me, please?

Code: Select all

rve.SearchText('Inicia bloco', [rvseoDown, rvseoWholeWord]).ToInteger;
nPosI := RVGetLinearCaretPos(rve);
rve.SearchText('Termina bloco', [rvseoDown, rvseoWholeWord]).ToInteger;
nPosF := RVGetLinearCaretPos(rve);

rve.DeleteParas(nPosI, nPosF);

or

rve.SetSelectionBounds(nPosI, rve.GetOffsBeforeItem(nPosI), nPosF, rve.GetOffsAfterItem(nPosF));
rve.DeleteSelection;


Posted: Sun Nov 02, 2014 11:35 am
by Sergey Tkachenko
You must not use RVGetLinearCaretPos here. This function returns a number of characters from the beginning of document to the caret position. But DeleteParas and SetSelectedBounds does not need this value, they need index of item.

The first code could be:

Code: Select all

rve.SearchText('Inicia bloco', [rvseoDown, rvseoWholeWord]);
nPosI := rve.CurItemNo;
rve.SearchText('Termina bloco', [rvseoDown, rvseoWholeWord]);
nPosF := rve.CurItemNo;
rve.DeleteParas(nPosI, nPosF); 
It deletes all paragraphs, starting from paragraphs containing the first word and ending to paragraph containing the last word. Document is reformatted, but this change is not written in undo buffer, so it may become invalid, and you need to call rve.ClearUndo.

Do you need to delete reserved words as well? In this case, the second code could be:

Code: Select all

var ItemNoI, ItemNoF, OffsI, OffsF: Integer;

rve.SearchText('Inicia bloco', [rvseoDown, rvseoWholeWord]); 
rve.GetSelectionBounds(ItemNoI, OffsI, dummy, dummy, True); // storing the position  before selection in ItemNoI, OffsI
rve.SearchText('Termina bloco', [rvseoDown, rvseoWholeWord]); 
rve.GetSelectionBounds(dummy, dummy, ItemNoF, OffsF, True);// storing the position  after selection in ItemNoF, OffsF

rve.SetSelectionBounds(ItemNoI, OffsI, ItemNoF, OffsF);
rve.DeleteSelection;
Note 1: In a real code, you need to check the result of SearchText to see if the word was really found.
Note 2: These code fragments assume that both words are in the root editor, not in table cells. The second code can be modified to support table cells:

Code: Select all

var ItemNoI, ItemNoF, OffsI, OffsF: Integer;
  tle1, tle2: TCustomRichViewEdit;

rve.SearchText('Inicia bloco', [rvseoDown, rvseoWholeWord]); 
tle1 := rve.TopLevelEditor;
tle1.GetSelectionBounds(ItemNoI, OffsI, dummy, dummy, True); // storing the position  before selection in ItemNoI, OffsI
rve.SearchText('Termina bloco', [rvseoDown, rvseoWholeWord]); 
tle2 := rve.TopLevelEditor;
tle2.GetSelectionBounds(dummy, dummy, ItemNoF, OffsF, True);// storing the position  after selection in ItemNoF, OffsF
if tle1=tle2 then begin // otherwise, the selection is in different cells
  tle2.SetSelectionBounds(ItemNoI, OffsI, ItemNoF, OffsF);
  tle2.DeleteSelection;
end;

Posted: Sun Nov 02, 2014 11:39 pm
by Alvaro
Thank you very much Sergey was exactly what I needed, here in Brazil is still night, but have a excelente day my friend.

Re: Deleting a range

Posted: Wed Apr 30, 2025 8:09 am
by DanielM
var ItemNoI, ItemNoF, OffsI, OffsF: Integer;
tle1, tle2: TCustomRichViewEdit;

rve.SearchText('Inicia bloco', [rvseoDown, rvseoWholeWord]);
tle1 := rve.TopLevelEditor;
tle1.GetSelectionBounds(ItemNoI, OffsI, dummy, dummy, True); // storing the position before selection in ItemNoI, OffsI
rve.SearchText('Termina bloco', [rvseoDown, rvseoWholeWord]);
tle2 := rve.TopLevelEditor;
tle2.GetSelectionBounds(dummy, dummy, ItemNoF, OffsF, True);// storing the position after selection in ItemNoF, OffsF
if tle1=tle2 then begin // otherwise, the selection is in different cells
tle2.SetSelectionBounds(ItemNoI, OffsI, ItemNoF, OffsF);
tle2.DeleteSelection;
end;
I tried this code and if the delimiting words are in different cells, and there are other words after the first one, the delimiters are deleted, but also what is between them.

How can I delete delimited text when it is in different cells?

Re: Deleting a range

Posted: Wed Apr 30, 2025 9:06 am
by Sergey Tkachenko
This code must do nothing is the words are in different cells.
The check "if tle1=tle2 then" is to ensure that the words are in the same cell.

The code for deleting content between two cells would be much more complicated.
What does "content between cells" mean? If the cells are in different rows and columns? If they are in different tables, maybe nested in each other?

Re: Deleting a range

Posted: Wed Apr 30, 2025 9:13 am
by DanielM
Theoretically it should delete everything between the two keywords, true, it could be on other rows, but never in different tables.

Re: Deleting a range

Posted: Wed Apr 30, 2025 9:40 am
by Sergey Tkachenko
For example, if the cells are (2, 2) and (3,3).
Should it clear the cells in the (2, 3) and (3, 2)?
Or should it clear all cels in the row after (2, 2), and all cells in the row before (3, 3)?

Re: Deleting a range

Posted: Wed Apr 30, 2025 9:51 am
by DanielM
Like this demo, remove all item between \if_del\ and \end_del\
3.png
3.png (48.13 KiB) Viewed 569 times

Re: Deleting a range

Posted: Wed Apr 30, 2025 12:47 pm
by Sergey Tkachenko
The original code has a bug.
It's incorrect to compare tle1 and tle2.
If a new tle2 is created, tle1 is destroyed.
It is possible that the Delphi memory manager reuses a freed memory, so tle1 = tle2.

The comparison must be like this:

Code: Select all

var ItemNoI, ItemNoF, OffsI, OffsF: Integer;
tle1, tle2: TCustomRichViewEdit;
SourceData: TCustomRVData;

rve.SearchText('Inicia bloco', [rvseoDown, rvseoWholeWord]);
tle1 := rve.TopLevelEditor;
SourceData := tle1.RVData.GetSourceRVData;
tle1.GetSelectionBounds(ItemNoI, OffsI, dummy, dummy, True); // storing the position before selection in ItemNoI, OffsI
rve.SearchText('Termina bloco', [rvseoDown, rvseoWholeWord]);
tle2 := rve.TopLevelEditor;
tle2.GetSelectionBounds(dummy, dummy, ItemNoF, OffsF, True);// storing the position after selection in ItemNoF, OffsF
if SourceData = tle2.RVData.GetSourceRVData then// otherwise, the selection is in different cells
begin
  tle2.SetSelectionBounds(ItemNoI, OffsI, ItemNoF, OffsF);
  tle2.DeleteSelection;
end;

Re: Deleting a range

Posted: Wed Apr 30, 2025 1:02 pm
by Sergey Tkachenko
The code supporting starting and ending codes in different cells is below.

This kind of selection (from the starting cell till the end of the row; then all cells in the rows between; then cells till the ending cell) is not natural for TRichViewEdit: TRichViewEdit selects cell that are inside the specified rectangular area.
As a result, all cells need to be cleared one-by-one; and the code became large.

Code: Select all

procedure DeleteBetween(rve: TCustomRichViewEdit; const StartWord, EndWord: String);
var
  ItemNoI, ItemNoF, OffsI, OffsF, dummy, R1, C1, R2, C2, R, C: Integer;
  tle1, tle2: TCustomRichViewEdit;
  Cell1, Cell2: TRVTableCellData;
  SourceData: TCustomRVData;
  Table: TRVTableItemInfo;
begin
  if not rve.SearchText(StartWord, [rvseoDown, rvseoWholeWord]) then
    exit;
  tle1 := rve.TopLevelEditor;
  SourceData := tle1.RVData.GetSourceRVData;
  // storing the position  before selection in ItemNoI, OffsI
  tle1.GetSelectionBounds(ItemNoI, OffsI, dummy, dummy, True);
  if rve.TopLevelEditor <> rve then
  begin
    // if the word is in a table, storing this table and the cell
    Cell1 := SourceData as TRVTableCellData;
    Table := Cell1.GetTable;
    Table.GetCellPosition(Cell1, R1, C1);
  end
  else
  begin
    Table := nil;
    Cell1 := nil;
  end;
  if not rve.SearchText(EndWord, [rvseoDown, rvseoWholeWord]) then
    exit;
  tle2 := rve.TopLevelEditor;
  tle2.GetSelectionBounds(dummy, dummy, ItemNoF, OffsF, True);// storing the position  after selection in ItemNoF, OffsF
  if SourceData = tle2.RVData.GetSourceRVData then
  begin
    // the both words are in the same document/subdocument
    tle2.SetSelectionBounds(ItemNoI, OffsI, ItemNoF, OffsF);
    tle2.DeleteSelection;
  end
  else if (Table <> nil) and (rve.TopLevelEditor <> rve) then
  begin
    // the both words are in tables (or in the same table)
    Cell2 := tle2.RVData.GetSourceRVData as TRVTableCellData;
    if Cell2.GetTable <> Table then
      exit;
    // the both words are in the same table
    Table.GetCellPosition(Cell2, R2, C2);
    rve.Und
    rve.BeginUpdate;
    try
      rve.BeginUndoGroup2(rvutDelete);
      // deleting content in the ending cell
      tle2.SetSelectionBounds(0, tle2.GetOffsBeforeItem(0), ItemNoF, OffsF);
      rve.DeleteSelection;
      // deleting content in the starting cell
      Cell1.Edit;
      TCustomRVFormattedData(Cell1.GetRVData).SetSelectionBounds(ItemNoI, OffsI,
        Cell1.GetRVData.ItemCount - 1,
        Cell1.GetRVData.GetOffsAfterItem(Cell1.GetRVData.ItemCount - 1));
      rve.DeleteSelection;
      if R2 <> R1 then
      begin
        // clearing all cells after the starting cell
        for C := C1 + 1 to Table.ColCount - 1 do
          if Table.Cells[R1, C] <> nil then
          begin
            Table.Select(R1, C, 0, 0);
            rve.DeleteSelection;
          end;
        // clearing all rows between
        for R := R1 + 1 to R2 - 1 do
          for C := 0 to Table.ColCount - 1 do
            if Table.Cells[R, C] <> nil then
            begin
              Table.Select(R, C, 0, 0);
              rve.DeleteSelection;
            end;
        // clearing all cells before the ending cell
        for C := 0 to C2 - 1 do
          if Table.Cells[R2, C] <> nil then
          begin
            Table.Select(R2, C, 0, 0);
            rve.DeleteSelection;
          end;
      end
      else
        // clearing all cells between
        for C := C1 + 1 to C2 - 1 do
          if Table.Cells[R1, C] <> nil then
          begin
            Table.Select(R1, C, 0, 0);
            rve.DeleteSelection;
          end;
      rve.EndUndoGroup2(rvutDelete);
      rve.TopLevelEditor.Change;
    finally
      rve.EndUpdate;
    end;
  end;
end;

Re: Deleting a range

Posted: Wed Apr 30, 2025 1:05 pm
by DanielM
Yes, now it detects the two keywords in the text ok, but the problem remained with detecting keywords in tables an remove text in cells.

Re: Deleting a range

Posted: Wed Apr 30, 2025 1:07 pm
by DanielM
Wow, how fast you posted, I'll try the acid towards the end of the weekend. Thanks.