We help IT Professionals succeed at work.

Virtuailstring tree compare node issue

drama22
drama22 used Ask the Experts™
on
in my previous question i asked for the same question that i am asking now

https://www.experts-exchange.com/questions/28943546/how-do-i-use-on-compare-node-correctly-in-TVirtualStringTree.html

thats my old question. sadly answers did not solve the main issue i have

here is the current code

procedure Tform1.VDT1CompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
Data1, Data2: PUserData;
begin
Data1 := VDT1.GetNodeData(Node1);
Data2 := VDT1.GetNodeData(Node2);

      if (not Assigned(Data1)) or (not Assigned(Data2)) then
      begin //
        Result := 0;
        exit;
      end;


      //hand check  less than

      if (Data1.FObject.Userhand < Data2.FObject.Userhand) and (istalkon=True) then
      begin
        Result := -1;
        memo1.Lines.Add('is old date');
      end
      else
      if (Data1.FObject.Userhand < Data2.FObject.Userhand) and (istalkon=False) then
      begin
      Result := 1;
      end else

       // hand check greater than
      if (Data1.FObject.Userhand > Data2.FObject.Userhand) and (istalkon=True) then
      begin
        Result := -1;
        memo1.Lines.Add('is New date');
      end
      else
      if (Data1.FObject.Userhand > Data2.FObject.Userhand) and (istalkon=False) then
      begin
      Result := 1;
      end else

      //hand check  less than

      if (Data2.FObject.Userhand < Data1.FObject.Userhand) and (istalkon=True) then
      begin
        Result := -1;
        memo1.Lines.Add('is older date');
      end
      else
      if (Data2.FObject.Userhand < Data1.FObject.Userhand) and (istalkon=False) then
      begin
      Result := 1;
      end else
     //end


      if Data1.FObject.istalking = Data2.FObject.istalking then
      begin
        Result := CompareStr(Data1.FObject.Username, Data2.FObject.Username);
      end
      else

        if Data1.FObject.istalking < Data2.FObject.istalking then
      begin
        Result := 1;
      end
      else if Data2.FObject.istalking > Data1.FObject.istalking then
      begin
        Result := 1;
      end; { else

        Result := CompareStr(Data1.FObject.username, Data2.FObject.username); }
    end;

Open in new window


my application have students that allow them to chat with each others

Student A when he is talking he become at the top of VTS like his node become first
Student B when he raise his hand he should come first if no students talking else he should come second and other users comes under the user who raise his hand . if 2 student raise there hands they already have record as time and date that set To now

so student with older date should come First and student with newer date  should come second and so on .. i couldnt make this in coding and other answers did not help to solve this certain issue hope to find one here
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Sinisa VukSoftware architect
Top Expert 2012

Commented:
I would go with this ....
function Tform1.UserTalking(Data: PUserData): Boolean;
begin
  Result := False;
  //implement rest here ....
end;

function Tform1.UserRaiseAHand(Data: PUserData): Boolean;
begin
  Result := False;
  //implement rest here ....
end;

function Tform1.CheckUserTalking(Data1, Data2: PUserData): Integer;
begin
  Result := 0; //both users talking or not talking
  if UserTalking(Data1) and (not UserTalking(Data2)) then Result := -1 //push user 1 to top
  else if (not UserTalking(Data1)) and UserTalking(Data2) then Result := 1; //push user 1 to down
end;

function Tform1.CheckRaiseAHand(Data1, Data2: PUserData): Integer;
begin
  Result := 0; 
  if UserRaiseAHand(Data1) and UserRaiseAHand(Data2) then 
  begin
     //both raise - chk time
     if Data1.Userhand<Data2.Userhand then Result := -1 //push user 1 to top
     else Result := 1; //push user 1 to down
  end
  else if UserRaiseAHand(Data1) then Result := -1 //push user 1 to top
  else if UserRaiseAHand(Data2) then Result := 1; //push user 1 to down
end;

procedure Tform1.VDT1CompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
Data1, Data2: PUserData;
begin
  Result := 0;
  Data1 := VDT1.GetNodeData(Node1);
  Data2 := VDT1.GetNodeData(Node2);

      if (not Assigned(Data1)) or (not Assigned(Data2)) then
      begin //
        Result := 0;
        exit;
      end;
     
      // check if talking...
     Result := CheckUserTalking(Data1, Data2);
     //no-one or both talking...
     if Result = 0 then
     begin
        //check hands
        Result :=CheckRaiseAHand(Data1, Data2);
     end;
     //when both equal in a state
     if Result = 0 then
     begin
        //check user name
         Result := CompareStr(Data1.FObject.Username, Data2.FObject.Username);
     end;
      
end;

Open in new window


... check comments in code
You need to implement functions UserTalking and UserRaiseAHand to suit your internal logic
(when user is talking and when raise a hand)
Top Expert 2016

Commented:
if (Data1.FObject.IsTalking = True) then Result:=-1;
else if (Data2.FObject.IsTalking = True) then Result:=1;
else if (Data1.FObject.RaisedHand = True)  and (Data2.FObject.RaisedHand = False) then Result:=-1;
else if (Data2.FObject.RaisedHand = True)  and (Data2.FObject.RaisedHand = True) then Result:=1;
else 
begin
    if (Data1.FObject.RaisedHand = True) then  
    begin
          Result:=CompareDateTime(Data1.FObject.TimeRaisedHand, Data2.FObject.TimeRaisedHand);
    end
    else
    begin
          Result:=CompareDateTime(Data1.FObject.TimeEnteredChat, Data2.FObject.TimeEnteredChat);
    end
end
....

Open in new window



this code would work if

- IsTalking and RaisedHand are boolean type
- IsTalking only is true for 1 Student at a time
- you have timestamps for each node taken when they entered the chat and when they raised hand
- there is a compare function for date/time which returns -1,0,1(same as CompareStr.

note, if the date/time compare function is missing, you may convert the timestamps to strings or numbers and compare those.

Sara

Author

Commented:
Sinisa the code about this issue have mestrey

you gives me the answer but with another question

  //implement rest here .... what i should to implement i dont get the way to compare the time and date so when user hand value equals to Now; which means current date and there is older user hand date  

old Date should comes first newer date should come second . Thats the main issue how to compare time and date like that
Top Expert 2016

Commented:
see

http://www.freepascal.org/docs-html/rtl/dateutils/comparedatetime.html

for a function to compare date/time.

Sara

Author

Commented:
Thanks sara forthat details

Sinisa i am trying to track your code  there is mistakes

if UserTalking(Data1) and (not UserTalking(Data2)) then Result := -1 

Open in new window


-1 do not move node to top ,  instead 1 Do .

i still cannot  get your point of //implement rest here ....

:) this is not helping at all
Sinisa VukSoftware architect
Top Expert 2012

Commented:
Cause I'm writing code from my head :-) there are mistakes.... So, try to replace all Result := -1 with Result := 1  and all Result := 1 with Result := -1
It would be easier/faster if you could make a small test app and post it here (or else with link)... Most people have no time to build an app from scratch....

Author

Commented:
as you requested here is sample project of what goal i want to achieve so i hope got help with the issue

current problem is i could sort node with hands but they could complicate when i try to remove there hands record

compare function is there  every thing implemented ...

https://www.mediafire.com/?6ohkxzr98we6n57

Author

Commented:
current progress work around
procedure Tform1.VDT1CompareNodes(Sender: TBaseVirtualTree;
  Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
  Data1, Data2: PUserData;
begin
  Data1 := VDT1.GetNodeData(Node1);
  Data2 := VDT1.GetNodeData(Node2);

  if (Assigned(Data1)) And (Assigned(Data2)) then
  begin
    // Assign Start

    if Data1.FObject.hand = Data2.FObject.hand then
    begin
      Result := CompareDateTime(Data1.FObject.handTime, Data2.FObject.handTime);
    end
    else
    begin
      // check start
      if Data1.FObject.hand < Data2.FObject.hand then
      begin
        Result := 1;
      end
      else if Data1.FObject.hand > Data2.FObject.hand then
      begin
        Result := -1;
      end
      else
        Result := -1;
    end; // check end

  end;

  // Assign end
end;

Open in new window


hand arranged right but only one issue when new node inserted and surely its hand not set yet the time date compration gets wrong

when new node inserted New date comes First and older date comes second

i wanted new date comes second older date comes first

i solved Talking by adding other list for it .. hope get solve with this issue
Software architect
Top Expert 2012
Commented:
This is what I modified in your example and works for me:
...
procedure TForm2.Button1Click(Sender: TObject);
var
userdataclass: Tuserdataclass;
begin
vts1.NodeDataSize:=SizeOf(TUserData);
Vts1.BeginUpdate;
begin
userdataclass := Tuserdataclass.Create;
userdataclass.username:=edit1.Text;
userdataclass.Timehnd := Now;  //added
userdataclass.hnd := '0';      //added
AddVSTStructure(Vts1,nil,userdataclass);
end;
Vts1.EndUpdate;

Vts1.SortTree(0, sdAscending, false); //added
end;

function TForm2.UserTalking(Data: PUserData): Boolean;
begin
  Result := (Data.FObject.hnd = '2');
end;

function TForm2.UserRaiseAHand(Data: PUserData): Boolean;
begin
  Result := (Data.FObject.hnd = '1');
end;

function TForm2.CheckUserTalking(Data1, Data2: PUserData): Integer;
begin
  Result := 0; //both users talking or not talking
  if UserTalking(Data1) and (not UserTalking(Data2)) then Result := -1 //push user 1 to top
  else if (not UserTalking(Data1)) and UserTalking(Data2) then Result := 1; //push user 1 to down
end;

function TForm2.CheckRaiseAHand(Data1, Data2: PUserData): Integer;
begin
  Result := 0; 
  if UserRaiseAHand(Data1) and UserRaiseAHand(Data2) then 
  begin
     //both raise - chk time
     if Data1.FObject.Timehnd<Data2.FObject.Timehnd then Result := -1 //push user 1 to top
     else Result := 1; //push user 1 to down
  end
  else if UserRaiseAHand(Data1) then Result := -1 //push user 1 to top
  else if UserRaiseAHand(Data2) then Result := 1; //push user 1 to down
end;

procedure TForm2.VTs1CompareNodes(Sender: TBaseVirtualTree; Node1,
  Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
Data1, Data2: PUserData;
Cmp : Integer;
begin
Data1 := VTS1.GetNodeData(Node1);
Data2 := VTS1.GetNodeData(Node2);

if (Assigned(Data1)) And (Assigned(Data2)) then
begin

 // check if talking...
     Result := CheckUserTalking(Data1, Data2);
     //no-one or both talking...
     if Result = 0 then
     begin
        //check hands
        Result :=CheckRaiseAHand(Data1, Data2);
     end;
     //when both equal in a state
     if Result = 0 then
     begin
        //check user name
         Result := CompareStr(Data1.FObject.Username, Data2.FObject.Username);
     end;
end;

Open in new window


additionally add new Talk button:
procedure TForm2.Button3Click(Sender: TObject);
var
Node: PVirtualNode;
Data: PUserData;
begin
Node := lookingTreeView(edit2.Text);

if (Node <> nil) then
begin
Data := VTS1.GetNodeData(Node);

Data.FObject.hnd := '2';
Data.FObject.Timehnd := Now;
end;

Vts1.SortTree(0, sdAscending, false);
end;

Open in new window


Almost not touch my original code...Do some initialization of FObject which is essential because you use this values in compare routine...

Author

Commented:
the issue is  when both node has there hands raised and new node added the  other nodes with raised hands gets wrong position see image for understanding

image issue
Top Expert 2016

Commented:
if Data1.FObject.hand = Data2.FObject.hand then
if Data1.FObject.hand < Data2.FObject.hand then

i don't think that integer values for 'hand' can be used in a senseful way to solve the issues. 'raised hand' surely is a boolean; either a student had raised their hand, or not. which meaning could an integer haved to 'add' more information?

when new node inserted and surely its hand not set yet the time date compration gets wrong

that is not true. you definitively should set all values for new nodes such that they could be sorted well, same as existing nodes.

the issue is  when both node has there hands raised and new node added the  other nodes with raised hands gets wrong position
why should they? if addding a new node, you have to decide whether 'hand' is raised or not. if not, it comes after all nodes with hands raised up, and comparision result with nodes that also don't  have 'hands raised' needed to be computed by comparing timestamps.


assuming the tree is sorted in ascending order. then, if left node should be above of right node, comparision result is -1, else it is +1. so, if you want the new one to come first and hands are not raised, you should return -1 if the left node is the new one and the right one hasn't hands raised up. you would get this result by comparing timestamps of both nodes, BUT, you have to exchange left and right timestamp, since the new node will have a younger timestamp.

if you want new ones to have automatically hands raised up, then you have to set 'hands raised' to true and assign current time to the hands timestamp. again, if left node and right node have different hands state, return -1, if left has hands raied up, else +1. if both hands are raised compare the hands timestamp and since oler hands should be first, pass left node hand timestamp as first argument and right node hand timestamp as second. tzhat way older timestamps would be first.

Sara
Sinisa VukSoftware architect
Top Expert 2012

Commented:
I see that second user named addra as second goes to first place in front of ameer. This is not issue with my code. Did you try it put all together... Must be something in your second/other code...
As I noticed - always initialize all FObject settings (state (as hand down), handtime as Now,... )

Author

Commented:
I think I should set user hand in server side.
Currently I was sending hand requests each time new client arrived
Sinisa VukSoftware architect
Top Expert 2012

Commented:
Initialize with hand down (on server side), and after user request... set hand up...