From 6e8f7e1a2fa41b5857a806aae4031b536f274f06 Mon Sep 17 00:00:00 2001 From: Walter Bender Date: Mon, 09 Dec 2013 18:44:26 +0000 Subject: resync with v194 --- diff --git a/NEWS b/NEWS index 5556108..b02eb3b 100644 --- a/NEWS +++ b/NEWS @@ -1,15 +1,21 @@ 194 ENHANCEMENTS: -* Save/restore palette settings -* Add confirmation when emptying trash in GNOME version +* Save/restore palette settings in GConf +* Add confirmation when emptying trash in GNONE version (Alan Aguiar) +* Add load/save plugin dialog to GNOME version (Daniel Francis) +* Add busy cursor when projects are being prepared to run +* Reworked Duplicate Blocks warning graphic to reflect current block shapes +* New translations BUG FIX: -* Fix shade block dock settings (Alan Aguiar) -* Fix bug in empty trash (Alan Aguiar) -* Set active turtle after clean in exported Python code -* Execute until body once before entering loop in exported Python code -* Fix problem with WeDo plugin (Alan Aguiar) +* Fixed shade block dock settings (Alan Aguiar) +* Fixed bug in empty trash (Alan Aguiar) +* Set active turtle after 'clean' in exported Python code +* Execute 'until' body once before entering loop in exported Python code +* Fixed problem with running_blocks flag not being cleared (cause of spurious + "hit stop button" messages. +* Fixed problem with errant text entry widget on run. 193 diff --git a/TurtleArt/sprites.py b/TurtleArt/sprites.py index 7483c12..3f5d7df 100644 --- a/TurtleArt/sprites.py +++ b/TurtleArt/sprites.py @@ -106,7 +106,7 @@ class Sprites: def length_of_list(self): ''' How many sprites are there? ''' - return(len(self.list)) + return len(self.list) def append_to_list(self, spr): ''' Append a new sprite to the end of the list. ''' @@ -122,9 +122,7 @@ class Sprites: self.list.insert(i, spr) def find_in_list(self, spr): - if spr in self.list: - return True - return False + return (spr in self.list) def remove_from_list(self, spr): ''' Remove a sprite from the list. ''' @@ -258,7 +256,8 @@ class Sprite: if layer is not None: self.layer = layer for i in range(self._sprites.length_of_list()): - if self.layer < self._sprites.get_sprite(i).layer: + spr = self._sprites.get_sprite(i) + if spr is not None and self.layer < spr.layer: self._sprites.insert_in_list(self, i) self.inval() return diff --git a/TurtleArt/taconstants.py b/TurtleArt/taconstants.py index 4cedb34..78cb9e1 100644 --- a/TurtleArt/taconstants.py +++ b/TurtleArt/taconstants.py @@ -287,7 +287,7 @@ OVERLAY_SHAPES = ['Cartesian', 'Cartesian_labeled', 'polar', 'metric'] STATUS_SHAPES = ['status', 'info', 'nostack', 'dupstack', 'noinput', 'emptyheap', 'emptybox', 'nomedia', 'nocode', 'overflowerror', 'negroot', 'syntaxerror', 'nofile', 'nojournal', 'zerodivide', - 'notanumber', 'incompatible', 'help', 'print'] + 'notanumber', 'incompatible', 'help', 'print', 'noconnection'] # Emulate Sugar toolbar when running from outside of Sugar TOOLBAR_SHAPES = ['hideshowoff', 'eraseron', 'run-fastoff', diff --git a/TurtleArt/talogo.py b/TurtleArt/talogo.py index ba76085..67aa32c 100644 --- a/TurtleArt/talogo.py +++ b/TurtleArt/talogo.py @@ -29,6 +29,8 @@ from operator import isNumberType import os from os.path import exists as os_path_exists from UserDict import UserDict +import urllib2 +import tempfile try: from sugar.graphics import style @@ -1060,6 +1062,36 @@ class LogoCode: gobject.idle_add(self.tw.send_event, event) os.remove(tmp_file) + def get_from_url(self, url): + """ Get contents of URL as text or tempfile to image """ + if "://" not in url: # no protocol + url = "http://" + url # assume HTTP + try: + req = urllib2.urlopen(url) + except urllib2.HTTPError, e: + debug_output("Couldn't open %s: %s" % (url, e), + self.tw.running_sugar) + raise logoerror(url + ' [%d]' % (e.code)) + except urllib2.URLError, e: + if hasattr(e, 'code'): + debug_output("Couldn't open %s: %s" % (url, e), + self.tw.running_sugar) + raise logoerror(url + ' [%d]' % (e.code)) + else: # elif hasattr(e, 'reason'): + debug_output("Couldn't reach server: %s" % (e), + self.tw.running_sugar) + raise logoerror('#noconnection') + + if req.info().getheader("Content-Type")[0:5] == "image": + # it can't be deleted immediately, or else we won't ever access it + tmp = tempfile.NamedTemporaryFile(delete=False) + tmp.write(req.read()) # prepare for writing + tmp.flush() # actually write it + obj = Media('media', value=tmp.name) + return obj + else: + return req.read() + def showlist(self, objects): """ Display list of media objects """ x = (self.tw.turtles.get_active_turtle().get_xy()[0] / diff --git a/TurtleArt/tawindow.py b/TurtleArt/tawindow.py index 5b9a1c6..2aa8f89 100644 --- a/TurtleArt/tawindow.py +++ b/TurtleArt/tawindow.py @@ -1662,9 +1662,20 @@ before making changes to your program')) name = blk.name # You can only have one instance of some blocks if blk.name in ['start', 'hat1', 'hat2']: - if len(self.block_list.get_similar_blocks( - 'block', blk.name)) > 0: + blk_list = self.block_list.get_similar_blocks( + 'block', blk.name) + if len(blk_list) > 0: self.showlabel('dupstack') + if blk.name == 'start': + # Recenter the screen and move the start + # stack to the center of the screen + if self.running_sugar: + self.activity.recenter() + dx = 200 - blk_list[0].spr.get_xy()[0] + dy = 200 - blk_list[0].spr.get_xy()[1] + drag_group = find_group(blk_list[0]) + for dblk in drag_group: + dblk.spr.move_relative((dx, dy)) return True # We need to check to see if there is already a # similarly default named stack @@ -2176,7 +2187,7 @@ before making changes to your program')) for gblk in group: if gblk.name == 'sandwichclampcollapsed': restore_clamp(gblk) - self.resize_parent_clamps(gblk) + self._resize_parent_clamps(gblk) for gblk in group: gblk.rescale(self.block_scale) @@ -3217,6 +3228,13 @@ before making changes to your program')) if len(self.block_list.get_similar_blocks('block', 'forever')) > 0: debug_output('WARNING: Projects with forever blocks \ may not terminate.', False) + else: + self._hide_text_entry() + self.parent.get_window().set_cursor( + gtk.gdk.Cursor(gtk.gdk.WATCH)) + gobject.idle_add(self.__run_stack, blk) + + def __run_stack(self, blk): if self.status_spr is not None: self.status_spr.hide() self._autohide_shape = True @@ -3229,12 +3247,16 @@ before making changes to your program')) self.start_plugins() # Let the plugins know we are running. top = find_top_block(blk) code = self.lc.generate_code(top, self.just_blocks()) + if self.interactive_mode: + self.parent.get_window().set_cursor( + gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) self.lc.run_blocks(code) if self.interactive_mode: gobject.idle_add(self.lc.doevalstep) else: while self.lc.doevalstep(): pass + self.running_blocks = False def _snap_to_dock(self): ''' Snap a block (selected_block) to the dock of another block @@ -3810,11 +3832,8 @@ before making changes to your program')) self._snap_to_dock() self.drag_group = None - def _test_number(self): - ''' Make sure a 'number' block contains a number. ''' + def _hide_text_entry(self): if hasattr(self, '_text_entry'): - bounds = self._text_buffer.get_bounds() - text = self._text_buffer.get_text(bounds[0], bounds[1]) if self._focus_out_id is not None: self._text_entry.disconnect(self._focus_out_id) self._focus_out_id = None @@ -3822,6 +3841,13 @@ before making changes to your program')) self._text_buffer.disconnect(self._insert_text_id) self._insert_text_id = None self._text_entry.hide() + + def _test_number(self): + ''' Make sure a 'number' block contains a number. ''' + if hasattr(self, '_text_entry'): + bounds = self._text_buffer.get_bounds() + text = self._text_buffer.get_text(bounds[0], bounds[1]) + self._hide_text_entry() else: text = self.selected_blk.spr.labels[0] self._number_check(text) @@ -3868,12 +3894,9 @@ before making changes to your program')) def _test_string(self): if hasattr(self, '_text_entry'): - if self._focus_out_id is not None: - self._text_entry.disconnect(self._focus_out_id) - self._focus_out_id = None bounds = self._text_buffer.get_bounds() text = self._text_buffer.get_text(bounds[0], bounds[1]) - self._text_entry.hide() + self._hide_text_entry() else: text = self.selected_blk.spr.labels[0] self.selected_blk.spr.set_label(text.replace('\12', RETURN)) diff --git a/TurtleArtActivity.py b/TurtleArtActivity.py index f15650e..f6b94ca 100644 --- a/TurtleArtActivity.py +++ b/TurtleArtActivity.py @@ -63,6 +63,8 @@ except ImportError: from gettext import gettext as _ +from TurtleArt.taplugin import (load_a_plugin, cancel_plugin_install, + complete_plugin_install) from TurtleArt.tapalette import (palette_names, help_strings, help_palettes, help_windows, default_values) from TurtleArt.taconstants import (BLOCK_SCALE, XO1, XO15, XO175, XO4, @@ -95,6 +97,8 @@ class TurtleArtActivity(activity.Activity): self.tw = None self.init_complete = False + self.bundle_path = activity.get_bundle_path() + self.error_list = [] self.palette_buttons = [] @@ -327,9 +331,9 @@ class TurtleArtActivity(activity.Activity): def do_load_python_cb(self, button): ''' Load Python code from the Journal. ''' - self.load_python.set_icon('python-saveon') + self.load_python.set_icon('pippy-openon') self.tw.load_python_code_from_file(fname=None, add_new_block=True) - gobject.timeout_add(250, self.load_python.set_icon, 'python-saveoff') + gobject.timeout_add(250, self.load_python.set_icon, 'pippy-openoff') def do_save_as_image_cb(self, button): ''' Save the canvas to the Journal. ''' @@ -886,10 +890,7 @@ class TurtleArtActivity(activity.Activity): help_palettes['activity-toolbar'].show() add_paragraph(help_box, _('Share selected blocks'), icon='shareon') - if gtk.gdk.screen_width() < 1024: - add_paragraph(help_box, _('Save/Load'), icon='save-load') - else: - add_section(help_box, _('Save/Load'), icon='turtleoff') + add_paragraph(help_box, _('Save/Load'), icon='save-load') add_paragraph(help_box, _('Save as image'), icon='image-saveoff') add_paragraph(help_box, _('Save as Logo'), icon='logo-saveoff') add_paragraph(help_box, _('Save as Python'), icon='python-saveoff') @@ -899,7 +900,7 @@ class TurtleArtActivity(activity.Activity): if activity.get_bundle_path()[0:len(home)] == home: add_paragraph(help_box, _('Load plugin'), icon='pluginoff') add_paragraph(help_box, _('Load Python block'), - icon='python-saveoff') + icon='pippy-openoff') help_box = gtk.VBox() help_box.set_homogeneous(False) @@ -1067,10 +1068,10 @@ class TurtleArtActivity(activity.Activity): self._share_cb, toolbar) if self.has_toolbarbox: self._add_separator(toolbar, expand=False, visible=True) - save_load_button = self._add_button( - 'save-load', _('Save/Load'), self._save_load_palette_cb, + save_button = self._add_button( + 'save', _('Save'), self._save_load_palette_cb, toolbar) - self._palette = save_load_button.get_palette() + self._save_palette = save_button.get_palette() button_box = gtk.VBox() self.save_as_image, label = self._add_button_and_label( 'image-saveoff', _('Save as image'), self.do_save_as_image_cb, @@ -1086,6 +1087,14 @@ class TurtleArtActivity(activity.Activity): 'filesaveoff', _('Save snapshot'), self.do_keep_cb, None, button_box) + load_button = self._add_button( + 'load', _('Load'), self._save_load_palette_cb, + toolbar) + button_box.show_all() + self._save_palette.set_content(button_box) + + self._load_palette = load_button.get_palette() + button_box = gtk.VBox() # When screen is in portrait mode, the buttons don't fit # on the main toolbar, so put them here. self.samples_button2, self.samples_label2 = \ @@ -1107,10 +1116,10 @@ class TurtleArtActivity(activity.Activity): 'pluginoff', _('Load plugin'), self.do_load_ta_plugin_cb, None, button_box) self.load_python, label = self._add_button_and_label( - 'python-saveoff', _('Load Python block'), + 'pippy-openoff', _('Load Python block'), self.do_load_python_cb, None, button_box) button_box.show_all() - self._palette.set_content(button_box) + self._load_palette.set_content(button_box) else: self.save_as_image = self._add_button( 'image-saveoff', _('Save as image'), self.do_save_as_image_cb, @@ -1125,7 +1134,7 @@ class TurtleArtActivity(activity.Activity): self.keep_button = self._add_button( 'filesaveoff', _('Save snapshot'), self.do_keep_cb, toolbar) self.load_ta_project = self._add_button( - 'load-from-journal', _('Load project'), + 'load-from-journal', _('Add project'), self.do_load_ta_project_cb, toolbar) # Only enable plugin loading if installed in $HOME if activity.get_bundle_path()[0:len(home)] == home: @@ -1133,17 +1142,16 @@ class TurtleArtActivity(activity.Activity): 'pluginoff', _('Load plugin'), self.do_load_ta_plugin_cb, toolbar) self.load_python = self._add_button( - 'python-saveoff', _('Load Python block'), + 'pippy-openoff', _('Load Python block'), self.do_load_python_cb, toolbar) def _save_load_palette_cb(self, button): - if self._palette: - if not self._palette.is_up(): - self._palette.popup(immediate=True, - state=self._palette.SECONDARY) + palette = button.get_palette() + if palette: + if not palette.is_up(): + palette.popup(immediate=True, state=palette.SECONDARY) else: - self._palette.popdown(immediate=True) - return + palette.popdown(immediate=True) def _make_palette_buttons(self, toolbar, palette_button=False): ''' Creates the palette and block buttons for both toolbar types''' @@ -1337,109 +1345,6 @@ class TurtleArtActivity(activity.Activity): self.metadata['error_list'] = data_to_string(errors) _logger.debug('Wrote to file: %s' % (file_path)) - def _load_a_plugin(self, tmp_dir): - ''' Load a plugin from the Journal and initialize it ''' - plugin_path = os.path.join(tmp_dir, 'plugin.info') - _logger.debug(plugin_path) - file_info = ConfigParser.ConfigParser() - if len(file_info.read(plugin_path)) == 0: - _logger.debug('Required file plugin.info could not be found.') - self.tw.showlabel('status', - label=_('Plugin could not be installed.')) - elif not file_info.has_option('Plugin', 'name'): - _logger.debug('Required open name not found in \ -Plugin section of plugin.info file.') - self.tw.showlabel( - 'status', label=_('Plugin could not be installed.')) - else: - plugin_name = file_info.get('Plugin', 'name') - _logger.debug('Plugin name: %s' % (plugin_name)) - tmp_path = os.path.join(tmp_dir, plugin_name) - plugin_path = os.path.join(activity.get_bundle_path(), 'plugins') - if os.path.exists(os.path.join(plugin_path, plugin_name)): - self._reload_plugin_alert(tmp_dir, tmp_path, plugin_path, - plugin_name, file_info) - else: - self._complete_plugin_install(tmp_dir, tmp_path, plugin_path, - plugin_name, file_info) - - def _complete_plugin_install(self, tmp_dir, tmp_path, plugin_path, - plugin_name, file_info): - ''' We complete the installation directly or from ConfirmationAlert ''' - status = subprocess.call(['cp', '-r', tmp_path, plugin_path + '/']) - if status == 0: - # Save the plugin.info file in the plugin directory - subprocess.call(['cp', os.path.join(tmp_dir, 'plugin.info'), - os.path.join(plugin_path, plugin_name) + '/']) - _logger.debug('Plugin installed successfully.') - if self.has_toolbarbox: - palette_name_list = [] - if file_info.has_option('Plugin', 'palette'): - palette_name_list = file_info.get( - 'Plugin', 'palette').split(',') - create_palette = [] - for palette_name in palette_name_list: - if not palette_name.strip() in palette_names: - create_palette.append(True) - else: - create_palette.append(False) - _logger.debug('Initializing plugin...') - self.tw.init_plugin(plugin_name) - self.tw.turtleart_plugins[-1].setup() - self.tw.load_media_shapes() - for i, palette_name in enumerate(palette_name_list): - if create_palette[i]: - _logger.debug('Creating plugin palette %s (%d)' % - (palette_name.strip(), i)) - j = len(self.palette_buttons) - self.palette_buttons.append( - self._radio_button_factory( - palette_name.strip() + 'off', - self._palette_toolbar, - self.do_palette_buttons_cb, - j - 1, - help_strings[palette_name.strip()], - self.palette_buttons[0])) - self._overflow_buttons.append( - self._add_button( - palette_name.strip() + 'off', - None, - self.do_palette_buttons_cb, - None, - arg=j - 1)) - self._overflow_box.pack_start( - self._overflow_buttons[j - 1]) - self.tw.palettes.insert(j - 1, []) - self.tw.palette_sprs.insert(j - 1, [None, None]) - else: - _logger.debug('Palette already exists... \ -skipping insert') - # We need to change the index associated with the - # Trash Palette Button. - j = len(palette_names) - pidx = palette_names.index(palette_name.strip()) - self.palette_buttons[pidx].connect( - 'clicked', self.do_palette_buttons_cb, j - 1) - self._overflow_buttons[pidx].connect( - 'clicked', self.do_palette_buttons_cb, j - 1) - _logger.debug('reinitializing palette toolbar') - self._setup_palette_toolbar() - else: - self.tw.showlabel('status', - label=_('Please restart Turtle Art \ -in order to use the plugin.')) - else: - self.tw.showlabel( - 'status', label=_('Plugin could not be installed.')) - status = subprocess.call(['rm', '-r', tmp_path]) - if status != 0: - _logger.debug('Problems cleaning up tmp_path.') - shutil.rmtree(tmp_dir) - - def _cancel_plugin_install(self, tmp_dir): - ''' If we cancel, just cleanup ''' - shutil.rmtree(tmp_dir) - def _reload_plugin_alert(self, tmp_dir, tmp_path, plugin_path, plugin_name, file_info): ''' We warn the user if the plugin was previously loaded ''' @@ -1453,12 +1358,12 @@ in order to use the plugin.')) if response_id is gtk.RESPONSE_OK: _logger.debug('continue to install') self.remove_alert(alert) - self._complete_plugin_install(tmp_dir, tmp_path, plugin_path, - plugin_name, file_info) + complete_plugin_install(self, tmp_dir, tmp_path, plugin_path, + plugin_name, file_info) elif response_id is gtk.RESPONSE_CANCEL: _logger.debug('cancel install') self.remove_alert(alert) - self._cancel_plugin_install(tmp_dir) + cancel_plugin_install(self, tmp_dir) alert.connect('response', _reload_plugin_alert_response_cb, self, tmp_dir, tmp_path, plugin_path, plugin_name, file_info) @@ -1501,7 +1406,7 @@ in order to use the plugin.')) gobject.idle_add(self._project_loader, turtle_code) else: _logger.debug('load a plugin from %s' % (tmp_dir)) - self._load_a_plugin(tmp_dir) + load_a_plugin(self, tmp_dir) self.restore_cursor() except: _logger.debug('Could not extract files from %s.' % diff --git a/images/dupstack.svg b/images/dupstack.svg index 6a0f3fd..f3eacd9 100644 --- a/images/dupstack.svg +++ b/images/dupstack.svg @@ -47,21 +47,6 @@ style="font-size:12px">X - - - x - @@ -91,8 +76,54 @@ id="tspan2488" style="font-size:24px">! - + + + + + + + + x + + 1 + 2 diff --git a/plugins/turtle_blocks_extras/turtle_blocks_extras.py b/plugins/turtle_blocks_extras/turtle_blocks_extras.py index df0d1ff..3192021 100644 --- a/plugins/turtle_blocks_extras/turtle_blocks_extras.py +++ b/plugins/turtle_blocks_extras/turtle_blocks_extras.py @@ -862,6 +862,19 @@ module found in the Journal')) special_name=_('top'), help_string=_('top of a collapsed stack')) + palette.add_block('getfromurl', + style='number-style-1arg', + #TRANS: URL is universal resource locator + label=_('URL'), + default=\ +'http://wiki.sugarlabs.org/images/2/2c/Logo_alt_3.svg', + prim_name='getfromurl', + help_string=\ +_('gets a text string or an image from a URL')) + self.tw.lc.def_prim('getfromurl', 1, + Primitive(self.tw.lc.get_from_url, + arg_descs=[ArgSlot(TYPE_STRING)])) + def _portfolio_palette(self): palette = make_palette('portfolio', diff --git a/turtleblocks.py b/turtleblocks.py index 7e3aba4..051d447 100755 --- a/turtleblocks.py +++ b/turtleblocks.py @@ -36,6 +36,9 @@ import cStringIO import errno import ConfigParser import gconf +import tarfile +import tempfile +import subprocess try: # Try to use XDG Base Directory standard for config files. @@ -53,12 +56,15 @@ from gettext import gettext as _ from TurtleArt.taconstants import (OVERLAY_LAYER, DEFAULT_TURTLE_COLORS, TAB_LAYER, SUFFIX) -from TurtleArt.tautils import (data_from_string, get_save_name) +from TurtleArt.tautils import (data_from_string, get_load_name, + get_path, get_save_name) from TurtleArt.tapalette import default_values from TurtleArt.tawindow import TurtleArtWindow from TurtleArt.taexportlogo import save_logo from TurtleArt.taexportpython import save_python from TurtleArt.taprimitive import PyExportError +from TurtleArt.taplugin import (load_a_plugin, cancel_plugin_install, + complete_plugin_install) from util.menubuilder import MenuBuilder @@ -89,6 +95,7 @@ class TurtleMain(): self.summary = file_activity_info.get('Activity', 'summary') self.website = file_activity_info.get('Activity', 'website') self.icon_name = file_activity_info.get('Activity', 'icon') + self.bundle_path = self._abspath path = os.path.abspath('./locale/') gettext.bindtextdomain(bundle_id, path) gettext.textdomain(bundle_id) @@ -107,6 +114,7 @@ class TurtleMain(): self._gnome_plugins = [] self._selected_sample = None self._sample_window = None + self.has_toolbarbox = False if self._output_png: # Outputing to file, so no need for a canvas @@ -347,6 +355,18 @@ return %s(self)" % (p, P, P) self.vbox.set_size_request(rect[2], rect[3]) self.menu_height = self.menu_bar.size_request()[1] + def restore_cursor(self): + ''' No longer copying or sharing, so restore standard cursor. ''' + self.tw.copying_blocks = False + self.tw.sharing_blocks = False + self.tw.saving_blocks = False + self.tw.deleting_blocks = False + if hasattr(self, 'get_window'): + if hasattr(self.get_window(), 'get_cursor'): + self.get_window().set_cursor(self._old_cursor) + else: + self.get_window().set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)) + def _setup_gtk(self): ''' Set up a scrolled window in which to run Turtle Blocks. ''' win = gtk.Window(gtk.WINDOW_TOPLEVEL) @@ -403,7 +423,9 @@ return %s(self)" % (p, P, P) MenuBuilder.make_menu_item(menu, _('Show sample projects'), self._create_store) MenuBuilder.make_menu_item(menu, _('Open'), self._do_open_cb) - MenuBuilder.make_menu_item(menu, _('Load project'), self._do_load_cb) + MenuBuilder.make_menu_item(menu, _('Add project'), self._do_load_cb) + MenuBuilder.make_menu_item(menu, _('Load plugin'), + self._do_load_plugin_cb) MenuBuilder.make_menu_item(menu, _('Save'), self._do_save_cb) MenuBuilder.make_menu_item(menu, _('Save as'), self._do_save_as_cb) MenuBuilder.make_menu_item(menu, _('Save as image'), @@ -518,6 +540,27 @@ Would you like to save before quitting?')) dlg.destroy() return resp + def _reload_plugin_alert(self, tmp_dir, tmp_path, plugin_path, plugin_name, + file_info): + print "Already installed" + title = _('Plugin %s already installed') % plugin_name + msg = _('Do you want to reinstall %s?') % plugin_name + dlg = gtk.MessageDialog(parent=None, type=gtk.MESSAGE_INFO, + buttons=gtk.BUTTONS_YES_NO, + message_format=title) + dlg.format_secondary_text(msg) + dlg.set_title(title) + dlg.set_property('skip-taskbar-hint', False) + + resp = dlg.run() + dlg.destroy() + + if resp is gtk.RESPONSE_OK: + complete_plugin_install(tmp_dir, tmp_path, plugin_path, + plugin_name, file_info) + elif resp is gtk.RESPONSE_CANCEL: + cancel_plugin_install(tmp_dir) + def _do_new_cb(self, widget): ''' Callback for new project. ''' self.tw.new_project() @@ -531,6 +574,41 @@ Would you like to save before quitting?')) ''' Callback for load project (add to current project). ''' self.tw.load_file_from_chooser(False) + def _do_load_plugin_cb(self, widget): + self.tw.load_save_folder = self._get_execution_dir() + file_path, loaddir = get_load_name('.tar.gz', self.tw.load_save_folder) + if file_path is None: + return + try: + # Copy to tmp file since some systems had trouble + # with gunzip directly from datastore + datapath = get_path(None, 'instance') + if not os.path.exists(datapath): + os.makedirs(datapath) + tmpfile = os.path.join(datapath, 'tmpfile.tar.gz') + subprocess.call(['cp', file_path, tmpfile]) + status = subprocess.call(['gunzip', tmpfile]) + if status == 0: + tar_fd = tarfile.open(tmpfile[:-3], 'r') + else: + tar_fd = tarfile.open(tmpfile, 'r') + except: + tar_fd = tarfile.open(file_path, 'r') + + tmp_dir = tempfile.mkdtemp() + + try: + tar_fd.extractall(tmp_dir) + load_a_plugin(self, tmp_dir) + self.restore_cursor() + except: + self.restore_cursor() + finally: + tar_fd.close() + # Remove tmpfile.tar + subprocess.call(['rm', + os.path.join(datapath, 'tmpfile.tar')]) + def _do_save_cb(self, widget): ''' Callback for save project. ''' self.tw.save_file(self._ta_file) -- cgit v0.9.1