fpobserver.pp 41 KB

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