summaryrefslogtreecommitdiff
path: root/extras/tiopf/gui/tiListMediators.pas
diff options
context:
space:
mode:
authorgraemeg <graemeg@ae50a9b5-8222-0410-bf8d-8a13f76226bf>2008-08-22 14:52:49 +0000
committergraemeg <graemeg@ae50a9b5-8222-0410-bf8d-8a13f76226bf>2008-08-22 14:52:49 +0000
commit24c78a01ed317848c744be6e9e7dc42ab9335ee4 (patch)
tree9eae0af5db41d0161c057fa08291546e30d18058 /extras/tiopf/gui/tiListMediators.pas
parent8b8e6e91c58d73b8bd543433f789c43d062fd10a (diff)
downloadfpGUI-24c78a01ed317848c744be6e9e7dc42ab9335ee4.tar.xz
* Added Michael new refactored and improved MGM implementation.
* Removed the old units from the tiOPFfpGUI.lpk package and added new units. I did not delete the old mediator units yet.
Diffstat (limited to 'extras/tiopf/gui/tiListMediators.pas')
-rw-r--r--extras/tiopf/gui/tiListMediators.pas551
1 files changed, 551 insertions, 0 deletions
diff --git a/extras/tiopf/gui/tiListMediators.pas b/extras/tiopf/gui/tiListMediators.pas
new file mode 100644
index 00000000..257f72fc
--- /dev/null
+++ b/extras/tiopf/gui/tiListMediators.pas
@@ -0,0 +1,551 @@
+{
+ Abstract mediating views for GUI list controls. This allows you to use
+ standard list components and make them object-aware. See the demo
+ application for usage.
+}
+unit tiListMediators;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+ Classes
+ ,SysUtils
+ ,tiBaseMediator
+ ,Contnrs { TObjectList }
+ ,gui_listview { TfpgListView }
+ ,gui_grid { TfpgStringGrid }
+ ,tiObject
+ ;
+
+
+type
+
+ { Composite mediator for TfpgListView }
+ TListViewMediator = class(TCustomListMediator)
+ private
+ FObserversInTransit: TList;
+ FView: TfpgListView;
+ procedure SetView(const AValue: TfpgListView);
+ protected
+ function GetSelectedObject: TtiObject; override;
+ procedure SetSelectedObject(const AValue: TtiObject);override;
+ procedure CreateColumns; override;
+ procedure DoCreateItemMediator(AData: TtiObject; ARowIdx : Integer); override;
+ Function GetGuiControl : TComponent; override;
+ Procedure SetGuiControl (Const AValue : TComponent); override;
+ procedure SetupGUIandObject; override;
+ procedure RebuildList; override;
+ public
+ constructor CreateCustom(AModel: TtiObjectList; AView: TfpgListView; ADisplayNames: string; AIsObserving: Boolean = True); overload;
+ constructor CreateCustom(AModel: TtiObjectList; AView: TfpgListView; AOnBeforeSetupField: TOnBeforeSetupField; ADisplayNames: string; AIsObserving: Boolean = True); overload;
+ class function ComponentClass: TClass; virtual;
+ Constructor Create; override;
+ Destructor Destroy; override;
+ { Called from the GUI to trigger events }
+ procedure HandleSelectionChanged; virtual;
+ { Event handler to allow formatting of fields before they are written. }
+ published
+ property View: TfpgListView read FView Write SetView;
+ end;
+
+
+ // for backwards compatibility
+ TCompositeListViewMediator = TListViewMediator;
+
+
+ { Composite mediator for TfpgStringGrid }
+ TStringGridMediator = class(TCustomListMediator)
+ private
+ FView: TfpgStringGrid;
+ procedure DoCreateItemMediator(AData: TtiObject; ARowIdx : Integer); override;
+ procedure SetView(const AValue: TfpgStringGrid);
+ protected
+ function GetSelectedObject: TtiObject; override;
+ procedure SetSelectedObject(const AValue: TtiObject);override;
+ procedure CreateColumns; override;
+ Function GetGuiControl : TComponent; override;
+ Procedure SetGuiControl (Const AValue : TComponent); override;
+ procedure SetupGUIandObject; override;
+ procedure RebuildList;override;
+ public
+ constructor CreateCustom(AModel: TtiObjectList; AGrid: TfpgStringGrid; ADisplayNames: string; AIsObserving: Boolean = True);
+ class function ComponentClass: TClass; virtual;
+ published
+ property View: TfpgStringGrid read FView Write SetView;
+ property SelectedObject: TtiObject read GetSelectedObject write SetSelectedObject;
+ end;
+
+
+ // for backwards compatibility
+ TCompositeStringGridMediator = TStringGridMediator;
+
+
+ { Used internally for sub-mediators in ListView mediator. Moved to interface
+ section so it can be overridden. }
+ TListViewListItemMediator = class(TListItemMediator)
+ private
+ FView: TfpgLVItem;
+ procedure SetupFields; virtual;
+ public
+ constructor CreateCustom(AModel: TtiObject; AView: TfpgLVItem; const AFieldsInfo : TtiMediatorFieldInfoList; IsObserving: Boolean = True);
+ constructor CreateCustom(AModel: TtiObject; AView: TfpgLVItem; AOnBeforeSetupField: TOnBeforeSetupField; const AFieldsInfo : TtiMediatorFieldInfoList; IsObserving: Boolean = True); overload;
+ procedure BeforeDestruction; override;
+ procedure Update(ASubject: TtiObject); override;
+ published
+ property View: TfpgLVItem read FView;
+ end;
+
+
+ { Used internally for sub-mediators in StringGrid mediator. Moved to interface
+ section so it can be overridden. }
+ TStringGridRowMediator = class(TListItemMediator)
+ private
+ FView: TfpgStringGrid;
+ FRowIndex: Integer;
+ public
+ constructor CreateCustom(AModel: TtiObject; AGrid: TfpgStringGrid; Const AFieldsInfo : TtiMediatorFieldInfoList; ARowIndex: integer; IsObserving: Boolean = True);
+ procedure Update(ASubject: TtiObject); override;
+ published
+ property View: TfpgStringGrid read FView;
+ Property RowIndex : Integer Read FRowIndex;
+ end;
+
+
+implementation
+
+uses
+ tiUtils
+ ,typinfo
+ ,tiExcept
+ ;
+
+
+{ ---------------------------------------------------------------------
+ ListView
+ --------------------------------------------------------------------- }
+
+{ TListViewMediator }
+
+procedure TListViewMediator.SetView(const AValue: TfpgListView);
+begin
+ FView:=AValue;
+ SetGUIControl(AValue);
+end;
+
+function TListViewMediator.GetGuiControl: TComponent;
+begin
+ Result:=FView;
+end;
+
+procedure TListViewMediator.SetGuiControl(const AValue: TComponent);
+begin
+ FView:=AValue as TfpgListView;
+ inherited SetGuiControl(AValue);
+end;
+
+procedure TListViewMediator.SetSelectedObject(const AValue: TtiObject);
+var
+ i: integer;
+begin
+ for i := 0 to FView.Items.Count-1 do
+ begin
+ if TtiObject(FView.Items.Item[i].UserData) = AValue then
+ begin
+// FView.Selected := FView.Items.Item[i];
+ FView.ItemIndex := i;
+ HandleSelectionChanged;
+ Exit; //==>
+ end;
+ end;
+end;
+
+function TListViewMediator.GetSelectedObject: TtiObject;
+begin
+// if FView.SelCount = 0 then
+ if FView.ItemIndex = -1 then
+ Result := nil
+ else
+// FSelectedObject := TtiObject(FView.Selected.Data);
+ Result := TtiObject(FView.Items.Item[FView.ItemIndex].UserData);
+end;
+
+
+procedure TListViewMediator.DoCreateItemMediator(AData: TtiObject; ARowIdx : Integer);
+var
+ li: TfpgLVItem;
+ m: TListViewListItemMediator;
+begin
+ DataAndPropertyValid(AData);
+
+ { Create ListItem and Mediator }
+ li := TfpgLVItem.Create(FView.Items);
+ li.UserData := AData;
+ FView.Items.Add(li);
+ m := TListViewListItemMediator.CreateCustom(AData, li, OnBeforeSetupField, FieldsInfo, Active);
+ MediatorList.Add(m);
+end;
+
+procedure TListViewMediator.CreateColumns;
+
+var
+ c: integer;
+ lc: TfpgLVColumn;
+ lInfo : TtiMediatorFieldInfo;
+
+begin
+ if View.Columns.Count = 0 then
+ begin
+ { Create column headers }
+ for c := 0 to Pred(FieldsInfo.Count) do
+ begin
+ lInfo := FieldsInfo[c];
+ lc := TfpgLVColumn.Create(View.Columns);
+ lc.AutoSize := False;
+ lc.Caption := lInfo.Caption;
+ lc.Width := lInfo.FieldWidth;
+ lc.Alignment := lInfo.Alignment;
+ View.Columns.Add(lc);
+ end;
+ end;
+end;
+
+procedure TListViewMediator.SetupGUIandObject;
+begin
+ { Setup TfpgListView defaults }
+ FView.Columns.Clear;
+ FView.Items.Clear;
+// FView.ViewStyle := vsReport;
+ FView.ShowHeaders := True;
+// FView.RowSelect := True;
+// FView.AutoSize := False;
+// FView.ScrollBars := ssAutoBoth;
+end;
+
+procedure TListViewMediator.RebuildList;
+begin
+ MediatorList.Clear;
+ ClearList;
+ { This rebuilds the whole list. Not very efficient. You can always override
+ this in your mediators to create a more optimised rebuild. }
+ View.BeginUpdate;
+ try
+ View.Columns.Clear;
+ View.Items.Clear;
+ CreateSubMediators;
+ finally
+ View.EndUpdate;
+ end;
+end;
+
+constructor TListViewMediator.CreateCustom(AModel: TtiObjectList;
+ AView: TfpgListView; AOnBeforeSetupField: TOnBeforeSetupField;
+ ADisplayNames: string; AIsObserving: Boolean);
+begin
+ Create; // don't forget this
+ OnBeforeSetupField := AOnBeforeSetupField;
+ DisplayNames := ADisplayNames; // Will call ParseDisplaynames.
+ Subject := AModel;
+ GUIControl := AView; // Will call SetupGUIandObject;
+ CreateSubMediators;
+ Active := AIsObserving; // Will attach/Detach
+end;
+
+class function TListViewMediator.ComponentClass: TClass;
+begin
+ Result:=TfpgListView;
+end;
+
+constructor TListViewMediator.Create;
+begin
+ inherited Create;
+ FObserversInTransit := TList.Create;
+end;
+
+constructor TListViewMediator.CreateCustom(AModel: TtiObjectList;
+ AView: TfpgListView; ADisplayNames: string; AIsObserving: Boolean);
+begin
+ CreateCustom(AModel,AView,Nil,ADisplayNames,AIsObserving);
+end;
+
+Destructor TListViewMediator.Destroy;
+begin
+ IsObserving:=False;
+ FView := nil;
+ inherited;
+end;
+
+{ TODO: This is not working 100% yet. Be warned! }
+procedure TListViewMediator.HandleSelectionChanged;
+var
+ i: integer;
+begin
+ if View.ItemIndex = -1 then
+ SelectedObject := nil
+ else
+ begin
+ FObserversInTransit.Clear;
+ { If an item is already selected, assign the item's List of observers to a
+ temporary container. This is done so that the same observers can be
+ assigned to the new item. }
+ if Assigned(SelectedObject) then
+ FObserversInTransit.Assign(SelectedObject.ObserverList);
+
+ // Assign Newly selected item to SelectedObject Obj.
+ SelectedObject := TtiObject(View.Items.Item[View.ItemIndex].UserData);
+
+ { If an object was selected, copy the old item's observer List
+ to the new item's observer List. }
+ if FObserversInTransit.Count > 0 then
+ SelectedObject.ObserverList.Assign(FObserversInTransit);
+
+ { Set the Observers Subject property to the selected object }
+ for i := 0 to SelectedObject.ObserverList.Count-1 do
+ begin
+ TMediatorView(SelectedObject.ObserverList.Items[i]).Subject :=
+ SelectedObject;
+ end;
+
+ // execute the NotifyObservers event to update the observers.
+ SelectedObject.NotifyObservers;
+ end;
+end;
+
+
+{ TListViewListItemMediator }
+
+procedure TListViewListItemMediator.SetupFields;
+var
+ c: integer;
+ lMemberName: string;
+ lValue: string;
+begin
+ lMemberName :=FFieldsInfo[0].PropName;
+ lValue:=FModel.PropValue[lMemberName];
+ if Assigned(OnBeforeSetupField) then
+ OnBeforeSetupField(FModel, lMemberName, lValue);
+ FView.Caption := lValue;
+ for c := 1 to FFieldsInfo.Count-1 do
+ begin
+ lMemberName := FFieldsInfo[c].PropName;
+ lValue := FModel.PropValue[lMemberName];
+ if Assigned(OnBeforeSetupField) then
+ OnBeforeSetupField(FModel, lMemberName, lValue);
+ FView.SubItems.Add(lValue);
+ end;
+end;
+
+constructor TListViewListItemMediator.CreateCustom(AModel: TtiObject;
+ AView: TfpgLVItem; const AFieldsInfo: TtiMediatorFieldInfoList;
+ IsObserving: Boolean);
+begin
+ CreateCustom(AModel,AView,Nil,AFieldsInfo,IsObserving);
+end;
+
+constructor TListViewListItemMediator.CreateCustom(AModel: TtiObject;
+ AView: TfpgLVItem; AOnBeforeSetupField: TOnBeforeSetupField;
+ const AFieldsInfo: TtiMediatorFieldInfoList; IsObserving: Boolean);
+begin
+ inherited Create;
+ FModel := AModel;
+ FView := AView;
+ FFieldsInfo := AFieldsInfo;
+ OnBeforeSetupField := AOnBeforeSetupField;
+ SetupFields;
+ Active:=IsObserving; // Will attach
+end;
+
+procedure TListViewListItemMediator.BeforeDestruction;
+begin
+ FModel.DetachObserver(self);
+ FModel := nil;
+ FView := nil;
+ inherited BeforeDestruction;
+end;
+
+procedure TListViewListItemMediator.Update(ASubject: TtiObject);
+var
+ c: integer;
+ lMemberName: string;
+ lValue: string;
+begin
+ Assert(FModel = ASubject);
+
+ lMemberName := FFieldsInfo[0].PropName;
+ lValue := FModel.PropValue[lMemberName];
+ if Assigned(OnBeforeSetupField) then
+ OnBeforeSetupField(FModel, lMemberName, lValue);
+
+ FView.Caption := lValue;
+
+ for c := 1 to FFieldsInfo.Count-1 do
+ begin
+ lMemberName := FFieldsInfo[c].PropName;
+ lValue := FModel.PropValue[lMemberName];
+ if Assigned(OnBeforeSetupField) then
+ OnBeforeSetupField(FModel, lMemberName, lValue);
+ FView.SubItems[c-1] := lValue;
+ end;
+end;
+
+{ ---------------------------------------------------------------------
+ StringGrid
+ --------------------------------------------------------------------- }
+
+{ TStringGridMediator }
+
+function TStringGridMediator.GetSelectedObject: TtiObject;
+begin
+ if FView.FocusRow = -1 then
+// if FView.Selection.Top = 0 then
+ Result := nil
+ else
+// Result := TtiObject(FView.Objects[1, FView.Selection.Top]);
+ Result := TtiObject(FView.Objects[0, FView.FocusRow]);
+end;
+
+procedure TStringGridMediator.SetSelectedObject(const AValue: TtiObject);
+var
+ i: integer;
+begin
+ for i := 0 to FView.RowCount-1 do
+ begin
+ if TtiObject(FView.Objects[0, i]) = AValue then
+ begin
+ FView.FocusRow := i;
+ Exit; //==>
+ end;
+ end;
+end;
+
+procedure TStringGridMediator.SetView(const AValue: TfpgStringGrid);
+begin
+ SetGUIControl(AValue);
+end;
+
+function TStringGridMediator.GetGuiControl: TComponent;
+begin
+ Result:=fView;
+end;
+
+procedure TStringGridMediator.SetGuiControl(const AValue: TComponent);
+begin
+ FView:=AValue as TfpgStringGrid;
+end;
+
+procedure TStringGridMediator.DoCreateItemMediator(AData: TtiObject; ARowIdx: Integer);
+var
+ i: Integer;
+ lFieldName: string;
+ lMediatorView: TStringGridRowMediator;
+begin
+ FView.Objects[0, ARowIdx] := AData; // set Object reference inside grid
+ for i := 0 to FieldsInfo.Count-1 do
+ begin
+ lFieldName:=FieldsInfo[i].PropName;
+ FView.Cells[i, ARowIdx]:=AData.PropValue[lFieldName]; // set Cell text
+ end;
+ lMediatorView := TStringGridRowMediator.CreateCustom(AData, FView, FieldsInfo, ARowIdx, Active);
+ MediatorList.Add(lMediatorView);
+end;
+
+procedure TStringGridMediator.CreateColumns;
+var
+ i: integer;
+ lColumnTotalWidth: integer;
+begin
+ lColumnTotalWidth := 0;
+ for i := 0 to FieldsInfo.Count-1 do
+ begin
+ FView.ColumnWidth[i] := FieldsInfo[i].FieldWidth;
+ FView.ColumnTitle[i] := FieldsInfo[i].Caption;
+ FView.Columns[i].Alignment:=FieldsInfo[i].Alignment;
+ //resize the last column to fill the grid.
+ if i = FieldsInfo.Count-1 then
+ begin
+ If FView.Width > (lColumnTotalWidth + 10) then
+ FView.ColumnWidth[i] := FView.Width - (lColumnTotalWidth + 10)
+ end
+ else
+ lColumnTotalWidth := lColumnTotalWidth + FView.ColumnWidth[i] + 20;
+ end;
+end;
+
+procedure TStringGridMediator.SetupGUIandObject;
+begin
+ //Setup default properties for the StringGrid
+ FView.RowSelect := True;
+ FView.ColumnCount := FieldsInfo.Count;
+ if ShowDeleted then
+ FView.RowCount := Model.Count
+ else
+ FView.RowCount := Model.CountNotDeleted;
+end;
+
+procedure TStringGridMediator.RebuildList;
+begin
+ { This rebuilds the whole list. Not very efficient. }
+ View.BeginUpdate;
+ try
+ SetupGUIandObject;
+ MediatorList.Clear;
+// for i := View.ColumnCount-1 downto 0 do
+// View.DeleteColumn(i);
+ CreateSubMediators;
+ finally
+ View.EndUpdate;
+ end;
+end;
+
+constructor TStringGridMediator.CreateCustom(AModel: TtiObjectList;
+ AGrid: TfpgStringGrid; ADisplayNames: string; AIsObserving: Boolean);
+begin
+ inherited Create;
+ DisplayNames := ADisplayNames;
+ Subject := AModel;
+ GUIControl := AGrid;
+ CreateSubMediators;
+ IsObserving := AIsObserving;
+end;
+
+class function TStringGridMediator.ComponentClass: TClass;
+begin
+ Result:=TfpgStringGrid
+end;
+
+
+{ TStringGridRowMediator }
+
+constructor TStringGridRowMediator.CreateCustom(AModel: TtiObject;
+ AGrid: TfpgStringGrid; Const AFieldsInfo : TtiMediatorFieldInfoList; ARowIndex: integer;
+ IsObserving: Boolean);
+begin
+ inherited Create;
+ FModel := AModel;
+ FView := AGrid;
+ FFieldsInfo := AFieldsInfo;
+ FRowIndex := ARowIndex;
+ Active :=IsObserving; // Will attach
+end;
+
+procedure TStringGridRowMediator.Update(ASubject: TtiObject);
+var
+ i: Integer;
+ lvalue,
+ lFieldName: string;
+begin
+ Assert(FModel = ASubject);
+ for i := 0 to FFieldsInfo.Count-1 do
+ begin
+ lFieldName := FFieldsInfo[I].PropName;
+ lValue := FModel.PropValue[lFieldName];
+ if Assigned(OnBeforeSetupField) then
+ OnBeforeSetupField(FModel, lFieldName, lValue);
+ FView.Cells[i, FRowIndex] := lValue;
+ end;
+end;
+
+
+end.
+