Simulated MDI (one editor, multiple documents)

 

If the user should be able to edit multiple documents at the same time, very often the approach is to create multiple editor objects. Those can be on frames, MDI child windows or other different forms. WPTools supports this concept, i.e. it allows it to use just one toolbar for all editors and only the editor which was used last, will be active.

 

But often this approach is not wanted and also not used very much any more. Instead a tabbed user interface should be used:

 

clip0028

 

With WPTools this interface can be developed easily, stable and straight forward. You do not need to create multiple TWPRichText objects.

You only need one TWPRichText and switch the attached RTFDataCollection.

 

This is a feature which is possible because of the consequent separation of display logic and data structures, sometimes some competing products do not have. Basically you have multiple documents in memory and let one editor edit one after the other. This has several advantages:

 

1) Save windows resources (handles)

2) Avoid focus problems (MDI children can take away the focus of a window)

3) Share paragraph styles between editors

4) It is easy to manipulate all documents by code within one loop

5) Create the GUI more quickly

6) More stable concept

 

We enhanced the "mini" editor to do so (see the demo "DynamicRTFData/SimulatedMDI"). We just added a tab-set to switch between the documents, some code to intercept the OPEN, CLOSE and NEW actions of the TWPToolbar and of course a list with RTFData objects handled by TStringlist.

 

 

 

Variables:

 

type

 TForm1 = class(TForm)

...

public

  FRTFDataCollections : TStringList;

  function  AddRTFData(name : string) : Integer;

  procedure InitTabset;

  procedure DelRTFData;

end;

 

var

 Form1: TForm1;

 

implementation

 

{$R *.DFM}

 

Add a document

 

function TForm1.AddRTFData(name : string) : Integer;

var element : TWPRTFDataCollection;

begin

 element   := TWPRTFDataCollection.Create(TWPRTFDataBlock);

 element.MakeRTFProps;

 Result    := FRTFDataCollections.Count;

 FRTFDataCollections.AddObject(name, element);

 WPRichText1.RemoveRTFData;

 WPRichText1.SetRTFData(element);

 WPRichText1.ReformatAll(false, true);

 InitTabSet;

end;

 

Delete current document, clear if it is last

 

procedure TForm1.DelRTFData;

var i          : Integer;

   element    : TWPRTFDataCollection;

   bNeedClear : Boolean;

begin

 bNeedClear := true;

if FRTFDataCollections.Count>1 then

begin

   i := FRTFDataCollections.IndexOfObject( WPRichText1.RTFData );

  if i>=0 then

  begin

     element := WPRichText1.RTFData;

     WPRichText1.RemoveRTFData;

     FRTFDataCollections.Delete(i);

    if i>0 then dec(i);

     element.Free;

     element := TWPRTFDataCollection(FRTFDataCollections.Objects[i]);

     WPRichText1.SetRTFData(element);

     WPRichText1.ReformatAll(false, true);

     InitTabSet;

     bNeedClear := false;

  end;

end;

if bNeedClear then

begin

    WPRichText1.Clear;

    WPRichText1.CheckHasBody;

    WPRichText1.SetFocus;

end;

end;

 

Update the tabset "TabControl1" and display current filenames. Select the current tab.

 

procedure TForm1.InitTabset;

var i : Integer;

begin

 TabControl1.Tabs.Clear;

for i := 0 to FRTFDataCollections.Count-1 do

   TabControl1.Tabs.Add(

      TWPRTFDataCollection(FRTFDataCollections.Objects[i]).LastFileName

      );

 i := FRTFDataCollections.IndexOfObject( WPRichText1.RTFData );

if i>=0 then TabControl1.TabIndex := i

else TabControl1.Tabs.Add('#');

end;

 

Switch between documents - tabset OnChange event.

 

procedure TForm1.TabControl1Change(Sender: TObject);

begin

 WPRichText1.SetRTFData(TWPRTFDataCollection(FRTFDataCollections.Objects[TabControl1.TabIndex]));

end;

 

Update display of filename after SaveAs

 

This code is called by the TWPRichText after a file was saved. It makes it easy to update the GUI with the new filename. Since our method InitTabset is reading the filenames from the DataCollection objects, the handling is very easy.

 

procedure TForm1.WPRichText1ChangeLastFileName(Sender: TObject);

begin

 InitTabset;

end;

 

Intercept a click on tollbar button

 

This code is called by the TWPToolbar in the OnIconSelection event.

 

procedure TForm1.WPToolbar1IconSelection(Sender: TObject;

var Typ: TWpSelNr; const str: String; const group, num, index: Integer);

begin

if (typ=wptIconSel) and (group=WPI_GR_DISK) then

case num of

   WPI_CO_Exit : Close;

   WPI_CO_New  :

  begin

      AddRTFData( '' );

      Typ := wptIconDeSel;

  end;

   WPI_CO_Open :

  begin

      AddRTFData( '' );

      if not WPRichText1.Load then DelRTFData;

      Typ := wptIconDeSel;

  end;

   WPI_CO_Close:

  begin

      if WPRichText1.CanClose then

         DelRTFData;

      Typ := wptIconDeSel;

  end;

end;

end;

 

Clean up the documents

 

procedure TForm1.FormDestroy(Sender: TObject);

var i : Integer;

begin

 WPPreview1.WPRichText := nil;

 WPRichText1.RemoveRTFData;

 WPPreview1.RemoveRTFData;

for i:=0 to FRTFDataCollections.Count-1 do

 FRTFDataCollections.Objects[i].Free;

 FRTFDataCollections.Free;

end;

 

Initialize the document list in Form.OnCreate

 

procedure TForm1.FormCreate(Sender: TObject);

begin

 FRTFDataCollections := TStringList.Create;

 AddRTFData('');

...