Helios-Core.st 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447
  1. Smalltalk current createPackage: 'Helios-Core'!
  2. Object 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: #HLToolModel
  48. instanceVariableNames: 'selectedClass selectedPackage selectedProtocol selectedSelector'
  49. package: 'Helios-Core'!
  50. !HLToolModel commentStamp!
  51. I am a model specific to package and class manipulation. All browsers should either use me or a subclass as their model.
  52. I provide methods for package, class, protocol and method manipulation and access, forwarding to my environment.
  53. I also handle compilation of classes and methods as well as compilation and parsing errors.!
  54. !HLToolModel methodsFor: 'accessing'!
  55. allSelectors
  56. ^ self environment allSelectors
  57. !
  58. availableClassNames
  59. ^ self environment availableClassNames
  60. !
  61. availablePackageNames
  62. ^ self environment availablePackageNames
  63. !
  64. availablePackages
  65. ^ self environment availablePackageNames
  66. !
  67. availableProtocols
  68. ^ self environment availableProtocolsFor: self selectedClass
  69. !
  70. packages
  71. ^ self environment packages
  72. !
  73. selectedClass
  74. ^ selectedClass
  75. !
  76. selectedClass: aClass
  77. (self selectedClass = aClass and: [ aClass isNil ])
  78. ifTrue: [ ^ self ].
  79. self withChangesDo: [
  80. selectedClass = aClass ifTrue: [
  81. self selectedProtocol: nil ].
  82. aClass
  83. ifNil: [ selectedClass := nil ]
  84. ifNotNil: [
  85. self selectedPackage: aClass theNonMetaClass package.
  86. self showInstance
  87. ifTrue: [ selectedClass := aClass theNonMetaClass ]
  88. ifFalse: [ selectedClass := aClass theMetaClass ] ].
  89. self selectedProtocol: nil.
  90. self announcer announce: (HLClassSelected on: self selectedClass) ]
  91. !
  92. selectedMethod
  93. ^ self selectedClass ifNotNil: [
  94. self selectedClass methodDictionary
  95. at: selectedSelector
  96. ifAbsent: [ nil ] ]
  97. !
  98. selectedMethod: aCompiledMethod
  99. selectedSelector = aCompiledMethod ifTrue: [ ^ self ].
  100. self withChangesDo: [
  101. aCompiledMethod
  102. ifNil: [ selectedSelector := nil ]
  103. ifNotNil: [
  104. selectedClass := aCompiledMethod methodClass.
  105. selectedSelector := aCompiledMethod selector ].
  106. self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
  107. !
  108. selectedPackage
  109. ^ selectedPackage
  110. !
  111. selectedPackage: aPackage
  112. selectedPackage = aPackage ifTrue: [ ^ self ].
  113. self withChangesDo: [
  114. selectedPackage := aPackage.
  115. self selectedClass: nil.
  116. self announcer announce: (HLPackageSelected on: aPackage) ]
  117. !
  118. selectedProtocol
  119. ^ selectedProtocol
  120. !
  121. selectedProtocol: aString
  122. selectedProtocol = aString ifTrue: [ ^ self ].
  123. self withChangesDo: [
  124. selectedProtocol := aString.
  125. self selectedMethod: nil.
  126. self announcer announce: (HLProtocolSelected on: aString) ]
  127. ! !
  128. !HLToolModel methodsFor: 'actions'!
  129. addInstVarNamed: aString
  130. self environment addInstVarNamed: aString to: self selectedClass.
  131. self announcer announce: (HLInstVarAdded new
  132. theClass: self selectedClass;
  133. variableName: aString;
  134. yourself)
  135. !
  136. save: aString
  137. self announcer announce: HLSourceCodeSaved new.
  138. (self shouldCompileClassDefinition: aString)
  139. ifTrue: [ self compileClassDefinition: aString ]
  140. ifFalse: [ self compileMethod: aString ]
  141. !
  142. saveSourceCode
  143. self announcer announce: HLSaveSourceCode new
  144. ! !
  145. !HLToolModel methodsFor: 'commands actions'!
  146. commitPackage
  147. self
  148. withHelperLabelled: 'Committing package ', self selectedPackage name, '...'
  149. do: [ self environment commitPackage: self selectedPackage ]
  150. !
  151. copyClassTo: aClassName
  152. self withChangesDo: [
  153. self environment
  154. copyClass: self selectedClass theNonMetaClass
  155. to: aClassName ]
  156. !
  157. moveClassToPackage: aPackageName
  158. self withChangesDo: [
  159. self environment
  160. moveClass: self selectedClass theNonMetaClass
  161. toPackage: aPackageName ]
  162. !
  163. moveMethodToClass: aClassName
  164. self withChangesDo: [
  165. self environment
  166. moveMethod: self selectedMethod
  167. toClass: aClassName ]
  168. !
  169. moveMethodToProtocol: aProtocol
  170. self withChangesDo: [
  171. self environment
  172. moveMethod: self selectedMethod
  173. toProtocol: aProtocol ]
  174. !
  175. openClassNamed: aString
  176. | class |
  177. self withChangesDo: [
  178. class := self environment classNamed: aString.
  179. self selectedPackage: class package.
  180. self selectedClass: class ]
  181. !
  182. removeClass
  183. self withChangesDo: [
  184. self manager
  185. confirm: 'Do you REALLY want to remove class ', self selectedClass name
  186. ifTrue: [ self environment removeClass: self selectedClass ] ]
  187. !
  188. removeMethod
  189. self withChangesDo: [
  190. self manager
  191. confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector
  192. ifTrue: [ self environment removeMethod: self selectedMethod ] ]
  193. !
  194. removeProtocol
  195. self withChangesDo: [
  196. self manager
  197. confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol
  198. ifTrue: [ self environment
  199. removeProtocol: self selectedProtocol
  200. from: self selectedClass ] ]
  201. !
  202. renameClassTo: aClassName
  203. self withChangesDo: [
  204. self environment
  205. renameClass: self selectedClass theNonMetaClass
  206. to: aClassName ]
  207. !
  208. renameProtocolTo: aString
  209. self withChangesDo: [
  210. self environment
  211. renameProtocol: self selectedProtocol
  212. to: aString
  213. in: self selectedClass ]
  214. ! !
  215. !HLToolModel methodsFor: 'compiling'!
  216. compileClassComment: aString
  217. self environment
  218. compileClassComment: aString
  219. for: self selectedClass
  220. !
  221. compileClassDefinition: aString
  222. self environment compileClassDefinition: aString
  223. !
  224. compileMethod: aString
  225. | method |
  226. self withCompileErrorHandling: [
  227. method := self environment
  228. compileMethod: aString
  229. for: self selectedClass
  230. protocol: self compilationProtocol.
  231. self selectedMethod: method ]
  232. ! !
  233. !HLToolModel methodsFor: 'defaults'!
  234. allProtocol
  235. ^ '-- all --'
  236. !
  237. unclassifiedProtocol
  238. ^ 'as yet unclassified'
  239. ! !
  240. !HLToolModel methodsFor: 'error handling'!
  241. handleCompileError: anError
  242. self announcer announce: (HLCompileErrorRaised new
  243. error: anError;
  244. yourself)
  245. !
  246. handleParseError: anError
  247. | split line column messageToInsert |
  248. split := anError messageText tokenize: ' : '.
  249. messageToInsert := split second.
  250. "21 = 'Parse error on line ' size + 1"
  251. split := split first copyFrom: 21 to: split first size.
  252. split := split tokenize: ' column '.
  253. line := split first.
  254. column := split second.
  255. self announcer announce: (HLParseErrorRaised new
  256. line: line asNumber;
  257. column: column asNumber;
  258. message: messageToInsert;
  259. error: anError;
  260. yourself)
  261. !
  262. handleUnkownVariableError: anError
  263. self announcer announce: (HLUnknownVariableErrorRaised new
  264. error: anError;
  265. yourself)
  266. !
  267. withCompileErrorHandling: aBlock
  268. self environment
  269. evaluate: [
  270. self environment
  271. evaluate: [
  272. self environment
  273. evaluate: aBlock
  274. on: ParseError
  275. do: [:ex | self handleParseError: ex ] ]
  276. on: UnknownVariableError
  277. do: [ :ex | self handleUnkownVariableError: ex ] ]
  278. on: CompilerError
  279. do: [ :ex | self handleCompileError: ex ]
  280. ! !
  281. !HLToolModel methodsFor: 'private'!
  282. compilationProtocol
  283. | currentProtocol |
  284. currentProtocol := self selectedProtocol.
  285. currentProtocol ifNil: [ currentProtocol := self unclassifiedProtocol ].
  286. self selectedMethod ifNotNil: [ currentProtocol := self selectedMethod protocol ].
  287. ^ currentProtocol = self allProtocol
  288. ifTrue: [ self unclassifiedProtocol ]
  289. ifFalse: [ currentProtocol ]
  290. !
  291. withHelperLabelled: aString do: aBlock
  292. "TODO: doesn't belong here"
  293. (window jQuery: '#helper') remove.
  294. [ :html |
  295. html div
  296. id: 'helper';
  297. with: aString ] appendToJQuery: 'body' asJQuery.
  298. [
  299. aBlock value.
  300. (window jQuery: '#helper') remove
  301. ]
  302. valueWithTimeout: 10
  303. ! !
  304. !HLToolModel methodsFor: 'testing'!
  305. isToolModel
  306. ^ true
  307. !
  308. shouldCompileClassDefinition: aString
  309. ^ self selectedClass isNil or: [
  310. aString first asUppercase = aString first ]
  311. ! !
  312. !HLToolModel class methodsFor: 'actions'!
  313. on: anEnvironment
  314. ^ self new
  315. environment: anEnvironment;
  316. yourself
  317. ! !
  318. Widget subclass: #HLTab
  319. instanceVariableNames: 'widget label root'
  320. package: 'Helios-Core'!
  321. !HLTab commentStamp!
  322. I am a widget specialized into building another widget as an Helios tab.
  323. I should not be used directly, `HLWidget class >> #openAsTab` should be used instead.
  324. ## Example
  325. HLWorkspace openAsTab!
  326. !HLTab methodsFor: 'accessing'!
  327. activate
  328. self manager activate: self
  329. !
  330. add
  331. self manager addTab: self
  332. !
  333. cssClass
  334. ^ self widget tabClass
  335. !
  336. displayLabel
  337. ^ self label size > 20
  338. ifTrue: [ (self label first: 20), '...' ]
  339. ifFalse: [ self label ]
  340. !
  341. focus
  342. self widget canHaveFocus ifTrue: [
  343. self widget focus ]
  344. !
  345. label
  346. ^ label ifNil: [ '' ]
  347. !
  348. label: aString
  349. label := aString
  350. !
  351. manager
  352. ^ HLManager current
  353. !
  354. widget
  355. ^ widget
  356. !
  357. widget: aWidget
  358. widget := aWidget
  359. ! !
  360. !HLTab methodsFor: 'actions'!
  361. hide
  362. root ifNotNil: [ root asJQuery css: 'visibility' put: 'hidden' ]
  363. !
  364. registerBindings
  365. self widget registerBindings
  366. !
  367. remove
  368. self widget unregister.
  369. root ifNotNil: [ root asJQuery remove ]
  370. !
  371. show
  372. root
  373. ifNil: [ self appendToJQuery: 'body' asJQuery ]
  374. ifNotNil: [ root asJQuery css: 'visibility' put: 'visible' ]
  375. ! !
  376. !HLTab methodsFor: 'rendering'!
  377. renderOn: html
  378. root := html div
  379. class: 'tab';
  380. yourself.
  381. self renderTab
  382. !
  383. renderTab
  384. root contents: [ :html |
  385. html div
  386. class: 'amber_box';
  387. with: [ self widget renderOn: html ] ]
  388. ! !
  389. !HLTab methodsFor: 'testing'!
  390. isActive
  391. ^ self manager activeTab = self
  392. ! !
  393. !HLTab class methodsFor: 'instance creation'!
  394. on: aWidget labelled: aString
  395. ^ self new
  396. widget: aWidget;
  397. label: aString;
  398. yourself
  399. ! !
  400. Widget subclass: #HLWidget
  401. instanceVariableNames: 'wrapper'
  402. package: 'Helios-Core'!
  403. !HLWidget commentStamp!
  404. I am the abstract superclass of all Helios widgets.
  405. I provide common methods, additional behavior to widgets useful for Helios, like dialog creation, command execution and tab creation.!
  406. !HLWidget methodsFor: 'accessing'!
  407. manager
  408. ^ HLManager current
  409. !
  410. tabClass
  411. ^ self class tabClass
  412. !
  413. wrapper
  414. ^ wrapper
  415. ! !
  416. !HLWidget methodsFor: 'actions'!
  417. alert: aString
  418. window alert: aString
  419. !
  420. confirm: aString ifTrue: aBlock
  421. self manager confirm: aString ifTrue: aBlock
  422. !
  423. execute: aCommand
  424. HLManager current keyBinder
  425. activate;
  426. applyBinding: aCommand asBinding
  427. !
  428. request: aString do: aBlock
  429. self manager request: aString do: aBlock
  430. !
  431. request: aString value: valueString do: aBlock
  432. self manager
  433. request: aString
  434. value: valueString
  435. do: aBlock
  436. !
  437. unregister
  438. "This method is called whenever the receiver is closed (as a tab).
  439. Widgets subscribing to announcements should unregister there"
  440. ! !
  441. !HLWidget methodsFor: 'keybindings'!
  442. registerBindings
  443. self registerBindingsOn: self manager keyBinder bindings
  444. !
  445. registerBindingsOn: aBindingGroup
  446. ! !
  447. !HLWidget methodsFor: 'rendering'!
  448. renderContentOn: html
  449. !
  450. renderOn: html
  451. wrapper := html div.
  452. [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
  453. ! !
  454. !HLWidget methodsFor: 'testing'!
  455. canHaveFocus
  456. ^ false
  457. ! !
  458. !HLWidget methodsFor: 'updating'!
  459. refresh
  460. self wrapper ifNil: [ ^ self ].
  461. self wrapper asJQuery empty.
  462. [ :html | self renderContentOn: html ] appendToJQuery: self wrapper asJQuery
  463. ! !
  464. !HLWidget class methodsFor: 'accessing'!
  465. openAsTab
  466. self canBeOpenAsTab ifFalse: [ ^ self ].
  467. HLManager current addTab: (HLTab on: self new labelled: self tabLabel)
  468. !
  469. tabClass
  470. ^ ''
  471. !
  472. tabLabel
  473. ^ 'Tab'
  474. !
  475. tabPriority
  476. ^ 500
  477. ! !
  478. !HLWidget class methodsFor: 'testing'!
  479. canBeOpenAsTab
  480. ^ false
  481. ! !
  482. HLWidget subclass: #HLConfirmation
  483. instanceVariableNames: 'confirmationString actionBlock cancelBlock'
  484. package: 'Helios-Core'!
  485. !HLConfirmation methodsFor: 'accessing'!
  486. actionBlock
  487. ^ actionBlock ifNil: [ [] ]
  488. !
  489. actionBlock: aBlock
  490. actionBlock := aBlock
  491. !
  492. cancelBlock
  493. ^ cancelBlock ifNil: [ [] ]
  494. !
  495. cancelBlock: aBlock
  496. cancelBlock := aBlock
  497. !
  498. confirmationString
  499. ^ confirmationString ifNil: [ 'Confirm' ]
  500. !
  501. confirmationString: aString
  502. confirmationString := aString
  503. !
  504. cssClass
  505. ^ ''
  506. ! !
  507. !HLConfirmation methodsFor: 'actions'!
  508. cancel
  509. self cancelBlock value.
  510. self remove
  511. !
  512. confirm
  513. self actionBlock value.
  514. self remove
  515. !
  516. remove
  517. (window jQuery: '.dialog') removeClass: 'active'.
  518. [
  519. (window jQuery: '#overlay') remove.
  520. (window jQuery: '.dialog') remove
  521. ] valueWithTimeout: 300
  522. ! !
  523. !HLConfirmation methodsFor: 'rendering'!
  524. renderButtonsOn: html
  525. | confirmButton |
  526. html div
  527. class: 'buttons';
  528. with: [
  529. html button
  530. class: 'button';
  531. with: 'Cancel';
  532. onClick: [ self cancel ].
  533. confirmButton := html button
  534. class: 'button default';
  535. with: 'Confirm';
  536. onClick: [ self confirm ] ].
  537. confirmButton asJQuery focus
  538. !
  539. renderContentOn: html
  540. | confirmButton |
  541. html div id: 'overlay'.
  542. html div
  543. class: 'dialog ', self cssClass;
  544. with: [
  545. self
  546. renderMainOn: html;
  547. renderButtonsOn: html ].
  548. (window jQuery: '.dialog') addClass: 'active'.
  549. self setupKeyBindings
  550. !
  551. renderMainOn: html
  552. html span with: self confirmationString
  553. !
  554. setupKeyBindings
  555. (window jQuery: '.dialog') keyup: [ :e |
  556. e keyCode = 27 ifTrue: [ self cancel ] ]
  557. ! !
  558. HLConfirmation subclass: #HLRequest
  559. instanceVariableNames: 'input value'
  560. package: 'Helios-Core'!
  561. !HLRequest methodsFor: 'accessing'!
  562. cssClass
  563. ^ 'large'
  564. !
  565. value
  566. ^ value ifNil: [ '' ]
  567. !
  568. value: aString
  569. value := aString
  570. ! !
  571. !HLRequest methodsFor: 'actions'!
  572. confirm
  573. self actionBlock value: input asJQuery val.
  574. self remove
  575. ! !
  576. !HLRequest methodsFor: 'rendering'!
  577. renderMainOn: html
  578. super renderMainOn: html.
  579. input := html textarea.
  580. input asJQuery val: self value
  581. ! !
  582. HLWidget subclass: #HLFocusableWidget
  583. instanceVariableNames: ''
  584. package: 'Helios-Core'!
  585. !HLFocusableWidget methodsFor: 'accessing'!
  586. focusClass
  587. ^ 'focused'
  588. ! !
  589. !HLFocusableWidget methodsFor: 'events'!
  590. blur
  591. self wrapper asJQuery blur
  592. !
  593. focus
  594. self wrapper asJQuery focus
  595. !
  596. hasFocus
  597. ^ self wrapper notNil and: [ self wrapper asJQuery is: ':focus' ]
  598. ! !
  599. !HLFocusableWidget methodsFor: 'rendering'!
  600. renderContentOn: html
  601. !
  602. renderOn: html
  603. self registerBindings.
  604. wrapper := html div
  605. class: 'hl_widget';
  606. yourself.
  607. wrapper with: [ self renderContentOn: html ].
  608. wrapper
  609. at: 'tabindex' put: '0';
  610. onBlur: [ self wrapper asJQuery removeClass: self focusClass ];
  611. onFocus: [ self wrapper asJQuery addClass: self focusClass ]
  612. ! !
  613. !HLFocusableWidget methodsFor: 'testing'!
  614. canHaveFocus
  615. ^ true
  616. ! !
  617. HLFocusableWidget subclass: #HLListWidget
  618. instanceVariableNames: 'items selectedItem mapping'
  619. package: 'Helios-Core'!
  620. !HLListWidget methodsFor: 'accessing'!
  621. cssClassForItem: anObject
  622. ^ ''
  623. !
  624. items
  625. ^ items ifNil: [ items := self defaultItems ]
  626. !
  627. items: aCollection
  628. items := aCollection
  629. !
  630. listCssClassForItem: anObject
  631. ^ self selectedItem = anObject
  632. ifTrue: [ 'active' ]
  633. ifFalse: [ 'inactive' ]
  634. !
  635. positionOf: aListItem
  636. <
  637. return aListItem.parent().children().get().indexOf(aListItem.get(0)) + 1
  638. >
  639. !
  640. selectedItem
  641. ^ selectedItem
  642. !
  643. selectedItem: anObject
  644. selectedItem := anObject
  645. ! !
  646. !HLListWidget methodsFor: 'actions'!
  647. activateFirstListItem
  648. self activateListItem: (window jQuery: ((wrapper asJQuery find: 'li.inactive') get: 0))
  649. !
  650. activateItem: anObject
  651. self activateListItem: (mapping
  652. at: anObject
  653. ifAbsent: [ ^ self ]) asJQuery
  654. !
  655. activateListItem: aListItem
  656. | item |
  657. (aListItem get: 0) ifNil: [ ^self ].
  658. aListItem parent children removeClass: 'active'.
  659. aListItem addClass: 'active'.
  660. self ensureVisible: aListItem.
  661. "Activate the corresponding item"
  662. item := (self items at: (aListItem attr: 'list-data') asNumber).
  663. self selectedItem == item ifFalse: [
  664. self selectItem: item ]
  665. !
  666. activateNextListItem
  667. self activateListItem: (self wrapper asJQuery find: ' .active') next.
  668. "select the first item if none is selected"
  669. (self wrapper asJQuery find: ' .active') get ifEmpty: [
  670. self activateFirstListItem ]
  671. !
  672. activatePreviousListItem
  673. self activateListItem: (self wrapper asJQuery find: ' .active') prev
  674. !
  675. ensureVisible: aListItem
  676. "Move the scrollbar to show the active element"
  677. | perent position |
  678. position := self positionOf: aListItem.
  679. parent := aListItem parent.
  680. aListItem position top < 0 ifTrue: [
  681. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem position top - 10) ].
  682. aListItem position top + aListItem height > parent height ifTrue: [
  683. (parent get: 0) scrollTop: ((parent get: 0) scrollTop + aListItem height - (parent height - aListItem position top)) +10 ]
  684. !
  685. focus
  686. super focus.
  687. self items isEmpty ifFalse: [
  688. self selectedItem ifNil: [ self activateFirstListItem ] ]
  689. !
  690. refresh
  691. super refresh.
  692. self ensureVisible: (mapping
  693. at: self selectedItem
  694. ifAbsent: [ ^ self ]) asJQuery
  695. !
  696. selectItem: anObject
  697. self selectedItem: anObject
  698. ! !
  699. !HLListWidget methodsFor: 'defaults'!
  700. defaultItems
  701. ^ #()
  702. ! !
  703. !HLListWidget methodsFor: 'events'!
  704. setupKeyBindings
  705. "TODO: refactor this!!"
  706. | active interval delay repeatInterval |
  707. active := false.
  708. repeatInterval := 70.
  709. self wrapper asJQuery unbind: 'keydown'.
  710. self wrapper asJQuery keydown: [ :e |
  711. (e which = 38 and: [ active = false ]) ifTrue: [
  712. active := true.
  713. self activatePreviousListItem.
  714. delay := [
  715. interval := [
  716. (self wrapper asJQuery hasClass: self focusClass)
  717. ifTrue: [
  718. self activatePreviousListItem ]
  719. ifFalse: [
  720. active := false.
  721. interval ifNotNil: [ interval clearInterval ].
  722. delay ifNotNil: [ delay clearTimeout] ] ]
  723. valueWithInterval: repeatInterval ]
  724. valueWithTimeout: 300 ].
  725. (e which = 40 and: [ active = false ]) ifTrue: [
  726. active := true.
  727. self activateNextListItem.
  728. delay := [
  729. interval := [
  730. (self wrapper asJQuery hasClass: self focusClass)
  731. ifTrue: [
  732. self activateNextListItem ]
  733. ifFalse: [
  734. active := false.
  735. interval ifNotNil: [ interval clearInterval ].
  736. delay ifNotNil: [ delay clearTimeout] ] ]
  737. valueWithInterval: repeatInterval ]
  738. valueWithTimeout: 300 ] ].
  739. self wrapper asJQuery keyup: [ :e |
  740. active ifTrue: [
  741. active := false.
  742. interval ifNotNil: [ interval clearInterval ].
  743. delay ifNotNil: [ delay clearTimeout] ] ]
  744. ! !
  745. !HLListWidget methodsFor: 'initialization'!
  746. initialize
  747. super initialize.
  748. mapping := Dictionary new.
  749. ! !
  750. !HLListWidget methodsFor: 'private'!
  751. registerMappingFrom: anObject to: aTag
  752. mapping at: anObject put: aTag
  753. ! !
  754. !HLListWidget methodsFor: 'rendering'!
  755. renderButtonsOn: html
  756. !
  757. renderContentOn: html
  758. html ul
  759. class: 'nav nav-pills nav-stacked';
  760. with: [ self renderListOn: html ].
  761. html div class: 'pane_actions form-actions'; with: [
  762. self renderButtonsOn: html ].
  763. self setupKeyBindings
  764. !
  765. renderItem: anObject on: html
  766. | li |
  767. li := html li.
  768. self registerMappingFrom: anObject to: li.
  769. li
  770. at: 'list-data' put: (self items indexOf: anObject) asString;
  771. class: (self listCssClassForItem: anObject);
  772. with: [
  773. html a
  774. with: [
  775. (html tag: 'i') class: (self cssClassForItem: anObject).
  776. self renderItemLabel: anObject on: html ];
  777. onClick: [
  778. self activateListItem: li asJQuery ] ]
  779. !
  780. renderItemLabel: anObject on: html
  781. html with: anObject asString
  782. !
  783. renderListOn: html
  784. mapping := Dictionary new.
  785. self items do: [ :each |
  786. self renderItem: each on: html ]
  787. ! !
  788. HLListWidget subclass: #HLNavigationListWidget
  789. instanceVariableNames: 'previous next'
  790. package: 'Helios-Core'!
  791. !HLNavigationListWidget methodsFor: 'accessing'!
  792. next
  793. ^ next
  794. !
  795. next: aWidget
  796. next := aWidget.
  797. aWidget previous = self ifFalse: [ aWidget previous: self ]
  798. !
  799. previous
  800. ^ previous
  801. !
  802. previous: aWidget
  803. previous := aWidget.
  804. aWidget next = self ifFalse: [ aWidget next: self ]
  805. ! !
  806. !HLNavigationListWidget methodsFor: 'actions'!
  807. nextFocus
  808. self next ifNotNil: [ self next focus ]
  809. !
  810. previousFocus
  811. self previous ifNotNil: [ self previous focus ]
  812. ! !
  813. !HLNavigationListWidget methodsFor: 'events'!
  814. setupKeyBindings
  815. super setupKeyBindings.
  816. self wrapper asJQuery keydown: [ :e |
  817. e which = 39 ifTrue: [
  818. self nextFocus ].
  819. e which = 37 ifTrue: [
  820. self previousFocus ] ]
  821. ! !
  822. HLNavigationListWidget subclass: #HLToolListWidget
  823. instanceVariableNames: 'model'
  824. package: 'Helios-Core'!
  825. !HLToolListWidget methodsFor: 'accessing'!
  826. commandCategory
  827. ^ self label
  828. !
  829. label
  830. ^ 'List'
  831. !
  832. menuCommands
  833. "Answer a collection of commands to be put in the cog menu"
  834. ^ ((HLToolCommand concreteClasses
  835. select: [ :each | each isValidFor: self model ])
  836. collect: [ :each | each for: self model ])
  837. select: [ :each |
  838. each category = self commandCategory and: [
  839. each isAction and: [ each isActive ] ] ]
  840. !
  841. model
  842. ^ model
  843. !
  844. model: aBrowserModel
  845. model := aBrowserModel.
  846. self
  847. observeSystem;
  848. observeModel
  849. !
  850. selectedItem: anItem
  851. "Selection changed, update the cog menu"
  852. super selectedItem: anItem.
  853. self updateMenu
  854. ! !
  855. !HLToolListWidget methodsFor: 'actions'!
  856. activateListItem: anItem
  857. self model withChangesDo: [ super activateListItem: anItem ]
  858. !
  859. activateNextListItem
  860. self model withChangesDo: [ super activateNextListItem ]
  861. !
  862. activatePreviousListItem
  863. self model withChangesDo: [ super activatePreviousListItem ]
  864. !
  865. observeModel
  866. !
  867. observeSystem
  868. !
  869. unregister
  870. super unregister.
  871. self model announcer unsubscribe: self.
  872. self model systemAnnouncer unsubscribe: self
  873. ! !
  874. !HLToolListWidget methodsFor: 'rendering'!
  875. renderContentOn: html
  876. self renderHeadOn: html.
  877. super renderContentOn: html
  878. !
  879. renderHeadOn: html
  880. html div
  881. class: 'list-label';
  882. with: [
  883. html with: self label.
  884. self renderMenuOn: html ]
  885. !
  886. renderMenuOn: html
  887. | commands |
  888. commands := self menuCommands.
  889. commands isEmpty ifTrue: [ ^ self ].
  890. html div
  891. class: 'btn-group cog';
  892. with: [
  893. html a
  894. class: 'btn dropdown-toggle';
  895. at: 'data-toggle' put: 'dropdown';
  896. with: [ (html tag: 'i') class: 'icon-cog' ].
  897. html ul
  898. class: 'dropdown-menu pull-right';
  899. with: [
  900. self menuCommands do: [ :each |
  901. html li with: [ html a
  902. with: each menuLabel;
  903. onClick: [ self execute: each ] ] ] ] ]
  904. ! !
  905. !HLToolListWidget methodsFor: 'updating'!
  906. updateMenu
  907. (self wrapper asJQuery find: '.cog') remove.
  908. [ :html | self renderMenuOn: html ]
  909. appendToJQuery: (self wrapper asJQuery find: '.list-label')
  910. ! !
  911. !HLToolListWidget class methodsFor: 'instance creation'!
  912. on: aModel
  913. ^ self new
  914. model: aModel;
  915. yourself
  916. ! !
  917. HLWidget subclass: #HLManager
  918. instanceVariableNames: 'tabs activeTab keyBinder environment history'
  919. package: 'Helios-Core'!
  920. !HLManager methodsFor: 'accessing'!
  921. activeTab
  922. ^ activeTab
  923. !
  924. environment
  925. "The default environment used by all Helios objects"
  926. ^ environment ifNil: [ environment := self defaultEnvironment ]
  927. !
  928. environment: anEnvironment
  929. environment := anEnvironment
  930. !
  931. history
  932. ^ history ifNil: [ history := OrderedCollection new ]
  933. !
  934. history: aCollection
  935. history := aCollection
  936. !
  937. keyBinder
  938. ^ keyBinder ifNil: [ keyBinder := HLKeyBinder new ]
  939. !
  940. tabs
  941. ^ tabs ifNil: [ tabs := OrderedCollection new ]
  942. ! !
  943. !HLManager methodsFor: 'actions'!
  944. activate: aTab
  945. self keyBinder flushBindings.
  946. aTab registerBindings.
  947. activeTab := aTab.
  948. self
  949. refresh;
  950. addToHistory: aTab;
  951. show: aTab
  952. !
  953. addTab: aTab
  954. self tabs add: aTab.
  955. self activate: aTab
  956. !
  957. addToHistory: aTab
  958. self removeFromHistory: aTab.
  959. self history add: aTab
  960. !
  961. confirm: aString ifFalse: aBlock
  962. (HLConfirmation new
  963. confirmationString: aString;
  964. cancelBlock: aBlock;
  965. yourself)
  966. appendToJQuery: 'body' asJQuery
  967. !
  968. confirm: aString ifTrue: aBlock
  969. (HLConfirmation new
  970. confirmationString: aString;
  971. actionBlock: aBlock;
  972. yourself)
  973. appendToJQuery: 'body' asJQuery
  974. !
  975. registerErrorHandler: anErrorHandler
  976. self environment registerErrorHandler: anErrorHandler
  977. !
  978. registerInspector: anInspector
  979. self environment registerInspector: anInspector
  980. !
  981. removeActiveTab
  982. self removeTab: self activeTab
  983. !
  984. removeFromHistory: aTab
  985. self history: (self history reject: [ :each | each == aTab ])
  986. !
  987. removeTab: aTab
  988. (self tabs includes: aTab) ifFalse: [ ^ self ].
  989. self removeFromHistory: aTab.
  990. self tabs remove: aTab.
  991. self keyBinder flushBindings.
  992. aTab remove.
  993. self refresh.
  994. self history ifNotEmpty: [
  995. self history last activate ]
  996. !
  997. request: aString do: aBlock
  998. self
  999. request: aString
  1000. value: ''
  1001. do: aBlock
  1002. !
  1003. request: aString value: valueString do: aBlock
  1004. (HLRequest new
  1005. confirmationString: aString;
  1006. actionBlock: aBlock;
  1007. value: valueString;
  1008. yourself)
  1009. appendToJQuery: 'body' asJQuery
  1010. ! !
  1011. !HLManager methodsFor: 'defaults'!
  1012. defaultEnvironment
  1013. "If helios is loaded from within a frame, answer the parent window environment"
  1014. window parent ifNil: [ ^ Environment new ].
  1015. ^ ((window parent at: 'smalltalk')
  1016. at: 'Environment') new
  1017. ! !
  1018. !HLManager methodsFor: 'initialization'!
  1019. initialize
  1020. super initialize.
  1021. self registerInspector: HLInspector.
  1022. self registerErrorHandler: HLErrorHandler.
  1023. self keyBinder setupEvents
  1024. ! !
  1025. !HLManager methodsFor: 'rendering'!
  1026. refresh
  1027. (window jQuery: '.navbar') remove.
  1028. self appendToJQuery: 'body' asJQuery
  1029. !
  1030. renderAddOn: html
  1031. html li
  1032. class: 'dropdown';
  1033. with: [
  1034. html a
  1035. class: 'dropdown-toggle';
  1036. at: 'data-toggle' put: 'dropdown';
  1037. with: [
  1038. html with: 'Open...'.
  1039. (html tag: 'b') class: 'caret' ].
  1040. html ul
  1041. class: 'dropdown-menu';
  1042. with: [
  1043. ((HLWidget withAllSubclasses
  1044. select: [ :each | each canBeOpenAsTab ])
  1045. sorted: [ :a :b | a tabPriority < b tabPriority ])
  1046. do: [ :each |
  1047. html li with: [
  1048. html a
  1049. with: each tabLabel;
  1050. onClick: [ each openAsTab ] ] ] ] ]
  1051. !
  1052. renderContentOn: html
  1053. html div
  1054. class: 'navbar navbar-fixed-top';
  1055. with: [ html div
  1056. class: 'navbar-inner';
  1057. with: [ self renderTabsOn: html ] ]
  1058. !
  1059. renderTabsOn: html
  1060. html ul
  1061. class: 'nav';
  1062. with: [
  1063. self tabs do: [ :each |
  1064. html li
  1065. class: (each isActive ifTrue: [ 'active' ] ifFalse: [ 'inactive' ]);
  1066. with: [
  1067. html a
  1068. with: [
  1069. ((html tag: 'i') class: 'close')
  1070. onClick: [ self removeTab: each ].
  1071. html span
  1072. class: each cssClass;
  1073. with: each displayLabel ];
  1074. onClick: [ each activate ] ] ].
  1075. self renderAddOn: html ]
  1076. !
  1077. show: aTab
  1078. self tabs do: [ :each | each hide ].
  1079. aTab show; focus
  1080. ! !
  1081. HLManager class instanceVariableNames: 'current'!
  1082. !HLManager class methodsFor: 'accessing'!
  1083. current
  1084. ^ current ifNil: [ current := self basicNew initialize ]
  1085. ! !
  1086. !HLManager class methodsFor: 'initialization'!
  1087. initialize
  1088. self current appendToJQuery: 'body' asJQuery
  1089. ! !
  1090. !HLManager class methodsFor: 'instance creation'!
  1091. new
  1092. "Use current instead"
  1093. self shouldNotImplement
  1094. ! !
  1095. HLWidget subclass: #HLSUnit
  1096. instanceVariableNames: ''
  1097. package: 'Helios-Core'!
  1098. !HLSUnit class methodsFor: 'accessing'!
  1099. tabLabel
  1100. ^ 'SUnit'
  1101. !
  1102. tabPriority
  1103. ^ 1000
  1104. ! !
  1105. !HLSUnit class methodsFor: 'testing'!
  1106. canBeOpenAsTab
  1107. ^ true
  1108. ! !