Mega Code Archive

 
Categories / Delphi / Examples
 

Paragraph pouring from a text editor

In a word processor, you can work on paragraphs and then pour them into other programs as single lines, wrapped by the receiving windows. Here's how to write this into an ordinary text editor. Paragraph "pouring" from a text editor By Gene Fowler acorioso@ccnet.com Notes: 1: If you are putting code from my several articles about mdi text editors into one copy of TextEdit, there is a correction to be made in the SaveAs1Click routine you have in there. The line OpenFiles.Insert(Tag, Pathname); should be replaced by OpenFiles.Insert(0, Pathname); This matters here, because saving a New File is affected. Your first tests will undoubtedly be made in a New File. I assume TextEdit's original SaveAs1Click will not prsent any problem. I brought in my code from the very much more complex eWriter. 2: The test-bed for this code is Borland's TextEdit demo that comes with Delphi. If you are compiling in Delphi 5 or 5.01, you will need the modified forms.pas which I direct you to in my earlier article, Programming System/Next (Prev) in MDI editors. You can ignore the warning about 5.0x, because you do not need to do any child-window handling. One writing window is all you need to test the feature. I used the feature in my textwriter, eWriter, to pour this article into the page you are reading right now. You can use TextEdit to test the feature. Actually, TextEdit wraps lines at the window edge and exports paragraphs as single lines. You will have to widen TextEdit far enough beyond the line ends you create with your Enter key to prevent forgetting to Enter so the window wraps. In eWriter, I use "column wrap" so Enter isn't used for every line. The idea in a text editor or textwriter, though, is that you have column wrap or use the Enter key. Shaping the text is the writer's choice. It isn't a stream. However, the writer, then, may want to pour text into some windows and let them wrap or, as I do with Outlook Express, let the program wrap. OE wraps when it sends the text. TextEdit is an ordinary text editor. I say ordinary rather than plain, because it prints 8-bit characters, but it is ordinary in that it isn't an rtf editor. It's closer to Notepad than to Wordpad. But as you know, it is in a RichEdit control. This allows a good deal of magic. Want visual bookmarks? Mark blocks of text (phrases, titles, etc.) and color them red. Then, you can scroll among them quickly. Or, if you are working on html files, color your tags on loading (as an option). You can do all these things backstage in the RichEdit and those colorings do not affect your text at all. On the other hand, suppose you want to print your html text with colored tags. Export to another file as rtf and print from Wordpad. In the code below, I use a pair of memory streams to run the text through and pull out every #13#10 except where there are two, so that empty lines separating paragraphs remain to separate the filled lines. Editor.PlainText is set to False at the beginning and back to True at the end. This is how the magic box works. No doubt my reading and modifying the text stream could be simplified, but this works. Menu item: Caption: Pull n lines into 1 Name: NLinestoOne1 code: procedure TEditForm.NLinestoOne1Click(Sender: TObject); label Skip; var Stream1, Stream2: TMemoryStream; p, q: PChar; c: Char; IsPar: integer; procedure SetStreams; begin if Editor.Text <> '' then Editor.PlainText := False else Exit; Stream1 := nil; Stream2 := nil; try Stream1 := TMemoryStream.Create; Stream2 := TMemoryStream.Create; Stream1.SetSize(longInt(Length(Editor.Text))); Editor.Lines.SaveToStream(Stream1); Stream2.SetSize(2 * Stream1.Size); p := Stream1.Memory; q := Stream2.Memory; except if Stream1 <> nil then Stream1.Free; if Stream2 <> nil then Stream2.Free; end; end; begin if messageDlg('You may want the lines in blocks separated ' + 'by empty lines pulled up into single lines. You may ' + 'want paragraphs without line breaks so they can wrap at ' + 'a window edge. This will do it.'#13#13 + 'WARNING: This processes the entire file. If you wish to apply ' + 'this to only a block from the file, move it to another window ' + 'and process it there before moving it back.', mtInformation, [mbOK, mbCancel],0)= mrCancel then Exit; If Editor.Text = '' then Exit; IsPar := 0; try SetStreams; While not (p^ = #0) do begin c := p^; inc(p); if (IsPar = 4) and (c = ' ') then IsPar := 5 else if (IsPar = 3) and (c = 'r') then IsPar := 4 else if (IsPar = 2) and (c = 'a') then IsPar := 3 else if (IsPar = 1) and (c = 'p') then IsPar := 2 else if c = '\' then IsPar := 1 else IsPar := 0; if (IsPar = 5) then begin if not (p^ = #13) then q := q - 4 // removes \par, leaves following space else begin dec(q^); q^ := c; inc(q); q^ := '\'; inc(q); q^ := 'p'; inc(q); q^ := 'a'; inc(q); q^ := 'r'; inc(q); p := p + 7; // skip #13#10\par(sp) end; end; q^ := c; inc(q); if p^ = #0 then q^ := #0; end; Editor.Text := ''; Editor.Lines.LoadFromStream(Stream2); finally if Stream1 <> nil then Stream1.Free; if Stream2 <> nil then Stream2.Free; Editor.PlainText := True; Editor.Modified := True; end; end