Board index » cppbuilder » Persistent TStringListList

Persistent TStringListList


2005-09-27 08:11:39 PM
cppbuilder88
I want a class that's a list of TStringLists.
I have a working implementation derived from TObjectList that holds
TStringList items, but I want to make my class persistent...
Obviously it's got to now be derived from TPersistent, but I'm not sure how
best to handle this.
What I'd planned to do is to use definepropertyies to provide functions to
let the reader and writer stream each TStringList in turn, but it seems that
can't work because the TStringList::WriteData is a private function - and
also TStringList is derived from TPersistent rather than TComponent, and
there doesn't seem to be a TWriter::WriteComponent method.
Any suggestions?
- Roddy
 
 

Re:Persistent TStringListList

"Roddy Pratt" <roddy at spam fritter dot com>wrote in message
Quote
What I'd planned to do is to use definepropertyies to provide functions to
let the reader and writer stream each TStringList in turn, but it seems
that
can't work because the TStringList::WriteData is a private function - and
also TStringList is derived from TPersistent rather than TComponent, and
there doesn't seem to be a TWriter::WriteComponent method.
DefineProperties() is the correct thing to use, but you are approaching the
issue from the wrong angle. TStrings has SaveToStream() and
LoadFromStream() methods. You should use those methods, ie (untested):
class TStringListItem : public TObject
{
private:
TStrings *FStrings;
void __fastcall SetStrings(TStrings* Value);
public:
__fastcall TStringListItem();
__fastcall ~TStringListItem();
void __fastcall ReadData(TStream *Stream);
void __fastcall WriteData(TStream *Stream);
__property TStrings* Strings = {read=FStrings, write=SetStrings};
};
__fastcall TStringListItem::TStringListItem()
: TObject()
{
FStrings = new TStringList;
}
__fastcall TStringListItem::~TStringListItem()
{
delete FStrings;
}
void __fastcall TStringListItem::ReadData(TStream *Stream)
{
FStrings->LoadFromStream(Stream);
}
void __fastcall TStringListItem::WriteData(TStream *Stream)
{
FStrings->SaveToStream(Stream);
}
void __fastcall TStringListItem::SetStrings(TStrings* Value)
{
FStrings->Assign(Value);
}
class TStringListList : public TPersistent
{
private:
TObjectList *FStrings;
int __fastcall GetCount();
void __fastcall SetCount(int Value);
TString* __fastcall GetItem(int Index);
void __fastcall SetItem(int Index, TStrings *Value);
protected:
virtual void __fastcall DefineProperties(TFiler* Filer);
void __fastcall ReadCount(TReader* Reader);
void __fastcall WriteCount(TWriter* Writer);
public:
__fastcall TStringListList();
__fastcall ~TStringListList();
int __fastcall Add();
void __fastcall Delete(int Index);
void __fastcall Clear();
__property int Count = {read=GetCount, write=SetCount};
__property TStrings* Items[int Index] = {read=GetItem,
write=SetItem};
};
__fastcall TStringListList::TStringListList()
: TPersistent()
{
FStrings = new TObjectList(true);
}
__fastcall TStringListList::~TStringListList()
{
delete FStrings;
}
int __fastcall TStringListList::Add()
{
return FStrings->Add(new TStringListItem);
}
void __fastcall TStringListList::Delete(int Index)
{
FStrings->Delete(Index);
}
void __fastcall TStringListList::Clear()
{
FStrings->Clear();
}
int __fastcall TStringListList::GetCount()
{
return FStrings->Count;
}
void __fastcall TStringListList::SetCount(int Value)
{
for(int x = FStrings->Count-1; x>= Value; --x)
FStrings->Delete(x);
FStrings->Capacity = Value;
for(int x = FStrings->Count; x < Value; ++x)
Add();
}
TStrings* __fastcall TStringListList::GetItem(int Index)
{
return ((TStringListItem*) FStrings->Items[Index])->Strings;
}
void __fastcall TStringListList::SetItem(int Index, TStringList *Value)
{
((TStringListItem*) FStrings->Items[Index])->Strings = Value;
}
void __fastcall TStringListList::DefineProperties(TFiler* Filer)
{
Filer->DefineBinaryProperty("Count", ReadCount, WriteCount,
FStrings->Count>0);
for(int x = 0; x < FStrings->Count; ++x)
{
TStringListItem *Item = (TStringListItem*) FStrings->Items[x];
Filer->DefineBinaryProperty("Strings" + AnsiString(x+1),
Item->ReadData, Item->WriteData, Item->Strings->Count>0);
}
}
void __fastcall TStringListList::ReadCount(TReader* Reader)
{
SetCount(Reader->ReadInteger());
}
void __fastcall TStringListList::WriteCount(TWriter* Writer)
{
Writer->WriteInteger(FStrings->Count);
}
Gambit
 

Re:Persistent TStringListList

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote
DefineProperties() is the correct thing to use, but you are approaching
the
issue from the wrong angle. TStrings has SaveToStream() and
LoadFromStream() methods. You should use those methods, ie (untested):
<Snipped!>
Gambit, Thanks very much for your answer. I've learnt a lot by reading,
running and stepping through it.
In particular, I realised that properties are read/written *as they are
defined* in DefineProperties. I'd assumed this was a one-off function, and
therefore you couldn't define additional properties 'on the fly'.
I also now understand DefineBinaryProperty - and that it uses streams
instead of Reader/Writers. I'd thought it was a legacy function for non-text
DFM's!
The only possible catch I see with your implementation is that it uses
LoadToStream/SaveToStream. I'm not entirely sure how well they handle
strings with embedded newline sequences....
Regards - and thanks again,
Roddy
 

{smallsort}

Re:Persistent TStringListList

"Roddy Pratt" <roddy at spam fritter dot com>wrote in message
Quote
The only possible catch I see with your implementation is that it
uses LoadToStream/SaveToStream. I'm not entirely sure how
well they handle strings with embedded newline sequences....
SaveToStream() does not care about the contents of the strings. They are
stored as-is. LoadFromStream(), on the other hand, does not recognize
embedded newline sequences. If you need that, then you will have to stream
the individual strings manually. For example:
void __fastcall TStringListItem::ReadData(TStream *Stream)
{
FStrings->Clear();
int count = 0;
Stream->ReadBuffer(&count, sizeof(int));
for(int i = 0; i < count; ++i)
{
int length = 0;
Stream->ReadBuffer(&length, sizeof(int));
AnsiString s;
s.SetLength(length);
Stream->ReadBuffer(s.c_str(), length);
FStrings->Add(s);
}
}
void __fastcall TStringListItem::WriteData(TStream *Stream)
{
int count = FStrings->Count;
Stream->WriteBuffer(&count, sizeof(int));
for(int i = 0; i < count; ++i)
{
AnsiString s = FStrings->Strings[i];
int length = s.Length();
Stream->WriteBuffer(&length, sizeof(int));
Stream->WriteBuffer(s.c_str(), length);
}
}
Gambit
 

Re:Persistent TStringListList

"Remy Lebeau (TeamB)" < XXXX@XXXXX.COM >wrote in message
Quote


SaveToStream() does not care about the contents of the strings. They are
stored as-is. LoadFromStream(), on the other hand, does not recognize
embedded newline sequences. If you need that, then you will have to
stream
the individual strings manually. For example:
Thanks. That's what I thought.
I was just wondering - (if TPersistent::DefineProperties was public rather
than protected) - if you could somehow just call the
TStringList::DefineProperties from the TStringListItem::ReadData - then you
could easily make a TThingList without knowing the underlying structure of
TThing. Just an idea...
- Roddy
 

Re:Persistent TStringListList

"Roddy Pratt" <roddy at spam fritter dot com>wrote in message
Quote
I was just wondering - (if TPersistent::DefineProperties was public
rather than protected) - if you could somehow just call the
TStringList::DefineProperties from the TStringListItem::ReadData
That would not work.
However, there is another option that you not been explored yet - derive a
class from TCollectionItem that has a TStrings published property, and then
derive TStringListList from TCollection. That way, all streaming will be
handled for you automatically by the VCL without any additional coding on
your part. For example:
class TStringListItem : public TCollectionItem
{
private:
TStrings *FStrings;
void __fastcall SetStrings(TStrings* Value);
public:
__fastcall TStringListItem(TCollection *Collection);
__fastcall ~TStringListItem();
__published:
__property TStrings* Strings = {read=FStrings, write=SetStrings};
};
__fastcall TStringListItem::TStringListItem(TCollection *Collection)
: TCollectionItem(Collection)
{
FStrings = new TStringList;
}
__fastcall TStringListItem::~TStringListItem()
{
delete FStrings;
}
void __fastcall TStringListItem::SetStrings(TStrings* Value)
{
FStrings->Assign(Value);
}
class TStringListList : public TCollection
{
private:
TStringListItem* __fastcall GetString(int Index);
void __fastcall SetString(int Index, TStringListItem *Value);
public:
__fastcall TStringListList();
HIDESBASE TStringListItem* __fastcall Add();
__property TStringListItem* Strings[int Index] = {read=GetString,
write=SetString};
};
__fastcall TStringListList::TStringListList()
: TCollection(__classid(TStringListItem))
{
}
TStringListItem* __fastcall TStringListList::Add()
{
return (TStringListItem*) TCollection::Add();
}
TStringListItem* __fastcall TStringListList::GetString(int Index)
{
return (TStringListItem*) TCollection::Items[Index];
}
void __fastcall TStringListList::SetString(int Index, TStringListItem
*Value)
{
TCollection::SetItem(Index, Value);
}
Gambit