Solved

Hard Work With Ini's - For the motherload.

Posted on 2000-05-01
10
221 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
ID: 2768157
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
ID: 2768166
Someone get me a fire extinguisher! My brain's on fire!
(Evaluating response)
0
 

Expert Comment

by:QuazzeMan
ID: 2768172
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
Active Directory Webinar

We all know we need to protect and secure our privileges, but where to start? Join Experts Exchange and ManageEngine on Tuesday, April 11, 2017 10:00 AM PDT to learn how to track and secure privileged users in Active Directory.

 

Author Comment

by:Psylord
ID: 2768253
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
ID: 2768511
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
 

Expert Comment

by:QuazzeMan
ID: 2769791
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
ID: 2770860
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
ID: 2770865
Adjusted points from 20 to 25
0
 

Author Comment

by:Psylord
ID: 2771125
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
ID: 2771209
Strike that last question from the record. I wasn't paying attention. Sorry about that. :)
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
A short tutorial showing how to set up an email signature in Outlook on the Web (previously known as OWA). For free email signatures designs, visit https://www.mail-signatures.com/articles/signature-templates/?sts=6651 If you want to manage em…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

830 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