2
0

FrameCfgSyntax.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592
  1. {Frame para la configuración de los elementos de la sintaxis de los editores de texto.
  2. A diferencia de los otros frames, este no trabaja a la manera común, que sería asociar
  3. propiedades a controles, con rutinas de MiConfig.
  4. Aquí se leen directamente las propiedades de lso archivos XML de sintaxis, y se cargan
  5. en la lista synLangList. Allí se modifican y solo cuando se pulsa "Aplicar", se vuelca
  6. nuevamente el contenido a disco, sobreescribiendo todo el archivo.
  7. }
  8. unit FrameCfgSyntax;
  9. {$mode objfpc}{$H+}
  10. interface
  11. uses
  12. Classes, SysUtils, FileUtil, LazUTF8, LazFileUtils, Forms, Controls, StdCtrls,
  13. LCLProc, Graphics, MisUtils, fgl, Types, LCLIntf, Dialogs, SynFacilBasic,
  14. strutils;
  15. type
  16. { TSynParam }
  17. {Registro para modelar a un parámetro (color de texto, de fondo, ....) de un
  18. atributo. Un atributo contiene varios parámetros.
  19. El objeto TParamPos, realmente no guarda copia del valor de un parámetro, sino solo
  20. referencias de posición al objeto lines[], que es el único contenedor del archivo de
  21. sintaxis. Cuando se actualiza TParamPos, se actualiza directamente el contenido de
  22. Lines[].
  23. Se podría pensar que guardar las referencias a lines[] y "nlin", podría ser redundante
  24. porque todos de los parámetros, están en la misma línea, pero eso es solo cierto para
  25. los parámetros de un atributo. Los parámetros peuden aparecer también, fuera de los
  26. atributos (por ejemplo el parámetro "pOpenOnKeyUp"), y ocupar líneas diferentes.
  27. }
  28. TSynAttribute = class;
  29. TSynParam = class
  30. parName: string; //Nombre del parámetro
  31. lines : TStringList; //Referencia a archivo de sintaxis
  32. nlin : integer; //Índice de línea
  33. OnModified: procedure(paramModf: TSynParam) of object; //Cuando se modifica
  34. function Exist: boolean;
  35. function ReadString: string;
  36. function ReadColor: TColor;
  37. function ReadBool: boolean;
  38. procedure WriteString(value: string);
  39. procedure WriteColor(color: TColor);
  40. procedure WriteBool(value: boolean);
  41. private
  42. procedure ReadParamPos(parLabel: string; out p1, p2: integer);
  43. public
  44. procedure SetSourcePosition(parName0: string; lines0: TStringList;
  45. nlin0: integer);
  46. end;
  47. TSynParamList = specialize TFPGObjectList<TSynParam>;
  48. { TSynAttribute }
  49. {Modela a un atributo (Identificadores, Cadenas, Números, etc.)
  50. Un archivo de sinatxis contiene varios atributos.
  51. Un atributo contiene a varios parámetros.}
  52. TSynAttribute = class
  53. private
  54. function GetName: string;
  55. procedure SetName(AValue: string);
  56. public
  57. pName : TSynParam;
  58. pTextColor: TSynParam;
  59. pBackColor: TSynParam;
  60. pBold : TSynParam;
  61. pItalic : TSynParam;
  62. pUnder : TSynParam;
  63. public //Inicialización
  64. constructor Create; virtual;
  65. destructor Destroy; override;
  66. end;
  67. TSynAttributeList = specialize TFPGObjectList<TSynAttribute>;
  68. { TSynLang }
  69. {Almacena al archivo de sintaxis, y alguna posiciones importantes para poder
  70. modificarlo. No usa documentos XML, sino que lo maneja el archivo como líneas de
  71. texto para manteenr el formato, en las líneas no editadas.}
  72. TSynLang = class
  73. private
  74. lines : TStringList; //Contenedor del archivo de sintaxis
  75. linComplet: integer; //línea donde esta <Completion>
  76. linLangua : integer; //línea donde esta <Language>
  77. pName: TSynParam;
  78. pOpenOnKeyUp: TSynParam;
  79. public
  80. filName: string;
  81. Attributes: TSynAttributeList; //Lista de atributos
  82. public
  83. procedure ReadFromFile(fil: string);
  84. procedure SaveToFile;
  85. constructor Create; virtual;
  86. destructor Destroy; override;
  87. end;
  88. TSynLangList = specialize TFPGObjectList<TSynLang>;
  89. { TfraCfgSyntax }
  90. TfraCfgSyntax = class(TFrame)
  91. chkBold: TCheckBox;
  92. chkAutoComp: TCheckBox;
  93. chkItalic: TCheckBox;
  94. chkUnder: TCheckBox;
  95. colTextCol: TColorButton;
  96. colBackCol: TColorButton;
  97. ComboBox1: TComboBox;
  98. Label1: TLabel;
  99. Label2: TLabel;
  100. Label3: TLabel;
  101. Label4: TLabel;
  102. ListBox1: TListBox;
  103. procedure chkAutoCompChange(Sender: TObject);
  104. procedure chkBoldChange(Sender: TObject);
  105. procedure chkItalicChange(Sender: TObject);
  106. procedure chkUnderChange(Sender: TObject);
  107. procedure colTextColColorChanged(Sender: TObject);
  108. procedure ComboBox1Change(Sender: TObject);
  109. procedure ListBox1Click(Sender: TObject);
  110. private
  111. pathSyn: string;
  112. curLang: TSynLang; //Sintaxis actual
  113. curAttr: TSynAttribute; //Atributo actual
  114. synLangList: TSynLangList;
  115. function AddSyntax(synFile: string): TSynLang;
  116. public
  117. procedure SaveChanges;
  118. function GetPropertiesForTheme: string;
  119. procedure SetPropertiesForTheme(themeFile: string);
  120. public //Inicialización
  121. procedure LoadSyntaxFiles(pathSyn0: string);
  122. procedure SetLanguage;
  123. constructor Create(AOwner: TComponent) ; override;
  124. destructor Destroy; override;
  125. end;
  126. implementation
  127. {$R *.lfm}
  128. { TSynParam }
  129. procedure TSynParam.ReadParamPos(parLabel: string; out p1, p2: integer);
  130. {Lee la ubicación (p1 y p2) del parámetro de nombre "parLabel", en la línea lines[nlin].
  131. Si no enecuentra, pone p1:=0}
  132. function BuscarFinDe(cadBusq: string; const lin: string): integer;
  133. {Busca la cadena "cadBusq" en "lin". Si encuentra, devuelve la posición al final de
  134. la cadena de búsqueda, saltando espacios.
  135. Si no encuentra, devuelve 0.}
  136. var
  137. p: SizeInt;
  138. begin
  139. p := pos(cadBusq, lin);
  140. if p=0 then begin
  141. //No enceontró
  142. exit(0);
  143. end else begin
  144. //Encontró la cadena
  145. p := p + length(cadBusq); //Para que pase
  146. //salta blancos
  147. while (p<=length(lin)) and (lin[p] in [' ',#9]) do begin
  148. inc(p);
  149. end;
  150. //No debería fallar, si ya se cargó (validó) la sintaxis
  151. if p>length(lin) then begin
  152. exit(0);
  153. end;
  154. //Termina apuntando a la siguiente posición no vacía
  155. exit(p);
  156. end;
  157. end;
  158. var
  159. carStr: Char;
  160. lin, cadBuscar: String;
  161. begin
  162. lin := lines[nlin];
  163. parName := parLabel; //actualzia nombre
  164. //Busca el inicio del parámetro
  165. lin := UpCase(lin); //Para realizar la búsqueda sin considera caja
  166. cadBuscar := UpCase(parLabel + '='); //construye cadena de búsqueda
  167. p1 := BuscarFinDe(cadBuscar, lin);
  168. if p1 <> 0 then begin
  169. //Debería seguir comilla o doble comilla
  170. carStr := lin[p1];
  171. if not (carStr in ['''', '"']) then begin
  172. p1 := 0;
  173. exit;
  174. end;
  175. //Busca el final de cadena
  176. p1 := p1 + 1;
  177. p2 := posEx(carStr, lin, p1+1)-1;
  178. end;
  179. end;
  180. function TSynParam.Exist: boolean;
  181. var
  182. p1, p2: integer;
  183. begin
  184. //Esta verifiación no es muy eficiente, así que usarla con cuidado
  185. ReadParamPos(parName, p1, p2); //actualiza p1 y p2
  186. Result := p1<>0;
  187. end;
  188. function TSynParam.ReadString: string;
  189. var
  190. p1, p2: integer;
  191. begin
  192. ReadParamPos(parName, p1, p2); //actualiza p1 y p2
  193. if p1 = 0 then exit('');
  194. Result := copy(lines[nlin], p1, p2 - p1 + 1);
  195. end;
  196. function TSynParam.ReadColor: TColor;
  197. function EsHexa(txt: string; out num: integer): boolean;
  198. //Convierte un texto en un número entero. Si es numérico devuelve TRUE
  199. var
  200. i: integer;
  201. begin
  202. Result := true; //valor por defecto
  203. num := 0; //valor por defecto
  204. for i:=1 to length(txt) do begin
  205. if not (txt[i] in ['0'..'9','a'..'f','A'..'F']) then exit(false); //no era
  206. end;
  207. //todos los dígitos son numéricos
  208. num := StrToInt('$'+txt);
  209. end;
  210. var
  211. cad: String;
  212. begin
  213. cad := ReadString;
  214. if cad='' then exit(clBlack);
  215. Result := clBlack; //Color por defecto
  216. Result := ColorFromStr(cad);
  217. end;
  218. function TSynParam.ReadBool: boolean;
  219. begin
  220. Result := UpCase(ReadString)='TRUE';
  221. end;
  222. procedure TSynParam.WriteString(value: string);
  223. var
  224. lin, newline: String;
  225. p1, p2: integer;
  226. begin
  227. ReadParamPos(parName, p1, p2); //actualiza p1 y p2
  228. if p1 = 0 then exit;
  229. lin := lines[nlin];
  230. newline := copy(lin, 1, p1-1)+ value + copy(lin, p2+1, length(lin));
  231. lines[nlin] := newline;
  232. if OnModified<>nil then OnModified(self); //Para que se actuliazen los otros parámetros
  233. end;
  234. procedure TSynParam.WriteColor(color: TColor);
  235. var
  236. value: String;
  237. r, g, b: Integer;
  238. begin
  239. r := color and $FF;
  240. g := (color >> 8) and $FF;
  241. b := (color >> 16) and $FF;
  242. value := '#' + IntToHex(r,2) + IntToHex(g,2) + IntToHex(b,2);
  243. WriteString(value);
  244. end;
  245. procedure TSynParam.WriteBool(value: boolean);
  246. begin
  247. if Value then WriteString('True') else WriteString('False');
  248. end;
  249. procedure TSynParam.SetSourcePosition(parName0: string; lines0: TStringList; nlin0: integer);
  250. {Configura la ubicación del parámetro, para que pueda encontrar su valro, cuando
  251. necesite leerlo o modificarlo}
  252. begin
  253. parName:= parName0;
  254. lines := lines0;
  255. nlin := nlin0;
  256. end;
  257. { TSynAttribute }
  258. function TSynAttribute.GetName: string;
  259. begin
  260. Result := pName.ReadString;
  261. end;
  262. procedure TSynAttribute.SetName(AValue: string);
  263. begin
  264. pName.WriteString(AValue);
  265. end;
  266. //Inicialización
  267. constructor TSynAttribute.Create;
  268. begin
  269. //Crea y ubica a sus atributos
  270. pName := TSynParam.Create;
  271. pTextColor:= TSynParam.Create;
  272. pBackColor:= TSynParam.Create;
  273. pBold := TSynParam.Create;
  274. pItalic := TSynParam.Create;
  275. pUnder := TSynParam.Create;
  276. end;
  277. destructor TSynAttribute.Destroy;
  278. begin
  279. pName.Destroy;
  280. pTextColor.Destroy;
  281. pBackColor.Destroy;
  282. pBold.Destroy;
  283. pItalic.Destroy;
  284. pUnder.Destroy;
  285. inherited Destroy;
  286. end;
  287. { TSynLang }
  288. procedure TSynLang.ReadFromFile(fil: string);
  289. var
  290. lin: String;
  291. i: Integer;
  292. att: TSynAttribute;
  293. begin
  294. filName := fil;
  295. lines.LoadFromFile(fil);
  296. linComplet := 0;
  297. for i := 0 to lines.Count-1 do begin
  298. lin := lines[i];
  299. if AnsiContainsText(lin, '<Completion') then begin
  300. linComplet := i;
  301. pOpenOnKeyUp.SetSourcePosition('OpenOnKeyUp', lines, i );
  302. end else if AnsiContainsText(lin, '<Language') then begin
  303. linLangua := i;
  304. pName.SetSourcePosition('Name', lines, i);
  305. end else if AnsiContainsText(lin, '<Attribute') then begin
  306. //Crea el atributo
  307. att := TSynAttribute.Create;
  308. att.pName .SetSourcePosition('Name' , lines, i);
  309. att.pTextColor.SetSourcePosition('ForeCol' , lines, i);
  310. att.pBackColor.SetSourcePosition('BackCol' , lines, i);
  311. att.pBold .SetSourcePosition('Bold' , lines, i);
  312. att.pItalic .SetSourcePosition('Italic' , lines, i);
  313. att.pUnder .SetSourcePosition('Underline', lines, i);
  314. Attributes.Add(att);
  315. end;
  316. end;
  317. end;
  318. procedure TSynLang.SaveToFile;
  319. {Vuelca el contenido de todo el archivo de este TSynLang, a disco. Las propiedades ya
  320. deben haber sido actualizadas en lines[]}
  321. begin
  322. lines.SaveToFile(filName);
  323. end;
  324. constructor TSynLang.Create;
  325. begin
  326. pName := TSynParam.Create;
  327. pOpenOnKeyUp:= TSynParam.Create;
  328. lines := TStringList.Create;
  329. Attributes:= TSynAttributeList.Create(true);
  330. end;
  331. destructor TSynLang.Destroy;
  332. begin
  333. pOpenOnKeyUp.Destroy;
  334. pName.Destroy;
  335. lines.Destroy;
  336. Attributes.Destroy;
  337. inherited Destroy;
  338. end;
  339. { TfraCfgSyntax }
  340. procedure TfraCfgSyntax.SetLanguage;
  341. begin
  342. //curLang := idLang;
  343. //
  344. end;
  345. procedure TfraCfgSyntax.chkAutoCompChange(Sender: TObject);
  346. begin
  347. if curLang = nil then exit;
  348. curLang.pOpenOnKeyUp.WriteBool(chkAutoComp.Checked);
  349. end;
  350. procedure TfraCfgSyntax.chkBoldChange(Sender: TObject);
  351. begin
  352. if curAttr = nil then exit;
  353. curAttr.pBold.WriteBool(chkBold.Checked);
  354. end;
  355. procedure TfraCfgSyntax.chkItalicChange(Sender: TObject);
  356. begin
  357. if curAttr = nil then exit;
  358. curAttr.pItalic.WriteBool(chkItalic.Checked);
  359. end;
  360. procedure TfraCfgSyntax.chkUnderChange(Sender: TObject);
  361. begin
  362. if curAttr = nil then exit;
  363. curAttr.pUnder.WriteBool(chkUnder.Checked);
  364. end;
  365. procedure TfraCfgSyntax.colTextColColorChanged(Sender: TObject);
  366. begin
  367. if curAttr = nil then exit;
  368. curAttr.pTextColor.WriteColor(colTextCol.ButtonColor);
  369. end;
  370. function TfraCfgSyntax.GetPropertiesForTheme: string;
  371. {Devuelve en una cadena, las propiedades que se deben guardar como parte de un tema,
  372. como son los colores.
  373. Se usa para obtener información de algunas propiedades para guardarlas como parte de
  374. un tema.}
  375. var
  376. synLang: TSynLang;
  377. att: TSynAttribute;
  378. begin
  379. Result := '';
  380. for synLang in synLangList do begin
  381. Result := Result + 'f:' + synLang.filName + LineEnding;
  382. for att in synLang.Attributes do begin
  383. //Agrega una línea por atributo
  384. Result := Result + att.GetName + #9 +
  385. I2f(att.pTextColor.ReadColor) + #9 +
  386. I2f(att.pBackColor.ReadColor) + #9 +
  387. B2f(att.pBold.ReadBool) + #9 +
  388. B2f(att.pItalic.ReadBool) + #9 +
  389. B2f(att.pUnder.ReadBool) + #9 +
  390. #9 + #9 + #9 + //para amplaición
  391. LineEnding;
  392. end;
  393. end;
  394. end;
  395. procedure TfraCfgSyntax.SetPropertiesForTheme(themeFile: string);
  396. {Fija las propiedades que lee GetPropertiesForTheme(), a partir del contenido de un
  397. archivo}
  398. procedure SetAttribute(fil: string; attribLine: string);
  399. var
  400. synLang: TSynLang;
  401. att: TSynAttribute;
  402. campos: TStringDynArray;
  403. begin
  404. for synLang in synLangList do begin
  405. if Upcase(ExtractFileNameOnly(synLang.filName)) = Upcase(ExtractFileNameOnly(fil)) then begin
  406. //Encontró al synLang, que corresponde al archivo
  407. campos := Explode(#9, attribLine); //separa campos
  408. //Ahora debe ubicar al atributo que corresponde "attribLine"
  409. for att in synLang.Attributes do begin
  410. if att.GetName = campos[0] then begin
  411. //Encontró al atributo. Ahora lee los parámetros
  412. att.pTextColor.WriteColor(f2I(campos[1]));
  413. att.pBackColor.WriteColor(f2I(campos[2]));
  414. att.pBold.WriteBool (f2B(campos[3]));
  415. att.pItalic.WriteBool (f2B(campos[4]));
  416. att.pUnder.WriteBool (f2B(campos[5]));
  417. end;
  418. end;
  419. //synLang.Attributes;
  420. end;
  421. end;
  422. end;
  423. var
  424. lin, SyntaxInf, fileNam: String;
  425. isSyntaxInf: Boolean;
  426. lineas: TStringList;
  427. begin
  428. lineas:= TStringList.Create;
  429. try
  430. lineas.LoadFromFile(themeFile);
  431. isSyntaxInf := false;
  432. SyntaxInf := '';
  433. for lin in lineas do begin
  434. if copy(lin,1,2) = 'f:' then isSyntaxInf := true;
  435. if lin = '' then isSyntaxInf := false;
  436. if isSyntaxInf then begin
  437. //Es una línea Propiedad
  438. if copy(lin,1,2) = 'f:' then begin
  439. //Es el inicio de un archivo
  440. fileNam := copy(lin, 3);
  441. end else begin
  442. //Debe ser un atributo
  443. SetAttribute(fileNam, lin);
  444. end;
  445. SyntaxInf := SyntaxInf + lin + LineEnding;
  446. end;
  447. end;
  448. finally
  449. lineas.Destroy;
  450. end;
  451. end;
  452. procedure TfraCfgSyntax.ComboBox1Change(Sender: TObject);
  453. var
  454. att: TSynAttribute;
  455. begin
  456. if ComboBox1.ItemIndex = -1 then begin
  457. curLang := nil;
  458. exit;
  459. end;
  460. //Actualiza curSynLang
  461. curLang := synLangList[ComboBox1.ItemIndex];
  462. //Llena las propiedades
  463. ListBox1.Clear;
  464. if curLang.linComplet= 0 then begin
  465. //No tiene inforrmación de completado
  466. chkAutoComp.Enabled := false;
  467. end else begin //Sí tiene completado
  468. chkAutoComp.Enabled := true;
  469. chkAutoComp.Checked := curLang.pOpenOnKeyUp.ReadBool;
  470. end;
  471. //Llena los atributos encontrados
  472. for att in curLang.Attributes do begin
  473. ListBox1.AddItem(att.pName.ReadString, att); //Guarda referencia al objeto
  474. end;
  475. if ListBox1.Count>0 then begin
  476. ListBox1.ItemIndex := 0;
  477. ListBox1Click(self); //Actualiza
  478. end;
  479. end;
  480. procedure TfraCfgSyntax.ListBox1Click(Sender: TObject);
  481. {Se selecciona un atributo de la lista de atributos.}
  482. var
  483. att: TSynAttribute;
  484. Exist: Boolean;
  485. begin
  486. if ListBox1.ItemIndex = -1 then begin
  487. curAttr := nil;
  488. exit;
  489. end;
  490. curAttr := nil; //Se poene en NIl, para evitar disparar eventos en los botones
  491. att := TSynAttribute(ListBox1.Items.Objects[ListBox1.ItemIndex]);
  492. // MsgBox(att.pName.ReadString);
  493. Exist := att.pTextColor.Exist;
  494. colTextCol.Enabled := Exist;
  495. Label2.Enabled := Exist;
  496. if Exist then colTextCol.ButtonColor := att.pTextColor.ReadColor;
  497. Exist := att.pBackColor.Exist;
  498. colBackCol.Enabled := Exist;
  499. Label4.Enabled := Exist;
  500. if Exist then colBackCol.ButtonColor := att.pBackColor.ReadColor;
  501. Exist := att.pBold.Exist;
  502. chkBold.Enabled := Exist;
  503. if Exist then chkBold.Checked := att.pBold.ReadBool;
  504. Exist := att.pItalic.Exist;
  505. chkItalic.Enabled := Exist;
  506. if Exist then chkItalic.Checked := att.pItalic.ReadBool;
  507. Exist := att.pUnder.Exist;
  508. chkUnder.Enabled := Exist;
  509. if Exist then chkUnder.Checked := att.pUnder.ReadBool;
  510. //Actualiza al final "curAttr".
  511. curAttr := att;
  512. end;
  513. function TfraCfgSyntax.AddSyntax(synFile: string): TSynLang;
  514. {Agrega una sintaxis a la lista de sintaxis. Devuelve la referecnia a la sinatxis}
  515. var
  516. synLan: TSynLang;
  517. begin
  518. try
  519. //Agrega sintaxis a la lista
  520. synLan := TSynLang.Create;
  521. synLan.ReadFromFile(synFile);
  522. synLangList.add(synLan);
  523. Result := synLan;
  524. except
  525. Result := nil;
  526. end;
  527. end;
  528. procedure TfraCfgSyntax.LoadSyntaxFiles(pathSyn0: string);
  529. //Carga el contendio de los archivos de sintaxis en "synLangList".
  530. var
  531. directorio, nomArc: String;
  532. SearchRec: TSearchRec;
  533. synt: TSynLang;
  534. begin
  535. pathSyn := pathSyn0;
  536. ComboBox1.Clear;
  537. directorio := pathSyn;
  538. if FindFirst(directorio + DirectorySeparator + '*.xml', faDirectory, SearchRec) = 0 then begin
  539. repeat
  540. nomArc := SysToUTF8(SearchRec.Name);
  541. if SearchRec.Attr and faDirectory = faDirectory then begin
  542. //directorio
  543. end else begin //archivo
  544. //Agrega la sintaxis
  545. synt := AddSyntax(directorio + DirectorySeparator + nomArc);
  546. //Argega nombre de archivo, sin extensión
  547. nomArc := copy(nomArc, 1, length(nomArc)-4); //quita extensión
  548. delete(nomArc,1, 6); //quita parte inicial
  549. ComboBox1.AddItem(synt.pName.ReadString, nil);
  550. end;
  551. until FindNext(SearchRec) <> 0;
  552. //Ya no hay más archivos
  553. FindClose(SearchRec);
  554. end;
  555. //Actualiza
  556. if ComboBox1.Items.Count = 0 then exit;
  557. ComboBox1.ItemIndex := 0;
  558. ComboBox1Change(self);
  559. end;
  560. procedure TfraCfgSyntax.SaveChanges;
  561. var
  562. synLang: TSynLang;
  563. begin
  564. for synLang in synLangList do begin
  565. synLang.SaveToFile;
  566. end;
  567. end;
  568. constructor TfraCfgSyntax.Create(AOwner: TComponent);
  569. begin
  570. inherited Create(AOwner);
  571. synLangList:= TSynLangList.Create(true);
  572. end;
  573. destructor TfraCfgSyntax.Destroy;
  574. begin
  575. synLangList.Destroy;
  576. inherited Destroy;
  577. end;
  578. end.