Helios-Core.st 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890
  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. aBlock value.
  33. ]
  34. on: HLChangeForbidden
  35. do: [ :ex | ]
  36. ! !
  37. !HLModel methodsFor: 'testing'!
  38. isBrowserModel
  39. ^ false
  40. !
  41. isReferencesModel
  42. ^ false
  43. !
  44. isToolModel
  45. ^ false
  46. ! !
  47. HLModel subclass: #HLFinder
  48. instanceVariableNames: ''
  49. package: 'Helios-Core'!
  50. !HLFinder commentStamp!
  51. I am the `Finder` service handler of Helios.
  52. Finding a class will open a new class browser, while finding a method will open a references browser.!
  53. !HLFinder methodsFor: 'finding'!
  54. findClass: aClass
  55. HLBrowser openAsTab openClassNamed: aClass name
  56. !
  57. findMethod: aCompiledMethod
  58. HLBrowser openAsTab openMethod: aCompiledMethod
  59. !
  60. findString: aString
  61. | foundClass |
  62. foundClass := self environment classes
  63. detect: [ :each | each name = aString ]
  64. ifNone: [ nil ].
  65. foundClass
  66. ifNil: [ HLReferences openAsTab search: aString ]
  67. ifNotNil: [ self findClass: foundClass ]
  68. ! !
  69. HLModel subclass: #HLToolModel
  70. instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
  71. package: 'Helios-Core'!
  72. !HLToolModel commentStamp!
  73. I am a model specific to package and class manipulation. All browsers should either use me or a subclass as their model.
  74. I provide methods for package, class, protocol and method manipulation and access, forwarding to my environment.
  75. I also handle compilation of classes and methods as well as compilation and parsing errors.!
  76. !HLToolModel methodsFor: 'accessing'!
  77. allSelectors
  78. ^ self environment allSelectors
  79. !
  80. availableClassNames
  81. ^ self environment availableClassNames
  82. !
  83. availablePackageNames
  84. ^ self environment availablePackageNames
  85. !
  86. availablePackages
  87. ^ self environment availablePackageNames
  88. !
  89. availableProtocols
  90. ^ self environment availableProtocolsFor: self selectedClass
  91. !
  92. packageToCommit
  93. "Answer the package to commit depending on the context:
  94. - if a Method is selected, answer its package
  95. - else answer the `selectedPackage`"
  96. ^ self selectedMethod
  97. ifNil: [ self selectedPackage ]
  98. ifNotNil: [ :method | method package ]
  99. !
  100. packages
  101. ^ self environment packages
  102. !
  103. selectedClass
  104. ^ selectedClass
  105. !
  106. selectedClass: aClass
  107. (self selectedClass = aClass and: [ aClass isNil ])
  108. ifTrue: [ ^ self ].
  109. self withChangesDo: [
  110. selectedClass = aClass ifTrue: [
  111. self selectedProtocol: nil ].
  112. aClass
  113. ifNil: [ selectedClass := nil ]
  114. ifNotNil: [
  115. self selectedPackage: aClass theNonMetaClass package.
  116. self showInstance
  117. ifTrue: [ selectedClass := aClass theNonMetaClass ]
  118. ifFalse: [ selectedClass := aClass theMetaClass ] ].
  119. self selectedProtocol: nil.
  120. self announcer announce: (HLClassSelected on: self selectedClass) ]
  121. !
  122. selectedMethod
  123. ^ self selectedClass ifNotNil: [
  124. self selectedClass methodDictionary
  125. at: selectedSelector
  126. ifAbsent: [ nil ] ]
  127. !
  128. selectedMethod: aCompiledMethod
  129. selectedSelector = aCompiledMethod ifTrue: [ ^ self ].
  130. self withChangesDo: [
  131. aCompiledMethod
  132. ifNil: [ selectedSelector := nil ]
  133. ifNotNil: [
  134. selectedClass := aCompiledMethod methodClass.
  135. selectedPackage := selectedClass theNonMetaClass package.
  136. selectedSelector := aCompiledMethod selector ].
  137. self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
  138. !
  139. selectedPackage
  140. ^ selectedPackage
  141. !
  142. selectedPackage: aPackage
  143. selectedPackage = aPackage ifTrue: [ ^ self ].
  144. self withChangesDo: [
  145. selectedPackage := aPackage.
  146. self selectedClass: nil.
  147. self announcer announce: (HLPackageSelected on: aPackage) ]
  148. !
  149. selectedProtocol
  150. ^ selectedProtocol
  151. !
  152. selectedProtocol: aString
  153. selectedProtocol = aString ifTrue: [ ^ self ].
  154. self withChangesDo: [
  155. selectedProtocol := aString.
  156. self selectedMethod: nil.
  157. self announcer announce: (HLProtocolSelected on: aString) ]
  158. ! !
  159. !HLToolModel methodsFor: 'actions'!
  160. addInstVarNamed: aString
  161. self environment addInstVarNamed: aString to: self selectedClass.
  162. self announcer announce: (HLInstVarAdded new
  163. theClass: self selectedClass;
  164. variableName: aString;
  165. yourself)
  166. !
  167. save: aString
  168. self announcer announce: HLSourceCodeSaved new.
  169. (self shouldCompileClassDefinition: aString)
  170. ifTrue: [ self compileClassDefinition: aString ]
  171. ifFalse: [ self compileMethod: aString ]
  172. !
  173. saveSourceCode
  174. self announcer announce: HLSaveSourceCode new
  175. ! !
  176. !HLToolModel methodsFor: 'commands actions'!
  177. commitPackage
  178. self environment commitPackage: self packageToCommit
  179. !
  180. copyClassTo: aClassName
  181. self withChangesDo: [
  182. self environment
  183. copyClass: self selectedClass theNonMetaClass
  184. to: aClassName ]
  185. !
  186. moveClassToPackage: aPackageName
  187. self withChangesDo: [
  188. self environment
  189. moveClass: self selectedClass theNonMetaClass
  190. toPackage: aPackageName ]
  191. !
  192. moveMethodToClass: aClassName
  193. self withChangesDo: [
  194. self environment
  195. moveMethod: self selectedMethod
  196. toClass: aClassName ]
  197. !
  198. moveMethodToProtocol: aProtocol
  199. self withChangesDo: [
  200. self environment
  201. moveMethod: self selectedMethod
  202. toProtocol: aProtocol ]
  203. !
  204. openClassNamed: aString
  205. | class |
  206. self withChangesDo: [
  207. class := self environment classNamed: aString.
  208. self selectedPackage: class package.
  209. self selectedClass: class ]
  210. !
  211. removeClass
  212. self withChangesDo: [
  213. self manager
  214. confirm: 'Do you REALLY want to remove class ', self selectedClass name
  215. ifTrue: [ self environment removeClass: self selectedClass ] ]
  216. !
  217. removeMethod
  218. self withChangesDo: [
  219. self manager
  220. confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector
  221. ifTrue: [ self environment removeMethod: self selectedMethod ] ]
  222. !
  223. removeProtocol
  224. self withChangesDo: [
  225. self manager
  226. confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol
  227. ifTrue: [ self environment
  228. removeProtocol: self selectedProtocol
  229. from: self selectedClass ] ]
  230. !
  231. renameClassTo: aClassName
  232. self withChangesDo: [
  233. self environment
  234. renameClass: self selectedClass theNonMetaClass
  235. to: aClassName ]
  236. !
  237. renameProtocolTo: aString
  238. self withChangesDo: [
  239. self environment
  240. renameProtocol: self selectedProtocol
  241. to: aString
  242. in: self selectedClass ]
  243. ! !
  244. !HLToolModel methodsFor: 'compiling'!
  245. compileClassComment: aString
  246. self environment
  247. compileClassComment: aString
  248. for: self selectedClass
  249. !
  250. compileClassDefinition: aString
  251. self environment compileClassDefinition: aString
  252. !
  253. compileMethod: aString
  254. | method |
  255. self withCompileErrorHandling: [
  256. method := self environment
  257. compileMethod: aString
  258. for: self selectedClass
  259. protocol: self compilationProtocol.
  260. self selectedMethod: method ]
  261. ! !
  262. !HLToolModel methodsFor: 'defaults'!
  263. allProtocol
  264. ^ '-- all --'
  265. !
  266. unclassifiedProtocol
  267. ^ 'as yet unclassified'
  268. ! !
  269. !HLToolModel methodsFor: 'error handling'!
  270. handleCompileError: anError
  271. self announcer announce: (HLCompileErrorRaised new
  272. error: anError;
  273. yourself)
  274. !
  275. handleParseError: anError
  276. | split line column messageToInsert |
  277. split := anError messageText tokenize: ' : '.
  278. messageToInsert := split second.
  279. "21 = 'Parse error on line ' size + 1"
  280. split := split first copyFrom: 21 to: split first size.
  281. split := split tokenize: ' column '.
  282. line := split first.
  283. column := split second.
  284. self announcer announce: (HLParseErrorRaised new
  285. line: line asNumber;
  286. column: column asNumber;
  287. message: messageToInsert;
  288. error: anError;
  289. yourself)
  290. !
  291. handleUnkownVariableError: anError
  292. self announcer announce: (HLUnknownVariableErrorRaised new
  293. error: anError;
  294. yourself)
  295. !
  296. withCompileErrorHandling: aBlock
  297. self environment
  298. evaluate: [
  299. self environment
  300. evaluate: [
  301. self environment
  302. evaluate: aBlock
  303. on: ParseError
  304. do: [ :ex | self handleParseError: ex ] ]
  305. on: UnknownVariableError
  306. do: [ :ex | self handleUnkownVariableError: ex ] ]
  307. on: CompilerError
  308. do: [ :ex | self handleCompileError: ex ]
  309. ! !
  310. !HLToolModel methodsFor: 'private'!
  311. compilationProtocol
  312. | currentProtocol |
  313. currentProtocol := self selectedProtocol.
  314. currentProtocol ifNil: [ currentProtocol := self unclassifiedProtocol ].
  315. self selectedMethod ifNotNil: [ currentProtocol := self selectedMethod protocol ].
  316. ^ currentProtocol = self allProtocol
  317. ifTrue: [ self unclassifiedProtocol ]
  318. ifFalse: [ currentProtocol ]
  319. !
  320. withHelperLabelled: aString do: aBlock
  321. "TODO: doesn't belong here"
  322. '#helper' asJQuery remove.
  323. [ :html |
  324. html div
  325. id: 'helper';
  326. with: aString ] appendToJQuery: 'body' asJQuery.
  327. [
  328. aBlock value.
  329. '#helper' asJQuery remove
  330. ]
  331. valueWithTimeout: 10
  332. ! !
  333. !HLToolModel methodsFor: 'testing'!
  334. isToolModel
  335. ^ true
  336. !
  337. shouldCompileClassDefinition: aString
  338. ^ self selectedClass isNil or: [
  339. aString match: '^\s*[A-Z]' ]
  340. ! !
  341. !HLToolModel class methodsFor: 'actions'!
  342. on: anEnvironment
  343. ^ self new
  344. environment: anEnvironment;
  345. yourself
  346. ! !
  347. Object subclass: #HLProgressHandler
  348. instanceVariableNames: ''
  349. package: 'Helios-Core'!
  350. !HLProgressHandler commentStamp!
  351. I am a specific progress handler for Helios, displaying progresses in a modal window.!
  352. !HLProgressHandler methodsFor: 'progress handling'!
  353. do: aBlock on: aCollection displaying: aString
  354. HLProgressWidget default
  355. do: aBlock
  356. on: aCollection
  357. displaying: aString
  358. ! !
  359. Widget subclass: #HLTabWidget
  360. instanceVariableNames: 'widget label root'
  361. package: 'Helios-Core'!
  362. !HLTabWidget commentStamp!
  363. I am a widget specialized into building another widget as an Helios tab.
  364. I should not be used directly, `HLWidget class >> #openAsTab` should be used instead.
  365. ## Example
  366. HLWorkspace openAsTab!
  367. !HLTabWidget methodsFor: 'accessing'!
  368. activate
  369. self manager activate: self
  370. !
  371. add
  372. self manager addTab: self
  373. !
  374. cssClass
  375. ^ self widget tabClass
  376. !
  377. displayLabel
  378. ^ self label size > 20
  379. ifTrue: [ (self label first: 20), '...' ]
  380. ifFalse: [ self label ]
  381. !
  382. focus
  383. self widget canHaveFocus ifTrue: [
  384. self widget focus ]
  385. !
  386. label
  387. ^ label ifNil: [ '' ]
  388. !
  389. label: aString
  390. label := aString
  391. !
  392. manager
  393. ^ HLManager current
  394. !
  395. widget
  396. ^ widget
  397. !
  398. widget: aWidget
  399. widget := aWidget
  400. ! !
  401. !HLTabWidget methodsFor: 'actions'!
  402. hide
  403. root ifNotNil: [ root asJQuery css: 'visibility' put: 'hidden' ]
  404. !
  405. registerBindings
  406. self widget registerBindings
  407. !
  408. remove
  409. self widget unregister.
  410. root ifNotNil: [ root asJQuery remove ]
  411. !
  412. show
  413. root
  414. ifNil: [ self appendToJQuery: 'body' asJQuery ]
  415. ifNotNil: [ root asJQuery css: 'visibility' put: 'visible' ]
  416. ! !
  417. !HLTabWidget methodsFor: 'rendering'!
  418. renderOn: html
  419. root := html div
  420. class: 'tab';
  421. yourself.
  422. self renderTab
  423. !
  424. renderTab
  425. root contents: [ :html |
  426. html div
  427. class: 'amber_box';
  428. with: [ self widget renderOn: html ] ]
  429. ! !
  430. !HLTabWidget methodsFor: 'testing'!
  431. isActive
  432. ^ self manager activeTab = self
  433. ! !
  434. !HLTabWidget class methodsFor: 'instance creation'!
  435. on: aWidget labelled: aString
  436. ^ self new
  437. widget: aWidget;
  438. label: aString;
  439. yourself
  440. ! !
  441. Widget subclass: #HLWidget
  442. instanceVariableNames: 'wrapper'
  443. package: 'Helios-Core'!
  444. !HLWidget commentStamp!
  445. I am the abstract superclass of all Helios widgets.
  446. I provide common methods, additional behavior to widgets useful for Helios, like dialog creation, command execution and tab creation.
  447. ## API
  448. 1. Rendering
  449. Instead of overriding `#renderOn:` as with other Widget subclasses, my subclasses should override `#renderContentOn:`.
  450. 2. Refreshing
  451. To re-render a widget, use `#refresh`.
  452. 3. Key bindings registration and tabs
  453. When displayed as a tab, the widget has a chance to register keybindings with the `#registerBindingsOn:` hook method.
  454. 4. Unregistration
  455. 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.
  456. 5. Tabs
  457. 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.
  458. 6. Command execution
  459. An helios command (instance of `HLCommand` or one of its subclass) can be executed with `#execute:`.!
  460. !HLWidget methodsFor: 'accessing'!
  461. manager
  462. ^ HLManager current
  463. !
  464. tabClass
  465. ^ self class tabClass
  466. !
  467. wrapper
  468. ^ wrapper
  469. ! !
  470. !HLWidget methodsFor: 'actions'!
  471. confirm: aString ifTrue: aBlock
  472. self manager confirm: aString ifTrue: aBlock
  473. !
  474. execute: aCommand
  475. HLManager current keyBinder
  476. activate;
  477. applyBinding: aCommand asBinding
  478. !
  479. openAsTab
  480. HLManager current addTab: (HLTabWidget on: self labelled: self class tabLabel)
  481. !
  482. request: aString do: aBlock
  483. self manager request: aString do: aBlock
  484. !
  485. request: aString value: valueString do: aBlock
  486. self manager
  487. request: aString
  488. value: valueString
  489. do: aBlock
  490. !
  491. unregister
  492. "This method is called whenever the receiver is closed (as a tab).
  493. Widgets subscribing to announcements should unregister there"
  494. ! !
  495. !HLWidget methodsFor: 'keybindings'!
  496. bindKeyDown: keyDownBlock keyUp: keyUpBlock
  497. self wrapper asJQuery
  498. keydown: keyDownBlock;
  499. keyup: keyUpBlock
  500. !
  501. registerBindings
  502. self registerBindingsOn: self manager keyBinder bindings
  503. !
  504. registerBindingsOn: aBindingGroup
  505. !
  506. unbindKeyDownKeyUp
  507. self wrapper asJQuery
  508. unbind: 'keydown';
  509. unbind: 'keyup'
  510. ! !
  511. !HLWidget methodsFor: 'rendering'!
  512. renderContentOn: html
  513. !
  514. renderOn: html
  515. wrapper := html div.
  516. [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
  517. ! !
  518. !HLWidget methodsFor: 'testing'!
  519. canHaveFocus
  520. ^ false
  521. ! !
  522. !HLWidget methodsFor: 'updating'!
  523. refresh
  524. self wrapper ifNil: [ ^ self ].
  525. self wrapper asJQuery empty.
  526. [ :html | self renderContentOn: html ] appendToJQuery: self wrapper asJQuery
  527. ! !
  528. !HLWidget class methodsFor: 'accessing'!
  529. openAsTab
  530. | instance |
  531. instance := self new.
  532. HLManager current addTab: (HLTabWidget
  533. on: instance
  534. labelled: self tabLabel).
  535. ^ instance
  536. !
  537. tabClass
  538. ^ ''
  539. !
  540. tabLabel
  541. ^ 'Tab'
  542. !
  543. tabPriority
  544. ^ 500
  545. ! !
  546. !HLWidget class methodsFor: 'testing'!
  547. canBeOpenAsTab
  548. ^ false
  549. ! !
  550. HLWidget subclass: #HLFocusableWidget
  551. instanceVariableNames: ''
  552. package: 'Helios-Core'!
  553. !HLFocusableWidget commentStamp!
  554. I am a widget that can be focused.
  555. ## API
  556. Instead of overriding `#renderOn:` as with other `Widget` subclasses, my subclasses should override `#renderContentOn:`.
  557. To bring the focus to the widget, use the `#focus` method.!
  558. !HLFocusableWidget methodsFor: 'accessing'!
  559. focusClass
  560. ^ 'focused'
  561. ! !
  562. !HLFocusableWidget methodsFor: 'events'!
  563. blur
  564. self wrapper asJQuery blur
  565. !
  566. focus
  567. self wrapper asJQuery focus
  568. ! !
  569. !HLFocusableWidget methodsFor: 'rendering'!
  570. renderContentOn: html
  571. !
  572. renderOn: html
  573. wrapper := html div
  574. class: 'hl_widget';
  575. yourself.
  576. wrapper with: [ self renderContentOn: html ].
  577. wrapper
  578. at: 'tabindex' put: '0';
  579. onBlur: [ self wrapper asJQuery removeClass: self focusClass ];
  580. onFocus: [ self wrapper asJQuery addClass: self focusClass ]
  581. ! !
  582. !HLFocusableWidget methodsFor: 'testing'!
  583. canHaveFocus
  584. ^ true
  585. !
  586. hasFocus
  587. ^ self wrapper notNil and: [ self wrapper asJQuery hasClass: self focusClass ]
  588. ! !
  589. HLFocusableWidget subclass: #HLListWidget
  590. instanceVariableNames: 'items selectedItem'
  591. package: 'Helios-Core'!
  592. !HLListWidget methodsFor: 'accessing'!
  593. cssClassForItem: anObject
  594. ^ ''
  595. !
  596. findListItemFor: anObject
  597. ^ (((wrapper asJQuery find: 'li')
  598. filter: [ :thisArg :otherArg | (thisArg asJQuery data: 'item') = anObject ] currySelf) eq: 0)
  599. !
  600. items
  601. ^ items ifNil: [ items := self defaultItems ]
  602. !
  603. items: aCollection
  604. items := aCollection
  605. !
  606. listCssClassForItem: anObject
  607. ^ self selectedItem = anObject
  608. ifTrue: [ 'active' ]
  609. ifFalse: [ 'inactive' ]
  610. !
  611. positionOf: aListItem
  612. <
  613. return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1
  614. >
  615. !
  616. selectedItem
  617. ^ selectedItem
  618. !
  619. selectedItem: anObject
  620. selectedItem := anObject
  621. ! !
  622. !HLListWidget methodsFor: 'actions'!
  623. activateFirstListItem
  624. self activateListItem: ((wrapper asJQuery find: 'li.inactive') eq: 0)
  625. !
  626. activateItem: anObject
  627. self activateListItem: (self findListItemFor: anObject)
  628. !
  629. activateListItem: aListItem
  630. | item |
  631. (aListItem get: 0) ifNil: [ ^ self ].
  632. aListItem parent children removeClass: 'active'.
  633. aListItem addClass: 'active'.
  634. self ensureVisible: aListItem.
  635. "Activate the corresponding item"
  636. item := aListItem data: 'item'.
  637. self selectedItem == item ifFalse: [
  638. self selectItem: item ]
  639. !
  640. activateNextListItem
  641. self activateListItem: (self wrapper asJQuery find: 'li.active') next.
  642. "select the first item if none is selected"
  643. (self wrapper asJQuery find: ' .active') get ifEmpty: [
  644. self activateFirstListItem ]
  645. !
  646. activatePreviousListItem
  647. self activateListItem: (self wrapper asJQuery find: 'li.active') prev
  648. !
  649. ensureVisible: aListItem
  650. "Move the scrollbar to show the active element"
  651. | parent position |
  652. (aListItem get: 0) ifNil: [ ^ self ].
  653. position := self positionOf: aListItem.
  654. parent := aListItem parent.
  655. aListItem position top < 0 ifTrue: [
  656. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
  657. aListItem position top + aListItem height > parent height ifTrue: [
  658. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]
  659. !
  660. focus
  661. super focus.
  662. self items isEmpty ifFalse: [
  663. self selectedItem ifNil: [ self activateFirstListItem ] ]
  664. !
  665. refresh
  666. super refresh.
  667. self selectedItem ifNotNil: [self ensureVisible: (self findListItemFor: self selectedItem)].
  668. !
  669. selectItem: anObject
  670. self selectedItem: anObject
  671. ! !
  672. !HLListWidget methodsFor: 'defaults'!
  673. defaultItems
  674. ^ #()
  675. ! !
  676. !HLListWidget methodsFor: 'events'!
  677. setupKeyBindings
  678. (HLRepeatedKeyDownHandler on: self)
  679. whileKeyDown: 38 do: [ self activatePreviousListItem ];
  680. whileKeyDown: 40 do: [ self activateNextListItem ];
  681. rebindKeys
  682. ! !
  683. !HLListWidget methodsFor: 'rendering'!
  684. renderButtonsOn: html
  685. !
  686. renderContentOn: html
  687. html ul
  688. class: 'nav nav-pills nav-stacked';
  689. with: [ self renderListOn: html ].
  690. html div class: 'pane_actions form-actions'; with: [
  691. self renderButtonsOn: html ].
  692. self setupKeyBindings
  693. !
  694. renderItem: anObject on: html
  695. | li |
  696. li := html li.
  697. li asJQuery data: 'item' put: anObject.
  698. li
  699. class: (self listCssClassForItem: anObject);
  700. with: [
  701. html a
  702. with: [
  703. (html tag: 'i') class: (self cssClassForItem: anObject).
  704. self renderItemLabel: anObject on: html ];
  705. onClick: [
  706. self activateListItem: li asJQuery ] ]
  707. !
  708. renderItemLabel: anObject on: html
  709. html with: anObject asString
  710. !
  711. renderListOn: html
  712. self items do: [ :each |
  713. self renderItem: each on: html ]
  714. ! !
  715. HLListWidget subclass: #HLNavigationListWidget
  716. instanceVariableNames: 'previous next'
  717. package: 'Helios-Core'!
  718. !HLNavigationListWidget methodsFor: 'accessing'!
  719. next
  720. ^ next
  721. !
  722. next: aWidget
  723. next := aWidget.
  724. aWidget previous = self ifFalse: [ aWidget previous: self ]
  725. !
  726. previous
  727. ^ previous
  728. !
  729. previous: aWidget
  730. previous := aWidget.
  731. aWidget next = self ifFalse: [ aWidget next: self ]
  732. ! !
  733. !HLNavigationListWidget methodsFor: 'actions'!
  734. nextFocus
  735. self next ifNotNil: [ self next focus ]
  736. !
  737. previousFocus
  738. self previous ifNotNil: [ self previous focus ]
  739. ! !
  740. !HLNavigationListWidget methodsFor: 'events'!
  741. setupKeyBindings
  742. super setupKeyBindings.
  743. self wrapper asJQuery keydown: [ :e |
  744. e which = 39 ifTrue: [
  745. self nextFocus ].
  746. e which = 37 ifTrue: [
  747. self previousFocus ] ]
  748. ! !
  749. HLNavigationListWidget subclass: #HLToolListWidget
  750. instanceVariableNames: 'model'
  751. package: 'Helios-Core'!
  752. !HLToolListWidget methodsFor: 'accessing'!
  753. commandCategory
  754. ^ self label
  755. !
  756. label
  757. ^ 'List'
  758. !
  759. menuCommands
  760. "Answer a collection of commands to be put in the cog menu"
  761. ^ ((HLToolCommand concreteClasses
  762. select: [ :each | each isValidFor: self model ])
  763. collect: [ :each | each for: self model ])
  764. select: [ :each |
  765. each category = self commandCategory and: [
  766. each isAction and: [ each isActive ] ] ]
  767. !
  768. model
  769. ^ model
  770. !
  771. model: aBrowserModel
  772. model := aBrowserModel.
  773. self
  774. observeSystem;
  775. observeModel
  776. !
  777. selectedItem: anItem
  778. "Selection changed, update the cog menu"
  779. super selectedItem: anItem.
  780. self updateMenu
  781. ! !
  782. !HLToolListWidget methodsFor: 'actions'!
  783. activateListItem: anItem
  784. self model withChangesDo: [ super activateListItem: anItem ]
  785. !
  786. activateNextListItem
  787. self model withChangesDo: [ super activateNextListItem ]
  788. !
  789. activatePreviousListItem
  790. self model withChangesDo: [ super activatePreviousListItem ]
  791. !
  792. observeModel
  793. !
  794. observeSystem
  795. !
  796. unregister
  797. super unregister.
  798. self model announcer unsubscribe: self.
  799. self model systemAnnouncer unsubscribe: self
  800. ! !
  801. !HLToolListWidget methodsFor: 'rendering'!
  802. renderContentOn: html
  803. self renderHeadOn: html.
  804. super renderContentOn: html
  805. !
  806. renderHeadOn: html
  807. html div
  808. class: 'list-label';
  809. with: [
  810. html with: self label.
  811. self renderMenuOn: html ]
  812. !
  813. renderMenuOn: html
  814. | commands |
  815. commands := self menuCommands.
  816. commands isEmpty ifTrue: [ ^ self ].
  817. html div
  818. class: 'btn-group cog';
  819. with: [
  820. html a
  821. class: 'btn dropdown-toggle';
  822. at: 'data-toggle' put: 'dropdown';
  823. with: [ (html tag: 'i') class: 'icon-chevron-down' ].
  824. html ul
  825. class: 'dropdown-menu pull-right';
  826. with: [
  827. self menuCommands do: [ :each |
  828. html li with: [ html a
  829. with: each menuLabel;
  830. onClick: [ self execute: each ] ] ] ] ]
  831. ! !
  832. !HLToolListWidget methodsFor: 'updating'!
  833. updateMenu
  834. (self wrapper asJQuery find: '.cog') remove.
  835. [ :html | self renderMenuOn: html ]
  836. appendToJQuery: (self wrapper asJQuery find: '.list-label')
  837. ! !
  838. !HLToolListWidget class methodsFor: 'instance creation'!
  839. on: aModel
  840. ^ self new
  841. model: aModel;
  842. yourself
  843. ! !
  844. HLListWidget subclass: #HLTabListWidget
  845. instanceVariableNames: 'callback'
  846. package: 'Helios-Core'!
  847. !HLTabListWidget commentStamp!
  848. I am a widget used to display a list of helios tabs.
  849. When a tab is selected, `callback` is evaluated with the selected tab as argument.!
  850. !HLTabListWidget methodsFor: 'accessing'!
  851. callback
  852. ^ callback ifNil: [ [] ]
  853. !
  854. callback: aBlock
  855. callback := aBlock
  856. ! !
  857. !HLTabListWidget methodsFor: 'actions'!
  858. selectItem: aTab
  859. super selectItem: aTab.
  860. self callback value: aTab
  861. ! !
  862. !HLTabListWidget methodsFor: 'rendering'!
  863. renderItemLabel: aTab on: html
  864. html span
  865. class: aTab cssClass;
  866. with: aTab label
  867. ! !
  868. HLWidget subclass: #HLManager
  869. instanceVariableNames: 'tabs activeTab environment history'
  870. package: 'Helios-Core'!
  871. !HLManager methodsFor: 'accessing'!
  872. activeTab
  873. ^ activeTab
  874. !
  875. environment
  876. "The default environment used by all Helios objects"
  877. ^ environment ifNil: [ environment := self defaultEnvironment ]
  878. !
  879. environment: anEnvironment
  880. environment := anEnvironment
  881. !
  882. history
  883. ^ history ifNil: [ history := OrderedCollection new ]
  884. !
  885. history: aCollection
  886. history := aCollection
  887. !
  888. keyBinder
  889. ^ HLKeyBinder current
  890. !
  891. tabs
  892. ^ tabs ifNil: [ tabs := OrderedCollection new ]
  893. ! !
  894. !HLManager methodsFor: 'actions'!
  895. activate: aTab
  896. self keyBinder flushBindings.
  897. aTab registerBindings.
  898. activeTab := aTab.
  899. self
  900. refresh;
  901. addToHistory: aTab;
  902. show: aTab
  903. !
  904. addTab: aTab
  905. self tabs add: aTab.
  906. self activate: aTab
  907. !
  908. addToHistory: aTab
  909. self removeFromHistory: aTab.
  910. self history add: aTab
  911. !
  912. confirm: aString ifFalse: aBlock
  913. HLConfirmationWidget new
  914. confirmationString: aString;
  915. cancelBlock: aBlock;
  916. show
  917. !
  918. confirm: aString ifTrue: aBlock
  919. HLConfirmationWidget new
  920. confirmationString: aString;
  921. actionBlock: aBlock;
  922. show
  923. !
  924. removeActiveTab
  925. self removeTab: self activeTab
  926. !
  927. removeFromHistory: aTab
  928. self history: (self history reject: [ :each | each == aTab ])
  929. !
  930. removeTab: aTab
  931. (self tabs includes: aTab) ifFalse: [ ^ self ].
  932. self removeFromHistory: aTab.
  933. self tabs remove: aTab.
  934. self keyBinder flushBindings.
  935. aTab remove.
  936. self refresh.
  937. self history ifNotEmpty: [
  938. self history last activate ]
  939. !
  940. request: aString do: aBlock
  941. self
  942. request: aString
  943. value: ''
  944. do: aBlock
  945. !
  946. request: aString value: valueString do: aBlock
  947. HLRequestWidget new
  948. confirmationString: aString;
  949. actionBlock: aBlock;
  950. value: valueString;
  951. show
  952. ! !
  953. !HLManager methodsFor: 'defaults'!
  954. defaultEnvironment
  955. "If helios is loaded from within a frame, answer the parent window environment"
  956. | parent parentSmalltalkGlobals |
  957. parent := window opener ifNil: [ window parent ].
  958. parent ifNil: [ ^ Environment new ].
  959. parentSmalltalkGlobals := (parent at: 'requirejs') value: 'amber_vm/globals'.
  960. parentSmalltalkGlobals ifNil: [ ^ Environment new ].
  961. ^ (parentSmalltalkGlobals at: 'Environment') new
  962. ! !
  963. !HLManager methodsFor: 'initialization'!
  964. setup
  965. self
  966. registerServices;
  967. setupEvents.
  968. self keyBinder
  969. setupEvents;
  970. setupHelper
  971. ! !
  972. !HLManager methodsFor: 'private'!
  973. registerServices
  974. self
  975. registerInspector;
  976. registerErrorHandler;
  977. registerProgressHandler;
  978. registerTranscript;
  979. registrFinder
  980. !
  981. setupEvents
  982. "on ctrl keydown, adds a 'navigation' css class to <body>
  983. for the CodeMirror navigation links. See `HLCodeWidget`."
  984. 'body' asJQuery keydown: [ :event |
  985. event ctrlKey ifTrue: [
  986. 'body' asJQuery addClass: 'navigation' ] ].
  987. 'body' asJQuery keyup: [ :event |
  988. 'body' asJQuery removeClass: 'navigation' ]
  989. ! !
  990. !HLManager methodsFor: 'rendering'!
  991. refresh
  992. '.navbar' asJQuery remove.
  993. self appendToJQuery: 'body' asJQuery
  994. !
  995. renderAddOn: html
  996. html li
  997. class: 'dropdown';
  998. with: [
  999. html a
  1000. class: 'dropdown-toggle';
  1001. at: 'data-toggle' put: 'dropdown';
  1002. with: [
  1003. html with: 'Open...'.
  1004. (html tag: 'b') class: 'caret' ].
  1005. html ul
  1006. class: 'dropdown-menu';
  1007. with: [
  1008. ((HLWidget withAllSubclasses
  1009. select: [ :each | each canBeOpenAsTab ])
  1010. sorted: [ :a :b | a tabPriority < b tabPriority ])
  1011. do: [ :each |
  1012. html li with: [
  1013. html a
  1014. with: each tabLabel;
  1015. onClick: [ each openAsTab ] ] ] ] ]
  1016. !
  1017. renderContentOn: html
  1018. html div
  1019. class: 'navbar navbar-fixed-top';
  1020. with: [ html div
  1021. class: 'navbar-inner';
  1022. with: [ self renderTabsOn: html ] ]
  1023. !
  1024. renderTabsOn: html
  1025. html ul
  1026. class: 'nav';
  1027. with: [
  1028. self tabs do: [ :each |
  1029. html li
  1030. class: (each isActive ifTrue: [ 'active' ] ifFalse: [ 'inactive' ]);
  1031. with: [
  1032. html a
  1033. with: [
  1034. ((html tag: 'i') class: 'close')
  1035. onClick: [ self removeTab: each ].
  1036. html span
  1037. class: each cssClass;
  1038. with: each displayLabel ];
  1039. onClick: [ each activate ] ] ].
  1040. self renderAddOn: html ]
  1041. !
  1042. show: aTab
  1043. self tabs do: [ :each | each hide ].
  1044. aTab show; focus
  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: 'accessing'!
  1088. cssClass
  1089. ^ ''
  1090. ! !
  1091. !HLModalWidget methodsFor: 'actions'!
  1092. cancel
  1093. self remove
  1094. !
  1095. confirm
  1096. "Override in subclasses"
  1097. self remove
  1098. !
  1099. remove
  1100. '.dialog' asJQuery removeClass: 'active'.
  1101. [
  1102. '#overlay' asJQuery remove.
  1103. '.dialog' asJQuery remove
  1104. ] valueWithTimeout: 300
  1105. !
  1106. show
  1107. self appendToJQuery: 'body' asJQuery
  1108. ! !
  1109. !HLModalWidget methodsFor: 'private'!
  1110. giveFocusToButton: aButton
  1111. aButton asJQuery focus
  1112. ! !
  1113. !HLModalWidget methodsFor: 'rendering'!
  1114. hasButtons
  1115. ^ true
  1116. !
  1117. renderButtonsOn: html
  1118. | confirmButton |
  1119. html div
  1120. class: 'buttons';
  1121. with: [
  1122. html button
  1123. class: 'button';
  1124. with: 'Cancel';
  1125. onClick: [ self cancel ].
  1126. confirmButton := html button
  1127. class: 'button default';
  1128. with: 'Confirm';
  1129. onClick: [ self confirm ] ].
  1130. self giveFocusToButton:confirmButton
  1131. !
  1132. renderContentOn: html
  1133. | confirmButton |
  1134. html div id: 'overlay'.
  1135. html div
  1136. class: 'dialog ', self cssClass;
  1137. with: [
  1138. self renderMainOn: html.
  1139. self hasButtons ifTrue: [
  1140. self renderButtonsOn: html ] ].
  1141. '.dialog' asJQuery addClass: 'active'.
  1142. self setupKeyBindings
  1143. !
  1144. renderMainOn: html
  1145. !
  1146. setupKeyBindings
  1147. '.dialog' asJQuery keyup: [ :e |
  1148. e keyCode = String esc asciiValue ifTrue: [ self cancel ] ]
  1149. ! !
  1150. HLModalWidget subclass: #HLConfirmationWidget
  1151. instanceVariableNames: 'confirmationString actionBlock cancelBlock'
  1152. package: 'Helios-Core'!
  1153. !HLConfirmationWidget commentStamp!
  1154. I display confirmation messages.
  1155. Instead of creating an instance directly, use `HLWidget >> #confirm:ifTrue:`.!
  1156. !HLConfirmationWidget methodsFor: 'accessing'!
  1157. actionBlock
  1158. ^ actionBlock ifNil: [ [] ]
  1159. !
  1160. actionBlock: aBlock
  1161. actionBlock := aBlock
  1162. !
  1163. cancelBlock
  1164. ^ cancelBlock ifNil: [ [] ]
  1165. !
  1166. cancelBlock: aBlock
  1167. cancelBlock := aBlock
  1168. !
  1169. confirmationString
  1170. ^ confirmationString ifNil: [ 'Confirm' ]
  1171. !
  1172. confirmationString: aString
  1173. confirmationString := aString
  1174. ! !
  1175. !HLConfirmationWidget methodsFor: 'actions'!
  1176. cancel
  1177. self cancelBlock value.
  1178. super cancel
  1179. !
  1180. confirm
  1181. super confirm.
  1182. self actionBlock value
  1183. ! !
  1184. !HLConfirmationWidget methodsFor: 'rendering'!
  1185. renderMainOn: html
  1186. html span with: self confirmationString
  1187. ! !
  1188. HLConfirmationWidget subclass: #HLRequestWidget
  1189. instanceVariableNames: 'input value'
  1190. package: 'Helios-Core'!
  1191. !HLRequestWidget commentStamp!
  1192. I display a modal window requesting user input.
  1193. Instead of creating instances manually, use `HLWidget >> #request:do:` and `#request:value:do:`.!
  1194. !HLRequestWidget methodsFor: 'accessing'!
  1195. cssClass
  1196. ^ 'large'
  1197. !
  1198. value
  1199. ^ value ifNil: [ '' ]
  1200. !
  1201. value: aString
  1202. value := aString
  1203. ! !
  1204. !HLRequestWidget methodsFor: 'actions'!
  1205. confirm
  1206. super confirm.
  1207. self actionBlock value: input asJQuery val
  1208. ! !
  1209. !HLRequestWidget methodsFor: 'private'!
  1210. giveFocusToButton: aButton
  1211. ! !
  1212. !HLRequestWidget methodsFor: 'rendering'!
  1213. renderMainOn: html
  1214. super renderMainOn: html.
  1215. input := html textarea.
  1216. input asJQuery
  1217. val: self value;
  1218. focus
  1219. ! !
  1220. HLModalWidget subclass: #HLProgressWidget
  1221. instanceVariableNames: 'progressBars visible'
  1222. package: 'Helios-Core'!
  1223. !HLProgressWidget commentStamp!
  1224. I am a widget used to display progress modal dialogs.
  1225. My default instance is accessed with `HLProgressWidget class >> #default`.
  1226. See `HLProgressHandler` for usage.!
  1227. !HLProgressWidget methodsFor: 'accessing'!
  1228. progressBars
  1229. ^ progressBars ifNil: [ progressBars := OrderedCollection new ]
  1230. ! !
  1231. !HLProgressWidget methodsFor: 'actions'!
  1232. addProgressBar: aProgressBar
  1233. self show.
  1234. self progressBars add: aProgressBar.
  1235. aProgressBar appendToJQuery: (self wrapper asJQuery find: '.dialog')
  1236. !
  1237. do: aBlock on: aCollection displaying: aString
  1238. | progressBar |
  1239. progressBar := HLProgressBarWidget new
  1240. parent: self;
  1241. label: aString;
  1242. workBlock: aBlock;
  1243. collection: aCollection;
  1244. yourself.
  1245. self addProgressBar: progressBar.
  1246. progressBar start
  1247. !
  1248. flush
  1249. self progressBars do: [ :each |
  1250. self removeProgressBar: each ]
  1251. !
  1252. remove
  1253. self isVisible ifTrue: [
  1254. visible := false.
  1255. super remove ]
  1256. !
  1257. removeProgressBar: aProgressBar
  1258. self progressBars remove: aProgressBar ifAbsent: [].
  1259. aProgressBar wrapper asJQuery remove.
  1260. self progressBars ifEmpty: [ self remove ]
  1261. !
  1262. show
  1263. self isVisible ifFalse: [
  1264. visible := true.
  1265. super show ]
  1266. ! !
  1267. !HLProgressWidget methodsFor: 'rendering'!
  1268. renderMainOn: html
  1269. self progressBars do: [ :each |
  1270. html with: each ]
  1271. ! !
  1272. !HLProgressWidget methodsFor: 'testing'!
  1273. hasButtons
  1274. ^ false
  1275. !
  1276. isVisible
  1277. ^ visible ifNil: [ false ]
  1278. ! !
  1279. HLProgressWidget class instanceVariableNames: 'default'!
  1280. !HLProgressWidget class methodsFor: 'accessing'!
  1281. default
  1282. ^ default ifNil: [ default := self new ]
  1283. ! !
  1284. HLModalWidget subclass: #HLTabSelectionWidget
  1285. instanceVariableNames: 'tabs tabList selectedTab selectCallback cancelCallback confirmCallback'
  1286. package: 'Helios-Core'!
  1287. !HLTabSelectionWidget commentStamp!
  1288. I am a modal window used to select or create tabs.!
  1289. !HLTabSelectionWidget methodsFor: 'accessing'!
  1290. cancelCallback
  1291. ^ cancelCallback ifNil: [ [] ]
  1292. !
  1293. cancelCallback: aBlock
  1294. cancelCallback := aBlock
  1295. !
  1296. confirmCallback
  1297. ^ confirmCallback ifNil: [ [] ]
  1298. !
  1299. confirmCallback: aBlock
  1300. confirmCallback := aBlock
  1301. !
  1302. selectCallback
  1303. ^ selectCallback ifNil: [ [] ]
  1304. !
  1305. selectCallback: aBlock
  1306. selectCallback := aBlock
  1307. !
  1308. selectedTab
  1309. ^ selectedTab
  1310. !
  1311. selectedTab: aTab
  1312. selectedTab := aTab
  1313. !
  1314. tabs
  1315. ^ tabs ifNil: [ #() ]
  1316. !
  1317. tabs: aCollection
  1318. tabs := aCollection
  1319. ! !
  1320. !HLTabSelectionWidget methodsFor: 'actions'!
  1321. cancel
  1322. super cancel.
  1323. self cancelCallback value
  1324. !
  1325. confirm
  1326. super confirm.
  1327. self confirmCallback value: self selectedTab
  1328. !
  1329. selectTab: aTab
  1330. self selectedTab: aTab.
  1331. self selectCallback value: aTab
  1332. !
  1333. setupKeyBindings
  1334. super setupKeyBindings.
  1335. '.dialog' asJQuery keyup: [ :e |
  1336. e keyCode = String cr asciiValue ifTrue: [ self confirm ] ]
  1337. ! !
  1338. !HLTabSelectionWidget methodsFor: 'rendering'!
  1339. renderContentOn: html
  1340. super renderContentOn: html.
  1341. self tabList focus
  1342. !
  1343. renderMainOn: html
  1344. html div
  1345. class: 'title';
  1346. with: 'Tab selection'.
  1347. html with: self tabList
  1348. !
  1349. renderTab: aTab on: html
  1350. html
  1351. span
  1352. class: aTab cssClass;
  1353. with: aTab label
  1354. !
  1355. renderTabsOn: html
  1356. self tabs do: [ :each |
  1357. html li with: [
  1358. html a
  1359. with: [
  1360. self renderTab: each on: html ];
  1361. onClick: [ self selectTab: each ] ] ]
  1362. !
  1363. tabList
  1364. tabList ifNil: [
  1365. tabList := HLTabListWidget new.
  1366. tabList
  1367. callback: [ :tab | self selectTab: tab. tabList focus ];
  1368. selectedItem: self selectedTab;
  1369. items: self tabs ].
  1370. ^ tabList
  1371. ! !
  1372. HLWidget subclass: #HLProgressBarWidget
  1373. instanceVariableNames: 'label parent workBlock collection bar'
  1374. package: 'Helios-Core'!
  1375. !HLProgressBarWidget commentStamp!
  1376. I am a widget used to display a progress bar while iterating over a collection.!
  1377. !HLProgressBarWidget methodsFor: 'accessing'!
  1378. collection
  1379. ^ collection
  1380. !
  1381. collection: aCollection
  1382. collection := aCollection
  1383. !
  1384. label
  1385. ^ label
  1386. !
  1387. label: aString
  1388. label := aString
  1389. !
  1390. parent
  1391. ^ parent
  1392. !
  1393. parent: aProgress
  1394. parent := aProgress
  1395. !
  1396. workBlock
  1397. ^ workBlock
  1398. !
  1399. workBlock: aBlock
  1400. workBlock := aBlock
  1401. ! !
  1402. !HLProgressBarWidget methodsFor: 'actions'!
  1403. evaluateAt: anInteger
  1404. self updateProgress: (anInteger / self collection size) * 100.
  1405. anInteger <= self collection size
  1406. ifTrue: [
  1407. [
  1408. self workBlock value: (self collection at: anInteger).
  1409. self evaluateAt: anInteger + 1 ] valueWithTimeout: 10 ]
  1410. ifFalse: [ [ self remove ] valueWithTimeout: 500 ]
  1411. !
  1412. remove
  1413. self parent removeProgressBar: self
  1414. !
  1415. start
  1416. "Make sure the UI has some time to update itself between each iteration"
  1417. self evaluateAt: 1
  1418. !
  1419. updateProgress: anInteger
  1420. bar asJQuery css: 'width' put: anInteger asString, '%'
  1421. ! !
  1422. !HLProgressBarWidget methodsFor: 'rendering'!
  1423. renderContentOn: html
  1424. html span with: self label.
  1425. html div
  1426. class: 'progress';
  1427. with: [
  1428. bar := html div
  1429. class: 'bar';
  1430. style: 'width: 0%' ]
  1431. ! !
  1432. HLProgressBarWidget class instanceVariableNames: 'default'!
  1433. !HLProgressBarWidget class methodsFor: 'accessing'!
  1434. default
  1435. ^ default ifNil: [ default := self new ]
  1436. ! !