Pharo /
SandstoneDbOn the Pharocasts, there are two presentations, one on building a GUI using Polymorph (Contact Manager) and another on using SandstoneDb, to create persistent external records. See http://www.pharocasts.com/2011/02/pharo-gui-with-polymorph.html and http://www.pharocasts.com/2010/04/sandstonedb-simple-activerecord-style.html I developed some code that uses SandstoneDb for the ContactManager program. This is not a full-fledged system, any more than the original Pharocast. The purpose is to give you an example of how to use SandstoneDb, so you have something to model from. Here's the code. You can also download it at http://dougedmunds.com/pub/Pharo. Get the file ContactManagerSSDb.zip Object subclass: #ContactEditor instanceVariableNames: 'contact onOKAction' classVariableNames: '' poolDictionaries: '' category: 'ContactManagerSSDb'! !ContactEditor commentStamp: 'estelle 2/3/2011 08:06' prior: 0! Dialog to edit a Contact. For example: ContactEditor new contact: (Contact new firstName: 'Miles'; lastName:'Davis'); openModal.! !ContactEditor methodsFor: 'accessing' stamp: 'LaurentLaffont 1/23/2011 10:08'! contact: aContact contact := aContact! ! !ContactEditor methodsFor: 'ok actions' stamp: 'LaurentLaffont 1/23/2011 13:50'! doOnOK ^ self onOK value! ! !ContactEditor methodsFor: 'ok actions' stamp: 'LaurentLaffont 1/23/2011 13:50'! onOK ^ onOKAction ifNil: [onOKAction := []].! ! !ContactEditor methodsFor: 'ok actions' stamp: 'LaurentLaffont 1/23/2011 13:50'! onOK: aBlock onOKAction := aBlock! ! !ContactEditor methodsFor: 'open/close' stamp: 'LaurentLaffont 1/25/2011 21:15'! openModal |builder dialog content firstName| builder := UITheme builder. content := (builder newLabelGroup: { 'First name' -> (firstName := (builder newTextEntryFor: contact getText: #firstName setText: #firstName: help: 'Enter the first name of the contact') acceptOnCR: false; minWidth: 200). 'Last name' -> ((builder newTextEntryFor: contact getText: #lastName setText: #lastName: help: 'Enter the last name of the contact') acceptOnCR: false; minWidth: 200) }). dialog := builder newPluggableDialogWindow:'Edit contact' for: content. dialog rememberKeyboardFocus: firstName. builder openModal: dialog. dialog cancelled ifFalse: [self doOnOK].! ! SDActiveRecord subclass: #Contact instanceVariableNames: 'firstName lastName' classVariableNames: '' poolDictionaries: '' category: 'ContactManagerSSDb'! !Contact commentStamp: 'estelle 2/3/2011 08:08' prior: 0! I have informations about people. I can store created instances. |someone| someone := Contact new firstName: 'Miles'; lastName:'Davis'. Contact database add: someone. self assert: Contact database last firstName = 'Miles'. self assert: Contact database last lastName = 'Davis'.! !Contact methodsFor: 'accessing' stamp: 'LaurentLaffont 1/23/2011 10:20'! firstName ^ firstName ifNil: [firstName := 'unknown']! ! !Contact methodsFor: 'accessing' stamp: 'LaurentLaffont 1/22/2011 18:11'! firstName: anObject firstName := anObject! ! !Contact methodsFor: 'accessing' stamp: 'LaurentLaffont 1/23/2011 10:19'! lastName ^ lastName ifNil: [lastName := 'unknown']! ! !Contact methodsFor: 'accessing' stamp: 'LaurentLaffont 1/22/2011 18:11'! lastName: anObject lastName := anObject! ! !Contact methodsFor: 'printing' stamp: 'LaurentLaffont 1/22/2011 18:15'! printOn: aStream aStream nextPutAll: self className; nextPutAll: '('; nextPutAll: self firstName; nextPutAll: ' '; nextPutAll: self lastName; nextPutAll: ')'.! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! Contact class instanceVariableNames: ''! !Contact class methodsFor: 'accessing' stamp: 'DougEdmunds 5/3/2011 12:38'! database |db| db := Contact findAll asOrderedCollection. ^ db! ! Object subclass: #ContactListEditor instanceVariableNames: 'selectedContactIndex mainWindow' classVariableNames: '' poolDictionaries: '' category: 'ContactManagerSSDb'! !ContactListEditor commentStamp: 'DougEdmunds 5/3/2011 12:37' prior: 0! Window to add / remove / edit a list of Contact. Open with "ContactListEditor open."! !ContactListEditor methodsFor: 'callback' stamp: 'DougEdmunds 5/3/2011 11:11'! addButtonClick |newContact| newContact := Contact new. ContactEditor new contact: newContact; onOK: [ newContact save. selectedContactIndex := Contact database size. self changed: #contacts; changed: #hasSelectedContact]; openModal. ! ! !ContactListEditor methodsFor: 'callback' stamp: 'LaurentLaffont 1/25/2011 21:17'! contactSelectedIndex: aSmallInteger selectedContactIndex := aSmallInteger. self changed: #contactSelectedIndex; changed: #hasSelectedContact! ! !ContactListEditor methodsFor: 'callback' stamp: 'DougEdmunds 5/3/2011 11:56'! editButtonClick |thisContact| ContactEditor new contact: (thisContact := Contact database at: selectedContactIndex); onOK: [ thisContact save. selectedContactIndex := Contact database size. Transcript cr; show: selectedContactIndex. self changed: #contacts; changed: #hasSelectedContact]; openModal. self changed: #contacts.! ! !ContactListEditor methodsFor: 'callback' stamp: 'DougEdmunds 5/3/2011 11:18'! removeButtonClick (Contact database at: selectedContactIndex) delete. self contactSelectedIndex: (self contactSelectedIndex min: Contact database size); changed: #contacts ! ! !ContactListEditor methodsFor: 'accessing' stamp: 'LaurentLaffont 1/25/2011 21:17'! contactSelectedIndex ^ selectedContactIndex ifNil: [selectedContactIndex := 0]! ! !ContactListEditor methodsFor: 'accessing' stamp: 'DougEdmunds 5/3/2011 11:38'! contacts ^ (Contact database) collect: [:aContact| ', ' join: {aContact lastName. aContact firstName} ].! ! !ContactListEditor methodsFor: 'accessing' stamp: 'LaurentLaffont 1/25/2011 21:18'! hasSelectedContact ^selectedContactIndex > 0! ! !ContactListEditor methodsFor: 'open/close' stamp: 'DougEdmunds 5/3/2011 11:41'! open |builder content| builder := UITheme builder. content := builder newColumn: { builder newListFor: self list: #contacts selected: #contactSelectedIndex changeSelected: #contactSelectedIndex: help: 'contacts'. builder newRow: { builder newButtonFor: self action: #addButtonClick label: 'Add' help: 'Create a new contact'. builder newButtonFor: self action: #removeButtonClick getEnabled: #hasSelectedContact label: 'Remove' help: 'Remove selected contact'. builder newButtonFor: self action: #editButtonClick getEnabled: #hasSelectedContact label: 'Edit' help: 'Edit selected contact'. builder newButtonFor: self action: #closeButtonClick label: 'Close' help: 'Close' . }}. mainWindow := (content openInWindowLabeled: 'Contacts') extent: 400@300.! ! !ContactListEditor methodsFor: 'as yet unclassified' stamp: 'DougEdmunds 5/3/2011 11:12'! closeButtonClick mainWindow delete.! ! !ContactListEditor methodsFor: 'as yet unclassified' stamp: 'DougEdmunds 5/3/2011 12:44'! initialize SDCheckPointer startUp: true. Contact warmUp.! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! ContactListEditor class instanceVariableNames: ''! !ContactListEditor class methodsFor: 'menu' stamp: 'LaurentLaffont 1/28/2011 21:38'! menuCommandOn: aBuilder <worldMenu> (aBuilder item: #'Manage contacts') action:[ self open].! ! !ContactListEditor class methodsFor: 'instance creation' stamp: 'LaurentLaffont 1/23/2011 11:10'! open ^ self new open.! ! |