TFPET.Mod 93 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908
  1. MODULE TFPET; (** AUTHOR "TF, PL"; PURPOSE "Programmer's Editing Tool"; *)
  2. (**
  3. * Shortcuts:
  4. *
  5. * CTRL-F: Show search panel of current page, set focus to its editor and clear the content of the editor
  6. * CTRL-N: If search panel is visible: Find next occurence downwards
  7. * elsif error grid is visible: Jump to next error position
  8. * CTRL-P: If search panel is visible: Find next occurence upwards
  9. * elsif error grid is visible: Jump to previous error position
  10. *
  11. * CTRL-0: Set cursor to position zero
  12. * CTRL-9: Move cursor to end of text
  13. *
  14. * CTRL-O: Set focus to filename editor and clear its content
  15. * CTRL-S: Store current page
  16. *
  17. * CTRL-M: Toggle visibility of sidepanel
  18. *
  19. * CTRL-H: Compile file opened in current page
  20. * CTRL-U: Unload module opened in current page
  21. * CTRL-D: Diff current tab to file
  22. *
  23. * CTRL-DEL Delete end-of-line whitespace in current page
  24. *
  25. * ALT-INS Uncomment selected code of commented
  26. * ALT-DEL Comment selected code
  27. *
  28. * CTRL-PgUp Load PET state from file
  29. * CTRL-PgDn Save PET state to file
  30. *
  31. * CTRL-SHIFT-Tab Select previous tab
  32. * CTRL-Tab Select next tab
  33. *
  34. * SHIFT-F1..F12 Store current cursor position
  35. * CTRL-F1..F12 Recall cursor position
  36. *
  37. * When the filename editor has the keyboard focus:
  38. *
  39. * ESC Reset filename to filename of currently opened tab
  40. * ENTER Open file
  41. * SHIFT_ENTER Open file in new PET window instance
  42. *)
  43. IMPORT
  44. KernelLog, Modules, Commands, Options, Streams, Inputs, Files, WMRestorable, XML, XMLScanner, XMLParser, XMLObjects,
  45. WMStandardComponents, WMGraphics, CompilerInterface,
  46. WMComponents, WMRectangles, WMMessages, WMDialogs,
  47. WMTextView, WMEditors, Strings, TextUtilities, Texts,
  48. WMWindowManager, WMGrids, WMMacros, WMPopups, WMDropTarget, WMDiagnostics,
  49. PETTrees, Configuration, Codecs, WMTabComponents, UndoManager, WMSearchComponents, WhitespaceRemover,
  50. TFModuleTrees;
  51. CONST
  52. WindowWidth = 800; WindowHeight = 600;
  53. (* Default Settings for all PET instances *)
  54. (* backup levels when storing a file *)
  55. No = 0; (* don't create backup file *)
  56. Yes = 1; (* create backup file *)
  57. Paranoid = 2; (* create backup file for each store *)
  58. (* General *)
  59. DefaultBackupOnStore = No;
  60. DefaultBackupOnCompile = FALSE;
  61. DefaultShowPathInTabs = FALSE;
  62. DefaultScratchPanelHeight = 250;
  63. DefaultEnableWhitespaceWarnings = FALSE;
  64. DefaultShowLineNumbers = FALSE;
  65. DefaultIndicateTabs = FALSE;
  66. DefaultCurrentLineColor = 0;
  67. (* Compiler *)
  68. DefaultCompilerName = "Fox";
  69. DefaultCompilerCaption = "Compile";
  70. DefaultCompilerOptions = "-b=AMD --warnings";
  71. DefaultCompilerLoadModule = "Compiler";
  72. DefaultCompilerFileExtension = "MOD";
  73. DefaultCompilerFindPC = TRUE;
  74. (* Diff *)
  75. (* The Diff shortcurt will use the DiffCommand to compare the file currently opened in PET to a file specified by the user... *)
  76. DefaultDiffCommand = "WMDiff.Open";
  77. (* PET will suggest a filename based on the following constants: *)
  78. DefaultDiffPrefix = ""; (* Add this string as prefix to the current filename (e.g. path) *)
  79. DefaultDiffSuffix = ".Bak"; (* Add this string as suffix to the current filename (e.g. ".Bak") *)
  80. (* Search *)
  81. DefaultSearchWrap = FALSE;
  82. DefaultSearchCaseSensitive = TRUE;
  83. DefaultSearchHighlightAll = FALSE;
  84. (* If you really don't like any shortcuts, disable them! *)
  85. DisableShortcuts = FALSE;
  86. BackupOnCompileFilename = "PETBackup.Mod.Bak";
  87. ScratchTextFilename = "PETScratch.Text";
  88. StateFileExtension = ".pet";
  89. SearchStringMaxLen = 128;
  90. MaxNbrOfTabs = 100;
  91. MaxNbrOfCompilers = 8;
  92. WindowTitle = "TF Programmer's Editing Tool v2.1";
  93. DefaultTextFormat = "UTF-8";
  94. EditorFocus = 1;
  95. SplitEditorFocus = 2;
  96. TYPE
  97. CompilerOptions = ARRAY 256 OF CHAR;
  98. Filename = ARRAY 256 OF CHAR;
  99. String = ARRAY 128 OF CHAR;
  100. SearchString = ARRAY SearchStringMaxLen OF CHAR;
  101. TYPE
  102. CompilerSettings = RECORD
  103. name : ARRAY 32 OF CHAR; (* name of compiler (same as in CompilerInterface) *)
  104. caption : ARRAY 16 OF CHAR; (* Caption of "compile" button *)
  105. options : CompilerOptions; (* default compiler options *)
  106. fileExtension : ARRAY 16 OF CHAR; (* file extension *)
  107. loadmodule : Filename; (* module to be loaded to register compiler at CompilerInterface *)
  108. genTree : ARRAY 128 OF CHAR; (* Factory procedure to generate a sidepanel tree *)
  109. findPC : BOOLEAN; (* Use Find PC button? *)
  110. END;
  111. (* Global PET settings for all window instances *)
  112. Settings = OBJECT
  113. VAR
  114. (* General *)
  115. backupOnStore : LONGINT; (* No | Yes | Always *)
  116. backupOnCompile : BOOLEAN;
  117. showPathInTabs : BOOLEAN;
  118. scratchPanelHeight : LONGINT;
  119. enableWhitespaceWarnings : BOOLEAN;
  120. showLineNumbers : BOOLEAN;
  121. indicateTabs : BOOLEAN;
  122. currentLineColor : LONGINT;
  123. (* Compiler *)
  124. defaultCompilerOptions : CompilerOptions;
  125. defaultCompilerSettings : CompilerSettings;
  126. compilers : ARRAY MaxNbrOfCompilers OF CompilerSettings;
  127. nofCompilers : LONGINT;
  128. (* Diff *)
  129. diffCommand, diffPrefix, diffSuffix : String;
  130. (* Search *)
  131. searchWrap, searchHighlightAll, searchCaseSensitive : BOOLEAN;
  132. (* Initialize settings to default values *)
  133. PROCEDURE &Init*;
  134. BEGIN
  135. (* General *)
  136. backupOnStore := DefaultBackupOnStore;
  137. backupOnCompile := DefaultBackupOnCompile;
  138. showPathInTabs := DefaultShowPathInTabs;
  139. scratchPanelHeight := DefaultScratchPanelHeight;
  140. enableWhitespaceWarnings := DefaultEnableWhitespaceWarnings;
  141. showLineNumbers := DefaultShowLineNumbers;
  142. indicateTabs := DefaultIndicateTabs;
  143. currentLineColor := DefaultCurrentLineColor;
  144. (* Compiler *)
  145. COPY(DefaultCompilerOptions, defaultCompilerOptions);
  146. nofCompilers := 0;
  147. defaultCompilerSettings.name := DefaultCompilerName;
  148. defaultCompilerSettings.caption := DefaultCompilerCaption;
  149. defaultCompilerSettings.options := DefaultCompilerOptions;
  150. defaultCompilerSettings.fileExtension := DefaultCompilerFileExtension;
  151. defaultCompilerSettings.loadmodule := DefaultCompilerLoadModule;
  152. defaultCompilerSettings.genTree := "";
  153. defaultCompilerSettings.findPC := DefaultCompilerFindPC;
  154. (* Diff *)
  155. diffCommand := DefaultDiffCommand; diffPrefix := DefaultDiffPrefix; diffSuffix := DefaultDiffSuffix;
  156. (* Search *)
  157. searchWrap := DefaultSearchWrap; searchCaseSensitive := DefaultSearchCaseSensitive; searchHighlightAll := DefaultSearchHighlightAll;
  158. END Init;
  159. PROCEDURE GetCompilerSettings(CONST filename : ARRAY OF CHAR) : CompilerSettings;
  160. VAR settings : CompilerSettings; i : LONGINT; extension : ARRAY 16 OF CHAR;
  161. BEGIN
  162. settings := defaultCompilerSettings;
  163. i := 0;
  164. LOOP
  165. IF (i >= nofCompilers) THEN (* no compiler found *) EXIT; END;
  166. extension := ".";
  167. Strings.Append(extension, compilers[i].fileExtension);
  168. IF ContainsFileExtension(filename, extension) THEN (* found *) EXIT; END;
  169. INC(i);
  170. END;
  171. IF (i < nofCompilers) THEN (* found *)
  172. settings := compilers[i];
  173. END;
  174. RETURN settings;
  175. END GetCompilerSettings;
  176. PROCEDURE LoadCompilerSettings;
  177. VAR
  178. element, e : XML.Element;
  179. sectionEnumerator : XMLObjects.Enumerator;
  180. p : ANY; string : XML.String;
  181. PROCEDURE GetAttributeValue(element : XML.Element; CONST attributeName : ARRAY OF CHAR; VAR value : ARRAY OF CHAR);
  182. VAR attribute : XML.Attribute;
  183. BEGIN
  184. ASSERT(element # NIL);
  185. COPY("", value);
  186. attribute := element.GetAttribute(attributeName);
  187. IF (attribute # NIL) THEN
  188. string := attribute.GetValue();
  189. IF (string # NIL) THEN
  190. COPY(string^, value);
  191. END;
  192. END;
  193. END GetAttributeValue;
  194. PROCEDURE ParseCompilerSettings(element : XML.Element; VAR settings : CompilerSettings);
  195. VAR enumerator : XMLObjects.Enumerator; e : XML.Element; p : ANY; string : XML.String; value : ARRAY 64OF CHAR;
  196. BEGIN
  197. ASSERT(element # NIL);
  198. GetAttributeValue(element, "name", value);
  199. IF (value # "") THEN
  200. COPY(value, settings.name);
  201. enumerator := element.GetContents();
  202. WHILE enumerator.HasMoreElements() DO
  203. p := enumerator.GetNext();
  204. IF (p IS XML.Element) THEN
  205. e := p (XML.Element);
  206. string := e.GetName();
  207. IF (string # NIL) & (string^ = "Setting") THEN
  208. GetAttributeValue(e, "name", value);
  209. IF (value = "caption") THEN
  210. GetAttributeValue(e, "value", settings.caption);
  211. IF (settings.caption = "") THEN settings.caption := "Action"; END;
  212. ELSIF (value = "options") THEN
  213. GetAttributeValue(e, "value", settings.options);
  214. ELSIF (value = "fileExtension") THEN
  215. GetAttributeValue(e, "value", settings.fileExtension);
  216. ELSIF (value = "loadmodule") THEN
  217. GetAttributeValue(e, "value", settings.loadmodule);
  218. ELSIF (value = "genTree") THEN
  219. GetAttributeValue(e, "value", value);
  220. Strings.TrimWS(value);
  221. COPY(value, settings.genTree);
  222. ELSIF (value = "findPC") THEN
  223. GetAttributeValue(e, "value", value);
  224. Strings.UpperCase(value); Strings.TrimWS(value);
  225. settings.findPC := (value = "TRUE");
  226. ELSE
  227. KernelLog.String("PET: Warning: Unknown compiler setting '");
  228. KernelLog.String(value); KernelLog.String("'"); KernelLog.Ln;
  229. END;
  230. ELSE
  231. KernelLog.String("PET: Warning: Expected 'Setting' element."); KernelLog.Ln;
  232. END;
  233. END;
  234. END;
  235. END;
  236. END ParseCompilerSettings;
  237. BEGIN
  238. element := Configuration.GetSection("Applications.PET.Compilers");
  239. IF (element # NIL) THEN
  240. sectionEnumerator := element.GetContents();
  241. WHILE sectionEnumerator.HasMoreElements() DO
  242. p := sectionEnumerator.GetNext();
  243. IF (p IS XML.Element) THEN
  244. e := p (XML.Element);
  245. string := e.GetName();
  246. IF (string # NIL) & (string^ = "Section") THEN (* sanity check *)
  247. IF (nofCompilers < LEN(compilers)) THEN
  248. ParseCompilerSettings(e, compilers[nofCompilers]);
  249. INC(nofCompilers);
  250. ELSE
  251. KernelLog.String("PET: Warning: Maximum number of compiler settings exceeded."); KernelLog.Ln;
  252. END;
  253. ELSE
  254. KernelLog.String("PET: Warning: Expected 'Section' element."); KernelLog.Ln;
  255. END;
  256. END;
  257. END;
  258. END;
  259. END LoadCompilerSettings;
  260. (* Load settings from system configuration database *)
  261. PROCEDURE Load;
  262. VAR string : String; temp: LONGINT; res: WORD;
  263. BEGIN
  264. (* General *)
  265. Configuration.Get("Applications.PET.General.BackupOnStore", string, res);
  266. Strings.TrimWS(string);
  267. Strings.LowerCase(string);
  268. IF (string = "yes") THEN backupOnStore := Yes;
  269. ELSIF (string = "no") THEN backupOnStore := No;
  270. ELSIF (string = "paranoid") THEN backupOnStore := Paranoid;
  271. ELSE
  272. KernelLog.String("Warning: PET.Settings.Load: BackupOnStore # Yes | No | Paranoid, using default."); KernelLog.Ln;
  273. backupOnStore := DefaultBackupOnStore;
  274. END;
  275. IF (backupOnStore < No) OR (Paranoid < backupOnStore) THEN backupOnStore := DefaultBackupOnStore; END;
  276. Configuration.GetBoolean("Applications.PET.General.BackupOnCompile", backupOnCompile, res);
  277. Configuration.GetBoolean("Applications.PET.General.ShowPathInTabs", showPathInTabs, res);
  278. Configuration.GetInteger("Applications.PET.General.ScratchPanelHeight", scratchPanelHeight, res);
  279. Configuration.GetBoolean("Applications.PET.General.EnableWhitespaceWarnings", enableWhitespaceWarnings, res);
  280. Configuration.GetBoolean("Applications.PET.General.ShowLineNumbers", showLineNumbers, res);
  281. Configuration.GetBoolean("Applications.PET.General.IndicateTabs", indicateTabs, res);
  282. Configuration.GetColor("Applications.PET.General.CurrentLineColor", temp, res);
  283. IF (res = Configuration.Ok) THEN
  284. currentLineColor := temp
  285. END;
  286. (* Compiler *)
  287. Configuration.Get("Applications.PET.Compilers.DefaultOptions", defaultCompilerOptions, res);
  288. LoadCompilerSettings;
  289. (* Diff *)
  290. Configuration.Get("Applications.PET.Diff.Command", diffCommand, res);
  291. Configuration.Get("Applications.PET.Diff.Prefix", diffPrefix, res);
  292. Configuration.Get("Applications.PET.Diff.Suffix", diffSuffix, res);
  293. (* Search *)
  294. Configuration.GetBoolean("Applications.PET.Search.Wrap", searchWrap, res);
  295. Configuration.GetBoolean("Applications.PET.Search.CaseSensitive", searchCaseSensitive, res);
  296. Configuration.GetBoolean("Applications.PET.Search.HighlightAll", searchHighlightAll, res);
  297. END Load;
  298. END Settings;
  299. TYPE
  300. CaptionObject = OBJECT
  301. VAR caption : ARRAY 128 OF CHAR;
  302. PROCEDURE &New*(CONST caption: ARRAY OF CHAR);
  303. BEGIN
  304. COPY(caption, SELF.caption);
  305. END New;
  306. END CaptionObject;
  307. TYPE
  308. (* Association between a text position and a key combination *)
  309. Position = OBJECT
  310. VAR
  311. marker : WMTextView.PositionMarker;
  312. ucs, keysym : LONGINT; flags : SET;
  313. next : Position;
  314. PROCEDURE &Init*(ucs, keysym : LONGINT; flags : SET);
  315. BEGIN
  316. SELF.ucs := ucs; SELF.keysym := keysym; SELF.flags := flags;
  317. marker := NIL; next := NIL;
  318. END Init;
  319. END Position;
  320. (* Store and Recall cursor positions in the main editor. Flags are ignored for now *)
  321. Positions = OBJECT
  322. VAR
  323. textView : WMTextView.TextView;
  324. positions : Position;
  325. PROCEDURE &Init*(textView : WMTextView.TextView);
  326. BEGIN
  327. ASSERT(textView # NIL);
  328. SELF.textView := textView;
  329. END Init;
  330. PROCEDURE FindPosition(ucs, keysym : LONGINT; flags : SET) : Position;
  331. VAR p : Position;
  332. BEGIN
  333. p := positions;
  334. WHILE (p # NIL) & ~((p.ucs = ucs) & (p.keysym = keysym) & (p.flags = flags)) DO
  335. p := p.next;
  336. END;
  337. RETURN p;
  338. END FindPosition;
  339. (* Associate current cursor position with the spec ified key combination. *)
  340. PROCEDURE StoreCurrentPosition(ucs, keysym : LONGINT; flags : SET);
  341. VAR newPosition : Position; intPos : LONGINT;
  342. BEGIN
  343. ASSERT(flags * { Inputs.Release} = {});
  344. newPosition := FindPosition(ucs, keysym, flags);
  345. IF (newPosition = NIL) THEN
  346. NEW(newPosition, ucs, keysym, flags);
  347. newPosition.marker := textView.CreatePositionMarker();
  348. newPosition.marker.SetVisible(FALSE);
  349. newPosition.next := positions;
  350. positions := newPosition;
  351. END;
  352. intPos := textView.GetInternalPos(textView.cursor.GetPosition());
  353. newPosition.marker.SetPosition(intPos);
  354. END StoreCurrentPosition;
  355. PROCEDURE RecallPosition(ucs, keysym : LONGINT; flags : SET);
  356. VAR position : Position;
  357. BEGIN
  358. position := FindPosition(ucs, keysym, flags);
  359. IF (position # NIL) THEN
  360. textView.cursor.SetPosition(position.marker.GetPosition());
  361. END;
  362. END RecallPosition;
  363. END Positions;
  364. TYPE
  365. ScratchPanel = OBJECT(WMComponents.VisualComponent)
  366. VAR
  367. editor : WMEditors.Editor;
  368. label : WMStandardComponents.Label;
  369. PROCEDURE &Init*;
  370. BEGIN
  371. Init^;
  372. SetNameAsString(StrScratchPanel);
  373. NEW(label); label.alignment.Set(WMComponents.AlignTop); label.bounds.SetHeight(20);
  374. label.fillColor.Set(0CCCCCCFFH); label.caption.SetAOC(" Scratch Text");
  375. AddContent(label);
  376. NEW(editor); editor.alignment.Set(WMComponents.AlignClient);
  377. editor.tv.showBorder.Set(TRUE);
  378. AddContent(editor);
  379. editor.SetText(scratchText)
  380. END Init;
  381. PROCEDURE SetText(text : Texts.Text);
  382. BEGIN
  383. ASSERT(text # NIL);
  384. editor.SetText(text);
  385. label.caption.SetAOC(" Project Text");
  386. END SetText;
  387. PROCEDURE Finalize*;
  388. BEGIN
  389. Finalize^;
  390. StoreScratchText;
  391. END Finalize;
  392. END ScratchPanel;
  393. URLDropTarget = OBJECT(WMDropTarget.DropTarget);
  394. VAR win : Window;
  395. PROCEDURE &New*(win : Window);
  396. BEGIN
  397. SELF.win := win
  398. END New;
  399. PROCEDURE GetInterface*(type : LONGINT) : WMDropTarget.DropInterface;
  400. VAR di : DropURL;
  401. BEGIN
  402. IF type = WMDropTarget.TypeURL THEN
  403. NEW(di, SELF.win);
  404. RETURN di
  405. ELSE RETURN NIL
  406. END
  407. END GetInterface;
  408. END URLDropTarget;
  409. DropURL = OBJECT(WMDropTarget.DropURLs)
  410. VAR win : Window;
  411. PROCEDURE &New*(win: Window);
  412. BEGIN
  413. SELF.win := win;
  414. END New;
  415. PROCEDURE URL*(CONST url : ARRAY OF CHAR; VAR res : WORD);
  416. BEGIN
  417. win.Load(url, "AUTO");
  418. res := 0
  419. END URL;
  420. END DropURL;
  421. TYPE
  422. PETPanel = OBJECT(WMComponents.VisualComponent)
  423. VAR
  424. editor, splitEditor : WMEditors.Editor;
  425. logEdit : WMEditors.Editor;
  426. scratchPanel, splitPanel : WMStandardComponents.Panel;
  427. scratch : ScratchPanel;
  428. sidePanel : WMStandardComponents.Panel;
  429. logPanel, editPanel: WMStandardComponents.Panel;
  430. searchPanel: WMSearchComponents.SearchPanel;
  431. errorGrid : WMDiagnostics.DiagnosticsView;
  432. diagnostics : WMDiagnostics.Model;
  433. tree : PETTrees.Tree;
  434. modified, splitted, wrap: BOOLEAN;
  435. focus : LONGINT;
  436. codecFormat: ARRAY 128 OF CHAR;
  437. autoCodecFormat: ARRAY 128 OF CHAR;
  438. name : Filename; (* name of tab (filename without path *)
  439. filename : Filename; (* Filename including path *)
  440. options : CompilerOptions;
  441. compilerSettings : CompilerSettings;
  442. showErrorMarkers : BOOLEAN;
  443. positions : Positions;
  444. owner : Window;
  445. PROCEDURE &InitPanel *(window: Window);
  446. VAR
  447. resizerH, resizerV: WMStandardComponents.Resizer;
  448. um: UndoManager.UndoManager;
  449. colWidths : WMGrids.Spacings;
  450. textViews : ARRAY 2 OF WMTextView.TextView;
  451. BEGIN
  452. Init;
  453. owner := window;
  454. tree := NIL;
  455. SetNameAsString(StrPETPanel);
  456. showErrorMarkers := TRUE;
  457. COPY("Untitled.Mod", filename);
  458. COPY("Untitled.Mod", name);
  459. (* -- left tool area *)
  460. NEW(sidePanel);
  461. sidePanel.bounds.SetWidth(250); sidePanel.alignment.Set(WMComponents.AlignLeft);
  462. AddContent(sidePanel);
  463. NEW(resizerH); resizerH.alignment.Set(WMComponents.AlignRight);
  464. resizerH.bounds.SetWidth(4);
  465. sidePanel.AddContent(resizerH);
  466. (* scratch panel *)
  467. NEW(scratchPanel);
  468. scratchPanel.bounds.SetHeight(250); scratchPanel.alignment.Set(WMComponents.AlignBottom);
  469. NEW(resizerV); resizerV.alignment.Set(WMComponents.AlignTop);
  470. resizerV.bounds.SetHeight(4);
  471. scratchPanel.AddContent(resizerV);
  472. NEW(scratch); scratch.alignment.Set(WMComponents.AlignClient);
  473. scratch.editor.tv.commandCaller := window;
  474. scratchPanel.AddContent(scratch);
  475. sidePanel.AddContent(scratchPanel);
  476. (* -- Editor Area *)
  477. NEW(editPanel); editPanel.alignment.Set(WMComponents.AlignClient);
  478. AddContent(editPanel);
  479. NEW(logPanel);
  480. logPanel.alignment.Set(WMComponents.AlignBottom);
  481. logPanel.bounds.SetHeight(130);
  482. NEW(resizerH); resizerH.alignment.Set(WMComponents.AlignTop);
  483. resizerH.bounds.SetHeight(4);
  484. logPanel.AddContent(resizerH);
  485. NEW(logEdit); logEdit.bounds.SetHeight(30); logEdit.alignment.Set(WMComponents.AlignBottom);
  486. logEdit.allowScrollbars.Set(FALSE);
  487. logEdit.tv.showBorder.Set(TRUE); logEdit.visible.Set(FALSE);
  488. NEW(resizerV); resizerV.alignment.Set(WMComponents.AlignTop);
  489. resizerV.bounds.SetHeight(4);
  490. logEdit.AddContent(resizerV);
  491. editPanel.AddContent(logEdit);
  492. editPanel.AddContent(logPanel);
  493. NEW(diagnostics);
  494. NEW(errorGrid);
  495. errorGrid.SetModel(diagnostics);
  496. errorGrid.alignment.Set(WMComponents.AlignClient);
  497. errorGrid.nofCols.Set(3);
  498. errorGrid.fixedRows.Set(1);
  499. errorGrid.adjustFocusPosition.Set(FALSE);
  500. NEW(colWidths, 3);
  501. colWidths[0] := 60;
  502. colWidths[1] := 40;
  503. colWidths[2] := 2048;
  504. errorGrid.SetColSpacings(colWidths);
  505. errorGrid.onClick.Add(ErrorClick);
  506. errorGrid.SetSelectionMode(WMGrids.GridSelectSingleRow);
  507. errorGrid.visible.Set(FALSE);
  508. logPanel.AddContent(errorGrid);
  509. NEW(searchPanel);
  510. searchPanel.alignment.Set(WMComponents.AlignBottom);
  511. searchPanel.bounds.SetHeight(40); searchPanel.visible.Set(FALSE);
  512. editPanel.AddContent(searchPanel);
  513. NEW(splitPanel);
  514. splitPanel.alignment.Set(WMComponents.AlignBottom);
  515. splitPanel.bounds.SetHeight(400);
  516. editPanel.AddContent(splitPanel);
  517. NEW(editor); editor.alignment.Set(WMComponents.AlignClient); editor.tv.showBorder.Set(TRUE);
  518. editor.tv.SetExtFocusHandler(EditorFocusHandler);
  519. editPanel.AddContent(editor);
  520. editor.macros.Add(WMMacros.Handle);
  521. editor.multiLine.Set(TRUE);
  522. editor.tv.wrapMode.Set(WMTextView.NoWrap);
  523. editor.tv.onCursorChanged := CursorChanged;
  524. editor.tv.commandCaller := window;
  525. editor.text.onTextChanged.Add(TextChanged);
  526. editor.tv.showLineNumbers.Set(settings.showLineNumbers);
  527. editor.tv.indicateTabs.Set(settings.indicateTabs);
  528. editor.tv.clBgCurrentLine.Set(settings.currentLineColor);
  529. NEW(positions, editor.tv);
  530. searchPanel.SetText(editor.text);
  531. NEW(resizerV);
  532. resizerV.bounds.SetHeight(5); resizerV.alignment.Set(WMComponents.AlignTop);
  533. resizerV.fillColor.Set(0808080FFH);
  534. splitPanel.AddContent(resizerV);
  535. NEW(splitEditor); splitEditor.alignment.Set(WMComponents.AlignClient); splitEditor.tv.showBorder.Set(TRUE);
  536. splitEditor.tv.SetExtFocusHandler(SplitEditorFocusHandler);
  537. splitPanel.AddContent(splitEditor);
  538. splitEditor.macros.Add(WMMacros.Handle);
  539. splitEditor.multiLine.Set(TRUE);
  540. splitEditor.tv.wrapMode.Set(WMTextView.NoWrap);
  541. splitEditor.tv.commandCaller := window;
  542. splitEditor.SetText(editor.text);
  543. splitEditor.tv.showLineNumbers.Set(settings.showLineNumbers);
  544. splitEditor.tv.indicateTabs.Set(settings.indicateTabs);
  545. splitEditor.tv.clBgCurrentLine.Set(settings.currentLineColor);
  546. textViews[0] := editor.tv;
  547. textViews[1] := splitEditor.tv;
  548. errorGrid.SetTextViews(textViews);
  549. logPanel.visible.Set(FALSE);
  550. splitPanel.visible.Set(FALSE);
  551. modified := FALSE;
  552. splitted := FALSE;
  553. wrap := FALSE;
  554. codecFormat := "AUTO";
  555. autoCodecFormat := DefaultTextFormat;
  556. options := settings.defaultCompilerOptions;
  557. NEW(um, 1001, TRUE);
  558. editor.text.SetUndoManager(um);
  559. editor.SetUndoManager(um);
  560. END InitPanel;
  561. PROCEDURE CreateSidePanel(settings : CompilerSettings);
  562. VAR factory : PETTrees.Factory; strings : Strings.StringArray;
  563. BEGIN
  564. IF (tree # NIL) THEN sidePanel.RemoveContent(tree); tree := NIL END;
  565. IF settings.fileExtension = "MOD" THEN
  566. GETPROCEDURE("TFModuleTrees", "GenModuleTree", factory);
  567. IF (factory # NIL) THEN
  568. tree := factory();
  569. END
  570. ELSE
  571. IF (settings.genTree # "") THEN
  572. strings := Strings.Split(settings.genTree, ".");
  573. IF (LEN(strings) = 2) THEN
  574. GETPROCEDURE(strings[0]^, strings[1]^, factory);
  575. IF (factory # NIL) THEN
  576. tree := factory();
  577. END;
  578. END
  579. END
  580. END;
  581. IF (tree # NIL) THEN
  582. tree.alignment.Set(WMComponents.AlignClient);
  583. tree.SetEditor(editor);
  584. tree.onExpandNode.Add(OnNodeExpand);
  585. tree.onGoToFile.Add(OnGoToFile);
  586. tree.onGoToDefinition.Add(OnGoToDefinition);
  587. tree.onRefresh.Add(HandleTreeRefresh);
  588. sidePanel.AddContent(tree);
  589. tree.RefreshHandler(NIL, NIL);
  590. sidePanel.visible.Set(TRUE);
  591. ELSE
  592. sidePanel.visible.Set(FALSE);
  593. scratchPanel.alignment.Set(WMComponents.AlignClient);
  594. scratchPanel.bounds.Set(sidePanel.bounds.Get());
  595. END;
  596. END CreateSidePanel;
  597. PROCEDURE OnGoToFile(sender, data : ANY);
  598. VAR info : PETTrees.ExternalInfo; file : Files.File; filename : Files.FileName;
  599. BEGIN
  600. IF (data # NIL) & (data IS PETTrees.ExternalInfo) THEN
  601. info := data (PETTrees.ExternalInfo);
  602. COPY(info.filename, filename); Strings.Append(filename, ".Mod");
  603. file := Files.Old(filename);
  604. IF (file # NIL) THEN
  605. owner.GotoFile(filename, info.position);
  606. END;
  607. END;
  608. END OnGoToFile;
  609. PROCEDURE OnGoToDefinition(sender, data : ANY);
  610. VAR info : PETTrees.ExternalDefinitionInfo;
  611. BEGIN
  612. IF (data # NIL) & (data IS PETTrees.ExternalDefinitionInfo) THEN
  613. info := data (PETTrees.ExternalDefinitionInfo);
  614. owner.GotoDefinition(info);
  615. END;
  616. END OnGoToDefinition;
  617. PROCEDURE OnNodeExpand (sender, data: ANY);
  618. BEGIN
  619. IF (tree # NIL) THEN tree.SelectNodeByPos (editor.tv.cursor.GetPosition()) END
  620. END OnNodeExpand;
  621. PROCEDURE HandleTreeRefresh(sender, data : ANY);
  622. BEGIN
  623. END HandleTreeRefresh;
  624. PROCEDURE ClearLog;
  625. BEGIN
  626. logEdit.text.AcquireWrite;
  627. logEdit.text.Delete(0, logEdit.text.GetLength());
  628. logEdit.tv.firstLine.Set(0); logEdit.tv.cursor.SetPosition(0);
  629. logEdit.text.ReleaseWrite;
  630. END ClearLog;
  631. PROCEDURE DoCompile(findPC : BOOLEAN; CONST pc :ARRAY OF CHAR; options : CompilerOptions);
  632. VAR
  633. compiler : CompilerInterface.Compiler; tw : TextUtilities.TextWriter; errors : BOOLEAN;
  634. positions : ARRAY 2 OF LONGINT;
  635. type : LONGINT;
  636. BEGIN
  637. ClearLog;
  638. IF findPC THEN Strings.Append(options, " /f") END;
  639. NEW(tw, logEdit.text);
  640. diagnostics.DisableNotification;
  641. diagnostics.Clear;
  642. compiler := CompilerInterface.GetCompilerByName(compilerSettings.name);
  643. IF (compiler = NIL) & (compilerSettings.loadmodule # "") THEN
  644. LoadModule(compilerSettings.loadmodule); (* compiler shall register itself at the CompilerInterface *)
  645. compiler := CompilerInterface.GetCompilerByName(compilerSettings.name);
  646. END;
  647. IF (compiler # NIL) THEN
  648. compiler.CompileText(editor.text, "", 0, pc, options, tw, diagnostics, errors);
  649. IF ~errors THEN
  650. IF tree IS TFModuleTrees.ModuleTree THEN
  651. (* tree(TFModuleTrees.ModuleTree).StoreSymbols(NIL, NIL);*)
  652. END
  653. END;
  654. ELSE
  655. tw.String("No compiler available for file '"); tw.String(filename); tw.String("'");
  656. logPanel.visible.Set(TRUE);
  657. END;
  658. tw.Update;
  659. IF settings.enableWhitespaceWarnings THEN
  660. WhitespaceRemover.CheckWhitespace(editor.text, diagnostics);
  661. END;
  662. diagnostics.EnableNotification;
  663. IF (diagnostics.nofEntries > 0) THEN
  664. errorGrid.GetFirstPosition(positions, type);
  665. IF (focus = EditorFocus) & (positions[0] # Streams.Invalid) THEN
  666. editor.tv.cursor.SetPosition(positions[0]);
  667. editor.SetFocus;
  668. ELSIF (focus = SplitEditorFocus) THEN
  669. splitEditor.tv.cursor.SetPosition(positions[0]);
  670. splitEditor.SetFocus;
  671. END;
  672. CursorChanged;
  673. errorGrid.visible.Set(TRUE);
  674. logPanel.visible.Set(TRUE); logEdit.visible.Set(TRUE);
  675. ELSE
  676. logPanel.visible.Set(FALSE); logEdit.visible.Set(TRUE);
  677. errorGrid.visible.Set(FALSE);
  678. END;
  679. END DoCompile;
  680. PROCEDURE ErrorClick(sender, data : ANY);
  681. VAR
  682. focusEditor: WMEditors.Editor;
  683. entry : WMDiagnostics.ViewEntry;
  684. index: LONGINT;
  685. BEGIN
  686. IF (data # NIL) & (data IS WMDiagnostics.CellInfo) & (data(WMDiagnostics.CellInfo).entryValid) THEN
  687. IF (focus = EditorFocus) THEN focusEditor := editor; index := 0;
  688. ELSIF (focus = SplitEditorFocus) THEN focusEditor := splitEditor; index := 1;
  689. ELSE
  690. HALT(99);
  691. END;
  692. entry := data(WMDiagnostics.CellInfo).entry;
  693. IF (entry.pos # NIL) & (LEN(entry.pos) = 2) & (entry.pos[index] # NIL) THEN
  694. focusEditor.tv.selection.SetFromTo(0, 0);
  695. focusEditor.tv.cursor.SetPosition(entry.pos[index].GetPosition());
  696. focusEditor.SetFocus;
  697. END;
  698. END;
  699. END ErrorClick;
  700. PROCEDURE GoToNextError(forward : BOOLEAN);
  701. VAR nearestPosition, row, index : LONGINT; focusEditor: WMEditors.Editor;
  702. BEGIN
  703. IF focus = EditorFocus THEN focusEditor := editor; index := 0;
  704. ELSIF focus = SplitEditorFocus THEN focusEditor := splitEditor; index := 1;
  705. ELSE RETURN;
  706. END;
  707. focusEditor.tv.selection.SetFromTo(0, 0);
  708. errorGrid.GetNearestPosition(editor.tv.cursor.GetPosition(), index, forward, nearestPosition, row);
  709. editor.tv.cursor.SetPosition(nearestPosition);
  710. errorGrid.SelectEntry(row, TRUE);
  711. END GoToNextError;
  712. PROCEDURE EditorFocusHandler(hasFocus: BOOLEAN);
  713. BEGIN
  714. IF hasFocus THEN
  715. focus := EditorFocus;
  716. searchPanel.SetTextView(editor.tv);
  717. IF (tree # NIL) THEN tree.SetEditor(editor) END;
  718. END;
  719. END EditorFocusHandler;
  720. PROCEDURE SplitEditorFocusHandler(hasFocus: BOOLEAN);
  721. BEGIN
  722. IF hasFocus THEN
  723. focus := SplitEditorFocus;
  724. searchPanel.SetTextView(splitEditor.tv);
  725. IF (tree # NIL) THEN tree.SetEditor(splitEditor) END;
  726. END
  727. END SplitEditorFocusHandler;
  728. PROCEDURE ToggleLabels;
  729. BEGIN
  730. IF editor.tv.showLabels.Get() THEN
  731. editor.tv.showLabels.Set(FALSE);
  732. splitEditor.tv.showLabels.Set(FALSE);
  733. ELSE
  734. editor.tv.showLabels.Set(TRUE);
  735. splitEditor.tv.showLabels.Set(TRUE);
  736. END;
  737. Invalidate;
  738. END ToggleLabels;
  739. PROCEDURE ToggleWrap;
  740. BEGIN
  741. IF (editor.tv.wrapMode.Get() = WMTextView.WrapWord) THEN
  742. editor.tv.wrapMode.Set(WMTextView.NoWrap);
  743. splitEditor.tv.wrapMode.Set(WMTextView.NoWrap);
  744. ELSE
  745. editor.tv.wrapMode.Set(WMTextView.WrapWord);
  746. splitEditor.tv.wrapMode.Set(WMTextView.WrapWord);
  747. END;
  748. wrap := ~wrap;
  749. END ToggleWrap;
  750. PROCEDURE TextChanged(sender, data : ANY);
  751. BEGIN
  752. IF logPanel.visible.Get() THEN
  753. logPanel.Invalidate
  754. END;
  755. IF ~modified THEN
  756. IF (owner # NIL) THEN owner.SetModified(TRUE) END;
  757. modified := TRUE
  758. END;
  759. CursorChanged
  760. END TextChanged;
  761. PROCEDURE CursorChanged;
  762. VAR position : LONGINT; pos : ARRAY 16 OF CHAR;
  763. BEGIN
  764. position := editor.tv.cursor.GetPosition();
  765. Strings.IntToStr(position, pos);
  766. owner.positionEdit.SetAsString(pos);
  767. IF (tree # NIL) THEN tree.SelectNodeByPos (position) END
  768. END CursorChanged;
  769. PROCEDURE HandleShortcut(ucs : LONGINT; flags : SET; keysym : LONGINT) : BOOLEAN;
  770. VAR pos : LONGINT;
  771. PROCEDURE HandlePreviousNext(forward : BOOLEAN);
  772. BEGIN
  773. IF (focus = EditorFocus) THEN
  774. editor.SetFocus;
  775. ELSE
  776. splitEditor.SetFocus;
  777. END;
  778. IF searchPanel.visible.Get() THEN
  779. searchPanel.HandlePreviousNext(forward);
  780. ELSIF errorGrid.visible.Get() THEN
  781. GoToNextError(forward);
  782. END;
  783. CursorChanged;
  784. END HandlePreviousNext;
  785. PROCEDURE HandleDiff;
  786. VAR
  787. filename, string : Filename; context : Commands.Context; res : WORD;
  788. arg : Streams.StringReader;
  789. BEGIN
  790. IF (settings.diffCommand = "") THEN
  791. WMDialogs.Error(WindowTitle, "No diff command specified");
  792. RETURN;
  793. END;
  794. COPY(settings.diffPrefix, filename);
  795. Strings.Append(filename, SELF.filename);
  796. Strings.Append(filename, settings.diffSuffix);
  797. IF (WMDialogs.QueryString("Diff to file...", filename) = WMDialogs.ResOk) THEN
  798. string := ""; Strings.Append(string, filename); Strings.Append(string, " "); Strings.Append(string, SELF.filename);
  799. NEW(arg, LEN(string)); arg.SetRaw(string, 0, LEN(string));
  800. NEW(context, NIL, arg, NIL, NIL, owner);
  801. Commands.Activate(settings.diffCommand, context, {}, res, string);
  802. IF (res # Commands.Ok) THEN
  803. WMDialogs.Error(WindowTitle, string);
  804. END;
  805. END;
  806. END HandleDiff;
  807. PROCEDURE HandlePositions;
  808. BEGIN
  809. IF (flags * Inputs.Ctrl # {}) THEN
  810. positions.RecallPosition(ucs, keysym, flags - Inputs.Ctrl);
  811. ELSE (* ShiftKeyDown(flags) *)
  812. positions.StoreCurrentPosition(ucs, keysym, flags - Inputs.Shift);
  813. END;
  814. END HandlePositions;
  815. PROCEDURE RemoveWhitespace;
  816. VAR tw : TextUtilities.TextWriter; nofRemoved : LONGINT;
  817. BEGIN
  818. ClearLog;
  819. NEW(tw, logEdit.text);
  820. WhitespaceRemover.RemoveFromText(editor.text, nofRemoved);
  821. tw.String("Removed "); tw.Int(nofRemoved, 0); tw.String(" end-of-line whitespace"); tw.Update;
  822. logEdit.visible.Set(TRUE);
  823. END RemoveWhitespace;
  824. PROCEDURE HandleComments(remove : BOOLEAN);
  825. VAR editor : WMEditors.Editor;
  826. BEGIN
  827. IF (focus = EditorFocus) THEN editor := SELF.editor; ELSE editor := splitEditor; END;
  828. editor.text.AcquireWrite;
  829. editor.tv.selection.Sort;
  830. IF (editor.tv.selection.a # editor.tv.selection.b) THEN
  831. IF remove THEN
  832. UncommentSelection(editor.text, editor.tv.selection.from, editor.tv.selection.to);
  833. ELSE
  834. CommentSelection(editor.text, editor.tv.selection.from, editor.tv.selection.to);
  835. END;
  836. END;
  837. editor.text.ReleaseWrite;
  838. END HandleComments;
  839. BEGIN
  840. IF (keysym = 06H) & ControlKeyDown(flags)THEN (* CTRL-F *)
  841. searchPanel.ToggleVisibility;
  842. ELSIF (keysym= 0EH) & ControlKeyDown(flags) THEN (* CTRL-N *)
  843. HandlePreviousNext(TRUE);
  844. ELSIF (keysym = 10H) & ControlKeyDown(flags) THEN (* CTRL-P *)
  845. HandlePreviousNext(FALSE);
  846. ELSIF (keysym = 0DH) & ControlKeyDown(flags) THEN (* CTRL-M *)
  847. IF sidePanel.visible.Get() THEN sidePanel.visible.Set(FALSE);
  848. ELSE sidePanel.visible.Set(TRUE);
  849. END;
  850. ELSIF (keysym = 04H) & ControlKeyDown(flags) THEN (* CTRL-D *)
  851. HandleDiff;
  852. ELSIF (keysym = 30H) & ControlKeyDown(flags) THEN (* CTRL- 0 *)
  853. IF (focus = EditorFocus) THEN
  854. editor.tv.cursor.SetPosition(0);
  855. ELSE
  856. splitEditor.tv.cursor.SetPosition(0);
  857. END;
  858. ELSIF (keysym = 39H) & ControlKeyDown(flags) THEN (* CTRL - 0 *)
  859. IF (focus = EditorFocus) THEN
  860. editor.text.AcquireRead; pos := editor.text.GetLength()-1; editor.text.ReleaseRead;
  861. editor.tv.cursor.SetPosition(pos);
  862. ELSE
  863. splitEditor.text.AcquireRead; pos := splitEditor.text.GetLength()-1; splitEditor.text.ReleaseRead;
  864. splitEditor.tv.cursor.SetPosition(pos);
  865. END;
  866. ELSIF (0FFBEH <= keysym) & (keysym <= 0FFC9H) & EitherShiftOrControlDown(flags) THEN
  867. HandlePositions;
  868. ELSIF (keysym = Inputs.KsTab) & (flags = {}) THEN (* TAB *)
  869. RETURN searchPanel.HandleTab();
  870. ELSIF (keysym = Inputs.KsDelete) & ControlKeyDown(flags) THEN (* CTRL-DELETE *)
  871. RemoveWhitespace;
  872. ELSIF (keysym = Inputs.KsInsert) & (flags * Inputs.Alt # {}) THEN
  873. HandleComments(FALSE);
  874. ELSIF (keysym = Inputs.KsDelete) & (flags * Inputs.Alt # {}) THEN
  875. HandleComments(TRUE);
  876. ELSE
  877. RETURN FALSE; (* Key not handled *)
  878. END;
  879. RETURN TRUE;
  880. END HandleShortcut;
  881. PROCEDURE Finalize*;
  882. BEGIN
  883. Finalize^;
  884. IF (editor # NIL) & (editor.text # NIL) THEN
  885. editor.text.onTextChanged.Remove(TextChanged);
  886. editor.tv.onCursorChanged := NIL;
  887. IF editor.undoMgr # NIL THEN
  888. editor.undoMgr.nrUpdatesListener := NIL;
  889. END;
  890. END;
  891. END Finalize;
  892. END PETPanel;
  893. TYPE
  894. KillerMsg = OBJECT
  895. END KillerMsg;
  896. BrowseEntry = POINTER TO RECORD
  897. prev, next : BrowseEntry;
  898. filename : Filename;
  899. pos : LONGINT;
  900. END;
  901. Window = OBJECT (WMComponents.FormWindow)
  902. VAR
  903. filenameEdit, optionsEdit, positionEdit: WMEditors.Editor;
  904. loadBtn, storeBtn, closeBtn, compileBtn, findPCBtn, undoBtn, redoBtn: WMStandardComponents.Button;
  905. splitBtn, formatBtn, searchBtn, labelsBtn, wrapBtn, forwardBtn, backBtn : WMStandardComponents.Button;
  906. popup: WMPopups.Popup;
  907. tabs : WMTabComponents.Tabs;
  908. pages : ARRAY MaxNbrOfTabs OF PETPanel;
  909. tabList : ARRAY MaxNbrOfTabs OF WMTabComponents.Tab;
  910. currentPage : PETPanel;
  911. currentPageNr : LONGINT;
  912. page : WMStandardComponents.Panel;
  913. xmlHasErrors : BOOLEAN;
  914. codecFormat: ARRAY 128 OF CHAR;
  915. autoCodecFormat: ARRAY 128 OF CHAR;
  916. projectText : Texts.Text;
  917. projectTextFilename : Filename;
  918. projectTextModified : BOOLEAN;
  919. showTypeHierarchy, showImportedModules : BOOLEAN;
  920. windowInfo : WMWindowManager.WindowInfo;
  921. (* window icons handling *)
  922. currentIcon : WMGraphics.Image;
  923. iconIdle, iconWorking : WMGraphics.Image;
  924. modifierFlags : SET;
  925. browseBase, browseTOS : BrowseEntry;
  926. PROCEDURE &New*(c : WMRestorable.Context);
  927. VAR vc : WMComponents.VisualComponent;
  928. BEGIN
  929. IncCount;
  930. InitCodecs;
  931. vc := CreateForm();
  932. currentPageNr := -1;
  933. projectTextFilename := "";
  934. projectText := NIL;
  935. projectTextModified := FALSE;
  936. tabs.onSelectTab.Add(TabSelected);
  937. showTypeHierarchy := FALSE;
  938. showImportedModules := FALSE;
  939. modifierFlags := {};
  940. IF (c # NIL) THEN
  941. Init(c.r - c.l, c.b - c.t, FALSE);
  942. ELSE
  943. Init(WindowWidth, WindowHeight, FALSE);
  944. END;
  945. SetContent(vc);
  946. SetTitle(Strings.NewString(WindowTitle));
  947. currentIcon := NIL;
  948. iconIdle := WMGraphics.LoadImage("WMIcons.tar://PETIdle.png", TRUE);
  949. iconWorking := WMGraphics.LoadImage("WMIcons.tar://PET.png", TRUE);
  950. IF (iconIdle = NIL) THEN
  951. iconIdle := iconWorking;
  952. ELSIF (iconWorking = NIL) THEN
  953. iconWorking := iconIdle;
  954. END;
  955. SetIcon(iconIdle);
  956. IF c # NIL THEN (* restore the desktop *)
  957. WMRestorable.AddByContext(SELF, c);
  958. IF c.appData # NIL THEN
  959. DisableUpdate;
  960. LoadPages(c.appData(XML.Element));
  961. EnableUpdate;
  962. END;
  963. vc.Invalidate;
  964. ELSE WMWindowManager.DefaultAddWindow(SELF);
  965. (* NewTab; *)
  966. codecFormat := "AUTO";
  967. autoCodecFormat := DefaultTextFormat;
  968. SetFormatCaption("AUTO");
  969. END;
  970. NEW(browseBase); (* sentinel *)
  971. browseBase.prev := browseBase;
  972. browseTOS := browseBase
  973. END New;
  974. PROCEDURE CreateForm():WMComponents.VisualComponent;
  975. VAR
  976. panel, resizerPanel : WMStandardComponents.Panel;
  977. resizer : WMStandardComponents.Resizer;
  978. posLabel : WMStandardComponents.Label;
  979. font: WMGraphics.Font;
  980. dx, dy: LONGINT;
  981. PROCEDURE CreateToolbar() : WMComponents.VisualComponent;
  982. VAR toolbar : WMStandardComponents.Panel;
  983. BEGIN
  984. (* -- top toolbar *)
  985. NEW(toolbar); toolbar.bounds.SetHeight(20); toolbar.alignment.Set(WMComponents.AlignTop);
  986. NEW(resizerPanel);
  987. resizerPanel.alignment.Set(WMComponents.AlignLeft);
  988. resizerPanel.bounds.SetWidth(200);
  989. toolbar.AddContent(resizerPanel);
  990. NEW(resizer);
  991. resizer.alignment.Set(WMComponents.AlignRight);
  992. resizer.bounds.SetWidth(4);
  993. resizerPanel.AddContent(resizer);
  994. NEW(filenameEdit); filenameEdit.alignment.Set(WMComponents.AlignClient);
  995. filenameEdit.multiLine.Set(FALSE); filenameEdit.bounds.SetWidth(200);
  996. filenameEdit.fillColor.Set(0FFFFFFFFH);
  997. filenameEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  998. filenameEdit.tv.showBorder.Set(TRUE);
  999. filenameEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
  1000. filenameEdit.tv.commandCaller := SELF;
  1001. filenameEdit.onEnter.Add(LoadHandler);
  1002. filenameEdit.onEscape.Add(FilenameEditEscapeHandler);
  1003. resizerPanel.AddContent(filenameEdit);
  1004. NEW(loadBtn); loadBtn.caption.SetAOC("Load"); loadBtn.alignment.Set(WMComponents.AlignLeft);
  1005. loadBtn.onClick.Add(LoadHandler);
  1006. toolbar.AddContent(loadBtn);
  1007. NEW(storeBtn); storeBtn.caption.SetAOC("Store"); storeBtn.alignment.Set(WMComponents.AlignLeft);
  1008. storeBtn.onClick.Add(StoreHandler);
  1009. toolbar.AddContent(storeBtn);
  1010. NEW(closeBtn); closeBtn.caption.SetAOC("Close"); closeBtn.alignment.Set(WMComponents.AlignLeft);
  1011. closeBtn.onClick.Add(CloseHandler);
  1012. toolbar.AddContent(closeBtn);
  1013. NEW(formatBtn); formatBtn.caption.SetAOC("Format : ---"); formatBtn.alignment.Set(WMComponents.AlignLeft);
  1014. formatBtn.SetExtPointerDownHandler(FormatHandler);
  1015. formatBtn.bounds.SetWidth(3 * formatBtn.bounds.GetWidth());
  1016. toolbar.AddContent(formatBtn);
  1017. NEW(searchBtn); searchBtn.caption.SetAOC("Search"); searchBtn.alignment.Set(WMComponents.AlignLeft);
  1018. searchBtn.onClick.Add(ButtonHandler);
  1019. toolbar.AddContent(searchBtn);
  1020. NEW(compileBtn); compileBtn.caption.SetAOC("Compile"); compileBtn.alignment.Set(WMComponents.AlignLeft);
  1021. compileBtn.onClick.Add(ButtonHandler);
  1022. toolbar.AddContent(compileBtn);
  1023. NEW(findPCBtn); findPCBtn.caption.SetAOC("Find PC"); findPCBtn.alignment.Set(WMComponents.AlignLeft);
  1024. findPCBtn.onClick.Add(FindPC);
  1025. toolbar.AddContent(findPCBtn);
  1026. NEW(undoBtn);
  1027. font := undoBtn.GetFont();
  1028. font.GetStringSize(" Undo (000) ", dx, dy);
  1029. undoBtn.bounds.SetWidth(dx);
  1030. undoBtn.caption.SetAOC("Undo"); undoBtn.alignment.Set(WMComponents.AlignLeft);
  1031. undoBtn.onClick.Add(ButtonHandler);
  1032. toolbar.AddContent(undoBtn);
  1033. NEW(redoBtn);
  1034. font := redoBtn.GetFont();
  1035. font.GetStringSize(" Redo (000) ", dx, dy);
  1036. redoBtn.bounds.SetWidth(dx);
  1037. redoBtn.caption.SetAOC("Redo"); redoBtn.alignment.Set(WMComponents.AlignLeft);
  1038. redoBtn.onClick.Add(ButtonHandler);
  1039. toolbar.AddContent(redoBtn);
  1040. NEW(optionsEdit); optionsEdit.tv.showBorder.Set(TRUE); optionsEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
  1041. optionsEdit.alignment.Set(WMComponents.AlignClient); optionsEdit.multiLine.Set(FALSE);
  1042. optionsEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  1043. optionsEdit.bounds.SetWidth(80); optionsEdit.fillColor.Set(0FFFFFFFFH);
  1044. optionsEdit.SetAsString(settings.defaultCompilerOptions);
  1045. toolbar.AddContent(optionsEdit);
  1046. RETURN toolbar;
  1047. END CreateToolbar;
  1048. PROCEDURE CreateStatusbar() : WMComponents.VisualComponent;
  1049. VAR statusbar : WMStandardComponents.Panel;
  1050. BEGIN
  1051. NEW(statusbar); statusbar.bounds.SetHeight(20); statusbar.alignment.Set(WMComponents.AlignBottom); statusbar.fillColor.Set(0CCCCCCFFH);
  1052. NEW(posLabel); posLabel.caption.SetAOC(" Position: "); posLabel.bounds.SetWidth(60); posLabel.alignment.Set(WMComponents.AlignLeft);
  1053. statusbar.AddContent(posLabel); posLabel.textColor.Set(0000000FFH);
  1054. NEW(positionEdit); positionEdit.tv.showBorder.Set(TRUE); positionEdit.tv.borders.Set(WMRectangles.MakeRect(3,3,1,1));
  1055. positionEdit.alignment.Set(WMComponents.AlignLeft); positionEdit.multiLine.Set(FALSE);
  1056. positionEdit.tv.textAlignV.Set(WMGraphics.AlignCenter);
  1057. positionEdit.bounds.SetWidth(80); positionEdit.fillColor.Set(0FFFFFFFFH); positionEdit.onEnter.Add(PositionHandler);
  1058. statusbar.AddContent(positionEdit);
  1059. NEW(splitBtn); splitBtn.caption.SetAOC("Split"); splitBtn.alignment.Set(WMComponents.AlignRight);
  1060. splitBtn.onClick.Add(SplitHandler);
  1061. splitBtn.isToggle.Set(TRUE); splitBtn.SetPressed(FALSE);
  1062. statusbar.AddContent(splitBtn);
  1063. NEW(labelsBtn); labelsBtn.caption.SetAOC("Labels"); labelsBtn.alignment.Set(WMComponents.AlignRight);
  1064. labelsBtn.isToggle.Set(TRUE); labelsBtn.SetPressed(FALSE);
  1065. labelsBtn.onClick.Add(ButtonHandler);
  1066. statusbar.AddContent(labelsBtn);
  1067. NEW(wrapBtn); wrapBtn.caption.SetAOC("Wrap"); wrapBtn.alignment.Set(WMComponents.AlignRight);
  1068. wrapBtn.isToggle.Set(TRUE); wrapBtn.SetPressed(FALSE);
  1069. wrapBtn.onClick.Add(ButtonHandler);
  1070. statusbar.AddContent(wrapBtn);
  1071. NEW(forwardBtn); forwardBtn.caption.SetAOC("-->"); forwardBtn.alignment.Set(WMComponents.AlignRight);
  1072. forwardBtn.onClick.Add(ButtonHandler);
  1073. statusbar.AddContent(forwardBtn);
  1074. NEW(backBtn); backBtn.caption.SetAOC("<--"); backBtn.alignment.Set(WMComponents.AlignRight);
  1075. backBtn.onClick.Add(ButtonHandler);
  1076. statusbar.AddContent(backBtn);
  1077. RETURN statusbar;
  1078. END CreateStatusbar;
  1079. BEGIN
  1080. (* -- Main Panel holding the tabs, toolbar and tabcontents (instance of PETPanel) *)
  1081. NEW(panel); panel.alignment.Set(WMComponents.AlignClient); panel.fillColor.Set(0FFFFFFFFH); panel.takesFocus.Set(TRUE);
  1082. (* -- Tabs for the PETPanels *)
  1083. NEW(tabs); tabs.fillColor.Set(00000CCCCH); tabs.bounds.SetHeight(20); tabs.alignment.Set(WMComponents.AlignTop);
  1084. panel.AddContent(tabs); tabs.SetExtDragDroppedHandler(DragDroppedHandler);
  1085. panel.AddContent(CreateToolbar());
  1086. panel.AddContent(CreateStatusbar());
  1087. (* -- Page holding the PETPanel *)
  1088. NEW(page); page.fillColor.Set(0CCCCCCFFH); page.alignment.Set(WMComponents.AlignClient);
  1089. panel.AddContent(page);
  1090. RETURN panel;
  1091. END CreateForm;
  1092. PROCEDURE ButtonHandler(sender, data : ANY);
  1093. VAR options : CompilerOptions; searchString : SearchString; res : WORD;
  1094. BEGIN
  1095. IF sender = undoBtn THEN
  1096. currentPage.editor.Undo;
  1097. ELSIF sender = redoBtn THEN
  1098. currentPage.editor.Redo;
  1099. ELSIF sender = searchBtn THEN
  1100. IF (currentPage # NIL) THEN
  1101. currentPage.searchPanel.visible.Set(TRUE);
  1102. currentPage.searchPanel.SetToLastSelection;
  1103. currentPage.searchPanel.searchEdit.GetAsString(searchString);
  1104. IF (searchString # "") THEN
  1105. currentPage.searchPanel.SearchHandler(NIL, NIL);
  1106. ELSE
  1107. currentPage.searchPanel.searchEdit.SetFocus;
  1108. END;
  1109. END;
  1110. ELSIF sender = labelsBtn THEN
  1111. IF (currentPage # NIL) THEN currentPage.ToggleLabels; END;
  1112. ELSIF sender = compileBtn THEN
  1113. IF currentPage # NIL THEN
  1114. IF (settings.backupOnCompile) THEN
  1115. TextUtilities.StoreOberonText(currentPage.editor.text, BackupOnCompileFilename, res);
  1116. IF (res = 0) THEN
  1117. KernelLog.String("PET: Backup stored in "); KernelLog.String(BackupOnCompileFilename); KernelLog.Ln;
  1118. ELSE
  1119. KernelLog.String("PET: Warning: Backup-on-compile file creating failed."); KernelLog.Ln;
  1120. END;
  1121. END;
  1122. optionsEdit.GetAsString(options);
  1123. currentPage.DoCompile(FALSE, "", options);
  1124. END;
  1125. ELSIF sender = wrapBtn THEN
  1126. IF (currentPage # NIL) THEN
  1127. currentPage.ToggleWrap;
  1128. END;
  1129. ELSIF sender = backBtn THEN
  1130. BrowseBack
  1131. ELSIF sender = forwardBtn THEN
  1132. BrowseForward
  1133. END;
  1134. END ButtonHandler;
  1135. PROCEDURE NrUpdatesChanged(nrUndos, nrRedos: LONGINT);
  1136. VAR lbl, str: ARRAY 32 OF CHAR;
  1137. BEGIN
  1138. IF nrUndos = 0 THEN
  1139. undoBtn.enabled.Set(FALSE);
  1140. undoBtn.clDefault.Set(999999FFH);
  1141. ELSE
  1142. undoBtn.enabled.Set(TRUE);
  1143. undoBtn.clDefault.Reset;
  1144. END;
  1145. lbl := "Undo (";
  1146. Strings.IntToStr(nrUndos, str);
  1147. Strings.Append(lbl, str);
  1148. Strings.Append(lbl, ")");
  1149. undoBtn.caption.SetAOC(lbl);
  1150. IF nrRedos = 0 THEN
  1151. redoBtn.enabled.Set(FALSE);
  1152. redoBtn.clDefault.Set(999999FFH);
  1153. ELSE
  1154. redoBtn.enabled.Set(TRUE);
  1155. redoBtn.clDefault.Reset;
  1156. END;
  1157. lbl := "Redo (";
  1158. Strings.IntToStr(nrRedos, str);
  1159. Strings.Append(lbl, str);
  1160. Strings.Append(lbl, ")");
  1161. redoBtn.caption.SetAOC(lbl);
  1162. END NrUpdatesChanged;
  1163. PROCEDURE ProjectTextModified(sender, data : ANY);
  1164. BEGIN
  1165. projectTextModified :=TRUE;
  1166. END ProjectTextModified;
  1167. PROCEDURE InitCodecs;
  1168. VAR caption: CaptionObject;
  1169. elem: XML.Element; enum: XMLObjects.Enumerator; ptr: ANY; str : Strings.String;
  1170. BEGIN
  1171. NEW(popup);
  1172. (* retrieve available Text-Codecs *)
  1173. elem := Configuration.config.GetRoot();
  1174. IF elem # NIL THEN
  1175. enum := elem.GetContents(); enum.Reset;
  1176. WHILE enum.HasMoreElements() DO
  1177. ptr := enum.GetNext();
  1178. IF ptr IS XML.Element THEN
  1179. str := ptr(XML.Element).GetAttributeValue("name");
  1180. IF (str # NIL) & (str^ = "Codecs") THEN
  1181. enum := ptr(XML.Element).GetContents(); enum.Reset;
  1182. WHILE enum.HasMoreElements() DO
  1183. ptr := enum.GetNext();
  1184. IF ptr IS XML.Element THEN
  1185. str := ptr(XML.Element).GetAttributeValue("name");
  1186. IF (str # NIL) & (str^ = "Decoder") THEN
  1187. enum := ptr(XML.Element).GetContents(); enum.Reset;
  1188. WHILE enum.HasMoreElements() DO
  1189. ptr := enum.GetNext();
  1190. IF ptr IS XML.Element THEN
  1191. str := ptr(XML.Element).GetAttributeValue("name");
  1192. IF (str # NIL) & (str^ = "Text") THEN
  1193. enum := ptr(XML.Element).GetContents(); enum.Reset;
  1194. WHILE enum.HasMoreElements() DO
  1195. ptr := enum.GetNext();
  1196. IF ptr IS XML.Element THEN
  1197. str := ptr(XML.Element).GetAttributeValue("name");
  1198. NEW(caption, str^);
  1199. popup.AddParButton(str^, FormatPopupHandler, caption);
  1200. END;
  1201. END;
  1202. END;
  1203. END;
  1204. END;
  1205. END;
  1206. END;
  1207. END;
  1208. END;
  1209. END;
  1210. END;
  1211. END;
  1212. NEW(caption, "AUTO");
  1213. popup.AddParButton("AUTO", FormatPopupHandler, caption);
  1214. END InitCodecs;
  1215. PROCEDURE SelectNextTab;
  1216. VAR i : LONGINT;
  1217. BEGIN
  1218. IF currentPageNr < 0 THEN RETURN; END;
  1219. i := currentPageNr + 1;
  1220. LOOP
  1221. IF (i >= MaxNbrOfTabs) OR (pages[i] # NIL) THEN EXIT; END;
  1222. INC(i);
  1223. END;
  1224. IF (i < MaxNbrOfTabs) THEN
  1225. SelectTab(i);
  1226. END;
  1227. END SelectNextTab;
  1228. PROCEDURE SelectPreviousTab;
  1229. VAR i : LONGINT;
  1230. BEGIN
  1231. IF currentPageNr < 0 THEN RETURN; END;
  1232. i := currentPageNr - 1;
  1233. LOOP
  1234. IF (i < 0) OR (pages[i] # NIL) THEN EXIT; END;
  1235. DEC(i);
  1236. END;
  1237. IF (i >= 0) THEN
  1238. SelectTab(i);
  1239. END;
  1240. END SelectPreviousTab;
  1241. PROCEDURE SelectTab(tabNr : LONGINT);
  1242. BEGIN
  1243. IF (tabNr >= 0) & (tabNr < LEN(SELF.pages)) & (SELF.pages[tabNr] # NIL) THEN
  1244. TabSelected(NIL, tabList[tabNr]);
  1245. tabs.Select(tabList[tabNr]);
  1246. END;
  1247. END SelectTab;
  1248. PROCEDURE RecordCurrentPos;
  1249. VAR be : BrowseEntry;
  1250. BEGIN
  1251. IF (currentPage # NIL) THEN
  1252. NEW(be);
  1253. COPY(currentPage.filename, be.filename);
  1254. be.pos := currentPage.editor.tv.cursor.GetPosition();
  1255. be.next := NIL;
  1256. be.prev := browseTOS;
  1257. browseTOS.next := be;
  1258. browseTOS := be;
  1259. END;
  1260. END RecordCurrentPos;
  1261. PROCEDURE GotoFileInternal(CONST filename : ARRAY OF CHAR; pos : LONGINT);
  1262. VAR page : PETPanel; i : LONGINT;
  1263. BEGIN
  1264. KernelLog.String("filename= "); KernelLog.String(filename); KernelLog.Ln;
  1265. KernelLog.String("pos= "); KernelLog.Int(pos, 0); KernelLog.Ln;
  1266. i := 0;
  1267. page := NIL;
  1268. WHILE (i < LEN(pages)-1) & (page = NIL) DO
  1269. IF (pages[i] # NIL) & (pages[i].filename = filename) THEN
  1270. page := pages[i];
  1271. ELSE
  1272. INC(i);
  1273. END;
  1274. END;
  1275. IF (page = NIL) THEN
  1276. Load(filename, "AUTO");
  1277. page := currentPage;
  1278. ELSE
  1279. SelectTab(i);
  1280. END;
  1281. IF (page # NIL) THEN
  1282. currentPage.editor.tv.cursor.SetPosition(pos);
  1283. IF (currentPage.tree # NIL) THEN
  1284. currentPage.tree.SelectNodeByPos(pos);
  1285. END;
  1286. END;
  1287. END GotoFileInternal;
  1288. PROCEDURE BrowseBack;
  1289. BEGIN
  1290. IF browseTOS.prev # browseBase THEN
  1291. browseTOS := browseTOS.prev;
  1292. (* browseBase.prev = browseBase *)
  1293. GotoFileInternal(browseTOS.filename, browseTOS.pos);
  1294. END
  1295. END BrowseBack;
  1296. PROCEDURE BrowseForward;
  1297. BEGIN
  1298. IF browseTOS.next # NIL THEN
  1299. browseTOS := browseTOS.next;
  1300. GotoFileInternal(browseTOS.filename, browseTOS.pos)
  1301. END
  1302. END BrowseForward;
  1303. PROCEDURE GotoFile(CONST filename : ARRAY OF CHAR; pos : LONGINT);
  1304. VAR page : PETPanel; i : LONGINT;
  1305. BEGIN
  1306. IF browseTOS = browseBase THEN RecordCurrentPos END;
  1307. i := 0;
  1308. page := NIL;
  1309. WHILE (i < LEN(pages)-1) & (page = NIL) DO
  1310. IF (pages[i] # NIL) & (pages[i].name = filename) THEN
  1311. page := pages[i];
  1312. ELSE
  1313. INC(i);
  1314. END;
  1315. END;
  1316. IF (page = NIL) THEN
  1317. Load(filename, "AUTO");
  1318. page := currentPage;
  1319. ELSE
  1320. SelectTab(i);
  1321. END;
  1322. IF (page # NIL) THEN
  1323. currentPage.editor.tv.cursor.SetPosition(pos);
  1324. IF (currentPage.tree # NIL) THEN
  1325. currentPage.tree.SelectNodeByPos(pos);
  1326. END;
  1327. RecordCurrentPos
  1328. END
  1329. END GotoFile;
  1330. PROCEDURE GotoDefinition(info : PETTrees.ExternalDefinitionInfo);
  1331. VAR page : PETPanel; i : LONGINT;
  1332. BEGIN
  1333. IF info.filename = "" THEN RETURN END;
  1334. IF browseTOS = browseBase THEN RecordCurrentPos END;
  1335. i := 0;
  1336. page := NIL;
  1337. WHILE (i < LEN(pages)-1) & (page = NIL) DO
  1338. IF (pages[i] # NIL) & (pages[i].filename = info.filename) THEN
  1339. page := pages[i];
  1340. ELSE
  1341. INC(i);
  1342. END;
  1343. END;
  1344. IF (page = NIL) THEN
  1345. Load(info.filename, "AUTO");
  1346. page := currentPage;
  1347. ELSE
  1348. SelectTab(i);
  1349. END;
  1350. IF (page # NIL) THEN
  1351. IF (currentPage.tree # NIL) THEN
  1352. currentPage.tree.BrowseToDefinition(SELF, info);
  1353. END;
  1354. RecordCurrentPos
  1355. END;
  1356. END GotoDefinition;
  1357. PROCEDURE GetNrFromPage(page : PETPanel): LONGINT;
  1358. VAR i : LONGINT; found : BOOLEAN;
  1359. BEGIN
  1360. i := 0; found := FALSE;
  1361. WHILE (~found & (i < MaxNbrOfTabs)) DO
  1362. IF (page = pages[i]) THEN RETURN i END;
  1363. INC(i)
  1364. END;
  1365. RETURN -1
  1366. END GetNrFromPage;
  1367. PROCEDURE TabSelected(sender, data : ANY);
  1368. VAR tab : WMTabComponents.Tab;
  1369. BEGIN
  1370. IF (data # NIL) & (data IS WMTabComponents.Tab) THEN
  1371. DisableUpdate;
  1372. optionsEdit.GetAsString(currentPage.options);
  1373. compileBtn.caption.SetAOC(currentPage.compilerSettings.caption);
  1374. findPCBtn.visible.Set(currentPage.compilerSettings.findPC);
  1375. page.RemoveContent(currentPage);
  1376. tab := data(WMTabComponents.Tab);
  1377. IF (tab.data # NIL) & (tab.data IS WMComponents.VisualComponent) THEN
  1378. currentPage := tab.data(PETPanel);
  1379. currentPageNr := GetNrFromPage(currentPage);
  1380. page.AddContent(currentPage);
  1381. IF ~currentPage.initialized THEN currentPage.Initialize END;
  1382. currentPage.Reset(SELF, NIL);
  1383. page.AlignSubComponents;
  1384. END;
  1385. EnableUpdate;
  1386. UpdateState;
  1387. page.Invalidate
  1388. END
  1389. END TabSelected;
  1390. PROCEDURE UpdatePages;
  1391. VAR i : LONGINT;
  1392. tab : WMTabComponents.Tab;
  1393. s : Strings.String;
  1394. foundModifiedPage : BOOLEAN;
  1395. BEGIN
  1396. DisableUpdate;
  1397. tabs.RemoveAllTabs;
  1398. IF currentPage # NIL THEN page.RemoveContent(currentPage);
  1399. currentPage := NIL
  1400. END;
  1401. IF currentPageNr >= 0 THEN currentPage := pages[currentPageNr] END;
  1402. foundModifiedPage := FALSE;
  1403. FOR i := 0 TO 99 DO
  1404. tabList[i] := NIL;
  1405. IF pages[i] # NIL THEN
  1406. pages[i].alignment.Set(WMComponents.AlignClient);
  1407. tab := tabs.NewTab();
  1408. tab.attention := pages[i].modified;
  1409. foundModifiedPage := foundModifiedPage OR pages[i].modified;
  1410. tabs.AddTab(tab);
  1411. tabList[i] := tab;
  1412. s := Strings.NewString(pages[i].name);
  1413. tabs.SetTabCaption(tab, s);
  1414. tabs.SetTabData(tab, pages[i]);
  1415. END
  1416. END;
  1417. IF currentPage = NIL THEN
  1418. i := 0;
  1419. WHILE (i < MaxNbrOfTabs) & (currentPage = NIL) DO
  1420. IF pages[i] # NIL THEN currentPage := pages[i]; currentPageNr := i END;
  1421. INC(i);
  1422. END;
  1423. IF currentPage = NIL THEN SetModified(FALSE) END;
  1424. END;
  1425. IF currentPage # NIL THEN
  1426. IF ~currentPage.initialized THEN currentPage.Initialize END;
  1427. page.AddContent(currentPage);
  1428. currentPage.Reset(SELF, NIL);
  1429. page.AlignSubComponents;
  1430. page.Invalidate;
  1431. IF tabList[currentPageNr] # NIL THEN tabs.Select(tabList[currentPageNr]) END
  1432. END;
  1433. UpdateState;
  1434. EnableUpdate;
  1435. UpdateInfo;
  1436. IF foundModifiedPage THEN
  1437. SetIcon(iconWorking);
  1438. ELSE
  1439. SetIcon(iconIdle);
  1440. END;
  1441. END UpdatePages;
  1442. PROCEDURE UpdateInfo;
  1443. VAR i, j : LONGINT;
  1444. BEGIN
  1445. FOR i := 0 TO LEN(windowInfo.openDocuments)-1 DO windowInfo.openDocuments[i].name := ""; END;
  1446. windowInfo.handleDocumentInfo := HandleDocumentInfo;
  1447. windowInfo.vc.generator := NIL;
  1448. j := 0;
  1449. FOR i := 0 TO LEN(pages)-1 DO
  1450. IF (pages[i] # NIL) & (j < LEN(windowInfo.openDocuments)) THEN
  1451. windowInfo.openDocuments[j].id := i;
  1452. COPY(pages[i].name, windowInfo.openDocuments[j].name);
  1453. COPY(pages[i].filename, windowInfo.openDocuments[j].fullname);
  1454. windowInfo.openDocuments[j].modified := pages[i].modified;
  1455. windowInfo.openDocuments[j].hasFocus := pages[i] = currentPage;
  1456. INC(j);
  1457. END;
  1458. END;
  1459. SetInfo(windowInfo);
  1460. END UpdateInfo;
  1461. PROCEDURE HandleDocumentInfo(CONST info : WMWindowManager.DocumentInfo; new : BOOLEAN; VAR res : WORD);
  1462. BEGIN
  1463. IF (pages[info.id] # NIL) THEN SelectTab(info.id); END;
  1464. END HandleDocumentInfo;
  1465. PROCEDURE UpdateState;
  1466. VAR tInt : LONGINT; tStr : ARRAY 16 OF CHAR;
  1467. PROCEDURE SetSplitted(splitted : BOOLEAN);
  1468. BEGIN
  1469. IF splitted THEN splitBtn.SetPressed(TRUE); ELSE splitBtn.SetPressed(FALSE); END;
  1470. END SetSplitted;
  1471. PROCEDURE SetLabels(show : BOOLEAN);
  1472. BEGIN
  1473. IF show THEN labelsBtn.SetPressed(TRUE); ELSE labelsBtn.SetPressed(FALSE); END;
  1474. END SetLabels;
  1475. PROCEDURE SetWrap(wrap : BOOLEAN);
  1476. BEGIN
  1477. IF wrap THEN wrapBtn.SetPressed(TRUE); ELSE wrapBtn.SetPressed(FALSE); END;
  1478. END SetWrap;
  1479. PROCEDURE ResetUndo;
  1480. BEGIN
  1481. undoBtn.caption.Reset;
  1482. redoBtn.caption.Reset;
  1483. undoBtn.clDefault.Reset;
  1484. redoBtn.clDefault.Reset;
  1485. END ResetUndo;
  1486. BEGIN
  1487. (* set state of current page *)
  1488. IF (currentPage # NIL) THEN
  1489. SetModified(currentPage.modified);
  1490. SetSplitted(currentPage.splitted);
  1491. SetWrap(currentPage.wrap);
  1492. SetLabels(currentPage.editor.tv.showLabels.Get());
  1493. SetFormatCaption(currentPage.codecFormat);
  1494. filenameEdit.SetAsString(currentPage.filename);
  1495. optionsEdit.SetAsString(currentPage.options);
  1496. compileBtn.caption.SetAOC(currentPage.compilerSettings.caption);
  1497. findPCBtn.visible.Set(currentPage.compilerSettings.findPC);
  1498. currentPage.editor.tv.cursor.SetVisible(TRUE);
  1499. currentPage.editor.SetFocus;
  1500. tInt := currentPage.editor.tv.cursor.GetPosition(); Strings.IntToStr(tInt, tStr);
  1501. positionEdit.SetAsString(tStr);
  1502. IF currentPage.editor.undoMgr # NIL THEN
  1503. NrUpdatesChanged(currentPage.editor.undoMgr.nrUndoUpdates, currentPage.editor.undoMgr.nrRedoUpdates);
  1504. END;
  1505. ELSE
  1506. SetModified(FALSE);
  1507. SetSplitted(FALSE);
  1508. SetWrap(FALSE);
  1509. codecFormat := "AUTO";
  1510. autoCodecFormat := DefaultTextFormat;
  1511. SetFormatCaption("AUTO");
  1512. storeBtn.caption.SetAOC("Store");
  1513. filenameEdit.SetAsString("");
  1514. optionsEdit.SetAsString("");
  1515. compileBtn.caption.Reset;
  1516. findPCBtn.visible.Set(FALSE);
  1517. positionEdit.SetAsString("-");
  1518. ResetUndo;
  1519. END;
  1520. END UpdateState;
  1521. PROCEDURE DragDroppedHandler(x, y : LONGINT; dragInfo : WMWindowManager.DragInfo; VAR handled : BOOLEAN);
  1522. VAR dropTarget : URLDropTarget;
  1523. BEGIN
  1524. NEW(dropTarget, SELF);
  1525. dragInfo.data := dropTarget;
  1526. ConfirmDrag(TRUE, dragInfo)
  1527. END DragDroppedHandler;
  1528. PROCEDURE PositionHandler(sender, data : ANY);
  1529. VAR tempString : ARRAY 16 OF CHAR;
  1530. tempInt : LONGINT;
  1531. BEGIN
  1532. IF (currentPage # NIL) THEN
  1533. positionEdit.GetAsString(tempString);
  1534. Strings.StrToInt(tempString, tempInt);
  1535. currentPage.editor.tv.cursor.SetPosition(tempInt);
  1536. currentPage.editor.tv.cursor.SetVisible(TRUE);
  1537. currentPage.editor.SetFocus;
  1538. END
  1539. END PositionHandler;
  1540. PROCEDURE FormatHandler(x, y: LONGINT; keys: SET; VAR handled: BOOLEAN);
  1541. VAR rectangle: WMRectangles.Rectangle;
  1542. BEGIN
  1543. handled := TRUE;
  1544. rectangle := formatBtn.bounds.Get();
  1545. popup.Popup(bounds.l + rectangle.l, bounds.t + rectangle.b+ 20);
  1546. END FormatHandler;
  1547. PROCEDURE SetFormatCaption(CONST format: ARRAY OF CHAR);
  1548. VAR caption : ARRAY 100 OF CHAR;
  1549. BEGIN
  1550. caption := "Format : ";
  1551. Strings.Append(caption, format);
  1552. IF (format = "AUTO") THEN
  1553. IF (currentPage # NIL) THEN Strings.Append(caption, " "); Strings.Append(caption, currentPage.autoCodecFormat);
  1554. ELSE Strings.Append(caption, " "); Strings.Append(caption, autoCodecFormat);
  1555. END;
  1556. END;
  1557. formatBtn.caption.SetAOC(caption);
  1558. END SetFormatCaption;
  1559. PROCEDURE SetCursorPosition (position: LONGINT);
  1560. VAR string : ARRAY 16 OF CHAR;
  1561. BEGIN
  1562. IF (currentPage # NIL) THEN
  1563. Strings.IntToStr(position, string);
  1564. positionEdit.SetAsString(string);
  1565. currentPage.editor.tv.cursor.SetPosition(position);
  1566. END;
  1567. END SetCursorPosition;
  1568. PROCEDURE SetModified(modified : BOOLEAN);
  1569. BEGIN
  1570. IF currentPage # NIL THEN
  1571. tabList[currentPageNr].attention := modified;
  1572. tabs.Invalidate;
  1573. IF modified THEN
  1574. SetIcon(iconWorking);
  1575. storeBtn.caption.SetAOC("Store !")
  1576. ELSE
  1577. storeBtn.caption.SetAOC("Store");
  1578. END;
  1579. END
  1580. END SetModified;
  1581. PROCEDURE SetIcon*(icon : WMGraphics.Image);
  1582. BEGIN
  1583. IF (icon # NIL) & (icon # currentIcon) THEN
  1584. currentIcon := icon;
  1585. SetIcon^(icon);
  1586. END;
  1587. END SetIcon;
  1588. PROCEDURE FormatPopupHandler(sender, data: ANY);
  1589. BEGIN
  1590. IF (data # NIL) & (data IS CaptionObject) THEN
  1591. popup.Close;
  1592. IF (currentPage # NIL) THEN
  1593. COPY(data(CaptionObject).caption, currentPage.codecFormat);
  1594. COPY(currentPage.codecFormat, codecFormat);
  1595. COPY(currentPage.autoCodecFormat, autoCodecFormat);
  1596. ELSE
  1597. COPY(data(CaptionObject).caption, codecFormat);
  1598. COPY(DefaultTextFormat, autoCodecFormat);
  1599. END;
  1600. SetFormatCaption(codecFormat);
  1601. END
  1602. END FormatPopupHandler;
  1603. (* Called when pressing the Escape key while the filename editor has the keyboard focus. *)
  1604. PROCEDURE FilenameEditEscapeHandler(sernder, data : ANY);
  1605. BEGIN
  1606. IF (currentPage # NIL) THEN
  1607. filenameEdit.SetAsString(currentPage.filename);
  1608. END;
  1609. END FilenameEditEscapeHandler;
  1610. PROCEDURE LoadHandler(sender, data : ANY);
  1611. VAR filename : Filename; command : ARRAY 1024 OF CHAR; msg : ARRAY 64 OF CHAR; ignoreRes : WORD;
  1612. BEGIN
  1613. filenameEdit.GetAsString(filename);
  1614. Strings.TrimWS(filename);
  1615. IF (filename # "") THEN
  1616. IF (Inputs.LeftShift IN modifierFlags) THEN
  1617. command := "PET.Open "; Strings.AppendX(command, filename);
  1618. Commands.Call(command, {}, ignoreRes, msg);
  1619. IF (currentPage # NIL) THEN
  1620. filenameEdit.SetAsString(currentPage.filename);
  1621. ELSE
  1622. filenameEdit.SetAsString("");
  1623. END;
  1624. ELSE
  1625. Load(filename, codecFormat);
  1626. IF (currentPage # NIL) THEN
  1627. optionsEdit.GetAsString(currentPage.options);
  1628. END;
  1629. END;
  1630. END;
  1631. END LoadHandler;
  1632. PROCEDURE Load(CONST filename, format : ARRAY OF CHAR);
  1633. VAR
  1634. text : Texts.Text; res : WORD;
  1635. decoder : Codecs.TextDecoder;
  1636. msg : ARRAY 512 OF CHAR;
  1637. readonly : BOOLEAN;
  1638. name, fullname, archiveName, entryName, path : Filename;
  1639. syntaxHighlighterName : ARRAY 32 OF CHAR;
  1640. file : Files.File;
  1641. in: Streams.Reader;
  1642. BEGIN
  1643. DisableUpdate;
  1644. res := -1;
  1645. NewTab; (* create a new Tab with an empty PETPanel to Load into *)
  1646. Codecs.SplitName(filename, archiveName, entryName);
  1647. IF (archiveName # "") THEN
  1648. COPY(archiveName, name);
  1649. ELSE
  1650. COPY(filename, name);
  1651. END;
  1652. COPY(name, fullname);
  1653. readonly := FALSE;
  1654. (* Check whether file/archive exists and get its canonical name *)
  1655. file := Files.Old(name);
  1656. IF (file # NIL) THEN
  1657. file.GetName(fullname);
  1658. readonly := Files.ReadOnly IN file.flags;
  1659. ELSE
  1660. file := Files.New(name); (* to get path *)
  1661. IF (file # NIL) THEN
  1662. file.GetName(fullname);
  1663. file := NIL;
  1664. END;
  1665. END;
  1666. IF (archiveName # "") THEN
  1667. Codecs.JoinName(fullname, entryName, currentPage.filename);
  1668. ELSE
  1669. COPY(fullname, currentPage.filename);
  1670. END;
  1671. IF (settings.showPathInTabs) THEN
  1672. COPY(fullname, currentPage.name);
  1673. IF (archiveName # "") THEN Codecs.JoinName(currentPage.name, entryName, currentPage.name); END;
  1674. ELSE
  1675. Files.SplitPath(fullname, path, currentPage.name);
  1676. IF (archiveName # "") THEN Codecs.JoinName(currentPage.name, entryName, currentPage.name); END;
  1677. END;
  1678. IF readonly THEN Strings.Append(currentPage.name, " (R)"); END;
  1679. IF (archiveName # "") THEN Codecs.JoinName(fullname, entryName, fullname); END;
  1680. filenameEdit.SetAsString(fullname);
  1681. IF projectText # NIL THEN
  1682. currentPage.scratch.SetText(projectText);
  1683. END;
  1684. text := currentPage.editor.text;
  1685. text.AcquireWrite;
  1686. currentPage.modified := TRUE; (* avoid the ! on the store button while loading *)
  1687. text.Delete(0, text.GetLength());
  1688. currentPage.editor.tv.firstLine.Set(0);
  1689. currentPage.editor.tv.onLinkClicked.Add(LinkClickedHandler);
  1690. text.ReleaseWrite;
  1691. IF (file # NIL) THEN
  1692. IF (format = "AUTO") THEN
  1693. decoder := TextUtilities.DecodeAuto(fullname, autoCodecFormat);
  1694. COPY(autoCodecFormat, currentPage.autoCodecFormat);
  1695. ELSE
  1696. decoder := Codecs.GetTextDecoder(format);
  1697. END;
  1698. IF (decoder # NIL) THEN
  1699. COPY(format, currentPage.codecFormat);
  1700. in := Codecs.OpenInputStream(fullname);
  1701. IF in # NIL THEN
  1702. decoder.Open(in, res);
  1703. IF res = 0 THEN
  1704. currentPage.editor.text.onTextChanged.Remove(currentPage.TextChanged);
  1705. currentPage.editor.SetText(decoder.GetText());
  1706. currentPage.searchPanel.SetText(decoder.GetText());
  1707. currentPage.splitEditor.SetText(currentPage.editor.text);
  1708. currentPage.editor.text.onTextChanged.Add(currentPage.TextChanged);
  1709. currentPage.editor.text.SetUndoManager(currentPage.editor.undoMgr)
  1710. END;
  1711. ELSE
  1712. msg := "Can't open input stream on file "; Strings.Append(msg, fullname);
  1713. WMDialogs.Error(WindowTitle, msg);
  1714. END;
  1715. ELSE
  1716. msg := "No decoder for file "; Strings.Append(msg, fullname);
  1717. Strings.Append(msg, " (Format: "); Strings.Append(msg, format); Strings.Append(msg, ")");
  1718. WMDialogs.Error(WindowTitle, msg);
  1719. END;
  1720. END;
  1721. SetFormatCaption(format);
  1722. currentPage.editor.tv.firstLine.Set(0);
  1723. currentPage.editor.tv.cursor.SetPosition(0);
  1724. currentPage.editor.tv.SetFocus;
  1725. currentPage.searchPanel.SetSettings(settings.searchWrap, settings.searchCaseSensitive, FALSE, settings.searchHighlightAll);
  1726. currentPage.compilerSettings := settings.GetCompilerSettings(filename);
  1727. currentPage.options := currentPage.compilerSettings.options;
  1728. GetSyntaxHighlighterName(filename, syntaxHighlighterName);
  1729. IF (syntaxHighlighterName # "") THEN
  1730. currentPage.editor.highlighting.SetAOC(syntaxHighlighterName);
  1731. currentPage.splitEditor.highlighting.SetAOC(syntaxHighlighterName);
  1732. END;
  1733. currentPage.CreateSidePanel(currentPage.compilerSettings);
  1734. COPY(currentPage.name, tabList[currentPageNr].caption^); tabs.Invalidate;
  1735. currentPage.modified := FALSE;
  1736. SetModified(FALSE);
  1737. UpdatePages;
  1738. EnableUpdate;
  1739. form.Invalidate;
  1740. END Load;
  1741. PROCEDURE StoreHandler(sender, data : ANY);
  1742. VAR filename : Filename;
  1743. BEGIN
  1744. IF (currentPage # NIL) THEN
  1745. filenameEdit.GetAsString(filename);
  1746. Strings.TrimWS(filename);
  1747. IF filename # "" THEN
  1748. Store(filename, currentPage.codecFormat);
  1749. ELSE
  1750. WMDialogs.Error(WindowTitle, "Filename invalid");
  1751. filenameEdit.SetAsString(currentPage.filename);
  1752. END;
  1753. END
  1754. END StoreHandler;
  1755. PROCEDURE CompleteHandler(sender, data : ANY);
  1756. BEGIN
  1757. IF currentPage.tree IS TFModuleTrees.ModuleTree THEN
  1758. currentPage.tree(TFModuleTrees.ModuleTree).Complete(NIL, NIL);
  1759. END
  1760. END CompleteHandler;
  1761. PROCEDURE Store(CONST filename, format : ARRAY OF CHAR);
  1762. VAR
  1763. res : WORD;
  1764. msg : ARRAY 512 OF CHAR;
  1765. name, backName, fullname, archiveName, entryName, path: Filename;
  1766. syntaxHighlighterName : ARRAY 32 OF CHAR;
  1767. backExt, t, ext: ARRAY 12 OF CHAR;
  1768. options : CompilerOptions;
  1769. encoder : Codecs.TextEncoder;
  1770. w : Streams.Writer; i : LONGINT;
  1771. file, oldFile : Files.File;
  1772. PROCEDURE FileExists(CONST filename : ARRAY OF CHAR) : BOOLEAN;
  1773. BEGIN
  1774. RETURN Files.Old(filename) # NIL
  1775. END FileExists;
  1776. PROCEDURE CreateBackupFile;
  1777. BEGIN
  1778. IF settings.backupOnStore = Paranoid THEN
  1779. Strings.Concat(filename, ".Bak", backName);
  1780. IF FileExists(backName) THEN
  1781. i := 0;
  1782. REPEAT
  1783. backExt := "."; Strings.IntToStr(i, t);
  1784. Strings.Append(backExt, t); Strings.Append(backExt, ".Bak");
  1785. Strings.Concat(filename, backExt, backName);
  1786. INC(i);
  1787. UNTIL ~FileExists(backName);
  1788. END;
  1789. ELSE
  1790. ASSERT(settings.backupOnStore = Yes);
  1791. Strings.Concat(filename, ".Bak", backName);
  1792. END;
  1793. Files.Rename(filename, backName, res);
  1794. IF res = Files.Ok THEN KernelLog.String("Backup created in "); KernelLog.String(backName); KernelLog.Ln END;
  1795. END CreateBackupFile;
  1796. BEGIN
  1797. IF currentPage # NIL THEN
  1798. filenameEdit.SetAsString(filename);
  1799. Codecs.SplitName(filename, archiveName, entryName);
  1800. IF (archiveName # "") THEN
  1801. COPY(archiveName, name);
  1802. ELSE
  1803. COPY(filename, name);
  1804. END;
  1805. COPY(name, fullname);
  1806. oldFile := Files.Old(name);
  1807. IF (oldFile # NIL) THEN
  1808. IF (Files.ReadOnly IN oldFile.flags) THEN
  1809. msg := "File is read-only: "; Strings.Append(msg, name);
  1810. WMDialogs.Error("Error", msg);
  1811. RETURN;
  1812. END;
  1813. END;
  1814. IF (archiveName = "") & (settings.backupOnStore # No) THEN CreateBackupFile; END;
  1815. IF (format = "AUTO") THEN
  1816. IF (currentPage.autoCodecFormat = "") THEN
  1817. encoder := Codecs.GetTextEncoder(DefaultTextFormat);
  1818. ELSE
  1819. encoder := Codecs.GetTextEncoder(currentPage.autoCodecFormat);
  1820. IF encoder = NIL THEN
  1821. encoder := Codecs.GetTextEncoder(DefaultTextFormat);
  1822. END;
  1823. END;
  1824. ELSE
  1825. encoder := Codecs.GetTextEncoder(format);
  1826. END;
  1827. IF (encoder # NIL) THEN
  1828. IF (archiveName # "") & (oldFile # NIL) THEN
  1829. file := oldFile;
  1830. ELSE
  1831. oldFile := NIL;
  1832. file := Files.New(name);
  1833. IF (file = NIL) THEN
  1834. msg := "Could not create file "; Strings.Append(msg, name);
  1835. WMDialogs.Error(WindowTitle, msg);
  1836. RETURN;
  1837. END;
  1838. END;
  1839. file.GetName(fullname);
  1840. IF (archiveName # "") THEN Codecs.JoinName(fullname, entryName, fullname); END;
  1841. filenameEdit.SetAsString(fullname);
  1842. w := Codecs.OpenOutputStream(fullname);
  1843. IF (w # NIL) THEN
  1844. encoder.Open(w);
  1845. currentPage.editor.text.AcquireWrite;
  1846. encoder.WriteText(currentPage.editor.text, res);
  1847. currentPage.editor.text.ReleaseWrite;
  1848.  w.Update;
  1849.  IF res # 0 THEN
  1850.  msg := "Could not encode file "; Strings.Append(msg, fullname);
  1851. WMDialogs.Error(WindowTitle, msg);
  1852.  END;
  1853. ELSE
  1854.  msg := "Could not store to file "; Strings.Append(msg, fullname); Strings.Append(msg, " (Could not open output stream)");
  1855.  WMDialogs.Error(WindowTitle, msg);
  1856. END;
  1857. ELSE
  1858. msg := "Could not store file "; Strings.Append(msg, fullname); Strings.Append(msg, " (No encoder found)");
  1859. WMDialogs.Error(WindowTitle, msg);
  1860. END;
  1861. IF (settings.showPathInTabs) THEN
  1862. COPY(fullname, pages[currentPageNr].name);
  1863. ELSE
  1864. IF (archiveName # "") THEN
  1865. Files.SplitPath(archiveName, path, name);
  1866. Codecs.JoinName(name, entryName, pages[currentPageNr].name);
  1867. ELSE
  1868. Files.SplitPath(fullname, path, pages[currentPageNr].name);
  1869. END;
  1870. END;
  1871. tabs.SetTabCaption(tabList[currentPageNr], Strings.NewString(currentPage.name));
  1872. tabs.Invalidate;
  1873. Files.SplitExtension (fullname, backName, ext);
  1874. Files.SplitExtension (currentPage.filename, backName, backExt);
  1875. IF ext # backExt THEN
  1876. currentPage.compilerSettings := settings.GetCompilerSettings(name);
  1877. currentPage.options := currentPage.compilerSettings.options;
  1878. optionsEdit.SetAsString(currentPage.options);
  1879. GetSyntaxHighlighterName(filename, syntaxHighlighterName);
  1880. IF (syntaxHighlighterName # "") THEN
  1881. currentPage.editor.highlighting.SetAOC(syntaxHighlighterName);
  1882. currentPage.editor.highlighting.SetAOC(syntaxHighlighterName);
  1883. END;
  1884. END;
  1885. COPY(fullname, currentPage.filename);
  1886. compileBtn.caption.SetAOC(currentPage.compilerSettings.caption);
  1887. findPCBtn.visible.Set(currentPage.compilerSettings.findPC);
  1888. optionsEdit.GetAsString(options); COPY(options, currentPage.options);
  1889. currentPage.modified := FALSE;
  1890. SetModified(FALSE);
  1891. IF HasModifiedPage() THEN
  1892. SetIcon(iconWorking);
  1893. ELSE
  1894. SetIcon(iconIdle);
  1895. END;
  1896. END
  1897. END Store;
  1898. PROCEDURE NewTab;
  1899. VAR pet : PETPanel;
  1900. i : LONGINT;
  1901. found : BOOLEAN;
  1902. BEGIN
  1903. found := FALSE;
  1904. NEW(pet, SELF); pet.alignment.Set(WMComponents.AlignClient); pet.fillColor.Set(0FFFFFFFFH); pet.takesFocus.Set(TRUE);
  1905. IF pet.editor.undoMgr # NIL THEN
  1906. pet.editor.undoMgr.nrUpdatesListener := NrUpdatesChanged;
  1907. NrUpdatesChanged(0, 0);
  1908. END;
  1909. IF (pet.scratchPanel # NIL) THEN
  1910. pet.scratchPanel.bounds.SetHeight(settings.scratchPanelHeight);
  1911. END;
  1912. (* find a free place *)
  1913. i := 0;
  1914. WHILE (i < MaxNbrOfTabs) & (~found) DO
  1915. IF pages[i] = NIL THEN pages[i] := pet; currentPageNr := i; found := TRUE; END;
  1916. INC(i)
  1917. END;
  1918. UpdatePages;
  1919. END NewTab;
  1920. (** Returns TRUE if at least one page has been modified, FALSE otherwise *)
  1921. PROCEDURE HasModifiedPage() : BOOLEAN;
  1922. VAR modified : BOOLEAN; i : LONGINT;
  1923. BEGIN
  1924. modified := FALSE;
  1925. i := 0;
  1926. WHILE ~modified & (i < MaxNbrOfTabs) DO
  1927. IF (pages[i] # NIL) & (pages[i].modified) THEN
  1928. modified := TRUE;
  1929. END;
  1930. INC(i);
  1931. END;
  1932. RETURN modified;
  1933. END HasModifiedPage;
  1934. (* Returns FALSE if the user declines to close all tabs *)
  1935. PROCEDURE CloseAllTabs() : BOOLEAN;
  1936. VAR res, i : LONGINT;
  1937. BEGIN
  1938. (* First check whether all pages are saved to disk *)
  1939. i := 0;
  1940. LOOP
  1941. IF i >= MaxNbrOfTabs THEN EXIT; END;
  1942. IF (pages[i] # NIL) & (pages[i].modified) THEN
  1943. res := WMDialogs.Confirmation(WindowTitle, "At least on page has not been stored. Continue?");
  1944. IF res = WMDialogs.ResNo THEN
  1945. RETURN FALSE;
  1946. ELSIF res = WMDialogs.ResYes THEN
  1947. EXIT;
  1948. END;
  1949. END;
  1950. INC(i);
  1951. END;
  1952. i := 0;
  1953. WHILE (i < MaxNbrOfTabs) DO
  1954. IF (pages[i] # NIL) THEN pages[i].Finalize; pages[i] := NIL; END;
  1955. INC(i);
  1956. END;
  1957. UpdatePages;
  1958. form.Invalidate;
  1959. RETURN TRUE;
  1960. END CloseAllTabs;
  1961. PROCEDURE CloseHandler(sender, data: ANY);
  1962. VAR found : BOOLEAN; i : LONGINT;
  1963. BEGIN
  1964. (* close current tab, warn user if not saved *)
  1965. IF (currentPage = NIL) OR (currentPage.modified) & (
  1966. WMDialogs.Confirmation(WindowTitle, "The current text was not stored. Continue ?") = WMDialogs.ResNo)
  1967. THEN RETURN END;
  1968. (* remove current page *)
  1969. found := FALSE; i := 0;
  1970. WHILE (~found & (i < MaxNbrOfTabs)) DO
  1971. IF (currentPage = pages[i]) THEN pages[i].Finalize; pages[i] := NIL; found := TRUE END;
  1972. INC(i);
  1973. END;
  1974. IF found & (i >= 2) THEN currentPageNr := i-2; END;
  1975. UpdatePages;
  1976. form.Invalidate;
  1977. END CloseHandler;
  1978. PROCEDURE SplitHandler(sender, data: ANY);
  1979. BEGIN
  1980. IF (currentPage # NIL) THEN
  1981. IF currentPage.splitted THEN
  1982. currentPage.splitPanel.visible.Set(FALSE);
  1983. currentPage.editor.SetFocus;
  1984. ELSE
  1985. currentPage.splitPanel.visible.Set(TRUE);
  1986. END;
  1987. currentPage.splitted := ~currentPage.splitted
  1988. END
  1989. END SplitHandler;
  1990. PROCEDURE LinkClickedHandler(sender, data : ANY);
  1991. BEGIN
  1992. IF data IS WMTextView.LinkWrapper THEN
  1993. KernelLog.String("Link: "); KernelLog.String(data(WMTextView.LinkWrapper).link^); KernelLog.Ln
  1994. END;
  1995. END LinkClickedHandler;
  1996. PROCEDURE FindPC(sender, data : ANY);
  1997. VAR a, b : LONGINT;
  1998. pcStr : ARRAY 128 OF CHAR;
  1999. selectionText: Texts.Text;
  2000. from, to: Texts.TextPosition;
  2001. options : CompilerOptions;
  2002. BEGIN
  2003. IF currentPage = NIL THEN RETURN; END;
  2004. IF Texts.GetLastSelection(selectionText, from, to) THEN
  2005. selectionText.AcquireRead;
  2006. a := MIN(from.GetPosition(), to.GetPosition());
  2007. b := MAX(from.GetPosition(), to.GetPosition());
  2008. TextUtilities.SubTextToStr(selectionText, a, b - a, pcStr);
  2009. selectionText.ReleaseRead;
  2010. Strings.Trim(pcStr, " ");
  2011. END;
  2012. optionsEdit.GetAsString(options);
  2013. IF pcStr = "" THEN
  2014. IF WMDialogs.QueryString("Enter PC to locate", pcStr) = WMDialogs.ResOk THEN
  2015. currentPage.DoCompile(TRUE, pcStr, options)
  2016. END
  2017. ELSE
  2018. currentPage.DoCompile(TRUE, pcStr, options)
  2019. END
  2020. END FindPC;
  2021. PROCEDURE UnloadModule;
  2022. VAR
  2023. path, filename : Files.FileName;
  2024. name, extension, msg : ARRAY 128 OF CHAR;
  2025. tw : TextUtilities.TextWriter; res : WORD;
  2026. BEGIN
  2027. ASSERT(currentPage # NIL);
  2028. Files.SplitPath(currentPage.filename, path, filename);
  2029. Strings.GetExtension(filename, name, extension);
  2030. IF (name # "PET") THEN
  2031. Modules.FreeModule(name, res, msg);
  2032. ELSE
  2033. res := -1; msg := "Unloading module PET not allowed! PET is running.";
  2034. END;
  2035. IF res = 0 THEN
  2036. msg := "Module "; Strings.Append(msg, name); Strings.Append(msg, " unloaded.");
  2037. END;
  2038. currentPage.ClearLog;
  2039. NEW(tw, currentPage.logEdit.text); tw.String (msg); tw.Update;
  2040. IF currentPage.logEdit.visible.Get() = FALSE THEN currentPage.logEdit.visible.Set(TRUE); END;
  2041. END UnloadModule;
  2042. PROCEDURE Close*;
  2043. VAR page : LONGINT;
  2044. BEGIN
  2045. Close^;
  2046. FOR page := 0 TO LEN(pages)-1 DO
  2047. IF pages[page] # NIL THEN pages[page].Finalize; END;
  2048. END;
  2049. IF projectTextModified THEN
  2050. StoreText(projectTextFilename, projectText);
  2051. END;
  2052. DecCount;
  2053. END Close;
  2054. (* XML scanner/parser error handler *)
  2055. PROCEDURE Error(pos, line, row: LONGINT; CONST msg: ARRAY OF CHAR);
  2056. BEGIN
  2057.  xmlHasErrors := TRUE;
  2058. END Error;
  2059. PROCEDURE LoadState(CONST filename : ARRAY OF CHAR) : BOOLEAN;
  2060. VAR
  2061. file : Files.File;
  2062. scanner : XMLScanner.Scanner;
  2063. parser : XMLParser.Parser;
  2064. reader : Files.Reader;
  2065. doc : XML.Document;
  2066. elem : XML.Element;
  2067. string : XML.String;
  2068. msg : ARRAY 128 OF CHAR;
  2069. BEGIN
  2070. xmlHasErrors := FALSE;
  2071. file := Files.Old(filename);
  2072. IF file # NIL THEN
  2073. NEW(reader, file, 0);
  2074. NEW(scanner, reader); scanner.reportError := Error;
  2075. NEW(parser, scanner); parser.reportError := Error;
  2076. doc := parser.Parse();
  2077. IF xmlHasErrors THEN
  2078. msg := "Could not load state: "; Strings.Append(msg, filename); Strings.Append(msg, " could not be parsed");
  2079. WMDialogs.Error(WindowTitle, msg);
  2080. RETURN FALSE;
  2081. END;
  2082. elem := doc.GetRoot();
  2083. IF elem # NIL THEN string := elem.GetName(); END;
  2084. IF (string # NIL) & (string^ = "PETData") THEN
  2085. DisableUpdate;
  2086. LoadPages(doc.GetRoot());
  2087. EnableUpdate;
  2088. ELSE
  2089. msg := "Could not load state: "; Strings.Append(msg, filename); Strings.Append(msg, " not valid");
  2090. WMDialogs.Error(WindowTitle, msg);
  2091. RETURN FALSE;
  2092. END;
  2093. ELSE
  2094. msg := "Could not load state: XML file "; Strings.Append(msg, filename); Strings.Append(msg, " not found");
  2095. WMDialogs.Error(WindowTitle, msg);
  2096. RETURN FALSE;
  2097. END;
  2098. RETURN TRUE;
  2099. END LoadState;
  2100. (* Store the current editor settings into a file *)
  2101. PROCEDURE StoreState(CONST filename : ARRAY OF CHAR);
  2102. VAR state : XML.Element; file : Files.File; w : Files.Writer;
  2103. BEGIN
  2104. file := Files.New(filename);
  2105. IF file # NIL THEN
  2106. Files.OpenWriter(w, file, 0);
  2107. state := StorePages();
  2108. state.Write(w, NIL, 0);
  2109. w.Update;
  2110. Files.Register(file);
  2111. KernelLog.String("PET state saved into "); KernelLog.String(filename); KernelLog.Ln;
  2112. ELSE
  2113. WMDialogs.Error(WindowTitle, "Could not create file");
  2114. END;
  2115. END StoreState;
  2116. PROCEDURE LoadPages(pages : XML.Element);
  2117. VAR
  2118. elem : XML.Element; enum : XMLObjects.Enumerator; ptr : ANY; s : XML.String;
  2119. selectedPageNr : LONGINT;
  2120. BEGIN
  2121. selectedPageNr := -1;
  2122. enum := pages.GetContents(); enum.Reset;
  2123. WHILE (enum.HasMoreElements()) DO
  2124. ptr := enum.GetNext();
  2125. IF ptr IS XML.Element THEN
  2126. elem := ptr(XML.Element);
  2127. s := elem.GetName();
  2128. IF (s # NIL) & (s^ = "Tab") THEN
  2129. LoadPage(elem);
  2130. ELSIF (s # NIL) & (s^ = "General") THEN
  2131. WMRestorable.LoadLongint(elem, "SelectedPageNr", selectedPageNr);
  2132. WMRestorable.LoadString(elem, "ProjectTextFile", projectTextFilename);
  2133. IF projectTextFilename # "" THEN
  2134. projectText := LoadText(projectTextFilename);
  2135. projectText.onTextChanged.Add(ProjectTextModified);
  2136. END;
  2137. END;
  2138. END;
  2139. END;
  2140. IF (selectedPageNr >= 0) & (selectedPageNr < LEN(SELF.pages)) & (SELF.pages[selectedPageNr] # NIL) THEN
  2141. TabSelected(NIL, tabList[selectedPageNr]);
  2142. tabs.Select(tabList[selectedPageNr]);
  2143. END;
  2144. END LoadPages;
  2145. PROCEDURE StorePages() : XML.Element;
  2146. VAR data, elem : WMRestorable.XmlElement; i : LONGINT;
  2147. BEGIN
  2148. NEW(data); data.SetName("PETData");
  2149. NEW(elem); elem.SetName("General");
  2150. WMRestorable.StoreLongint(elem, "SelectedPageNr", currentPageNr);
  2151. WMRestorable.StoreString(elem, "ProjectTextFile", projectTextFilename);
  2152. data.AddContent(elem);
  2153. WHILE (i < MaxNbrOfTabs) DO
  2154. IF (pages[i] # NIL) THEN
  2155. elem := StorePage(pages[i]);
  2156. data.AddContent(elem);
  2157. END;
  2158. INC(i)
  2159. END;
  2160. RETURN data;
  2161. END StorePages;
  2162. PROCEDURE LoadPage(page : WMRestorable.XmlElement);
  2163. VAR
  2164. entries: XMLObjects.Enumerator;
  2165. entry : XML.Element;
  2166. s : Strings.String;
  2167. firstLine, cursorPos, width, height : LONGINT;
  2168. options : CompilerOptions;
  2169. showLabels, wordWrap, visible, wrap, caseSensitive, backwards, highlightAll : BOOLEAN;
  2170. searchString, replaceString : WMSearchComponents.SearchString;
  2171. ptr : ANY;
  2172. BEGIN
  2173. WMRestorable.LoadString(page, "codecFormat", codecFormat);
  2174. WMRestorable.LoadString(page, "compilerOptions", options);
  2175. WMRestorable.LoadBoolean(page, "showLabels", showLabels);
  2176. WMRestorable.LoadBoolean(page, "wordWrap", wordWrap);
  2177. WMRestorable.LoadStringPtr(page, "file", s);
  2178. IF (s # NIL) THEN
  2179. Load(s^, codecFormat);
  2180. COPY(options, currentPage.options);
  2181. optionsEdit.SetAsString(options);
  2182. IF showLabels THEN currentPage.ToggleLabels; labelsBtn.SetPressed(TRUE); END;
  2183. IF wordWrap THEN currentPage.ToggleWrap; wrapBtn.SetPressed(TRUE); END;
  2184. entries := page.GetContents(); entries.Reset;
  2185. WHILE(entries.HasMoreElements()) DO
  2186. ptr := entries.GetNext();
  2187. IF ptr IS XML.Element THEN
  2188. entry := ptr (XML.Element);
  2189. s := entry.GetName();
  2190. IF (s # NIL) THEN
  2191. IF (s^ = "Editor") THEN
  2192. WMRestorable.LoadLongint(entry, "firstLine", firstLine);
  2193. WMRestorable.LoadLongint(entry, "cursorPos", cursorPos);
  2194. currentPage.editor.tv.firstLine.Set(firstLine);
  2195. currentPage.editor.tv.cursor.SetPosition(cursorPos);
  2196. ELSIF (s^ = "SplitEditor") THEN
  2197. WMRestorable.LoadLongint(entry, "firstLine", firstLine);
  2198. WMRestorable.LoadLongint(entry, "cursorPos", cursorPos);
  2199. WMRestorable.LoadBoolean(entry, "visible", visible);
  2200. WMRestorable.LoadLongint(entry, "height", height);
  2201. currentPage.splitEditor.tv.firstLine.Set(firstLine);
  2202. currentPage.splitEditor.tv.cursor.SetPosition(cursorPos);
  2203. currentPage.splitPanel.visible.Set(visible);
  2204. currentPage.splitted := visible;
  2205. currentPage.splitPanel.bounds.SetHeight(height);
  2206. ELSIF (s^ = "SidePanel") THEN
  2207. WMRestorable.LoadBoolean(entry, "visible", visible);
  2208. WMRestorable.LoadLongint(entry, "width", width);
  2209. WMRestorable.LoadLongint(entry, "scratchHeight", height);
  2210. currentPage.sidePanel.visible.Set(visible);
  2211. currentPage.sidePanel.bounds.SetWidth(width);
  2212. currentPage.scratchPanel.bounds.SetHeight(height);
  2213. ELSIF (s^ = "SearchPanel") THEN
  2214. WMRestorable.LoadBoolean(entry, "visible", visible);
  2215. WMRestorable.LoadBoolean(entry, "wrap", wrap);
  2216. WMRestorable.LoadBoolean(entry, "casesensitive", caseSensitive);
  2217. WMRestorable.LoadBoolean(entry, "backwards", backwards);
  2218. WMRestorable.LoadBoolean(entry, "highlight", highlightAll);
  2219. WMRestorable.LoadString(entry, "searchString", searchString);
  2220. WMRestorable.LoadString(entry, "replaceString", replaceString);
  2221. currentPage.searchPanel.visible.Set(visible);
  2222. currentPage.searchPanel.SetSettings(wrap, caseSensitive, backwards, highlightAll);
  2223. currentPage.searchPanel.searchEdit.SetAsString(searchString);
  2224. currentPage.searchPanel.replEdit.SetAsString(replaceString);
  2225. ELSIF (s^ = "LogPanel") THEN
  2226. WMRestorable.LoadLongint(entry, "height", height);
  2227. currentPage.logPanel.bounds.SetHeight(height);
  2228. END;
  2229. END;
  2230. END;
  2231. END; (* WHILE (entries.HasMoreElements() *)
  2232. END;
  2233. END LoadPage;
  2234. PROCEDURE StorePage(page : PETPanel) : WMRestorable.XmlElement;
  2235. VAR
  2236. elem, entry : WMRestorable.XmlElement;
  2237. wrap, caseSensitive, backwards, highlightAll : BOOLEAN;
  2238. string : WMSearchComponents.SearchString;
  2239. BEGIN
  2240. ASSERT(page # NIL);
  2241. NEW(elem); elem.SetName("Tab");
  2242. WMRestorable.StoreString(elem, "file", page.filename);
  2243. WMRestorable.StoreString(elem, "codecFormat", page.codecFormat);
  2244. WMRestorable.StoreString(elem, "compilerOptions", page.options);
  2245. WMRestorable.StoreBoolean(elem, "showLabels", page.editor.tv.showLabels.Get());
  2246. WMRestorable.StoreBoolean(elem, "wordWrap", page.editor.tv.wrapMode.Get() = WMTextView.WrapWord);
  2247. NEW(entry); entry.SetName("Editor");
  2248. WMRestorable.StoreLongint(entry, "firstLine", page.editor.tv.firstLine.Get());
  2249. WMRestorable.StoreLongint(entry, "cursorPos", page.editor.tv.cursor.GetPosition());
  2250. elem.AddContent(entry);
  2251. NEW(entry); entry.SetName("SplitEditor");
  2252. WMRestorable.StoreBoolean(entry, "visible", page.splitPanel.visible.Get());
  2253. WMRestorable.StoreLongint(entry, "firstLine", page.splitEditor.tv.firstLine.Get());
  2254. WMRestorable.StoreLongint(entry, "cursorPos", page.splitEditor.tv.cursor.GetPosition());
  2255. WMRestorable.StoreLongint(entry, "height", page.splitPanel.bounds.GetHeight());
  2256. elem.AddContent(entry);
  2257. NEW(entry); entry.SetName("SearchPanel");
  2258. page.searchPanel.GetSettings(wrap, caseSensitive, backwards, highlightAll);
  2259. WMRestorable.StoreBoolean(entry, "visible", page.searchPanel.visible.Get());
  2260. WMRestorable.StoreBoolean(entry, "wrap", wrap);
  2261. WMRestorable.StoreBoolean(entry, "casesensitive", caseSensitive);
  2262. WMRestorable.StoreBoolean(entry, "backwards", backwards);
  2263. WMRestorable.StoreBoolean(entry, "highlight", highlightAll);
  2264. page.searchPanel.searchEdit.GetAsString(string);
  2265. WMRestorable.StoreString(entry, "searchString", string);
  2266. page.searchPanel.replEdit.GetAsString(string);
  2267. WMRestorable.StoreString(entry, "replaceString", string);
  2268. elem.AddContent(entry);
  2269. NEW(entry); entry.SetName("LogPanel");
  2270. WMRestorable.StoreLongint(entry, "height", page.logPanel.bounds.GetHeight());
  2271. elem.AddContent(entry);
  2272. NEW(entry); entry.SetName("SidePanel");
  2273. WMRestorable.StoreBoolean(entry, "visible", page.sidePanel.visible.Get());
  2274. WMRestorable.StoreLongint(entry, "width", page.sidePanel.bounds.GetWidth());
  2275. WMRestorable.StoreLongint(entry, "scratchHeight", page.scratchPanel.bounds.GetHeight());
  2276. elem.AddContent(entry);
  2277. RETURN elem;
  2278. END StorePage;
  2279. PROCEDURE HandleShortcut(ucs : LONGINT; flags : SET; keysym : LONGINT) : BOOLEAN;
  2280. VAR filename : Filename; options : CompilerOptions;
  2281. BEGIN
  2282. modifierFlags := flags;
  2283. IF DisableShortcuts THEN RETURN FALSE; END;
  2284. IF (keysym = 13H) & ControlKeyDown(flags) THEN (* CTRL-S *)
  2285. StoreHandler(NIL, NIL);
  2286. ELSIF (keysym = 20H) & ControlKeyDown(flags) THEN (* CTRL-<space> *)
  2287. CompleteHandler(NIL, NIL);
  2288. ELSIF (keysym = 08H) & ControlKeyDown(flags) THEN (* CTRL-H *)
  2289. IF currentPage # NIL THEN
  2290. optionsEdit.GetAsString(options);
  2291. currentPage.DoCompile(FALSE, "", options);
  2292. END;
  2293. ELSIF (keysym = 0FH) & ControlKeyDown(flags) THEN (* CTRL-O *)
  2294. filenameEdit.SetAsString("");
  2295. filenameEdit.SetFocus;
  2296. ELSIF (keysym = Inputs.KsPageDown) & ControlKeyDown(flags) THEN (* CTRL-PgDn *)
  2297. IF (WMDialogs.QueryString("Save PET state into (.pet extension is appended)", filename) = WMDialogs.ResOk) & (filename # "") THEN
  2298. Strings.Append(filename, StateFileExtension);
  2299. StoreState(filename);
  2300. END;
  2301. ELSIF (keysym = Inputs.KsPageUp) & ControlKeyDown(flags) THEN (* CTRL-PgUp *)
  2302. IF (WMDialogs.QueryString("Load PET state from (.pet extension is appended)", filename) = WMDialogs.ResOk) & (filename # "") THEN
  2303. DisableUpdate;
  2304. IF CloseAllTabs() THEN
  2305. Strings.Append(filename, StateFileExtension);
  2306. IF LoadState(filename) THEN
  2307. UpdatePages;
  2308. UpdateState;
  2309. END;
  2310. END;
  2311. EnableUpdate;
  2312. form.Invalidate;
  2313. END;
  2314. ELSIF (keysym = Inputs.KsTab) & ControlKeyDown(flags) THEN (* CTRL-Tab *)
  2315. DisableUpdate; SelectNextTab; EnableUpdate;
  2316. ELSIF (keysym = Inputs.KsTab) & (flags * Inputs.Ctrl # {}) & (flags * Inputs.Shift # {}) &
  2317. (flags - Inputs.Ctrl - Inputs.Shift = {}) THEN (* CTRL-SHIFT-Tab *)
  2318. DisableUpdate; SelectPreviousTab; EnableUpdate;
  2319. ELSIF (keysym = 015H) & ControlKeyDown(flags) THEN (* CTRL-U *)
  2320. IF (currentPage # NIL) THEN UnloadModule; END;
  2321. (* relay hot key to current page *)
  2322. ELSIF (currentPage = NIL) OR ((currentPage # NIL) & (~currentPage.HandleShortcut(ucs, flags, keysym))) THEN
  2323. RETURN FALSE; (* Key not handled *)
  2324. END;
  2325. RETURN TRUE;
  2326. END HandleShortcut;
  2327. PROCEDURE Handle*(VAR m: WMMessages.Message);
  2328. VAR data : WMRestorable.XmlElement;
  2329. BEGIN
  2330. IF m.msgType = WMMessages.MsgKey THEN
  2331. IF ~HandleShortcut(m.x, m.flags, m.y) THEN
  2332. Handle^(m);
  2333. END;
  2334. ELSIF (m.msgType = WMMessages.MsgExt) & (m.ext # NIL) THEN
  2335. IF (m.ext IS KillerMsg) THEN Close
  2336. ELSIF (m.ext IS WMRestorable.Storage) THEN
  2337. data := StorePages();
  2338. m.ext(WMRestorable.Storage).Add("TFPET", "TFPET.Restore", SELF, data)
  2339. ELSE Handle^(m)
  2340. END
  2341. ELSE Handle^(m)
  2342. END
  2343. END Handle;
  2344. END Window;
  2345. VAR
  2346. nofWindows : LONGINT;
  2347. scratchText : Texts.Text;
  2348. scratchModified : BOOLEAN;
  2349. settings : Settings;
  2350. StrScratchPanel, StrPETPanel : Strings.String;
  2351. (** Open document *)
  2352. PROCEDURE Open*(context : Commands.Context); (** [Options] {filename['@'position]} ~ *)
  2353. VAR
  2354. window : Window; count, index, temp : SIZE; position : LONGINT;
  2355. filename : Filename; format : ARRAY 32 OF CHAR;
  2356. options: Options.Options;
  2357. BEGIN
  2358. NEW(options);
  2359. options.Add("e","external",Options.Flag);
  2360. options.Add("f", "format", Options.String);
  2361. IF options.Parse(context.arg, context.error) THEN
  2362. IF (context.caller # NIL) & (context.caller IS Window) & ~options.GetFlag("external") THEN
  2363. window := context.caller(Window);
  2364. ELSE
  2365. NEW(window, NIL);
  2366. END;
  2367. IF ~options.GetString("format", format) THEN format := "AUTO"; END;
  2368. count := 0;
  2369. WHILE context.arg.GetString(filename) DO
  2370. position := 0; index := Strings.Find(filename, 0, '@');
  2371. IF index >= 0 THEN temp := index + 1; Strings.StrToIntPos(filename, position, temp); ASSERT (position # 0); Strings.Truncate(filename, index) END;
  2372. IF filename # "" THEN window.Load(filename, format); window.SetCursorPosition(position); INC(count) END
  2373. END;
  2374. IF count = 0 THEN window.Load("Untitled.Mod", "AUTO") END;
  2375. END;
  2376. END Open;
  2377. PROCEDURE OpenState*(context : Commands.Context); (** filename ~ *)
  2378. VAR filename : Filename; window : Window;
  2379. BEGIN
  2380. context.arg.SkipWhitespace; context.arg.String(filename);
  2381. NEW(window, NIL);
  2382. IF ~window.LoadState(filename) THEN
  2383. context.error.String("PET: Could not state from file "); context.error.String(filename); context.error.Ln;
  2384. END;
  2385. END OpenState;
  2386. PROCEDURE Restore*(context : WMRestorable.Context);
  2387. VAR w : Window;
  2388. BEGIN
  2389. NEW(w, context)
  2390. END Restore;
  2391. (** Comment the currently selected text *)
  2392. PROCEDURE CommentSelection*(text : Texts.Text; from, to : Texts.TextPosition);
  2393. VAR a, b : LONGINT; string : ARRAY 4 OF Texts.Char32;
  2394. BEGIN
  2395. ASSERT((text # NIL) & (from # NIL) & (to # NIL));
  2396. text.AcquireWrite;
  2397. a := MIN(from.GetPosition(), to.GetPosition());
  2398. b := MAX(from.GetPosition(), to.GetPosition());
  2399. string[0] := ORD(" "); string[1] := ORD("*"); string[2] := ORD(")"); string[3] := 0;
  2400. text.InsertUCS32(b, string);
  2401. string[0] := ORD("("); string[1] := ORD("*"); string[2] := ORD(" "); string[3] := 0;
  2402. text.InsertUCS32(a, string);
  2403. IF (a <= b) THEN from.SetPosition(a); ELSE to.SetPosition(a); END;
  2404. text.ReleaseWrite;
  2405. Texts.SetLastSelection(text, from, to);
  2406. END CommentSelection;
  2407. (** Uncomment the currently selected text if it is commented *)
  2408. PROCEDURE UncommentSelection*(text : Texts.Text; from, to : Texts.TextPosition);
  2409. VAR
  2410. reader : Texts.TextReader; ch : Texts.Char32;
  2411. a, b : LONGINT;
  2412. openPos, closePos, openLen, closeLen : LONGINT;
  2413. BEGIN
  2414. text.AcquireWrite;
  2415. a := MIN(from.GetPosition(), to.GetPosition());
  2416. b := MAX(from.GetPosition(), to.GetPosition());
  2417. NEW(reader, text);
  2418. (* find open *)
  2419. openPos := -1; openLen := 2;
  2420. reader.SetPosition(a);
  2421. REPEAT reader.ReadCh(ch); UNTIL reader.eot OR ~TextUtilities.IsWhiteSpace(ch, FALSE) OR (reader.GetPosition() >= b);
  2422. IF (ch = ORD("(")) THEN
  2423. reader.ReadCh(ch);
  2424. IF (ch = ORD("*")) THEN
  2425. openPos := reader.GetPosition() - 2;
  2426. reader.ReadCh(ch);
  2427. IF (ch = ORD(" ")) THEN INC(openLen); END; (* delete the space character right to the open comment string *)
  2428. END;
  2429. END;
  2430. (* find close *)
  2431. closePos := -1; closeLen := 2;
  2432. IF (openPos > 0) THEN
  2433. reader.SetDirection(-1);
  2434. reader.SetPosition(b - 1);
  2435. REPEAT reader.ReadCh(ch); UNTIL reader.eot OR ~TextUtilities.IsWhiteSpace(ch, FALSE) OR (reader.GetPosition() <= a);
  2436. IF (ch = ORD(")")) THEN
  2437. reader.ReadCh(ch);
  2438. IF (ch = ORD("*")) THEN
  2439. closePos := reader.GetPosition() + 1;
  2440. reader.ReadCh(ch);
  2441. IF (ch = ORD(" ")) & (openPos + openLen - 1 < closePos - closeLen + 2) THEN
  2442. (* delete the space character left to the close comment string *)
  2443. INC(closeLen); DEC(closePos);
  2444. END;
  2445. END;
  2446. END;
  2447. END;
  2448. IF (openPos + openLen - 1 < closePos) THEN
  2449. text.Delete(closePos, closeLen);
  2450. text.Delete(openPos, openLen);
  2451. END;
  2452. text.ReleaseWrite;
  2453. END UncommentSelection;
  2454. (** Comment the currently selected text *)
  2455. PROCEDURE Comment*;
  2456. VAR text : Texts.Text; from, to : Texts.TextPosition;
  2457. BEGIN
  2458. IF Texts.GetLastSelection(text, from, to) THEN
  2459. CommentSelection(text, from, to);
  2460. END;
  2461. END Comment;
  2462. (** Uncomment the currently selected text if it is commented *)
  2463. PROCEDURE Uncomment*;
  2464. VAR text : Texts.Text; from, to : Texts.TextPosition;
  2465. BEGIN
  2466. IF Texts.GetLastSelection(text, from, to) THEN
  2467. UncommentSelection(text, from, to);
  2468. END;
  2469. END Uncomment;
  2470. PROCEDURE GetSyntaxHighlighterName*(fullname : ARRAY OF CHAR; VAR name : ARRAY OF CHAR);
  2471. VAR filename, extension, config : Files.FileName; res : WORD;
  2472. BEGIN
  2473. name := "";
  2474. Strings.UpperCase(fullname);
  2475. Strings.GetExtension(fullname, filename, extension);
  2476. IF (extension # "") THEN
  2477. config := "Applications.PET.SyntaxHighlighter.";
  2478. Strings.AppendX(config, extension);
  2479. Configuration.Get(config, name, res);
  2480. IF (res # Configuration.Ok) THEN name := ""; END;
  2481. END;
  2482. END GetSyntaxHighlighterName;
  2483. PROCEDURE ControlKeyDown(flags : SET) : BOOLEAN;
  2484. BEGIN
  2485. RETURN (flags * Inputs.Ctrl # {}) & (flags - Inputs.Ctrl = {});
  2486. END ControlKeyDown;
  2487. PROCEDURE EitherShiftOrControlDown(flags : SET) : BOOLEAN;
  2488. BEGIN
  2489. RETURN ((flags * Inputs.Shift # {}) & (flags * Inputs.Ctrl = {})) OR ((flags * Inputs.Ctrl # {}) & (flags * Inputs.Shift = {}));
  2490. END EitherShiftOrControlDown;
  2491. PROCEDURE ContainsFileExtension(filename , extension : ARRAY OF CHAR) : BOOLEAN;
  2492. BEGIN
  2493. Strings.UpperCase(filename);
  2494. Strings.UpperCase(extension);
  2495. RETURN Strings.Pos(extension, filename) > 0;
  2496. END ContainsFileExtension;
  2497. PROCEDURE ScratchModified(sender, data : ANY);
  2498. BEGIN {EXCLUSIVE}
  2499. scratchModified := TRUE
  2500. END ScratchModified;
  2501. PROCEDURE StoreScratchText;
  2502. BEGIN (* caller holds module lock *)
  2503. IF scratchModified THEN
  2504. StoreText(ScratchTextFilename, scratchText);
  2505. scratchModified := FALSE;
  2506. END;
  2507. END StoreScratchText;
  2508. PROCEDURE LoadScratchText;
  2509. BEGIN (* caller holds module lock *)
  2510. scratchText := LoadText(ScratchTextFilename);
  2511. scratchText.onTextChanged.Add(ScratchModified);
  2512. END LoadScratchText;
  2513. PROCEDURE StoreText(CONST filename : ARRAY OF CHAR; text : Texts.Text);
  2514. VAR res : WORD;
  2515. BEGIN
  2516. text.AcquireRead;
  2517. TextUtilities.StoreOberonText(text, filename, res);
  2518. text.ReleaseRead
  2519. END StoreText;
  2520. PROCEDURE LoadText(CONST filename : ARRAY OF CHAR) : Texts.Text;
  2521. VAR text : Texts.Text; res : WORD;
  2522. BEGIN
  2523. NEW(text);
  2524. text.AcquireWrite;
  2525. TextUtilities.LoadOberonText(text, filename, res);
  2526. text.ReleaseWrite;
  2527. RETURN text;
  2528. END LoadText;
  2529. PROCEDURE IncCount;
  2530. BEGIN {EXCLUSIVE}
  2531. INC(nofWindows);
  2532. IF (nofWindows = 1) THEN
  2533. NEW(settings); settings.Load;
  2534. LoadScratchText;
  2535. END;
  2536. END IncCount;
  2537. PROCEDURE DecCount;
  2538. BEGIN {EXCLUSIVE}
  2539. DEC(nofWindows);
  2540. IF (nofWindows = 0) THEN
  2541. StoreScratchText;
  2542. scratchText := NIL;
  2543. settings := NIL;
  2544. END;
  2545. END DecCount;
  2546. PROCEDURE Cleanup;
  2547. VAR die : KillerMsg;
  2548. msg : WMMessages.Message;
  2549. m : WMWindowManager.WindowManager;
  2550. BEGIN {EXCLUSIVE}
  2551. NEW(die); msg.ext := die; msg.msgType := WMMessages.MsgExt;
  2552. m := WMWindowManager.GetDefaultManager();
  2553. m.Broadcast(msg);
  2554. AWAIT(nofWindows = 0);
  2555. END Cleanup;
  2556. PROCEDURE LoadModule(CONST moduleName : ARRAY OF CHAR);
  2557. VAR module : Modules.Module; msg : ARRAY 128 OF CHAR; res : WORD;
  2558. BEGIN
  2559. module := Modules.ThisModule(moduleName, res, msg);
  2560. END LoadModule;
  2561. PROCEDURE InitStrings;
  2562. BEGIN
  2563. StrScratchPanel := Strings.NewString("ScratchPanel");
  2564. StrPETPanel := Strings.NewString("PETPanel");
  2565. END InitStrings;
  2566. BEGIN
  2567. nofWindows := 0;
  2568. scratchText := NIL; scratchModified := FALSE;
  2569. Modules.InstallTermHandler(Cleanup);
  2570. InitStrings;
  2571. END TFPET.
  2572. System.Free TFPET ~
  2573. WMMacros.ReadMacros Macros.XML ~
  2574. TFPET.Open TFAOParser.Mod~
  2575. TFPET.Open TFPET.Mod ~
  2576. System.Free TFPET WMXMLTree ~
  2577. PC.Compile TFPET.Mod ~
  2578. System.Free TFXRef TFPET TFModuleTrees TFAOParser TFDumpTS TFCheck TFScopeTools TFTypeSys BimboScanner TFStringPool~
  2579. Compiler.Compile TFStringPool.Mod BimboScanner.Mod TFTypeSys.Mod TFScopeTools.Mod TFCheck.Mod TFDumpTS.Mod TFAOParser.Mod TFModuleTrees.Mod TFPET.Mod~
  2580. TFPET.OpenState a.pet ~
  2581. (* Create .xym files for all modules in a directory *)
  2582. TFAOParser.MakeSymbolFiles "Strings" "Oberon*"~ (* main *.Mod*)
  2583. TFAOParser.MakeSymbolFiles "Trunk/" ~ (* main *.Mod*)
  2584. TFAOParser.MakeSymbolFiles "D:\Aos\trunk\source\" "*Oberon*"~ (* d:/release/*.Mod *)
  2585. TFAOParser.MakeSymbolFiles "D:\Aos\trunk\WinAos\Work\" "*Oberon*"~
  2586. AosTar.Create TFPET20061118.tar TextUtilities.Mod WMTextView.Mod TFStringPool.Mod BimboScanner.Mod TFScopeTools.Mod TFTypeSys.Mod TFCheck.Mod TFDumpTS.Mod TFAOParser.Mod
  2587. TFModuleTrees.Mod TFPET.Mod ~
  2588. TFPET.Open TFModuleTrees.Mod~
  2589. TFPET.Open PET.Mod~
  2590. TFPET.Open TFPET.Mod ~
  2591. TFPET.Open WMComponents.Mod~
  2592. PET.Open TFPET.Mod ~
  2593. WMTextView.Mod
  2594. Changed Highlight and TextMarker to use TextPositionKeeper instead of Texts.TextPosition