Helios-Core.st 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450
  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. 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. selectedPackage := selectedClass theNonMetaClass package.
  106. selectedSelector := aCompiledMethod selector ].
  107. self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
  108. !
  109. selectedPackage
  110. ^ selectedPackage
  111. !
  112. selectedPackage: aPackage
  113. selectedPackage = aPackage ifTrue: [ ^ self ].
  114. self withChangesDo: [
  115. selectedPackage := aPackage.
  116. self selectedClass: nil.
  117. self announcer announce: (HLPackageSelected on: aPackage) ]
  118. !
  119. selectedProtocol
  120. ^ selectedProtocol
  121. !
  122. selectedProtocol: aString
  123. selectedProtocol = aString ifTrue: [ ^ self ].
  124. self withChangesDo: [
  125. selectedProtocol := aString.
  126. self selectedMethod: nil.
  127. self announcer announce: (HLProtocolSelected on: aString) ]
  128. ! !
  129. !HLToolModel methodsFor: 'actions'!
  130. addInstVarNamed: aString
  131. self environment addInstVarNamed: aString to: self selectedClass.
  132. self announcer announce: (HLInstVarAdded new
  133. theClass: self selectedClass;
  134. variableName: aString;
  135. yourself)
  136. !
  137. save: aString
  138. self announcer announce: HLSourceCodeSaved new.
  139. (self shouldCompileClassDefinition: aString)
  140. ifTrue: [ self compileClassDefinition: aString ]
  141. ifFalse: [ self compileMethod: aString ]
  142. !
  143. saveSourceCode
  144. self announcer announce: HLSaveSourceCode new
  145. ! !
  146. !HLToolModel methodsFor: 'commands actions'!
  147. commitPackage
  148. self
  149. withHelperLabelled: 'Committing package ', self selectedPackage name, '...'
  150. do: [ self environment commitPackage: self selectedPackage ]
  151. !
  152. copyClassTo: aClassName
  153. self withChangesDo: [
  154. self environment
  155. copyClass: self selectedClass theNonMetaClass
  156. to: aClassName ]
  157. !
  158. moveClassToPackage: aPackageName
  159. self withChangesDo: [
  160. self environment
  161. moveClass: self selectedClass theNonMetaClass
  162. toPackage: aPackageName ]
  163. !
  164. moveMethodToClass: aClassName
  165. self withChangesDo: [
  166. self environment
  167. moveMethod: self selectedMethod
  168. toClass: aClassName ]
  169. !
  170. moveMethodToProtocol: aProtocol
  171. self withChangesDo: [
  172. self environment
  173. moveMethod: self selectedMethod
  174. toProtocol: aProtocol ]
  175. !
  176. openClassNamed: aString
  177. | class |
  178. self withChangesDo: [
  179. class := self environment classNamed: aString.
  180. self selectedPackage: class package.
  181. self selectedClass: class ]
  182. !
  183. removeClass
  184. self withChangesDo: [
  185. self manager
  186. confirm: 'Do you REALLY want to remove class ', self selectedClass name
  187. ifTrue: [ self environment removeClass: self selectedClass ] ]
  188. !
  189. removeMethod
  190. self withChangesDo: [
  191. self manager
  192. confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector
  193. ifTrue: [ self environment removeMethod: self selectedMethod ] ]
  194. !
  195. removeProtocol
  196. self withChangesDo: [
  197. self manager
  198. confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol
  199. ifTrue: [ self environment
  200. removeProtocol: self selectedProtocol
  201. from: self selectedClass ] ]
  202. !
  203. renameClassTo: aClassName
  204. self withChangesDo: [
  205. self environment
  206. renameClass: self selectedClass theNonMetaClass
  207. to: aClassName ]
  208. !
  209. renameProtocolTo: aString
  210. self withChangesDo: [
  211. self environment
  212. renameProtocol: self selectedProtocol
  213. to: aString
  214. in: self selectedClass ]
  215. ! !
  216. !HLToolModel methodsFor: 'compiling'!
  217. compileClassComment: aString
  218. self environment
  219. compileClassComment: aString
  220. for: self selectedClass
  221. !
  222. compileClassDefinition: aString
  223. self environment compileClassDefinition: aString
  224. !
  225. compileMethod: aString
  226. | method |
  227. self withCompileErrorHandling: [
  228. method := self environment
  229. compileMethod: aString
  230. for: self selectedClass
  231. protocol: self compilationProtocol.
  232. self selectedMethod: method ]
  233. ! !
  234. !HLToolModel methodsFor: 'defaults'!
  235. allProtocol
  236. ^ '-- all --'
  237. !
  238. unclassifiedProtocol
  239. ^ 'as yet unclassified'
  240. ! !
  241. !HLToolModel methodsFor: 'error handling'!
  242. handleCompileError: anError
  243. self announcer announce: (HLCompileErrorRaised new
  244. error: anError;
  245. yourself)
  246. !
  247. handleParseError: anError
  248. | split line column messageToInsert |
  249. split := anError messageText tokenize: ' : '.
  250. messageToInsert := split second.
  251. "21 = 'Parse error on line ' size + 1"
  252. split := split first copyFrom: 21 to: split first size.
  253. split := split tokenize: ' column '.
  254. line := split first.
  255. column := split second.
  256. self announcer announce: (HLParseErrorRaised new
  257. line: line asNumber;
  258. column: column asNumber;
  259. message: messageToInsert;
  260. error: anError;
  261. yourself)
  262. !
  263. handleUnkownVariableError: anError
  264. self announcer announce: (HLUnknownVariableErrorRaised new
  265. error: anError;
  266. yourself)
  267. !
  268. withCompileErrorHandling: aBlock
  269. self environment
  270. evaluate: [
  271. self environment
  272. evaluate: [
  273. self environment
  274. evaluate: aBlock
  275. on: ParseError
  276. do: [:ex | self handleParseError: ex ] ]
  277. on: UnknownVariableError
  278. do: [ :ex | self handleUnkownVariableError: ex ] ]
  279. on: CompilerError
  280. do: [ :ex | self handleCompileError: ex ]
  281. ! !
  282. !HLToolModel methodsFor: 'private'!
  283. compilationProtocol
  284. | currentProtocol |
  285. currentProtocol := self selectedProtocol.
  286. currentProtocol ifNil: [ currentProtocol := self unclassifiedProtocol ].
  287. self selectedMethod ifNotNil: [ currentProtocol := self selectedMethod protocol ].
  288. ^ currentProtocol = self allProtocol
  289. ifTrue: [ self unclassifiedProtocol ]
  290. ifFalse: [ currentProtocol ]
  291. !
  292. withHelperLabelled: aString do: aBlock
  293. "TODO: doesn't belong here"
  294. (window jQuery: '#helper') remove.
  295. [ :html |
  296. html div
  297. id: 'helper';
  298. with: aString ] appendToJQuery: 'body' asJQuery.
  299. [
  300. aBlock value.
  301. (window jQuery: '#helper') remove
  302. ]
  303. valueWithTimeout: 10
  304. ! !
  305. !HLToolModel methodsFor: 'testing'!
  306. isToolModel
  307. ^ true
  308. !
  309. shouldCompileClassDefinition: aString
  310. ^ self selectedClass isNil or: [
  311. aString first asUppercase = aString first ]
  312. ! !
  313. !HLToolModel class methodsFor: 'actions'!
  314. on: anEnvironment
  315. ^ self new
  316. environment: anEnvironment;
  317. yourself
  318. ! !
  319. Widget subclass: #HLTab
  320. instanceVariableNames: 'widget label root'
  321. package: 'Helios-Core'!
  322. !HLTab commentStamp!
  323. I am a widget specialized into building another widget as an Helios tab.
  324. I should not be used directly, `HLWidget class >> #openAsTab` should be used instead.
  325. ## Example
  326. HLWorkspace openAsTab!
  327. !HLTab methodsFor: 'accessing'!
  328. activate
  329. self manager activate: self
  330. !
  331. add
  332. self manager addTab: self
  333. !
  334. cssClass
  335. ^ self widget tabClass
  336. !
  337. displayLabel
  338. ^ self label size > 20
  339. ifTrue: [ (self label first: 20), '...' ]
  340. ifFalse: [ self label ]
  341. !
  342. focus
  343. self widget canHaveFocus ifTrue: [
  344. self widget focus ]
  345. !
  346. label
  347. ^ label ifNil: [ '' ]
  348. !
  349. label: aString
  350. label := aString
  351. !
  352. manager
  353. ^ HLManager current
  354. !
  355. widget
  356. ^ widget
  357. !
  358. widget: aWidget
  359. widget := aWidget
  360. ! !
  361. !HLTab methodsFor: 'actions'!
  362. hide
  363. root ifNotNil: [ root asJQuery css: 'visibility' put: 'hidden' ]
  364. !
  365. registerBindings
  366. self widget registerBindings
  367. !
  368. remove
  369. self widget unregister.
  370. root ifNotNil: [ root asJQuery remove ]
  371. !
  372. show
  373. root
  374. ifNil: [ self appendToJQuery: 'body' asJQuery ]
  375. ifNotNil: [ root asJQuery css: 'visibility' put: 'visible' ]
  376. ! !
  377. !HLTab methodsFor: 'rendering'!
  378. renderOn: html
  379. root := html div
  380. class: 'tab';
  381. yourself.
  382. self renderTab
  383. !
  384. renderTab
  385. root contents: [ :html |
  386. html div
  387. class: 'amber_box';
  388. with: [ self widget renderOn: html ] ]
  389. ! !
  390. !HLTab methodsFor: 'testing'!
  391. isActive
  392. ^ self manager activeTab = self
  393. ! !
  394. !HLTab class methodsFor: 'instance creation'!
  395. on: aWidget labelled: aString
  396. ^ self new
  397. widget: aWidget;
  398. label: aString;
  399. yourself
  400. ! !
  401. Widget subclass: #HLWidget
  402. instanceVariableNames: 'wrapper'
  403. package: 'Helios-Core'!
  404. !HLWidget commentStamp!
  405. I am the abstract superclass of all Helios widgets.
  406. I provide common methods, additional behavior to widgets useful for Helios, like dialog creation, command execution and tab creation.!
  407. !HLWidget methodsFor: 'accessing'!
  408. manager
  409. ^ HLManager current
  410. !
  411. tabClass
  412. ^ self class tabClass
  413. !
  414. wrapper
  415. ^ wrapper
  416. ! !
  417. !HLWidget methodsFor: 'actions'!
  418. alert: aString
  419. window alert: aString
  420. !
  421. confirm: aString ifTrue: aBlock
  422. self manager confirm: aString ifTrue: aBlock
  423. !
  424. execute: aCommand
  425. HLManager current keyBinder
  426. activate;
  427. applyBinding: aCommand asBinding
  428. !
  429. request: aString do: aBlock
  430. self manager request: aString do: aBlock
  431. !
  432. request: aString value: valueString do: aBlock
  433. self manager
  434. request: aString
  435. value: valueString
  436. do: aBlock
  437. !
  438. unregister
  439. "This method is called whenever the receiver is closed (as a tab).
  440. Widgets subscribing to announcements should unregister there"
  441. ! !
  442. !HLWidget methodsFor: 'keybindings'!
  443. registerBindings
  444. self registerBindingsOn: self manager keyBinder bindings
  445. !
  446. registerBindingsOn: aBindingGroup
  447. ! !
  448. !HLWidget methodsFor: 'rendering'!
  449. renderContentOn: html
  450. !
  451. renderOn: html
  452. wrapper := html div.
  453. [ :renderer | self renderContentOn: renderer ] appendToJQuery: wrapper asJQuery
  454. ! !
  455. !HLWidget methodsFor: 'testing'!
  456. canHaveFocus
  457. ^ false
  458. ! !
  459. !HLWidget methodsFor: 'updating'!
  460. refresh
  461. self wrapper ifNil: [ ^ self ].
  462. self wrapper asJQuery empty.
  463. [ :html | self renderContentOn: html ] appendToJQuery: self wrapper asJQuery
  464. ! !
  465. !HLWidget class methodsFor: 'accessing'!
  466. openAsTab
  467. self canBeOpenAsTab ifFalse: [ ^ self ].
  468. HLManager current addTab: (HLTab on: self new labelled: self tabLabel)
  469. !
  470. tabClass
  471. ^ ''
  472. !
  473. tabLabel
  474. ^ 'Tab'
  475. !
  476. tabPriority
  477. ^ 500
  478. ! !
  479. !HLWidget class methodsFor: 'testing'!
  480. canBeOpenAsTab
  481. ^ false
  482. ! !
  483. HLWidget subclass: #HLConfirmation
  484. instanceVariableNames: 'confirmationString actionBlock cancelBlock'
  485. package: 'Helios-Core'!
  486. !HLConfirmation methodsFor: 'accessing'!
  487. actionBlock
  488. ^ actionBlock ifNil: [ [] ]
  489. !
  490. actionBlock: aBlock
  491. actionBlock := aBlock
  492. !
  493. cancelBlock
  494. ^ cancelBlock ifNil: [ [] ]
  495. !
  496. cancelBlock: aBlock
  497. cancelBlock := aBlock
  498. !
  499. confirmationString
  500. ^ confirmationString ifNil: [ 'Confirm' ]
  501. !
  502. confirmationString: aString
  503. confirmationString := aString
  504. !
  505. cssClass
  506. ^ ''
  507. ! !
  508. !HLConfirmation methodsFor: 'actions'!
  509. cancel
  510. self cancelBlock value.
  511. self remove
  512. !
  513. confirm
  514. self actionBlock value.
  515. self remove
  516. !
  517. remove
  518. (window jQuery: '.dialog') removeClass: 'active'.
  519. [
  520. (window jQuery: '#overlay') remove.
  521. (window jQuery: '.dialog') remove
  522. ] valueWithTimeout: 300
  523. ! !
  524. !HLConfirmation methodsFor: 'rendering'!
  525. renderButtonsOn: html
  526. | confirmButton |
  527. html div
  528. class: 'buttons';
  529. with: [
  530. html button
  531. class: 'button';
  532. with: 'Cancel';
  533. onClick: [ self cancel ].
  534. confirmButton := html button
  535. class: 'button default';
  536. with: 'Confirm';
  537. onClick: [ self confirm ] ].
  538. confirmButton asJQuery focus
  539. !
  540. renderContentOn: html
  541. | confirmButton |
  542. html div id: 'overlay'.
  543. html div
  544. class: 'dialog ', self cssClass;
  545. with: [
  546. self
  547. renderMainOn: html;
  548. renderButtonsOn: html ].
  549. (window jQuery: '.dialog') addClass: 'active'.
  550. self setupKeyBindings
  551. !
  552. renderMainOn: html
  553. html span with: self confirmationString
  554. !
  555. setupKeyBindings
  556. (window jQuery: '.dialog') keyup: [ :e |
  557. e keyCode = 27 ifTrue: [ self cancel ] ]
  558. ! !
  559. HLConfirmation subclass: #HLRequest
  560. instanceVariableNames: 'input value'
  561. package: 'Helios-Core'!
  562. !HLRequest methodsFor: 'accessing'!
  563. cssClass
  564. ^ 'large'
  565. !
  566. value
  567. ^ value ifNil: [ '' ]
  568. !
  569. value: aString
  570. value := aString
  571. ! !
  572. !HLRequest methodsFor: 'actions'!
  573. confirm
  574. self actionBlock value: input asJQuery val.
  575. self remove
  576. ! !
  577. !HLRequest methodsFor: 'rendering'!
  578. renderMainOn: html
  579. super renderMainOn: html.
  580. input := html textarea.
  581. input asJQuery val: self value
  582. ! !
  583. HLWidget subclass: #HLFocusableWidget
  584. instanceVariableNames: ''
  585. package: 'Helios-Core'!
  586. !HLFocusableWidget methodsFor: 'accessing'!
  587. focusClass
  588. ^ 'focused'
  589. ! !
  590. !HLFocusableWidget methodsFor: 'events'!
  591. blur
  592. self wrapper asJQuery blur
  593. !
  594. focus
  595. self wrapper asJQuery focus
  596. !
  597. hasFocus
  598. ^ self wrapper notNil and: [ self wrapper asJQuery is: ':focus' ]
  599. ! !
  600. !HLFocusableWidget methodsFor: 'rendering'!
  601. renderContentOn: html
  602. !
  603. renderOn: html
  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. tabClass
  1100. ^ 'sunit'
  1101. !
  1102. tabLabel
  1103. ^ 'SUnit'
  1104. !
  1105. tabPriority
  1106. ^ 1000
  1107. ! !
  1108. !HLSUnit class methodsFor: 'testing'!
  1109. canBeOpenAsTab
  1110. ^ true
  1111. ! !