FormRemoteEditor.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. {Programa ejemplo de uso de la librería para implementar editores "utilEditSyn".
  2. Por Tito Hinostroza 11/07/2014 }
  3. unit FormRemoteEditor;
  4. {$mode objfpc}{$H+}
  5. interface
  6. uses
  7. Classes, SysUtils, FileUtil, LazUTF8, SynEdit, Forms, Controls, Graphics,
  8. Dialogs, Menus, ComCtrls, ActnList, StdActns, SynEditMiscClasses, MisUtils,
  9. Globales, SynFacilUtils, FormRemoteOpenDial, FrameTabSession;
  10. type
  11. // TEditionMode = (
  12. // temLocal, //Edición normal de un archivo local
  13. // temRemSFTP, //Edición remota pro SFTP
  14. // temRemShell //Ediicón remota por comandos SSH (No recomendable)
  15. // );
  16. { TfrmRemoteEditor }
  17. TfrmRemoteEditor = class(TForm)
  18. published
  19. acFilOpen: TAction;
  20. acFilSaveAs: TAction;
  21. acFilSave: TAction;
  22. acFilNew: TAction;
  23. acFilExit: TAction;
  24. acSrchSearch: TAction;
  25. acSrchSearchNext: TAction;
  26. acSrchReplace: TAction;
  27. acEdiCopy: TEditCopy;
  28. acEdiCut: TEditCut;
  29. acEdiPaste: TEditPaste;
  30. acEdiRedo: TAction;
  31. acEdiSelecAll: TAction;
  32. acEdiUndo: TAction;
  33. AcToolSettings: TAction;
  34. ActionList: TActionList;
  35. acViewFilPanel: TAction;
  36. ImageList1: TImageList;
  37. MainMenu1: TMainMenu;
  38. MenuItem1: TMenuItem;
  39. MenuItem10: TMenuItem;
  40. MenuItem11: TMenuItem;
  41. MenuItem12: TMenuItem;
  42. MenuItem13: TMenuItem;
  43. MenuItem14: TMenuItem;
  44. MenuItem15: TMenuItem;
  45. MenuItem16: TMenuItem;
  46. MenuItem18: TMenuItem;
  47. MenuItem19: TMenuItem;
  48. MenuItem20: TMenuItem;
  49. MenuItem21: TMenuItem;
  50. MenuItem22: TMenuItem;
  51. MenuItem24: TMenuItem;
  52. MenuItem25: TMenuItem;
  53. MenuItem26: TMenuItem;
  54. mnLenguaje: TMenuItem;
  55. mnRecents: TMenuItem;
  56. MenuItem17: TMenuItem;
  57. MenuItem2: TMenuItem;
  58. MenuItem23: TMenuItem;
  59. MenuItem3: TMenuItem;
  60. MenuItem4: TMenuItem;
  61. MenuItem5: TMenuItem;
  62. MenuItem6: TMenuItem;
  63. MenuItem7: TMenuItem;
  64. MenuItem8: TMenuItem;
  65. MenuItem9: TMenuItem;
  66. OpenDialog1: TOpenDialog;
  67. PopupMenu1: TPopupMenu;
  68. SaveDialog1: TSaveDialog;
  69. StatusBar1: TStatusBar;
  70. ed: TSynEdit;
  71. ToolBar1: TToolBar;
  72. ToolButton1: TToolButton;
  73. ToolButton10: TToolButton;
  74. ToolButton11: TToolButton;
  75. ToolButton2: TToolButton;
  76. ToolButton3: TToolButton;
  77. ToolButton4: TToolButton;
  78. ToolButton5: TToolButton;
  79. ToolButton6: TToolButton;
  80. ToolButton7: TToolButton;
  81. ToolButton8: TToolButton;
  82. ToolButton9: TToolButton;
  83. acViewStaBar: TAction;
  84. acViewLinNum: TAction;
  85. procedure acFilOpenExecute(Sender: TObject);
  86. procedure acFilSaveAsExecute(Sender: TObject);
  87. procedure acFilSaveExecute(Sender: TObject);
  88. procedure acFilNewExecute(Sender: TObject);
  89. procedure acFilExitExecute(Sender: TObject);
  90. procedure acEdiRedoExecute(Sender: TObject);
  91. procedure acEdiSelecAllExecute(Sender: TObject);
  92. procedure acEdiUndoExecute(Sender: TObject);
  93. procedure AcToolSettingsExecute(Sender: TObject);
  94. procedure ChangeEditorState;
  95. procedure editChangeFileInform;
  96. procedure edSpecialLineMarkup(Sender: TObject; Line: integer;
  97. var Special: boolean; Markup: TSynSelectedColor);
  98. procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
  99. procedure FormCreate(Sender: TObject);
  100. procedure FormDestroy(Sender: TObject);
  101. procedure FormDropFiles(Sender: TObject; const FileNames: array of String);
  102. procedure FormShow(Sender: TObject);
  103. private
  104. ses: TfraTabSession;
  105. edit: TSynFacilEditor;
  106. lineas: TStringList; //lista temporal
  107. localFile, destFile: String; //Rutas de archivo
  108. public
  109. MsjErr: String;
  110. NomArcLocal: string; //nombre de archivo local
  111. procedure Open(destFile0: string);
  112. procedure Init(ses0: TfraTabSession);
  113. end;
  114. var
  115. frmRemoteEditor: TfrmRemoteEditor;
  116. implementation
  117. uses FormPrincipal, FormConfig, Comandos;
  118. {$R *.lfm}
  119. { TfrmRemoteEditor }
  120. procedure TfrmRemoteEditor.FormCreate(Sender: TObject);
  121. begin
  122. InicEditorC1(ed); //inicia editor con configuraciones por defecto
  123. ed.OnSpecialLineMarkup:=@edSpecialLineMarkup; //solo para corregir falla de resaltado de línea actual
  124. edit := TSynFacilEditor.Create(ed,'SinNombre', 'sh');
  125. edit.OnChangeEditorState:=@ChangeEditorState;
  126. edit.OnChangeFileInform:=@editChangeFileInform;
  127. //define paneles
  128. edit.PanFileSaved := StatusBar1.Panels[0]; //panel para mensaje "Guardado"
  129. edit.PanCursorPos := StatusBar1.Panels[1]; //panel para la posición del cursor
  130. edit.PanForEndLin := StatusBar1.Panels[2]; //panel para el tipo de delimitador de línea
  131. edit.PanCodifFile := StatusBar1.Panels[3]; //panel para la codificación del archivo
  132. edit.PanLangName := StatusBar1.Panels[4]; //panel para el nombre del lenguaje
  133. lineas := TStringList.Create;
  134. end;
  135. procedure TfrmRemoteEditor.FormShow(Sender: TObject);
  136. begin
  137. edit.NewFile; //para actualizar estado
  138. mnLenguaje.Clear;
  139. edit.InitMenuLanguages(mnLenguaje, patSyntax);
  140. edit.LoadSyntaxFromPath; //para que busque el archivo apropiado
  141. edit.InitMenuRecents(mnRecents,nil); //inicia el menú "Recientes"
  142. end;
  143. procedure TfrmRemoteEditor.FormCloseQuery(Sender: TObject; var CanClose: boolean);
  144. var
  145. rpta: Byte;
  146. begin
  147. if edit.Modified then begin //primero pregunta
  148. rpta := MsgYesNoCancel('File modified. Save on Server?');
  149. if rpta = 3 then begin //Cancel
  150. CanClose := false; //no deja cerrar
  151. exit;
  152. end;
  153. if rpta = 1 then begin //Yes
  154. acFilSaveExecute(self); //Primero guarda
  155. end;
  156. end;
  157. //se debe cerrar.
  158. //Limpiar el contenido, ya que solo se ocultará, y no queremos que aparezca el último
  159. //archivo cargado.
  160. edit.NewFile(false);
  161. end;
  162. procedure TfrmRemoteEditor.FormDestroy(Sender: TObject);
  163. begin
  164. lineas.Destroy;
  165. edit.Destroy;
  166. end;
  167. procedure TfrmRemoteEditor.FormDropFiles(Sender: TObject; const FileNames: array of String);
  168. begin
  169. //Carga archivo arrastrados
  170. if edit.SaveQuery then Exit; //Verifica cambios
  171. edit.LoadFile(FileNames[0]);
  172. edit.LoadSyntaxFromPath; //para que busque el archivo apropiado
  173. end;
  174. procedure TfrmRemoteEditor.ChangeEditorState;
  175. begin
  176. acFilSave.Enabled:=edit.Modified;
  177. acEdiUndo.Enabled:=edit.CanUndo;
  178. acEdiRedo.Enabled:=edit.CanRedo;
  179. //Para estas acciones no es necesario controlarlas, porque son acciones pre-determinadas
  180. // acEdiCortar.Enabled := edit.canCopy;
  181. // acEdiCopiar.Enabled := edit.canCopy;
  182. // acEdiPegar.Enabled:= edit.CanPaste;
  183. end;
  184. procedure TfrmRemoteEditor.editChangeFileInform;
  185. begin
  186. //actualiza nombre de archivo
  187. Caption := 'Remote Editor - ' + edit.FileName;
  188. end;
  189. procedure TfrmRemoteEditor.edSpecialLineMarkup(Sender: TObject; Line: integer;
  190. var Special: boolean; Markup: TSynSelectedColor);
  191. begin
  192. //vacío
  193. end;
  194. /////////////////// Acciones de Archivo /////////////////////
  195. procedure TfrmRemoteEditor.acFilNewExecute(Sender: TObject);
  196. begin
  197. edit.NewFile;
  198. edit.LoadSyntaxFromPath; //para que busque el archivo apropiado
  199. end;
  200. procedure TfrmRemoteEditor.acFilOpenExecute(Sender: TObject);
  201. begin
  202. // OpenDialog1.Filter:='Text files|*.txt|All files|*.*';
  203. // edit.OpenDialog(OpenDialog1);
  204. frmRemoteOpenDial.ShowModal;
  205. if frmRemoteOpenDial.archivo <> '' then begin
  206. Open(frmRemoteOpenDial.archivo);
  207. end;
  208. end;
  209. procedure TfrmRemoteEditor.acFilSaveExecute(Sender: TObject);
  210. var
  211. txt: String;
  212. begin
  213. if ses.editMode = edtLocal then begin
  214. //Edición normal en archivo local
  215. edit.SaveFile;
  216. end else if ses.editMode = edtRemotSFTP then begin
  217. if destFile='' then begin
  218. MsgExc('There isn''t a file opened');
  219. exit;
  220. end;
  221. //Modo SFTP
  222. edit.SaveFile; //Guarda localmente
  223. //Transfiere archivo usando la misma IP de la conexión.
  224. ExecSFTP(ses.ftpEditUser, ses.ftpEditPass, ses.ip,
  225. 'lcd "'+ patTemp + '"' + LineEnding +
  226. 'cd "'+ ExtractFileDir(destFile) + '"' + LineEnding +
  227. 'put "' + ExtractFileName(destFile) + '"' + LineEnding +
  228. 'quit');
  229. end else if ses.editMode = edtBashComm then begin
  230. //Modo de puro comandos del shell
  231. txt := edit.Text; //toma texto
  232. {Usa comillas simples para evitar sustitución, porque las comillas simples ponen todo
  233. literalmente. El problema está cuando se quiere imprimir precisamente, comilla simple.
  234. Para ello se debe hacer una sustitución}
  235. ed.Enabled := False;
  236. txt := StringReplace(txt, '''', '''"''"''',[rfReplaceAll]);
  237. if ses<>nil then begin
  238. ses.EnviarComando('echo ''' + txt + ''' > "' + edit.FileName+'"', lineas);
  239. end;
  240. ed.Enabled := True;
  241. //para actualizar controles
  242. edit.Modified:=false; //Este método no es público en la librería original
  243. end;
  244. end;
  245. procedure TfrmRemoteEditor.acFilSaveAsExecute(Sender: TObject);
  246. var
  247. arc0: String;
  248. begin
  249. // edit.SaveAsDialog(SaveDialog1);
  250. if not SaveDialog1.Execute then begin //se canceló
  251. exit; //se canceló
  252. end;
  253. arc0 := SaveDialog1.FileName;
  254. if FileExists(arc0) then begin
  255. if MsgYesNoCancel('File already exists. Overwrite?',[arc0]) in [2,3] then exit;
  256. end;
  257. NomArcLocal := UTF8ToSys(arc0); //asigna nuevo nombre
  258. // if ExtractFileExt(NomArc) = '' then NomArc += '.'+extDef; //completa extensión
  259. edit.SaveFile; //lo guarda
  260. end;
  261. procedure TfrmRemoteEditor.acFilExitExecute(Sender: TObject);
  262. begin
  263. frmRemoteEditor.Close;
  264. end;
  265. //////////// Acciones de Edición ////////////////
  266. procedure TfrmRemoteEditor.acEdiUndoExecute(Sender: TObject);
  267. begin
  268. edit.Undo;
  269. end;
  270. procedure TfrmRemoteEditor.AcToolSettingsExecute(Sender: TObject);
  271. begin
  272. config.Configurar('3');
  273. end;
  274. procedure TfrmRemoteEditor.acEdiRedoExecute(Sender: TObject);
  275. begin
  276. edit.Redo;
  277. end;
  278. procedure TfrmRemoteEditor.acEdiSelecAllExecute(Sender: TObject);
  279. begin
  280. ed.SelectAll;
  281. end;
  282. procedure TfrmRemoteEditor.Open(destFile0: string); //Opcional para archivos locales
  283. //Permite editar un archivo almacenado en un archivo externo
  284. begin
  285. destFile := destFile0; //Guarda archivo abierto
  286. if self.Visible and edit.SaveQuery then Exit; //Verifica cambios
  287. if not self.Visible then self.Show;
  288. if ses.editMode = edtLocal then begin
  289. //Edición normal
  290. edit.LoadFile(destFile);
  291. end else if ses.editMode = edtRemotSFTP then begin //Edición por SFTP
  292. //Crea ruta de archivo local
  293. localFile := patTemp + DirectorySeparator + ExtractFileName(destFile);
  294. //Elimina si ya existe
  295. if FileExists(localFile) then DeleteFile(localFile);
  296. //Trae archivo usando la misma IP de la conexión.
  297. ExecSFTP(ses.ftpEditUser, ses.ftpEditPass, ses.ip,
  298. 'lcd "'+ patTemp + '"' + LineEnding +
  299. 'get ' + destFile + LineEnding +
  300. 'quit');
  301. //Carga archivo local
  302. //edit.Text := StringFromFile(patTemp + DirectorySeparator + localFile);
  303. edit.LoadFile(localFile);
  304. end else if ses.editMode = edtBashComm then begin
  305. //Ediicón por comandos
  306. if ses<>nil then begin
  307. MsjErr := ses.EnviarComando('cat "'+destFile+'"', lineas);
  308. end;
  309. ed.Lines.Clear;
  310. ed.Lines.AddStrings(lineas);
  311. edit.FileName:=destFile;
  312. //para actualizar controles
  313. edit.Modified:=false; //Este método no es público en la librería original)
  314. //para actualizar nombre
  315. edit.ChangeFileInform; //Este método no es público en la librería original)
  316. edit.LoadSyntaxFromPath; //para que busque el archivo apropiado
  317. end;
  318. end;
  319. procedure TfrmRemoteEditor.Init(ses0: TfraTabSession);
  320. {Inicializa parámetros que necesita la herramienta Editor.
  321. Para mostrar el editor se necesita simplemente llamar a .Show }
  322. begin
  323. //Se necesita acceder a la sesión para determinar el modo de edición.
  324. ses := ses0;
  325. end;
  326. end.