diff options
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | po/es.po | 174 | ||||
-rw-r--r-- | po/tvl.po | 206 | ||||
-rw-r--r-- | po/zh_TW.po | 167 | ||||
-rw-r--r-- | src/sugar/activity/__init__py | 0 | ||||
-rw-r--r-- | src/sugar/activity/activityfactory.py | 11 | ||||
-rw-r--r-- | src/sugar/datastore/Makefile.am | 1 | ||||
-rw-r--r-- | src/sugar/datastore/datastore.py | 330 | ||||
-rw-r--r-- | src/sugar/datastore/dbus_helpers.py | 115 | ||||
-rw-r--r-- | src/sugar/graphics/icon.py | 28 | ||||
-rw-r--r-- | src/sugar/graphics/style.py | 1 |
11 files changed, 706 insertions, 332 deletions
diff --git a/configure.ac b/configure.ac index 8e0c26e..fab862b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([sugar-toolkit],[0.87.3],[],[sugar-toolkit]) +AC_INIT([sugar-toolkit],[0.87.4],[],[sugar-toolkit]) AC_PREREQ([2.59]) @@ -26,7 +26,8 @@ AC_SUBST(PYGTK_DEFSDIR) # Setup GETTEXT # -ALL_LINGUAS="af am ar ay bg bn bn_IN ca de dz el en es fa fa_AF ff fr gu ha hi ht ig is it ja km ko mk ml mn mr mvo nb ne nl pa pap pis pl ps pt pt_BR qu ro ru rw sd si sl te th tpi tr ur vi yo zh_CN zh_TW" +ALL_LINGUAS="af am ar ay bg bi bn_IN bn ca cpp cs da de dz el en es fa_AF fa ff fil fr gu ha he hi ht hu id ig is it ja km ko kos mg mi mk ml mn mr ms mvo nb ne nl pa pap pis pl ps pt_BR pt qu ro ru rw sd si sk sl sq sv sw ta te th tpi tr tvl tzo ug ur vi wa yo zh_CN zh_TW" + GETTEXT_PACKAGE=sugar-toolkit AC_PROG_INTLTOOL([0.33]) AC_SUBST(GETTEXT_PACKAGE) @@ -6,140 +6,137 @@ msgid "" msgstr "" "Project-Id-Version: olpc-sugar\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-01-20 00:31-0500\n" -"PO-Revision-Date: 2009-01-30 20:27-0500\n" -"Last-Translator: Maria del Pilar Saenz Rodriguez <mapisaro@gmail.com>\n" +"POT-Creation-Date: 2009-08-26 00:33-0400\n" +"PO-Revision-Date: 2009-09-02 18:26-0400\n" +"Last-Translator: Rafael Ortiz <rafael@laptop.org>\n" "Language-Team: Fedora Spanish <fedora-trans-es@redhat.com>\n" +"Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Pootle 1.1.0rc2\n" +"X-Generator: Pootle 1.2.1\n" "X-Poedit-Language: Spanish\n" "X-Poedit-SourceCharset: utf-8\n" "X-Poedit-Basepath: .\n" -#: ../src/sugar/activity/activity.py:123 -msgid "Share with:" -msgstr "Compartir con:" - -#: ../src/sugar/activity/activity.py:125 -msgid "Private" -msgstr "Privado" - -#: ../src/sugar/activity/activity.py:126 -msgid "My Neighborhood" -msgstr "Mi Vecindario" - -# self._stop_item = MenuItem(_('Stop download'), 'stock-close') -# TODO: Implement stopping downloads -# self._stop_item.connect('activate', self._stop_item_activate_cb) -# self.append_menu_item(self._stop_item) -#: ../src/sugar/activity/activity.py:133 -#: ../src/sugar/activity/namingalert.py:65 -msgid "Keep" -msgstr "Guardar" - -#: ../src/sugar/activity/activity.py:144 -msgid "Stop" -msgstr "Parar" - -#: ../src/sugar/activity/activity.py:258 -msgid "Undo" -msgstr "Deshacer" - -#: ../src/sugar/activity/activity.py:263 -msgid "Redo" -msgstr "Rehacer" - -#: ../src/sugar/activity/activity.py:273 -msgid "Copy" -msgstr "Copiar" - -#: ../src/sugar/activity/activity.py:278 -msgid "Paste" -msgstr "Pegar" - -#: ../src/sugar/activity/activity.py:304 -msgid "Activity" -msgstr "Actividad" - -#: ../src/sugar/activity/activity.py:542 +#: ../src/sugar/activity/activity.py:329 #, python-format msgid "%s Activity" msgstr "Actividad %s" -#: ../src/sugar/activity/activity.py:910 +#: ../src/sugar/activity/activity.py:714 msgid "Keep error" msgstr "Error al guardar" -#: ../src/sugar/activity/activity.py:911 +#: ../src/sugar/activity/activity.py:715 msgid "Keep error: all changes will be lost" msgstr "Error al guardar: todos los cambios se perderán" -#: ../src/sugar/activity/activity.py:914 +#: ../src/sugar/activity/activity.py:718 msgid "Don't stop" msgstr "No detener" -#: ../src/sugar/activity/activity.py:917 +#: ../src/sugar/activity/activity.py:721 msgid "Stop anyway" msgstr "Detener de todas formas" -#: ../src/sugar/activity/namingalert.py:60 +#: ../src/sugar/activity/namingalert.py:82 msgid "Name this entry" msgstr "Nombre esta entrada" -#: ../src/sugar/activity/namingalert.py:248 +# self._stop_item = MenuItem(_('Stop download'), 'stock-close') +# TODO: Implement stopping downloads +# self._stop_item.connect('activate', self._stop_item_activate_cb) +# self.append_menu_item(self._stop_item) +#: ../src/sugar/activity/namingalert.py:87 +#: ../src/sugar/activity/widgets.py:162 +msgid "Keep" +msgstr "Guardar" + +#: ../src/sugar/activity/namingalert.py:283 msgid "Untitled" msgstr "Sin título" -#: ../src/sugar/activity/namingalert.py:255 +#: ../src/sugar/activity/namingalert.py:290 msgid "Description:" msgstr "Descripción:" -#: ../src/sugar/activity/namingalert.py:279 +#: ../src/sugar/activity/namingalert.py:314 msgid "Tags:" msgstr "Etiquetas:" -#: ../src/sugar/graphics/alert.py:288 ../src/sugar/graphics/alert.py:367 +#: ../src/sugar/activity/widgets.py:79 +msgid "Stop" +msgstr "Parar" + +#: ../src/sugar/activity/widgets.py:91 +msgid "Undo" +msgstr "Deshacer" + +#: ../src/sugar/activity/widgets.py:99 +msgid "Redo" +msgstr "Rehacer" + +#: ../src/sugar/activity/widgets.py:106 +msgid "Copy" +msgstr "Copiar" + +#: ../src/sugar/activity/widgets.py:113 +msgid "Paste" +msgstr "Pegar" + +#: ../src/sugar/activity/widgets.py:123 +msgid "Private" +msgstr "Privado" + +#: ../src/sugar/activity/widgets.py:130 +msgid "My Neighborhood" +msgstr "Mi Vecindario" + +#: ../src/sugar/activity/widgets.py:341 +msgid "Activity" +msgstr "Actividad" + +#: ../src/sugar/graphics/alert.py:286 ../src/sugar/graphics/alert.py:365 msgid "Cancel" msgstr "Cancelar" -#: ../src/sugar/graphics/alert.py:292 ../src/sugar/graphics/alert.py:426 +#: ../src/sugar/graphics/alert.py:290 ../src/sugar/graphics/alert.py:424 msgid "Ok" msgstr "Ok" -#: ../src/sugar/graphics/alert.py:377 +#: ../src/sugar/graphics/alert.py:375 msgid "Continue" msgstr "Continuar" -#: ../src/sugar/graphics/colorbutton.py:49 +#: ../src/sugar/graphics/colorbutton.py:52 msgid "Choose a color" msgstr "Escoja un color" -#: ../src/sugar/graphics/colorbutton.py:262 +#: ../src/sugar/graphics/colorbutton.py:272 msgid "Red" msgstr "Rojo" -#: ../src/sugar/graphics/colorbutton.py:264 +#: ../src/sugar/graphics/colorbutton.py:274 msgid "Green" msgstr "Verde" -#: ../src/sugar/graphics/colorbutton.py:266 +#: ../src/sugar/graphics/colorbutton.py:276 msgid "Blue" msgstr "Azul" -#: ../src/sugar/util.py:194 +#: ../src/sugar/util.py:218 msgid " and " msgstr " y " -#: ../src/sugar/util.py:195 +#: ../src/sugar/util.py:219 msgid ", " msgstr ", " # TRANS: Indicating something that just happened, eg. "just now", "moments ago" #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" -#: ../src/sugar/util.py:198 +#: ../src/sugar/util.py:222 msgid "Seconds ago" msgstr "Segundos atrás" @@ -148,7 +145,7 @@ msgstr "Segundos atrás" # "[2 minutes] in the past", or "[3 years, 1 month] earlier" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" -#: ../src/sugar/util.py:202 +#: ../src/sugar/util.py:226 #, python-format msgid "%s ago" msgstr "%s atrás" @@ -157,48 +154,75 @@ msgstr "%s atrás" # Traduction: I don't know why somebody wrote the same for plural and singular traduction. # TRANS: Relative dates (eg. 1 month and 5 days). #. TRANS: Relative dates (eg. 1 month and 5 days). -#: ../src/sugar/util.py:215 +#: ../src/sugar/util.py:241 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d año" msgstr[1] "%d años" -#: ../src/sugar/util.py:216 +#: ../src/sugar/util.py:242 #, python-format msgid "%d month" msgid_plural "%d months" msgstr[0] "%d mes" msgstr[1] "%d meses" -#: ../src/sugar/util.py:217 +#: ../src/sugar/util.py:243 #, python-format msgid "%d week" msgid_plural "%d weeks" msgstr[0] "%d semana" msgstr[1] "%d semanas" -#: ../src/sugar/util.py:218 +#: ../src/sugar/util.py:244 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d día" msgstr[1] "%d días" -#: ../src/sugar/util.py:219 +#: ../src/sugar/util.py:245 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d hora" msgstr[1] "%d horas" -#: ../src/sugar/util.py:220 +#: ../src/sugar/util.py:246 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d minuto" msgstr[1] "%d minutos" +#: ../src/sugar/util.py:339 +msgid "Empty" +msgstr "Vacio" + +#: ../src/sugar/util.py:341 +#, python-format +msgid "%d B" +msgstr "%d B" + +#: ../src/sugar/util.py:343 +#, python-format +msgid "%d KB" +msgstr "%d KB" + +#: ../src/sugar/util.py:345 +#, python-format +msgid "%d MB" +msgstr "%d MB" + +#: ../src/sugar/util.py:347 +#, python-format +msgid "%d GB" +msgstr "%d GB" + +#~ msgid "Share with:" +#~ msgstr "Compartir con:" + #~ msgid "Name:" #~ msgstr "Nombre:" diff --git a/po/tvl.po b/po/tvl.po new file mode 100644 index 0000000..5e78660 --- /dev/null +++ b/po/tvl.po @@ -0,0 +1,206 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2009-08-26 00:33-0400\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Translate Toolkit 1.3.0\n" + +#: ../src/sugar/activity/activity.py:329 +#, python-format +msgid "%s Activity" +msgstr "" + +#: ../src/sugar/activity/activity.py:714 +msgid "Keep error" +msgstr "" + +#: ../src/sugar/activity/activity.py:715 +msgid "Keep error: all changes will be lost" +msgstr "" + +#: ../src/sugar/activity/activity.py:718 +msgid "Don't stop" +msgstr "" + +#: ../src/sugar/activity/activity.py:721 +msgid "Stop anyway" +msgstr "" + +#: ../src/sugar/activity/namingalert.py:82 +msgid "Name this entry" +msgstr "" + +#: ../src/sugar/activity/namingalert.py:87 +#: ../src/sugar/activity/widgets.py:162 +msgid "Keep" +msgstr "" + +#: ../src/sugar/activity/namingalert.py:283 +msgid "Untitled" +msgstr "" + +#: ../src/sugar/activity/namingalert.py:290 +msgid "Description:" +msgstr "" + +#: ../src/sugar/activity/namingalert.py:314 +msgid "Tags:" +msgstr "" + +#: ../src/sugar/activity/widgets.py:79 +msgid "Stop" +msgstr "" + +#: ../src/sugar/activity/widgets.py:91 +msgid "Undo" +msgstr "" + +#: ../src/sugar/activity/widgets.py:99 +msgid "Redo" +msgstr "" + +#: ../src/sugar/activity/widgets.py:106 +msgid "Copy" +msgstr "" + +#: ../src/sugar/activity/widgets.py:113 +msgid "Paste" +msgstr "" + +#: ../src/sugar/activity/widgets.py:123 +msgid "Private" +msgstr "" + +#: ../src/sugar/activity/widgets.py:130 +msgid "My Neighborhood" +msgstr "" + +#: ../src/sugar/activity/widgets.py:341 +msgid "Activity" +msgstr "" + +#: ../src/sugar/graphics/alert.py:286 ../src/sugar/graphics/alert.py:365 +msgid "Cancel" +msgstr "" + +#: ../src/sugar/graphics/alert.py:290 ../src/sugar/graphics/alert.py:424 +msgid "Ok" +msgstr "" + +#: ../src/sugar/graphics/alert.py:375 +msgid "Continue" +msgstr "" + +#: ../src/sugar/graphics/colorbutton.py:52 +msgid "Choose a color" +msgstr "" + +#: ../src/sugar/graphics/colorbutton.py:272 +msgid "Red" +msgstr "" + +#: ../src/sugar/graphics/colorbutton.py:274 +msgid "Green" +msgstr "" + +#: ../src/sugar/graphics/colorbutton.py:276 +msgid "Blue" +msgstr "" + +#: ../src/sugar/util.py:218 +msgid " and " +msgstr "" + +#: ../src/sugar/util.py:219 +msgid ", " +msgstr "" + +#. TRANS: Indicating something that just happened, eg. "just now", "moments ago" +#: ../src/sugar/util.py:222 +msgid "Seconds ago" +msgstr "" + +#. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", +#. "[2 minutes] in the past", or "[3 years, 1 month] earlier" +#: ../src/sugar/util.py:226 +#, python-format +msgid "%s ago" +msgstr "" + +#. TRANS: Relative dates (eg. 1 month and 5 days). +#: ../src/sugar/util.py:241 +#, python-format +msgid "%d year" +msgid_plural "%d years" +msgstr[0] "" +msgstr[1] "" + +#: ../src/sugar/util.py:242 +#, python-format +msgid "%d month" +msgid_plural "%d months" +msgstr[0] "" +msgstr[1] "" + +#: ../src/sugar/util.py:243 +#, python-format +msgid "%d week" +msgid_plural "%d weeks" +msgstr[0] "" +msgstr[1] "" + +#: ../src/sugar/util.py:244 +#, python-format +msgid "%d day" +msgid_plural "%d days" +msgstr[0] "" +msgstr[1] "" + +#: ../src/sugar/util.py:245 +#, python-format +msgid "%d hour" +msgid_plural "%d hours" +msgstr[0] "" +msgstr[1] "" + +#: ../src/sugar/util.py:246 +#, python-format +msgid "%d minute" +msgid_plural "%d minutes" +msgstr[0] "" +msgstr[1] "" + +#: ../src/sugar/util.py:339 +msgid "Empty" +msgstr "" + +#: ../src/sugar/util.py:341 +#, python-format +msgid "%d B" +msgstr "" + +#: ../src/sugar/util.py:343 +#, python-format +msgid "%d KB" +msgstr "" + +#: ../src/sugar/util.py:345 +#, python-format +msgid "%d MB" +msgstr "" + +#: ../src/sugar/util.py:347 +#, python-format +msgid "%d GB" +msgstr "" diff --git a/po/zh_TW.po b/po/zh_TW.po index 2cacea2..b3526bf 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -6,178 +6,203 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2009-01-20 00:31-0500\n" -"PO-Revision-Date: 2009-01-28 19:22-0500\n" +"POT-Creation-Date: 2009-08-26 00:33-0400\n" +"PO-Revision-Date: 2009-12-22 08:05-0400\n" "Last-Translator: Yuan Chao <yuanchao@gmail.com>\n" "Language-Team: LANGUAGE <LL@li.org>\n" +"Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Pootle 1.1.0rc2\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Pootle 1.2.1\n" -#: ../src/sugar/activity/activity.py:123 -msgid "Share with:" -msgstr "分享給:" - -#: ../src/sugar/activity/activity.py:125 -msgid "Private" -msgstr "私人" - -#: ../src/sugar/activity/activity.py:126 -msgid "My Neighborhood" -msgstr "我的鄰居" - -#: ../src/sugar/activity/activity.py:133 -#: ../src/sugar/activity/namingalert.py:65 -msgid "Keep" -msgstr "保存" - -#: ../src/sugar/activity/activity.py:144 -msgid "Stop" -msgstr "停止" - -#: ../src/sugar/activity/activity.py:258 -msgid "Undo" -msgstr "復原" - -#: ../src/sugar/activity/activity.py:263 -msgid "Redo" -msgstr "取消復原" - -#: ../src/sugar/activity/activity.py:273 -msgid "Copy" -msgstr "複製" - -#: ../src/sugar/activity/activity.py:278 -msgid "Paste" -msgstr "貼上" - -#: ../src/sugar/activity/activity.py:304 -msgid "Activity" -msgstr "活動" - -#: ../src/sugar/activity/activity.py:542 +#: ../src/sugar/activity/activity.py:329 #, python-format msgid "%s Activity" msgstr "%s 活動" -#: ../src/sugar/activity/activity.py:910 +#: ../src/sugar/activity/activity.py:714 msgid "Keep error" msgstr "保存時發生錯誤" -#: ../src/sugar/activity/activity.py:911 +#: ../src/sugar/activity/activity.py:715 msgid "Keep error: all changes will be lost" msgstr "保存時發生錯誤:所作的變動將遺失" -#: ../src/sugar/activity/activity.py:914 +#: ../src/sugar/activity/activity.py:718 msgid "Don't stop" msgstr "不停止" -#: ../src/sugar/activity/activity.py:917 +#: ../src/sugar/activity/activity.py:721 msgid "Stop anyway" msgstr "確定停止" -#: ../src/sugar/activity/namingalert.py:60 +#: ../src/sugar/activity/namingalert.py:82 msgid "Name this entry" msgstr "命名" -#: ../src/sugar/activity/namingalert.py:248 +#: ../src/sugar/activity/namingalert.py:87 +#: ../src/sugar/activity/widgets.py:162 +msgid "Keep" +msgstr "保存" + +#: ../src/sugar/activity/namingalert.py:283 msgid "Untitled" msgstr "未命名" -#: ../src/sugar/activity/namingalert.py:255 +#: ../src/sugar/activity/namingalert.py:290 msgid "Description:" msgstr "描述:" -#: ../src/sugar/activity/namingalert.py:279 +#: ../src/sugar/activity/namingalert.py:314 msgid "Tags:" msgstr "標籤:" -#: ../src/sugar/graphics/alert.py:288 ../src/sugar/graphics/alert.py:367 +#: ../src/sugar/activity/widgets.py:79 +msgid "Stop" +msgstr "停止" + +#: ../src/sugar/activity/widgets.py:91 +msgid "Undo" +msgstr "復原" + +#: ../src/sugar/activity/widgets.py:99 +msgid "Redo" +msgstr "取消復原" + +#: ../src/sugar/activity/widgets.py:106 +msgid "Copy" +msgstr "複製" + +#: ../src/sugar/activity/widgets.py:113 +msgid "Paste" +msgstr "貼上" + +#: ../src/sugar/activity/widgets.py:123 +msgid "Private" +msgstr "私人" + +#: ../src/sugar/activity/widgets.py:130 +msgid "My Neighborhood" +msgstr "我的鄰居" + +#: ../src/sugar/activity/widgets.py:341 +msgid "Activity" +msgstr "活動" + +#: ../src/sugar/graphics/alert.py:286 ../src/sugar/graphics/alert.py:365 msgid "Cancel" msgstr "取消" -#: ../src/sugar/graphics/alert.py:292 ../src/sugar/graphics/alert.py:426 +#: ../src/sugar/graphics/alert.py:290 ../src/sugar/graphics/alert.py:424 msgid "Ok" msgstr "確定" -#: ../src/sugar/graphics/alert.py:377 +#: ../src/sugar/graphics/alert.py:375 msgid "Continue" msgstr "繼續" -#: ../src/sugar/graphics/colorbutton.py:49 +#: ../src/sugar/graphics/colorbutton.py:52 msgid "Choose a color" msgstr "選擇喜歡的顏色" -#: ../src/sugar/graphics/colorbutton.py:262 +#: ../src/sugar/graphics/colorbutton.py:272 msgid "Red" msgstr "紅色" -#: ../src/sugar/graphics/colorbutton.py:264 +#: ../src/sugar/graphics/colorbutton.py:274 msgid "Green" msgstr "綠色" -#: ../src/sugar/graphics/colorbutton.py:266 +#: ../src/sugar/graphics/colorbutton.py:276 msgid "Blue" msgstr "藍色" -#: ../src/sugar/util.py:194 +#: ../src/sugar/util.py:218 msgid " and " msgstr " 和 " -#: ../src/sugar/util.py:195 +#: ../src/sugar/util.py:219 msgid ", " msgstr ", " # TRANS: Indicating something that just happened, eg. "just now", "moments ago" #. TRANS: Indicating something that just happened, eg. "just now", "moments ago" -#: ../src/sugar/util.py:198 +#: ../src/sugar/util.py:222 msgid "Seconds ago" -msgstr "秒鐘前" +msgstr "數秒鐘前" # TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", # "[2 minutes] in the past", or "[3 years, 1 month] earlier" #. TRANS: Indicating time passed, eg. "[10 day, 5 hours] ago", #. "[2 minutes] in the past", or "[3 years, 1 month] earlier" -#: ../src/sugar/util.py:202 +#: ../src/sugar/util.py:226 #, python-format msgid "%s ago" msgstr "%s 前" # TRANS: Relative dates (eg. 1 month and 5 days). #. TRANS: Relative dates (eg. 1 month and 5 days). -#: ../src/sugar/util.py:215 +#: ../src/sugar/util.py:241 #, python-format msgid "%d year" msgid_plural "%d years" msgstr[0] "%d 年" -#: ../src/sugar/util.py:216 +#: ../src/sugar/util.py:242 #, python-format msgid "%d month" msgid_plural "%d months" msgstr[0] "%d 個月" -#: ../src/sugar/util.py:217 +#: ../src/sugar/util.py:243 #, python-format msgid "%d week" msgid_plural "%d weeks" msgstr[0] "%d 週" -#: ../src/sugar/util.py:218 +#: ../src/sugar/util.py:244 #, python-format msgid "%d day" msgid_plural "%d days" msgstr[0] "%d 天" -#: ../src/sugar/util.py:219 +#: ../src/sugar/util.py:245 #, python-format msgid "%d hour" msgid_plural "%d hours" msgstr[0] "%d 小時" -#: ../src/sugar/util.py:220 +#: ../src/sugar/util.py:246 #, python-format msgid "%d minute" msgid_plural "%d minutes" msgstr[0] "%d 分鐘" + +#: ../src/sugar/util.py:339 +msgid "Empty" +msgstr "無" + +#: ../src/sugar/util.py:341 +#, python-format +msgid "%d B" +msgstr "%d B" + +#: ../src/sugar/util.py:343 +#, python-format +msgid "%d KB" +msgstr "%d KB" + +#: ../src/sugar/util.py:345 +#, python-format +msgid "%d MB" +msgstr "%d MB" + +#: ../src/sugar/util.py:347 +#, python-format +msgid "%d GB" +msgstr "%d GB" + +#~ msgid "Share with:" +#~ msgstr "分享給:" diff --git a/src/sugar/activity/__init__py b/src/sugar/activity/__init__py deleted file mode 100644 index e69de29..0000000 --- a/src/sugar/activity/__init__py +++ /dev/null diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py index c195572..eda7d9a 100644 --- a/src/sugar/activity/activityfactory.py +++ b/src/sugar/activity/activityfactory.py @@ -30,6 +30,7 @@ from sugar.presence import presenceservice from sugar.activity.activityhandle import ActivityHandle from sugar import util from sugar import env +from sugar.datastore import datastore from errno import EEXIST, ENOSPC @@ -42,10 +43,6 @@ _SHELL_SERVICE = "org.laptop.Shell" _SHELL_PATH = "/org/laptop/Shell" _SHELL_IFACE = "org.laptop.Shell" -_DS_SERVICE = "org.laptop.sugar.DataStore" -_DS_INTERFACE = "org.laptop.sugar.DataStore" -_DS_PATH = "/org/laptop/sugar/DataStore" - _ACTIVITY_FACTORY_INTERFACE = "org.laptop.ActivityFactory" # helper method to close all filedescriptors @@ -211,13 +208,9 @@ class ActivityCreationHandler(gobject.GObject): self._shell = dbus.Interface(bus_object, _SHELL_IFACE) if handle.activity_id is not None and handle.object_id is None: - datastore = dbus.Interface( - bus.get_object(_DS_SERVICE, _DS_PATH), _DS_INTERFACE) datastore.find({'activity_id': self._handle.activity_id}, - [], reply_handler=self._find_object_reply_handler, - error_handler=self._find_object_error_handler, - byte_arrays=True) + error_handler=self._find_object_error_handler) else: self._launch_activity() diff --git a/src/sugar/datastore/Makefile.am b/src/sugar/datastore/Makefile.am index a5f16b7..81d760c 100644 --- a/src/sugar/datastore/Makefile.am +++ b/src/sugar/datastore/Makefile.am @@ -1,5 +1,4 @@ sugardir = $(pythondir)/sugar/datastore sugar_PYTHON = \ __init__.py \ - dbus_helpers.py \ datastore.py diff --git a/src/sugar/datastore/datastore.py b/src/sugar/datastore/datastore.py index 8d23721..b83b2e2 100644 --- a/src/sugar/datastore/datastore.py +++ b/src/sugar/datastore/datastore.py @@ -1,4 +1,5 @@ # Copyright (C) 2007, One Laptop Per Child +# Copyright (C) 2010, Simon Schampijer # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -16,7 +17,7 @@ # Boston, MA 02111-1307, USA. """ -STABLE. +STABLE """ import logging @@ -27,75 +28,144 @@ import tempfile import gobject import gconf import gio +import dbus +import dbus.glib from sugar import env -from sugar.datastore import dbus_helpers from sugar import mime +from sugar import dispatch + +DS_DBUS_SERVICE = "org.laptop.sugar.DataStore" +DS_DBUS_INTERFACE = "org.laptop.sugar.DataStore" +DS_DBUS_PATH = "/org/laptop/sugar/DataStore" + +_data_store = None + + +def _get_data_store(): + global _data_store + + if not _data_store: + _bus = dbus.SessionBus() + _data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE, + DS_DBUS_PATH), + DS_DBUS_INTERFACE) + _data_store.connect_to_signal('Created', __datastore_created_cb) + _data_store.connect_to_signal('Deleted', __datastore_deleted_cb) + _data_store.connect_to_signal('Updated', __datastore_updated_cb) + + return _data_store + + +def __datastore_created_cb(object_id): + metadata = _get_data_store().get_properties(object_id, byte_arrays=True) + updated.send(None, object_id=object_id, metadata=metadata) + + +def __datastore_updated_cb(object_id): + metadata = _get_data_store().get_properties(object_id, byte_arrays=True) + updated.send(None, object_id=object_id, metadata=metadata) + + +def __datastore_deleted_cb(object_id): + deleted.send(None, object_id=object_id) + +created = dispatch.Signal() +deleted = dispatch.Signal() +updated = dispatch.Signal() + +_get_data_store() class DSMetadata(gobject.GObject): + """A representation of the metadata associated with a DS entry.""" __gsignals__ = { 'updated': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ([])), } - def __init__(self, props=None): + def __init__(self, properties=None): gobject.GObject.__init__(self) - if not props: - self._props = {} + if not properties: + self._properties = {} else: - self._props = props + self._properties = properties default_keys = ['activity', 'activity_id', 'mime_type', 'title_set_by_user'] for key in default_keys: - if not self._props.has_key(key): - self._props[key] = '' + if key not in self._properties: + self._properties[key] = '' def __getitem__(self, key): - return self._props[key] + return self._properties[key] def __setitem__(self, key, value): - if not self._props.has_key(key) or self._props[key] != value: - self._props[key] = value + if key not in self._properties or self._properties[key] != value: + self._properties[key] = value self.emit('updated') def __delitem__(self, key): - del self._props[key] + del self._properties[key] def __contains__(self, key): - return self._props.__contains__(key) + return self._properties.__contains__(key) def has_key(self, key): - return self._props.has_key(key) + logging.warning(".has_key() is deprecated, use 'in'") + return key in self._properties def keys(self): - return self._props.keys() + return self._properties.keys() def get_dictionary(self): - return self._props + return self._properties def copy(self): - return DSMetadata(self._props.copy()) + return DSMetadata(self._properties.copy()) def get(self, key, default=None): - if self._props.has_key(key): - return self._props[key] + if key in self._properties: + return self._properties[key] else: return default + def update(self, properties): + """Update all of the metadata""" + for (key, value) in properties.items(): + self[key] = value + class DSObject(object): + """A representation of a DS entry.""" def __init__(self, object_id, metadata=None, file_path=None): - self.object_id = object_id + self._object_id = object_id self._metadata = metadata self._file_path = file_path self._destroyed = False self._owns_file = False + def get_object_id(self): + return self._object_id + + def set_object_id(self, object_id): + if object_id is not None: + _get_data_store().connect_to_signal('Updated', + self.__object_updated_cb, + arg0=object_id) + self._object_id = object_id + + object_id = property(get_object_id, set_object_id) + + def __object_updated_cb(self, object_id): + properties = _get_data_store().get_properties(self.object_id, + byte_arrays=True) + self._metadata.update(properties) + def get_metadata(self): if self._metadata is None and not self.object_id is None: - metadata = DSMetadata(dbus_helpers.get_properties(self.object_id)) + properties = _get_data_store().get_properties(self.object_id) + metadata = DSMetadata(properties) self._metadata = metadata return self._metadata @@ -107,7 +177,7 @@ class DSObject(object): def get_file_path(self, fetch=True): if fetch and self._file_path is None and not self.object_id is None: - self.set_file_path(dbus_helpers.get_filename(self.object_id)) + self.set_file_path(_get_data_store().get_filename(self.object_id)) self._owns_file = True return self._file_path @@ -141,7 +211,12 @@ class DSObject(object): def copy(self): return DSObject(None, self._metadata.copy(), self._file_path) + class RawObject(object): + """A representation for objects not in the DS but + in the file system. + + """ def __init__(self, file_path): stat = os.stat(file_path) @@ -198,12 +273,20 @@ class RawObject(object): def get(object_id): + """Get the properties of the object with the ID given. + + Keyword arguments: + object_id -- unique identifier of the object + + Return: a DSObject + + """ logging.debug('datastore.get') if object_id.startswith('/'): return RawObject(object_id) - metadata = dbus_helpers.get_properties(object_id) + metadata = _get_data_store().get_properties(object_id, byte_arrays=True) ds_object = DSObject(object_id, DSMetadata(metadata), None) # TODO: register the object for updates @@ -211,14 +294,59 @@ def get(object_id): def create(): + """Create a new DSObject. + + Return: a DSObject + + """ metadata = DSMetadata() metadata['mtime'] = datetime.now().isoformat() metadata['timestamp'] = int(time.time()) return DSObject(object_id=None, metadata=metadata, file_path=None) +def _update_ds_entry(uid, properties, filename, transfer_ownership=False, + reply_handler=None, error_handler=None, timeout=-1): + debug_properties = properties.copy() + if "preview" in debug_properties: + debug_properties["preview"] = "<omitted>" + logging.debug('dbus_helpers.update: %s, %s, %s, %s', uid, filename, + debug_properties, transfer_ownership) + if reply_handler and error_handler: + _get_data_store().update(uid, dbus.Dictionary(properties), filename, + transfer_ownership, + reply_handler=reply_handler, + error_handler=error_handler, + timeout=timeout) + else: + _get_data_store().update(uid, dbus.Dictionary(properties), + filename, transfer_ownership) + + +def _create_ds_entry(properties, filename, transfer_ownership=False): + object_id = _get_data_store().create(dbus.Dictionary(properties), filename, + transfer_ownership) + return object_id + + def write(ds_object, update_mtime=True, transfer_ownership=False, reply_handler=None, error_handler=None, timeout=-1): + """Write the DSObject given to the datastore. Creates a new entry if + the entry does not exist yet. + + Keyword arguments: + update_mtime -- boolean if the mtime of the entry should be regenerated + (default True) + transfer_ownership -- set it to true if the ownership of the entry should + be passed - who is responsible to delete the file + when done with it (default False) + reply_handler -- will be called with the method's return values as + arguments (default None) + error_handler -- will be called with an instance of a DBusException + representing a remote exception (default None) + timeout -- dbus timeout for the caller to wait (default -1) + + """ logging.debug('datastore.write') properties = ds_object.metadata.get_dictionary().copy() @@ -234,33 +362,71 @@ def write(ds_object, update_mtime=True, transfer_ownership=False, # FIXME: this func will be sync for creates regardless of the handlers # supplied. This is very bad API, need to decide what to do here. if ds_object.object_id: - dbus_helpers.update(ds_object.object_id, - properties, - file_path, - transfer_ownership, - reply_handler=reply_handler, - error_handler=error_handler, - timeout=timeout) + _update_ds_entry(ds_object.object_id, + properties, + file_path, + transfer_ownership, + reply_handler=reply_handler, + error_handler=error_handler, + timeout=timeout) else: if reply_handler or error_handler: logging.warning('datastore.write() cannot currently be called' \ 'async for creates, see ticket 3071') - ds_object.object_id = dbus_helpers.create(properties, - file_path, - transfer_ownership) + ds_object.object_id = _create_ds_entry(properties, file_path, + transfer_ownership) ds_object.metadata['uid'] = ds_object.object_id # TODO: register the object for updates logging.debug('Written object %s to the datastore.', ds_object.object_id) def delete(object_id): + """Delete the datastore entry with the given uid. + + Keyword arguments: + object_id -- uid of the datastore entry + + """ logging.debug('datastore.delete') - dbus_helpers.delete(object_id) + _get_data_store().delete(object_id) def find(query, sorting=None, limit=None, offset=None, properties=None, reply_handler=None, error_handler=None): - + """Find DS entries that match the query provided. + + Keyword arguments: + query -- a dictionary containing metadata key value pairs + for a fulltext search use the key 'query' e.g. {'query': 'blue*'} + other possible well-known properties are: + 'activity': 'my.organization.MyActivity' + 'activity_id': '6f7f3acacca87886332f50bdd522d805f0abbf1f' + 'title': 'My new project' + 'title_set_by_user': '0' + 'keep': '0' + 'ctime': '1972-05-12T18:41:08' + 'mtime': '2007-06-16T03:42:33' + 'timestamp': 1192715145 + 'preview': ByteArray(png file data, 300x225 px) + 'icon-color': '#ff0000,#ffff00' + 'mime_type': 'application/x-my-activity' + 'share-scope': # if shared + 'buddies': '{}' + 'description': 'some longer text' + 'tags': 'one two' + sorting -- key to order results by e.g. 'timestamp' (default None) + limit -- return only limit results (default None) + offset -- return only results starting at offset (default None) + properties -- you can specify here a list of metadata you want to be + present in the result e.g. ['title, 'keep'] (default None) + reply_handler -- will be called with the method's return values as + arguments (default None) + error_handler -- will be called with an instance of a DBusException + representing a remote exception (default None) + + Return: DSObjects matching the query, number of matches + + """ query = query.copy() if properties is None: @@ -273,57 +439,103 @@ def find(query, sorting=None, limit=None, offset=None, properties=None, if offset: query['offset'] = offset - props_list, total_count = dbus_helpers.find(query, properties, - reply_handler, error_handler) + if reply_handler and error_handler: + _get_data_store().find(query, properties, + reply_handler=reply_handler, + error_handler=error_handler, + byte_arrays=True) + return + else: + entries, total_count = _get_data_store().find(query, properties, + byte_arrays=True) + ds_objects = [] + for entry in entries: + object_id = entry['uid'] + del entry['uid'] - objects = [] - for props in props_list: - object_id = props['uid'] - del props['uid'] + ds_object = DSObject(object_id, DSMetadata(entry), None) + ds_objects.append(ds_object) - ds_object = DSObject(object_id, DSMetadata(props), None) - objects.append(ds_object) + return ds_objects, total_count - return objects, total_count +def copy(ds_object, mount_point): + """Copy a datastore entry -def copy(jobject, mount_point): + Keyword arguments: + ds_object -- DSObject to copy + mount_point -- mount point of the new datastore entry - new_jobject = jobject.copy() - new_jobject.metadata['mountpoint'] = mount_point + """ + new_ds_object = ds_object.copy() + new_ds_object.metadata['mountpoint'] = mount_point - if jobject.metadata.has_key('title'): - filename = jobject.metadata['title'] + if 'title' in ds_object.metadata: + filename = ds_object.metadata['title'] - if jobject.metadata.has_key('mime_type'): - mime_type = jobject.metadata['mime_type'] + if 'mime_type' in ds_object.metadata: + mime_type = ds_object.metadata['mime_type'] extension = mime.get_primary_extension(mime_type) if extension: filename += '.' + extension - new_jobject.metadata['suggested_filename'] = filename + new_ds_object.metadata['suggested_filename'] = filename # this will cause the file be retrieved from the DS - new_jobject.file_path = jobject.file_path + new_ds_object.file_path = ds_object.file_path - write(new_jobject) + write(new_ds_object) def mount(uri, options, timeout=-1): - return dbus_helpers.mount(uri, options, timeout=timeout) + """Deprecated. API private to the shell. Mount a device. + + Keyword arguments: + uri -- identifier of the device + options -- mount options + timeout -- dbus timeout for the caller to wait (default -1) + + Return: empty string + + """ + return _get_data_store().mount(uri, options, timeout=timeout) def unmount(mount_point_id): - dbus_helpers.unmount(mount_point_id) + """Deprecated. API private to the shell. + + Keyword arguments: + mount_point_id -- id of the mount point + + Note: API private to the shell. + + """ + _get_data_store().unmount(mount_point_id) def mounts(): - return dbus_helpers.mounts() + """Deprecated. Returns the mount point of the datastore. We get mount + points through gio now. API private to the shell. + + Return: datastore mount point + + """ + return _get_data_store().mounts() def complete_indexing(): - return dbus_helpers.complete_indexing() + """Deprecated. API private to the shell.""" + logging.warning('The method complete_indexing has been deprecated.') def get_unique_values(key): - return dbus_helpers.get_unique_values(key) + """Retrieve an array of unique values for a field. + + Keyword arguments: + key -- only the property activity is currently supported + + Return: list of activities + + """ + return _get_data_store().get_uniquevaluesfor( + key, dbus.Dictionary({}, signature='ss')) diff --git a/src/sugar/datastore/dbus_helpers.py b/src/sugar/datastore/dbus_helpers.py deleted file mode 100644 index 008b7a0..0000000 --- a/src/sugar/datastore/dbus_helpers.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2006-2007 Red Hat, Inc. -# Copyright (C) 2007, One Laptop Per Child -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the -# Free Software Foundation, Inc., 59 Temple Place - Suite 330, -# Boston, MA 02111-1307, USA. - -""" -UNSTABLE. Should be internal to the datastore module. -""" - -import logging - -import dbus -import dbus.glib - -DS_DBUS_SERVICE = "org.laptop.sugar.DataStore" -DS_DBUS_INTERFACE = "org.laptop.sugar.DataStore" -DS_DBUS_PATH = "/org/laptop/sugar/DataStore" - -_data_store = None - - -def _get_data_store(): - global _data_store - - if not _data_store: - _bus = dbus.SessionBus() - _data_store = dbus.Interface(_bus.get_object(DS_DBUS_SERVICE, - DS_DBUS_PATH), - DS_DBUS_INTERFACE) - return _data_store - - -def create(properties, filename, transfer_ownership=False): - object_id = _get_data_store().create(dbus.Dictionary(properties), filename, - transfer_ownership) - logging.debug('dbus_helpers.create: ' + object_id) - return object_id - - -def update(uid, properties, filename, transfer_ownership=False, - reply_handler=None, error_handler=None, timeout=-1): - debug_props = properties.copy() - if debug_props.has_key("preview"): - debug_props["preview"] = "<omitted>" - logging.debug('dbus_helpers.update: %s, %s, %s, %s', uid, filename, - debug_props, transfer_ownership) - if reply_handler and error_handler: - _get_data_store().update(uid, dbus.Dictionary(properties), filename, - transfer_ownership, - reply_handler=reply_handler, - error_handler=error_handler, - timeout=timeout) - else: - _get_data_store().update(uid, dbus.Dictionary(properties), - filename, transfer_ownership) - - -def delete(uid): - logging.debug('dbus_helpers.delete: %r', uid) - _get_data_store().delete(uid) - - -def get_properties(uid): - logging.debug('dbus_helpers.get_properties: %s', uid) - return _get_data_store().get_properties(uid, byte_arrays=True) - - -def get_filename(uid): - filename = _get_data_store().get_filename(uid) - logging.debug('dbus_helpers.get_filename: %s, %s', uid, filename) - return filename - - -def find(query, properties, reply_handler, error_handler): - logging.debug('dbus_helpers.find: %r %r', query, properties) - if reply_handler and error_handler: - return _get_data_store().find(query, properties, - reply_handler=reply_handler, error_handler=error_handler, - byte_arrays=True) - else: - return _get_data_store().find(query, properties, byte_arrays=True) - - -def mount(uri, options, timeout=-1): - return _get_data_store().mount(uri, options, timeout=timeout) - - -def unmount(mount_point_id): - _get_data_store().unmount(mount_point_id) - - -def mounts(): - return _get_data_store().mounts() - - -def get_unique_values(key): - return _get_data_store().get_uniquevaluesfor( - key, dbus.Dictionary({}, signature='ss')) - - -def complete_indexing(): - return _get_data_store().complete_indexing() diff --git a/src/sugar/graphics/icon.py b/src/sugar/graphics/icon.py index 94c66aa..4a94479 100644 --- a/src/sugar/graphics/icon.py +++ b/src/sugar/graphics/icon.py @@ -1146,3 +1146,31 @@ def get_icon_file_name(icon_name): filename = info.get_filename() del info return filename + + +def get_surface(**kwargs): + """Get cached cairo surface. + + Keyword arguments: + icon_name -- name of icon to load, default None + file_name -- path to image file, default None + fill_color -- for svg images, change default fill color + default None + stroke_color -- for svg images, change default stroke color + default None + background_color -- draw background or surface will be transparent + default None + badge_name -- name of icon which will be drawn on top of + original image, default None + width -- change image width, default None + height -- change image height, default None + cache -- if image is svg, keep svg file content for later + scale -- scale image, default 1.0 + + Return: cairo surface or None if image was not found + + """ + icon = _IconBuffer() + for key, value in kwargs.items(): + icon.__setattr__(key, value) + return icon.get_surface() diff --git a/src/sugar/graphics/style.py b/src/sugar/graphics/style.py index 929b78e..2828b7f 100644 --- a/src/sugar/graphics/style.py +++ b/src/sugar/graphics/style.py @@ -141,6 +141,7 @@ COLOR_BUTTON_GREY = Color('#808080') COLOR_INACTIVE_FILL = Color('#9D9FA1') COLOR_INACTIVE_STROKE = Color('#757575') COLOR_TEXT_FIELD_GREY = Color('#E5E5E5') +COLOR_HIGHLIGHT = Color('#E7E7E7') PALETTE_CURSOR_DISTANCE = zoom(10) |