Page 1 of 2
[Example] DeleteBlankLines, RemoveParagraphBreaks, etc.
Posted: Tue Sep 06, 2005 8:45 pm
by Sergey Tkachenko
This code deletes all empty lines:
Code: Select all
procedure DeleteBlankLines(RVData: TCustomRVData);
var i,r,c: Integer;
table: TRVTableItemInfo;
begin
for i := RVData.ItemCount-1 downto 0 do
if RVData.IsFromNewLine(i) and (RVData.GetItemStyle(i)>=0) and
(RVData.GetItemText(i)='') and (RVData.ItemCount>1) and
((i = RVData.ItemCount - 1) or RVData.IsFromNewLine(i+1)) then
RVData.DeleteItems(i,1)
else if RVData.GetItem(i) is TRVTableItemInfo then
begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.RowCount-1 do
for c := 0 to table.ColCount-1 do
if table.Cells[r,c]<>nil then
DeleteBlankLines(table.Cells[r,c].GetRVData);
end;
end;
This procedure cannot be undone/redone. If called for editor, the editor's undo buffer becomes incorrect, so call ClearUndo.
Call:
Code: Select all
DeleteBlankLines(RichViewEdit1.RVData);
RichViewEdit1.ClearUndo;
RichViewEdit1.Format;
- [+] History of changes
-
2018-May-28: making sure that the deleted item is a single line; changed IsParaStart to IsFromNewLine
Posted: Tue Sep 06, 2005 8:51 pm
by Sergey Tkachenko
This procedure removes all line breaks that can be removed:
Code: Select all
procedure RemoveParagraphBreaks(RVData: TCustomRVData);
var i,r,c: Integer;
table: TRVTableItemInfo;
begin
for i := 0 to RVData.ItemCount-1 do
if (i>0) and RVData.IsFromNewLine(i) and
not RVData.GetItem(i).GetBoolValue(rvbpFullWidth) and
not RVData.GetItem(i-1).GetBoolValue(rvbpFullWidth) and
(RVData.GetItemStyle(i)<>rvsListMarker) then
RVData.GetItem(i).SameAsPrev := True
else if RVData.GetItem(i) is TRVTableItemInfo then
begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.RowCount-1 do
for c := 0 to table.ColCount-1 do
if table.Cells[r,c]<>nil then
RemoveParagraphBreaks(table.Cells[r,c].GetRVData);
end;
end;
This function cannot be undone/redone. If it's called for editor, information in the editor's undo buffer becomes incorrect, so you need to call RichViewEdit.ClearUndo.
In some cases, documents after calling this functions do not conform to the rules of valid RichView document (see the help file, "Valid
Documents" topic).
In order to fix it, call NormalizeRichView procedure from RVNormalize.pas. This unit is included in RichViewActions.
Call:
Code: Select all
RemoveParagraphBreaks(RichViewEdit1.RVData);
NormalizeRichView(RichViewEdit1.RVData);
RichViewEdit1.ClearUndo;
RichViewEdit1.Format;
Posted: Wed Nov 02, 2005 9:19 pm
by Sergey Tkachenko
Modification of DeleteBlankLines - removing blank lines only from the end of the document:
Code: Select all
procedure DeleteTrailingBlankLines(RVData: TCustomRVData);
var i: Integer;
begin
for i := RVData.ItemCount-1 downto 1 do
if RVData.IsParaStart(i) and (RVData.GetItemStyle(i)>=0) and
(RVData.GetItemText(i)='') then
RVData.DeleteItems(i,1)
else
break;
end;
Call:
Code: Select all
DeleteBlankLines(RichViewEdit1.RVData);
RichViewEdit1.ClearUndo;
RichViewEdit1.Format;
Posted: Tue Dec 13, 2005 7:40 pm
by Sergey Tkachenko
This procedure converts all single line breaks to "soft" line breaks (which can be added by Shift+Return keys). Double line breaks remain paragraph breaks (which can be added by Return key), but empty line is removed (actually, all empty lines are removed)
Code: Select all
procedure NormalizeLineBreaks(RVData: TCustomRVData);
var i,r,c: Integer;
table: TRVTableItemInfo;
begin
for i := RVData.ItemCount-1 downto 0 do
begin
if RVData.IsParaStart(i) then
begin
// removing empty line
if RVData.IsParaStart(i) and (RVData.GetItemStyle(i)>=0) and
(RVData.ItemCount>0) then
begin
RVData.DeleteItems(i,1);
continue;
end;
// converting "Return-linebreak" to "Shift+Return-linebreak", if
// there is no empty line before. Making sure that this conversion is
// not applied to tables and breaks, items after them, and the very first
// item
if (i>0) and not RVData.GetItem(i).GetBoolValue(rvbpFullWidth) and
not RVData.GetItem(i-1).GetBoolValue(rvbpFullWidth) and
(RVData.GetItemStyle(i)<>rvsListMarker) and
not ((RVData.GetItemStyle(i-1)>=0) and (RVData.GetItemText(i-1)='')) then
RVData.GetItem(i).BR := True;
continue;
end;
// recursive table traversal
if RVData.GetItem(i) is TRVTableItemInfo then
begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.RowCount-1 do
for c := 0 to table.ColCount-1 do
if table.Cells[r,c]<>nil then
NormalizeLineBreaks(table.Cells[r,c].GetRVData);
end;
end;
end;
Modified 2007-May-31: added (RVData.GetItemStyle(i)<>rvsListMarker) check
Posted: Thu May 31, 2007 1:10 pm
by Sergey Tkachenko
Similar function: removing all single line breaks and empty lines.
Code: Select all
procedure NormalizeLineBreaks2(RVData: TCustomRVData);
var i,r,c: Integer;
table: TRVTableItemInfo;
begin
for i := RVData.ItemCount-1 downto 0 do begin
if RVData.IsParaStart(i) then begin
// removing empty line
if RVData.IsParaStart(i) and (RVData.GetItemStyle(i)>=0) and
(RVData.ItemCount>0) then begin
RVData.DeleteItems(i,1);
continue;
end;
// Removing line break if there is no empty line before it
// Making sure that this conversion is
// not applied to tables and breaks, items after them,
// the very first item and list marker
if (i>0) and not RVData.GetItem(i).GetBoolValue(rvbpFullWidth) and
not RVData.GetItem(i-1).GetBoolValue(rvbpFullWidth) and
(RVData.GetItemStyle(i)<>rvsListMarker) and
not ((RVData.GetItemStyle(i-1)>=0) and (RVData.GetItemText(i-1)='')) then
RVData.GetItem(i).SameAsPrev := True;
continue;
end;
// recursive table traversal
if RVData.GetItemStyle(i)=rvsTable then begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.Rows.Count-1 do
for c := 0 to table.Rows[r].Count-1 do
if table.Cells[r,c]<>nil then
NormalizeLineBreaks2(table.Cells[r,c].GetRVData);
end;
end;
end;
It's recommended to call NormalizeRichView (RVNormalize.pas, can be found in RichViewActions) after calling this procedure.
Posted: Thu May 13, 2010 9:36 pm
by palmeira
I am not sure if this is a bug, but at least for some documents when I use DeleteBlankLines to delete a line, and the next paragraph has a different format (a border), the border is lost.
Posted: Fri May 14, 2010 8:51 pm
by Sergey Tkachenko
DeleteBlandLines assumes that document may have empty text items only as separate lines (paragraphs).
Do you generate your documents yourself?
Try calling NormalizeRichView procedure (RVNormalize.pas, included in RichViewActions) before DeleteBlandLines.
Posted: Fri Feb 28, 2014 5:54 am
by gary
A small improve, Replace Paragraph Breaks with space.
Code: Select all
procedure RemoveParagraphBreaks(RVData: TCustomRVData);
var i,r,c: Integer;
table: TRVTableItemInfo;
s: string;
begin
for i := 0 to RVData.ItemCount-1 do
if (i>0) and RVData.IsFromNewLine(i) and
not RVData.GetItem(i).GetBoolValue(rvbpFullWidth) and
not RVData.GetItem(i-1).GetBoolValue(rvbpFullWidth) and
(RVData.GetItemStyle(i)<>rvsListMarker) then
begin
if RVData.GetItemStyle(i) >= 0 then
begin
s := RVData.GetItemText(i);
if (Length(s) > 0) then
RVData.SetItemText(i, ' ' + s);
end;
RVData.GetItem(i).SameAsPrev := True
end
else if RVData.GetItemStyle(i)=rvsTable then begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.Rows.Count-1 do
for c := 0 to table.Rows[r].Count-1 do
if table.Cells[r,c]<>nil then
RemoveParagraphBreaks(table.Cells[r,c].GetRVData);
end;
end;
Posted: Fri Feb 28, 2014 7:35 am
by Sergey Tkachenko
This function is ok, except for it does not insert a space, if a paragraph started from a non-text item, such as image.
Posted: Sun Mar 02, 2014 2:21 am
by gary
A procedure to trim Leading And Trailing Spaces in paragraph.
Any suggestion is welcome.
Code: Select all
procedure TrimLeadingAndTrailingSpaces(RVData: TCustomRVData);
var
i,r,c: Integer;
s: string;
table: TRVTableItemInfo;
begin
for i := 0 to RVData.ItemCount - 1 do
begin
if RVData.IsParaStart(i) then
begin
if RVData.GetItemStyle(i) >= 0 then
begin
s := RVData.GetItemText(i);
s := TrimLeft(s);
RVData.SetItemText(i, s);
end;
if (i - 1 >= 0) and (RVData.GetItemStyle(i - 1) >= 0) then
begin
s := RVData.GetItemText(i - 1);
s := TrimRight(s);
RVData.SetItemText(i - 1, s);
end;
end;
if (i = RVData.ItemCount - 1) and (RVData.GetItemStyle(i) >= 0) then
begin
s := RVData.GetItemText(i);
s := TrimRight(s);
RVData.SetItemText(i, s);
end;
if RVData.GetItemStyle(i)=rvsTable then
begin
table := TRVTableItemInfo(RVData.GetItem(i));
for r := 0 to table.Rows.Count-1 do
for c := 0 to table.Rows[r].Count-1 do
if table.Cells[r,c]<>nil then
TrimLeadingAndTrailingSpaces(table.Cells[r,c].GetRVData);
end;
end;
end;
Posted: Mon Mar 03, 2014 5:33 am
by gary
A procedure is make these methods support apply to selection and support undo. Any suggestion is welcome.
gRVE: TRichViewEdit
RVEditor: TRichViewEdit
Code: Select all
function GetSelectedCells(ARVE: TRichViewEdit; ARowList, AColList: TList): TRVTableItemInfo;
var
ItemRichViewEdit: TCustomRichViewEdit;
item: TCustomRVItemInfo;
i, r, c: Integer;
StartRow, StartCol, RowOffs, ColOffs: Integer;
begin
ARowList.Clear;
AColList.Clear;
if ARVE.GetCurrentItemEx(TRVTableItemInfo, ItemRichViewEdit, item) then
begin
Result := TRVTableItemInfo(item);
if Result.GetSelectionBounds(StartRow, StartCol, RowOffs, ColOffs) then
begin
for r := 0 to Result.RowCount-1 do
for c := 0 to Result.ColCount-1 do
if (Result.Cells[r,c]<>nil) and Result.IsCellSelected(r,c) then
begin
ARowList.Add(Pointer(r));
AColList.Add(Pointer(c));
end;
end;
end;
if ARowList.Count = 0 then
Result := nil;
end;
procedure TfM.RemoveParagraphBreaks_Click(Sender: TObject);
var
table: TRVTableItemInfo;
i, r, c: Integer;
RowList, ColList: TList;
procedure ApplyChangeToSelection(ARVE: TCustomRichViewEdit)
var
Stream: TMemoryStream;
begin
Stream := TMemoryStream.Create;
try
ARVE.SaveRVFToStream(Stream, True);
Stream.Position := 0;
gRVE.LoadRVFFromStream(Stream);
RemoveParagraphBreaks(gRVE.RVData);
NormalizeRichView(gRVE.RVData);
gRVE.ClearUndo;
gRVE.Format;
Stream.Clear;
gRVE.SaveRVFToStream(Stream, False);
Stream.Position := 0;
ARVE.InsertRVFFromStreamEd(Stream);
finally
Stream.Free;
end;
end;
begin
RowList := TList.Create;
ColList := TList.Create;
try
table := GetSelectedCells(RVEditor, RowList, ColList);
if table <> nil then //Process Table->Select
begin
for i := 0 to RowList.Count - 1 do
begin
r := Integer(RowList[i]);
c := Integer(ColList[i]);
table.Cells[r,c].Edit;
RVEditor.TopLevelEditor.SelectAll;
ApplyChangeToSelection(RVEditor.TopLevelEditor);
end;
end
else
ApplyChangeToSelection(RVEditor);
finally
RowList.Free;
ColList.Free;
end;
end;
How to do Delete blank lines from a selection
Posted: Tue Jul 15, 2014 6:40 pm
by gdemers_logilys
I tried the code from the first post and it does what I need but on all the RichView content.
I need to do it on the selection only.
Posted: Fri Aug 01, 2014 7:00 pm
by Sergey Tkachenko
The last post by gary contains the function that is applied to the selection.
I did not test it myself, but I hope it works and can be useful for you.
Posted: Sun Aug 02, 2015 4:38 pm
by Sergey Tkachenko
Line breaks -> paragraph breaks
Converting all line breaks (added with Shift+Enter) to paragraph breaks (added with Enter).
Undoable. If selection is not empty, the procedure is applied to the selection. Otherwise, it is applied to the whole document (if the caret is in a table cell, it is applied to the whole cell).
This procedure is not applied to selected table cells.
Code: Select all
procedure NormalizeLineBreaksEd(rve: TCustomRichViewEdit);
var ItemNo1, Offs1, ItemNo2, Offs2: Integer;
Whole, FR: Boolean;
i: Integer;
begin
rve := rve.TopLevelEditor;
if not rve.BeforeChange(False) then
exit;
rve.GetSelectionBounds(ItemNo1, Offs1, ItemNo2, Offs2, True);
Whole := (ItemNo1<0) or ((ItemNo1=ItemNo2) and (Offs1=Offs2));
if Whole then begin
ItemNo1 := 0;
ItemNo2 := rve.ItemCount-1;
end;
rve.BeginUndoGroup(rvutPara);
rve.SetUndoGroupMode(True);
for i := ItemNo2 downto ItemNo1 do
if rve.IsFromNewLine(i) then
TRVEditRVData(rve.RVData).Do_BR(i, False, FR);
rve.SetUndoGroupMode(False);
rve.Change;
rve.Reformat;
end;
Paragraph breaks -> line breaks
The opposite procedure.
Code: Select all
procedure MakeSoftLineBreaksEd(rve: TCustomRichViewEdit);
var ItemNo1, Offs1, ItemNo2, Offs2: Integer;
Whole, FR: Boolean;
i: Integer;
begin
rve := rve.TopLevelEditor;
if not rve.BeforeChange(False) then
exit;
rve.GetSelectionBounds(ItemNo1, Offs1, ItemNo2, Offs2, True);
Whole := (ItemNo1<0) or ((ItemNo1=ItemNo2) and (Offs1=Offs2));
if Whole then begin
ItemNo1 := 0;
ItemNo2 := rve.ItemCount-1;
end;
rve.BeginUndoGroup(rvutPara);
rve.SetUndoGroupMode(True);
if ItemNo1<1 then
ItemNo1 := 1;
for i := ItemNo2 downto ItemNo1 do
if rve.IsParaStart(i) and (rve.GetItemStyle(i)<>rvsListMarker) and
not rve.GetItem(i-1).GetBoolValue(rvbpFullWidth) then
TRVEditRVData(rve.RVData).Do_BR(i, True, FR);
rve.SetUndoGroupMode(False);
rve.Change;
rve.Reformat;
end;
Unfortunately, TRichViewEdit does not have documented methods for converting line breaks, so these procedures use undocumented methods.
Re:
Posted: Tue Jun 20, 2017 6:12 pm
by filo
Sergey Tkachenko wrote: ↑Wed Nov 02, 2005 9:19 pm
Modification of DeleteBlankLines - removing blank lines only from the end of the document:
Code: Select all
procedure DeleteTrailingBlankLines(RVData: TCustomRVData);
var i: Integer;
begin
for i := RVData.ItemCount-1 downto 1 do
if RVData.IsParaStart(i) and (RVData.GetItemStyle(i)>=0) and
(RVData.GetItemText(i)='') then
RVData.DeleteItems(i,1)
else
break;
end;
Call:
Code: Select all
DeleteBlankLines(RichViewEdit1.RVData);
RichViewEdit1.ClearUndo;
RichViewEdit1.Format;
Hi Sergey,
thank you for your code, works perfectly with RichViewEdit, but something is wrong with ScaleRichViewEdit in case when there are more than one blank lines at the end of the document AND caret is positioned at the end of document.
In that case I have got an error message List Index out of bounds (x) where x is number of all lines -1.
How to reproduce:
dfm:
- Empty form with SRichViewEdit component
pas:
- Implement code above
runtime:
- Type some character on the first line and 2 blank lines (or make 3 blank lines, it doesn't matter)
- Call DeleteBlankLines
Thank you for your answer.
PS: I'm using RichEdit 16.15.2, demo version