Page 2 of 3

Posted: Wed Nov 24, 2010 4:27 pm
by jonjon
Are the character, paragraph and line count functions tread-safe ? Thanks in advance.

Posted: Wed Nov 24, 2010 5:25 pm
by Sergey Tkachenko
Interesting question.
Characters, paragraphs - yes.
As for word enumeration, as I can see, it is safe too, with one possible problem. It uses TRVWordEnumerator class that was primarily created for spell checking. When called for TRichViewEdit, it prevents its form from closing by assigning its OnCloseQuery event and restoring it after its work.
If several word enumerators will work at the same time in threads, it may happen that the original OnCloseQuery will not be restored.

Posted: Thu Nov 25, 2010 9:44 am
by jonjon
Thank you Sergey.

Posted: Mon Apr 11, 2011 4:39 pm
by Sergey Tkachenko
Calculating paragraph counts in the way like MS Word: empty paragraphs are not taken into account.
Paragraphs are considered empty if they do not contain any of:
- non-empty text items (at least one non-space character);
- bullet or numbering (text);
- non-empty labelitem (label/number/footnote/endnote)
As you can see, paragraph containing only pictures, spaces and tabs are considered empty.
For tables, the count of paragraphs equals to sum of counts of paragraphs in all its cells. The table itself is not counted as a paragraph.

Code: Select all

function GetParaCount(RVData: TCustomRVData): Integer;
var i, r, c, StyleNo: Integer;
    table: TRVTableItemInfo;
    EmptyPara: Boolean;
    ListNo, ListLevel, StartFrom: Integer;
    Reset: Boolean;
begin
  Result := 0;
  EmptyPara := True;
  for i := 0 to RVData.ItemCount-1 do begin
    if RVData.IsParaStart(i) then begin
      if not EmptyPara then
        inc(Result);
      EmptyPara := True;
    end;
    StyleNo := RVData.GetItemStyle(i);
    if StyleNo=rvsListMarker then begin
      RVData.GetListMarkerInfo(i,ListNo, ListLevel, StartFrom, Reset);
      if (ListNo>=0) and (ListNo<RVData.GetRVStyle.ListStyles.Count) and
         (ListLevel>=0) and (ListLevel<RVData.GetRVStyle.ListStyles[ListNo].Levels.Count) and
         RVData.GetRVStyle.ListStyles[ListNo].Levels[ListLevel].UsesFont then
        EmptyPara := False
      end
    else if RVData.GetItem(i) is TRVLabelItemInfo then begin
      if Trim(TRVLabelItemInfo(RVData.GetItem(i)).Text)<>'' then
      end
    else if StyleNo>=0 then begin
      if Trim(RVData.GetItemText(i))<>'' then
        EmptyPara := False;
      end
    else if StyleNo=rvsTable 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
            inc(Result, GetParaCount(table.Cells[r,c].GetRVData));
    end;
  end;
  if not EmptyPara then
    inc(Result);
end;
Use:

Code: Select all

  lblParaCount.Caption := IntToStr(GetParaCount(RichViewEdit1.RVData));

Posted: Tue Jun 07, 2011 6:36 am
by Marsianin
Ok, everything works fine here, i can count words/characters/paragraphs but still have some quiestions:

1. When counting document lines globally (including tables) how can I check cursor position globally too? Because RVE.GetCurrentLineCol(line,col); returns only local line number.

2. Using GetLineCount(RVE.RVData); from your example inside RVE.OnCaretMove generates errors. How can I avoid this checking cursor position when it moves?

Posted: Thu Jun 16, 2011 7:39 am
by Marsianin
Any suggestions?

Posted: Thu Jun 16, 2011 4:22 pm
by Sergey Tkachenko
May be you can try to use a PostMessage from OnCaretMove to calculate line/col outside of this event?

Posted: Fri Jun 17, 2011 11:17 pm
by Marsianin
No idea :roll:

Posted: Thu Jun 23, 2011 1:03 am
by Marsianin
So how can I get cursor/current line globally?
Your example shows how to count lines including tables but when you get cursor inside the table GetCurrentLineCol(line,col) will give you local in-cell line number.

Posted: Sat Jul 02, 2011 1:24 am
by Marsianin
I want to know global current line number.
How can I check if we got cursor in the current line in this routine:

Code: Select all

...
if RVData.GetItemStyle(RVData.DrawItems[i].ItemNo)=rvsTable then begin
  table := TRVTableItemInfo(RVData.GetItem(RVData.DrawItems[i].ItemNo));
  for r := 0 to table.RowCount-1 do
    for c := 0 to table.ColCount-1 do
      if table.Cells[r,c]<>nil then
        inc(Result, GetLineCount(TCustomRVFormattedData(table.Cells[r,c].GetRVData)));
...

Posted: Sun Jul 03, 2011 12:46 pm
by Sergey Tkachenko

Code: Select all

function GetCurrentLine(rve: TCustomRichViewEdit): Integer;
var
  CurRVData: TCustomRVFormattedData;
  CurDItemNo: Integer;
  CurDOffs: Integer;

  function DoGetCurrentLine(RVData: TCustomRVFormattedData; var LineNo: Integer): Boolean;
  var i,r,c: Integer;
     table: TRVTableItemInfo;
  begin
    Result := False;
    for i := 0 to RVData.DrawItems.Count-1 do begin
      if RVData.DrawItems[i].FromNewLine then
        inc(LineNo);
      Result := (RVData=CurRVData) and (i=CurDItemNo);
      if Result then
        exit;
      if RVData.GetItemStyle(RVData.DrawItems[i].ItemNo)=rvsTable then begin
        table := TRVTableItemInfo(RVData.GetItem(RVData.DrawItems[i].ItemNo));
        for r := 0 to table.RowCount-1 do
          for c := 0 to table.ColCount-1 do
            if table.Cells[r,c]<>nil then begin
              Result := DoGetCurrentLine(TCustomRVFormattedData(table.Cells[r,c].GetRVData), LineNo);
              if Result then
                exit;
            end;
      end;
    end;
  end;

begin
  CurRVData := rve.TopLevelEditor.RVData;
  CurRVData.Item2DrawItem(rve.TopLevelEditor.CurItemNo,
    rve.TopLevelEditor.OffsetInCurItem, CurDItemNo, CurDOffs);
  Result := 0;
  DoGetCurrentLine(rve.RVData, Result);
end;
In this procedure, lines are counted in RichViewEdit's way: a table itself is treated as a line (the next line after the table is the first line in the first cell).

Posted: Mon Jul 04, 2011 2:45 am
by Marsianin
But the table may contain several lines and in your first example it counts them.
So I can have just one table with 100 lines and get 100 lines result in your line count example. And this is what I need. Just want to know cursor line number according all my 100 lines (now I'm getting 100 lines total and current line is some 3rd line in a table cell, but must include all previous lines)

Posted: Tue Jul 05, 2011 7:59 am
by Sergey Tkachenko
Yes, this GetCurrentLine calculates the current line using the same method as GetLineCount.
These functions are compatible.

Posted: Tue Jul 05, 2011 8:36 am
by Marsianin
Ok, thanks. I didn't see it's another function.
I'm going to join GetCurrentLine and GetLineCount in one function to not do same job twice.

Posted: Thu Jan 26, 2012 3:36 pm
by Petko
Sergey, how can we get the same statistics (characters, words and lines) for the selected text instead for the whole document (for paragraphs there is already as I see)?