fpobserver.pp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466
  1. unit fpobserver;
  2. {$mode objfpc}{$H+}
  3. {$interfaces corba}
  4. interface
  5. uses
  6. Classes, SysUtils, typinfo, contnrs;
  7. Type
  8. TObservedHook = Class(TObject,IFPObserved)
  9. Protected
  10. FObservers : TFPList;
  11. FSender : TObject;
  12. Public
  13. // ASender will be the default sender.
  14. Constructor CreateSender(ASender : TObject);
  15. Destructor Destroy; override;
  16. Procedure FPOAttachObserver(AObserver : TObject);
  17. Procedure FPODetachObserver(AObserver : TObject);
  18. Procedure Changed;
  19. Procedure AddItem(AItem : TObject);
  20. Procedure DeleteItem(AItem : TObject);
  21. Procedure CustomNotify(Data : Pointer = Nil);
  22. Procedure FPONotifyObservers(ASender : TObject; AOperation : TFPObservedOperation; Data : Pointer);
  23. Property Sender : TObject Read FSender;
  24. end;
  25. // EObserver = Class(Exception);
  26. { TBaseMediator }
  27. TMediatingEvent = Procedure(Sender : TObject; var Handled : Boolean) of object;
  28. TBaseMediator = Class(TComponent,IFPObserver)
  29. private
  30. FActive: Boolean;
  31. FOnObjectToView: TMediatingEvent;
  32. FOnViewToObject: TMediatingEvent;
  33. FReadOnly: Boolean;
  34. FTransferring : Boolean;
  35. FSubjectPropertyName: String;
  36. FSubject: TObject;
  37. FValueList: TObjectList;
  38. FViewPropertyName: String;
  39. procedure SetReadOnly(const AValue: Boolean);
  40. procedure SetValueList(const AValue: TObjectList);
  41. procedure SetViewPropertyName(const AValue: String); Virtual;
  42. Protected
  43. // Should return true (Default) if ViewPropertyName is published
  44. Class Function PublishedViewProperty : Boolean; virtual;
  45. // Should return true (Default) if SubjectPropertyName is published
  46. Class Function PublishedSubjectProperty : Boolean; virtual;
  47. // Set active. Descendents (such as list mediators) can override this.
  48. procedure SetActive(const AValue: Boolean); virtual;
  49. // set subject. Attaches observer and calls MaybeObjectToView
  50. procedure SetSubject(const AValue: TObject); virtual;
  51. // set subjectpropertyname. Checks if it exists, and calls MaybeObjectToView
  52. procedure SetSubjectPropertyName(const AValue: String); virtual;
  53. // Can be used in descendents to respond to onchange events
  54. Procedure ViewChangedHandler(Sender : TObject); virtual;
  55. // Check if APropertyName is published property of AObject.
  56. // Only performed if both parameters are not empty.
  57. procedure CheckPropertyName(AObject: TObject; const APropertyName: String);
  58. // If all CheckObjectSubject and Active are true, call ObjectToView.
  59. Procedure MaybeObjectToView;
  60. // If all CheckObjectSubject and Active are true, call ViewToObject.
  61. Procedure MaybeViewToObject;
  62. // Check if Subject/View and property names are set up correctly.
  63. Function CheckViewSubject : Boolean;
  64. // Override next two for custom behaviour.
  65. // Copies Subject.SubjectPropertyName to View.ViewPropertyName.
  66. Procedure DoObjectToView; virtual;
  67. // Copies View.ViewPropertyName to Subject.SubjectPropertyName
  68. Procedure DoViewToObject; virtual;
  69. // Override these, and call inherited at the end.
  70. // Get View component. Typically a TCustomEdit instance.
  71. function GetView : TObject; virtual;
  72. // Descendents should call this when the view changed.
  73. procedure ViewChanged; virtual;
  74. // Descendents should override this to handle changes in the value list
  75. procedure ValuelistChanged; virtual;
  76. // IFPObserver. Will call the necessary events.
  77. Procedure FPOObservedChanged(ASender : TObject; Operation : TFPObservedOperation; Data : Pointer);
  78. // Raise an error which shows more information about the control, subject and fieldname.
  79. Procedure RaiseMediatorError(Const Msg : String); overload;
  80. // Format version
  81. Procedure RaiseMediatorError(Const Fmt : String; Args : Array of const); overload;
  82. // View property that will be set by default
  83. Property ViewPropertyName : String Read FViewPropertyName Write SetViewPropertyName;
  84. // Is a copy operation View <-> Subject in progress ?
  85. Property Transferring : Boolean Read FTransferring;
  86. Public
  87. Destructor Destroy; override;
  88. // Copy subject to view. No check is done to see if all is well.
  89. Procedure ObjectToView;
  90. // Copy view to subject. No check is done to see if all is well.
  91. Procedure ViewToObject;
  92. // Minimum class that View must have to be handled by this mediator.
  93. class function ViewClass: TClass; virtual;
  94. // Composite mediator or not ?
  95. class function CompositeMediator : Boolean; virtual;
  96. // Subject. Must have IFPObserved interface
  97. Property Subject : TObject Read FSubject Write SetSubject;
  98. // View. Must have ViewPropertyName, if in use.
  99. Property View : TObject Read GetView;
  100. // Value list. To be used in mediators that use a dynamical value list
  101. // such as Listbox, combobox, groupbox.
  102. Property Valuelist : TObjectList Read FValueList Write SetValueList;
  103. Published
  104. // Property that will be copied to view.
  105. Property SubjectPropertyName : String Read FSubjectPropertyName Write SetSubjectPropertyName;
  106. // If not active, no copying is being done either way.
  107. Property Active : Boolean Read FActive Write SetActive;
  108. // If ReadOnly, only ObjectToView is used
  109. Property ReadOnly : Boolean Read FReadOnly Write SetReadOnly;
  110. // Can be used to copy data from control (view) to subject manually
  111. Property OnViewToObject : TMediatingEvent Read FOnViewToObject Write FOnViewToObject;
  112. // Can be used to copy data from control (view) to subject manually
  113. Property OnObjectToView : TMediatingEvent Read FOnObjectToView Write FOnObjectToView;
  114. end;
  115. TMediatorClass = Class of TBaseMediator;
  116. // Forward definitions
  117. TBaseListMediator = Class;
  118. { TComponentMediator }
  119. { General-purpose of Mediating views. Can be used on any form/component }
  120. TComponentMediator = Class(TBaseMediator)
  121. FViewComponent : TComponent;
  122. Protected
  123. function GetView : TObject; override;
  124. procedure SetComponent(const AValue: TComponent);
  125. Public
  126. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  127. Published
  128. // General component which can be set in Object Inspector
  129. Property ViewComponent : TComponent Read FViewComponent Write SetComponent;
  130. // Punlish property so it can be set in Object Inspector
  131. Property ViewPropertyName;
  132. end;
  133. { Event object used for OnBeforeSetupField event. Is used to allow formatting
  134. of fields before written to listview Caption or Items. }
  135. TOnBeforeSetupField = procedure(AObject: TObject; const AFieldName: string; var AValue: string) of object;
  136. { TListItemMediator }
  137. TListItemMediator = class(TObject, IFPObserver)
  138. private
  139. FSubject: TObject;
  140. FOnBeforeSetupField: TOnBeforeSetupField;
  141. FListMediator : TBaseListMediator;
  142. Function GetActive : Boolean;
  143. protected
  144. procedure SetSubject(const AValue: TObject); virtual;
  145. Procedure FPOObservedChanged(ASender : TObject; Operation : TFPObservedOperation; Data : Pointer); virtual;
  146. Procedure ObjectToView; virtual;
  147. Procedure ViewToObject; virtual;
  148. public
  149. destructor Destroy; override;
  150. procedure MaybeObjectToView;
  151. property OnBeforeSetupField: TOnBeforeSetupField read FOnBeforeSetupField write FOnBeforeSetupField;
  152. property Subject : TObject read FSubject write SetSubject;
  153. property Active : Boolean read GetActive;
  154. end;
  155. { TBaseListMediator - Base mediator that handles lists of objects.
  156. Needs a TList as subject. Items in list must have IFPObserved
  157. interface. It will create one (and use as subject) if passed a normal
  158. list or a collection.
  159. }
  160. TBaseListMediator = class(TBaseMediator)
  161. private
  162. FOnBeforeSetupField: TOnBeforeSetupField;
  163. FMediatorList: TFPObjectList;
  164. FListChanged : Boolean;
  165. procedure SetOnBeforeSetupField(const Value: TOnBeforeSetupField);
  166. protected
  167. // This needs to return false
  168. Class Function PublishedViewProperty : Boolean; override;
  169. // Descendents can override;
  170. Function AddObject(AObject: TObject; AIndex: Integer) : TListItemMediator; virtual;
  171. // Set all descendents to active
  172. procedure SetActive(const AValue: Boolean); override;
  173. // Must be overridden in descendents, and should return selected object
  174. function GetSelectedObject: TObject; virtual;
  175. // Must be overridden in descendents, and should set selected object
  176. procedure SetSelectedObject(const AValue: TObject); virtual;
  177. // Must be overridden in descendents to create an item mediator and add it to GUI control
  178. // Subject will be set after this call.
  179. Function CreateItemMediator(AData: TObject; ARow : integer) : TListItemMediator; virtual; abstract;
  180. // This frees the mediator. Descendents can override to additionally update the GUI control
  181. procedure DoDeleteItemMediator(AIndex : Integer; AMediator : TListItemMediator); virtual;
  182. // Creates a mediator for all items in the list. List Item Mediators are re-used (subject is set)
  183. procedure CreateSubMediators; virtual;
  184. // Does nothing
  185. procedure DoViewToObject; override;
  186. // Calls CreateSubMediators. Override for additional GUI setup.
  187. procedure DoObjectToView; override;
  188. // Additional checks on subject.
  189. procedure SetSubject(const AValue: TObject); override;
  190. Function FindObjectMediator(AObject : TObject; out AtIndex : Integer) : TListItemMediator;
  191. property MediatorList: TFPObjectList read FMediatorList;
  192. public
  193. constructor Create(AOwner : TComponent); override;
  194. destructor Destroy; override;
  195. class function CompositeMediator: Boolean; override;
  196. // This should handle additional additem/deleteitem events
  197. Procedure ObservedChanged(ASender : TObject; Operation : TFPObservedOperation);
  198. // Selected item in the list.
  199. property SelectedObject: TObject read GetSelectedObject write SetSelectedObject;
  200. published
  201. // Event to setup fields in item mediators.
  202. property OnBeforeSetupField: TOnBeforeSetupField read FOnBeforeSetupField write SetOnBeforeSetupField;
  203. end;
  204. { TMediatorFieldInfo - Describe a column in a columnar list display }
  205. TMediatorFieldInfo = class(TCollectionItem)
  206. private
  207. FWidth: integer;
  208. FCaption: string;
  209. FPropName: string;
  210. FAlign: TAlignment;
  211. function GetCaption: string;
  212. procedure SetAlign(const AValue: TAlignment);
  213. procedure SetCaption(const AValue: string);
  214. procedure SetPropName(const AValue: string);
  215. procedure SetWidth(const AValue: Integer);
  216. protected
  217. function GetAsString: string; virtual;
  218. procedure SetAsString(const AValue: string); virtual;
  219. Procedure Change;
  220. public
  221. procedure Assign(Source: TPersistent); override;
  222. // Setting this will parse everything.
  223. property AsString: string read GetAsString write SetAsString;
  224. published
  225. // Property Caption to be used for column head.
  226. property Caption: string read GetCaption write SetCaption;
  227. // Property Name to be displayed in column
  228. property PropertyName: string read FPropName write SetPropName;
  229. // Width of column
  230. property Width: Integer read FWidth write SetWidth;
  231. // Alignment of column
  232. property Alignment: TAlignment read FAlign write SetAlign default taLeftJustify;
  233. end;
  234. TColumnsListMediator = Class;
  235. { TMediatorFieldInfoList - Collection describing the columns in a columnar list display }
  236. TMediatorFieldInfoList = class(TCollection)
  237. private
  238. FMediator : TColumnsListMediator;
  239. function GetAsString: string;
  240. function GetI(Index: integer): TMediatorFieldInfo;
  241. procedure SetI(Index: integer; const AValue: TMediatorFieldInfo);
  242. protected
  243. procedure Notify(Item: TCollectionItem;Action: TCollectionNotification); override;
  244. Property Mediator : TColumnsListMediator read FMediator;
  245. public
  246. // Adding items to the collection.
  247. function AddFieldInfo: TMediatorFieldInfo; overload;
  248. function AddFieldInfo (Const APropName : String; AFieldWidth : Integer) : TMediatorFieldInfo; overload;
  249. function AddFieldInfo (Const APropName,ACaption : String; AFieldWidth : Integer) : TMediatorFieldInfo; overload;
  250. function AddFieldInfo (Const APropName,ACaption : String; AFieldWidth : Integer; AAlignment : TAlignment) : TMediatorFieldInfo; overload;
  251. property FieldInfo[Index: integer]: TMediatorFieldInfo read GetI write SetI; default;
  252. property AsString: string read GetAsString;
  253. end;
  254. { TColumnsListItemMediator - List item mediator that can handle multiple columns }
  255. TColumnsListItemMediator = class(TListItemMediator)
  256. Private
  257. Function GetFieldsInfo: TMediatorFieldInfoList;
  258. Published
  259. property FieldsInfo: TMediatorFieldInfoList read GetFieldsInfo;
  260. end;
  261. { TColumnsListMediator - List mediator that handles multiple columns }
  262. TColumnsListMediator = class(TBaseListMediator)
  263. Private
  264. FFieldsInfo: TMediatorFieldInfoList;
  265. procedure SetFieldsInfo(const AValue: TMediatorFieldInfoList);
  266. function GetDisplayNames: string;
  267. procedure SetDisplayNames(const AValue: string);
  268. procedure FieldInfoChanged(Item: TMediatorFieldInfo; Action: TCollectionNotification); virtual;
  269. Protected
  270. Class Function PublishedSubjectProperty : Boolean; override;
  271. procedure ParseDisplayNames(const AValue: string);
  272. // Called by DoViewToObject prior to creating item mediators
  273. procedure CreateColumns; virtual;
  274. // Calls CreateColumns and CreateSubMediators. Override for additional GUI setup.
  275. procedure DoObjectToView; override;
  276. Public
  277. Constructor Create(AOwner: TComponent); override;
  278. Destructor Destroy; override;
  279. // Can be used to set the column properties in 1 statement.
  280. property DisplayNames: string read GetDisplayNames write SetDisplayNames;
  281. Published
  282. // How to display the columns in the list.
  283. property FieldsInfo: TMediatorFieldInfoList read FFieldsInfo write SetFieldsInfo;
  284. end;
  285. { TMediatorDef - Mediator Definition Storage for MediatorManager }
  286. TMediatorDef = class(TCollectionItem)
  287. private
  288. FMC: TMediatorClass;
  289. FMSC: TClass;
  290. FPN: string;
  291. FPT: TTypeKinds;
  292. public
  293. // Return True if this definition handles the Subject,Gui,APropinfo trio
  294. function Handles(ASubject: TObject; AGui: TComponent; APropInfo: PPropInfo): Boolean;
  295. // Return True if this definition matches 'closer' than M.
  296. // Note that both current and M must have Handles() returned true for this to be useful.
  297. function BetterMatch(M: TMediatorDef): Boolean;
  298. // Definition
  299. property MediatorClass: TMediatorClass read FMC write FMC;
  300. property MinSubjectClass: TClass read FMSC write FMSC;
  301. property PropertyTypes: TTypeKinds read FPT write FPT;
  302. property PropertyName: string read FPN write FPN;
  303. end;
  304. TMediatorDefs = class(TCollection)
  305. private
  306. function GetDef(Index: integer): TMediatorDef;
  307. procedure SetDef(Index: integer; const AValue: TMediatorDef);
  308. public
  309. function AddDef: TMediatorDef;
  310. property Defs[Index: integer]: TMediatorDef read GetDef write SetDef; default;
  311. end;
  312. TMediatorManager = class(TObject)
  313. private
  314. FDefs: TMediatorDefs;
  315. public
  316. constructor Create;
  317. destructor Destroy; override;
  318. // If APropName is empty or APropInfo is Nil, a composite mediator will be searched.
  319. function FindDefFor(ASubject: TObject; AGui: TComponent): TMediatorDef; overload;
  320. function FindDefFor(ASubject: TObject; AGui: TComponent; const APropName: string): TMediatorDef; overload;
  321. function FindDefFor(ASubject: TObject; AGui: TComponent; APropInfo: PPropInfo): TMediatorDef; overload;
  322. function RegisterMediator(MediatorClass: TMediatorClass; MinSubjectClass: TClass): TMediatorDef; overload;
  323. function RegisterMediator(MediatorClass: TMediatorClass; MinSubjectClass: TClass; PropertyName: string): TMediatorDef; overload;
  324. function RegisterMediator(MediatorClass: TMediatorClass; MinSubjectClass: TClass; PropertyTypes: TTypeKinds): TMediatorDef; overload;
  325. property Defs: TMediatorDefs read FDefs;
  326. end;
  327. EMediator = class(Exception);
  328. function MediatorManager: TMediatorManager;
  329. Procedure MediatorError(Sender : TObject; Const Msg : String); overload;
  330. Procedure MediatorError(Sender : TObject; Const Fmt : String; Args : Array of const); overload;
  331. implementation
  332. Resourcestring
  333. SErrNotObserver = 'Instance of class %s is not an observer.';
  334. SErrInvalidPropertyName = '%s is not a valid published property of class %s';
  335. SErrObjectCannotBeObserved = 'Cannot observe an instance of class %d';
  336. sErrInvalidFieldName = 'No fieldname specified for column %d';
  337. sErrInvalidAlignmentChar = 'Invalid alignment character "%s" specified for column %d';
  338. sErrInvalidWidthSpecifier = 'Invalid with "%s" specified for column %d';
  339. sErrNotListObject = '%s is not a TObjectList';
  340. sErrCompositeNeedsList = '%s needs a TObjectList class but is registered with %s';
  341. SErrActive = 'Operation not allowed while the mediator is active';
  342. SErrNoGuiFieldName = 'no gui fieldname set';
  343. SErrNoSubjectFieldName = 'no subject fieldname set';
  344. { ---------------------------------------------------------------------
  345. Mediator global routines
  346. ---------------------------------------------------------------------}
  347. Procedure MediatorError(Sender : TObject; Const Msg : String); overload;
  348. Var
  349. M : TBaseMediator;
  350. C : TComponent;
  351. V,S : TObject;
  352. CN,SN,Err : String;
  353. begin
  354. if (Sender=Nil) then
  355. Err:=Msg
  356. else If Sender is TBaseMediator then
  357. begin
  358. M:=TBaseMediator(Sender);
  359. V:=M.View;
  360. S:=M.Subject;
  361. CN:='';
  362. If Assigned(V) then
  363. begin
  364. if (V is TComponent) then
  365. begin
  366. C:=TComponent(V);
  367. CN:=C.Name;
  368. end;
  369. If (CN='') then
  370. CN:=C.ClassName+' instance';
  371. end
  372. else
  373. CN:='Nil';
  374. If Assigned(S) then
  375. SN:=S.ClassName
  376. else
  377. SN:='Nil';
  378. Err:=Format('Mediator %s (%s,%s,%s) : %s',[M.ClassName,SN,CN,M.SubjectPropertyName,Msg]);
  379. end
  380. else if (Sender is TComponent) and (TComponent(Sender).Name<>'') then
  381. Err:=Format('%s : %s',[TComponent(Sender).Name,Msg])
  382. else
  383. Err:=Format('%s : %s',[Sender.ClassName,Msg]);
  384. Raise EMediator.Create(Err);
  385. end;
  386. Procedure MediatorError(Sender : TObject; const Fmt : String; Args : Array of const); overload;
  387. begin
  388. MediatorError(Sender,Format(Fmt,Args));
  389. end;
  390. Var
  391. MM : TMediatorManager;
  392. function MediatorManager: TMediatorManager;
  393. begin
  394. if (MM = nil) then
  395. MM := TMediatorManager.Create;
  396. Result := MM;
  397. end;
  398. { TObservedHook }
  399. constructor TObservedHook.CreateSender(ASender: TObject);
  400. begin
  401. FSender:=ASender;
  402. If FSender=Nil then
  403. FSender:=Self;
  404. end;
  405. destructor TObservedHook.Destroy;
  406. begin
  407. If Assigned(FObservers) then
  408. begin
  409. FPONotifyObservers(FSender,ooFree,Nil);
  410. FreeAndNil(FObservers);
  411. end;
  412. inherited Destroy;
  413. end;
  414. procedure TObservedHook.FPOAttachObserver(AObserver: TObject);
  415. Var
  416. I : IFPObserver;
  417. begin
  418. If Not AObserver.GetInterface(SGUIDObserver,I) then
  419. Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
  420. If not Assigned(FObservers) then
  421. FObservers:=TFPList.Create;
  422. FObservers.Add(I);
  423. end;
  424. procedure TObservedHook.FPODetachObserver(AObserver: TObject);
  425. Var
  426. I : IFPObserver;
  427. begin
  428. If Not AObserver.GetInterface(SGUIDObserver,I) then
  429. Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
  430. If Assigned(FObservers) then
  431. begin
  432. FObservers.Remove(I);
  433. If (FObservers.Count=0) then
  434. FreeAndNil(FObservers);
  435. end;
  436. end;
  437. procedure TObservedHook.Changed;
  438. begin
  439. FPONotifyObservers(Sender,ooChange,Nil)
  440. end;
  441. procedure TObservedHook.AddItem(AItem: TObject);
  442. begin
  443. FPONotifyObservers(FSender,ooAddItem,AItem);
  444. end;
  445. procedure TObservedHook.DeleteItem(AItem: TObject);
  446. begin
  447. FPONotifyObservers(FSender,ooDeleteItem,AItem);
  448. end;
  449. procedure TObservedHook.CustomNotify(Data : Pointer = Nil);
  450. begin
  451. FPONotifyObservers(FSender,ooCustom,Data);
  452. end;
  453. procedure TObservedHook.FPONotifyObservers(ASender: TObject; AOperation: TFPObservedOperation; Data : Pointer);
  454. Var
  455. O : TObject;
  456. I : Integer;
  457. Obs : IFPObserver;
  458. begin
  459. If Assigned(FObservers) then
  460. For I:=FObservers.Count-1 downto 0 do
  461. begin
  462. Obs:=IFPObserver(FObservers[i]);
  463. Obs.FPOObservedChanged(ASender,AOperation,Data);
  464. end;
  465. end;
  466. { TBaseMediator }
  467. function TBaseMediator.GetView: TObject;
  468. begin
  469. Result:=Nil;
  470. end;
  471. procedure TBaseMediator.ViewChanged;
  472. begin
  473. If PublishedViewProperty then
  474. CheckPropertyName(View,ViewPropertyName);
  475. MaybeObjectToView
  476. end;
  477. procedure TBaseMediator.ValuelistChanged;
  478. begin
  479. // Do nothing
  480. end;
  481. procedure TBaseMediator.SetActive(const AValue: Boolean);
  482. begin
  483. if FActive=AValue then exit;
  484. FActive:=AValue;
  485. MaybeObjectToView;
  486. end;
  487. procedure TBaseMediator.SetReadOnly(const AValue: Boolean);
  488. begin
  489. if FReadOnly=AValue then exit;
  490. FReadOnly:=AValue;
  491. MaybeObjectToView;
  492. end;
  493. procedure TBaseMediator.SetValueList(const AValue: TObjectList);
  494. Var
  495. I : IFPObserved;
  496. begin
  497. if FValueList=AValue then exit;
  498. If FValueList<>Nil then
  499. I.FPODetachObserver(Self);
  500. If Assigned(AValue) then
  501. begin
  502. FValueList:=AValue;
  503. If Assigned(AValue) then
  504. AValue.FPOAttachObserver(Self);
  505. end;
  506. FValueList:=AValue;
  507. ValueListChanged;
  508. end;
  509. procedure TBaseMediator.CheckPropertyName(AObject : TObject; const APropertyName : String);
  510. begin
  511. If Assigned(AObject) and (APropertyName<>'') then
  512. If Not IsPublishedProp(AObject,APropertyName) then
  513. Raise EObserver.CreateFmt(SErrInvalidPropertyName,[APropertyName,AObject.ClassName]);
  514. end;
  515. procedure TBaseMediator.MaybeObjectToView;
  516. begin
  517. If FActive and CheckViewSubject then
  518. ObjectToView
  519. end;
  520. procedure TBaseMediator.MaybeViewToObject;
  521. begin
  522. If FActive and (Not ReadOnly) and CheckViewSubject then
  523. ViewToObject;
  524. end;
  525. function TBaseMediator.CheckViewSubject: Boolean;
  526. Var
  527. O : TObject;
  528. begin
  529. O:=GetView;
  530. Result:=Assigned(FSubject)
  531. and Assigned(O)
  532. and (ViewPropertyName<>'')
  533. and (SubjectPropertyName<>'');
  534. end;
  535. procedure TBaseMediator.SetSubjectPropertyName(const AValue: String);
  536. begin
  537. if FSubjectPropertyName=AValue then exit;
  538. If PublishedSubjectProperty then
  539. CheckPropertyName(FSubject,AValue);
  540. FSubjectPropertyName:=AValue;
  541. MaybeObjectToView;
  542. end;
  543. procedure TBaseMediator.SetSubject(const AValue: TObject);
  544. Var
  545. I : IFPObserved;
  546. begin
  547. if FSubject=AValue then exit;
  548. If PublishedSubjectProperty then
  549. CheckPropertyName(AValue,FSubjectPropertyName);
  550. If FSubject<>Nil then
  551. If FSubject.GetInterface(SGUIDObserved,I) then
  552. I.FPODetachObserver(Self);
  553. If (AValue<>Nil) then
  554. begin
  555. If not AValue.GetInterface(SGUIDObserved,I) then
  556. Raise EObserver.CreateFmt(SErrObjectCannotBeObserved,[AValue.ClassName]);
  557. FSubject:=AValue;
  558. I.FPOAttachObserver(Self);
  559. end
  560. else
  561. FSubject:=AValue;
  562. MaybeObjectToView;
  563. end;
  564. procedure TBaseMediator.SetViewPropertyName(const AValue: String);
  565. begin
  566. if FViewPropertyName=AValue then exit;
  567. If PublishedViewProperty then
  568. CheckPropertyName(GetView,AValue);
  569. FViewPropertyName:=AValue;
  570. MaybeObjectToView;
  571. end;
  572. class function TBaseMediator.PublishedViewProperty: Boolean;
  573. begin
  574. Result:=True;
  575. end;
  576. class function TBaseMediator.PublishedSubjectProperty: Boolean;
  577. begin
  578. Result:=True;
  579. end;
  580. procedure TBaseMediator.ViewChangedHandler(Sender: TObject);
  581. begin
  582. MaybeViewToObject;
  583. end;
  584. procedure TBaseMediator.FPOObservedChanged(ASender: TObject;
  585. Operation: TFPObservedOperation; Data : Pointer);
  586. begin
  587. If (ASender=FSubject) then
  588. begin
  589. If Operation=ooChange then
  590. MaybeObjectToView
  591. else if Operation=ooFree then
  592. FSubject:=Nil;
  593. end
  594. else if (ASender=FValueList) then
  595. begin
  596. If Operation=ooChange then
  597. ValueListChanged
  598. else if Operation=ooFree then
  599. FValueList:=Nil;
  600. end;
  601. end;
  602. procedure TBaseMediator.RaiseMediatorError(const Msg: String);
  603. begin
  604. MediatorError(Self,Msg);
  605. end;
  606. procedure TBaseMediator.RaiseMediatorError(const Fmt: String;
  607. Args: array of const);
  608. begin
  609. RaiseMediatorError(Format(FMT,Args));
  610. end;
  611. destructor TBaseMediator.Destroy;
  612. begin
  613. Subject:=Nil;
  614. ValueList:=Nil;
  615. inherited Destroy;
  616. end;
  617. procedure TBaseMediator.DoObjectToView;
  618. begin
  619. SetPropValue(GetView,ViewPropertyName,GetPropValue(FSubject,FSubjectPropertyName));
  620. end;
  621. procedure TBaseMediator.DoViewToObject;
  622. begin
  623. SetPropValue(FSubject,FSubjectPropertyName,GetPropValue(GetView,ViewPropertyName));
  624. end;
  625. procedure TBaseMediator.ObjectToView;
  626. Var
  627. B : Boolean;
  628. begin
  629. If Not FTransferring then
  630. begin
  631. FTransferring:=True;
  632. try
  633. B:=False;
  634. If Assigned(FOnObjectToView) then
  635. FOnObjectToView(Self,B);
  636. If not B then
  637. DoObjectToView;
  638. finally
  639. FTransferring:=False;
  640. end;
  641. end;
  642. end;
  643. procedure TBaseMediator.ViewToObject;
  644. Var
  645. B : Boolean;
  646. begin
  647. If Not FTransferring then
  648. begin
  649. FTransferring:=True;
  650. try
  651. B:=False;
  652. If Assigned(FONViewToObject) then
  653. FONViewToObject(Self,B);
  654. If not B then
  655. DoViewToObject;
  656. finally
  657. FTransferring:=False;
  658. end;
  659. end;
  660. end;
  661. class function TBaseMediator.ViewClass: TClass;
  662. begin
  663. Result:=TObject;
  664. end;
  665. class function TBaseMediator.CompositeMediator: Boolean;
  666. begin
  667. Result:=False;
  668. end;
  669. { TComponentMediator }
  670. function TComponentMediator.GetView: TObject;
  671. begin
  672. Result:=FViewComponent;
  673. end;
  674. procedure TComponentMediator.SetComponent(const AValue: TComponent);
  675. begin
  676. If (Avalue=FViewComponent) then
  677. Exit;
  678. If Assigned(FViewComponent) then
  679. FViewComponent.RemoveFreeNotification(Self);
  680. FViewComponent:=AValue;
  681. If Assigned(FViewComponent) then
  682. FViewComponent.FreeNotification(Self);
  683. ViewChanged;
  684. end;
  685. procedure TComponentMediator.Notification(AComponent: TComponent;
  686. Operation: TOperation);
  687. begin
  688. inherited Notification(AComponent, Operation);
  689. If (Operation=opRemove) and (AComponent=FViewComponent) then
  690. begin
  691. FViewComponent:=Nil;
  692. ViewChanged;
  693. end;
  694. end;
  695. { TMediatorDef }
  696. function TMediatorDef.Handles(ASubject: TObject; AGui: TComponent; APropInfo: PPropInfo): Boolean;
  697. var
  698. N: string;
  699. begin
  700. if (APropInfo = nil) then
  701. Result := FMC.CompositeMediator
  702. else
  703. begin
  704. N := APropInfo^.Name;
  705. Result := True;
  706. end;
  707. if not Result then
  708. Exit; // ==>
  709. // At least the classes must match
  710. Result := AGui.InheritsFrom(FMC.ViewClass) and ASubject.InheritsFrom(FMSC);
  711. if Result and not FMC.CompositeMediator then
  712. if (PropertyName <> '') then
  713. Result := (CompareText(N, PropertyName) = 0)
  714. else // Property kind should match. Note that property MUST be set to something.
  715. Result := (APropInfo^.PropType^.Kind in PropertyTypes); // If PropertyName is set, it must match
  716. end;
  717. function TMediatorDef.BetterMatch(M: TMediatorDef): Boolean;
  718. begin
  719. Result := (M = nil);
  720. if not Result then
  721. begin
  722. Result := (FMC.CompositeMediator = M.MediatorClass.CompositeMediator);
  723. if Result then
  724. begin
  725. Result := (PropertyName <> '') and (M.PropertyName = '');
  726. if not Result then
  727. begin
  728. // M's property matches closer
  729. Result := not ((M.PropertyName <> '') and (PropertyName = ''));
  730. if Result then
  731. begin
  732. // Properties are on equal level. Check GUI class.
  733. // Closer GUI class ?
  734. Result := FMC.ViewClass.InheritsFrom(M.MediatorClass.ViewClass);
  735. if not Result then
  736. begin
  737. // M's GUI class matches closer ?
  738. Result := not (M.MediatorClass.ViewClass.InheritsFrom(FMC.ViewClass));
  739. if Result then
  740. begin
  741. // GUI classes are on equal level (different branches in tree). Check subject class.
  742. // Closer Subject class ?
  743. Result := FMSC.InheritsFrom(M.FMSC);
  744. if not Result then
  745. // M's subject class matches closer ?
  746. Result := not M.FMSC.InheritsFrom(FMSC);
  747. end;
  748. end;
  749. end;
  750. end;
  751. end;
  752. end;
  753. end;
  754. { TMediatorDefs }
  755. function TMediatorDefs.GetDef(Index: integer): TMediatorDef;
  756. begin
  757. Result := TMediatorDef(Items[Index]);
  758. end;
  759. procedure TMediatorDefs.SetDef(Index: integer; const AValue: TMediatorDef);
  760. begin
  761. Items[Index] := AValue;
  762. end;
  763. function TMediatorDefs.AddDef: TMediatorDef;
  764. begin
  765. Result := Add as TMediatorDef;
  766. end;
  767. { TMediatorManager }
  768. constructor TMediatorManager.Create;
  769. begin
  770. FDefs := TMediatorDefs.Create(TMediatorDef);
  771. end;
  772. destructor TMediatorManager.Destroy;
  773. begin
  774. FreeAndNil(FDefs);
  775. inherited Destroy;
  776. end;
  777. function TMediatorManager.FindDefFor(ASubject: TObject; AGui: TComponent): TMediatorDef;
  778. begin
  779. Result := FindDefFor(ASubject, AGUI, PPropInfo(nil));
  780. end;
  781. function TMediatorManager.FindDefFor(ASubject: TObject; AGui: TComponent; const APropName: string): TMediatorDef;
  782. var
  783. propinfo: PPropInfo;
  784. begin
  785. propinfo := GetPropInfo(ASubject, APropName);
  786. Result := FindDefFor(ASubject, AGUI, propinfo);
  787. end;
  788. function TMediatorManager.FindDefFor(ASubject: TObject; AGui: TComponent; APropInfo: PPropInfo): TMediatorDef;
  789. var
  790. D: TMediatorDef;
  791. I: integer;
  792. begin
  793. Result := nil;
  794. for I := 0 to FDefs.Count - 1 do
  795. begin
  796. D := FDefs[I];
  797. if D.Handles(ASubject, AGUI, APropInfo) then
  798. if (D.BetterMatch(Result)) then
  799. Result := D;
  800. end;
  801. end;
  802. function TMediatorManager.RegisterMediator(MediatorClass: TMediatorClass; MinSubjectClass: TClass): TMediatorDef;
  803. begin
  804. Result := FDefs.AddDef;
  805. Result.MediatorClass := MediatorClass;
  806. Result.FMSC := MinSubjectClass;
  807. Result.FPN := '';
  808. Result.FPT := tkProperties - [tkClass, tkInterface, tkDynArray, tkObject, tkInterfaceRaw];
  809. end;
  810. function TMediatorManager.RegisterMediator(MediatorClass: TMediatorClass; MinSubjectClass: TClass; PropertyName: string): TMediatorDef;
  811. begin
  812. Result := FDefs.AddDef;
  813. Result.MediatorClass := MediatorClass;
  814. Result.FMSC := MinSubjectClass;
  815. Result.FPN := PropertyName;
  816. Result.FPT := [];
  817. end;
  818. function TMediatorManager.RegisterMediator(MediatorClass: TMediatorClass; MinSubjectClass: TClass; PropertyTypes: TTypeKinds): TMediatorDef;
  819. begin
  820. Result := FDefs.AddDef;
  821. Result.MediatorClass := MediatorClass;
  822. Result.FMSC := MinSubjectClass;
  823. Result.FPN := '';
  824. Result.FPT := PropertyTypes;
  825. end;
  826. { TListItemMediator }
  827. function TListItemMediator.GetActive: Boolean;
  828. begin
  829. Result:=False;
  830. If Assigned(FListMediator) then
  831. Result:=FListMediator.Active;
  832. end;
  833. procedure TListItemMediator.SetSubject(const AValue: TObject);
  834. Var
  835. I : IFPObserved;
  836. begin
  837. if Avalue=FSubject then
  838. Exit;
  839. If FSubject<>Nil then
  840. If FSubject.GetInterface(SGUIDObserved,I) then
  841. I.FPODetachObserver(Self);
  842. FSubject:=AValue;
  843. If (FSubject<>Nil) then
  844. begin
  845. If not FSubject.GetInterface(SGUIDObserved,I) then
  846. Raise EObserver.CreateFmt(SErrObjectCannotBeObserved,[FSubject.ClassName]);
  847. I.FPOAttachObserver(Self);
  848. end;
  849. MaybeObjectToView
  850. end;
  851. procedure TListItemMediator.FPOObservedChanged(ASender: TObject;
  852. Operation: TFPObservedOperation; Data : Pointer);
  853. begin
  854. If Operation=ooFree then
  855. FSubject:=Nil
  856. else
  857. MaybeObjectToView;
  858. end;
  859. procedure TListItemMediator.ObjectToView;
  860. begin
  861. // Do nothing
  862. end;
  863. procedure TListItemMediator.ViewToObject;
  864. begin
  865. // Do nothing
  866. end;
  867. destructor TListItemMediator.Destroy;
  868. begin
  869. Subject:=Nil;
  870. inherited Destroy;
  871. end;
  872. procedure TListItemMediator.MaybeObjectToView;
  873. begin
  874. If Assigned(FSubject) and Active then
  875. ObjectToView;
  876. end;
  877. { TMediatorFieldInfo }
  878. procedure TMediatorFieldInfo.Change;
  879. begin
  880. FPONotifyObservers(Self,ooChange,Nil);
  881. end;
  882. function TMediatorFieldInfo.GetCaption: string;
  883. begin
  884. Result:=FCaption;
  885. If (Result='') then
  886. Result:=FPropName;
  887. end;
  888. procedure TMediatorFieldInfo.SetAlign(const AValue: TAlignment);
  889. begin
  890. If AValue=fAlign then Exit;
  891. FAlign:=AValue;
  892. Change;
  893. end;
  894. procedure TMediatorFieldInfo.SetCaption(const AValue: string);
  895. begin
  896. If AValue=Caption then Exit;
  897. FCaption:=AValue;
  898. Change;
  899. end;
  900. procedure TMediatorFieldInfo.SetPropName(const AValue: string);
  901. begin
  902. If AValue=FPropName then Exit;
  903. FPropName:=AValue;
  904. Change;
  905. end;
  906. procedure TMediatorFieldInfo.SetWidth(const AValue: Integer);
  907. begin
  908. If (FWidth=AValue) then Exit;
  909. FWidth:=AValue;
  910. Change;
  911. end;
  912. const
  913. AlignChars: array[TAlignMent] of char = ('l', 'r', 'c');
  914. function TMediatorFieldInfo.GetAsString: string;
  915. begin
  916. Result := Format('%s|%s|%d|%s', [PropertyName, AlignChars[Alignment], Width, Caption]);
  917. end;
  918. procedure TMediatorFieldInfo.SetAsString(const AValue: string);
  919. Function GetToken(Var S : String) : String;
  920. Var
  921. P : Integer;
  922. begin
  923. P:=Pos('|',S);
  924. If P=0 then P:=Length(S)+1;
  925. Result:=Copy(S,1,P-1);
  926. Delete(S,1,P);
  927. end;
  928. var
  929. V,S: string;
  930. A: TAlignment;
  931. I: integer;
  932. begin
  933. V:=S;
  934. I := 0;
  935. PropertyName:=GetToken(V);
  936. if (PropertyName = '') then
  937. MediatorError(Self,SErrInvalidFieldName, [Index + 1]);
  938. Alignment:=taLeftJustify;
  939. Width:=50;
  940. S:=GetToken(V);
  941. if (S<>'') then
  942. begin
  943. if (length(S)<>1) then
  944. MediatorError(Self,SErrInvalidAlignmentChar, [S,Index+1]);
  945. for A := Low(Talignment) to High(TAlignment) do
  946. if (Upcase(AlignChars[A])=Upcase(S[1])) then
  947. Alignment := A;
  948. S:=GetToken(V);
  949. if (S<>'') then
  950. begin
  951. if not TryStrToInt(S,i) then
  952. MediatorError(Self,SErrInvalidWidthSpecifier,[S]);
  953. Width:=I;
  954. S:=getToken(V);
  955. if (S<>'') then
  956. Caption := S;
  957. end;
  958. end;
  959. end;
  960. procedure TMediatorFieldInfo.Assign(Source: TPersistent);
  961. Var
  962. M : TMediatorFieldInfo;
  963. begin
  964. if (Source is TMediatorFieldInfo) then
  965. begin
  966. M:=Source as TMediatorFieldInfo;
  967. FWidth:=M.FWidth;
  968. FCaption:=M.FCaption;
  969. FPropName:=M.FPropname;
  970. FAlign:=M.FAlign;
  971. end
  972. else
  973. inherited Assign(Source);
  974. end;
  975. { TColumnsListItemMediator }
  976. function TColumnsListItemMediator.GetFieldsInfo: TMediatorFieldInfoList;
  977. begin
  978. If Assigned(FListmediator) and (FListMediator is TColumnsListMediator) then
  979. Result:=TColumnsListMediator(FListMediator).FFieldsInfo;
  980. end;
  981. { TBaseListMediator }
  982. procedure TBaseListMediator.SetOnBeforeSetupField(
  983. const Value: TOnBeforeSetupField);
  984. var
  985. I: integer;
  986. begin
  987. FOnBeforeSetupField := Value;
  988. for I := 0 to FMediatorList.Count - 1 do
  989. TListItemMediator(FMediatorList[i]).OnBeforeSetupField := Value;
  990. end;
  991. class function TBaseListMediator.PublishedViewProperty: Boolean;
  992. begin
  993. Result:=False;
  994. end;
  995. procedure TBaseListMediator.SetActive(const AValue: Boolean);
  996. Var
  997. i : Integer;
  998. begin
  999. inherited SetActive(AValue);
  1000. If AValue then
  1001. For I:=0 to MediatorList.Count-1 do
  1002. TListItemMediator(MediatorList[i]).MaybeObjectToView;
  1003. end;
  1004. function TBaseListMediator.GetSelectedObject: TObject;
  1005. begin
  1006. Result := nil;
  1007. end;
  1008. procedure TBaseListMediator.SetSelectedObject(const AValue: TObject);
  1009. begin
  1010. // Do nothing
  1011. end;
  1012. procedure TBaseListMediator.DoDeleteItemMediator(AIndex: Integer;
  1013. AMediator: TListItemMediator);
  1014. begin
  1015. MediatorList.Delete(AIndex);
  1016. end;
  1017. Function TBaseListMediator.AddObject(AObject : TObject; AIndex : Integer) : TListItemMediator;
  1018. begin
  1019. Result:=CreateItemMediator(AObject,AIndex);
  1020. If (Result<>Nil) then
  1021. begin
  1022. Result.FListMediator:=Self;
  1023. Result.Subject:=AObject;
  1024. MediatorList.Add(Result);
  1025. end;
  1026. end;
  1027. procedure TBaseListMediator.CreateSubMediators;
  1028. var
  1029. I : integer;
  1030. Model : TObjectList;
  1031. begin
  1032. Model:=Subject as TObjectList;
  1033. for i := 0 to Model.Count - 1 do
  1034. begin
  1035. if i < MediatorList.Count then
  1036. TListItemMediator(MediatorList[i]).Subject := Model[i]
  1037. else
  1038. AddObject(Model[i], i);
  1039. end;
  1040. for i := MediatorList.Count-1 downto Model.Count do
  1041. DoDeleteItemMediator(I,TListItemMediator(MediatorList[i]));
  1042. FListChanged:=False;
  1043. end;
  1044. procedure TBaseListMediator.DoViewToObject;
  1045. begin
  1046. // Do nothing
  1047. end;
  1048. procedure TBaseListMediator.DoObjectToView;
  1049. begin
  1050. CreateSubMediators;
  1051. end;
  1052. procedure TBaseListMediator.SetSubject(const AValue: TObject);
  1053. Var
  1054. V : TOBject;
  1055. begin
  1056. if (AValue <> nil) then
  1057. begin
  1058. V:=Nil;
  1059. if (AValue is TObjectList) then
  1060. V:=AValue
  1061. else If (AValue is TList) then
  1062. V:=AValue
  1063. else If (AValue is TCollection) then
  1064. V:=AValue;
  1065. if (V=Nil) then
  1066. RaiseMediatorError(SErrNotListObject, [AValue.ClassName]);
  1067. end;
  1068. FListChanged:=True;
  1069. inherited SetSubject(AValue)
  1070. end;
  1071. function TBaseListMediator.FindObjectMediator(AObject: TObject; out
  1072. AtIndex: Integer): TListItemMediator;
  1073. begin
  1074. AtIndex:=FMediatorList.Count-1;
  1075. While (AtIndex>=0) and (TListItemMediator(FMediatorList[AtIndex]).Subject<>AObject) do
  1076. Dec(AtIndex);
  1077. If (AtIndex=-1) then
  1078. Result:=Nil
  1079. else
  1080. Result:=TListItemMediator(FMediatorList[AtIndex]);
  1081. end;
  1082. constructor TBaseListMediator.Create(AOwner: TComponent);
  1083. begin
  1084. inherited Create(AOwner);
  1085. FMediatorList := TFPObjectList.Create;
  1086. Active := False;
  1087. ViewPropertyName:='Caption';
  1088. end;
  1089. destructor TBaseListMediator.Destroy;
  1090. begin
  1091. FreeAndNil(FMediatorList);
  1092. inherited Destroy;
  1093. end;
  1094. class function TBaseListMediator.CompositeMediator: Boolean;
  1095. begin
  1096. Result:=True;
  1097. end;
  1098. procedure TBaseListMediator.ObservedChanged(ASender: TObject;
  1099. Operation: TFPObservedOperation);
  1100. var
  1101. M : TListItemMediator;
  1102. Model : TObjectList;
  1103. I : Integer;
  1104. begin
  1105. // Do not call inherited, it will rebuild the list !!
  1106. Case Operation of
  1107. ooAddItem : AddObject(ASender,TObjectList(Subject).Count-1); // always at the end...
  1108. ooDeleteItem : begin
  1109. M:=FindObjectMediator(ASender,I);
  1110. if M<>nil then
  1111. DoDeleteItemMediator(I,M);
  1112. end;
  1113. ooChange : begin
  1114. Model:=(Subject as TObjectList);
  1115. if FListChanged or (TObjectList(Model).Count<>MediatorList.Count) or (Model.Count=0) then // Safety measure
  1116. MaybeObjectToView;
  1117. end;
  1118. end;
  1119. end;
  1120. { TColumnsListMediator }
  1121. procedure TColumnsListMediator.SetFieldsInfo(
  1122. const AValue: TMediatorFieldInfoList);
  1123. begin
  1124. FFieldsInfo.Assign(AValue);
  1125. end;
  1126. function TColumnsListMediator.GetDisplayNames: string;
  1127. begin
  1128. Result := FFieldsInfo.AsString;
  1129. end;
  1130. procedure TColumnsListMediator.SetDisplayNames(const AValue: string);
  1131. begin
  1132. SubjectPropertyName:=AValue;
  1133. ParseDisplayNames(AValue);
  1134. end;
  1135. procedure TColumnsListMediator.FieldInfoChanged(Item: TMediatorFieldInfo;
  1136. Action: TCollectionNotification);
  1137. begin
  1138. If Active then
  1139. RaiseMediatorError(SErrActive);
  1140. end;
  1141. class function TColumnsListMediator.PublishedSubjectProperty: Boolean;
  1142. begin
  1143. Result:=False;
  1144. end;
  1145. procedure TColumnsListMediator.ParseDisplayNames(const AValue: string);
  1146. Function GetToken(Var S : String) : String;
  1147. Var
  1148. P : Integer;
  1149. begin
  1150. P:=Pos(';',S);
  1151. If P=0 then P:=Length(S)+1;
  1152. Result:=Copy(S,1,P-1);
  1153. Delete(S,1,P);
  1154. end;
  1155. var
  1156. I : integer;
  1157. lField : string;
  1158. MFI : TMediatorFieldInfo;
  1159. A,S : String;
  1160. begin
  1161. FFieldsInfo.Clear;
  1162. A:=AValue;
  1163. Repeat
  1164. S:=GetToken(A);
  1165. If (S<>'') then
  1166. begin
  1167. MFI:=FFieldsInfo.AddFieldInfo;
  1168. MFI.AsString:=S;
  1169. end;
  1170. until (S='');
  1171. end;
  1172. procedure TColumnsListMediator.CreateColumns;
  1173. begin
  1174. // Do nothing. Must be implemented by descendent objects.
  1175. end;
  1176. procedure TColumnsListMediator.DoObjectToView;
  1177. begin
  1178. CreateColumns;
  1179. inherited DoObjectToView;
  1180. end;
  1181. constructor TColumnsListMediator.Create(AOwner: TComponent);
  1182. begin
  1183. inherited Create(AOwner);
  1184. FFieldsInfo:=TMediatorFieldInfoList.create(TMediatorFieldInfo);
  1185. SubjectPropertyName:='Caption';
  1186. end;
  1187. destructor TColumnsListMediator.Destroy;
  1188. begin
  1189. FreeAndNil(FFieldsInfo);
  1190. inherited Destroy;
  1191. end;
  1192. { TMediatorFieldInfoList }
  1193. function TMediatorFieldInfoList.GetAsString: string;
  1194. var
  1195. I: integer;
  1196. begin
  1197. Result := '';
  1198. for I := 0 to Count - 1 do
  1199. begin
  1200. if (Result <> '') then
  1201. Result := Result + ';';
  1202. Result := Result + FieldInfo[i].AsString;
  1203. end;
  1204. end;
  1205. function TMediatorFieldInfoList.GetI(Index: integer): TMediatorFieldInfo;
  1206. begin
  1207. Result := TMediatorFieldInfo(Items[Index]);
  1208. end;
  1209. procedure TMediatorFieldInfoList.SetI(Index: integer;
  1210. const AValue: TMediatorFieldInfo);
  1211. begin
  1212. Items[Index] := AValue;
  1213. end;
  1214. procedure TMediatorFieldInfoList.Notify(Item: TCollectionItem;
  1215. Action: TCollectionNotification);
  1216. begin
  1217. inherited Notify(Item, Action);
  1218. If Assigned(FMediator) then
  1219. FMediator.FieldInfoChanged(Item as TMediatorFieldInfo,Action)
  1220. end;
  1221. function TMediatorFieldInfoList.AddFieldInfo: TMediatorFieldInfo;
  1222. begin
  1223. Result := Add as TMediatorFieldInfo;
  1224. end;
  1225. function TMediatorFieldInfoList.AddFieldInfo(const APropName: String;
  1226. AFieldWidth: Integer): TMediatorFieldInfo;
  1227. begin
  1228. Result:=AddFieldInfo();
  1229. Result.PropertyName:=APropName;
  1230. Result.Width:=AFieldWidth;
  1231. end;
  1232. function TMediatorFieldInfoList.AddFieldInfo(const APropName, ACaption: String;
  1233. AFieldWidth: Integer): TMediatorFieldInfo;
  1234. begin
  1235. Result:=AddFieldInfo(APropName,AFieldWidth);
  1236. Result.Caption:=ACaption;
  1237. end;
  1238. function TMediatorFieldInfoList.AddFieldInfo(const APropName, ACaption: String;
  1239. AFieldWidth: Integer; AAlignment: TAlignment): TMediatorFieldInfo;
  1240. begin
  1241. Result:=AddFieldInfo(APropName,ACaption,AFieldWidth);
  1242. Result.Alignment:=AAlignment;
  1243. end;
  1244. end.