diff options
Diffstat (limited to 'turtleart.py')
-rwxr-xr-x | turtleart.py | 558 |
1 files changed, 217 insertions, 341 deletions
diff --git a/turtleart.py b/turtleart.py index d3a0f70..996e94a 100755 --- a/turtleart.py +++ b/turtleart.py @@ -32,14 +32,6 @@ import cStringIO import errno try: - import pycurl - import xmlrpclib - _UPLOAD_AVAILABLE = True -except ImportError, e: - print "Import Error: %s. Project upload is disabled." % (e) - _UPLOAD_AVAILABLE = False - -try: # Try to use XDG Base Directory standard for config files import xdg.BaseDirectory CONFIG_HOME = os.path.join(xdg.BaseDirectory.xdg_config_home, 'turtleart') @@ -57,86 +49,128 @@ from TurtleArt.tautils import data_to_string, data_from_string, get_save_name from TurtleArt.tawindow import TurtleArtWindow from TurtleArt.taexporthtml import save_html from TurtleArt.taexportlogo import save_logo +from extra.upload import Uploader + -_HELP_MSG = 'turtleart.py: ' + _('usage is') + """ +class TurtleMain(): + """ Launch Turtle Art from outside of Sugar """ + + _HELP_MSG = 'turtleart.py: ' + _('usage is') + """ \tturtleart.py \tturtleart.py project.ta \tturtleart.py --output_png project.ta \tturtleart.py -o project""" + _INSTALL_PATH = '/usr/share/turtleart' + _ALTERNATE_INSTALL_PATH = '/usr/local/share/turtleart' + _ICON_SUBPATH = 'images/turtle.png' -_MAX_FILE_SIZE = 950000 - -_INSTALL_PATH = '/usr/share/turtleart' -_ALTERNATE_INSTALL_PATH = '/usr/local/share/turtleart' -_ICON_SUBPATH = 'images/turtle.png' -_UPLOAD_SERVER = 'http://turtleartsite.appspot.com' - + def __init__(self): + self._init_vars() + self._parse_command_line() + self._ensure_sugar_paths() -def mkdir_p(path): - '''Create a directory in a fashion similar to `mkdir -p`''' - try: - os.makedirs(path) - except OSError as exc: - if exc.errno == errno.EEXIST: - pass + if self.output_png: + pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, + gtk.gdk.screen_width(), + gtk.gdk.screen_height()) + self.canvas, mask = pixbuf.render_pixmap_and_mask() + self._build_window() + self._draw_and_quit() else: - raise - - -def _make_sub_menu(menu, name): - """ add a new submenu to the toolbar """ - sub_menu = gtk.MenuItem(name) - sub_menu.show() - sub_menu.set_submenu(menu) - return sub_menu - - -def _make_menu_item(menu, tooltip, callback, arg=None): - """ add a new item to the submenu """ - menu_items = gtk.MenuItem(tooltip) - menu.append(menu_items) - if arg is None: - menu_items.connect('activate', callback) - else: - menu_items.connect('activate', callback, arg) - menu_items.show() - - -def makepath(path): - """ Make a path if it doesn't previously exist """ - from os import makedirs - from os.path import normpath, dirname, exists - - dpath = normpath(dirname(path)) - if not exists(dpath): - makedirs(dpath) + self._read_initial_pos() + self._setup_gtk() + self._build_window() + self._uploader.set_tw(self.tw) + self._start_gtk() + + def _mkdir_p(path): + '''Create a directory in a fashion similar to `mkdir -p`''' + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST: + pass + else: + raise + + def _make_sub_menu(self, menu, name): + """ add a new submenu to the toolbar """ + sub_menu = gtk.MenuItem(name) + sub_menu.show() + sub_menu.set_submenu(menu) + return sub_menu + + + def _make_menu_item(self, menu, tooltip, callback, arg=None): + """ add a new item to the submenu """ + menu_items = gtk.MenuItem(tooltip) + menu.append(menu_items) + if arg is None: + menu_items.connect('activate', callback) + else: + menu_items.connect('activate', callback, arg) + menu_items.show() + + def _makepath(self, path): + """ Make a path if it doesn't previously exist """ + from os import makedirs + from os.path import normpath, dirname, exists + + dpath = normpath(dirname(path)) + if not exists(dpath): + makedirs(dpath) + + def _start_gtk(self): + self.win.connect('configure_event', self.tw.update_overlay_position) + self.tw.win = self.win + if self.ta_file is None: + self.tw.load_start() + else: + print self.ta_file + self.tw.load_start(self.ta_file) + self.tw.lc.trace = 0 + self.tw.run_button(0) + gtk.main() + def _draw_and_quit(self): + self.tw.load_start(self.ta_file) + self.tw.lc.trace = 0 + self.tw.run_button(0) + self.tw.save_as_image(self.ta_file, self.canvas) -class TurtleMain(): - """ Launch Turtle Art from outside of Sugar """ + def _build_window(self): + if os.path.exists(self._INSTALL_PATH): + self.tw = TurtleArtWindow(self.canvas, self._INSTALL_PATH) + elif os.path.exists(self._ALTERNATE_INSTALL_PATH): + self.tw = TurtleArtWindow(self.canvas, self._ALTERNATE_INSTALL_PATH) + else: + self.tw = TurtleArtWindow(self.canvas, os.path.abspath('.')) - def __init__(self): - """ Parse command-line options and initialize class """ + self.tw.save_folder = os.path.expanduser('~') + def _init_vars(self): # If we are invoked to start a project from Gnome, we should make # sure our current directory is TA's source dir. os.chdir(os.path.dirname(__file__)) + self._uploader = Uploader() self.ta_file = None self.output_png = False - self.uploading = False + self.i = 0 # FIXME: use a better name for this variable + self.scale = 2.0 + self.tw = None - # Parse command line + def _parse_command_line(self): try: opts, args = getopt.getopt(argv[1:], 'ho', ['help', 'output_png']) except getopt.GetoptError, err: print str(err) - print _HELP_MSG + print self._HELP_MSG sys.exit(2) for o, a in opts: if o in ('-h', '--help'): - print _HELP_MSG + print self._HELP_MSG sys.exit() if o in ('-o', '--output_png'): self.output_png = True @@ -146,7 +180,7 @@ class TurtleMain(): self.ta_file = args[0] if len(args) > 1 or self.output_png and self.ta_file is None: - print _HELP_MSG + print self._HELP_MSG sys.exit() if self.ta_file is not None: @@ -155,163 +189,134 @@ class TurtleMain(): if not os.path.exists(self.ta_file): assert False, ('%s: %s' % (self.ta_file, _('File not found'))) - self.i = 0 - self.scale = 2.0 - self.tw = None - - # make sure Sugar paths are present + """ + make sure Sugar paths are present + """ + def _ensure_sugar_paths(self): tapath = os.path.join(os.environ['HOME'], '.sugar', 'default', 'org.laptop.TurtleArtActivity') - map(makepath, (os.path.join(tapath, 'data/'), + map(self._makepath, (os.path.join(tapath, 'data/'), os.path.join(tapath, 'instance/'))) - if self.output_png: - pixbuf = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, False, 8, - gtk.gdk.screen_width(), - gtk.gdk.screen_height()) - canvas, mask = pixbuf.render_pixmap_and_mask() + def _read_initial_pos(self): + try: + data_file = open(os.path.join(CONFIG_HOME, 'turtleartrc'), 'r') + except IOError: + # Opening the config file failed + # We'll assume it needs to be created + try: + self._mkdir_p(CONFIG_HOME) + data_file = open(os.path.join(CONFIG_HOME, 'turtleartrc'), + 'a+') + except IOError, e: + # We can't write to the configuration file, use + # a faux file that will persist for the length of + # the session. + print _('Configuration directory not writable: %s') % (e) + data_file = cStringIO.StringIO() + data_file.write(str(50) + '\n') + data_file.write(str(50) + '\n') + data_file.write(str(800) + '\n') + data_file.write(str(550) + '\n') + data_file.seek(0) + self.x = int(data_file.readline()) + self.y = int(data_file.readline()) + self.width = int(data_file.readline()) + self.height = int(data_file.readline()) + + def _setup_gtk(self): + win = gtk.Window(gtk.WINDOW_TOPLEVEL) + win.set_default_size(self.width, self.height) + win.move(self.x, self.y) + win.maximize() + win.set_title(_('Turtle Art')) + if os.path.exists(os.path.join(self._INSTALL_PATH, self._ICON_SUBPATH)): + win.set_icon_from_file(os.path.join(self._INSTALL_PATH, + self._ICON_SUBPATH)) else: - win = gtk.Window(gtk.WINDOW_TOPLEVEL) - try: - data_file = open(os.path.join(CONFIG_HOME, 'turtleartrc'), 'r') + win.set_icon_from_file(self._ICON_SUBPATH) except IOError: - # Opening the config file failed - # We'll assume it needs to be created - try: - mkdir_p(CONFIG_HOME) - data_file = open(os.path.join(CONFIG_HOME, 'turtleartrc'), - 'a+') - except IOError, e: - # We can't write to the configuration file, use - # a faux file that will persist for the length of - # the session. - print _('Configuration directory not writable: %s') % (e) - data_file = cStringIO.StringIO() - data_file.write(str(50) + '\n') - data_file.write(str(50) + '\n') - data_file.write(str(800) + '\n') - data_file.write(str(550) + '\n') - data_file.seek(0) - self.x = int(data_file.readline()) - self.y = int(data_file.readline()) - self.width = int(data_file.readline()) - self.height = int(data_file.readline()) - - win.set_default_size(self.width, self.height) - win.move(self.x, self.y) - win.maximize() - win.set_title(_('Turtle Art')) - if os.path.exists(os.path.join(_INSTALL_PATH, _ICON_SUBPATH)): - win.set_icon_from_file(os.path.join(_INSTALL_PATH, - _ICON_SUBPATH)) - else: - try: - win.set_icon_from_file(_ICON_SUBPATH) - except IOError: - pass - win.connect('delete_event', self._quit_ta) - - menu = gtk.Menu() - _make_menu_item(menu, _('New'), self._do_new_cb) - _make_menu_item(menu, _('Open'), self._do_open_cb) - _make_menu_item(menu, _('Save'), self._do_save_cb) - _make_menu_item(menu, _('Save As'), self._do_save_as_cb) - _make_menu_item(menu, _('Save as image'), self._do_save_picture_cb) - _make_menu_item(menu, _('Save as HTML'), self._do_save_html_cb) - _make_menu_item(menu, _('Save as Logo'), self._do_save_logo_cb) - if _UPLOAD_AVAILABLE: - _make_menu_item(menu, _('Upload to Web'), - self._do_upload_to_web) - _make_menu_item(menu, _('Quit'), self.destroy) - activity_menu = _make_sub_menu(menu, _('File')) - - menu = gtk.Menu() - _make_menu_item(menu, _('Cartesian coordinates'), - self._do_cartesian_cb) - _make_menu_item(menu, _('Polar coordinates'), self._do_polar_cb) - _make_menu_item(menu, _('Rescale coordinates'), - self._do_rescale_cb) - _make_menu_item(menu, _('Grow blocks'), self._do_resize_cb, 1.5) - _make_menu_item(menu, _('Shrink blocks'), - self._do_resize_cb, 0.667) - _make_menu_item(menu, _('Reset block size'), - self._do_resize_cb, -1) - view_menu = _make_sub_menu(menu, _('View')) - - menu = gtk.Menu() - _make_menu_item(menu, _('Copy'), self._do_copy_cb) - _make_menu_item(menu, _('Paste'), self._do_paste_cb) - edit_menu = _make_sub_menu(menu, _('Edit')) - - menu = gtk.Menu() - _make_menu_item(menu, _('Show palette'), self._do_palette_cb) - _make_menu_item(menu, _('Hide palette'), self._do_hide_palette_cb) - _make_menu_item(menu, _('Show/hide blocks'), self._do_hideshow_cb) - tool_menu = _make_sub_menu(menu, _('Tools')) - - menu = gtk.Menu() - _make_menu_item(menu, _('Clean'), self._do_eraser_cb) - _make_menu_item(menu, _('Run'), self._do_run_cb) - _make_menu_item(menu, _('Step'), self._do_step_cb) - _make_menu_item(menu, _('Debug'), self._do_trace_cb) - _make_menu_item(menu, _('Stop'), self._do_stop_cb) - turtle_menu = _make_sub_menu(menu, _('Turtle')) - - vbox = gtk.VBox(False, 0) - win.add(vbox) - vbox.show() - - menu_bar = gtk.MenuBar() - vbox.pack_start(menu_bar, False, False, 2) - menu_bar.show() - - sw = gtk.ScrolledWindow() - sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) - sw.show() - canvas = gtk.DrawingArea() - width = gtk.gdk.screen_width() * 2 - height = gtk.gdk.screen_height() * 2 - canvas.set_size_request(width, height) - sw.add_with_viewport(canvas) - canvas.show() - vbox.pack_end(sw, True, True) - - menu_bar.append(activity_menu) - menu_bar.append(edit_menu) - menu_bar.append(view_menu) - menu_bar.append(tool_menu) - menu_bar.append(turtle_menu) - - win.show_all() - - if os.path.exists(_INSTALL_PATH): - self.tw = TurtleArtWindow(canvas, _INSTALL_PATH) - elif os.path.exists(_ALTERNATE_INSTALL_PATH): - self.tw = TurtleArtWindow(canvas, _ALTERNATE_INSTALL_PATH) - else: - self.tw = TurtleArtWindow(canvas, os.path.abspath('.')) - - self.tw.save_folder = os.path.expanduser('~') - - if not self.output_png: - win.connect('configure_event', self.tw.update_overlay_position) - self.tw.win = win - if self.ta_file is None: - self.tw.load_start() - else: - print self.ta_file - self.tw.load_start(self.ta_file) - self.tw.lc.trace = 0 - self.tw.run_button(0) - - gtk.main() - - else: - self.tw.load_start(self.ta_file) - self.tw.lc.trace = 0 - self.tw.run_button(0) - self.tw.save_as_image(self.ta_file, canvas) + pass + win.connect('delete_event', self._quit_ta) + + vbox = gtk.VBox(False, 0) + win.add(vbox) + vbox.show() + + menu_bar = self._get_menu_bar() + vbox.pack_start(menu_bar, False, False, 2) + menu_bar.show() + + sw = gtk.ScrolledWindow() + sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + sw.show() + canvas = gtk.DrawingArea() + width = gtk.gdk.screen_width() * 2 + height = gtk.gdk.screen_height() * 2 + canvas.set_size_request(width, height) + sw.add_with_viewport(canvas) + canvas.show() + vbox.pack_end(sw, True, True) + + win.show_all() + self.win = win + self.canvas = canvas + + def _get_menu_bar(self): + menu = gtk.Menu() + self._make_menu_item(menu, _('New'), self._do_new_cb) + self._make_menu_item(menu, _('Open'), self._do_open_cb) + self._make_menu_item(menu, _('Save'), self._do_save_cb) + self._make_menu_item(menu, _('Save As'), self._do_save_as_cb) + self._make_menu_item(menu, _('Save as image'), self._do_save_picture_cb) + self._make_menu_item(menu, _('Save as HTML'), self._do_save_html_cb) + self._make_menu_item(menu, _('Save as Logo'), self._do_save_logo_cb) + if self._uploader.enabled(): + self._make_menu_item(menu, _('Upload to Web'), + self._uploader.do_upload_to_web) + self._make_menu_item(menu, _('Quit'), self.destroy) + activity_menu = self._make_sub_menu(menu, _('File')) + + menu = gtk.Menu() + self._make_menu_item(menu, _('Cartesian coordinates'), + self._do_cartesian_cb) + self._make_menu_item(menu, _('Polar coordinates'), self._do_polar_cb) + self._make_menu_item(menu, _('Rescale coordinates'), + self._do_rescale_cb) + self._make_menu_item(menu, _('Grow blocks'), self._do_resize_cb, 1.5) + self._make_menu_item(menu, _('Shrink blocks'), + self._do_resize_cb, 0.667) + self._make_menu_item(menu, _('Reset block size'), + self._do_resize_cb, -1) + view_menu = self._make_sub_menu(menu, _('View')) + + menu = gtk.Menu() + self._make_menu_item(menu, _('Copy'), self._do_copy_cb) + self._make_menu_item(menu, _('Paste'), self._do_paste_cb) + edit_menu = self._make_sub_menu(menu, _('Edit')) + + menu = gtk.Menu() + self._make_menu_item(menu, _('Show palette'), self._do_palette_cb) + self._make_menu_item(menu, _('Hide palette'), self._do_hide_palette_cb) + self._make_menu_item(menu, _('Show/hide blocks'), self._do_hideshow_cb) + tool_menu = self._make_sub_menu(menu, _('Tools')) + + menu = gtk.Menu() + self._make_menu_item(menu, _('Clean'), self._do_eraser_cb) + self._make_menu_item(menu, _('Run'), self._do_run_cb) + self._make_menu_item(menu, _('Step'), self._do_step_cb) + self._make_menu_item(menu, _('Debug'), self._do_trace_cb) + self._make_menu_item(menu, _('Stop'), self._do_stop_cb) + turtle_menu = self._make_sub_menu(menu, _('Turtle')) + + menu_bar = gtk.MenuBar() + menu_bar.append(activity_menu) + menu_bar.append(edit_menu) + menu_bar.append(view_menu) + menu_bar.append(tool_menu) + menu_bar.append(turtle_menu) + return menu_bar def _quit_ta(self, widget=None, e=None): """ Save changes on exit """ @@ -528,134 +533,5 @@ class TurtleMain(): """ Callback for destroy event. """ gtk.main_quit() - def _do_upload_to_web(self, widget): - """ Create dialog for uploading current project to the Web """ - if not self.uploading: - self.uploading = True - self.pop_up = gtk.Window() - self.pop_up.set_default_size(600, 400) - self.pop_up.connect('delete_event', self._stop_uploading) - table = gtk.Table(8, 1, False) - self.pop_up.add(table) - - login_label = gtk.Label(_('You must have an account at \ -http://turtleartsite.sugarlabs.org to upload your project.')) - table.attach(login_label, 0, 1, 0, 1) - self.login_message = gtk.Label('') - table.attach(self.login_message, 0, 1, 1, 2) - - self.Hbox1 = gtk.HBox() - table.attach(self.Hbox1, 0, 1, 2, 3, xpadding=5, ypadding=3) - self.username_entry = gtk.Entry() - username_label = gtk.Label(_('Username:') + ' ') - username_label.set_size_request(150, 25) - username_label.set_alignment(1.0, 0.5) - self.username_entry.set_size_request(450, 25) - self.Hbox1.add(username_label) - self.Hbox1.add(self.username_entry) - - self.Hbox2 = gtk.HBox() - table.attach(self.Hbox2, 0, 1, 3, 4, xpadding=5, ypadding=3) - self.password_entry = gtk.Entry() - password_label = gtk.Label(_('Password:') + ' ') - self.password_entry.set_visibility(False) - password_label.set_size_request(150, 25) - password_label.set_alignment(1.0, 0.5) - self.password_entry.set_size_request(450, 25) - self.Hbox2.add(password_label) - self.Hbox2.add(self.password_entry) - - self.Hbox3 = gtk.HBox() - table.attach(self.Hbox3, 0, 1, 4, 5, xpadding=5, ypadding=3) - self.title_entry = gtk.Entry() - title_label = gtk.Label(_('Title:') + ' ') - title_label.set_size_request(150, 25) - title_label.set_alignment(1.0, 0.5) - self.title_entry.set_size_request(450, 25) - self.Hbox3.add(title_label) - self.Hbox3.add(self.title_entry) - - self.Hbox4 = gtk.HBox() - table.attach(self.Hbox4, 0, 1, 5, 6, xpadding=5, ypadding=3) - self.description_entry = gtk.TextView() - description_label = gtk.Label(_('Description:') + ' ') - description_label.set_size_request(150, 25) - description_label.set_alignment(1.0, 0.5) - self.description_entry.set_wrap_mode(gtk.WRAP_WORD) - self.description_entry.set_size_request(450, 50) - self.Hbox4.add(description_label) - self.Hbox4.add(self.description_entry) - - self.Hbox5 = gtk.HBox() - table.attach(self.Hbox5, 0, 1, 6, 7, xpadding=5, ypadding=3) - self.submit_button = gtk.Button(_('Submit to Web')) - self.submit_button.set_size_request(300, 25) - self.submit_button.connect('pressed', self._do_remote_logon) - self.Hbox5.add(self.submit_button) - self.cancel_button = gtk.Button(_('Cancel')) - self.cancel_button.set_size_request(300, 25) - self.cancel_button.connect('pressed', self._stop_uploading) - self.Hbox5.add(self.cancel_button) - - self.pop_up.show_all() - - def _stop_uploading(self, widget, event=None): - """ Hide the popup when the upload is complte """ - self.uploading = False - self.pop_up.hide() - - def _do_remote_logon(self, widget): - """ Log into the upload server """ - username = self.username_entry.get_text() - password = self.password_entry.get_text() - server = xmlrpclib.ServerProxy(_UPLOAD_SERVER + '/call/xmlrpc') - logged_in = server.login_remote(username, password) - if logged_in: - upload_key = logged_in - self._do_submit_to_web(upload_key) - else: - self.login_message.set_text(_('Login failed')) - - def _do_submit_to_web(self, key): - """ Submit project to the server """ - title = self.title_entry.get_text() - description = self.description_entry.get_buffer().get_text( - *self.description_entry.get_buffer().get_bounds()) - tafile, imagefile = self.tw.save_for_upload(title) - - # Set a maximum file size for image to be uploaded. - if int(os.path.getsize(imagefile)) > _MAX_FILE_SIZE: - import Image - while int(os.path.getsize(imagefile)) > _MAX_FILE_SIZE: - big_file = Image.open(imagefile) - smaller_file = big_file.resize(int(0.9 * big_file.size[0]), - int(0.9 * big_file.size[1]), - Image.ANTIALIAS) - smaller_file.save(imagefile, quality = 100) - - c = pycurl.Curl() - c.setopt(c.POST, 1) - c.setopt(c.FOLLOWLOCATION, 1) - c.setopt(c.URL, _UPLOAD_SERVER + '/upload') - c.setopt(c.HTTPHEADER, ["Expect:"]) - c.setopt(c.HTTPPOST, [('file', (c.FORM_FILE, tafile)), - ('newimage', (c.FORM_FILE, imagefile)), - ('small_image', (c.FORM_FILE, imagefile)), - ('title', title), - ('description', description), - ('upload_key', key), ('_formname', - 'image_create')]) - c.perform() - error_code = c.getinfo(c.HTTP_CODE) - c.close - os.remove(imagefile) - os.remove(tafile) - if error_code == 400: - self.login_message.set_text(_('Failed to upload!')) - else: - self.pop_up.hide() - self.uploading = False - - if __name__ == "__main__": TurtleMain() |