Recent

Author Topic: TIPEdit - Component for entering IP Addresses  (Read 3931 times)

bobby100

  • Full Member
  • ***
  • Posts: 164
    • Malzilla
Re: TIPEdit - Component for entering IP Addresses
« Reply #15 on: April 02, 2022, 12:13:23 pm »
btw. did I found a bug in TStringHelper.Replace, or I didn't understand the documentation:
https://www.freepascal.org/docs-html/rtl/sysutils/tstringhelper.replace.html
Quote
If rfReplaceAll is in the ReplaceFlags, then all occurrences will be replaced, otherwise only the first occurrence is replaced.
If I use the form TStringHelper.Replace(OldChar, NewChar), without specifying any flags - all occurrences will be replaced.
I need to use TStringHelper.Replace(OldChar, NewChar, []) to get just the first occurrence replaced.
https://gitlab.com/bobby100 - my Lazarus components and units
https://sourceforge.net/u/boban_spasic/profile/ - my open source apps

https://malzilla.org/ - remainder at my previous life as a web security expert

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: TIPEdit - Component for entering IP Addresses
« Reply #16 on: April 02, 2022, 02:33:54 pm »
Doesn't this go wrong:
Code: Pascal  [Select][+][-]
  1.     tmp := tmp.Replace('0:0:', '::', []);
  2.  

If at that time tmp = 'f0:0:0:0:5:6:7:8' it will change tmp into  'f:0:0:0:5:6:7:8', which is an entirely different address.

Bart

bobby100

  • Full Member
  • ***
  • Posts: 164
    • Malzilla
Re: TIPEdit - Component for entering IP Addresses
« Reply #17 on: April 02, 2022, 02:53:24 pm »
Yup, it will go wrong. I need to rethink this one.

Update: I think I got it right this time, see attachment
« Last Edit: April 02, 2022, 03:03:38 pm by bobby100 »
https://gitlab.com/bobby100 - my Lazarus components and units
https://sourceforge.net/u/boban_spasic/profile/ - my open source apps

https://malzilla.org/ - remainder at my previous life as a web security expert

AlexTP

  • Hero Member
  • *****
  • Posts: 2402
    • UVviewsoft
Re: TIPEdit - Component for entering IP Addresses
« Reply #18 on: April 02, 2022, 05:00:19 pm »
Why not to upload it to Github? You won't need to use Git. Just register on site, and use Web UI to upload files (in browser).

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: TIPEdit - Component for entering IP Addresses
« Reply #19 on: April 02, 2022, 05:02:27 pm »
I came up with a similar construction:
Code: Pascal  [Select][+][-]
  1.         begin
  2.           Result := format('%4x:%4x:%4x:%4x:%4x:%4x:%4x:%4x',[H[1],H[2],H[3],H[4],H[5],H[6],H[7],H[8]]);
  3.           Result := LowerCase(Result);
  4.           for i := 8 downto 2 do
  5.           begin
  6.             Pattern := DupeString('   0:', i);
  7.             SetLength(Pattern, Length(Pattern)-1);   //remove last colon
  8.             if (Pos(Pattern, Result) > 0) then
  9.             begin
  10.               Result := StringReplace(Result, Pattern, ':', []);
  11.               Break;
  12.             end;
  13.           end;
  14.           Result := StringReplace(Result, #32, '', [rfReplaceAll]);
  15.           Result := StringReplace(Result, ':::','::', []);
  16.           if Result = ':' then //happens if everything is zero
  17.             Result := '::';
  18.         end;

Now at http://svn.code.sf.net/p/flyingsheep/code/trunk/MijnLib/ipedit.pp (renamed it).

Bart
« Last Edit: April 02, 2022, 05:21:22 pm by Bart »

bobby100

  • Full Member
  • ***
  • Posts: 164
    • Malzilla
Re: TIPEdit - Component for entering IP Addresses
« Reply #20 on: April 02, 2022, 05:30:03 pm »
Why not to upload it to Github? You won't need to use Git. Just register on site, and use Web UI to upload files (in browser).
https://gitlab.com/bobby100

I need to update my profile


@Bart
will you also make it as installable component?
https://gitlab.com/bobby100 - my Lazarus components and units
https://sourceforge.net/u/boban_spasic/profile/ - my open source apps

https://malzilla.org/ - remainder at my previous life as a web security expert

AlexTP

  • Hero Member
  • *****
  • Posts: 2402
    • UVviewsoft
Re: TIPEdit - Component for entering IP Addresses
« Reply #21 on: April 02, 2022, 05:32:09 pm »
@bobby100,
On the GitLab, I don't see the repo- "This user doesn't have any personal projects".

bobby100

  • Full Member
  • ***
  • Posts: 164
    • Malzilla
Re: TIPEdit - Component for entering IP Addresses
« Reply #22 on: April 02, 2022, 05:51:39 pm »
Sorry, forgot to set the visibility to public. It should be visible now
https://gitlab.com/bobby100 - my Lazarus components and units
https://sourceforge.net/u/boban_spasic/profile/ - my open source apps

https://malzilla.org/ - remainder at my previous life as a web security expert

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: TIPEdit - Component for entering IP Addresses
« Reply #23 on: April 02, 2022, 09:57:06 pm »
@Bart
will you also make it as installable component?

To be quite honest, I never did that before.
I'm just too laxy to find out how to and make all the icons for my components.
Mostly I just create them at runtime.

Feel free however to add this (or other components of mine) to you own private package file.

I also added a function to parse IPV6 as strings (it'll convert '1::8' into '0001:0000:0000:0000:0000:0000:0000:0008').
Might be an idea to have that as a class function.

Bart
« Last Edit: April 02, 2022, 10:01:56 pm by Bart »

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: TIPEdit - Component for entering IP Addresses
« Reply #24 on: April 03, 2022, 08:03:24 pm »
I moved all IP String parsing routines to a separate FsiIpStrings unit.
It contains:
Code: Pascal  [Select][+][-]
  1. function OctetsAreValid(O: TIntOctets): Boolean;
  2. function HextetsAreValid(H: TIntHextets): Boolean;
  3.  
  4. function DWordToIPV4String(AValue: DWord): String;
  5. function TryParseIPV4String(AValue: String; out O: TIntOctets): Boolean;
  6. function TryParseIPV4String(AValue: String; out D: DWord): Boolean;
  7. function TryParseIPV4String(AValue: String; out IPString: String): Boolean;
  8.  
  9. function TryParseIPV6String(AValue: String; out IPString: String; ToLowerCase: Boolean = True): Boolean;
  10. function TryParseIPV6String(AValue: String; out H: TIntHextets): Boolean;
  11.  
  12. function HextetsToShorthandIPV6String(H: TIntHextets): String;
  13. function TryIpV6StringToShortHand(AValue: String; out IPString: String): Boolean;

Renamed the IpEdit unit to FsiIpEdit, just for consistency with my other libraries.

Bart
« Last Edit: April 03, 2022, 10:16:46 pm by Bart »

AlexTP

  • Hero Member
  • *****
  • Posts: 2402
    • UVviewsoft
Re: TIPEdit - Component for entering IP Addresses
« Reply #25 on: April 03, 2022, 08:39:35 pm »
>Renamed the IpEdit unit to FsiIpEdit,
Broken link.

Bart

  • Hero Member
  • *****
  • Posts: 5290
    • Bart en Mariska's Webstek
Re: TIPEdit - Component for entering IP Addresses
« Reply #26 on: April 03, 2022, 10:17:35 pm »
>Renamed the IpEdit unit to FsiIpEdit,
Broken link.
Fixed (in post #24).
Thanks.

Bart

BSaidus

  • Hero Member
  • *****
  • Posts: 545
  • lazarus 1.8.4 Win8.1 / cross FreeBSD
Re: TIPEdit - Component for entering IP Addresses
« Reply #27 on: December 19, 2023, 11:11:07 pm »
@bobby100
Hello.
Thank you for this wonderful component.
I wonder if you can implement a database oriented IPEdit (TDBIPEdit).
I attache this simple implementation of the DB oriented IPEdit ( but not completed), if someone can help.
Code: Pascal  [Select][+][-]
  1. {
  2.  *****************************************************************************
  3.   See the file COPYING.modifiedLGPL.txt, included in this distribution,
  4.   for details about the license.
  5.  *****************************************************************************
  6.  
  7.  Author: Boban Spasic
  8.  
  9. }
  10.  
  11. unit DBIPEdit;
  12.  
  13. interface
  14.  
  15. uses
  16.   SysUtils, Classes, Controls, StdCtrls, LResources, LCLType, StrUtils, DBCtrls,
  17.   Db, LMessages, IPEdit
  18. ;
  19.  
  20. type
  21.   { TDBIPEdit }
  22.  
  23.   TDBIPEdit = class (TIPEdit)
  24.   private
  25.     FDataLink: TFieldDataLink;
  26.     FFocusedDisplay: boolean;
  27.     procedure DataChange(Sender: TObject);
  28.     procedure UpdateData(Sender: TObject);
  29.     function GetDataField: string;
  30.     function GetDataSource: TDataSource;
  31.     function GetField: TField;
  32.     procedure SetDataField(AValue: string);
  33.     procedure SetDataSource(AValue: TDataSource);
  34.     procedure CMGetDataLink(var Message: TLMessage); message CM_GETDATALINK;
  35.  
  36.   protected
  37.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  38.  
  39.     procedure WMSetFocus(var Message: TLMSetFocus); message LM_SETFOCUS;
  40.     procedure WMKillFocus(var Message: TLMKillFocus); message LM_KILLFOCUS;
  41.     procedure WndProc(var Message: TLMessage); override;
  42.   public
  43.     constructor Create(AOwner: TComponent); override;
  44.     destructor Destroy(); override;
  45.     function ExecuteAction(AAction: TBasicAction): Boolean; override;
  46.     function UpdateAction(AAction: TBasicAction): Boolean; override;
  47.     property Field: TField read GetField;
  48.   published
  49.     property DataField: string read GetDataField write SetDataField;
  50.     property DataSource: TDataSource read GetDataSource write SetDataSource;
  51.   end;  
  52.  
  53. procedure Register;
  54.  
  55. implementation
  56.  
  57. procedure Register;
  58. begin
  59.   RegisterComponents('Misc', [TIPEdit]);
  60.   {.$I ipedit.lrs}
  61. end;
  62.  
  63. { TDBIPEdit }
  64.  
  65. function TDBIPEdit.GetDataField(): string;
  66. begin
  67.   Result := FDataLink.FieldName;
  68. end;
  69.  
  70. function TDBIPEdit.GetDataSource(): TDataSource;
  71. begin
  72.   Result := FDataLink.DataSource;
  73. end;
  74.  
  75. function TDBIPEdit.GetField(): TField;
  76. begin
  77.   Result := FDataLink.Field;
  78. end;
  79.  
  80. procedure TDBIPEdit.SetDataField(AValue: string);
  81. begin
  82.   FDataLink.FieldName := AValue;
  83. end;
  84.  
  85. procedure TDBIPEdit.SetDataSource(AValue: TDataSource);
  86. begin
  87.   ChangeDataSource(Self,FDataLink,AValue);
  88. end;
  89.  
  90. procedure TDBIPEdit.CMGetDataLink(var Message: TLMessage);
  91. begin
  92.   Message.Result := PtrUInt(FDataLink);
  93. end;
  94.  
  95. //update the caption on next record etc...
  96. procedure TDBIPEdit.DataChange(Sender: TObject);
  97. var
  98.   DataLinkField: TField;
  99. begin
  100.   DataLinkField := FDataLink.Field;
  101.   if DataLinkField <> nil then begin
  102.     Alignment := DataLinkField.Alignment;
  103.     if FDatalink.CanModify then
  104.     begin
  105.       Text := DatalinkField.Text;
  106.     end;
  107.  
  108.     if (DataLinkField.DataType in [ftString, ftFixedChar, ftWidestring, ftFixedWideChar]) and (MaxLength = 0) then
  109.     begin
  110.       MaxLength := DatalinkField.Size;
  111.     end;
  112.   end
  113.   else
  114.   begin
  115.     Text := '';
  116.     MaxLength := 0;
  117.   end;
  118.  
  119.   Inherited EditingDone;
  120.  
  121. end;
  122.  
  123. procedure TDBIPEdit.UpdateData(Sender: TObject);
  124. begin
  125.   //the field is being updated, probably for post
  126.   //so we are getting called to make sure its
  127.   //up-to-date and matches any modifications
  128.   //since its possible to have a mask for say
  129.   //date or currency we need to make sure the
  130.   //text is valid before we update this is in
  131.   //case for instance they call table.post via
  132.   //a keyboard shortcut while still focused, before
  133.   //the changes have been validated
  134.   EditingDone();
  135.   FDataLink.Field.Text := Text;
  136. end;
  137.  
  138. procedure TDBIPEdit.Notification(AComponent: TComponent; Operation: TOperation);
  139. begin
  140.   inherited Notification(AComponent, Operation);
  141.   // if the datasource is being removed then we need to make sure
  142.   // we are updated or we can get AV/Seg's *cough* as I foolishly
  143.   // discovered firsthand....
  144.   if (Operation=opRemove) then begin
  145.     if (FDataLink<>nil) and (AComponent=DataSource) then
  146.       DataSource:=nil;
  147.   end;
  148. end;
  149.  
  150. procedure TDBIPEdit.WMSetFocus(var Message: TLMSetFocus);
  151. var
  152.   EditOnFocus: Boolean;
  153. begin
  154.   // update text before inherited so DoEnter has the new text
  155.   if not FFocusedDisplay then
  156.   begin
  157.      FDataLink.Reset;
  158.   end;
  159.   inherited WMSetFocus(Message);
  160. end;
  161.  
  162. procedure TDBIPEdit.WMKillFocus(var Message: TLMKillFocus);
  163. begin
  164.   inherited WMKillFocus(Message);
  165.    FFocusedDisplay := False;
  166.    if csDestroying in ComponentState then Exit;
  167.    if FDatalink.Editing then
  168.    begin
  169.      FDatalink.UpdateRecord;
  170.      //check for Focused before disabling the mask since SetFocus can be called
  171.      //inside events propagated by WMKillFocus or UpdateRecord
  172.      if not Focused then
  173.      begin
  174.        //DisableMask(FDataLink.Field.DisplayText);
  175.        FDataLink.Field.DisplayText;
  176.        //reset the modified flag that is changed after setting the text
  177.        FDataLink.Reset; //IsModified := False;
  178.      end;
  179.    end
  180.    else
  181.      FDatalink.Reset;
  182. end;
  183.  
  184. procedure TDBIPEdit.WndProc(var Message: TLMessage);
  185. begin
  186.   case Message.Msg of
  187.     LM_CLEAR,
  188.     LM_CUT,
  189.     LM_PASTE:
  190.       begin
  191.         if FDataLink.CanModify then
  192.         begin
  193.           //LCL changes the Text before LM_PASTE is called and not after like Delphi. Issue 20330
  194.           //When Edit is called the Text property is reset to the previous value
  195.           //Add a workaround while bug is not fixed
  196.           FDataLink.OnDataChange := nil;
  197.           FDatalink.Edit;
  198.           FDataLink.Modified;
  199.           FDataLink.OnDataChange := @DataChange;
  200.           inherited WndProc(Message);
  201.         end
  202.         else
  203.           Message.Result := 1; // prevent calling default window proc
  204.       end;
  205.     else
  206.       inherited WndProc(Message);
  207.   end;
  208. end;
  209.  
  210. constructor TDBIPEdit.Create(AOwner: TComponent);
  211. begin
  212.   inherited Create(AOwner);
  213.   FDataLink := TFieldDataLink.Create;
  214.   FDataLink.Control := Self;
  215.   FDataLink.OnDataChange := @DataChange;
  216.   FDataLink.OnUpdateData := @UpdateData;
  217. end;
  218.  
  219. destructor TDBIPEdit.Destroy;
  220. begin
  221.   FDataLink.Destroy;
  222.   inherited Destroy;
  223. end;
  224.  
  225. function TDBIPEdit.ExecuteAction(AAction: TBasicAction): Boolean;
  226. begin
  227.   Result := inherited ExecuteAction(AAction) or
  228.             (FDataLink <> nil) and FDataLink.ExecuteAction(AAction);
  229. end;
  230.  
  231. function TDBIPEdit.UpdateAction(AAction: TBasicAction): Boolean;
  232. begin
  233.   Result := inherited UpdateAction(AAction) or
  234.             (FDataLink <> nil) and FDataLink.UpdateAction(AAction);
  235. end;
  236.  
  237.  
  238. end.
  239.  
  240.  
Thank you.
« Last Edit: December 19, 2023, 11:29:11 pm by BSaidus »
lazarus 1.8.4 Win8.1 / cross FreeBSD
dhukmucmur vernadh!

 

TinyPortal © 2005-2018