diff options
author | root <root@ghunt-desktop.(none)> | 2010-10-30 19:36:14 (GMT) |
---|---|---|
committer | root <root@ghunt-desktop.(none)> | 2010-10-30 19:36:14 (GMT) |
commit | 966312ba98d729177238f4663d789a789663eb2e (patch) | |
tree | e39e90f5699170b3cc05e03fdd8b2e05110d9498 /project_gui.py | |
parent | 7e0dfb3e1df6ffa0194048d93ac4f55df00107a0 (diff) |
start working on release 7, include all new files, breakpoints still need work
Diffstat (limited to 'project_gui.py')
-rw-r--r-- | project_gui.py | 957 |
1 files changed, 957 insertions, 0 deletions
diff --git a/project_gui.py b/project_gui.py new file mode 100644 index 0000000..397cfee --- /dev/null +++ b/project_gui.py @@ -0,0 +1,957 @@ +#!/usr/bin/env python +# Copyright (C) 2009, George Hunt <georgejhunt@gmail.com> +# Copyright (C) 2009, One Laptop Per Child +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +from __future__ import with_statement +import os, shutil, sys, time + +from gettext import gettext as _ + +#major packages +import gtk +import gtk.glade + +#sugar stuff +from sugar.graphics.toolbutton import ToolButton +import sugar.graphics.toolbutton +from sugar.datastore import datastore + +#pydebug stuff +from filetree import FileTree +from project import ProjectFunctions + +from pydebug_logging import _logger, log_environment + + +#colors for the playpen side of the project page +PROJECT_FG = '#990000' +PROJECT_BASE = "#fdd99b" +PROJECT_BG = '#FFFFCC' + +class ProjectGui(ProjectFunctions): + def __init__(self,activity): + self._activity = activity + self.file_pane_is_activities = False + self.manifest_class = None + self.journal_class = None + + #establish the glade pydebug connection + self.wTree=gtk.glade.XML(os.path.join(activity.sugar_bundle_path,"project.glade")) + self.connect_journal() + + #disable the change callbacks on the activity.info panel + self.ignore_changes = True + + #set up the toolbar + project_run = ToolButton() + project_run.set_stock_id('gtk-media-forward') + project_run.set_icon_widget(None) + project_run.set_tooltip(_('Start Debugging')) + project_run.connect('clicked', self._activity.project_run_cb) + project_run.add_accelerator('clicked',self._activity.accelerator,ord('G'),\ + gtk.gdk.CONTROL_MASK,gtk.ACCEL_VISIBLE) + #project_run.props.accelerator = '<Ctrl>C' + project_run.show() + + separator = gtk.SeparatorToolItem() + separator.set_draw(False) + separator.set_expand(True) + separator.show() + + projectbar = gtk.Toolbar() + projectbar.show_all() + projectbar.insert(project_run, -1) + projectbar.insert(separator, -1) + #projectbar.insert(self.keep,-1) + + self.projectbar = projectbar + + ######################################################################################### + + def get_editor(self): + raise NotImplimentedError + + def get_activity(self): + raise NotImplimentedError + + def get_activity_toolbar(self): + raise NotImplimentedError + + def get_projectbar(self): + return self.projectbar + + def _get_project_canvas(self): + #initialize the link between program and the glade XML file + self.contents = self.wTree.get_widget("contents") + self.contents.unparent() + return self.contents + + def setup_project_page(self): + self.activity_treeview = self.wTree.get_widget('file_system') + self.activity_window = FileTree(self, self.activity_treeview,self.wTree) + self.activity_window.set_file_sys_root('/home/olpc/Activities') + self.examples_treeview = self.wTree.get_widget('examples') + self.examples_window = FileTree(self._activity, self.examples_treeview,self.wTree) + self.examples_window.set_file_sys_root(os.path.join\ + (self._activity.sugar_bundle_path,'examples')) + self.journal_treeview = self.wTree.get_widget('journal') + self.journal_class = DataStoreTree(self._activity,self.journal_treeview,self.wTree) + if self.journal_class: + _logger.debug('journal class object created') + self.connect_project_info() #make connections to signals from buttons + self.activity_toggled_cb(None) + + self.icon_type = self.wTree.get_widget('icon_outline') + model = gtk.ListStore(str,str) + model.append(["icon_circle", _('Circle')]) + model.append(['icon_square', _('Square')]) + model.append(['icon_diamond', _('Diamond')]) + model.append(['icon_star', _('Star')]) + cell = gtk.CellRendererText() + self.icon_type.set_model(model) + self.icon_type.pack_start(cell) + self.icon_type.add_attribute(cell,'text',1) + self.icon_type.set_active(self._activity.debug_dict.get('icon_active',1)) + + if self._activity.child_path and self._activity.child_path.endswith('.activity') and \ + os.path.isdir(self._activity.child_path): + self.setup_new_activity() + """ + ds_mounts = datastore.mounts() + for x in ds_mounts: + _logger.debug('Title:%s Uri:%s'%(x.get('title'),x.get('uri'))) + """ + self.activity_data_changed = False + + """ + #get set to sense addition of a usb flash drive + self.volume_monitor = gio.volume_monitor_get() + self.volume_monitor.connect('mount-added',self.__mount_added_cb) + self.volume_monitor.connect('mount-removed',self.__mount_removed_cb) + mount_list = self.volume_monitor.get_mounts() + for m in mount_list: + s = m.get_root().get_path() + if s.startswith('/media'):_logger.debug('volume:%s',s) + """ + + ############################################################################ + #first connect the glade xml file to the servicing call backs + def connect_project_info(self, wTree=None): + mdict = { + 'name_leave_notify_event_cb':self.name_changed_cb, + 'bundle_id_leave_notify_event_cb':self.bundle_id_changed_cb, + 'module_leave_notify_event_cb':self.module_changed_cb, + 'class_leave_notify_event_cb':self.class_changed_cb, + 'icon_outline_changed_cb':self.icon_changed_cb, + 'version_leave_notify_event_cb':self.version_changed_cb, + 'file_toggle_clicked_cb':self.activity_toggled_cb, + 'to_activities_clicked_cb':self.to_home_clicked_cb, + 'from_activities_clicked_cb':self.from_home_clicked_cb, + 'from_examples_clicked_cb':self.from_examples_clicked_cb, + 'help_clicked_cb':self._keep_activity_info, + 'create_icon_clicked_cb':self.create_icon_cb, + 'delete_file_clicked_cb':self.delete_file_cb, + 'clear_clicked_cb':self.clear_clicked_cb, + } + self.wTree.signal_autoconnect(mdict) + + button = self.wTree.get_widget('file_toggle') + tt = gtk.Tooltips() + tt.set_tip(button,_('Switch views between the "Installed" Activities directory and your "home" storage directory')) + #button.set_tooltip_text(_('Switch views between the "Installed" Activities directory and your "home" storage directory')) + + button = self.wTree.get_widget('to_activities') + tt = gtk.Tooltips() + tt.set_tip(button,_('Copy the files in the debug workplace to your "home" storage directory')) + #button.set_tooltip_text(_('Copy the files in the debug workplace to your "home" storage directory') + + button = self.wTree.get_widget('from_examples') + tt = gtk.Tooltips() + tt.set_tip(button,_('Load and modify these example programs. See the help Tutorials')) + #button.set_tooltip_text(_('Load and modify these example programs. See the help Tutorials')) + + button = self.wTree.get_widget('delete_file') + map = button.get_colormap() + color = map.alloc_color(PROJECT_FG) + style = button.get_style().copy() + style.bg[gtk.STATE_NORMAL] = color + button.set_style(style) + + button = self.wTree.get_widget('clear') + button.set_style(style) + + button = self.wTree.get_widget('help') + button.set_style(style) + + button = self.wTree.get_widget('create_icon') + button.set_style(style) + + button = self.wTree.get_widget('icon_outline') + button.set_style(style) + + def connect_journal(self, wTree=None): + mdict = { + 'from_journal_clicked_cb':self.load_from_journal_cb, + 'to_journal_clicked_cb':self.save_to_journal_cb , + } + self.wTree.signal_autoconnect(mdict) + + def load_from_journal_cb(self,button): + selection=self.journal_treeview.get_selection() + (model,iter)=selection.get_selected() + if iter == None: + self.parent.util.alert(_('Must select Journal item to Load')) + return + object_id = model.get(iter,9) + _logger.debug('object id %s from journal'%object_id) + self.try_to_load_from_journal(object_id) + + def save_to_journal_cb(self,button): + self.write_binary_to_datastore() + + def name_changed_cb(self, widget, event): + if self.ignore_changes: return + self.activity_data_changed = True + name = widget.get_text() + + #make a suggestion for module if it is blank + widget_field = self.wTree.get_widget('module') + module = widget_field.get_text() + if module == '': + widget_field.set_text(name.lower()) + + #make a suggestion for class if it is blank + widget_field = self.wTree.get_widget('class') + myclass = widget_field.get_text() + if myclass == '': + widget_field.set_text(name) + + #make a suggestion for bundle_id if it is blank + widget_field = self.wTree.get_widget('bundle_id') + bundle_id = widget_field.get_text() + if bundle_id == '': + suggestion = 'org.laptop.' + name + else: #working from a template, suggest changing last element + bundle_chunks = bundle_id.split('.') + prefix = '.'.join(bundle_chunks[:-1]) + suggestion = prefix + '.' + name + widget_field.set_text(suggestion) + #self.display_current_project() + + def bundle_id_changed_cb(self,widget, event): + if self.ignore_changes: return + self.activity_data_changed = True + + def module_changed_cb(self, widget, event): + if self.ignore_changes: return + self.activity_data_changed = True + + def class_changed_cb(self, widget, event): + if self.ignore_changes: return + self.activity_data_changed = True + + def version_changed_cb(self, widget, event): + if self.ignore_changes: return + self.activity_data_changed = True + version = widget.get_text() + _logger.debug('version changed to %s'%version) + + def icon_changed_cb(self, combo): + self.activity_data_changed = True + model = combo.get_model() + i = combo.get_active() + self.icon_outline = model[i][0] + _logger.debug('icon outline select is %s'%self.icon_outline) + self._activity.debug_dict['icon_active'] = i + + def create_icon_cb(self,widget): + self.activity_data_changed = True + #get the two characters and substitute them in the proper svg template + chrs_entry = self.wTree.get_widget('icon_chr') + chars = chrs_entry.get_text() + _logger.debug('CREATE A NEW ICON !!!!text characters: %s'%chars) + if chars == '':chars = '??' + template = os.path.join(self.pydebug_path,'bin',self.icon_outline)+'.svg' + try: + icon_fd = file(template,'r') + icon_str = icon_fd.read() + except IOError, e: + _logger.error('read exception %s'%e) + return + icon_str = icon_str.replace('??', chars) + self.icon_basename = self._activity.activity_dict.get('bundle_id','dummy').split('.')[-1] + \ + '_' + chars + '_' + self.icon_outline[5:6] + self._activity.activity_dict['icon_base'] = os.path.join(self._activity.child_path,'activity',self.icon_basename) + + target = self._activity.activity_dict['icon_base'] + '.svg' + if self.last_icon_file: + os.unlink(self.last_icon_file) + self.last_icon_file = None + try: + _file = file(target, 'w+') + _file.write(icon_str) + _file.close() + except IOError, e: + msg = _("I/O error(%s): %s"%(e)) + _logger.error(msg) + except Exception, e: + msg = "Unexpected error:%s"%e + _logger.error(msg) + if _file: + self.last_icon_file = target + _file.close() + self._activity.activity_dict['icon'] = self._activity.activity_dict.get('name') + self._activity.update_metadata() + _logger.debug('about to POP UP THE ICON') + if self.icon_window: + self.icon_window.destroy() + self.icon_window = Icon_Panel(None) + self.icon_window._icon.set_file(target) + self.icon_window._icon.show() + self.icon_window.connect_button_press(self.button_press_event) + self.icon_window.show() + + def button_press_event(self,event, data=None): + self.icon_window.destroy() + self.icon_window = None + + def activity_toggled_cb(self, widget): + _logger.debug('Entered activity_toggled_cb. Button: %r'%self.file_pane_is_activities) + but = self.wTree.get_widget('to_activities') + to_what = self.wTree.get_widget('file_toggle') + window_label = self.wTree.get_widget('file_system_label') + if self.file_pane_is_activities == True: + to_what.set_label('Installed_') + but.show() + #display_label = self.storage[:18]+' . . . '+self.storage[-24:] + display_label = 'PyDebug SHELF storage:' + self.activity_window.set_file_sys_root(self._activity.storage) + button = self.wTree.get_widget('from_activities') + tt = gtk.Tooltips() + tt.set_tip(button,_('Copy the selected directory or file from your "home" storage to the debug workplace')) + #button.set_tooltip_text(_('Copy the selected directory or file from your "home" storage to the debug workplace')) + window_label.set_text(display_label) + else: + to_what.set_label('shelf') + but.hide() + self.activity_window.set_file_sys_root('/home/olpc/Activities') + button = self.wTree.get_widget('from_activities') + tt = gtk.Tooltips() + tt.set_tip(button,_('Copy the selected Activity or file to the debug workplace')) + #button.set_tooltip_text(_('Copy the selected Activity or file to the debug workplace')) + window_label.set_text('INSTALLED ACTIVITIES:') + self.file_pane_is_activities = not self.file_pane_is_activities + + def to_home_clicked_cb(self,widget): + _logger.debug('Entered to_home_clicked_cb') + self._to_home_dest = os.path.join(self.storage,self._activity.activity_dict['name']+'.activity') + if False: #os.path.isdir(self._to_home_dest): + target_md5sum = self._activity.util.md5sum_tree(self._to_home_dest) + if target_md5sum != self._activity.debug_dict.get('tree_md5',''): + self._activity.util.confirmation_alert(_('OK to delete/overwrite %s?'%self._to_home_dest), + _('This destination has been changed by another application'), + self._to_home_cb) + return + self._to_home_cb( None, gtk.RESPONSE_OK) + + def _to_home_cb(self, alert, response_id): + """write playpen tree to writeable storage, and USB/SD if pydebug folder exists + in root directory""" + if alert != None: self.remove_alert(alert) + if response_id is gtk.RESPONSE_OK: + """ + cmd = ['rsync','-av',self._activity.child_path + '/',self._to_home_dest] + _logger.debug('do to_home_cb with cmd:%s'%cmd) + p1 = Popen(cmd,stdout=PIPE) + output = p1.communicate() + if p1.returncode != 0: + self._activity.util.alert('rsync command returned non zero\n'+output[0]+ 'COPY FAILURE') + return + """ + + #remove any embeded shell breakpoints + self.get_editor().clear_embeds() + + _logger.debug('removing tree, and then copying to %s'%self._to_home_dest) + if os.path.isdir(self._to_home_dest): + shutil.rmtree(self._to_home_dest, ignore_errors=True) + shutil.copytree(self._activity.child_path,self._to_home_dest) + self._activity.util.set_permissions(self._to_home_dest) + #redraw the treeview + self.activity_window.set_file_sys_root(self.storage) + + #write snapshot of source tree to removable media if /pydebug directory exists + self.removable_backup() + + def from_home_clicked_cb(self,widget): + _logger.debug('Entered from_home_clicked_cb') + selection=self.activity_treeview.get_selection() + (model,iter)=selection.get_selected() + if iter == None: + self._activity.util.alert(_('Must select File or Directory item to Load')) + return + fullpath = model.get(iter,4)[0] + if os.path.isdir(fullpath): + if fullpath.endswith('.activity'): + if fullpath.startswith(self._activity.activity_playpen): #just re-initialize the project + self._activity.debug_dict['source_tree'] = fullpath + self._activity.child_path = fullpath + self.setup_new_activity() + return + self.load_activity_to_playpen(fullpath) + else: #this is a file folder, just copy it to project + source_basename = os.path.basename(fullpath) + dest = os.path.join(self._activity.activity_playpen,source_basename) + self.copy_tree(fullpath,dest) + else: + #selected is a file, just copy it into the current project + basename = os.path.basename(fullpath) + if os.path.isfile(os.path.join(self._activity.child_path,basename)): + #change name if necessary to prevent collision + basename = self._activity.util.non_conflicting(self._activity.child_path,basename) + shutil.copy(fullpath,os.path.join(self._activity.child_path,basename)) + self.manifest_point_to(os.path.join(self._activity.child_path,basename)) + + def from_examples_clicked_cb(self,widget): + _logger.debug('Entered from_examples_clicked_cb') + selection=self.examples_treeview.get_selection() + (model,iter)=selection.get_selected() + if iter == None: + self._activity.util.alert(_('Must select File or Directory item to Load')) + return + fullpath = model.get(iter,4)[0] + self._load_to_playpen_source = fullpath + if fullpath.endswith('.activity'): + self.load_activity_to_playpen(fullpath) + return + if fullpath.endswith('.xo'): + try: + self._bundler = ActivityBundle(fullpath) + except: + self._activity.util.alert('Error: Malformed Activity Bundle') + return + self._new_child_path = os.path.join(self._activity.activity_playpen,self._bundler._zip_root_dir) + #check to see if current activity in playpen needs to be saved, and load new activity if save is ok + self._load_playpen(fullpath, iszip=True) + return + if fullpath.endswith('.tar.gz'): + self._new_child_path = os.path.join(self._activity.activity_playpen,self._bundler._zip_root_dir) + #check to see if current activity in playpen needs to be saved, and load new activity if save is ok + self._load_playpen(fullpath, istar=True) + return + #if os.path.isdir(fullpath): + self._new_child_path = self._activity.child_path + self._load_playpen(fullpath) + + #def filetree_activated(self): + #_logger.debug('entered pydebug filetree_activated') + + def _keep_activity_info(self,widget): + """ Act on the changes made to the screen project data fields + changing the name of the activity turns out to be a big deal -- + it will be done frequently in order to branch off an experimental branch + and it requires changing the root path, and therefore all the open edit files which + include the old root name in the path. There's also the meta- that has to be updated. + So let's deal with writing the activity.info file first + """ + _logger.debug('in keep_activity_activity.info') + name_widget = self.wTree.get_widget('name') + name = name_widget.get_text() + old_name = self._activity.activity_dict['name'] + self.old_icon = self._activity.activity_dict.get('icon') + self._activity.activity_dict['name'] = name + + name_widget = self.wTree.get_widget('version') + self._activity.activity_dict['version'] = name_widget.get_text() + + name_widget = self.wTree.get_widget('version') + self._activity.activity_dict['version'] = name_widget.get_text() + + name_widget = self.wTree.get_widget('bundle_id') + self._activity.activity_dict['bundle_id'] = name_widget.get_text() + + name_widget = self.wTree.get_widget('module') + self._activity.activity_dict['module'] = name_widget.get_text() + + name_widget = self.wTree.get_widget('class') + self._activity.activity_dict['class'] = name_widget.get_text() + + self._activity.update_metadata() + self.write_activity_info() + + #now the to the more difficult part -- is renaming required? + new_name = name + '.activity' + new_child_path = os.path.join(self._activity.activity_playpen,new_name) + if name.startswith('untitled'): + self._activity.util.alert(_("Activities must be given a new and unique name")) + return + if old_name != self._activity.activity_dict.get('name'): + #check to see if the folder already exists, if so change its name + _logger.debug('need to make decision to move or create child base:%s. new_name:%s'%\ + (os.path.basename(self._activity.child_path), new_name)) + if os.path.isdir(self._activity.child_path) and os.path.basename(self._activity.child_path) != new_name: + self.get_editor().remove_all() + self._activity.init_activity_dict() + + cmd = 'mv %s %s'%(self._activity.child_path,new_child_path) + result,status = self._activity.util.command_line(cmd) + if status != 0: + _logger.error('tried to rename %s directory unsuccessfully'%self._activity.child_path) + return + self._activity.child_path = new_child_path + else: #need to create the directories + if not os.path.isdir(os.path.join(new_child_path,'activity')): + os.makedirs(os.path.join(new_child_path,'activity')) + + + def write_activity_info(self): + #write the activity.info file + #if not self.activity_data_changed: return + filen = os.path.join(self._activity.child_path,'activity','activity.info') + _logger.debug('write_activity_info to %s'%filen) + if os.path.isfile(filen): #set aside the info file encountered + new_filename = self._activity.util.non_conflicting(os.path.join(self._activity.child_path,'activity'),'activity.info') + _logger.debug('decided to move %s to %s'%(filen,new_filename)) + cmd = 'mv %s %s'%(filen,new_filename) + results,status = self._activity.util.command_line(cmd) + self.write_new_activity_info(filen) + + def write_new_activity_info(self,fn): + dirname = os.path.dirname(fn) + if not os.path.isdir(dirname): + try: + os.makedirs(dirname) + except: + pass + try: + with open(fn,'w+') as fdw: + #write the required lines + _logger.debug('writing activity info to %s'%fn) + fdw.write('[Activity]\n') + fdw.write('name = %s\n'%self._activity.activity_dict.get('name')) + fdw.write('bundle_id = %s\n'%self._activity.activity_dict.get('bundle_id')) + fdw.write('activity_version = %s\n'%self._activity.activity_dict.get('version')) + fdw.write('show_launcher = yes\n') + icon = self._activity.activity_dict.get('icon') + if self.icon_basename: + icon_nibble = self.icon_basename + else: + icon_nibble = os.path.basename(self.old_icon).split('.')[0] + fdw.write('icon = %s\n'%icon_nibble) + if self._activity.activity_dict.get('class','') == '': + if self._activity.activity_dict.get('module'): + fdw.write('exec = %s\n'%self._activity.activity_dict.get('module')) + else: + fdw.write('exec = %s\n'%self._activity.activity_dict.get('name')) + else: + fdw.write('class = %s.%s\n'%(self._activity.activity_dict.get('module'), + self._activity.activity_dict.get('class'))) + fdw.close() + except Exception, e: + _logger.debug('write new activity info file exception %s'%e) + raise e + + def delete_file_cb(self,widget): + selection=self.manifest_treeview.get_selection() + (model,iter)=selection.get_selected() + if iter == None: + self._activity.util.alert(_('Must select a File or Folder to delete')) + return + fullpath = model.get(iter,4)[0] + _logger.debug(' delete_file_clicked_cb. File: %s'%(fullpath)) + self.delete_file_storage = fullpath + if os.path.isdir(fullpath): + self._activity.util.confirmation_alert(_('Would you like to continue deleting %s?'%os.path.basename(fullpath)), + _('CAUTION: You are about to DELETE a FOLDER!!'),self.do_delete_folder) + return + self._activity.util.confirmation_alert(_('Would you like to continue deleting %s?'%os.path.basename(fullpath)), + _('ABOUT TO DELETE A FILE!!'),self.do_delete) + + def do_delete(self, alert, response): + _logger.debug('doing delete of: %s'%self.delete_file_storage) + self.manifest_point_to(self.delete_file_storage) + os.unlink(self.delete_file_storage) + self.manifest_class.set_file_sys_root(self._activity.child_path) + self.manifest_class.position_recent() + + def do_delete_folder(self, alert, response): + _logger.debug('doing delete of: %s'%self.delete_file_storage) + self.manifest_point_to(self.delete_file_storage) + shutil.rmtree(self.delete_file_storage) + self.manifest_class.set_file_sys_root(self._activity.child_path) + self.manifest_class.position_recent() + + def clear_clicked_cb(self, button): + new_tree = os.path.join(self._activity.activity_playpen,'untitled.activity') + if self._activity.child_path == new_tree: + root = self.storage + else: + self.get_editor().remove_all() + self._activity.init_activity_dict() + if os.path.isdir(new_tree): + shutil.rmtree(new_tree,ignore_errors=True) + act_path = os.path.join(new_tree,'activity') + if not os.path.isdir(act_path): + os.makedirs(act_path) + self._activity.child_path = new_tree + self._activity.activity_dict['child_path'] = new_tree + src = os.path.join(self._activity.sugar_bundle_path,'setup.py') + shutil.copy(src,new_tree) + root = self._activity.activity_playpen + if self.manifest_class: + self.manifest_class.set_file_sys_root(root) + self.display_current_project() + + def setup_new_activity(self): + _logger.debug('in setup_new_activity. child path before chdir:%s'%self._activity.child_path) + if self._activity.child_path == None or not os.path.isdir(self._activity.child_path): + return + os.chdir(self._activity.child_path) + #cd_cmd = 'cd %s'%self._activity.child_path + #self._activity.feed_virtual_terminal(0,cd_cmd) + self.read_activity_info(self._activity.child_path) + self._activity.debug_dict['child_path'] = self._activity.child_path + self.display_current_project() + + #set the current working directory for debugging in the child context + cwd_cmd = 'cd %s\n'%(self._activity.child_path,) + self._activity.feed_virtual_terminal(0,cwd_cmd) + + #add the bin directory to path + if self._activity.child_path not in os.environ['PATH'].split(':'): + os.environ['PATH'] = os.path.join(self._activity.child_path,'bin') + ':' + os.environ['PATH'] + + #calculate and store the md5sum + self._activity.debug_dict['tree_md5'] = self._activity.util.md5sum_tree(self._activity.child_path) + + #if this is a resumption, open previous python files and position to previous location + if self._activity.debug_dict.get(os.path.basename(self._activity.child_path)): + for filenm, line in self._activity.debug_dict.get(os.path.basename(self._activity.child_path)): + if os.path.isfile(filenm): + self.get_editor().load_object(filenm,os.path.basename(filenm)) + self.get_editor().position_to(filenm,line) + current_page = self._activity.debug_dict.get(os.path.basename(self._activity.child_path)+'-page',0) + self.get_editor().edit_notebook.set_current_page(current_page) + self.get_editor().load_breakpoints = False + else: + #find largest python files for editor + list = [f for f in os.listdir(self._activity.child_path) if f[0] <> '.'] + #list = self.manifest_class.get_filenames_list(self._activity.child_path) + if not list: return + sizes = [] + for f in list: + full_path = os.path.join(self._activity.child_path,f) + if not f.endswith('.py'):continue + size = self.manifest_class.file_size(full_path) + sizes.append((size,full_path,)) + #_logger.debug('python file "%s size %d'%(f,size)) + for s,f in sorted(sizes,reverse=True)[:5]: + self.get_editor().load_object(f,os.path.basename(f)) + self.get_editor().set_current_page(0) + + def get_manifest_class(self): + return self.manifest_class + + def display_current_project(self): + global start_clock + #try to colorize the playpen + pp = self.wTree.get_widget('playpen_event_box') + map = pp.get_colormap() + color = map.alloc_color(PROJECT_BG) + style = pp.get_style().copy() + style.bg[gtk.STATE_NORMAL] = color + pp.set_style(style) + + self.manifest_treeview = self.wTree.get_widget('manifest') + map =self.manifest_treeview.get_colormap() + color = map.alloc_color(PROJECT_BASE) + style = self.manifest_treeview.get_style().copy() + style.bg[gtk.STATE_NORMAL] = color + color = map.alloc_color(PROJECT_BASE) + style.base[gtk.STATE_NORMAL] = color + self.manifest_treeview.set_style(style) + if self.manifest_class == None: + self.manifest_class = FileTree(self, self.manifest_treeview,self.wTree) + self.manifest_class.set_file_sys_root(self._activity.child_path) + + #disable the on change callbacks + self.ignore_changes = True + + name = self.wTree.get_widget('name') + #map = name.get_colormap() + color = map.alloc_color(PROJECT_BASE) + style = name.get_style().copy() + style.base[gtk.STATE_NORMAL] = color + name.set_style(style) + name.set_text(self._activity.activity_dict.get('name','')) + + version = self.wTree.get_widget('version') + version.set_style(style) + version.set_text(self._activity.activity_dict.get('version','')) + + bundle = self.wTree.get_widget('bundle_id') + bundle.set_style(style) + bundle.set_text(self._activity.activity_dict.get('bundle_id','')) + + pyclass = self.wTree.get_widget('class') + pyclass.set_style(style) + pyclass.set_text(self._activity.activity_dict.get('class','')) + self.pdbclass = pyclass + + pymodule = self.wTree.get_widget('module') + pymodule.set_style(style) + pymodule.set_text(self._activity.activity_dict.get('module','')) + self.pdbmodule = pymodule.get_text() + + pyicon = self.wTree.get_widget('icon_chr') + pyicon.set_style(style) + pyicon.set_text(self._activity.activity_dict.get('icon_chr','')) + + #re-enable the on change callbacks + self.ignore_changes = False + + """ + self.wTree.get_widget('home_save').set_text(self._activity.activity_dict.get('home_save','')) + self.wTree.get_widget('host').set_text(self.debug_dict.get('host','')) + self.wTree.get_widget('port').set_text(str(self.debug_dict.get('port',''))) + activity_size = os.system('du --max-depth=0') + self.wTree.get_widget('activity_size').set_text(str(activity_size)) + self.wTree.get_widget('icon').set_text(self._activity.activity_dict.get('icon','').split('/')[-1:][0]) + """ + + def manifest_point_to(self,fullpath): + if self.child_path: + self.manifest_class.set_file_sys_root(self.child_path) + else: + self.manifest_class.set_file_sys_root(self._activity.activity_playpen) + self.manifest_class.position_to(fullpath) + +class DataStoreTree(): + column_names = [_('Name'), _('Size'), _('Last Changed')] + + def __init__(self, parent, widget=None,wTree=None): + self.parent = parent + self._activity = parent + self.treeview = widget + self.wTree = wTree + self.init_model() + self.init_columns() + self.limit=10 + self.journal_page_size =10 + self.journal_page_num = 0 + self.journal_max = 0 + self.new_directory() + button = self.wTree.get_widget('from_journal') + tt = gtk.Tooltips() + tt.set_tip(button,_('Load the selected Journal XO (or tar.gz) file to the debug workplace')) + #button.set_tooltip_text(_('Load the selected Journal XO (or tar.gz) file to the debug workplace')) + button = self.wTree.get_widget('to_journal') + tt = gtk.Tooltips() + tt.set_tip(button,_('Zip up all the files in your debug workplace and store them in the Journal')) + #button.set_tooltip_text(_('Zip up all the files in your debug workplace and store them in the Journal')) + + + + def init_model(self): + #plan for the store: pixbuf,title,size,last-updated,tooltip,jobject-id + self.journal_model = gtk.TreeStore(gtk.gdk.Pixbuf, str,str,str,str,str,str,str,str,str,str) + if not self.treeview: + self.treeview = gtk.TreeView() + self.treeview.set_model(self.journal_model) + self.treeview.show() + #self.treeview.has_tooltip = True + #self.treeview.set_tooltip_column(10) + #self.treeview.connect('query-tooltip',self.display_tooltip) + self.show_hidden = False + + def init_columns(self): + col = gtk.TreeViewColumn() + col.set_title(self.column_names[0]) + render_pixbuf = gtk.CellRendererPixbuf() + col.pack_start(render_pixbuf, expand=False) + col.add_attribute(render_pixbuf, 'pixbuf', 0) + render_text = gtk.CellRendererText() + col.pack_start(render_text, expand=True) + col.add_attribute(render_text, 'text', 1) + col.set_fixed_width(20) + self.treeview.append_column(col) + cell = gtk.CellRendererText() + col = gtk.TreeViewColumn(self.column_names[1], cell) + col.add_attribute(cell, 'text', 2) + self.treeview.append_column(col) + cell = gtk.CellRendererText() + col = gtk.TreeViewColumn(self.column_names[2], cell) + col.add_attribute(cell, 'text', 3) + self.treeview.append_column(col) + + def get_datastore_list(self, next=False): + dslist = [] + self.journal_model.clear() + ds_list = [] + num_found = 0 + mime_list = [self._activity.MIME_TYPE,'application/zip'] + + #build 650 doesn't seem to understand correctly the dictionary with a list right hand side + info = self._activity.util.sugar_version() + if len(info)>0: + (major,minor,micro,release) = info + _logger.debug('sugar version major:%s minor:%s micro:%s release:%s'%info) + else: + _logger.debug('sugar version failure') + minor = 70 + try: + if minor > 80: + (ds_list,num_found) = datastore.find({'mime_type': mime_list}) + else: + (results,count) = datastore.find({'mime_type': self._activity.MIME_TYPE}) + ds_list.extend(results) + num_found += count + (results,count) = datastore.find({'mime_type': 'application/zip'}) + ds_list.extend(results) + except Exception,e: + _logger.error('datastore error %s'%e) + return [] + if num_found < self.limit: + self.journal_max = self.journal_page_num * self.journal_page_size + num_found + _logger.debug( 'datastoretree-get_datastore_list: count= %s'%num_found) + keys = ('title','size','timestamp','activity','package','mime_type','file_path') + for jobject in ds_list: + itemlist = [None,] + datastoredict=jobject.get_metadata().get_dictionary() #get the property dictionary + src = jobject.get_file_path() #returns the full path of the file + datastoredict['object_id'] = jobject.object_id + + if False: #if src null, there is no file related to this meta data + jobject.destroy() + continue #go get the next iterations + #add in the info that we intend to use + if src: + info = os.stat(src) #get the directory information about this file + datastoredict['size'] = info.st_size + else: + datastoredict['size'] = 0 + datastoredict['file_path'] = src + for key in keys: + if datastoredict.has_key(key): + if key == 'timestamp': + pkg = time.strftime('%Y-%m-%d %H:%M:%S',time.gmtime(float(datastoredict[key]))) + elif key == 'title': + pkg = datastoredict[key][:18] + else: + pkg = '%s'%(datastoredict[key]) + else: + pkg = '' + itemlist.append(pkg) + itemlist.append(datastoredict['title']) + itemlist.append(jobject.object_id) + text = 'Mime_type: %s, Journal ID: %s, Bundle: %s'%(datastoredict.get('mime_type',''), + datastoredict.get('object_id',''), + datastoredict.get('package','')) + itemlist.append(text) + #_logger.debug('journal tooltip:%s'%text) + dslist.append(itemlist) + jobject.destroy() + return dslist + + def new_directory(self,piter = None, next=True): + journal_list = self.get_datastore_list(next) + for journal_selected_data in journal_list: + appended_iter = self.journal_model.append(piter, journal_selected_data ) + model=self.journal_model + appended_path = model.get_path(appended_iter) + + def file_pixbuf(self, filename): + folderpb = self.get_icon_pixbuf('STOCK_DIRECTORY') + filepb = self.get_icon_pixbuf('STOCK_FILE') + if os.path.isdir(filename): + pb = folderpb + else: + pb = filepb + return pb + + def get_icon_pixbuf(self, stock): + return self.treeview.render_icon(stock_id=getattr(gtk, stock), + size=gtk.ICON_SIZE_MENU, + detail=None) + + def get_treeview(self): + return self.treeview + + def newer_in_journal_cb(self,button): + _logger.debug('younger call back') + self.get_datastore_list(next=False) + + def older_in_journal_cb(self,button): + _logger.debug('older call back') + self.get_datastore_list(next=True) + + def datastore_row_activated_cb(self): + self.load_from_journal_cb() + + def display_tooltip(self, widget,x,y,mode,tooltip): + _logger.debug('in display_tooltip') + tooltip.show() + return True + +class Icon_Panel(gtk.Window): + + def __init__(self, icon): + gtk.Window.__init__(self) + + self.set_decorated(False) + self.set_resizable(False) + self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG) + + self.set_border_width(0) + + self.props.accept_focus = False + + #Setup estimate of width, height + w, h = gtk.icon_size_lookup(gtk.ICON_SIZE_LARGE_TOOLBAR) + self._width = w + self._height = h + + self.connect('size-request', self._size_request_cb) + + screen = self.get_screen() + screen.connect('size-changed', self._screen_size_changed_cb) + + self._button = gtk.Button() + self._button.set_relief(gtk.RELIEF_NONE) + + self._icon = Icon( icon_size=gtk.ICON_SIZE_LARGE_TOOLBAR) + self._button.add(self._icon) + + self._button.show() + self.add(self._button) + _logger.debug('completed init of icon_panel') + + def connect_button_press(self, cb): + self._button.connect('button-press-event', cb) + + def _reposition(self): + x = gtk.gdk.screen_width() - self._width + self.move(x, 347) + + def _size_request_cb(self, widget, req): + self._width = req.width + self._height = req.height + self._reposition() + + def _screen_size_changed_cb(self, screen): + self._reposition() + |