<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"><html><head><meta name="qrichtext" content="1" /><style type="text/css">p, li { white-space: pre-wrap; }</style></head><body style=" font-family:'Luxi Sans'; font-size:11pt; font-weight:400; font-style:normal;">Hi Bert,<br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p>Thanks for your detail comments. I will probably try to get the "patched" version working this weekend so that I can get quickly to the part of coding the Datastore interactions. I have been stalling on this too long (mostly time reasons I cannot get anything done except weekends), so I want to get to the Datastore part first as a step 1 experiment. <br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p>But I completely agree it is best to replace SugarLauncher with a more generic one asy ou suggested, which I'd make to be step 2. <br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p>Let me see how far I get this weekend on step 1. I have a feeling I will ask for help along the way :)<br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p>Thanks and later, Milan<br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p>On June 1, 2009, Bert Freudenberg wrote:<br>
&gt; On 31.05.2009, at 23:23, Milan Zimmermann wrote:<br>
&gt; &gt; Hi Bert,<br>
&gt; &gt;<br>
&gt; &gt; After 3 weekend delay I got back today to FreeCell. I re-read the<br>
&gt; &gt; email thread and put together high level steps of how FreeCell's<br>
&gt; &gt; statistics state could be managed. I hope the steps are<br>
&gt; &gt; uderstandable, and realize architecturally it is not very nice, but<br>
&gt; &gt; a step..<br>
&gt; &gt;<br>
&gt; &gt; Below, I am listing base code (additions and patches) that would<br>
&gt; &gt; plugin FreeCell into the workflow so that everything is in place<br>
&gt; &gt; where it's statistics state could be managed, serialized and stored<br>
&gt; &gt; in Datastore. Could you comment if the following would work as a<br>
&gt; &gt; first step to play with the Datastore stuff in FreeCell - Thanks.<br>
&gt; &gt; There are some questions at the end, and I appreciate any<br>
&gt; &gt; suggestions and alternatives :)<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt; 1) Patch SugarLauncher&gt;&gt;#startUp to call<br>
&gt; &gt; self class allInstances do: [:ea| ea shutdown]. "is this neded?"<br>
&gt;<br>
&gt; It's a safety net, not strictly needed.<br>
&gt;<br>
&gt; &gt; parameters at 'ACTIVITY_ID' ifPresent: [:activityId|<br>
&gt; &gt; objectId := "todo get objectId".<br>
&gt; &gt; "Make FreeCell and recover statistics from journal"<br>
&gt; &gt; FreeCell class startUpInSugarForActivity: activityId object: objectId.<br>
&gt; &gt; World windowEventHandler: self.<br>
&gt; &gt; ].<br>
&gt; &gt;<br>
&gt; &gt; (A note: I realize you suggested to use FREECELL_ACTIVITY_ID and<br>
&gt; &gt; FREECELL_OBJECT_ID instead of ACTIVITY_ID and OBJECT_ID and then we<br>
&gt; &gt; would not have to patch SugarLauncher&gt;&gt;#startup, but it seems we<br>
&gt; &gt; probably need to patch some other SugarLauncher methods such as<br>
&gt; &gt; invite anyway, so I thought this could be ok)<br>
&gt;<br>
&gt; No, in that case SugarLauncher would not be used at all, that was what<br>
&gt; I was proposing. Better implement the whole caboodle on your own so<br>
&gt; you know what's happening. Less magic ;) OTOH SugarLauncher is hard-<br>
&gt; wired in some places, like in the SugarNavBar, so some refactoring may<br>
&gt; be needed anyway.<br>
&gt;<br>
&gt; A potential problem is that the FreeCell code gets loaded via<br>
&gt; ProjectLauncher so it depends on ProjectLauncher being started first<br>
&gt; before SugarLauncher:<br>
&gt;<br>
&gt;         AutoStart installedLaunchers<br>
&gt;<br>
&gt; &gt; 2) Add method FreeCell class&gt;&gt;#startUpInSugarForActivity: activityId<br>
&gt; &gt; object: objectId<br>
&gt; &gt;<br>
&gt; &gt; which would perform the steps currently performed in the FreeCell.st<br>
&gt; &gt; doits:<br>
&gt; &gt;<br>
&gt; &gt; Project current flapsSurpressed: true.<br>
&gt; &gt; World color: Color black.<br>
&gt; &gt; FreeCell<br>
&gt; &gt; instance<br>
&gt; &gt; (recoverStatisticsOnSugarStartUpForActivity: activityId object:<br>
&gt; &gt; objectId)<br>
&gt; &gt; openInWorld.<br>
&gt; &gt; (... center and zoom to screen extent)<br>
&gt;<br>
&gt; Yes, though objectId may not be present (if this was run the first<br>
&gt; time).<br>
&gt;<br>
&gt; &gt; 3) Add method FreeCell class&gt;&gt;#instance<br>
&gt; &gt; FreeCellSingleton := FreeCell new. "just a class var"<br>
&gt; &gt; ^ FreeCellSingleton.<br>
&gt; &gt;<br>
&gt; &gt; 4) Add method FreeCell&gt;&gt;#recoverStatisticsOnSugarStartUpForActivity:<br>
&gt; &gt; activityId object: objectId<br>
&gt; &gt; this method is eventually called from patched<br>
&gt; &gt; SugarLauncher&gt;&gt;#startUp, and it would do:<br>
&gt; &gt; - use activityId and objectId to read Datastore, and obtain value<br>
&gt; &gt; for key=serialized_statistics<br>
&gt;<br>
&gt; You only need the object id to read from datastore.<br>
&gt;<br>
&gt; &gt; - obtain sessionWins, sessionLosses, totalWins ... etc from<br>
&gt; &gt; serialized_statistics_value<br>
&gt; &gt; - set the deserialized values on the FreeCellStatistics members.<br>
&gt; &gt; (This will need a simple setter of the statistics values)<br>
&gt; &gt;<br>
&gt; &gt; 5) Patch SugarLauncher&gt;&gt;#shutDown as follows:<br>
&gt; &gt; activityId := parameters at: ACTIVITY_ID.<br>
&gt; &gt; objectId := parameters at: OBJECT_ID.<br>
&gt; &gt; freeCell := FreeCell instance.<br>
&gt; &gt; freeCell #shutDownInSugarAsActivity: activityId object: objectId.<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt; 6) Add method FreeCell&gt;&gt;#shutDownInSugarAsActivity: activityId<br>
&gt; &gt; object: objectId<br>
&gt; &gt; which would :<br>
&gt; &gt; - serialize sessionWins, sessionLosses, totalWins ... etc to<br>
&gt; &gt; serialized_statistics_value<br>
&gt; &gt; - put on Datastore, for activityId and objectId, an entry with<br>
&gt; &gt; key=serialized_statistics, value=serialized_statistics_value<br>
&gt; &gt;<br>
&gt; &gt; 7) Add method FreeCell&gt;&gt;#quit which would do:<br>
&gt; &gt; Sugarlauncher current quit<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt; &gt; 8) Patch SugarLauncher&gt;&gt;#quit to call<br>
&gt; &gt; self leaveSharedActivity. "is this needed?"<br>
&gt; &gt; Smalltalk quitPrimitive. "i hope this calls shutDown?"<br>
&gt;<br>
&gt; No, this quits immediately ...<br>
&gt;<br>
&gt; &gt; FreeCell class startUpInSugar.<br>
&gt;<br>
&gt; ... meaning you need to do the FreeCell shutdown before quitting.<br>
&gt;<br>
&gt; &gt; 9) Export the changes to FreeCell.st. so it will contain roughtly:<br>
&gt; &gt; - patches for:<br>
&gt; &gt; - SugarLauncher&gt;&gt;#startUp<br>
&gt; &gt; - SugarLauncher&gt;&gt;#shutDown<br>
&gt; &gt; - SugarLauncher&gt;&gt;#quit<br>
&gt; &gt; - FreeCell&gt;&gt;#quit<br>
&gt; &gt;<br>
&gt; &gt; I did not run any of this .. this is my next step, but I wanted to<br>
&gt; &gt; run it by you for obvious problems, so:<br>
&gt; &gt;<br>
&gt; &gt; Questions, comments and doubts:<br>
&gt; &gt; =============================<br>
&gt; &gt;<br>
&gt; &gt; - Would this work in principal? I am especially not sure around<br>
&gt; &gt; handling the shutDown on quit.<br>
&gt;<br>
&gt; In principle it should work, yes.<br>
&gt;<br>
&gt; &gt; - Are there better more elegant/reusable ways if someone else wants<br>
&gt; &gt; to do something similar to other Etoys activity (ZIP, Speach etc etc)?<br>
&gt;<br>
&gt; Well, replacing SugarLauncher with a more generic one would be good.<br>
&gt; At least the Etoys-specific parts should be factored out. But then<br>
&gt; again getting it to work first is not the worst idea.<br>
&gt;<br>
&gt; &gt; - In step 6, what would be the mime type for the new datastore<br>
&gt; &gt; record, so it is associated with Etoys? There are Mime types listed<br>
&gt; &gt; in /usr/share/sugar/data/mime.defaults but it does not list Etoys...<br>
&gt;<br>
&gt; It should not be associated with Etoys but with FreeCell. You could<br>
&gt; make up any mimetype. It does not have to be listed in the mime<br>
&gt; database, unless you intend to transfer these files outside of Sugar.<br>
&gt; If you want that you need to make up an extension and add a mime rule,<br>
&gt; see mimetypes.xml in<br>
&gt;<br>
&gt; http://wiki.laptop.org/go/Activity_bundles<br>
&gt;<br>
&gt; &gt; - I need to check when etoys start SugarLauncher&gt;&gt;#startUp is<br>
&gt; &gt; performed when I click on a Journal FreeCell item, as startUp<br>
&gt; &gt; contains the FreeCell creation and initialization mechanism<br>
&gt;<br>
&gt; SugarLauncher is registered with AutoStart.<br>
&gt;<br>
&gt; &gt; - I cannot figure out which class puts the ACTIVITY_ID to<br>
&gt; &gt; AbstractLauncher&gt;&gt;member parameters, but that is not needed for the<br>
&gt; &gt; stuff above.<br>
&gt;<br>
&gt; AbstractLauncher&gt;&gt;parameters does lazy initialization. But before<br>
&gt; that, AutoStart&gt;&gt;startUp: actually sets the parameters. In either<br>
&gt; case, #extractParameters is what gets arguments from the command line<br>
&gt; (as passed in the activity script).<br>
&gt;<br>
&gt; - Bert -<br>
&gt;<br>
&gt;<br>
&gt; _______________________________________________<br>
&gt; Etoys mailing list<br>
&gt; Etoys@lists.laptop.org<br>
&gt; http://lists.laptop.org/listinfo/etoys<br>
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p><p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; -qt-user-state:0;"><br></p></body></html>