View Issue Details

IDProjectCategoryView StatusLast Update
0001642JEDI VCL04 Feature Requestpublic2004-06-14 14:32
ReporterbugfinderAssigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status resolvedResolutionopen 
Product Version 
Target VersionFixed in Version 
Summary0001642: AppStorage: add reading/writing of TCollection and TObjectList
DescriptionId like it if I could add some of the private/public variables of the form to the form storage. A number of my apps use TLists of classes Ive made, so for example an FTP set would be

   PSite = ^TSite;
  TSite = Record
      sitename : string;
      localdir : string;
      ftpuser : string;
      ftpasswd : string;
      ftpserver : string;
      ftpport : string;
      ftpdir : string;
  end;

I then make a tlist of the psites.. I looked at most of your copmonents to see if I could fudge it to do this, but I coudlnt see one.. (Please feel free to tell me to drink more coffee and point me in the right direction if I did miss it)..

I know I can add specific things to the form storage but I didnt see a way to add an unknown quantity of stuffs. I even tried making it a property of the form.. I dont really want to make components for it.. but if I have to, I suppose I could.. I just would rather not have to for each project I make.
TagsNo tags attached.

Activities

user72

2004-04-15 06:18

  ~0003872

Can't you use the specific AppStorage component hooked up to the formstorage (like JvAppIniFileStorage) to store the data?

bugfinder

2004-04-15 06:25

reporter   ~0003873

I dont see how no.. not without making as much work as the whole point was to avoid..

Given the above senario, and I have no example for the appstorage thing to cover classes and from what I can see the invividually added stored values, are like variables so Id have to go through each site, create a unique var name, and set value, and same on read back.. Hence wondering if it were possible to add something else..

If Im missing the point, a small chunk of example code would be appreciated thanks.

user72

2004-04-15 09:35

  ~0003876

It's hard to give any advice because I don't really understand what you are tring to accomplish. Could you provide an example on how you envision this support in JvFormStorage?

To me, it seems more appropriate to write the data to the AppStorage component, something like:

JvAppInFileStorage1.WriteString('FormData',Form.Name,SiteListToString(SiteList));

and

StringToSiteList(SiteList, JvAppInFileStorage1.ReadString('FormData',Form.Name,''));

The implementation of SiteListToString and StringToSiteList is, of course, up to you, but that would be the case in any scenario.

bugfinder

2004-04-15 12:48

reporter   ~0003885

Well, I gave an example of a structure Im trying to save. At the moment local variables are addible but you have to add the variable and the value.. and for a list, with sub properties, I am not saving much than doing the code as you would originally with

site1sitename=a test
site1localdir=c:\www
site1ftpuser=
site1ftpasswd=
site1ftpserver=
site1ftpport=
site1ftpdir=
site2sitename=another test
site2localdir=c:\homesite
site2ftpuser=test
site2ftpasswd=test
site2ftpserver=aserver
site2ftpport=21
site2ftpdir=/

Which is exactly what I was hoping to avoid doing. I could have made that code but the formstorage does so much nicely for you I wanted to be able to add these kinds of structures..

Maybe then rather than adding it to the formstorage, perhaps an ability have a JVCL control which allows you to store lists much like the MRU but of your own field structures like mine above, so it can be added to the formstorage?

Was just hoping as Im sure Im not the only one who has a structure per app that stores grouped data like that.. thats not going in a database....

user72

2004-04-15 14:01

  ~0003894

I don't see a woekable way of doing that. Basically, you are asking for what's already available with StoredValues but with auto-discovery of lists and each list items properties.

I guess it could be generically solved somehow using TCollection/TCollectionItem descendants (so we can use the Items property of TCollection and get RTTI for the items) but is it really worth it? The coding wouldn't be lesser, that's for sure...

marcelb

2004-04-16 02:12

manager   ~0003903

At least you can not use records if you want it to be automatic. Records have no RTTI about their members. Using a class (derived from TPersistent or from TObject but declared within a {$M+}...{$M-} section) and having the properties to save as published would help. The only thing I see missing is that TJvCustomAppStorage does not provide a proper way of saving a TObjectList. If that would be added, you could simple do something like JvAppIniFileStorage1.WriteObjectList(SiteList) to save it (and use ReadObjectList to read it back in).

If that would be desirable, I would suggest changing the subject to be more accurate (something like 'Storing TObjectList in AppStorages' would be good idea. I'm not sure if I have the time to do so, but maybe Jens will be tracking this and jump in?

bugfinder

2004-04-16 05:10

reporter   ~0003911

Thats an interesting thought Marcel. Ive always used sctructures in the past for my apps, however, if by making them objects we could build something to automate the saving of them, then Im sure I wouldnt be the only one who'd find it useful.

I suppose its opened a debate as to whats a good way to store collections of data that can be easily saved. :)

user72

2004-04-16 05:24

  ~0003912

Is TObjectList available in all SKU's? Wouldn't TCollection/TCollectionItem be more suitable? It seems to me that the requirement to add the {M+} directive could generate a lot of "it doesn't work" bug reports.

marcelb

2004-04-16 10:58

manager   ~0003916

I don;t know if TObjectList is available in the personal/standard editions. Doesn't really matter if we allow any TList descendant and simply assume it contains TPersistent descendants.
Regarding the possible complaints about things not working: I've come across those for JvInspector regurlary and cannot be avoided. Not everybody understands the RTTI stuff and that (out of the box) only TPersistent descendants allow this. JvInspector was never "advertised" as capable of inspecting a TObject but it does support it. We could do the same for the AppStorage: we mention only TPersistent and published properties and we "secretly" support TObject as well for those that know how to use TObject/{$M+}.

bugfinder

2004-04-17 01:04

reporter   ~0003918

Thanks for this guys. Using a TCollection/TCollectionitem then a component to show the collection, I have achieved what I wanted. Thanks.. Making a component set per app isnt what I imagined as idea, but actually, its not so bad..

:)

YAY for hidden extras :)

user72

2004-04-18 02:01

  ~0003929

Last edited: 2004-04-18 02:02

Does this mean that you no longer are interested in the modification?

edited on: 04-18-04 02:02

bugfinder

2004-04-18 04:37

reporter   ~0003931

I would very much prefer not have to make a component per app, so yes, Im still interested, but you have kindly given me a reasonable work around until such time as a better alternative can be made.

Making a component with a tcollection on it with the props on a tcollectionitem.. can be saved as is, which is a good work around IMHO.

user72

2004-04-18 06:34

  ~0003932

Marcel, do you think it is a good idea to add something like this:

WriteCollection(const Section:string;ACollection:TCollection);
ReadCollection(const Section:string;ACollection:TCollection);

to the base AppStorage class or do you have other suggestions/ideas?

As far as making this visible at design-time, I haven't got any ideas yet, but maybe you or someone else has?

marcelb

2004-04-18 10:13

manager   ~0003933

I think it's a great addition, along with the Read/WriteObjectList (and perhaps even update the string list writer to also allow reading/writing of linked objects). If it's OK with you, I would like to alter the subject line a bit (like my earlier proposal) and see if we can get Jens to take a look into it (I really don't have the time with the inspector bugs still open and docs and non-Jedi life).

bugfinder

2004-04-18 11:11

reporter   ~0003934

Well the Tcollection read/write semi works, in the sense I have one on my components and it happily works through that great.

But having a direct ability to just write one would be rocking.. So yes, alter ALL you like.. Im sure it will make me and many others happy

marcelb

2004-04-18 11:48

manager   ~0003935

Update the subject. Will mail Jens to attract his attention.

jfudickar

2004-04-18 14:45

developer   ~0003938

Hi (marcel: i'm online now) ,

shouldn't be so hard, principle. We have the general functions ReadList/Writelist. They should support anything what we want.

The only question is, how to initialize/create the objcts.

If we only have tpersistent it could be possible, but if someone tries to store components we got a problem because of the parent reference.

And i'm not excacty shure about how to create an object when i only have the name of the type in a string.

So we have something to discuss.

Any comments?

Greetings
Jens

user72

2004-04-19 00:14

  ~0003943

You shouldn't have to create the object (list or collection) yourself. Instead it should be passed by the caller:

WriteList(const Section:string;AList:TList);
ReadList(const Section:string;AList:TList);
WriteCollection(const Section:string;Collection:TCollection);
ReadCollection(const Section:string;Collection:TCollection);

Writing to storage should not be a problem for either list or collection.

(BTW, if lists are to be supported, I think we should use TList as base class, not TObjectList. We can then check each TList item if it contains a TObject and, if not, refrain from storing it).

When reading, however, it is impossible to directly get at the actual class of the saved items AFAIK, so unles someone else has a suggestion, this might mean we can't support generic lists.

With TCollection, you can just use the Add method and then set the values using RTTI.

marcelb

2004-04-19 02:16

manager   ~0003946

If we can assume every item in the list is of the same class, we could simply let the user specify the item class as a parameter (a ItemClass: TClass parameter would do nicely).
  For heterogenous lists we should store the class name and upon reading use GetClass(<name we just read in>) to obtain a TClass reference (as done in the JvDataProvider core; take a look at the various ReadItems/WriteItems methods). Problem here is that the user *must* call RegisterClass on any class it can read/write.
  I think TComponent would be impossible to store, unless we let the user specify a callback to create an instance (this could also be used as an alternative to the TClass approach) or assume the list already contains all items and just read/write the contents (as per Peters suggestion. I do not like this approach, since you then will have to assume the list really contains all the items upon reading. This is more of a fixed list option; lists that can vary in size are not usable in this approach). The callback could be a very nice way to accomplish the task of creating items as needed, since the callback could specify the ID of the object to create (which will usually be the class name, but we could opt to add a callback to the write method as well to allow the user to specify different IDs).

user72

2004-04-19 04:13

  ~0003949

You must have misunderstood me. I never suggested the lists should be prefilled, just that the TCollection/TList instance itslef must be created by the caller (i.e ReadCollection doesn't create the collection, just the items).

Anyway, one thing that strikes me with your suggestion is that the code would have to assume parameterless constructors for the list items, right? Or do you have an idea on solving that with the callback?

Generally, I think we should keep it as simple as possible. If it gets too complex (supporting lists of TComponent, callbacks with different ID's etc), no one will understand how to use it.

marcelb

2004-04-19 10:21

manager   ~0003958

I did misunderstand you. Anyway, you are correct about the parameterless constructors (hence a list of TComponent is basically impossible). However, I don't believe there is another way to do so without making it more complex for users. A hybrid solution could be used:

procedure ReadObjectList(Path: string; List: TList); overload;
procedure ReadObjectList(Path: string; List: TList; ItemCreator: TObjectListItemCreateEvent); overload;

I would even suggest to have the first version call the second with a nil for the ItemCreator event. The second version would interpret this as a parameterless constructor otherwise the event callback is called, providing the path and item number. The event handler would have to retrieve a class name/object type ID and create the item (optionally by reading additional values from the storage to provide values for constructor parameters).

  This would allow both a straight forward usage as well as a more advanced call.

user72

2004-04-23 06:17

  ~0004035

Jens, are you working on this?

jfudickar

2004-04-23 07:05

developer   ~0004036

I will try to do some work on it this weekend. Sorry i'm a little bit busy :-(

user72

2004-04-23 10:00

  ~0004037

> Sorry i'm a little bit busy :-(
I know the feeling...

jfudickar

2004-06-02 15:09

developer   ~0004439

6 weeks later :-)

I've made a first try. Please have a look at the attachment. It's not tested, only compiled (because it's too late).

I didn'T know if i'm going the way you were thinking on.

The new functions are : Read/Write/DeleteObjectItem and ReadObjectList and WriteObjectList.

An additional idea is to add two functions Read/WriteStringListObjects which does the same with tStrings instead of TList, or add an parameter IncludeObjects to Read/WriteStringList.

Comments are welcome.

Please be nice to me. My experiences with events and especialy dynmicly object creation with dynamic types are not so high :-)

Greetings
Jens

2004-06-02 15:09

 

JvAppStorage.pas (94,733 bytes)

marcelb

2004-06-03 02:36

manager   ~0004448

After a first cursory glance I see only one issue: ReadObjectList sets FCurrentObjectListItemCreateEvent of the current storage, but then uses TgtStore for the actual reading. While the latter is correct, I think you need to set TgtStore.FCurrentObjectListItemCreateEvent just in case the TgtStore is not the same as the current storage.

    I think WriteStringList should indeed get an additional StoreObjects parameter and ReadStringList should be overloaded to allow one to specify the InstanceCreator (perhaps you can rename FCurrentObjectListItemCreateEvent to FCurrentInstanceCreateEvent; it's a bit shorter).

    Additionally you could copy the Read/WriteObjectList to Read/WriteCollection which will allow a collection to be saved. Usually collections consist of a list of same typed items and you can use the collection's Add or New method (forgot what it's called) to create the objects and there's no need to store the type of the instances but I have no problems if you just keep the Read/WriteObjectList mechanism for collections (since it is not entirely impossible to create a collection of different items).

    The comments describing the new methods seem a bit off (you specify ClassName for the DefaultObjectListItemCreateEvent but ObjectType in ReadObjectList description; the ReadObjectList version without an ItemCreator parameter specifies that the ItemCreator event determines the type of the object created). Not a biggy but very confusing when reading it to gauge what is possible.

    When I'm in the mood again to fire up D5 instead of D8, I'll have a better look at do some testing.

jfudickar

2004-06-14 14:31

developer   ~0004556

Hi Marcel,

uploaded to cvs. The most of your suggestions are added/changed. Only open issue is the point of Read/WriteStringList.

I didn't like your suggestion of adding parameters. I think a better solution is to add two new functions Read/WriteStringListObject.

What do you think.

Greetings
Jens

Issue History

Date Modified Username Field Change
2004-04-15 04:07 bugfinder New Issue
2004-04-15 06:18 user72 Note Added: 0003872
2004-04-15 06:25 bugfinder Note Added: 0003873
2004-04-15 09:35 user72 Note Added: 0003876
2004-04-15 12:48 bugfinder Note Added: 0003885
2004-04-15 14:01 user72 Note Added: 0003894
2004-04-16 02:12 marcelb Note Added: 0003903
2004-04-16 05:10 bugfinder Note Added: 0003911
2004-04-16 05:24 user72 Note Added: 0003912
2004-04-16 10:58 marcelb Note Added: 0003916
2004-04-17 01:04 bugfinder Note Added: 0003918
2004-04-18 02:01 user72 Note Added: 0003929
2004-04-18 02:02 user72 Note Edited: 0003929
2004-04-18 04:37 bugfinder Note Added: 0003931
2004-04-18 06:34 user72 Note Added: 0003932
2004-04-18 06:35 user72 Status new => acknowledged
2004-04-18 10:13 marcelb Note Added: 0003933
2004-04-18 11:11 bugfinder Note Added: 0003934
2004-04-18 11:48 marcelb Summary Request for the formstorage component => AppStorage: add reading/writing of TCollection and TObjectList
2004-04-18 11:48 marcelb Note Added: 0003935
2004-04-18 14:45 jfudickar Note Added: 0003938
2004-04-19 00:14 user72 Note Added: 0003943
2004-04-19 02:16 marcelb Note Added: 0003946
2004-04-19 04:13 user72 Note Added: 0003949
2004-04-19 10:21 marcelb Note Added: 0003958
2004-04-23 06:17 user72 Note Added: 0004035
2004-04-23 07:05 jfudickar Note Added: 0004036
2004-04-23 10:00 user72 Note Added: 0004037
2004-06-02 15:09 jfudickar Note Added: 0004439
2004-06-02 15:09 jfudickar File Added: JvAppStorage.pas
2004-06-03 02:36 marcelb Note Added: 0004448
2004-06-14 14:31 jfudickar Note Added: 0004556
2004-06-14 14:32 jfudickar Status acknowledged => resolved