1
0

Helios-Core.st 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349
  1. Smalltalk createPackage: 'Helios-Core'!
  2. InterfacingObject subclass: #HLModel
  3. instanceVariableNames: 'announcer environment'
  4. package: 'Helios-Core'!
  5. !HLModel commentStamp!
  6. I am the abstract superclass of all models of Helios.
  7. I am the "Model" part of the MVC pattern implementation in Helios.
  8. I provide access to an `Environment` object and both a local (model-specific) and global (system-specific) announcer.
  9. The `#withChangesDo:` method is handy for performing model changes ensuring that all widgets are aware of the change and can prevent it from happening.
  10. Modifications of the system should be done via commands (see `HLCommand` and subclasses).!
  11. !HLModel methodsFor: 'accessing'!
  12. announcer
  13. ^ announcer ifNil: [ announcer := Announcer new ]
  14. !
  15. environment
  16. ^ environment ifNil: [ self manager environment ]
  17. !
  18. environment: anEnvironment
  19. environment := anEnvironment
  20. !
  21. manager
  22. ^ HLManager current
  23. !
  24. systemAnnouncer
  25. ^ self environment systemAnnouncer
  26. ! !
  27. !HLModel methodsFor: 'error handling'!
  28. withChangesDo: aBlock
  29. [
  30. self announcer announce: (HLAboutToChange new
  31. actionBlock: aBlock;
  32. yourself).
  33. aBlock value.
  34. ]
  35. on: HLChangeForbidden
  36. do: [ :ex | ]
  37. ! !
  38. !HLModel methodsFor: 'testing'!
  39. isBrowserModel
  40. ^ false
  41. !
  42. isReferencesModel
  43. ^ false
  44. !
  45. isToolModel
  46. ^ false
  47. ! !
  48. HLModel subclass: #HLFinder
  49. instanceVariableNames: ''
  50. package: 'Helios-Core'!
  51. !HLFinder commentStamp!
  52. I am the `Finder` service handler of Helios.
  53. Finding a class will open a new class browser, while finding a method will open a references browser.!
  54. !HLFinder methodsFor: 'finding'!
  55. findClass: aClass
  56. HLBrowser openAsTab openClassNamed: aClass name
  57. !
  58. findMethod: aCompiledMethod
  59. HLBrowser openAsTab openMethod: aCompiledMethod
  60. !
  61. findString: aString
  62. | foundClass |
  63. foundClass := self environment classes
  64. detect: [ :each | each name = aString ]
  65. ifNone: [ nil ].
  66. foundClass
  67. ifNil: [ HLReferences openAsTab search: aString ]
  68. ifNotNil: [ self findClass: foundClass ]
  69. ! !
  70. HLModel subclass: #HLToolModel
  71. instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
  72. package: 'Helios-Core'!
  73. !HLToolModel commentStamp!
  74. I am a model specific to package and class manipulation. All browsers should either use me or a subclass as their model.
  75. I provide methods for package, class, protocol and method manipulation and access, forwarding to my environment.
  76. I also handle compilation of classes and methods as well as compilation and parsing errors.!
  77. !HLToolModel methodsFor: 'accessing'!
  78. allSelectors
  79. ^ self environment allSelectors
  80. !
  81. availableClassNames
  82. ^ self environment availableClassNames
  83. !
  84. availablePackageNames
  85. ^ self environment availablePackageNames
  86. !
  87. availablePackages
  88. ^ self environment availablePackageNames
  89. !
  90. availableProtocols
  91. ^ self environment availableProtocolsFor: self selectedClass
  92. !
  93. forceSelectedClass: aClass
  94. self withChangesDo: [
  95. self
  96. selectedClass: nil;
  97. selectedClass: aClass ]
  98. !
  99. forceSelectedMethod: aMethod
  100. self withChangesDo: [
  101. self
  102. selectedMethod: nil;
  103. selectedMethod: aMethod ]
  104. !
  105. forceSelectedPackage: aPackage
  106. self withChangesDo: [
  107. self
  108. selectedPackage: nil;
  109. selectedPackage: aPackage ]
  110. !
  111. forceSelectedProtocol: aProtocol
  112. self withChangesDo: [
  113. self
  114. selectedProtocol: nil;
  115. selectedProtocol: aProtocol ]
  116. !
  117. packageToCommit
  118. "Answer the package to commit depending on the context:
  119. - if a Method is selected, answer its package
  120. - else answer the `selectedPackage`"
  121. ^ self selectedMethod
  122. ifNil: [ self selectedPackage ]
  123. ifNotNil: [ :method | method package ]
  124. !
  125. packages
  126. ^ self environment packages
  127. !
  128. selectedClass
  129. ^ selectedClass
  130. !
  131. selectedClass: aClass
  132. (self selectedClass = aClass and: [ aClass isNil ])
  133. ifTrue: [ ^ self ].
  134. self withChangesDo: [
  135. aClass
  136. ifNil: [ selectedClass := nil ]
  137. ifNotNil: [
  138. self selectedPackage: aClass theNonMetaClass package.
  139. self showInstance
  140. ifTrue: [ selectedClass := aClass theNonMetaClass ]
  141. ifFalse: [ selectedClass := aClass theMetaClass ] ].
  142. selectedProtocol := nil.
  143. self selectedProtocol: self allProtocol.
  144. self announcer announce: (HLClassSelected on: self selectedClass) ]
  145. !
  146. selectedMethod
  147. ^ self selectedClass ifNotNil: [
  148. self selectedClass methodDictionary
  149. at: selectedSelector
  150. ifAbsent: [ nil ] ]
  151. !
  152. selectedMethod: aCompiledMethod
  153. selectedSelector = aCompiledMethod ifTrue: [ ^ self ].
  154. self withChangesDo: [
  155. aCompiledMethod
  156. ifNil: [ selectedSelector := nil ]
  157. ifNotNil: [
  158. selectedClass := aCompiledMethod methodClass.
  159. selectedPackage := selectedClass theNonMetaClass package.
  160. selectedSelector := aCompiledMethod selector ].
  161. self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
  162. !
  163. selectedPackage
  164. ^ selectedPackage
  165. !
  166. selectedPackage: aPackage
  167. selectedPackage = aPackage ifTrue: [ ^ self ].
  168. self withChangesDo: [
  169. selectedPackage := aPackage.
  170. self selectedClass: nil.
  171. self announcer announce: (HLPackageSelected on: aPackage) ]
  172. !
  173. selectedProtocol
  174. ^ selectedProtocol
  175. !
  176. selectedProtocol: aString
  177. selectedProtocol = aString ifTrue: [ ^ self ].
  178. self withChangesDo: [
  179. selectedProtocol := aString.
  180. self selectedMethod: nil.
  181. self announcer announce: (HLProtocolSelected on: aString) ]
  182. ! !
  183. !HLToolModel methodsFor: 'actions'!
  184. addInstVarNamed: aString
  185. self environment addInstVarNamed: aString to: self selectedClass.
  186. self announcer announce: (HLInstVarAdded new
  187. theClass: self selectedClass;
  188. variableName: aString;
  189. yourself)
  190. !
  191. save: aString
  192. self announcer announce: HLSourceCodeSaved new.
  193. (self shouldCompileClassDefinition: aString)
  194. ifTrue: [ self compileClassDefinition: aString ]
  195. ifFalse: [ self compileMethod: aString ]
  196. !
  197. saveSourceCode
  198. self announcer announce: HLSaveSourceCode new
  199. ! !
  200. !HLToolModel methodsFor: 'commands actions'!
  201. commitPackageOnSuccess: aBlock onError: anotherBlock
  202. self environment
  203. commitPackage: self packageToCommit
  204. onSuccess: aBlock
  205. onError: anotherBlock
  206. !
  207. copyClassTo: aClassName
  208. self withChangesDo: [
  209. self environment
  210. copyClass: self selectedClass theNonMetaClass
  211. to: aClassName ]
  212. !
  213. moveClassToPackage: aPackageName
  214. self withChangesDo: [
  215. self environment
  216. moveClass: self selectedClass theNonMetaClass
  217. toPackage: aPackageName ]
  218. !
  219. moveMethodToClass: aClassName
  220. self withChangesDo: [
  221. self environment
  222. moveMethod: self selectedMethod
  223. toClass: aClassName ]
  224. !
  225. moveMethodToProtocol: aProtocol
  226. self withChangesDo: [
  227. self environment
  228. moveMethod: self selectedMethod
  229. toProtocol: aProtocol ]
  230. !
  231. openClassNamed: aString
  232. | class |
  233. self withChangesDo: [
  234. class := self environment classNamed: aString.
  235. self selectedPackage: class package.
  236. self selectedClass: class ]
  237. !
  238. removeClass
  239. self withChangesDo: [
  240. self manager
  241. confirm: 'Do you REALLY want to remove class ', self selectedClass theNonMetaClass name
  242. ifTrue: [ self environment removeClass: self selectedClass theNonMetaClass ] ]
  243. !
  244. removeMethod
  245. self withChangesDo: [
  246. self manager
  247. confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector
  248. ifTrue: [ self environment removeMethod: self selectedMethod ] ]
  249. !
  250. removeProtocol
  251. self withChangesDo: [
  252. self manager
  253. confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol
  254. ifTrue: [ self environment
  255. removeProtocol: self selectedProtocol
  256. from: self selectedClass ] ]
  257. !
  258. renameClassTo: aClassName
  259. self withChangesDo: [
  260. self environment
  261. renameClass: self selectedClass theNonMetaClass
  262. to: aClassName ]
  263. !
  264. renameProtocolTo: aString
  265. self withChangesDo: [
  266. self environment
  267. renameProtocol: self selectedProtocol
  268. to: aString
  269. in: self selectedClass ]
  270. ! !
  271. !HLToolModel methodsFor: 'compiling'!
  272. compileClassComment: aString
  273. self environment
  274. compileClassComment: aString
  275. for: self selectedClass
  276. !
  277. compileClassDefinition: aString
  278. self environment compileClassDefinition: aString
  279. !
  280. compileMethod: aString
  281. | method |
  282. self withCompileErrorHandling: [
  283. method := self environment
  284. compileMethod: aString
  285. for: self selectedClass
  286. protocol: self compilationProtocol.
  287. self selectedMethod: method ]
  288. ! !
  289. !HLToolModel methodsFor: 'defaults'!
  290. allProtocol
  291. ^ '-- all --'
  292. !
  293. unclassifiedProtocol
  294. ^ 'as yet unclassified'
  295. ! !
  296. !HLToolModel methodsFor: 'error handling'!
  297. handleCompileError: anError
  298. self announcer announce: (HLCompileErrorRaised new
  299. error: anError;
  300. yourself)
  301. !
  302. handleParseError: anError
  303. | split line column messageToInsert |
  304. split := anError messageText tokenize: ' : '.
  305. messageToInsert := split second.
  306. "21 = 'Parse error on line ' size + 1"
  307. split := split first copyFrom: 21 to: split first size.
  308. split := split tokenize: ' column '.
  309. line := split first.
  310. column := split second.
  311. self announcer announce: (HLParseErrorRaised new
  312. line: line asNumber;
  313. column: column asNumber;
  314. message: messageToInsert;
  315. error: anError;
  316. yourself)
  317. !
  318. handleUnkownVariableError: anError
  319. self announcer announce: (HLUnknownVariableErrorRaised new
  320. error: anError;
  321. yourself)
  322. !
  323. withCompileErrorHandling: aBlock
  324. self environment
  325. evaluate: [
  326. self environment
  327. evaluate: [
  328. self environment
  329. evaluate: aBlock
  330. on: ParseError
  331. do: [ :ex | self handleParseError: ex ] ]
  332. on: UnknownVariableError
  333. do: [ :ex | self handleUnkownVariableError: ex ] ]
  334. on: CompilerError
  335. do: [ :ex | self handleCompileError: ex ]
  336. ! !
  337. !HLToolModel methodsFor: 'private'!
  338. compilationProtocol
  339. | currentProtocol |
  340. currentProtocol := self selectedProtocol.
  341. currentProtocol ifNil: [ currentProtocol := self unclassifiedProtocol ].
  342. self selectedMethod ifNotNil: [ currentProtocol := self selectedMethod protocol ].
  343. ^ currentProtocol = self allProtocol
  344. ifTrue: [ self unclassifiedProtocol ]
  345. ifFalse: [ currentProtocol ]
  346. !
  347. withHelperLabelled: aString do: aBlock
  348. "TODO: doesn't belong here"
  349. '#helper' asJQuery remove.
  350. [ :html |
  351. html div
  352. id: 'helper';
  353. with: aString ] appendToJQuery: 'body' asJQuery.
  354. [
  355. aBlock value.
  356. '#helper' asJQuery remove
  357. ]
  358. valueWithTimeout: 10
  359. ! !
  360. !HLToolModel methodsFor: 'testing'!
  361. isToolModel
  362. ^ true
  363. !
  364. shouldCompileClassDefinition: aString
  365. ^ self selectedClass isNil or: [
  366. aString match: '^\s*[A-Z]' ]
  367. ! !
  368. !HLToolModel class methodsFor: 'actions'!
  369. on: anEnvironment
  370. ^ self new
  371. environment: anEnvironment;
  372. yourself
  373. ! !
  374. Object subclass: #HLProgressHandler
  375. instanceVariableNames: ''
  376. package: 'Helios-Core'!
  377. !HLProgressHandler commentStamp!
  378. I am a specific progress handler for Helios, displaying progresses in a modal window.!
  379. !HLProgressHandler methodsFor: 'progress handling'!
  380. do: aBlock on: aCollection displaying: aString
  381. HLProgressWidget default
  382. do: aBlock
  383. on: aCollection
  384. displaying: aString
  385. ! !
  386. Widget subclass: #HLWidget
  387. instanceVariableNames: 'wrapper'
  388. package: 'Helios-Core'!
  389. !HLWidget commentStamp!
  390. I am the abstract superclass of all Helios widgets.
  391. I provide common methods, additional behavior to widgets useful for Helios, like dialog creation, command execution and tab creation.
  392. ## API
  393. 1. Rendering
  394. Instead of overriding `#renderOn:` as with other Widget subclasses, my subclasses should override `#renderContentOn:`.
  395. 2. Refreshing
  396. To re-render a widget, use `#refresh`.
  397. 3. Key bindings registration and tabs
  398. When displayed as a tab, the widget has a chance to register keybindings with the `#registerBindingsOn:` hook method.
  399. 4. Unregistration
  400. When a widget has subscribed to announcements or other actions that need to be cleared when closing the tab, the hook method `#unregister` will be called by helios.
  401. 5. Tabs
  402. To enable a widget class to be open as a tab, override the class-side `#canBeOpenAsTab` method to answer `true`. `#tabClass` and `#tabPriority` can be overridden too to respectively change the css class of the tab and the order of tabs in the main menu.
  403. 6. Command execution
  404. An helios command (instance of `HLCommand` or one of its subclass) can be executed with `#execute:`.!
  405. !HLWidget methodsFor: 'accessing'!
  406. cssClass
  407. ^ 'hl_widget'
  408. !
  409. manager
  410. ^ HLManager current
  411. !
  412. removeTab
  413. self manager removeTabForWidget: self
  414. !
  415. setTabLabel: aString
  416. self manager announcer announce: (HLTabLabelChanged new
  417. widget: self;
  418. label: aString;
  419. yourself)
  420. !
  421. tabClass
  422. ^ self class tabClass
  423. !
  424. wrapper
  425. ^ wrapper
  426. ! !
  427. !HLWidget methodsFor: 'actions'!
  428. confirm: aString ifTrue: aBlock
  429. self manager confirm: aString ifTrue: aBlock
  430. !
  431. confirm: aString ifTrue: aBlock ifFalse: anotherBlock
  432. self manager
  433. confirm: aString
  434. ifTrue: aBlock
  435. ifFalse: anotherBlock
  436. !
  437. execute: aCommand
  438. HLManager current keyBinder
  439. activate;
  440. applyBinding: aCommand asBinding
  441. !
  442. inform: aString
  443. self manager inform: aString
  444. !
  445. openAsTab
  446. (HLTabWidget on: self labelled: self defaultTabLabel)
  447. add
  448. !
  449. request: aString do: aBlock
  450. self manager request: aString do: aBlock
  451. !
  452. request: aString value: valueString do: aBlock
  453. self manager
  454. request: aString
  455. value: valueString
  456. do: aBlock
  457. !
  458. unregister
  459. "This method is called whenever the receiver is closed (as a tab).
  460. Widgets subscribing to announcements should unregister there"
  461. ! !
  462. !HLWidget methodsFor: 'defaults'!
  463. defaultTabLabel
  464. ^ self class tabLabel
  465. ! !
  466. !HLWidget methodsFor: 'keybindings'!
  467. bindKeyDown: keyDownBlock keyUp: keyUpBlock
  468. self wrapper asJQuery
  469. keydown: keyDownBlock;
  470. keyup: keyUpBlock
  471. !
  472. registerBindings
  473. self registerBindingsOn: self manager keyBinder bindings
  474. !
  475. registerBindingsOn: aBindingGroup
  476. !
  477. unbindKeyDownKeyUp
  478. self wrapper asJQuery
  479. unbind: 'keydown';
  480. unbind: 'keyup'
  481. ! !
  482. !HLWidget methodsFor: 'rendering'!
  483. renderContentOn: html
  484. !
  485. renderOn: html
  486. wrapper := html div
  487. class: self cssClass;
  488. yourself.
  489. [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
  490. ! !
  491. !HLWidget methodsFor: 'testing'!
  492. canHaveFocus
  493. ^ false
  494. ! !
  495. !HLWidget methodsFor: 'updating'!
  496. refresh
  497. self wrapper ifNil: [ ^ self ].
  498. self wrapper asJQuery empty.
  499. [ :html | self renderContentOn: html ] appendToJQuery: self wrapper asJQuery
  500. ! !
  501. !HLWidget class methodsFor: 'accessing'!
  502. openAsTab
  503. | instance |
  504. instance := self new.
  505. (HLTabWidget
  506. on: instance
  507. labelled: instance defaultTabLabel) add.
  508. ^ instance
  509. !
  510. tabClass
  511. ^ ''
  512. !
  513. tabLabel
  514. ^ 'Tab'
  515. !
  516. tabPriority
  517. ^ 500
  518. ! !
  519. !HLWidget class methodsFor: 'testing'!
  520. canBeOpenAsTab
  521. ^ false
  522. ! !
  523. HLWidget subclass: #HLFocusableWidget
  524. instanceVariableNames: ''
  525. package: 'Helios-Core'!
  526. !HLFocusableWidget commentStamp!
  527. I am a widget that can be focused.
  528. ## API
  529. Instead of overriding `#renderOn:` as with other `Widget` subclasses, my subclasses should override `#renderContentOn:`.
  530. To bring the focus to the widget, use the `#focus` method.!
  531. !HLFocusableWidget methodsFor: 'accessing'!
  532. focusClass
  533. ^ 'focused'
  534. ! !
  535. !HLFocusableWidget methodsFor: 'events'!
  536. blur
  537. self wrapper asJQuery blur
  538. !
  539. focus
  540. self wrapper asJQuery focus
  541. ! !
  542. !HLFocusableWidget methodsFor: 'rendering'!
  543. renderContentOn: html
  544. !
  545. renderOn: html
  546. wrapper := html div
  547. class: self cssClass;
  548. yourself.
  549. wrapper with: [ self renderContentOn: html ].
  550. wrapper
  551. at: 'tabindex' put: '0';
  552. onBlur: [ self wrapper asJQuery removeClass: self focusClass ];
  553. onFocus: [ self wrapper asJQuery addClass: self focusClass ]
  554. ! !
  555. !HLFocusableWidget methodsFor: 'testing'!
  556. canHaveFocus
  557. ^ true
  558. !
  559. hasFocus
  560. ^ self wrapper notNil and: [ self wrapper asJQuery hasClass: self focusClass ]
  561. ! !
  562. HLFocusableWidget subclass: #HLListWidget
  563. instanceVariableNames: 'items selectedItem'
  564. package: 'Helios-Core'!
  565. !HLListWidget methodsFor: 'accessing'!
  566. activeItemCssClass
  567. ^'active'
  568. !
  569. buttonsDivCssClass
  570. ^ 'pane_actions form-actions'
  571. !
  572. cssClassForItem: anObject
  573. ^ ''
  574. !
  575. findListItemFor: anObject
  576. ^ (((wrapper asJQuery find: 'li')
  577. filter: [ :thisArg :otherArg | (thisArg asJQuery data: 'item') = anObject ] currySelf) eq: 0)
  578. !
  579. items
  580. ^ items ifNil: [ items := self defaultItems ]
  581. !
  582. items: aCollection
  583. items := aCollection
  584. !
  585. listCssClass
  586. ^'nav nav-pills nav-stacked'
  587. !
  588. listCssClassForItem: anObject
  589. ^ self selectedItem = anObject
  590. ifTrue: [ self activeItemCssClass ]
  591. ifFalse: [ 'inactive' ]
  592. !
  593. positionOf: aListItem
  594. <
  595. return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1
  596. >
  597. !
  598. selectedItem
  599. ^ selectedItem
  600. !
  601. selectedItem: anObject
  602. selectedItem := anObject
  603. ! !
  604. !HLListWidget methodsFor: 'actions'!
  605. activateFirstListItem
  606. self activateListItem: ((wrapper asJQuery find: 'li.inactive') eq: 0)
  607. !
  608. activateItem: anObject
  609. self activateListItem: (self findListItemFor: anObject)
  610. !
  611. activateListItem: aListItem
  612. | item |
  613. (aListItem get: 0) ifNil: [ ^ self ].
  614. aListItem parent children removeClass: self activeItemCssClass.
  615. aListItem addClass: self activeItemCssClass.
  616. self ensureVisible: aListItem.
  617. "Activate the corresponding item"
  618. item := aListItem data: 'item'.
  619. self selectedItem == item ifFalse: [
  620. self selectItem: item ]
  621. !
  622. activateNextListItem
  623. self activateListItem: (self wrapper asJQuery find: ('li.', self activeItemCssClass)) next.
  624. "select the first item if none is selected"
  625. (self wrapper asJQuery find: (' .', self activeItemCssClass)) get ifEmpty: [
  626. self activateFirstListItem ]
  627. !
  628. activatePreviousListItem
  629. self activateListItem: (self wrapper asJQuery find: ('li.', self activeItemCssClass)) prev
  630. !
  631. ensureVisible: aListItem
  632. "Move the scrollbar to show the active element"
  633. | parent position |
  634. (aListItem get: 0) ifNil: [ ^ self ].
  635. position := self positionOf: aListItem.
  636. parent := aListItem parent.
  637. aListItem position top < 0 ifTrue: [
  638. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
  639. aListItem position top + aListItem height > parent height ifTrue: [
  640. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]
  641. !
  642. focus
  643. super focus.
  644. self items isEmpty ifFalse: [
  645. self selectedItem ifNil: [ self activateFirstListItem ] ]
  646. !
  647. reactivateListItem: aListItem
  648. self activateListItem: aListItem.
  649. self reselectItem: self selectedItem
  650. !
  651. refresh
  652. super refresh.
  653. self selectedItem ifNotNil: [self ensureVisible: (self findListItemFor: self selectedItem)].
  654. !
  655. reselectItem: anObject
  656. !
  657. selectItem: anObject
  658. self selectedItem: anObject
  659. ! !
  660. !HLListWidget methodsFor: 'defaults'!
  661. defaultItems
  662. ^ #()
  663. ! !
  664. !HLListWidget methodsFor: 'events'!
  665. setupKeyBindings
  666. (HLRepeatedKeyDownHandler on: self)
  667. whileKeyDown: 38 do: [ self activatePreviousListItem ];
  668. whileKeyDown: 40 do: [ self activateNextListItem ];
  669. rebindKeys.
  670. self wrapper asJQuery keydown: [ :e |
  671. e which = 13 ifTrue: [
  672. self reselectItem: self selectedItem ] ]
  673. ! !
  674. !HLListWidget methodsFor: 'rendering'!
  675. renderButtonsOn: html
  676. !
  677. renderContentOn: html
  678. html ul
  679. class: self listCssClass;
  680. with: [ self renderListOn: html ];
  681. onClick: [ self focus ].
  682. html div class: self buttonsDivCssClass; with: [
  683. self renderButtonsOn: html ].
  684. self setupKeyBindings
  685. !
  686. renderItem: anObject on: html
  687. | li |
  688. li := html li.
  689. li asJQuery data: 'item' put: anObject.
  690. li
  691. class: (self listCssClassForItem: anObject);
  692. with: [
  693. html a
  694. with: [
  695. (html tag: 'i') class: (self cssClassForItem: anObject).
  696. self renderItemLabel: anObject on: html ];
  697. onClick: [
  698. self reactivateListItem: li asJQuery ] ]
  699. !
  700. renderItemLabel: anObject on: html
  701. html with: anObject asString
  702. !
  703. renderListOn: html
  704. self items do: [ :each |
  705. self renderItem: each on: html ]
  706. ! !
  707. HLListWidget subclass: #HLNavigationListWidget
  708. instanceVariableNames: 'previous next'
  709. package: 'Helios-Core'!
  710. !HLNavigationListWidget methodsFor: 'accessing'!
  711. next
  712. ^ next
  713. !
  714. next: aWidget
  715. next := aWidget.
  716. aWidget previous = self ifFalse: [ aWidget previous: self ]
  717. !
  718. previous
  719. ^ previous
  720. !
  721. previous: aWidget
  722. previous := aWidget.
  723. aWidget next = self ifFalse: [ aWidget next: self ]
  724. ! !
  725. !HLNavigationListWidget methodsFor: 'actions'!
  726. nextFocus
  727. self next ifNotNil: [ self next focus ]
  728. !
  729. previousFocus
  730. self previous ifNotNil: [ self previous focus ]
  731. ! !
  732. !HLNavigationListWidget methodsFor: 'events'!
  733. setupKeyBindings
  734. super setupKeyBindings.
  735. self wrapper asJQuery keydown: [ :e |
  736. e which = 39 ifTrue: [
  737. self nextFocus ].
  738. e which = 37 ifTrue: [
  739. self previousFocus ] ]
  740. ! !
  741. HLNavigationListWidget subclass: #HLToolListWidget
  742. instanceVariableNames: 'model'
  743. package: 'Helios-Core'!
  744. !HLToolListWidget methodsFor: 'accessing'!
  745. commandCategory
  746. ^ self label
  747. !
  748. label
  749. ^ 'List'
  750. !
  751. menuCommands
  752. "Answer a collection of commands to be put in the cog menu"
  753. ^ ((HLToolCommand concreteClasses
  754. select: [ :each | each isValidFor: self model ])
  755. collect: [ :each | each for: self model ])
  756. select: [ :each |
  757. each category = self commandCategory and: [
  758. each isAction and: [ each isActive ] ] ]
  759. !
  760. model
  761. ^ model
  762. !
  763. model: aBrowserModel
  764. model := aBrowserModel.
  765. self
  766. observeSystem;
  767. observeModel
  768. !
  769. selectedItem: anItem
  770. "Selection changed, update the cog menu"
  771. super selectedItem: anItem.
  772. self updateMenu
  773. ! !
  774. !HLToolListWidget methodsFor: 'actions'!
  775. activateListItem: anItem
  776. self model withChangesDo: [ super activateListItem: anItem ]
  777. !
  778. activateNextListItem
  779. self model withChangesDo: [ super activateNextListItem ]
  780. !
  781. activatePreviousListItem
  782. self model withChangesDo: [ super activatePreviousListItem ]
  783. !
  784. observeModel
  785. !
  786. observeSystem
  787. !
  788. reactivateListItem: anItem
  789. self model withChangesDo: [ super reactivateListItem: anItem ]
  790. !
  791. unregister
  792. super unregister.
  793. self model announcer unsubscribe: self.
  794. self model systemAnnouncer unsubscribe: self
  795. ! !
  796. !HLToolListWidget methodsFor: 'rendering'!
  797. renderContentOn: html
  798. self renderHeadOn: html.
  799. super renderContentOn: html
  800. !
  801. renderHeadOn: html
  802. html div
  803. class: 'list-label';
  804. with: [
  805. html with: self label.
  806. self renderMenuOn: html ]
  807. !
  808. renderMenuOn: html
  809. | commands |
  810. commands := self menuCommands.
  811. commands isEmpty ifTrue: [ ^ self ].
  812. html div
  813. class: 'btn-group cog';
  814. with: [
  815. html a
  816. class: 'btn dropdown-toggle';
  817. at: 'data-toggle' put: 'dropdown';
  818. with: [ (html tag: 'i') class: 'icon-chevron-down' ].
  819. html ul
  820. class: 'dropdown-menu pull-right';
  821. with: [
  822. self menuCommands do: [ :each |
  823. html li with: [ html a
  824. with: each menuLabel;
  825. onClick: [ self execute: each ] ] ] ] ]
  826. ! !
  827. !HLToolListWidget methodsFor: 'updating'!
  828. updateMenu
  829. (self wrapper asJQuery find: '.cog') remove.
  830. [ :html | self renderMenuOn: html ]
  831. appendToJQuery: (self wrapper asJQuery find: '.list-label')
  832. ! !
  833. !HLToolListWidget class methodsFor: 'instance creation'!
  834. on: aModel
  835. ^ self new
  836. model: aModel;
  837. yourself
  838. ! !
  839. HLListWidget subclass: #HLTabListWidget
  840. instanceVariableNames: 'callback'
  841. package: 'Helios-Core'!
  842. !HLTabListWidget commentStamp!
  843. I am a widget used to display a list of helios tabs.
  844. When a tab is selected, `callback` is evaluated with the selected tab as argument.!
  845. !HLTabListWidget methodsFor: 'accessing'!
  846. callback
  847. ^ callback ifNil: [ [] ]
  848. !
  849. callback: aBlock
  850. callback := aBlock
  851. ! !
  852. !HLTabListWidget methodsFor: 'actions'!
  853. selectItem: aTab
  854. super selectItem: aTab.
  855. self callback value: aTab
  856. ! !
  857. !HLTabListWidget methodsFor: 'rendering'!
  858. renderItemLabel: aTab on: html
  859. html span
  860. class: aTab cssClass;
  861. with: aTab label
  862. ! !
  863. HLWidget subclass: #HLInformationWidget
  864. instanceVariableNames: 'informationString'
  865. package: 'Helios-Core'!
  866. !HLInformationWidget commentStamp!
  867. I display an information dialog.
  868. ## API
  869. `HLWidget >> #inform:` is a convenience method for creating information dialogs.!
  870. !HLInformationWidget methodsFor: 'accessing'!
  871. informationString
  872. ^ informationString ifNil: [ '' ]
  873. !
  874. informationString: anObject
  875. informationString := anObject
  876. ! !
  877. !HLInformationWidget methodsFor: 'actions'!
  878. remove
  879. [
  880. self wrapper asJQuery fadeOut: 100.
  881. [ self wrapper asJQuery remove ]
  882. valueWithTimeout: 400.
  883. ]
  884. valueWithTimeout: 1500
  885. !
  886. show
  887. self appendToJQuery: 'body' asJQuery
  888. ! !
  889. !HLInformationWidget methodsFor: 'rendering'!
  890. renderContentOn: html
  891. html div
  892. class: 'growl';
  893. with: self informationString.
  894. self remove
  895. ! !
  896. HLWidget subclass: #HLManager
  897. instanceVariableNames: 'tabsWidget environment history announcer'
  898. package: 'Helios-Core'!
  899. !HLManager methodsFor: 'accessing'!
  900. activeTab
  901. ^ self tabsWidget activeTab
  902. !
  903. announcer
  904. ^ announcer ifNil: [ announcer := Announcer new ]
  905. !
  906. environment
  907. "The default environment used by all Helios objects"
  908. ^ environment ifNil: [ environment := self defaultEnvironment ]
  909. !
  910. environment: anEnvironment
  911. environment := anEnvironment
  912. !
  913. history
  914. ^ history ifNil: [ history := OrderedCollection new ]
  915. !
  916. history: aCollection
  917. history := aCollection
  918. !
  919. keyBinder
  920. ^ HLKeyBinder current
  921. !
  922. setEditorTheme: aTheme
  923. 'helios.editorTheme' asSetting value: aTheme
  924. !
  925. setTheme: aTheme
  926. | currentTheme |
  927. currentTheme := 'helios.theme' asSettingIfAbsent: 'default'.
  928. 'body' asJQuery
  929. removeClass: currentTheme value;
  930. addClass: aTheme.
  931. 'helios.theme' asSetting value: aTheme
  932. !
  933. tabWidth
  934. ^ (window asJQuery width - 90) / self tabs size
  935. !
  936. tabs
  937. ^ self tabsWidget tabs
  938. !
  939. tabsWidget
  940. ^ tabsWidget ifNil: [ tabsWidget := HLTabsWidget new ]
  941. ! !
  942. !HLManager methodsFor: 'actions'!
  943. activate: aTab
  944. self tabsWidget activate: aTab
  945. !
  946. addTab: aTab
  947. self tabsWidget addTab: aTab
  948. !
  949. confirm: aString ifFalse: aBlock
  950. self
  951. confirm: aString
  952. ifTrue: []
  953. ifFalse: aBlock
  954. !
  955. confirm: aString ifTrue: aBlock
  956. self
  957. confirm: aString
  958. ifTrue: aBlock
  959. ifFalse: []
  960. !
  961. confirm: aString ifTrue: aBlock ifFalse: anotherBlock
  962. HLConfirmationWidget new
  963. confirmationString: aString;
  964. actionBlock: aBlock;
  965. cancelBlock: anotherBlock;
  966. show
  967. !
  968. inform: aString
  969. HLInformationWidget new
  970. informationString: aString;
  971. show
  972. !
  973. removeActiveTab
  974. self tabsWidget removeActiveTab
  975. !
  976. removeTabForWidget: aWidget
  977. self tabsWidget removeTabForWidget: aWidget
  978. !
  979. request: aString do: aBlock
  980. self
  981. request: aString
  982. value: ''
  983. do: aBlock
  984. !
  985. request: aString value: valueString do: aBlock
  986. HLRequestWidget new
  987. confirmationString: aString;
  988. actionBlock: aBlock;
  989. value: valueString;
  990. show
  991. ! !
  992. !HLManager methodsFor: 'defaults'!
  993. defaultEnvironment
  994. "If helios is loaded from within a frame, answer the parent window environment"
  995. | parent parentSmalltalkGlobals |
  996. parent := window opener ifNil: [ window parent ].
  997. parent ifNil: [ ^ Environment new ].
  998. [ parentSmalltalkGlobals := ((parent at: 'requirejs') value: 'amber/boot') at: 'globals' ]
  999. on: Error do: [ parentSmalltalkGlobals := (parent at: 'requirejs') value: 'amber_vm/globals' ].
  1000. parentSmalltalkGlobals ifNil: [ ^ Environment new ].
  1001. ^ (parentSmalltalkGlobals at: 'Environment') new
  1002. ! !
  1003. !HLManager methodsFor: 'initialization'!
  1004. setup
  1005. self
  1006. registerServices;
  1007. setupEvents.
  1008. self keyBinder setupEvents.
  1009. self tabsWidget setupEvents.
  1010. self setupTheme.
  1011. '#helper' asJQuery fadeOut
  1012. ! !
  1013. !HLManager methodsFor: 'private'!
  1014. registerServices
  1015. self
  1016. registerInspector;
  1017. registerErrorHandler;
  1018. registerProgressHandler;
  1019. registerTranscript;
  1020. registerFinder
  1021. !
  1022. setupEvents
  1023. 'body' asJQuery keydown: [ :event |
  1024. "On ctrl keydown, adds a 'navigation' css class to <body>
  1025. for the CodeMirror navigation links. See `HLCodeWidget`."
  1026. event ctrlKey ifTrue: [
  1027. 'body' asJQuery addClass: 'navigation' ] ].
  1028. 'body' asJQuery keyup: [ :event |
  1029. 'body' asJQuery removeClass: 'navigation' ].
  1030. window asJQuery resize: [ :event |
  1031. self refresh ]
  1032. !
  1033. setupTheme
  1034. "self
  1035. setTheme: 'niflheim';
  1036. setEditorTheme: 'niflheim'."
  1037. self
  1038. setTheme: 'default';
  1039. setEditorTheme: 'default'.
  1040. ! !
  1041. !HLManager methodsFor: 'rendering'!
  1042. renderContentOn: html
  1043. html with: self tabsWidget.
  1044. html with: HLWelcomeWidget new
  1045. ! !
  1046. !HLManager methodsFor: 'services'!
  1047. registerErrorHandler
  1048. self environment registerErrorHandler: HLErrorHandler new.
  1049. ErrorHandler register: HLErrorHandler new
  1050. !
  1051. registerFinder
  1052. self environment registerFinder: HLFinder new.
  1053. Finder register: HLFinder new
  1054. !
  1055. registerInspector
  1056. self environment registerInspector: HLInspector.
  1057. Inspector register: HLInspector
  1058. !
  1059. registerProgressHandler
  1060. self environment registerProgressHandler: HLProgressHandler new.
  1061. ProgressHandler register: HLProgressHandler new
  1062. !
  1063. registerTranscript
  1064. self environment registerTranscript: HLTranscriptHandler
  1065. ! !
  1066. HLManager class instanceVariableNames: 'current'!
  1067. !HLManager class methodsFor: 'accessing'!
  1068. current
  1069. ^ current ifNil: [ current := self basicNew initialize ]
  1070. ! !
  1071. !HLManager class methodsFor: 'initialization'!
  1072. setup
  1073. self current
  1074. setup;
  1075. appendToJQuery: 'body' asJQuery
  1076. ! !
  1077. !HLManager class methodsFor: 'instance creation'!
  1078. new
  1079. "Use current instead"
  1080. self shouldNotImplement
  1081. ! !
  1082. HLWidget subclass: #HLModalWidget
  1083. instanceVariableNames: ''
  1084. package: 'Helios-Core'!
  1085. !HLModalWidget commentStamp!
  1086. I implement an abstract modal widget.!
  1087. !HLModalWidget methodsFor: 'actions'!
  1088. remove
  1089. '.dialog' asJQuery removeClass: 'active'.
  1090. [
  1091. '#overlay' asJQuery remove.
  1092. wrapper asJQuery remove
  1093. ] valueWithTimeout: 300
  1094. !
  1095. show
  1096. self appendToJQuery: 'body' asJQuery
  1097. ! !
  1098. !HLModalWidget methodsFor: 'private'!
  1099. giveFocusToButton: aButton
  1100. aButton asJQuery focus
  1101. ! !
  1102. !HLModalWidget methodsFor: 'rendering'!
  1103. hasButtons
  1104. ^ true
  1105. !
  1106. renderButtonsOn: html
  1107. !
  1108. renderContentOn: html
  1109. | confirmButton |
  1110. html div id: 'overlay'.
  1111. html div
  1112. class: 'dialog ', self cssClass;
  1113. with: [
  1114. self renderMainOn: html.
  1115. self hasButtons ifTrue: [
  1116. self renderButtonsOn: html ] ].
  1117. '.dialog' asJQuery addClass: 'active'.
  1118. self setupKeyBindings
  1119. !
  1120. renderMainOn: html
  1121. !
  1122. setupKeyBindings
  1123. '.dialog' asJQuery keyup: [ :e |
  1124. e keyCode = String esc asciiValue ifTrue: [ self cancel ] ]
  1125. ! !
  1126. HLModalWidget subclass: #HLConfirmationWidget
  1127. instanceVariableNames: 'cancelButtonLabel confirmButtonLabel confirmationString actionBlock cancelBlock'
  1128. package: 'Helios-Core'!
  1129. !HLConfirmationWidget commentStamp!
  1130. I display confirmation dialog.
  1131. ## API
  1132. HLWidget contains convenience methods like `HLWidget >> #confirm:ifTrue:` for creating confirmation dialogs.!
  1133. !HLConfirmationWidget methodsFor: 'accessing'!
  1134. actionBlock
  1135. ^ actionBlock ifNil: [ [] ]
  1136. !
  1137. actionBlock: aBlock
  1138. actionBlock := aBlock
  1139. !
  1140. cancelBlock
  1141. ^ cancelBlock ifNil: [ [] ]
  1142. !
  1143. cancelBlock: aBlock
  1144. cancelBlock := aBlock
  1145. !
  1146. cancelButtonLabel
  1147. ^ cancelButtonLabel ifNil: [ 'Cancel' ]
  1148. !
  1149. cancelButtonLabel: aString
  1150. ^ cancelButtonLabel := aString
  1151. !
  1152. confirmButtonLabel
  1153. ^ confirmButtonLabel ifNil: [ 'Confirm' ]
  1154. !
  1155. confirmButtonLabel: aString
  1156. ^ confirmButtonLabel := aString
  1157. !
  1158. confirmationString
  1159. ^ confirmationString ifNil: [ 'Confirm' ]
  1160. !
  1161. confirmationString: aString
  1162. confirmationString := aString
  1163. ! !
  1164. !HLConfirmationWidget methodsFor: 'actions'!
  1165. cancel
  1166. self cancelBlock value.
  1167. self remove
  1168. !
  1169. confirm
  1170. self remove.
  1171. self actionBlock value
  1172. ! !
  1173. !HLConfirmationWidget methodsFor: 'rendering'!
  1174. renderButtonsOn: html
  1175. | confirmButton |
  1176. html div
  1177. class: 'buttons';
  1178. with: [
  1179. html button
  1180. class: 'button';
  1181. with: self cancelButtonLabel;
  1182. onClick: [ self cancel ].
  1183. confirmButton := html button
  1184. class: 'button default';
  1185. with: self confirmButtonLabel;
  1186. onClick: [ self confirm ] ].
  1187. self giveFocusToButton:confirmButton
  1188. !
  1189. renderMainOn: html
  1190. html span
  1191. class: 'head';
  1192. with: self confirmationString
  1193. ! !
  1194. HLConfirmationWidget subclass: #HLRequestWidget
  1195. instanceVariableNames: 'input multiline value'
  1196. package: 'Helios-Core'!
  1197. !HLRequestWidget commentStamp!
  1198. I display a modal window requesting user input.
  1199. ## API
  1200. `HLWidget >> #request:do:` and `#request:value:do:` are convenience methods for creating modal request dialogs.!
  1201. !HLRequestWidget methodsFor: 'accessing'!
  1202. beMultiline
  1203. multiline := true
  1204. !
  1205. beSingleline
  1206. multiline := false
  1207. !
  1208. cssClass
  1209. ^ 'large'
  1210. !
  1211. value
  1212. ^ value ifNil: [ '' ]
  1213. !
  1214. value: aString
  1215. value := aString
  1216. ! !
  1217. !HLRequestWidget methodsFor: 'actions'!
  1218. confirm
  1219. | val |
  1220. val := input asJQuery val.
  1221. self remove.
  1222. self actionBlock value: val
  1223. ! !
  1224. !HLRequestWidget methodsFor: 'private'!
  1225. giveFocusToButton: aButton
  1226. ! !
  1227. !HLRequestWidget methodsFor: 'rendering'!
  1228. renderMainOn: html
  1229. super renderMainOn: html.
  1230. self isMultiline
  1231. ifTrue: [ input := html textarea ]
  1232. ifFalse: [ input := html input
  1233. type: 'text';
  1234. onKeyDown: [ :event |
  1235. event keyCode = 13 ifTrue: [
  1236. self confirm ] ];
  1237. yourself ].
  1238. input asJQuery
  1239. val: self value;
  1240. focus
  1241. ! !
  1242. !HLRequestWidget methodsFor: 'testing'!
  1243. isMultiline
  1244. ^ multiline ifNil: [ true ]
  1245. ! !
  1246. HLModalWidget subclass: #HLProgressWidget
  1247. instanceVariableNames: 'progressBars visible'
  1248. package: 'Helios-Core'!
  1249. !HLProgressWidget commentStamp!
  1250. I am a widget used to display progress modal dialogs.
  1251. My default instance is accessed with `HLProgressWidget class >> #default`.
  1252. See `HLProgressHandler` for usage.!
  1253. !HLProgressWidget methodsFor: 'accessing'!
  1254. progressBars
  1255. ^ progressBars ifNil: [ progressBars := OrderedCollection new ]
  1256. ! !
  1257. !HLProgressWidget methodsFor: 'actions'!
  1258. addProgressBar: aProgressBar
  1259. self show.
  1260. self progressBars add: aProgressBar.
  1261. aProgressBar appendToJQuery: (self wrapper asJQuery find: '.dialog')
  1262. !
  1263. do: aBlock on: aCollection displaying: aString
  1264. | progressBar |
  1265. progressBar := HLProgressBarWidget new
  1266. parent: self;
  1267. label: aString;
  1268. workBlock: aBlock;
  1269. collection: aCollection;
  1270. yourself.
  1271. self addProgressBar: progressBar.
  1272. progressBar start
  1273. !
  1274. flush
  1275. self progressBars do: [ :each |
  1276. self removeProgressBar: each ]
  1277. !
  1278. remove
  1279. self isVisible ifTrue: [
  1280. visible := false.
  1281. super remove ]
  1282. !
  1283. removeProgressBar: aProgressBar
  1284. self progressBars remove: aProgressBar ifAbsent: [].
  1285. aProgressBar wrapper asJQuery remove.
  1286. self progressBars ifEmpty: [ self remove ]
  1287. !
  1288. show
  1289. self isVisible ifFalse: [
  1290. visible := true.
  1291. super show ]
  1292. ! !
  1293. !HLProgressWidget methodsFor: 'rendering'!
  1294. renderMainOn: html
  1295. self progressBars do: [ :each |
  1296. html with: each ]
  1297. ! !
  1298. !HLProgressWidget methodsFor: 'testing'!
  1299. hasButtons
  1300. ^ false
  1301. !
  1302. isVisible
  1303. ^ visible ifNil: [ false ]
  1304. ! !
  1305. HLProgressWidget class instanceVariableNames: 'default'!
  1306. !HLProgressWidget class methodsFor: 'accessing'!
  1307. default
  1308. ^ default ifNil: [ default := self new ]
  1309. ! !
  1310. HLModalWidget subclass: #HLTabSelectionWidget
  1311. instanceVariableNames: 'tabs tabList selectedTab selectCallback cancelCallback confirmCallback'
  1312. package: 'Helios-Core'!
  1313. !HLTabSelectionWidget commentStamp!
  1314. I am a modal window used to select or create tabs.!
  1315. !HLTabSelectionWidget methodsFor: 'accessing'!
  1316. cancelCallback
  1317. ^ cancelCallback ifNil: [ [] ]
  1318. !
  1319. cancelCallback: aBlock
  1320. cancelCallback := aBlock
  1321. !
  1322. confirmCallback
  1323. ^ confirmCallback ifNil: [ [] ]
  1324. !
  1325. confirmCallback: aBlock
  1326. confirmCallback := aBlock
  1327. !
  1328. selectCallback
  1329. ^ selectCallback ifNil: [ [] ]
  1330. !
  1331. selectCallback: aBlock
  1332. selectCallback := aBlock
  1333. !
  1334. selectedTab
  1335. ^ selectedTab
  1336. !
  1337. selectedTab: aTab
  1338. selectedTab := aTab
  1339. !
  1340. tabs
  1341. ^ tabs ifNil: [ #() ]
  1342. !
  1343. tabs: aCollection
  1344. tabs := aCollection
  1345. ! !
  1346. !HLTabSelectionWidget methodsFor: 'actions'!
  1347. cancel
  1348. self remove.
  1349. self cancelCallback value
  1350. !
  1351. confirm
  1352. self remove.
  1353. self confirmCallback value: self selectedTab
  1354. !
  1355. selectTab: aTab
  1356. self selectedTab: aTab.
  1357. self selectCallback value: aTab
  1358. !
  1359. setupKeyBindings
  1360. super setupKeyBindings.
  1361. '.dialog' asJQuery keyup: [ :e |
  1362. e keyCode = String cr asciiValue ifTrue: [ self confirm ] ]
  1363. ! !
  1364. !HLTabSelectionWidget methodsFor: 'rendering'!
  1365. renderButtonsOn: html
  1366. | confirmButton |
  1367. html div
  1368. class: 'buttons';
  1369. with: [
  1370. html button
  1371. class: 'button';
  1372. with: 'Cancel';
  1373. onClick: [ self cancel ].
  1374. confirmButton := html button
  1375. class: 'button default';
  1376. with: 'Select tab';
  1377. onClick: [ self confirm ] ].
  1378. self giveFocusToButton:confirmButton
  1379. !
  1380. renderContentOn: html
  1381. super renderContentOn: html.
  1382. self tabList focus
  1383. !
  1384. renderMainOn: html
  1385. html div
  1386. class: 'title';
  1387. with: 'Tab selection'.
  1388. html with: self tabList
  1389. !
  1390. renderTab: aTab on: html
  1391. html
  1392. span
  1393. class: aTab cssClass;
  1394. with: aTab label
  1395. !
  1396. renderTabsOn: html
  1397. self tabs do: [ :each |
  1398. html li with: [
  1399. html a
  1400. with: [
  1401. self renderTab: each on: html ];
  1402. onClick: [ self selectTab: each ] ] ]
  1403. !
  1404. tabList
  1405. tabList ifNil: [
  1406. tabList := HLTabListWidget new.
  1407. tabList
  1408. callback: [ :tab | self selectTab: tab. tabList focus ];
  1409. selectedItem: self selectedTab;
  1410. items: self tabs ].
  1411. ^ tabList
  1412. ! !
  1413. HLWidget subclass: #HLProgressBarWidget
  1414. instanceVariableNames: 'label parent workBlock collection bar'
  1415. package: 'Helios-Core'!
  1416. !HLProgressBarWidget commentStamp!
  1417. I am a widget used to display a progress bar while iterating over a collection.!
  1418. !HLProgressBarWidget methodsFor: 'accessing'!
  1419. collection
  1420. ^ collection
  1421. !
  1422. collection: aCollection
  1423. collection := aCollection
  1424. !
  1425. label
  1426. ^ label
  1427. !
  1428. label: aString
  1429. label := aString
  1430. !
  1431. parent
  1432. ^ parent
  1433. !
  1434. parent: aProgress
  1435. parent := aProgress
  1436. !
  1437. workBlock
  1438. ^ workBlock
  1439. !
  1440. workBlock: aBlock
  1441. workBlock := aBlock
  1442. ! !
  1443. !HLProgressBarWidget methodsFor: 'actions'!
  1444. evaluateAt: anInteger
  1445. self updateProgress: (anInteger / self collection size) * 100.
  1446. anInteger <= self collection size
  1447. ifTrue: [
  1448. [
  1449. self workBlock value: (self collection at: anInteger).
  1450. self evaluateAt: anInteger + 1 ] valueWithTimeout: 10 ]
  1451. ifFalse: [ [ self remove ] valueWithTimeout: 500 ]
  1452. !
  1453. remove
  1454. self parent removeProgressBar: self
  1455. !
  1456. start
  1457. "Make sure the UI has some time to update itself between each iteration"
  1458. self evaluateAt: 1
  1459. !
  1460. updateProgress: anInteger
  1461. bar asJQuery css: 'width' put: anInteger asString, '%'
  1462. ! !
  1463. !HLProgressBarWidget methodsFor: 'rendering'!
  1464. renderContentOn: html
  1465. html span with: self label.
  1466. html div
  1467. class: 'progress';
  1468. with: [
  1469. bar := html div
  1470. class: 'bar';
  1471. style: 'width: 0%' ]
  1472. ! !
  1473. HLProgressBarWidget class instanceVariableNames: 'default'!
  1474. !HLProgressBarWidget class methodsFor: 'accessing'!
  1475. default
  1476. ^ default ifNil: [ default := self new ]
  1477. ! !
  1478. HLWidget subclass: #HLTabWidget
  1479. instanceVariableNames: 'widget label root'
  1480. package: 'Helios-Core'!
  1481. !HLTabWidget commentStamp!
  1482. I am a widget specialized into building another widget as an Helios tab.
  1483. I should not be used directly, `HLWidget class >> #openAsTab` should be used instead.
  1484. ## Example
  1485. HLWorkspace openAsTab!
  1486. !HLTabWidget methodsFor: 'accessing'!
  1487. activate
  1488. self manager activate: self
  1489. !
  1490. cssClass
  1491. ^ self widget tabClass
  1492. !
  1493. focus
  1494. self widget canHaveFocus ifTrue: [
  1495. self widget focus ]
  1496. !
  1497. label
  1498. ^ label ifNil: [ '' ]
  1499. !
  1500. label: aString
  1501. label := aString
  1502. !
  1503. manager
  1504. ^ HLManager current
  1505. !
  1506. widget
  1507. ^ widget
  1508. !
  1509. widget: aWidget
  1510. widget := aWidget
  1511. ! !
  1512. !HLTabWidget methodsFor: 'actions'!
  1513. add
  1514. self manager addTab: self.
  1515. self observeManager
  1516. !
  1517. hide
  1518. root ifNotNil: [ root asJQuery css: 'visibility' put: 'hidden' ]
  1519. !
  1520. observeManager
  1521. self manager announcer
  1522. on: HLTabLabelChanged
  1523. send: #onTabLabelChanged:
  1524. to: self
  1525. !
  1526. registerBindings
  1527. self widget registerBindings
  1528. !
  1529. remove
  1530. self unregister.
  1531. self widget unregister.
  1532. root ifNotNil: [ root asJQuery remove ]
  1533. !
  1534. show
  1535. root
  1536. ifNil: [ self appendToJQuery: 'body' asJQuery ]
  1537. ifNotNil: [ root asJQuery css: 'visibility' put: 'visible' ]
  1538. !
  1539. unregister
  1540. self manager announcer unsubscribe: self
  1541. ! !
  1542. !HLTabWidget methodsFor: 'reactions'!
  1543. onTabLabelChanged: anAnnouncement
  1544. anAnnouncement widget = self widget ifTrue: [
  1545. self label = anAnnouncement label ifFalse: [
  1546. self label: anAnnouncement label.
  1547. self manager refresh ] ]
  1548. ! !
  1549. !HLTabWidget methodsFor: 'rendering'!
  1550. renderOn: html
  1551. root := html div
  1552. class: 'tab';
  1553. yourself.
  1554. self renderTab
  1555. !
  1556. renderTab
  1557. root contents: [ :html |
  1558. html div
  1559. class: 'amber_box';
  1560. with: [ self widget renderOn: html ] ]
  1561. ! !
  1562. !HLTabWidget methodsFor: 'testing'!
  1563. isActive
  1564. ^ self manager activeTab = self
  1565. ! !
  1566. !HLTabWidget class methodsFor: 'instance creation'!
  1567. on: aWidget labelled: aString
  1568. ^ self new
  1569. widget: aWidget;
  1570. label: aString;
  1571. yourself
  1572. ! !
  1573. HLWidget subclass: #HLTabsWidget
  1574. instanceVariableNames: 'tabs activeTab history selectionDisabled'
  1575. package: 'Helios-Core'!
  1576. !HLTabsWidget methodsFor: 'accessing'!
  1577. activeTab
  1578. ^ activeTab
  1579. !
  1580. history
  1581. ^ history ifNil: [ history := OrderedCollection new ]
  1582. !
  1583. history: aCollection
  1584. history := aCollection
  1585. !
  1586. tabWidth
  1587. ^ (window asJQuery width - 90) / self tabs size
  1588. !
  1589. tabs
  1590. ^ tabs ifNil: [ tabs := OrderedCollection new ]
  1591. ! !
  1592. !HLTabsWidget methodsFor: 'actions'!
  1593. activate: aTab
  1594. self isSelectionDisabled ifTrue: [ ^ self ].
  1595. self manager keyBinder flushBindings.
  1596. aTab registerBindings.
  1597. activeTab := aTab.
  1598. self
  1599. refresh;
  1600. addToHistory: aTab;
  1601. show: aTab
  1602. !
  1603. activateNextTab
  1604. | nextTab |
  1605. self tabs ifEmpty: [ ^ self ].
  1606. nextTab := self tabs
  1607. at: (self tabs indexOf: self activeTab) + 1
  1608. ifAbsent: [ self tabs first ].
  1609. self activate: nextTab
  1610. !
  1611. activatePreviousTab
  1612. | previousTab |
  1613. self tabs ifEmpty: [ ^ self ].
  1614. previousTab := self tabs
  1615. at: (self tabs indexOf: self activeTab) - 1
  1616. ifAbsent: [ self tabs last ].
  1617. self activate: previousTab
  1618. !
  1619. addTab: aTab
  1620. self tabs add: aTab.
  1621. self activate: aTab
  1622. !
  1623. addToHistory: aTab
  1624. self removeFromHistory: aTab.
  1625. self history add: aTab
  1626. !
  1627. disableSelection
  1628. selectionDisabled := true
  1629. !
  1630. enableSelection
  1631. selectionDisabled := false
  1632. !
  1633. removeActiveTab
  1634. self removeTab: self activeTab
  1635. !
  1636. removeFromHistory: aTab
  1637. self history: (self history reject: [ :each | each == aTab ])
  1638. !
  1639. removeTab: aTab
  1640. (self tabs includes: aTab) ifFalse: [ ^ self ].
  1641. self removeFromHistory: aTab.
  1642. self tabs remove: aTab.
  1643. self manager keyBinder flushBindings.
  1644. aTab remove.
  1645. self refresh.
  1646. self history ifNotEmpty: [
  1647. self history last activate ]
  1648. !
  1649. removeTabForWidget: aWidget
  1650. self removeTab: (self tabs
  1651. detect: [ :each | each widget = aWidget ]
  1652. ifNone: [ ^ self ])
  1653. !
  1654. updateTabsOrder
  1655. tabs := '.main-tabs li' asJQuery toArray
  1656. collect: [ :each | each at: 'tab-data' ]
  1657. ! !
  1658. !HLTabsWidget methodsFor: 'private'!
  1659. setupEvents
  1660. 'body' asJQuery keydown: [ :event |
  1661. "ctrl+> and ctrl+<"
  1662. (event ctrlKey and: [ event which = 188 ]) ifTrue: [
  1663. self activatePreviousTab.
  1664. event preventDefault ].
  1665. (event ctrlKey and: [ event which = 190 ]) ifTrue: [
  1666. self activateNextTab.
  1667. event preventDefault ] ]
  1668. ! !
  1669. !HLTabsWidget methodsFor: 'rendering'!
  1670. renderAddOn: html
  1671. html div
  1672. class: 'dropdown new_tab';
  1673. with: [
  1674. html a
  1675. class: 'dropdown-toggle';
  1676. at: 'data-toggle' put: 'dropdown';
  1677. with: [
  1678. (html tag: 'b') class: 'caret' ].
  1679. html ul
  1680. class: 'dropdown-menu';
  1681. with: [
  1682. ((HLWidget withAllSubclasses
  1683. select: [ :each | each canBeOpenAsTab ])
  1684. sorted: [ :a :b | a tabPriority < b tabPriority ])
  1685. do: [ :each |
  1686. html li with: [
  1687. html a
  1688. with: each tabLabel;
  1689. onClick: [ each openAsTab ] ] ] ] ]
  1690. !
  1691. renderContentOn: html
  1692. html div
  1693. class: 'navbar navbar-fixed-top';
  1694. with: [ html div
  1695. class: 'navbar-inner';
  1696. with: [ self renderTabsOn: html ] ].
  1697. self renderAddOn: html
  1698. !
  1699. renderTab: aTab on: html
  1700. | li |
  1701. li := html li
  1702. style: 'width: ', self tabWidth asString, 'px';
  1703. class: (aTab isActive ifTrue: [ 'tab active' ] ifFalse: [ 'tab inactive' ]);
  1704. with: [
  1705. html a
  1706. with: [
  1707. ((html tag: 'i') class: 'close')
  1708. onClick: [ self removeTab: aTab ].
  1709. html span
  1710. class: aTab cssClass;
  1711. title: aTab label;
  1712. with: aTab label ] ];
  1713. onClick: [ aTab activate ].
  1714. (li asJQuery get: 0) at: 'tab-data' put: aTab
  1715. !
  1716. renderTabsOn: html
  1717. | ul |
  1718. ul := html ul
  1719. class: 'nav main-tabs';
  1720. with: [
  1721. self tabs do: [ :each |
  1722. self renderTab: each on: html ] ].
  1723. ul asJQuery sortable: #{
  1724. 'containment' -> 'parent'.
  1725. 'start' -> [ self disableSelection ].
  1726. 'stop' -> [ [ self enableSelection] valueWithTimeout: 300 ].
  1727. 'update' -> [ self updateTabsOrder ]
  1728. }
  1729. !
  1730. show: aTab
  1731. self tabs do: [ :each | each hide ].
  1732. aTab show; focus
  1733. ! !
  1734. !HLTabsWidget methodsFor: 'testing'!
  1735. isSelectionDisabled
  1736. ^ selectionDisabled ifNil: [ false ]
  1737. ! !
  1738. HLTabsWidget class instanceVariableNames: 'current'!
  1739. HLWidget subclass: #HLWelcomeWidget
  1740. instanceVariableNames: ''
  1741. package: 'Helios-Core'!
  1742. !HLWelcomeWidget methodsFor: 'accessing'!
  1743. cssClass
  1744. ^ 'welcome'
  1745. ! !
  1746. !HLWelcomeWidget methodsFor: 'actions'!
  1747. openClassBrowser
  1748. HLBrowser openAsTab
  1749. !
  1750. openHelp
  1751. !
  1752. openTestRunner
  1753. HLSUnit openAsTab
  1754. !
  1755. openWorkspace
  1756. HLWorkspace openAsTab
  1757. ! !
  1758. !HLWelcomeWidget methodsFor: 'rendering'!
  1759. renderButtonsOn: html
  1760. html button
  1761. class: 'button';
  1762. with: 'Class Browser';
  1763. onClick: [ self openClassBrowser ].
  1764. html button
  1765. class: 'button';
  1766. with: 'Workspace';
  1767. onClick: [ self openWorkspace ].
  1768. html button
  1769. class: 'button';
  1770. with: 'Test Runner';
  1771. onClick: [ self openTestRunner ].
  1772. "html button
  1773. class: 'button';
  1774. with: 'Help';
  1775. onClick: [ self openHelp ]"
  1776. !
  1777. renderContentOn: html
  1778. self
  1779. renderHelpOn: html;
  1780. renderButtonsOn: html
  1781. !
  1782. renderHelpOn: html
  1783. html h2 with: 'No tools are open'.
  1784. html ul with: [
  1785. html li with: 'Perform actions with ctrl + space'.
  1786. html li with: 'Open one of the common tools:' ]
  1787. ! !