fpobserver.pp 41 KB

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