Difference between revisions of "Development Team/Almanac/sugar.activity.activity"
m (invoke Sugar Almanac Table of Chapters template) |
|||
(14 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
+ | {{Sugar Almanac TOC}} | ||
The sugar.activity.activity package includes several important classes that are needed to run a basic activity. | The sugar.activity.activity package includes several important classes that are needed to run a basic activity. | ||
+ | |||
+ | = Helper Functions in sugar.activity.activity = | ||
+ | |||
+ | === How do I get the file path for my activity bundle? === | ||
+ | |||
+ | In the sugar model, all files needed to run an activity (the python code, icons, etc.) should be located under one directory: | ||
+ | |||
+ | "Every activity in the Sugar environment is packaged into a self-contained 'bundle'. The bundle contains all the resources and executable code (other than system-provided base libraries) which the activity needs to execute. Any resources or executable code that is not provided by the base system just be packaged within the bundle." <ref>[http://www.olpcaustria.org/mediawiki/index.php/Activity_handbook OLPC Austria - Activity Handbook for Sugar]</ref> | ||
+ | |||
+ | At present, the most direct way to get a handle on the directory where your activity code is saved is to use the activity.get_bundle_path() method. The following code retrieves the bundle path and prints it to screen - you can reuse it and do whatever you like to save files or manipulate data in your activity bundle directory. | ||
+ | |||
+ | from sugar.activity import activity | ||
+ | ... | ||
+ | print activity.get_bundle_path() | ||
+ | ... | ||
+ | |||
+ | === How do I get the file path where I can write files programmatically? === | ||
+ | |||
+ | The activity package also has a activity.get_activity_root() helper function that gets the root directory where your activity may write files. There are three [http://wiki.laptop.org/go/Low-level_Activity_API#Writable_Directories specific writable subdirectories] within your activity root: instance, data and tmp. | ||
+ | |||
+ | from sugar.activity import activity | ||
+ | import os | ||
+ | ... | ||
+ | #print out the root directory where this activity will be writing | ||
+ | print activity.get_activity_root() | ||
+ | #print out the names of the different root subdirectories to which | ||
+ | #I can write. | ||
+ | print os.path.join(activity.get_activity_root(), "instance") | ||
+ | print os.path.join(activity.get_activity_root(), "data") | ||
+ | print os.path.join(activity.get_activity_root(), "tmp") | ||
+ | |||
+ | |||
+ | === How do I get the name of my activity? === | ||
+ | |||
+ | from sugar.activity import activity | ||
+ | ... | ||
+ | #print out the name of this activity | ||
+ | print activity.get_bundle_name() | ||
= Class: Activity = | = Class: Activity = | ||
+ | Any activity has two major parts: a canvas and a toolbox. The activity class allows you to manipulate both UI sections of any activity. | ||
+ | |||
+ | [[Image:canvas-toolbox.jpg|600px]] | ||
+ | |||
+ | === How do I set the canvas (main work area) of my activity to a specific UI widget? === | ||
+ | |||
+ | Generally, you will set the main canvas of your activity to be either a GTK [http://www.pygtk.org/pygtk2tutorial/ch-ContainerWidgets.html container widget] or a [http://www.pygtk.org/pygtk2tutorial/ch-PackingWidgets.html packing box] that arranges other widgets. The code below demonstrates how a gtk.VBox object (which is later packed with other UI widgets) is set as the canvas for your activity. Usually, you will put this code in the __init__() method for your main activity class. | ||
+ | |||
+ | |||
+ | #Assign self._top_canvas_box to be the top level widget on the canvas | ||
+ | self._top_canvas_box = gtk.VBox() | ||
+ | self.set_canvas(self._top_canvas_box) | ||
+ | |||
=== What are activity id's? How do I obtain the activity id for an instance of my activity? === | === What are activity id's? How do I obtain the activity id for an instance of my activity? === | ||
The activity id is sort of like the unix process id (PID). However, unlike PIDs it is only different for each new instance (with create_jobject = True set) and stays the same every time a user resumes an activity. This is also the identity of your Activity to other XOs for use when sharing. | The activity id is sort of like the unix process id (PID). However, unlike PIDs it is only different for each new instance (with create_jobject = True set) and stays the same every time a user resumes an activity. This is also the identity of your Activity to other XOs for use when sharing. | ||
Line 28: | Line 80: | ||
activity.Activity.__init__(self, handle) | activity.Activity.__init__(self, handle) | ||
+ | === How do I implement a write_file method for my activity in order to persist my activity in the journal? === | ||
+ | |||
+ | Most basic activities can be frozen in the datastore by implementing the write_file() method within the main activity class. This method is then called by sugar to save the activity when it is closed or when user or program commands request that the activity be saved to the datastore. Once saved, the activity can be accessed and reloaded from the journal. | ||
+ | |||
+ | The following simple write_file() method shows how both metadata and files are written. Currently, write_file() will throw an error unless somewhere you actually write an actual file to the file_path that is passed to write_file. The code below writes a dummy file within the body of write_file itself (you can do this elsewhere as long as you have a handle on the file_path variable used by write_file). | ||
+ | |||
+ | class AnnotateActivity(activity.Activity): | ||
+ | ... | ||
+ | def write_file(self, file_path): | ||
+ | logging.debug('WRITING FILE ...') | ||
+ | #save some metadata | ||
+ | self.metadata['current_page'] = '3' | ||
+ | #save the file itself | ||
+ | f = open(file_path, 'w') | ||
+ | try: | ||
+ | f.write("Hello World") | ||
+ | finally: | ||
+ | f.close() | ||
=== How do I implement a read_file method for my activity so that I can resume activities from the sugar journal? === | === How do I implement a read_file method for my activity so that I can resume activities from the sugar journal? === | ||
+ | For most activities, you can implement a read_file() method that will be used by the journal to load your activity. This method is called when the user choses to resume an activity that was running previously. Thus, after ensuring that you write all the necessary data using write_file(), you should implement a read_file() method that reads relevant file data and metadata. This information can then be used to set state variables for your activity so that it resumes in the earlier state chosen by the user. | ||
+ | |||
+ | The following code shows how both file data and activity metadata are read. Notice the call at the end of read_file that actually sets up the activity UI once the state of the activity class is set. | ||
+ | |||
+ | <pre> | ||
+ | |||
+ | """Read saved data from datastore and resume activity based on a previous state | ||
+ | """ | ||
+ | def read_file(self, file_path): | ||
+ | logging.debug('RELOADING ACTIVITY DATA...') | ||
+ | |||
+ | #load data from file for this datastore entry in to the data variable | ||
+ | data = self._get_data_from_file_path(file_path) | ||
+ | |||
+ | #Access different metadata mappings and change any relevant state | ||
+ | #variables for this activity instance. | ||
+ | cp = self.metadata['current_page'] | ||
+ | self._CURRENT_PAGE = int(cp) | ||
− | + | #call any code that will actually initialize the activity with | |
+ | #data that is read from datastore | ||
+ | self._create_ui() | ||
+ | |||
+ | |||
+ | """This method simply returns data that is stored in a given | ||
+ | file_path""" | ||
+ | def _get_data_from_file_path(self, file_path): | ||
+ | fd = open(file_path, 'r') | ||
+ | try: | ||
+ | data = fd.read() | ||
+ | finally: | ||
+ | fd.close() | ||
+ | return data | ||
+ | </pre> | ||
− | = Class: ActivityToolbox = | + | = Class: ActivityToolbox ([[Sugar.graphics.toolbox|Toolbox]])= |
=== What is the standard toolbox needed in most activities and how do I create it? === | === What is the standard toolbox needed in most activities and how do I create it? === | ||
Line 56: | Line 158: | ||
activityToolbar = toolbox.get_activity_toolbar() | activityToolbar = toolbox.get_activity_toolbar() | ||
− | = Class: ActivityToolbar = | + | = Class: ActivityToolbar ([http://www.pygtk.org/docs/pygtk/ gtk.Toolbar]) = |
− | = Class: EditToolbar = | + | = Class: EditToolbar ([http://www.pygtk.org/docs/pygtk/ gtk.Toolbar]) = |
=== How do I add a standard edit toolbar to my activity? === | === How do I add a standard edit toolbar to my activity? === | ||
Line 94: | Line 196: | ||
You can enable buttons by simply passing True to the set_sensitive() method. | You can enable buttons by simply passing True to the set_sensitive() method. | ||
+ | |||
+ | |||
+ | = Notes = | ||
+ | <references /> |
Revision as of 01:24, 14 June 2008
Template:Sugar Almanac TOC The sugar.activity.activity package includes several important classes that are needed to run a basic activity.
Helper Functions in sugar.activity.activity
How do I get the file path for my activity bundle?
In the sugar model, all files needed to run an activity (the python code, icons, etc.) should be located under one directory:
"Every activity in the Sugar environment is packaged into a self-contained 'bundle'. The bundle contains all the resources and executable code (other than system-provided base libraries) which the activity needs to execute. Any resources or executable code that is not provided by the base system just be packaged within the bundle." [1]
At present, the most direct way to get a handle on the directory where your activity code is saved is to use the activity.get_bundle_path() method. The following code retrieves the bundle path and prints it to screen - you can reuse it and do whatever you like to save files or manipulate data in your activity bundle directory.
from sugar.activity import activity ... print activity.get_bundle_path() ...
How do I get the file path where I can write files programmatically?
The activity package also has a activity.get_activity_root() helper function that gets the root directory where your activity may write files. There are three specific writable subdirectories within your activity root: instance, data and tmp.
from sugar.activity import activity import os ... #print out the root directory where this activity will be writing print activity.get_activity_root() #print out the names of the different root subdirectories to which #I can write. print os.path.join(activity.get_activity_root(), "instance") print os.path.join(activity.get_activity_root(), "data") print os.path.join(activity.get_activity_root(), "tmp")
How do I get the name of my activity?
from sugar.activity import activity ... #print out the name of this activity print activity.get_bundle_name()
Class: Activity
Any activity has two major parts: a canvas and a toolbox. The activity class allows you to manipulate both UI sections of any activity.
How do I set the canvas (main work area) of my activity to a specific UI widget?
Generally, you will set the main canvas of your activity to be either a GTK container widget or a packing box that arranges other widgets. The code below demonstrates how a gtk.VBox object (which is later packed with other UI widgets) is set as the canvas for your activity. Usually, you will put this code in the __init__() method for your main activity class.
#Assign self._top_canvas_box to be the top level widget on the canvas self._top_canvas_box = gtk.VBox() self.set_canvas(self._top_canvas_box)
What are activity id's? How do I obtain the activity id for an instance of my activity?
The activity id is sort of like the unix process id (PID). However, unlike PIDs it is only different for each new instance (with create_jobject = True set) and stays the same every time a user resumes an activity. This is also the identity of your Activity to other XOs for use when sharing.
You can use the get_id() method in the Activity class to get the activity id for your activity. Since most activities should inherit from the Activity class, you can actually just get a handle on the top level object for your activity and use that to call get_id.
### TOOLBAREXAMPLE IS AN ACTIVITY THAT SUBCLASSES SUGAR'S ACTIVITY CLASS class ToolbarExample(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle) ... #store the activity id for this variable in the variable my_id my_id = self.get_id() ...
How do I create a new activity that is derived from the base Activity class?
All activities must implement a class derived from the 'Activity' class. The convention is to call it ActivitynameActivity, but this is not required as the activity.info file associated with your activity will tell the sugar-shell which class to start.
from sugar.activity import activity ... class ToolbarExample(activity.Activity): def __init__(self, handle): activity.Activity.__init__(self, handle)
How do I implement a write_file method for my activity in order to persist my activity in the journal?
Most basic activities can be frozen in the datastore by implementing the write_file() method within the main activity class. This method is then called by sugar to save the activity when it is closed or when user or program commands request that the activity be saved to the datastore. Once saved, the activity can be accessed and reloaded from the journal.
The following simple write_file() method shows how both metadata and files are written. Currently, write_file() will throw an error unless somewhere you actually write an actual file to the file_path that is passed to write_file. The code below writes a dummy file within the body of write_file itself (you can do this elsewhere as long as you have a handle on the file_path variable used by write_file).
class AnnotateActivity(activity.Activity): ... def write_file(self, file_path): logging.debug('WRITING FILE ...') #save some metadata self.metadata['current_page'] = '3' #save the file itself f = open(file_path, 'w') try: f.write("Hello World") finally: f.close()
How do I implement a read_file method for my activity so that I can resume activities from the sugar journal?
For most activities, you can implement a read_file() method that will be used by the journal to load your activity. This method is called when the user choses to resume an activity that was running previously. Thus, after ensuring that you write all the necessary data using write_file(), you should implement a read_file() method that reads relevant file data and metadata. This information can then be used to set state variables for your activity so that it resumes in the earlier state chosen by the user.
The following code shows how both file data and activity metadata are read. Notice the call at the end of read_file that actually sets up the activity UI once the state of the activity class is set.
"""Read saved data from datastore and resume activity based on a previous state """ def read_file(self, file_path): logging.debug('RELOADING ACTIVITY DATA...') #load data from file for this datastore entry in to the data variable data = self._get_data_from_file_path(file_path) #Access different metadata mappings and change any relevant state #variables for this activity instance. cp = self.metadata['current_page'] self._CURRENT_PAGE = int(cp) #call any code that will actually initialize the activity with #data that is read from datastore self._create_ui() """This method simply returns data that is stored in a given file_path""" def _get_data_from_file_path(self, file_path): fd = open(file_path, 'r') try: data = fd.read() finally: fd.close() return data
Class: ActivityToolbox (Toolbox)
What is the standard toolbox needed in most activities and how do I create it?
The ActivityToolbox is the standard toolbox that should be a part of any sugar activity. This toolbox starts out with an ActivityToolbar, which contains standard controls for saving to the journal, closing the activity and other basic activity tasks.
To create a standard ActivityToolbox for your activity, place the following code in your activity's __init__ method:
#### CREATE TOOLBOX # Creates the Toolbox. It contains the Activity Toolbar, which is the # bar that appears on every Sugar window and contains essential # functionalities, such as the 'Collaborate' and 'Close' buttons. toolbox = activity.ActivityToolbox(self) self.set_toolbox(toolbox) toolbox.show()
How do I get a handle on the standard activity toolbar given an ActivityToolbox object?
Use the get_activity_toolbar() method in ActivityToolbox to get a handle ont he activity toolbar.
#Get the activity toolbar from our ActivityToolbox object activityToolbar = toolbox.get_activity_toolbar()
Class: ActivityToolbar (gtk.Toolbar)
Class: EditToolbar (gtk.Toolbar)
How do I add a standard edit toolbar to my activity?
The activity package has a standard edit toolbar with the following members:
- undo -- the undo button
- redo -- the redo button
- copy -- the copy button
- paste -- the paste button
- separator -- A separator between undo/redo and copy/paste
You can create a standard edit tool bar using code similar to the following in the __init__ method of your activity's class after you have created a toolbox:
#### EDIT TOOLBAR # Create the edit toolbar: self._edit_toolbar = activity.EditToolbar() # Add the edit toolbar: toolbox.add_toolbar(_('Edit'), self._edit_toolbar) # And make it visible: self._edit_toolbar.show()
How do I hide a button in the edit toolbar that is not needed in my activity?
The following code shows how to hide the undo button. You can also apply similar code to hide the redo, copy and paste buttons.
#hide the undo button self._edit_toolbar.undo.props.visible=False
How do I disable and enable a button on the edit toolbar?
Some buttons, such as copy, may need to be disabled under certain circumstances (eg. there is nothing to copy). This can be done by changing the sensitivity of the widget, as the following code shows:
#disable the use of the copy button for now. self._edit_toolbar.copy.set_sensitive(False)
You can enable buttons by simply passing True to the set_sensitive() method.