2
0

PET.Mod 95 KB

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