'From etoys4.0 of 9 October 2008 [latest update: #2302] on 14 September 2009 at 8:31:43 pm'! "Change Set: sugarObjectId-bf Date: 14 September 2009 Author: Bert Freudenberg Remember Sugar object id in each project rather than globally. This prevents accidental overwriting of project in the Journal"! Notification subclass: #SugarPropertiesNotification instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Sugar'! !Project methodsFor: 'sugar' stamp: 'bf 9/14/2009 18:08'! keepSugarProperties: aDictionary monitor: aBoolean | dontKeep props | aDictionary at: 'title' ifPresent: [:title | self name: title]. dontKeep := #('activity' 'activity_id' 'title' 'title_set_by_user' 'keep' 'mtime' 'timestamp' 'preview' 'icon-color' 'mime_type') asSet. props := Dictionary new: aDictionary size. aDictionary keysAndValuesDo: [:key :value | (dontKeep includes: key) ifFalse: [props at: key put: value]]. self sugarProperties: props. aBoolean ifTrue: [ self sugarObjectId ifNotNilDo: [:id | SugarLauncher current monitorJournalEntry: id]].! ! !Project methodsFor: 'sugar' stamp: 'bf 9/14/2009 16:32'! sugarObjectId ^((self sugarProperties ifNil: [^nil]) at: 'uid' ifAbsent: [nil]) asString! ! !Project methodsFor: 'sugar' stamp: 'bf 9/14/2009 16:24'! sugarObjectId: aStringOrNil | props | props := self sugarProperties ifNil: [self sugarProperties: Dictionary new]. aStringOrNil ifNil: [props removeKey: 'uid' ifAbsent: []] ifNotNil: [props at: 'uid' put: aStringOrNil]! ! !Project methodsFor: 'sugar' stamp: 'bf 9/14/2009 16:16'! sugarProperties ^self projectParameterAt: #sugarProperties ifAbsent: [nil]! ! !Project methodsFor: 'sugar' stamp: 'bf 9/14/2009 16:16'! sugarProperties: aDictionary ^self projectParameterAt: #sugarProperties put: aDictionary! ! !ProjectLoading class methodsFor: 'public' stamp: 'bf 9/14/2009 20:25'! loadName: aFileName stream: preStream fromDirectory: aDirectoryOrNil withProjectView: existingView clearOriginFlag: clearOriginFlag "Reconstitute a Morph from the selected file, presumed to be represent a Morph saved via the SmartRefStream mechanism, and open it in an appropriate Morphic world." | morphOrList archive mgr substituteFont numberOfFontSubstitutes resultArray anObject project manifests dict | (self checkStream: preStream) ifTrue: [^ self]. ProgressNotification signal: '0.2'. archive _ preStream isZipArchive ifTrue:[ZipArchive new readFrom: preStream] ifFalse:[nil]. manifests _ (archive membersMatching: '*manifest'). (manifests size = 1 and: [((dict _ self parseManifest: manifests first contents) at: 'Project-Format' ifAbsent: []) = 'S-Expression']) ifTrue: [^ self loadSexpProjectDict: dict stream: preStream fromDirectory: aDirectoryOrNil withProjectView: existingView]. morphOrList _ self morphOrList: aFileName stream: preStream fromDirectory: aDirectoryOrNil archive: archive. morphOrList ifNil: [^ self]. ProgressNotification signal: '0.4'. resultArray _ self fileInName: aFileName archive: archive morphOrList: morphOrList. anObject _ resultArray first. numberOfFontSubstitutes _ resultArray second. substituteFont _ resultArray third. mgr _ resultArray fourth. preStream close. ProgressNotification signal: '0.7'. "the hard part is over" (anObject isKindOf: ImageSegment) ifTrue: [ project _ self loadImageSegment: anObject fromDirectory: aDirectoryOrNil withProjectView: existingView numberOfFontSubstitutes: numberOfFontSubstitutes substituteFont: substituteFont mgr: mgr. project noteManifestDetailsIn: dict. project removeParameter: #sugarProperties. SugarPropertiesNotification signal ifNotNilDo: [:props | project keepSugarProperties: props monitor: true]. clearOriginFlag ifTrue: [project forgetExistingURL]. ProgressNotification signal: '0.8'. ^ project ].! ! !ProjectLoading class methodsFor: 'public' stamp: 'bf 9/14/2009 18:09'! openName: aFileName stream: preStream fromDirectory: aDirectoryOrNil withProjectView: existingView clearOriginFlag: clearOriginFlag "Reconstitute a Morph from the selected file, presumed to represent a Morph saved via the SmartRefStream mechanism, and open it in an appropriate Morphic world." | morphOrList archive mgr substituteFont numberOfFontSubstitutes resultArray anObject project manifests dict | (self checkStream: preStream) ifTrue: [^ self]. ProgressNotification signal: '0.2'. archive _ preStream isZipArchive ifTrue:[ZipArchive new readFrom: preStream] ifFalse:[nil]. archive ifNotNil:[ manifests _ (archive membersMatching: '*manifest'). (manifests size = 1 and: [((dict _ self parseManifest: manifests first contents) at: 'Project-Format' ifAbsent: []) = 'S-Expression']) ifTrue: [^ self openSexpProjectDict: dict stream: preStream fromDirectory: aDirectoryOrNil withProjectView: existingView]]. morphOrList _ self morphOrList: aFileName stream: preStream fromDirectory: aDirectoryOrNil archive: archive. morphOrList ifNil: [^ self]. ProgressNotification signal: '0.4'. resultArray _ self fileInName: aFileName archive: archive morphOrList: morphOrList. anObject _ resultArray first. numberOfFontSubstitutes _ resultArray second. substituteFont _ resultArray third. mgr _ resultArray fourth. preStream close. ProgressNotification signal: '0.7'. "the hard part is over" (anObject isKindOf: ImageSegment) ifTrue: [ project _ self loadImageSegment: anObject fromDirectory: aDirectoryOrNil withProjectView: existingView numberOfFontSubstitutes: numberOfFontSubstitutes substituteFont: substituteFont mgr: mgr.]. (anObject isKindOf: ImageSegment) ifTrue: [ project noteManifestDetailsIn: dict. project removeParameter: #sugarProperties. SugarPropertiesNotification signal ifNotNilDo: [:props | project keepSugarProperties: props monitor: true]. clearOriginFlag ifTrue: [project forgetExistingURL]. ProgressNotification signal: '0.8'. ^ project ifNil: [self inform: 'No project found in this file' translated] ifNotNil: [ProjectEntryNotification signal: project]]. self loadSqueakPage: anObject! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 16:51'! createJournalEntryFor: aProject filename: aFilename mimetype: mimetypeString | properties id | properties := self propertiesFrom: aProject. properties at: 'ctime' put: (properties at: 'mtime'). properties at: 'mime_type' put: mimetypeString. aFilename ifEmpty: [properties at: 'title:text' put: 'Etoys' translated]. id := self dataStore create: properties with: aFilename squeakToUtf8 with: true. ^id asString! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 16:32'! getProperties: objectId | props | props := self dataStore getProperties: objectId. "Make sure the props we care about are strings" props at: 'title' ifPresent: [:value | props at: 'title' put: value asString utf8ToSqueak composeAccents]. props at: 'mime_type' ifPresent: [:value | props at: 'mime_type' put: value asString]. props at: 'uid' put: objectId asString. ^props! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 17:50'! makeJournalEntryFor: aProject filename: aFilename mimetype: mimetypeString | id | (id := aProject sugarObjectId) ifNil: [ id := self createJournalEntryFor: aProject filename: aFilename mimetype: mimetypeString. aProject sugarObjectId: id. self monitorJournalEntry: id] ifNotNil: [ (aProject projectParameterAt: #sugarAutoSave ifAbsent: [true]) ifTrue: [self updateJournalEntry: id for: aProject filename: aFilename mimetype: mimetypeString] ifFalse: [self createJournalEntryFor: aProject filename: aFilename mimetype: mimetypeString]]! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 16:47'! monitorJournalEntry: objectId self dataStore onUpdated: objectId send: #updatedJournalEntry: to: self.! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 16:18'! propertiesFrom: aProject | preview autoSave props | preview := [ByteArray streamContents: [:s | PNGReadWriter putForm: (aProject thumbnail asFormOfDepth: 16) onStream: s]] ifError: ['']. autoSave := aProject projectParameterAt: #sugarAutoSave ifAbsent: [true]. props := (aProject sugarProperties ifNil: [Dictionary new]) copy. { 'activity' -> self bundleId. 'activity_id' -> (autoSave ifTrue: [self activityId] ifFalse: ['']). "temp hack for trial-3" 'title:text' -> (self titleFromProject: aProject) squeakToUtf8. 'title_set_by_user' -> (aProject currentVersionNumber>0 ifTrue: ['1'] ifFalse: ['0']). 'keep' -> (autoSave ifTrue: ['0'] ifFalse: ['1']). 'mtime' -> (DateAndTime now asString first: 19). 'timestamp' -> (DateAndTime now asUnixTime). 'preview' -> preview. 'icon-color' -> self ownerBuddy colors. } do: [:each | props add: each]. ^props ! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 18:09'! resumeJournalEntry: id | props file title project mimetype | props := self getProperties: id. title := props at: 'title' ifAbsent: ['untitled' translated]. mimetype := props at: 'mime_type' ifAbsent: ['']. mimetype isEmpty ifTrue: [^self welcome: '']. mimetype = 'application/x-squeak-project' ifFalse: [ "reuse drop code" WorldState addDeferredUIMessage: [ self open: id title: title mimetype: mimetype]. ^Project enterNew]. ProjectLoading showProgressBarDuring: [ Display fillWhite;forceToScreen. file := self getFile: id. "load project and close temp file (which will thus be deleted)" project := ProjectLoading loadName: ((title copyReplaceAll: '/' with: '\') contractTo: 64) stream: file fromDirectory: nil withProjectView: nil. file close. project keepSugarProperties: props monitor: true. project projectParameterAt: #sugarAutoSave put: true. project enter]. ! ! !SugarLauncher methodsFor: 'datastore' stamp: 'bf 9/14/2009 18:09'! updatedJournalEntry: objectId "sent from DBus in background process" | id project props | id := objectId asString. project := Project allProjects detect: [:each | each sugarObjectId = id] ifNone: [^self]. props := [self getProperties: objectId] on: DBusError do: [^self]. project keepSugarProperties: props monitor: false.! ! !SugarLauncher methodsFor: 'chooser' stamp: 'bf 9/14/2009 17:39'! chooser: chooserId response: objectId self chooserDone: chooserId. WorldState addDeferredUIMessage: [ | props title mimetype | props := self getProperties: objectId. title := props at: 'title' ifAbsent: ['untitled' translated]. mimetype := props at: 'mime_type' ifAbsent: ['']. [self open: objectId title: title mimetype: mimetype] on: SugarPropertiesNotification do: [:ex | ex resume: props]].! ! SugarLauncher removeSelector: #keepProperties:for:! SugarLauncher removeSelector: #monitorJournalEntry!