diff options
Diffstat (limited to 'extras')
-rw-r--r-- | extras/tiopf/mvp/basic_impl.pas | 260 | ||||
-rw-r--r-- | extras/tiopf/mvp/basic_intf.pas | 5 | ||||
-rw-r--r-- | extras/tiopf/mvp/view_impl.pas | 12 |
3 files changed, 267 insertions, 10 deletions
diff --git a/extras/tiopf/mvp/basic_impl.pas b/extras/tiopf/mvp/basic_impl.pas index 791f16e0..8ce4b80b 100644 --- a/extras/tiopf/mvp/basic_impl.pas +++ b/extras/tiopf/mvp/basic_impl.pas @@ -55,15 +55,19 @@ type TCommand = class(TInterfacedObject, ICommand, IVisited) private + fEnabled: Boolean; fSelection: ISelection; procedure BindSelection(const Selection: ISelection); + function GetEnabled: Boolean; protected + property Selection: ISelection read fSelection; // IVisited procedure Accept(const Visitor: IVisitor); virtual; // ICommand function Execute: Boolean; virtual; abstract; - function GetEnabled: Boolean; virtual; abstract; function GetText: string; virtual; abstract; + public + constructor Create(Enabled: Boolean); virtual; end; @@ -78,7 +82,7 @@ type property Count: integer read GetCount; property Items: IInterfaceList read fItems; // IObserver - procedure Update(Subject: IInterface); + procedure Update(const ASubject: IInterface); virtual; // ISubject property Subject: ISubject read fSubject implements ISubject; public @@ -144,10 +148,69 @@ type end; + TStringModelCommandSet = class(TCommandSet) + protected + // IObserver + procedure Update(const ASubject: IInterface); override; + public + destructor Destroy; override; + end; + + + TStringVisitor = class(TInterfacedObject, IStringVisitor) + private + fTheString: IString; + protected + // IStringVisitor + function GetTheString: IString; virtual; + procedure VisitString(const Str: IString); virtual; + end; + + + TStringMoveVisitor = class(TStringVisitor, IStringMoveVisitor) + private + fCanDemote: Boolean; + fCanPromote: Boolean; + fModel: IStringListModel; + function GetCanDemote: Boolean; + function GetCanPromote: Boolean; + protected + procedure VisitString(const Str: IString); override; + public + constructor Create(const Model: IStringListModel); virtual; + end; + + + TPromoteStringCommand = class(TCommand) + private + fModel: Pointer; + function GetModel: IStringListModel; + protected + function Execute: Boolean; override; + function GetText: string; override; + public + constructor Create(Enabled: Boolean; const Model: IStringListModel); reintroduce; virtual; + end; + + + TDemoteStringCommand = class(TCommand) + private + fModel: Pointer; + function GetModel: IStringListModel; + protected + function Execute: Boolean; override; + function GetText: string; override; + public + constructor Create(Enabled: Boolean; const Model: IStringListModel); reintroduce; virtual; + end; + implementation +uses + Math; + { TSubject } function TSubject.GetController: IInterface; @@ -397,11 +460,22 @@ begin fSelection := Selection; end; +function TCommand.GetEnabled: Boolean; +begin + Result := fEnabled; +end; + procedure TCommand.Accept(const Visitor: IVisitor); begin (Visitor as ICommandVisitor).VisitComand(self); end; +constructor TCommand.Create(Enabled: Boolean); +begin + inherited Create; + fEnabled := Enabled; +end; + { TCommandSet } function TCommandSet.GetCount: integer; @@ -420,7 +494,7 @@ begin (fItems[i] as IVisited).Accept(Visitor); end; -procedure TCommandSet.Update(Subject: IInterface); +procedure TCommandSet.Update(const ASubject: IInterface); begin // do nothing yet end; @@ -462,5 +536,185 @@ begin inherited Destroy; end; +{ TStringModelCommandSet } + +procedure TStringModelCommandSet.Update(const ASubject: IInterface); +var + ObjSelection: ISelection; + ObjVisited: IVisited; + ObjModel: IStringListModel; + Visitor: IStringMoveVisitor; + Command: ICommand; +begin + ASubject.QueryInterface(ISelection, ObjSelection); + if ObjSelection <> nil then + begin + Items.Clear; + // We are only interested in a single selection. We don't have a + // mechanism for multi-select yet. + if ObjSelection.Count = 1 then + begin + ObjSelection.QueryInterface(IVisited, ObjVisited); + if ObjVisited <> nil then + begin + ObjVisited.QueryInterface(IStringListModel, ObjModel); + if ObjModel <> nil then + begin + Visitor := TStringMoveVisitor.Create(ObjModel); + ObjVisited.Accept(Visitor); + // This will only give commands that are applicable. So in a Menu the + // available items will keep changing. +{ + if Visitor.CanPromote then + begin + Command := TPromoteStringCommand.Create(True, ObjModel); + Command.BindSelection(ObjSelection); + Items.Add(Command); + end; + if Visitor.CanDemote then + begin + Command := TDemoteStringCommand.Create(True, ObjModel); + Command.BindSelection(ObjSelection); + Items.Add(Command); + end; +} + + // In this case it will return all commands, but only the applicable + // ones will be Enabled. I like this idea more. + Command := TPromoteStringCommand.Create(Visitor.CanPromote, ObjModel); + Command.BindSelection(ObjSelection); + Items.Add(Command); + + Command := TDemoteStringCommand.Create(Visitor.CanDemote, ObjModel); + Command.BindSelection(ObjSelection); + Items.Add(Command); + end; + end; + end; + Subject.Notify; + end; +end; + +destructor TStringModelCommandSet.Destroy; +begin + inherited Destroy; +end; + +{ TStringVisitor } + +function TStringVisitor.GetTheString: IString; +begin + Result := fTheString; +end; + +procedure TStringVisitor.VisitString(const Str: IString); +begin + fTheString := Str; +end; + +{ TStringMoveVisitor } + +function TStringMoveVisitor.GetCanDemote: Boolean; +begin + Result := fCanDemote; +end; + +function TStringMoveVisitor.GetCanPromote: Boolean; +begin + Result := fCanPromote; +end; + +procedure TStringMoveVisitor.VisitString(const Str: IString); +begin + inherited VisitString(Str); + fCanPromote := fModel.IndexOf(Str) > 0; + fCanDemote := fModel.IndexOf(Str) < (fModel.Count - 1) +end; + +constructor TStringMoveVisitor.Create(const Model: IStringListModel); +begin + inherited Create; + fModel := Model; +end; + + +{ TPromoteStringCommand } + +function TPromoteStringCommand.GetModel: IStringListModel; +begin + Result := IStringListModel(fModel); +end; + +function TPromoteStringCommand.Execute: Boolean; +var + Visitor: IStringVisitor; + BeforeIdx: Integer; +begin + Visitor := TStringVisitor.Create; + try + (Selection as IVisited).Accept(Visitor); + BeforeIdx := Max(GetModel.IndexOf(Visitor.TheString) - 1, 0); + GetModel.Move(Visitor.TheString, GetModel.Item[BeforeIdx]); + Result := True; + except + Result := False; + end; +end; + +function TPromoteStringCommand.GetText: string; +begin + Result := 'Promote String'; +end; + +constructor TPromoteStringCommand.Create(Enabled: Boolean; + const Model: IStringListModel); +begin + inherited Create(Enabled); + fModel := Pointer(Model); +end; + +{ TDemoteStringCommand } + +function TDemoteStringCommand.GetModel: IStringListModel; +begin + Result := IStringListModel(fModel); +end; + +function TDemoteStringCommand.Execute: Boolean; +var + Visitor: IStringVisitor; + BeforeIdx: Integer; +begin + Visitor := TStringVisitor.Create; + try + (Selection as IVisited).Accept(Visitor); + BeforeIdx := GetModel.IndexOf(Visitor.TheString) + 2; + if BeforeIdx > GetModel.Count - 1 then + begin + (GetModel as ISubject).BeginUpdate; + GetModel.Remove(Visitor.TheString); + GetModel.Add(Visitor.TheString); + (GetModel as ISubject).EndUpdate; + end + else + GetModel.Move(Visitor.TheString, GetModel.Item[BeforeIdx]); + Result := True; + except + Result := False; + end; +end; + +function TDemoteStringCommand.GetText: string; +begin + Result := 'Demote String'; +end; + +constructor TDemoteStringCommand.Create(Enabled: Boolean; + const Model: IStringListModel); +begin + inherited Create(Enabled); + fModel := Pointer(Model); +end; + end. diff --git a/extras/tiopf/mvp/basic_intf.pas b/extras/tiopf/mvp/basic_intf.pas index 1d1aad80..36f56f32 100644 --- a/extras/tiopf/mvp/basic_intf.pas +++ b/extras/tiopf/mvp/basic_intf.pas @@ -18,7 +18,7 @@ type IObserver = interface(IInterface) ['{16CD208B-5F37-41FC-82A4-BFDD16DB3203}'] - procedure Update(Subject: IInterface); + procedure Update(const ASubject: IInterface); end; @@ -139,7 +139,10 @@ type IStringVisitor = interface(IVisitor) ['{DA12355F-0727-41B3-9080-DDAF20797FC5}'] + function GetTheString: IString; procedure VisitString(const Str: IString); + property TheString: IString + read GetTheString; end; diff --git a/extras/tiopf/mvp/view_impl.pas b/extras/tiopf/mvp/view_impl.pas index 272da1dc..478ca9f9 100644 --- a/extras/tiopf/mvp/view_impl.pas +++ b/extras/tiopf/mvp/view_impl.pas @@ -12,14 +12,14 @@ type TListBoxView = class(TfpgListBox, IObserver) private procedure IObserver.Update = ObserverUpdate; - procedure ObserverUpdate(Subject: IInterface); + procedure ObserverUpdate(const ASubject: IInterface); end; TComboBoxView = class(TfpgComboBox, IObserver) private procedure IObserver.Update = ObserverUpdate; - procedure ObserverUpdate(Subject: IInterface); + procedure ObserverUpdate(const ASubject: IInterface); end; @@ -27,12 +27,12 @@ implementation { TListBoxView } -procedure TListBoxView.ObserverUpdate(Subject: IInterface); +procedure TListBoxView.ObserverUpdate(const ASubject: IInterface); var Obj: IListModel; i: integer; begin - Subject.QueryInterface(IListModel, Obj); + ASubject.QueryInterface(IListModel, Obj); if Obj <> nil then begin Items.BeginUpdate; @@ -45,12 +45,12 @@ end; { TComboBoxView } -procedure TComboBoxView.ObserverUpdate(Subject: IInterface); +procedure TComboBoxView.ObserverUpdate(const ASubject: IInterface); var Obj: IListModel; i: integer; begin - Subject.QueryInterface(IListModel, Obj); + ASubject.QueryInterface(IListModel, Obj); if Obj <> nil then begin Items.BeginUpdate; |