Solved

Hard Work With Ini's - For the motherload.

Posted on 2000-05-01
10
212 Views
Last Modified: 2010-04-04
Complete and sincere replies only please:

This is a complex (to me) question. In my FTP client... I'm currently working on an acocunt manager. I have the basic idea of how it needs to be done, and I have developed an ini format from which I need to build a procedure on. For this question, I will be giving all of my remaining points to the one who answers it (correctly), because I know there's a lot of hand writen code involved here.

To begin with, Let's call the procedure LoadAccounts;
Now... What we'll be doing is adding saved account names and folders (respectively) to a TTreeview. We'll call this Treeview1.

The important part now, since I already know how to save information to the ini, is the actual structure I've developed for the ini itself. This is is what your answer will need to load and display properly. The ini will look like this:

[My Main Folder Psylord]
Option 1=Value 1
Option 2=Value 2
OPtion 3=Value 3
Option 4=Value 4

NOW PAY ATTENTION:
"My Main Folder" Indicated a virtual folder under which the site (labeled "Psylord") will be stored. This means "Psylord" will have to be a child of "My Main Folder".

Now.. I have seen examples of people using two different characters RIGHT BEFORE and RIGHT AFTER the folder name... I don't know how they parse it, but this is obviously to filter out the folder name from the site name (in this case). For example if I were to make the ini look like this:

[<My Main Folder> Psylord]
Option 1=Value 1
Option 2=Value 2
OPtion 3=Value 3
Option 4=Value 4

The folder name may be distinguished by the "<" and ">" symbols. This would be acceptable if implemented in your answer's code. If you need to use other characters, so be it.

One of these two first example entries MUST BE IN YOUR ANSWER! It must load properly, displaying the Parent Node "My Main Folder" and the child of it should be an item with "Psylord" as the caption!

Additionally, the procedure must load items that do not have a parent, as in this example:

[Site 2]
Option 1=Value 1
Option 2=Value 2
OPtion 3=Value 3
Option 4=Value 4

Again, this must be part of your answer for it to be accepted.

Now for the tricky part...
Folders should be allowed to have folders inside them. This would look something like:

[<My Main Folder> <My Sub Folder> Site 3]
Option 1=Value 1
Option 2=Value 2
OPtion 3=Value 3
Option 4=Value 4

This as well needs to be implemented in your answer.
If you have what it takes, you'll get what you deserve, which is all of my points.

NOTE: When I say these things need to be part of your answer, that means that if I have an ini that has all of these things in it, it will load correctly. You don't need to make me an ini, just the proper procedure. Once I see how this data can be read, I can create edit/delete/create procedures.

If you really wanna make me happy, tell me what section I should write to by getting information of which node is selected (NOT A REQUIREMENT).

I wish I had more points to offer for this. I appreciate any help and sorry for the strict rules. :/

I will increase the points if my questions get deleted and when they get back in my account. If they don't get to me before the question is answered, I will set up a dummy question later so I can transfer the points to you at that time.

I have 445 Points all together so that's what this question is really worth.

-Psylord
0
Comment
Question by:Psylord
  • 6
  • 2
  • 2
10 Comments
 
LVL 2

Expert Comment

by:mullet_attack
Comment Utility
Fistly, thanks for a well written question (makes life easier...)

I think you may have a design problem to solve _before_ some code gets written. When you write the ini file, I guess you simply go thru the treeview's items array, using the Node's text ( and possibly it's parent's text etc) as the SECTION value for WriteString. That works fine, except when it comes to reading the data back. You don't know the node's text, nor do you know the SECTION heading is. So how are you going to use ReadString to get the data for your nodes?

I suggest an alternate ini structure. I know this isn't the exact answer to your Q, but I think this will allow you to solve it yourself.

take my sample tree :

TopNode
  ChildNode1
    BabyNode1
    BabyNode2
  ChildNode2
    BabyNode1

I would save it like this :

[Nodes]
NumNodes = 5
Node1 = ChildNode1
Node2 = ChildNode1~BabyNode1
Node3 = ChildNode1~BabyNode2
Node4 = ChildNode2
Node5 = ChildNode2~BabyNode1

[Node1]
Option 1=Value 1
Option 2=Value 2
OPtion 3=Value 3
Option 4=Value 4

[Node2]
Option 1=Value 1
Option 2=Value 2
OPtion 3=Value 3
Option 4=Value 4

etc. By having the [Nodes] section store the node hierachy, you separate it from the Node's data. The NumNodes value allows you to use a for-next loop to read each node

eg
for t := 1 to numnodes do
  ReadString('Nodes','Node' + IntToStr(t),'') (whatever !)

Once you have read each nodes value from the [Nodes] section, it can be parsed easily using the Pos function (I use tildes, as I've never seent them used anywhere) to determin it's full 'path', and created in the correct place. Also the Node1, Node2 variables can be used as the SECTION heading to read the additional data for each node.

Hope this helps, If you want code examples, just ask.




     
0
 

Author Comment

by:Psylord
Comment Utility
Someone get me a fire extinguisher! My brain's on fire!
(Evaluating response)
0
 

Expert Comment

by:QuazzeMan
Comment Utility
First use < > to separate the things in the ini file, like :

[<Main Folder> <Sub Folder> <Site>]
Option1=1
Option2=2

The do this :

Uses IniFiles;

Procedure LoadAccounts;
Var F    : TextFile;
    Root : TTreeNode;
    Item : TTreeNode;
    Str,
    Str2 : String;
Begin
 AssignFile(F, 'yourini.ini');
 Reset(F);

 Root := TTreeNode.Create(TreeView1);
 
 While NOT EOF(F) Do Begin
  ReadLn(F,Str);
  If Copy(Str,1,1) = '[' Then Begin
   Str2 := Copy(Str, Pos('<',Str)+1, Length(Str));
   TreeView1.Items.Add(Root, Str2);
   Str := Copy(Str, Pos('>',Str)+1, Length(Str));

   While Pos('>',Str) <> 0 Do Begin
    Str2 := Copy(Str,Pos('<',Str)+1, Length(Str));
    Str2 := Copy(Str2, 1, Pos('>',Str2)-1);
    Str := Copy(Str, Pos('>',Str)+1, Length(Str));

    Item := TTreeNode.Create(TreeView1);
    TreeView1.Items.AddChild(Root, Str2);
   End;
  End;
 End;
 CloseFile(F);
End;

Im in a hurry so ill write the get selected thinge in
some hours ...

later / Tommy
0
 

Author Comment

by:Psylord
Comment Utility
Well... Good effort QuazzeMan...
BUt besides the fact that I get numerous errors when trying to implement your code... I find mullet_attack's answer more interesting...

mullet_attack, I would indeed like to see an elaboration on this code... If you're willing that is.. I can get more specific on the items I'm saving if that helps. Lemme know what you think. This is quite advanced stuff to me as I am relativly new to Delphi still. :/

I really wish I could up the points.

-Psy
0
 
LVL 2

Accepted Solution

by:
mullet_attack earned 25 total points
Comment Utility
PsyLord,

here's a demo. It's a form with 3 buttons - SaveTree, LoadTree, and Clear Tree, and one Treeview. Add Some nodes to the tree at design time, just to play with, and press the buttons !

BTW, why don't you just use Treeview.SaveTofile?

Mark

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, IniFiles, StdCtrls;

type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    btnSaveTree: TButton;
    btnLoadTree: TButton;
    btnClearTree: TButton;
    procedure btnSaveTreeClick(Sender: TObject);
    procedure btnClearTreeClick(Sender: TObject);
    procedure btnLoadTreeClick(Sender: TObject);
  private
    procedure WriteToIniFile(Node : TTreeNode ; Num : integer);
    function GetNodePath(Node : TTreeNode) : string;
    function GetNumNodes : integer;
    procedure ReadAndCreateNodes(num : integer);
    procedure CreateNode(Nodename : string);
    function FindNode(ParentNode : TTreeNode ; NodeName : string) : TTreeNode;
    function GetFirstNodeName(var NodeName : string) : string;
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.btnSaveTreeClick(Sender: TObject);
var
  t : integer;
  aNode : TTreeNode;
begin
  for t := 0 to Treeview1.items.Count -1 do
    WriteToIniFile(TreeView1.items[t], t);
end;

function TForm1.GetNodePath(Node: TTreeNode): string;
// get the full path of a node, and return as string like 'node1~node2~node3'
var
  tempNode : TTreeNode;
begin
  tempNode := Node;
  result := '';
  with tempNode as TTreeNode do
    begin
      while tempNode.AbsoluteIndex <> 0 do
        begin
          result := '~' + tempnode.text + result;
          tempNode := tempNode.Parent;
        end;
      result := tempnode.text + result;
    end;
end;

procedure TForm1.WriteToIniFile(Node: TTreeNode; Num : integer);
// write each nodes path and data to the inifile
var
 IniFile : TIniFile;
begin
  with Node as TTreeNode do
    begin
      try
        IniFile := TIniFile.create('MyNodes.ini');
        IniFile.WriteString('Nodes', 'Node' + IntToStr(num),GetNodePath(Node));
        IniFile.WriteInteger('Nodes', 'NumNodes',Num);
        IniFile.WriteString('Node' + IntToStr(num),'Option1','Value1');
      finally
        IniFile.free;
      end;
    end;
end;

procedure TForm1.btnClearTreeClick(Sender: TObject);
begin
  treeview1.items.clear;
end;

procedure TForm1.btnLoadTreeClick(Sender: TObject);
// read all nodes from the inifile
var
  NumNodes : integer;
  t : integer;
begin
  NumNodes := GetNumNodes;
  for t := 0 to NumNodes do
    ReadAndCreateNodes(t);
end;

function TForm1.GetNumNodes: integer;
var
  IniFile : TIniFile;
begin
  result := 0;
  try
    IniFile := TIniFile.create('MyNodes.ini');
    result := IniFile.ReadInteger('Nodes', 'NumNodes', 0);
  finally
    IniFile.free;
  end;
end;

procedure TForm1.ReadAndCreateNodes(num: integer);
// read each entry from the inifile and create each node
var
  IniFile : TIniFile;
  NodeName : string;
  NodeOption : string;
begin
  try
    IniFile := TIniFile.create('MyNodes.ini');
    NodeName := IniFile.ReadString('Nodes', 'Node' + IntToStr(num), '');
    Nodeoption := IniFile.ReadString('Node' + IntToStr(num),'Option1', '');
    CreateNode(NodeName);
  finally
    IniFile.free;
  end;
end;

procedure TForm1.CreateNode(Nodename: string);
// create the nodes at the proper place, based on it's fullpath in NodeName
var
  temp : string;
  NodeText : string;
  FoundNode : TTreeNode;
  ParentNode : TTreeNode;
begin
  temp := NodeName;
  ParentNode := nil;
  while temp <> '' do
    begin
      NodeText := GetFirstNodeName(temp);
      FoundNode := FindNode(ParentNode,NodeText);
      if FoundNode = nil then
        ParentNode := TreeView1.items.AddChild(ParentNode,NodeText)
      else
        ParentNode := FoundNode;
    end;
end;

function TForm1.FindNode(ParentNode : TTreeNode ; NodeName: string): TTreeNode;
// find a particular node by name, checking the parent is the correct one
// this allows sub nodes to have the same name (different parents)
var
  t : integer;
begin
  for t := 0 to Treeview1.items.count -1 do
    if ((TTreenode(treeview1.items[t]).text = NodeName) and
     (TTreenode(treeview1.items[t]).HasAsParent(ParentNode))) then
      begin
        result := treeview1.items[t];
        exit;
      end;
  result := nil;
end;

function TForm1.GetFirstNodeName(var NodeName: string): string;
// returns the first node name from the fullpath, and also removes
// the first node name from the full path
// eg enter with Node1~Node2~Node3, and exit with result := Node1 and
// NodeName := Node2~Node3
begin
  if pos('~',NodeName) > 0 then
    begin
      result := Copy(NodeName,1,Pos('~',NodeName)-1);
      NodeName := Copy(NodeName,Pos('~',NodeName) + 1, length(NodeName) - Pos('~',NodeName));
    end
  else
    begin
      result := NodeName;
      NodeName := '';
    end;
end;

end.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Expert Comment

by:QuazzeMan
Comment Utility
hehe just tried to help, wrote it in
a hurry without delphi so i couldnt
check the code, had to catch a bus.

Well it seems mullet_attack coverd it
all =) good.

Later / Tommy
0
 

Author Comment

by:Psylord
Comment Utility
mullet_attack!

That's some great coding...
This will be a great account manager! :D

I'm gonna go ahead an d give you the points now... Even though I may have some more questions in the future.

If that's ok with you. :)~

-Psylord
0
 

Author Comment

by:Psylord
Comment Utility
Adjusted points from 20 to 25
0
 

Author Comment

by:Psylord
Comment Utility
mullet_attack,
I've added the code to my application and changed what needs changing (names mostly)...

Now I'm ready to start adding sites and folders. Forgive me if I should already understand this, but at runtime... If I add what is supposed to be a folder... How can I tell that it's a folder and not a site label? This is relevant to the icons I will add to the different items...

Will it be that folders just don't have any data? Oh! there goes my brain starting to hurt again.
0
 

Author Comment

by:Psylord
Comment Utility
Strike that last question from the record. I wasn't paying attention. Sorry about that. :)
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now