UtilMethods.pas 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. unit UtilMethods;
  2. interface
  3. uses
  4. Controls, ZhAPI, ActnList, ZjIDTree, DB, ZjGridDBA, ZjGrid, Windows, Messages,
  5. sdDB, VCLZip, VCLUnZip, Dialogs, Forms, ShlObj, Classes, StrUtils, Math, ADODB,
  6. IdGlobal;
  7. type
  8. TRoundMode = (rmNearest, rmUp, rmDown);
  9. TBookmarkRefreshEvent = procedure (AExpandFrame: Boolean) of object;
  10. {RoundTo}
  11. function QuantityRoundTo(AValue: Double): Double;
  12. function PriceRoundTo(AValue: Double): Double;
  13. function TotalPriceRoundTo(AValue: Double): Double;
  14. function CommonRoundTo(AValue: Double; ADigit: Integer; RoundMode: TRoundMode = rmNearest): Double;
  15. {Interface Control}
  16. procedure AlignControl(AControl, AParent: TWinControl; AAlign: TAlign);
  17. procedure SetDxBtnAction(AAction: TAction; ADxBtn: TObject);
  18. {DataBase Rela}
  19. function GetsdDataSetNewID(ADataSet: TsdDataSet; const AIndex: string): Integer;
  20. procedure ExecuteSql(AConnection: TADOConnection; const ASql: string);
  21. function QueryData(AConnection: TADOConnection; const ASql: string): TADOQuery;
  22. {Message}
  23. procedure WarningMessage(const AMsg: string; AHandle: THandle = 0);
  24. procedure ErrorMessage(const AMsg: string; AHandle: THandle = 0);
  25. function QuestMessage(const AMsg: string; AHandle: THandle = 0): Boolean;
  26. function QuestMessageYesNo(const AMsg: string; AHandle: THandle = 0): Boolean;
  27. procedure TipMessage(const AMsg: string; AHandle: THandle = 0);
  28. procedure DataSetErrorMessage(var Allow: Boolean; const AMsg: string);
  29. {Get Common Path}
  30. function GetAppFilePath: string;
  31. function GetMyProjectsFilePath: string;
  32. function GetEmptyDataBaseFileName: string;
  33. function GetTemplateBillsFileName: string;
  34. function GetTemplateXlsFileName: string;
  35. function GetBackupFilePath: string;
  36. function GetReportTemplatePath: string;
  37. {Select & Save File Choose}
  38. function GetFilter(AExt: string): string;
  39. function SelectFile(var AFileName: string; const AExt: string): Boolean;
  40. function SelectFiles(AFiles: TStrings; const AExt: string): Boolean;
  41. function SaveFile(var FileName: string; const AExt: string): Boolean;
  42. function SelectOutputDirectory(const ATitle: string; var ADirectory: string;
  43. AParentHandle: THandle = 0; AHasNewFolderBtn: Boolean = True): Boolean;
  44. function FixPathByAppPath(AFileName: string): string;
  45. function BrowseFolder(var APath: string; const ATitle: string;
  46. AParentHandle: THandle; AHasNewFolderBtn: Boolean = True): Boolean;
  47. {CheckStrings}
  48. function CheckPeg(const AStr: string): Boolean;
  49. function CheckValidPassword(APassword: string): Boolean;
  50. function ValidInteger(var AKey: Char): Boolean;
  51. {MergeStrings}
  52. function MergeRelaBGL(const ABGLCode1, ABGLCode2: string): string;
  53. procedure MergeRelaBGLAndNum(var ABGLCode1, ABGLNum1: string; const ABGLCode2, ABGLNum2: string);
  54. {CodeTransform}
  55. function B_CodeToIndexCode(const AB_Code: string): string;
  56. function ChinessNum(const ADigitNum: Integer): string;
  57. function Num2Peg(ANum: Double): string;
  58. {Compare Code}
  59. //function CompareCodeWithChar(const ACode1, ACode2: string): Integer;
  60. {Tree Relative}
  61. function CreateTree: TZjIDTree;
  62. procedure DisConnectTree(ATree: TZjIDTree);
  63. procedure ConnectTree(ATree: TZjIDTree; ADataset: TDataSet);
  64. procedure InitGridHead(AGridDBA: TZjGridDBA; AGrid: TZJGrid);
  65. {Generate Name/Directory/Path}
  66. function GetTempFileDir: string;
  67. function GetTempFilePath: string;
  68. function GetTempName(ALength: Integer = 8): string;
  69. function GetTempFileName: string;
  70. function GenerateTempFolder(AGeneratePath: string): string;
  71. function GetNewGUIDFileName(const AGeneratePath: string): string;
  72. {Progress bar Control}
  73. procedure UpdateSysProgress(APosition: Integer; const AHint: string);
  74. procedure UpdateProgress(APosition: Integer; const AHint: string);
  75. procedure DisableSysProgress;
  76. procedure EnableSysProgress;
  77. {Interface RePaint Control}
  78. procedure BeginUpdateWindow(AHandle: THandle);
  79. procedure EndUpdateWindow(AHandle: THandle);
  80. {Zip}
  81. procedure ZipFolder(AFileFolder, AFileName: string; ACheckMode: Integer = 0);
  82. function UnZipFile(AFileName, AFileFolder: string): Boolean;
  83. {Copy By Stream}
  84. procedure CopyFileByStream(const ASourceFile, ADestFile: string);
  85. // Add by chenshilong, 2014-04-11
  86. function GetVersion(APartCount: Integer = 4): string;
  87. function ExtractFileNameWithoutExt(const AFileName: string): string;
  88. function ShortText(AText: string; AWidth: Integer): string; // 文本缩略显示
  89. function CustomWidthText(AText: string; AWidth: Integer): string;
  90. function ReplaceCharsForJson(AText: string): string; // 替换Json文本中的特殊字符
  91. function RecoverCharsFromJson(AText: string): string; // 下载得到的Json文本恢复成用户需要的文本
  92. procedure FindFiles(APath, AExtName: string; AFileList: TStrings);
  93. function DeleteFolder(const FolderStr: string): Boolean;
  94. function HasExt(const AFileName: string): Boolean;
  95. function CopyFolder(const SrcFolder, DstFolder: string): Boolean;
  96. function FileCount(APath: string): Integer;
  97. implementation
  98. uses
  99. SysUtils, dxBar, MainFrm, ConstUnit, Globals, StdCtrls, ShellAPI;
  100. var
  101. SysProgressDisabled: Boolean;
  102. {RoundTo}
  103. function InnerRoundTo(const AValue: Extended; const ADigit: Integer; RoundMode: TRoundMode): Extended;
  104. var
  105. LFactor, Offset: Extended;
  106. HFactor: Integer;
  107. begin
  108. LFactor := IntPower(10, ADigit);
  109. HFactor := Trunc(IntPower(10, abs(ADigit)));
  110. Result := AValue;
  111. case RoundMode of
  112. rmNearest:
  113. begin
  114. if AValue >= 0 then
  115. Offset := 0.5
  116. else
  117. Offset := -0.5;
  118. Result := Trunc((AValue * HFactor) + Offset) * LFactor;
  119. end;
  120. rmUP:
  121. begin
  122. if Frac(AValue / LFactor) > 0 then
  123. Result := Trunc(AValue * HFactor + 1) * LFactor
  124. else
  125. Result := Trunc(AValue * HFactor) * LFactor;
  126. end;
  127. rmDown:
  128. begin
  129. Result := Trunc(AValue * HFactor) * LFactor;
  130. end;
  131. end;
  132. end;
  133. function QuantityRoundTo(AValue: Double): Double;
  134. begin
  135. if Assigned(OpenProjectManager.CurProjectData) then
  136. Result := CommonRoundTo(AValue, -OpenProjectManager.CurProjectData.ProjProperties.QuantityDigit)
  137. else
  138. Result := CommonRoundTo(AValue, iQuantityDigit);
  139. end;
  140. function PriceRoundTo(AValue: Double): Double;
  141. begin
  142. if Assigned(OpenProjectManager.CurProjectData) then
  143. Result := CommonRoundTo(AValue, -OpenProjectManager.CurProjectData.ProjProperties.PriceDigit)
  144. else
  145. Result := CommonRoundTo(AValue, iPriceDigit);
  146. end;
  147. function TotalPriceRoundTo(AValue: Double): Double;
  148. begin
  149. if Assigned(OpenProjectManager.CurProjectData) then
  150. Result := CommonRoundTo(AValue, -OpenProjectManager.CurProjectData.ProjProperties.TotalPriceDigit)
  151. else
  152. Result := CommonRoundTo(AValue, iTotalPriceDigit);
  153. end;
  154. function CommonRoundTo(AValue: Double; ADigit: Integer; RoundMode: TRoundMode = rmNearest): Double;
  155. var
  156. X: Double;
  157. P: Pointer;
  158. I: Integer;
  159. Buf: array [0..7] of Byte;
  160. begin
  161. P := @AValue;
  162. CopyMemory(@Buf[0], P, SizeOf(AValue));
  163. // 进位处理,从后往前,如果当前byte为$FF,则往前一byte进1
  164. // 注意到尾数开始的位置停止
  165. // 这里说的前后是二进制串,实际存储前后相反
  166. for I := 0 to 6 do
  167. if (I < 6) and (Buf[I] = $FF) then
  168. Buf[I] := 0
  169. else
  170. begin
  171. Buf[I] := Buf[I] + 1;
  172. Break;
  173. end;
  174. P := @X;
  175. CopyMemory(P, @Buf[0], SizeOf(X));
  176. Result := InnerRoundTo(X, ADigit, RoundMode);
  177. end;
  178. {Interface Control}
  179. procedure AlignControl(AControl, AParent: TWinControl; AAlign: TAlign);
  180. begin
  181. if Assigned(AControl) then
  182. begin
  183. if Assigned(AControl.Parent) then
  184. AControl.Parent.RemoveControl(AControl);
  185. AControl.Parent := AParent;
  186. AControl.Align := AAlign;
  187. end;
  188. end;
  189. procedure SetDxBtnAction(AAction: TAction; ADxBtn: TObject);
  190. begin
  191. if Assigned(ADxBtn) then
  192. if ADxBtn is TdxBarButton then
  193. TdxBarButton(ADxBtn).Action := AAction;
  194. end;
  195. {DataBase Rela}
  196. function GetsdDataSetNewID(ADataSet: TsdDataSet; const AIndex: string): Integer;
  197. var
  198. idx: TsdIndex;
  199. begin
  200. idx := ADataSet.FindIndex(AIndex);
  201. if idx.RecordCount > 0 then
  202. Result := idx.Records[idx.RecordCount - 1].ValueByName('ID').AsInteger + 1
  203. else
  204. Result := 1;
  205. end;
  206. procedure ExecuteSql(AConnection: TADOConnection; const ASql: string);
  207. var
  208. vQuery: TADOQuery;
  209. begin
  210. vQuery := TADOQuery.Create(nil);
  211. try
  212. vQuery.Connection := AConnection;
  213. vQuery.SQL.Add(ASql);
  214. vQuery.ExecSQL;
  215. finally
  216. vQuery.Free;
  217. end;
  218. end;
  219. function QueryData(AConnection: TADOConnection; const ASql: string): TADOQuery;
  220. begin
  221. Result := TADOQuery.Create(nil);
  222. Result.Connection := AConnection;
  223. Result.SQL.Clear;
  224. Result.SQL.Add(ASql);
  225. Result.Open;
  226. end;
  227. {Message}
  228. function GetValidHandle(AHandle: THandle = 0): THandle;
  229. begin
  230. if AHandle = 0 then
  231. begin
  232. if (Screen.ActiveForm <> nil) and (Screen.ActiveForm.HandleAllocated) then
  233. Result := Screen.ActiveForm.Handle
  234. else
  235. Result := Application.Handle;
  236. end
  237. else
  238. Result := AHandle;
  239. end;
  240. procedure WarningMessage(const AMsg: string; AHandle: THandle = 0);
  241. begin
  242. MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('警告'), MB_OK or MB_ICONWARNING);
  243. end;
  244. procedure ErrorMessage(const AMsg: string; AHandle: THandle = 0);
  245. begin
  246. MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('错误'), MB_OK or MB_ICONERROR);
  247. end;
  248. function QuestMessage(const AMsg: string; AHandle: THandle = 0): Boolean;
  249. begin
  250. Result := MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('询问'), MB_OKCANCEL or MB_ICONQUESTION) = IDOK;
  251. end;
  252. function QuestMessageYesNo(const AMsg: string; AHandle: THandle = 0): Boolean;
  253. begin
  254. Result := MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('询问'), MB_YESNO or MB_ICONQUESTION) = IDYes;
  255. end;
  256. procedure TipMessage(const AMsg: string; AHandle: THandle = 0);
  257. begin
  258. MessageBox(GetValidHandle(AHandle), PChar(AMsg), PChar('提示'), MB_OK or MB_ICONINFORMATION);
  259. end;
  260. procedure DataSetErrorMessage(var Allow: Boolean; const AMsg: string);
  261. begin
  262. Allow := False;
  263. ErrorMessage(AMsg);
  264. end;
  265. {Get Common Path}
  266. function GetAppFilePath: string;
  267. begin
  268. Result := ExtractFilePath(ParamStr(0));
  269. end;
  270. function GetMyProjectsFilePath: string;
  271. begin
  272. Result := GetAppFilePath + '我的项目\';
  273. end;
  274. function GetEmptyDataBaseFileName: string;
  275. begin
  276. Result := GetAppFilePath + 'Data\Base.dat';
  277. end;
  278. function GetTemplateBillsFileName: string;
  279. begin
  280. Result := GetAppFilePath + 'Data\Template.xls';
  281. end;
  282. function GetTemplateXlsFileName: string;
  283. begin
  284. Result := GetAppFilePath + 'Data\Basic.xls';
  285. end;
  286. function GetBackupFilePath: string;
  287. begin
  288. Result := GetAppFilePath + 'TenderBackup\';
  289. end;
  290. function GetReportTemplatePath: string;
  291. begin
  292. Result := GetAppFilePath + 'ReportTemplates\';
  293. end;
  294. {Select & Save File Choose}
  295. function GetFilter(AExt: string): string;
  296. begin
  297. if AExt = '' then
  298. Result := '所有文件(*.*)|*.*'
  299. else
  300. begin
  301. if AExt[1] <> '.' then
  302. AExt := '.' + AExt;
  303. Result := Format('(*%s)|*%s', [AExt, AExt]);
  304. end;
  305. end;
  306. function SelectFile(var AFileName: string; const AExt: string): Boolean;
  307. var
  308. odFile: TOpenDialog;
  309. begin
  310. odFile := TOpenDialog.Create(nil);
  311. try
  312. odFile.Filter := GetFilter(AExt);
  313. if odFile.Execute then
  314. begin
  315. Application.ProcessMessages;
  316. AFileName := odFile.FileName;
  317. Result := True;
  318. end
  319. else
  320. Result := False;
  321. finally
  322. odFile.Free;
  323. end;
  324. end;
  325. function SelectFiles(AFiles: TStrings; const AExt: string): Boolean;
  326. var
  327. odFile: TOpenDialog;
  328. begin
  329. odFile := TOpenDialog.Create(nil);
  330. try
  331. odFile.Options := odFile.Options + [ofAllowMultiSelect];
  332. odFile.Filter := GetFilter(AExt);
  333. if odFile.Execute then
  334. begin
  335. Application.ProcessMessages;
  336. AFiles.Assign(odFile.Files);
  337. Result := True;
  338. end
  339. else
  340. Result := False;
  341. finally
  342. odFile.Free;
  343. end;
  344. end;
  345. function SaveFile(var FileName: string; const AExt: string): Boolean;
  346. var
  347. sdFile: TSaveDialog;
  348. begin
  349. sdFile := TSaveDialog.Create(nil);
  350. try
  351. sdFile.FileName := FileName;
  352. sdFile.DefaultExt := AExt;
  353. sdFile.Filter := GetFilter(AExt);
  354. Result := sdFile.Execute;
  355. if Result then
  356. FileName := sdFile.FileName;
  357. Application.ProcessMessages;
  358. finally
  359. sdFile.Free;
  360. end;
  361. end;
  362. function SelectOutputDirectory(const ATitle: string; var ADirectory: string;
  363. AParentHandle: THandle; AHasNewFolderBtn: Boolean): Boolean;
  364. var
  365. pID: PItemIDList;
  366. bInfo: TBrowseInfo;
  367. AHandle: THandle;
  368. PStr: array[0..1023] of Char;
  369. sPath: string;
  370. function BFCallBack(Hwnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): Integer; stdcall;
  371. begin
  372. if uMsg = BFFM_INITIALIZED then
  373. begin
  374. SendMessage(Hwnd, BFFM_SETSELECTION, 1, lpData);
  375. end;
  376. Result := 0;
  377. end;
  378. begin
  379. Result := False;
  380. if AParentHandle = 0 then
  381. AHandle := Screen.ActiveForm.Handle
  382. else
  383. AHandle := AParentHandle;
  384. if ADirectory = '' then
  385. sPath := GetAppFilePath
  386. else
  387. sPath := ADirectory;
  388. with bInfo do
  389. begin
  390. hwndOwner := AParentHandle;
  391. iImage := 0;
  392. lParam := Integer(PChar(sPath));
  393. lpszTitle := PChar(ATitle);
  394. pidlRoot := nil;
  395. pszDisplayName := nil;
  396. if AHasNewFolderBtn then
  397. ulFlags := BIF_RETURNONLYFSDIRS or BIF_USENEWUI
  398. else
  399. ulFlags := BIF_RETURNONLYFSDIRS;
  400. lpfn := @BFCallBack;
  401. end;
  402. pID := SHBrowseForFolder(bInfo);
  403. if pID <> nil then
  404. begin
  405. SHGetPathFromIDList(pID, PStr);
  406. ADirectory := StrPas(PStr);
  407. if (ADirectory <> '') and (ADirectory[Length(ADirectory)] <> '\') then
  408. ADirectory := ADirectory + '\';
  409. Result := True;
  410. end;
  411. end;
  412. function FixPathByAppPath(AFileName: string): string;
  413. begin
  414. Result := AFileName;
  415. if AnsiPos(':\', Result) = 0 then
  416. begin
  417. if (Result <> '') and (Result[1] = '\') then
  418. Delete(Result, 1, 1);
  419. Result := ExtractFilePath(Application.ExeName) + Result;
  420. end;
  421. end;
  422. var
  423. PathStr: string;
  424. function BrowseFolder(var APath: string; const ATitle: string; AParentHandle: THandle;
  425. AHasNewFolderBtn: Boolean): Boolean;
  426. function BFCallBackFunc(hwnd: HWND; uMsg: UINT; lParam: LPARAM; lpData: LPARAM): Integer; stdcall;
  427. begin
  428. Result := 0;
  429. case uMsg of
  430. BFFM_INITIALIZED : // 初始化设置目录。
  431. begin
  432. SendMessage(Hwnd,BFFM_SETSELECTION,-1,Integer(PathStr));
  433. end;
  434. end;
  435. end;
  436. var
  437. pID: PItemIDList;
  438. bInfo: TBrowseInfo;
  439. PStr: array[0..1023] of Char;
  440. sPath: string;
  441. Hdl: THandle;
  442. begin
  443. Result := False;
  444. PathStr := '';
  445. if AParentHandle = 0 then
  446. Hdl := Screen.ActiveForm.Handle
  447. else
  448. Hdl := AParentHandle;
  449. sPath := FixPathByAppPath(APath);
  450. if DirectoryExists(sPath) then
  451. PathStr := sPath;
  452. bInfo.hwndOwner := Hdl;
  453. bInfo.iImage := 0;
  454. bInfo.lParam := 0;
  455. bInfo.lpszTitle := PChar(ATitle);
  456. bInfo.pidlRoot := nil;
  457. bInfo.pszDisplayName := nil;
  458. if (not AHasNewFolderBtn) then
  459. bInfo.ulFlags := BIF_RETURNONLYFSDIRS
  460. else
  461. bInfo.ulFlags := BIF_RETURNONLYFSDIRS or BIF_USENEWUI;
  462. bInfo.lpfn := @BFCallBackFunc;
  463. pID := SHBrowseForFolder(bInfo);
  464. if pID <> nil then
  465. begin
  466. SHGetPathFromIDList(pID,pStr);
  467. APath := StrPas(pStr);
  468. if (APath <> '') and (APath[Length(APath)] <> '\') then
  469. APath := APath + '\';
  470. Result := True;
  471. end;
  472. end;
  473. {CheckStrings}
  474. function CheckPeg(const AStr: string): Boolean;
  475. function GetPosition(const AName, AStr, AStrSpare: string): Integer;
  476. begin
  477. Result := Pos(AStr, AName);
  478. if Result = 0 then
  479. Result := Pos(AStrSpare, AName);
  480. end;
  481. var
  482. iPosK, iPosPlus: Integer;
  483. fNum: Double;
  484. begin
  485. Result := False;
  486. iPosK := GetPosition(AStr, 'K', 'k');
  487. iPosPlus := GetPosition(AStr, '+', '+');
  488. if (iPosK = 0) or (iPosPlus = 0) or (iPosPlus < iPosK) then Exit;
  489. Result := TryStrToFloat(Copy(AStr, iPosK + 1, iPosPlus - iPosK - 1), fNum);
  490. end;
  491. function CheckValidPassword(APassword: string): Boolean;
  492. var
  493. iIndex, iLength: Integer;
  494. begin
  495. Result := True;
  496. if APassword = '' then Exit;
  497. iIndex := 1;
  498. iLength := Length(APassword);
  499. Result := (iLength >= 6) and (iLength <= 16);
  500. while Result and (iIndex < iLength) do
  501. begin
  502. Result := APassword[iIndex] in ['A'..'Z', 'a'..'z', '0'..'9'];
  503. Inc(iIndex);
  504. end;
  505. end;
  506. function ValidInteger(var AKey: Char): Boolean;
  507. begin
  508. if AKey in ['+', '-', '0'..'9', #8, #13, #35, #36,
  509. #37, #38, #39, #40, #46] then
  510. begin
  511. Result := True;
  512. end
  513. else
  514. begin
  515. AKey := #0;
  516. Result := False;
  517. end;
  518. end;
  519. {MergeStrings}
  520. function MergeRelaBGL(const ABGLCode1, ABGLCode2: string): string;
  521. var
  522. sgs1, sgs2: TStrings;
  523. i1, i2: Integer;
  524. bExist: Boolean;
  525. begin
  526. Result := ABGLCode1;
  527. sgs1 := TStringList.Create;
  528. sgs2 := TStringList.Create;
  529. try
  530. sgs1.Delimiter := ';';
  531. sgs2.Delimiter := ';';
  532. sgs1.DelimitedText := ABGLCode1;
  533. sgs2.DelimitedText := ABGLCode2;
  534. for i2 := 0 to sgs2.Count - 1 do
  535. begin
  536. bExist := False;
  537. for i1 := 0 to sgs1.Count - 1 do
  538. if SameText(sgs2[i2], sgs1[i1]) then
  539. begin
  540. bExist := True;
  541. Break;
  542. end;
  543. if not bExist then
  544. sgs1.Add(sgs2[i2]);
  545. end;
  546. Result := sgs1.DelimitedText;
  547. finally
  548. sgs1.Free;
  549. sgs2.Free;
  550. end;
  551. end;
  552. procedure MergeRelaBGLAndNum(var ABGLCode1, ABGLNum1: string; const ABGLCode2, ABGLNum2: string);
  553. var
  554. sgsC1, sgsC2, sgsN1, sgsN2: TStrings;
  555. i1, i2: Integer;
  556. bExist: Boolean;
  557. begin
  558. sgsC1 := TStringList.Create;
  559. sgsC2 := TStringList.Create;
  560. sgsN1 := TStringList.Create;
  561. sgsN2 := TStringList.Create;
  562. try
  563. sgsC1.Delimiter := ';';
  564. sgsC2.Delimiter := ';';
  565. sgsC1.DelimitedText := ABGLCode1;
  566. sgsC2.DelimitedText := ABGLCode2;
  567. sgsN1.Delimiter := ';';
  568. sgsN2.Delimiter := ';';
  569. sgsN1.DelimitedText := ABGLNum1;
  570. sgsN2.DelimitedText := ABGLNum2;
  571. for i2 := 0 to sgsC2.Count - 1 do
  572. begin
  573. bExist := False;
  574. for i1 := 0 to sgsC1.Count - 1 do
  575. if SameText(sgsC2[i2], sgsC1[i1]) then
  576. begin
  577. bExist := True;
  578. Break;
  579. end;
  580. if bExist then
  581. begin
  582. sgsN1[i1] := FloatToStr(StrToFloatDef(sgsN1[i1], 0) + StrToFloatDef(sgsN2[i2], 0))
  583. end
  584. else
  585. begin
  586. sgsC1.Add(sgsC2[i2]);
  587. sgsN1.Add(sgsN2[i2]);
  588. end;
  589. end;
  590. ABGLCode1 := sgsC1.DelimitedText;
  591. ABGLNum1 := sgsN1.DelimitedText;
  592. finally
  593. sgsC1.Free;
  594. sgsC2.Free;
  595. sgsN1.Free;
  596. sgsN2.Free;
  597. end;
  598. end;
  599. function B_CodeToIndexCode(const AB_Code: string): string;
  600. var
  601. sgs: TStrings;
  602. i, iNum, iError: Integer;
  603. sError: string;
  604. begin
  605. sgs := TStringList.Create;
  606. try
  607. Result := '';
  608. sgs.Delimiter := '-';
  609. sgs.DelimitedText := AB_Code;
  610. for i := 0 to sgs.Count - 1 do
  611. begin
  612. Val(sgs[i], iNum, iError);
  613. if iError = 0 then
  614. sError := ''
  615. else
  616. sError := Copy(sgs[i], iError, Length(sgs[i])-iError+1);
  617. if iError = 0 then
  618. Result := Result + Format('%4d', [iNum]) + Format('%-4s', [sError])
  619. else if iNum = 0 then
  620. Result := Result + '9999' + Format('%-4s', [sError])
  621. else
  622. Result := Result + Format('%4d', [iNum]) + Format('%-4s', [sError]);
  623. end;
  624. finally
  625. sgs.Free;
  626. end;
  627. end;
  628. function ChinessNum(const ADigitNum: Integer): string;
  629. function TransChineseNum(const ANum, AZeroNum: Integer): string;
  630. begin
  631. Result := '';
  632. case ANum of
  633. 1: if AZeroNum <> 1 then Result := '一';
  634. 2: Result := '二';
  635. 3: Result := '三';
  636. 4: Result := '四';
  637. 5: Result := '五';
  638. 6: Result := '六';
  639. 7: Result := '七';
  640. 8: Result := '八';
  641. 9: Result := '九';
  642. end;
  643. if (Result = '') and ((AZeroNum <> 1) or (ANum = 0)) then Exit;
  644. case AZeroNum of
  645. 0: Result := Result;
  646. 1: Result := Result + '十';
  647. 2: Result := Result + '百';
  648. 3: Result := Result + '千';
  649. 4: Result := Result + '万';
  650. end;
  651. end;
  652. var
  653. iBai, iShi, iGe: Integer;
  654. begin
  655. Result := '';
  656. if (ADigitNum < 0) and (ADigitNum > 10000) then Exit;
  657. iBai := ADigitNum div 100;
  658. iShi := (ADigitNum mod 100) div 10;
  659. iGe := (ADigitNum mod 100) mod 10;
  660. Result := TransChineseNum(iBai, 2) + TransChineseNum(iShi, 1) + TransChineseNum(iGe, 0);
  661. end;
  662. function CheckDigit(ANum: Double): Integer;
  663. begin
  664. if abs(ANum - advRoundTo(ANum, -2)) > 0.0001 then
  665. Result := 3
  666. else if abs(ANum - advRoundTo(ANum, -1)) > 0.001 then
  667. Result := 2
  668. else if abs(ANum - AdvRoundTo(ANum, 0)) > 0.01 then
  669. Result := 1
  670. else
  671. Result := 0;
  672. end;
  673. function Num2Peg(ANum: Double): string;
  674. var
  675. fMod: Double;
  676. iK, iDigit: Integer;
  677. sDigit: string;
  678. begin
  679. iK := Trunc(ANum/1000);
  680. fMod := Frac(ANum/1000)*1000;
  681. iDigit := CheckDigit(fMod);
  682. case iDigit of
  683. 3: sDigit := FormatFloat('000.000', AdvRoundTo(fMod, -3));
  684. 2: sDigit := FormatFloat('000.00', AdvRoundTo(fMod, -2));
  685. 1: sDigit := FormatFloat('000.0', AdvRoundTo(fMod, -1));
  686. 0: sDigit := FormatFloat('000', Trunc(AdvRoundTo(fMod, 0)));
  687. end;
  688. { case iDigit of
  689. 3: Result := Format('K%d+%3.3f', [iK, ]);
  690. 2: Result := Format('K%d+%3.2f', [iK, AdvRoundTo(fMod, -2)]);
  691. 1: Result := Format('K%d+%3.1f', [iK, AdvRoundTo(fMod, -1)]);
  692. 0: Result := Format('K%d+%s', [iK, FormatFloat('000', [])]);
  693. end; }
  694. Result := Format('K%d+%s', [iK, sDigit]);
  695. end;
  696. {Tree Relative}
  697. function CreateTree: TZjIDTree;
  698. begin
  699. Result := TZjIDTree.Create;
  700. Result.KeyFieldName := 'ID';
  701. Result.ParentFieldName := 'ParentID';
  702. Result.NextSiblingFieldName := 'NextSiblingID';
  703. Result.AutoCreateKeyID := True;
  704. Result.AutoExpand := True;
  705. end;
  706. procedure DisConnectTree(ATree: TZjIDTree);
  707. begin
  708. ATree.DataSet := nil;
  709. ATree.Active := False;
  710. end;
  711. procedure ConnectTree(ATree: TZjIDTree; ADataset: TDataSet);
  712. begin
  713. ATree.DataSet := ADataset;
  714. ATree.Active := True;
  715. end;
  716. procedure InitGridHead(AGridDBA: TZjGridDBA; AGrid: TZJGrid);
  717. var
  718. I: Integer;
  719. begin
  720. for I := 0 to AGridDBA.Columns.Count - 1 do
  721. AGrid.Cells[I + 1, 0].Text := AGridDBA.Columns[I].Title.Caption;
  722. end;
  723. {Generate Name/Path}
  724. function GetTempFileDir: string;
  725. var
  726. TempPath: string;
  727. begin
  728. TempPath := GetEnvironmentVariable('TMP');
  729. if TempPath = '' then
  730. TempPath := GetEnvironmentVariable('TEMP');
  731. if TempPath = '' then
  732. begin
  733. if not DirectoryExists(ExtractFileDir(ParamStr(0)) + '\Temp') then
  734. CreateDir(ExtractFileDir(ParamStr(0)) + '\Temp');
  735. TempPath := ExtractFileDir(ParamStr(0)) + '\Temp';
  736. end;
  737. Result := TempPath;
  738. end;
  739. function GetTempFilePath: string;
  740. begin
  741. Result := GetTempFileDir + '\';
  742. end;
  743. function GetTempName(ALength: Integer): string;
  744. const
  745. CodedBuf: array[0..35] of Char = ('0', '1', '2', '3', '4', '5',
  746. '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
  747. 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
  748. 'W', 'X', 'Y', 'Z');
  749. var
  750. Temp: string;
  751. Num: Integer;
  752. begin
  753. Randomize;
  754. Temp := '';
  755. while Length(Temp) < ALength do
  756. begin
  757. Num := Random(37);
  758. If Num <> 36 Then
  759. Temp := Temp + CodedBuf[Num]; // 0..35
  760. end;
  761. Result := Temp;
  762. end;
  763. function GetTempFileName: string;
  764. var
  765. TempExt: string;
  766. begin
  767. Result := GetTempFilePath + GetTempName;
  768. TempExt := '.' + GetTempName(3);
  769. while SameText(TempExt, '.mdb') or SameText(TempExt, '.db') or
  770. SameText(TempExt, '.ldb') do
  771. TempExt := '.' + GetTempName(3);
  772. Result := Result + TempExt;
  773. while FileExists(Result) do
  774. begin
  775. Result := GetTempFilePath + GetTempName;
  776. TempExt := '.' + GetTempName(3);
  777. while SameText(TempExt, '.mdb') or SameText(TempExt, '.db') or
  778. SameText(TempExt, '.ldb') do
  779. TempExt := '.' + GetTempName(3);
  780. Result := Result + TempExt;
  781. end;
  782. end;
  783. function GenerateTempFolder(AGeneratePath: string): string;
  784. begin
  785. Result := AGeneratePath + GetTempName;
  786. while DirectoryExists(Result) do
  787. Result := AGeneratePath + GetTempName;
  788. CreateDirectoryInDeep(Result);
  789. end;
  790. function GetNewGUIDFileName(const AGeneratePath: string): string;
  791. var
  792. gFile: TGUID;
  793. begin
  794. repeat
  795. CreateGUID(gFile);
  796. Result := AGeneratePath + GUIDToString(gFile);
  797. until not FileExists(Result);
  798. end;
  799. {Progress bar Control}
  800. procedure UpdateSysProgress(APosition: Integer; const AHint: string);
  801. begin
  802. if not SysProgressDisabled then
  803. UpdateProgress(APosition, AHint);
  804. end;
  805. procedure UpdateProgress(APosition: Integer; const AHint: string);
  806. begin
  807. MainForm.UpdateProgress(APosition, AHint);
  808. end;
  809. procedure DisableSysProgress;
  810. begin
  811. SysProgressDisabled := True;
  812. end;
  813. procedure EnableSysProgress;
  814. begin
  815. SysProgressDisabled := False;
  816. end;
  817. {Interface RePaint Control}
  818. procedure BeginUpdateWindow(AHandle: THandle);
  819. begin
  820. SendMessage(AHandle, WM_SETREDRAW, 0, 0);
  821. end;
  822. procedure EndUpdateWindow(AHandle: THandle);
  823. begin
  824. SendMessage(AHandle, WM_SETREDRAW, 1, 0);
  825. end;
  826. {Zip}
  827. function ZipComplete(const AFileName: string; ACheckMode: Integer): Boolean;
  828. const
  829. i4k = 4096;
  830. var
  831. iSize1, iSize2: Integer;
  832. begin
  833. iSize1 := FileSizeByName(AFileName);
  834. Sleep(200);
  835. iSize2 := FileSizeByName(AFileName);
  836. Result := (iSize1 = iSize2);
  837. if ACheckMode = 0 then
  838. Result := Result and (iSize1 > i4k);
  839. end;
  840. procedure ZipFolder(AFileFolder, AFileName: string; ACheckMode: Integer = 0);
  841. procedure AppendLog(const ALog: string);
  842. begin
  843. if SupportManager.ConfigInfo.IsLog then
  844. MeasureLog.AppendLogTo(ALog);
  845. end;
  846. var
  847. sTempFile: string;
  848. vZip: TVCLZip;
  849. iCount: Integer;
  850. begin
  851. AppendLog('Zip');
  852. sTempFile := GetTempFileName;
  853. vZip := TVCLZip.Create(nil);
  854. iCount := 0;
  855. try
  856. vZip.FilesList.Clear;
  857. vZip.ZipName := sTempFile;
  858. vzip.RootDir := AFileFolder;
  859. vZip.OverwriteMode := Always;
  860. //vZip.AddDirEntriesOnRecurse:=True;
  861. vZip.RelativePaths := True;
  862. //vZip.RecreateDirs := True;
  863. vZip.FilesList.Add(AFileFolder + '\*.*');
  864. vZip.Zip;
  865. AppendLog(Format('Check Zip File, FileSize - %d', [FileSizeByName(sTempFile)]));
  866. while not ZipComplete(sTempFile, ACheckMode) and (iCount < 10) do
  867. begin
  868. Sleep(200);
  869. Inc(iCount);
  870. AppendLog(Format('Check Zip File - %d, FileSize - %d', [iCount + 1, FileSizeByName(sTempFile)]));
  871. end;
  872. AppendLog('Check Zip File --> Pass');
  873. CopyFileOrFolder(sTempFile, AFileName);
  874. AppendLog('Zip --> Pass');
  875. finally
  876. vZip.Free;
  877. if FileExists(sTempFile) then
  878. DeleteFile(sTempFile);
  879. end;
  880. end;
  881. function UnZipFile(AFileName, AFileFolder: string): Boolean;
  882. var
  883. vUnZip: TVCLZip;
  884. begin
  885. Result := True;
  886. vUnZip := TVCLZip.Create(nil);
  887. try
  888. vUnZip.FilesList.Clear;
  889. vUnZip.ZipName := AFileName;
  890. vUnZip.ReadZip;
  891. vUnZip.DestDir := AFileFolder;
  892. vUnZip.OverwriteMode := Always;
  893. vUnZip.RecreateDirs := True;
  894. vUnZip.RelativePaths := True;
  895. vUnZip.DoAll := True;
  896. vUnZip.FilesList.Add('*.*');
  897. try
  898. vUnZip.UnZip;
  899. except
  900. Result := False;
  901. end;
  902. finally
  903. vUnZip.Free;
  904. end;
  905. end;
  906. {Copy By Stream}
  907. procedure CopyFileByStream(const ASourceFile, ADestFile: string);
  908. var
  909. MS: TMemoryStream;
  910. begin
  911. MS := TMemoryStream.Create;
  912. try
  913. MS.LoadFromFile(ASourceFile);
  914. if FileExists(ADestFile) then
  915. DeleteFile(ADestFile);
  916. MS.SaveToFile(ADestFile);
  917. finally
  918. MS.Free;
  919. end;
  920. end;
  921. function GetVersion(APartCount: Integer = 4): string;
  922. var
  923. V1, V2, V3, V4: Word;
  924. FInfoSize, FF: Cardinal;
  925. FInfo: Pointer;
  926. FFixed: PVSFIXEDFILEINFO;
  927. begin
  928. FInfoSize := GetFileVersionInfoSize(PChar(Application.ExeName), FF);
  929. FInfo := AllocMem(FInfoSize);
  930. try
  931. GetFileVersionInfo(PChar(Application.ExeName), FF, FInfoSize, FInfo);
  932. VerQueryValue(FInfo, '\', Pointer(FFixed), FInfoSize);
  933. V1 := FFixed.dwFileVersionMS shr 16;
  934. V2 := FFixed.dwFileVersionMS and $FFFF;
  935. V3 := FFixed.dwFileVersionLS shr 16;
  936. V4 := FFixed.dwFileVersionLS and $FFFF;
  937. finally
  938. Dispose(FInfo);
  939. end;
  940. Result := '';
  941. case APartCount of
  942. 1:
  943. Result := Format('%d', [V1]);
  944. 2:
  945. Result := Format('%d.%d', [V1, V2]);
  946. 3:
  947. Result := Format('%d.%d.%d', [V1, V2, V3]);
  948. 4:
  949. Result := Format('%d.%d.%d.%d', [V1, V2, V3, V4]);
  950. end;
  951. end;
  952. function ExtractFileNameWithoutExt(const AFileName: string): string;
  953. var
  954. sFileName, Ext: string;
  955. begin
  956. Result := '';
  957. if AFileName = '' then
  958. Exit;
  959. sFileName := AFileName;
  960. if sFileName[Length(sFileName)] = '\' then
  961. Delete(sFileName, Length(sFileName), 1);
  962. Result := ExtractFileName(sFileName);
  963. Ext := ExtractFileExt(sFileName);
  964. Delete(Result, Length(Result) - Length(Ext) + 1, Length(Ext));
  965. end;
  966. function ShortText(AText: string; AWidth: Integer): string;
  967. var vMM: TMemo;
  968. begin
  969. if Trim(AText) = '' then
  970. begin
  971. Result := '';
  972. Exit;
  973. end;
  974. vMM := TMemo.Create(nil);
  975. try
  976. vMM.Visible := False;
  977. vMM.WordWrap := True;
  978. vMM.parent := Application.MainForm;
  979. vMM.Width := AWidth - 10; // 10像素留给3个小点
  980. vMM.Text := AText;
  981. if vMM.Lines.Count > 1 then
  982. Result := vMM.Lines[0] + '...'
  983. else
  984. Result := AText;
  985. finally
  986. vMM.Free;
  987. end;
  988. end;
  989. function CustomWidthText(AText: string; AWidth: Integer): string;
  990. var vMM: TMemo;
  991. i: Integer;
  992. begin
  993. if Trim(AText) = '' then
  994. begin
  995. Result := '';
  996. Exit;
  997. end;
  998. vMM := TMemo.Create(nil);
  999. try
  1000. vMM.Visible := False;
  1001. vMM.WordWrap := True;
  1002. vMM.parent := Application.MainForm;
  1003. vMM.Width := AWidth;
  1004. vMM.Text := AText;
  1005. for i := 0 to vMM.Lines.Count - 1 do
  1006. begin
  1007. if i = 0 then
  1008. Result := vMM.Lines[i]
  1009. else
  1010. Result := Result + #10#13 + vMM.Lines[i];
  1011. end;
  1012. finally
  1013. vMM.Free;
  1014. end;
  1015. end;
  1016. function ReplaceCharsForJson(AText: string): string;
  1017. const
  1018. BefChar: array [0..7] of Char = ('{', '}', ',', ':', '"', '[', ']', '%');
  1019. AftChar: array [0..7] of string = ('{', '}', ',', ':', '"', '【', '】', '♂');
  1020. var I: Integer;
  1021. begin
  1022. AText := Trim(AText);
  1023. Result := AText;
  1024. if AText = '' then Exit;
  1025. for I := low(BefChar) to High(BefChar) do
  1026. begin
  1027. if Pos(BefChar[I], AText) > 0 then
  1028. AText := StringReplace(AText, BefChar[I], AftChar[I], [rfReplaceAll]);
  1029. end;
  1030. Result := AText;
  1031. end;
  1032. function RecoverCharsFromJson(AText: string): string;
  1033. const
  1034. BefStr: array [0..3] of string = ('♂', '\r\n', '\r', '\n');
  1035. AftStr: array [0..3] of string = ('%', '', '', '');
  1036. var I: Integer;
  1037. begin
  1038. AText := Trim(AText);
  1039. Result := AText;
  1040. if AText = '' then Exit;
  1041. for I := low(BefStr) to High(BefStr) do
  1042. begin
  1043. if Pos(BefStr[I], AText) > 0 then
  1044. AText := StringReplace(AText, BefStr[I], AftStr[I], [rfReplaceAll]);
  1045. end;
  1046. Result := AText;
  1047. end;
  1048. procedure FindFiles(APath, AExtName: string; AFileList: TStrings);
  1049. var
  1050. SRec: TSearchRec;
  1051. retval: Integer;
  1052. begin
  1053. AFileList.Clear;
  1054. retval := FindFirst(APath + AExtName, faAnyFile, sRec);
  1055. try
  1056. while retval = 0 do
  1057. begin
  1058. if (SRec.Attr and faDirectory) = 0 then
  1059. AFileList.Add(Srec.Name);
  1060. retval := FindNext(SRec);
  1061. end;
  1062. finally
  1063. FindClose(SRec);
  1064. end;
  1065. end;
  1066. function DeleteFolder(const FolderStr: string): Boolean;
  1067. var
  1068. fos: SHFILEOPSTRUCT;
  1069. begin
  1070. ZeroMemory(@fos, SizeOf(fos));
  1071. fos.Wnd := HWND_DESKTOP;
  1072. fos.wFunc := FO_DELETE;
  1073. fos.fFlags := FOF_SILENT OR FOF_ALLOWUNDO OR FOF_NOCONFIRMATION;
  1074. fos.pFrom := PChar(FolderStr + #0);
  1075. Result := SHFileOperation(fos) <> 0;
  1076. end;
  1077. function HasExt(const AFileName: string): Boolean;
  1078. begin
  1079. Result := ExtractFileExt(AFileName) <> '';
  1080. end;
  1081. function CopyFolder(const SrcFolder, DstFolder: string): Boolean;
  1082. var
  1083. fos: SHFILEOPSTRUCT;
  1084. begin
  1085. ZeroMemory(@fos, SizeOf(fos));
  1086. fos.Wnd := HWND_DESKTOP;
  1087. fos.wFunc := FO_COPY;
  1088. fos.fFlags := FOF_SILENT OR FOF_ALLOWUNDO;
  1089. fos.pFrom := PChar(SrcFolder + #0);
  1090. fos.pTo := PChar(DstFolder + #0);
  1091. Result := SHFileOperation(fos) <> 0;
  1092. end;
  1093. function FileCount(APath: string): Integer;
  1094. var
  1095. vSR: TSearchRec;
  1096. iRetval: Integer;
  1097. vSL: TStringList;
  1098. begin
  1099. vSL := TStringList.Create;
  1100. iRetval := FindFirst(APath + '*.*', faAnyFile, vSR);
  1101. try
  1102. while iRetval = 0 do
  1103. begin
  1104. if (vSR.Attr and faDirectory) = 0 then
  1105. vSL.Add(vSR.Name);
  1106. iRetval := FindNext(vSR);
  1107. end;
  1108. Result := vSL.Count;
  1109. finally
  1110. FindClose(vSR);
  1111. vSL.Free;
  1112. end;
  1113. end;
  1114. end.