MisUtils.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. {
  2. MisUtils 0.6
  3. ============
  4. Por Tito Hinostroza 06/02/2017
  5. * Se agrega la función LoadPNGToImageList()
  6. * Se agrega la función AddStringToFile().
  7. * Se agrega una versión simple el método Join().
  8. MisUtils 0.5b
  9. ============
  10. Por Tito Hinostroza 13/05/2015
  11. * Se agregan las funciones DT2Number() and Number2DT().
  12. * Se agrega la función StringLike().
  13. * Se elimina la variable global msjError, ya que se encontró casos de duplicidad de
  14. nombre con la variable de error global de la aplicación. Además se está evitando usar
  15. variables globales.
  16. * Se agrega la función TrimEndLine() para quitar un salto de línea al final de una
  17. cadena.
  18. * Se modifica f2N, para fijar siempre el punto decimal como ".".
  19. * Se modifica f2S(), proque se detectó problemas en Win32.
  20. Descripción
  21. ============
  22. Librería de funciones útiles para mostrar mensajes en pantalla, para guardar datos en
  23. archivos, para crear aplicaciones en varios idiomas y algunas utilidades adicionales.
  24. }
  25. unit MisUtils;
  26. {$mode objfpc}{$H+}
  27. interface
  28. uses Classes, SysUtils, Forms, Graphics, Dialogs, process, Controls, lclType,
  29. LazFileUtils, Masks, types, dateutils, strutils, Menus, LCLProc, LCLIntf;
  30. var
  31. // msjError : string; //mensaje de error de la aplicación
  32. dictionary: TstringList; //diccionario para el manejo de mensajes
  33. TranslateMsgs: boolean; //activa la traducción del mensaje
  34. //funciones para mostrar mensajes
  35. procedure MsgExc(txt: string; Caption: string = '');
  36. procedure MsgExc(Fmt: String; const Args: array of const);
  37. procedure MsgErr(txt: string; Caption: string = '');
  38. procedure MsgErr(Fmt: String; const Args: array of const);
  39. //function MsgBox(txt: PChar; Caption: string = ''; flags: longint = 0): integer;
  40. function MsgBox(txt: String; Caption: string = ''; flags: longint = 0): integer;
  41. procedure MsgBox(Fmt : String; const Args : Array of const);
  42. function MsgYesNo(txt: string): byte;
  43. function MsgYesNo(Fmt: string; const Args: array of const): byte;
  44. function MsgYesNoCancel(txt: string): byte;
  45. function MsgYesNoCancel(Fmt: string; const Args: array of const): byte;
  46. //funciones diversas
  47. function Explode(delimiter:string; str:string):TStringDynArray;
  48. function Join(delimiter: char; const a: TStringDynArray): string;
  49. function Exec(com, par: string; WaitOnExit: boolean = false): boolean;
  50. procedure AnchorTo(Ctl: TControl; Side: TAnchorKind; Sibling: TControl;
  51. Space: integer = 0; Internal: Boolean = false);
  52. procedure TrimEndLine(var cad: string);
  53. function StringLike(const str: string; mask: string): boolean;
  54. procedure StringToFile(const s: string; const FileName: string);
  55. function StringFromFile(const FileName: string): string;
  56. function AddStringToFile(txt: string; const FileName: string): boolean;
  57. //Utilidades para menús
  58. function AddItemToMenu(menu: TMenuItem; txt: string; evento: TNotifyEvent): TMenuItem;
  59. procedure CheckOnlyOneItem(item: TMenuItem);
  60. procedure CheckOnlyOneItem(Menu: TMenuItem; Caption: string);
  61. function LoadPNGToImageList(imagList16: TImageList; imgFile: string): Integer;
  62. //Genera un nombre distinto de archivo
  63. function GetNewFileName(nomBase: String; maxNumFile: integer = 10): String;
  64. //Genera un nombre distinto de carpeta
  65. function GetNewFolderName(nomBase: String; maxNumFile: integer = 10): String;
  66. //Conversion de tipos a cadena
  67. function I2f(n: Integer):String;
  68. Function f2I(s : String): Integer;
  69. Function f2I(s : WideString): Integer;
  70. function N2f(n: Double):String;
  71. Function f2N(s : String): Double;
  72. Function f2N(s : WideString): Double;
  73. Function B2f(b : Boolean) : String;
  74. Function f2B(s : String) : Boolean;
  75. Function D2f(d : TDateTime): String;
  76. Function f2D(s : String) : TDateTime;
  77. Function f2D(s : WideString) : TDateTime;
  78. Function S2f(s : String) : String;
  79. function f2S(s : String) : String;
  80. function DT2Number(const dt: TDateTime): Int64;
  81. function Number2DT(n: Int64): TDateTime;
  82. function T2f(const dt: TDateTime): string;
  83. function f2T(hex: string): TDateTime;
  84. //Funciones del diccionario
  85. procedure dicClear; //limpia el diccionario
  86. procedure dicSet(key, value: string); //fija una entrada del diccionario
  87. procedure dicDel(key: string); //limpia una entrada del diccionario
  88. procedure TransCapCtrls(TheForm: TForm; Caption, value: string); //traduce un mensaje de un control
  89. function dic(key: string): string; //lee un mensaje traducido
  90. function dic(Fmt : String; const Args : Array of const): string; //lee un mensaje traducido
  91. //manejo de consola
  92. procedure console(Fmt : String; const Args : Array of const); //muestra mensaje en consola
  93. procedure consoleTickStart; //inicia contador de tiempo
  94. procedure consoleTickCount(msg: string); //muestra diferencia de tiempo
  95. implementation
  96. const
  97. szChar = SizeOf(Char);
  98. var
  99. timeCnt: types.DWORD; //contador para medir intervalos de tiempo
  100. procedure MsgExc(txt: string; Caption: string = '');
  101. //Mensaje de exclamación
  102. begin
  103. if TranslateMsgs then txt := dic(txt);
  104. Application.MessageBox(PChar(txt), PChar(Caption), MB_ICONEXCLAMATION);
  105. end;
  106. procedure MsgExc(Fmt: String; const Args: array of const);
  107. var
  108. txt: String;
  109. begin
  110. if TranslateMsgs then Fmt := dic(Fmt);
  111. txt := Format(Fmt, Args);
  112. Application.MessageBox(Pchar(txt), '', MB_ICONEXCLAMATION);
  113. end;
  114. procedure MsgErr(txt: string; Caption: string = '');
  115. //Mensaje de error
  116. begin
  117. if TranslateMsgs then txt := dic(txt);
  118. Application.MessageBox(PChar(txt), PChar(Caption), MB_ICONERROR);
  119. end;
  120. procedure MsgErr(Fmt: String; const Args: array of const);
  121. var
  122. txt: String;
  123. begin
  124. if TranslateMsgs then Fmt := dic(Fmt);
  125. txt := Format(Fmt, Args);
  126. Application.MessageBox(Pchar(txt), '', MB_ICONERROR);
  127. end;
  128. {function MsgBox(txt: PChar; Caption: string = ''; flags: longint = 0): integer;
  129. begin
  130. if TranslateMsgs then txt := dic(txt);
  131. Result := Application.MessageBox(txt, PChar(Caption), flags);
  132. end;}
  133. function MsgBox(txt: String; Caption: string = ''; flags: longint = 0): integer;
  134. begin
  135. if TranslateMsgs then txt := dic(txt);
  136. Result := Application.MessageBox(Pchar(txt), PChar(Caption), flags);
  137. end;
  138. procedure MsgBox(Fmt: String; const Args: array of const);
  139. var
  140. txt: String;
  141. begin
  142. if TranslateMsgs then Fmt := dic(Fmt);
  143. txt := Format(Fmt, Args);
  144. Application.MessageBox(Pchar(txt), '', 0);
  145. end;
  146. function MsgYesNo(txt: string): byte;
  147. //Muestra un mensaje en pantalla con los botones Yes - No
  148. //Devuelve 1, si para la opción Yes
  149. //Devuelve 2, si para la opción No
  150. var
  151. r: Integer;
  152. begin
  153. Result := 0; //Valor por defecto
  154. if TranslateMsgs then txt := dic(txt);
  155. r := Application.MessageBox(PChar(txt),'',MB_YESNO + MB_ICONQUESTION);
  156. if r = IDYES then exit(1);
  157. if r = IDNO then exit(2);
  158. end;
  159. function MsgYesNo(Fmt: string; const Args: array of const): byte;
  160. //Muestra un mensaje en pantalla con los botones Yes - No
  161. //Devuelve 1, si para la opción Yes
  162. //Devuelve 2, si para la opción No
  163. var
  164. r: Integer;
  165. txt: String;
  166. begin
  167. Result := 0; //Valor por defecto
  168. if TranslateMsgs then Fmt := dic(Fmt);
  169. txt := Format(Fmt, Args);
  170. r := Application.MessageBox(PChar(txt),'',MB_YESNO + MB_ICONQUESTION);
  171. if r = IDYES then exit(1);
  172. if r = IDNO then exit(2);
  173. end;
  174. function MsgYesNoCancel(txt: string): byte;
  175. //Muestra un mensaje en pantalla con los botones Yes - No - Cancel
  176. //Devuelve 1, si para la opción Yes
  177. //Devuelve 2, si para la opción No
  178. //Devuelve 3, si para la opción Cancel
  179. var
  180. r: Integer;
  181. begin
  182. Result := 0; //Valor por defecto
  183. if TranslateMsgs then txt := dic(txt);
  184. r := Application.MessageBox(PChar(txt),'',MB_YESNOCANCEL + MB_ICONQUESTION);
  185. if r = IDYES then exit(1);
  186. if r = IDNO then exit(2);
  187. if r = IDCANCEL then exit(3);
  188. end;
  189. function MsgYesNoCancel(Fmt: string; const Args: array of const): byte;
  190. //Muestra un mensaje en pantalla con los botones Yes - No - Cancel
  191. //Devuelve 1, si para la opción Yes
  192. //Devuelve 2, si para la opción No
  193. //Devuelve 3, si para la opción Cancel
  194. var
  195. r: Integer;
  196. txt: String;
  197. begin
  198. Result := 0; //Valor por defecto
  199. if TranslateMsgs then Fmt := dic(Fmt);
  200. txt := Format(Fmt, Args);
  201. r := Application.MessageBox(PChar(txt),'',MB_YESNOCANCEL + MB_ICONQUESTION);
  202. if r = IDYES then exit(1);
  203. if r = IDNO then exit(2);
  204. if r = IDCANCEL then exit(3);
  205. end;
  206. //funciones diversas
  207. function Explode(delimiter:string; str:string):TStringDynArray;
  208. var
  209. p, n, dsize:integer;
  210. begin
  211. n := 0;
  212. dsize := length(delimiter);
  213. while true do begin
  214. p := pos(delimiter,str);
  215. if p > 0 then begin
  216. inc(n);
  217. SetLength(Result,n);
  218. Result[n-1] := copy(str,1,p-1);
  219. delete(str,1,p+dsize-1);
  220. end else break;
  221. end;
  222. inc(n);
  223. SetLength(Result,n);
  224. Result[n-1] := str;
  225. end;
  226. function Join(delimiter: char; const a: TStringDynArray): string;
  227. var
  228. i: Integer;
  229. begin
  230. {
  231. linea := #9 + #9 + 'a'+#9 + 'b' + #9;
  232. debugln('linea ini=|' + linea + '|');
  233. debugln('long ini=' + IntToStr(length(linea)));
  234. a := explode(#9, linea);
  235. linea := join(a, #9);
  236. debugln('linea fin=|' + linea + '|');
  237. debugln('long fin=' + IntToStr(length(linea)));
  238. }
  239. Result := '';
  240. for i:=0 to high(a) do begin
  241. if i=0 then
  242. Result := a[0]
  243. else
  244. Result := Result + delimiter + a[i];
  245. end;
  246. end;
  247. function Exec(com, par: string; WaitOnExit: boolean = false): boolean;
  248. //Ejecuta un programa. Devuelve FALSE si hubo error
  249. var
  250. p : TProcess; //el proceso a manejar
  251. begin
  252. Result := true;
  253. p := TProcess.Create(nil); //Crea proceso
  254. if WaitOnExit then p.Options:= p.Options + [poWaitOnExit];
  255. //p.CommandLine := SysToUTF8(com);
  256. p.Executable:=com;
  257. p.Parameters.Clear;
  258. p.Parameters.Add(par);
  259. try
  260. p.Execute;
  261. except
  262. Result := false;
  263. MsgBox('Fallo al iniciar aplicativo: '+ p.Executable);;
  264. end;
  265. p.Free;
  266. end;
  267. procedure AnchorTo(Ctl: TControl; Side: TAnchorKind; Sibling: TControl;
  268. Space: integer = 0; Internal: Boolean = false);
  269. {Utilidad para facilitar el anclaje a un control vecino, o a un contenedor.
  270. Es una versión de AnchorToNeighbour(), ampliada. La idea es que se alínie
  271. un control al lado del otro. Si "Internal" es true, el alineamiento se hará
  272. en sentido opuesto}
  273. begin
  274. Ctl.AnchorSide[Side].Control:=Sibling; //define vecino
  275. case Side of
  276. akLeft: begin
  277. Ctl.BorderSpacing.Left:=Space;
  278. if Internal then Ctl.AnchorSide[Side].Side:=asrLeft
  279. else Ctl.AnchorSide[Side].Side:=asrRight;
  280. end;
  281. akTop: begin
  282. Ctl.BorderSpacing.Top:=Space;
  283. if Internal then Ctl.AnchorSide[Side].Side:=asrTop
  284. else Ctl.AnchorSide[Side].Side:=asrBottom;
  285. end;
  286. akRight: begin
  287. Ctl.BorderSpacing.Right:=Space;
  288. if Internal then Ctl.AnchorSide[Side].Side:=asrRight
  289. else Ctl.AnchorSide[Side].Side:=asrLeft;
  290. end;
  291. akBottom: begin
  292. Ctl.BorderSpacing.Bottom:=Space;
  293. if Internal then Ctl.AnchorSide[Side].Side:=asrBottom
  294. else Ctl.AnchorSide[Side].Side:=asrTop;
  295. end;
  296. end;
  297. Ctl.Anchors:=Ctl.Anchors+[Side]; //agrega bandera de anclaje
  298. end;
  299. procedure TrimEndLine(var cad: string);
  300. {Verifica si la cadena incluye un salto de línea al final y de ser así, lo quita}
  301. var
  302. lSalto: Integer;
  303. begin
  304. lSalto := length(LineEnding);
  305. if length(cad)<lSalto then exit; //no puede contener salto
  306. if RightStr(cad, lSalto) = LineEnding then begin
  307. //Contiene el salto
  308. delete(cad, length(cad)-lSalto +1 ,lSalto);
  309. end;
  310. end;
  311. function StringLike(const str: string; mask: string): boolean;
  312. {Utilidad para comparación de cadenas al estilo de VB. El patrón de comparación es
  313. "mask" y tiene los siguientes comodines:
  314. '?' -> coincide con cualquier caracter.
  315. '*' -> coincide con cualquier texto.
  316. '#' -> coincide con cualquier caracter numércio.
  317. '[]' -> indica un conjunto de cacacteres.
  318. }
  319. var
  320. msk: TMask;
  321. begin
  322. mask := StringReplace(mask, '#', '[0-9]', [rfReplaceAll]);
  323. msk := Tmask.Create(mask);
  324. Result := msk.Matches(str);
  325. msk.Destroy;
  326. end;
  327. procedure StringToFile(const s: string; const FileName: string);
  328. ///Guarda una cadena a un archivo. El archivo debe estar la codificaión del sistema.
  329. var
  330. FileStream: TFileStream;
  331. begin
  332. FileStream := TFileStream.Create(FileName, fmCreate);
  333. try
  334. FileStream.WriteBuffer(Pointer(s)^, (Length(s) * szChar));
  335. finally
  336. FreeAndNil(FileStream);
  337. end;
  338. end;
  339. function StringFromFile(const FileName: string): string;
  340. //Lee un archivo como una cadena.
  341. var
  342. FileStream: TFileStream;
  343. begin
  344. FileStream := TFileStream.Create(FileName, fmOpenRead);
  345. try
  346. SetLength(Result, (FileStream.Size div szChar));
  347. FileStream.ReadBuffer(Pointer(Result)^, FileStream.Size);
  348. finally
  349. FreeAndNil(FileStream);
  350. end;
  351. end;
  352. function AddStringToFile(txt: string; const FileName: string): boolean;
  353. {Escribe una cadena de texto a un archivo. }
  354. var
  355. f : Textfile;
  356. begin
  357. Result := False;
  358. AssignFile(f, FileName);
  359. try
  360. if FileExists(FileName) = False then begin
  361. Rewrite(f)
  362. end else begin
  363. Append(f);
  364. end;
  365. Writeln(f, txt);
  366. Result := True;
  367. finally
  368. CloseFile(f);
  369. end;
  370. end;//Utilidades para menús
  371. function AddItemToMenu(menu: TMenuItem; txt: string; evento: TNotifyEvent
  372. ): TMenuItem;
  373. //Agrega un ítema un menú. Devuelve la refrecnia ál nuevo ítem agregado.
  374. var
  375. item: TMenuItem;
  376. begin
  377. item := TMenuItem.Create(nil);
  378. item.Caption:= txt; //nombre
  379. item.OnClick:=evento;
  380. menu.Add(item);
  381. Result := item;
  382. end;
  383. procedure CheckOnlyOneItem(item: TMenuItem);
  384. //Marca un ítem de un menú y deja los demás desmarcados
  385. var
  386. MenuPadre: TMenuItem;
  387. i: Integer;
  388. begin
  389. MenuPadre := item.Parent;
  390. if MenuPadre= nil then exit;
  391. for i:=0 to MenuPadre.Count-1 do //limpia todos
  392. MenuPadre.Items[i].Checked := false;
  393. item.Checked:=true; //marca el ítem
  394. end;
  395. procedure CheckOnlyOneItem(Menu: TMenuItem; Caption: string);
  396. //Marca un ítem de un menú (usando su etiqueta) y deja los demás desmarcados.
  397. //Ignora la caja y el símbolo "&".
  398. var
  399. i: Integer;
  400. capItem: String;
  401. it: TMenuItem;
  402. begin
  403. if Menu = nil then exit; //proteción
  404. //busca el ítem por su etiqueta
  405. it := nil;
  406. Caption := UpCase(Caption);
  407. for i:=0 to Menu.Count-1 do begin
  408. capItem := Upcase(Menu.Items[i].Caption);
  409. capItem := StringReplace(capItem,'&','',[rfReplaceAll]);
  410. if capItem = Caption then begin
  411. it := Menu.Items[i];
  412. break;
  413. end;
  414. end;
  415. if it = nil then exit; //no encontró
  416. CheckOnlyOneItem(it); //marca
  417. end;
  418. function LoadPNGToImageList(imagList16: TImageList; imgFile: string): Integer;
  419. {Rutina para cargar un archivo PNG, en un ImageList. Devuelve el índice de la imagen}
  420. var
  421. pngbmp: TPortableNetworkGraphic;
  422. begin
  423. if not FileExists(imgFile) then exit(-1);
  424. pngbmp:=TPortableNetworkGraphic.Create;
  425. pngbmp.LoadFromFile(imgFile);
  426. Result:= imagList16.Add(pngbmp, nil);
  427. pngbmp.Destroy;
  428. end;
  429. function GetNewFileName(nomBase: String; maxNumFile: integer = 10): String;
  430. {Generate a different file name, using the base name.
  431. }
  432. var i : Integer; //Número de intentos con el nombre de archivo de salida
  433. cadBase : String; //Cadena base del nombre base
  434. extArc: string; //extensión
  435. function NombArchivo(i: integer): string;
  436. begin
  437. Result := cadBase + '-' + IntToStr(i) + extArc;
  438. end;
  439. begin
  440. Result := nomBase; //nombre por defecto
  441. extArc := ExtractFileExt(nomBase);
  442. if ExtractFilePath(nomBase) = '' then exit; //protección
  443. //quita ruta y cambia extensión
  444. cadBase := ChangeFileExt(nomBase,'');
  445. //busca archivo libre
  446. for i := 0 to maxNumFile-1 do begin
  447. If not FileExists(NombArchivo(i)) then begin
  448. //Se encontró nombre libre
  449. Exit(NombArchivo(i)); //Sale con nombre
  450. end;
  451. end;
  452. //All names were used. Return the same name.
  453. End;
  454. function GetNewFolderName(nomBase: String; maxNumFile: integer = 10): String;
  455. {Genera un nombre diferente de archivo, tomando el nombre dado como raiz.}
  456. var i : Integer; //Número de intentos con el nombre de archivo de salida
  457. cadBase : String; //Cadena base del nombre base
  458. function NombFolder(i: integer): string;
  459. begin
  460. Result := cadBase + '-' + IntToStr(i);
  461. end;
  462. begin
  463. Result := nomBase; //nombre por defecto
  464. // cadBase := ExtractFilePath(nomBase);
  465. cadBase := nomBase;
  466. if cadBase = '' then exit; //protección
  467. //busca archivo libre
  468. for i := 0 to maxNumFile-1 do begin
  469. If not DirectoryExists(NombFolder(i)) then begin
  470. //Se encontró nombre libre
  471. Exit(NombFolder(i)); //Sale con nombre
  472. end;
  473. end;
  474. //todos los nombres estaban ocupados. Sale con el mismo nombre
  475. End;
  476. //############## Funciones de conversión de datos para acceso a disco ############
  477. function I2f(n: Integer): String;
  478. begin
  479. Result := IntToStr(n);
  480. end;
  481. function f2I(s: String): Integer;
  482. begin
  483. Result := StrToInt(s);
  484. end;
  485. function f2I(s: WideString): Integer;
  486. begin
  487. Result := StrToInt(AnsiString(s));
  488. end;
  489. function N2f(n: Double):String;
  490. //Convierte número a cadena para guardar en disco. Independiente de la configuración regional
  491. begin
  492. Result := FloatToStr(n);
  493. End;
  494. function f2N(s: String): Double;
  495. //Convierte cadena de disco a número. Independiente de la configuración regional
  496. begin
  497. DefaultFormatSettings.DecimalSeparator:='.'; //para uniformizar el formato
  498. Result := StrToFloat(s); //usa siempre el punto decimal
  499. End;
  500. function f2N(s: WideString): Double;
  501. begin
  502. DefaultFormatSettings.DecimalSeparator:='.'; //para uniformizar el formato
  503. Result := StrToFloat(AnsiString(s)); //usa siempre el punto decimal
  504. end;
  505. function B2f(b: Boolean): String;
  506. //Convierte Boleean a cadena para guardar en disco.
  507. begin
  508. If b Then Result := 'V' Else Result := 'F';
  509. End;
  510. function f2B(s: String): Boolean;
  511. //Convierte cadena de disco a Boleean
  512. begin
  513. If s = 'V' Then exit(True) else exit(False);
  514. End;
  515. function D2f(d: TDateTime): String;
  516. //Convierte fecha a cadena para guardar en disco.
  517. var
  518. s: string;
  519. begin
  520. DateTimeToString(s,'yyyy:mm:dd:hh:nn:ss',d);
  521. Result := s;
  522. End;
  523. function f2D(s: String): TDateTime;
  524. //Convierte cadena de disco a fecha.
  525. var a: TStringDynArray;
  526. begin
  527. a := explode(':',s);
  528. Result := EncodeDateTime(StrToInt(a[0]), StrToInt(a[1]), StrToInt(a[2]),
  529. StrToInt(a[3]), StrToInt(a[4]), StrToInt(a[5]), 0);
  530. End;
  531. function f2D(s: WideString): TDateTime;
  532. var
  533. a: TStringDynArray;
  534. begin
  535. a := explode(':', AnsiString(s));
  536. Result := EncodeDateTime(StrToInt(a[0]), StrToInt(a[1]), StrToInt(a[2]),
  537. StrToInt(a[3]), StrToInt(a[4]), StrToInt(a[5]), 0);
  538. end;
  539. function S2f(s : String) : String;
  540. //Convierte cadena a formato para guardar en disco, en una línea.
  541. begin
  542. //Inicialmente se trabajó con ReplaceText() aquí, pero daba cadena vacía en Win32
  543. Result := StringReplace(s, LineEnding, #1, [rfReplaceAll]);
  544. end;
  545. function f2S(s : String) : String;
  546. //Convierte cadena leída de disco a cadena multilínea.
  547. begin
  548. //Inicialmente se trabajó con ReplaceText() aquí, pero daba cadena vacía en Win32
  549. Result := StringReplace(s, #1, LineEnding, [rfReplaceAll]);
  550. end;
  551. function DT2Number(const dt: TDateTime): Int64;
  552. {Convierte fecha-hora en número entero (no incluye milisegundos). Esta función se creó
  553. como reemplazo a DateTimeToUnix(), ya que en la presente versión de Lazarus, tiene
  554. errores de redondeo.}
  555. var
  556. hh, nn, ss, MilliSecond: word;
  557. begin
  558. DecodeTime(dt, hh, nn, ss, MilliSecond);
  559. Result := trunc(dt)*86400 + hh * 3600 + nn * 60 + ss;
  560. end;
  561. function Number2DT(n: Int64): TDateTime;
  562. {Función opuesta de DT2Number()}
  563. var
  564. day, hh, nn, ss: Int64;
  565. begin
  566. day := n div 86400;
  567. n := n mod 86400;
  568. hh := n div 3600;
  569. n := n mod 3600;
  570. nn := n div 60;
  571. ss := n mod 60;
  572. Result := EncodeTime(hh,nn,ss,0) + day;
  573. end;
  574. function T2f(const dt: TDateTime): string;
  575. {Codifica una fecha-hora en una cadena compacta, usando hexadecimal. Usaulmente para
  576. una fecha generará solo 8 caracteres.}
  577. var
  578. n: Int64;
  579. begin
  580. n := DT2Number(dt);
  581. if n=0 then
  582. Result := '0'
  583. else if n<=$FF then
  584. Result := IntTohex(n,2)
  585. else if n<=$FFF then
  586. Result := IntTohex(n,3)
  587. else if n<=$FFFF then
  588. Result := IntTohex(n,4)
  589. else if n<=$FFFFF then
  590. Result := IntTohex(n,5)
  591. else if n<=$FFFFFF then
  592. Result := IntTohex(n,6)
  593. else if n<=$FFFFFFF then
  594. Result := IntTohex(n,7)
  595. else if n<=$FFFFFFFF then
  596. Result := IntTohex(n,8)
  597. else
  598. Result := IntTohex(n,9);
  599. end;
  600. function f2T(hex: string): TDateTime;
  601. {Restaura la cadena convertida por DT2f}
  602. var
  603. m: Int64;
  604. begin
  605. m := StrToInt64('$'+hex);
  606. Result := Number2DT(m);
  607. end;
  608. procedure dicClear;
  609. //Limpia el diccionario, de modo que no se traducirá ningún mensaje
  610. begin
  611. dictionary.Clear;
  612. end;
  613. procedure dicSet(key, value: string);
  614. //Fija o agrega una entrada al diccionario
  615. begin
  616. //los símbolos "=", no se pueden ingresar
  617. key := StringReplace(key, '=', #31, [rfReplaceAll]);
  618. dictionary.values[key]:=value;
  619. end;
  620. procedure dicDel(key: string);
  621. //Limpia una entrada del diccionario
  622. begin
  623. dictionary.values[key]:='';
  624. end;
  625. procedure TransCapCtrls(TheForm: TForm; Caption, value: string);
  626. //Traduce la etiqueta de un control de un formulario
  627. var
  628. c: TControl;
  629. i : integer;
  630. begin
  631. for i := 0 to TheForm.ControlCount-1 do begin
  632. c := theForm.Controls[i];
  633. if c.Caption = Caption then c.Caption := value;
  634. end;
  635. end;
  636. function dic(key: string): string;
  637. //Devuelve un mensaje en el lenguaje definido, dada la clave.
  638. //La clave no puede tener el signo "="
  639. begin
  640. key := StringReplace(key, #31, '=', [rfReplaceAll]); //codifica la clave
  641. Result := dictionary.Values[key];
  642. //si no encuentra, devuelve la misma clave
  643. if Result = '' then Result := key;
  644. end;
  645. function dic(Fmt: String; const Args: array of const): string;
  646. var
  647. txt: String;
  648. begin
  649. txt := dic(Fmt); //busca
  650. Result := Format(txt, Args); //completa
  651. end;
  652. procedure console(Fmt: String; const Args: array of const);
  653. begin
  654. debugln(Format(Fmt, Args)); //completa
  655. end;
  656. procedure consoleTickStart;
  657. //Inicia el contador de milisegundos
  658. begin
  659. timeCnt:=GetTickCount;
  660. end;
  661. procedure consoleTickCount(msg: string);
  662. //Muestra la diferencia de tiempo transcurrido, e inicia otra cuenta
  663. begin
  664. debugln(msg + ':' + IntToStr(GetTickCount-timeCnt) + 'mseg');
  665. timeCnt := GetTickCount;
  666. end;
  667. Initialization
  668. //crea diccionario
  669. dictionary := TStringList.Create;
  670. TranslateMsgs := false;
  671. Finalization
  672. dictionary.Destroy;
  673. end.