Example #1
0
    def __init__(self, userdata_inst, startup_app=None):
        self.userdata = userdata_inst
        self.startup_app = startup_app
        self.builder = gtk.Builder()
        
        # https://bugzilla.gnome.org/show_bug.cgi?id=574520
        self.builder.set_translation_domain('mound')
        
        try:
            self.builder.add_from_file('data/mound.ui')
        except:
            self.builder.add_from_file('/usr/share/mound-data-manager/mound.ui')

        gtk.window_set_default_icon_name('mound-data-manager')

        # widgets to load
        load = [
            'win_main',
            'item_details',
            'item_delete',
            'item_userdata_update',
            'item_quit',
            'item_lp_help',
            'item_lp_translate',
            'item_lp_bug',
            'item_about',
            'dlg_about',
            'apps_scroll',
            'lst_applications',
            'apps_treeview',
            'img_appicon',
            'lbl_title',
            'lbl_app_details',
        ]
        for item in load:
            self.__dict__[item] = self.builder.get_object(item)

        self.snapshots_ui = SnapshotsUI(self.builder)
        self.details_ui = DetailsUI(self.builder)
        
        # signals
        self.item_quit.connect('activate', gtk.main_quit)
        self.item_lp_help.connect('activate', lambda s: Popen(['xdg-open', 'https://answers.launchpad.net/mound']))
        self.item_lp_translate.connect('activate', lambda s: Popen(['xdg-open', 'http://www.transifex.net/projects/p/mound/']))
        self.item_lp_bug.connect('activate', lambda s: Popen(['xdg-open', 'https://bugs.launchpad.net/mound/+filebug']))
        self.item_about.connect('activate', lambda s: self.dlg_about.run())
        self.dlg_about.connect('response', lambda s, r: s.hide())
        
        try:
            from Mound.info import version
            self.dlg_about.set_version(version)
        except: pass

        # connect some signals together
        self.apps_treeview.connect('cursor-changed', self.update_ui)
        self.apps_treeview_sel = self.apps_treeview.get_selection()
        self.item_details.connect('activate',
                lambda s: self.details_ui.show_details(self.selected_app))
        self.item_delete.connect('activate', self.delete_application_data)
        self.item_userdata_update.connect('activate', self.update_userdata)

        # update our ui
        self.update_ui()
        
        # finally show the window
        self.win_main.connect('focus-in-event', self.update_ui)
        self.win_main.connect('destroy', gtk.main_quit)
        self.win_main.show_all()

        # set the startup application when ready
        gobject.idle_add(self.set_startup_application)
Example #2
0
class MainUI:
    """
    Main window UI procedures.
    
    Takes an instance of Mound, which is used to load applications.
    """

    selected_app = None

    def __init__(self, userdata_inst, startup_app=None):
        self.userdata = userdata_inst
        self.startup_app = startup_app
        self.builder = gtk.Builder()
        
        # https://bugzilla.gnome.org/show_bug.cgi?id=574520
        self.builder.set_translation_domain('mound')
        
        try:
            self.builder.add_from_file('data/mound.ui')
        except:
            self.builder.add_from_file('/usr/share/mound-data-manager/mound.ui')

        gtk.window_set_default_icon_name('mound-data-manager')

        # widgets to load
        load = [
            'win_main',
            'item_details',
            'item_delete',
            'item_userdata_update',
            'item_quit',
            'item_lp_help',
            'item_lp_translate',
            'item_lp_bug',
            'item_about',
            'dlg_about',
            'apps_scroll',
            'lst_applications',
            'apps_treeview',
            'img_appicon',
            'lbl_title',
            'lbl_app_details',
        ]
        for item in load:
            self.__dict__[item] = self.builder.get_object(item)

        self.snapshots_ui = SnapshotsUI(self.builder)
        self.details_ui = DetailsUI(self.builder)
        
        # signals
        self.item_quit.connect('activate', gtk.main_quit)
        self.item_lp_help.connect('activate', lambda s: Popen(['xdg-open', 'https://answers.launchpad.net/mound']))
        self.item_lp_translate.connect('activate', lambda s: Popen(['xdg-open', 'http://www.transifex.net/projects/p/mound/']))
        self.item_lp_bug.connect('activate', lambda s: Popen(['xdg-open', 'https://bugs.launchpad.net/mound/+filebug']))
        self.item_about.connect('activate', lambda s: self.dlg_about.run())
        self.dlg_about.connect('response', lambda s, r: s.hide())
        
        try:
            from Mound.info import version
            self.dlg_about.set_version(version)
        except: pass

        # connect some signals together
        self.apps_treeview.connect('cursor-changed', self.update_ui)
        self.apps_treeview_sel = self.apps_treeview.get_selection()
        self.item_details.connect('activate',
                lambda s: self.details_ui.show_details(self.selected_app))
        self.item_delete.connect('activate', self.delete_application_data)
        self.item_userdata_update.connect('activate', self.update_userdata)

        # update our ui
        self.update_ui()
        
        # finally show the window
        self.win_main.connect('focus-in-event', self.update_ui)
        self.win_main.connect('destroy', gtk.main_quit)
        self.win_main.show_all()

        # set the startup application when ready
        gobject.idle_add(self.set_startup_application)

    def set_startup_application(self):
        """
        Set a selected application on startup. This must be called after
        the list is ready and gtk is idle.
        """
        if self.startup_app:
            i = 0
            for row in self.lst_applications:
                if self.lst_applications.get_value(row.iter, 0) == self.startup_app:
                    break
                i += 1
            self.apps_treeview.set_cursor(str(i))
        return False

    def load_applications(self):
        """
        Load the applications from the Mound instance and add them to our
        display.
        """
        for app_name in self.userdata.applications:
            app = self.userdata.applications[app_name]
            self.lst_applications.append((app.name, app.full_name, app.icon))
        self.lst_applications.set_sort_column_id(1, gtk.SORT_ASCENDING) 

    def delete_application_data(self, source=None):
        """
        Trigger a dialog to delete data for an application. The user is
        prompted to take a snapshot beforehand.
        """
        dlg_confirm = gtk.MessageDialog(self.win_main, 0, gtk.MESSAGE_WARNING)
        txt = "<i>" + _("You may want to take a snapshot before continuing.") + "</i>\n\n"
        txt += _("Are you sure you want to destroy all data, settings, and preferences for %(application)s?") % {'application': "<b>" + self.selected_app.full_name + "</b>"}
        dlg_confirm.set_markup(txt)
        dlg_confirm.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        dlg_confirm.add_button(_("Take Snapshot"), 10)
        dlg_confirm.add_button(gtk.STOCK_DELETE, gtk.RESPONSE_OK)
        dlg_confirm.connect('response', response)

        resp = dlg_confirm.run()
        if resp == gtk.RESPONSE_OK:
            self.selected_app.delete_data()
            self.selected_app.calculate_size(force=True)
            self.update_ui()
        elif resp == 10:
            dlg_confirm.hide()
            self.snapshots_ui.show_snapshots(self.selected_app)
            self.snapshots_ui.new_snapshot_ui()
        dlg_confirm.destroy()
    
    def update_ui(self, *args, **kwargs):
        """
        Update the bottom panel with information about the selected
        application. Disable certain buttons if their features are not
        available for use on the application.
        """
        model, treeiter = self.apps_treeview_sel.get_selected()
        if treeiter:
            # find the selected application
            selected = self.lst_applications.get_value(treeiter, 0)
            app = self.selected_app = self.userdata.applications[selected]
            # update the title & icon
            self.lbl_title.props.label = app.full_name
            self.img_appicon.set_from_pixbuf(app.icon)
            # check if it's running
            running = self.selected_app.check_running()
            txt = []
            if running:
                txt.append("<b>" + _("Please close %(application)s before managing it.") % {'application': self.selected_app.full_name} + "</b>")
                self.item_delete.props.sensitive = False
            else:
                self.item_delete.props.sensitive = True
            # grab the size
            app.calculate_size()
            if app.data_size > 0:
                size = format_size(app.data_size)
                size_info = _("This application is using %(size)s of space.") % {'size': "<b>" + size + "</b>"}
            else:
                size_info = _("This application is not storing any data.")
                self.item_delete.props.sensitive = False
            # find the number of snapshots
            app.load_snapshots()
            num_snapshots = len(app.snapshots)
            if num_snapshots == 1:
                size_info += "\n" + _("One snapshot is available.")
            elif num_snapshots > 1:
                size_info += "\n" + _("%(num)d snapshots are available.") % {'num': num_snapshots}
            txt.append(size_info)
            # check for errors
            if app.errors:
                txt = ["<b>" + _("A problem occurred. This application cannot be managed.") + "</b>"]
                self.item_delete.props.sensitive = False
            self.lbl_app_details.props.label = "\n\n".join(txt)
            self.item_details.props.sensitive = True
            # show & update snapshots
            self.snapshots_ui.show_snapshots(self.selected_app)
        else:
            self.selected_app = None
            self.lbl_app_details.props.label = ""
            self.lbl_title.props.label = _("Select an Application")
            self.img_appicon.set_from_stock('gtk-dialog-question', gtk.ICON_SIZE_DND);
            self.item_delete.props.sensitive = False
            self.item_details.props.sensitive = False
            self.snapshots_ui.show_snapshots(None)

    def update_userdata(self, source=None):
        """
        Download new userdata defaults from the Internet, and merge them
        with our local catalog. Saves the merged library to ~/.config/userdata
        """
        def idle_callback():
            self.userdata.default_locations.load_from_url(USERDATA_UPDATE_URL)
            self.userdata.default_locations.write_to_file(os.path.join(XDGCONFIG, 'userdata'))
            os.execl(sys.executable, sys.executable, *sys.argv)
            
        dlg_update = gtk.MessageDialog(self.win_main, 0, gtk.MESSAGE_QUESTION,
                message_format=_("Mound will now connect to the Internet to download updates for the applications it knows about."))
        dlg_update.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        dlg_update.add_button(gtk.STOCK_REFRESH, gtk.RESPONSE_OK)
        self.win_main.hide()
        if dlg_update.run() == gtk.RESPONSE_OK:
            # disable the interface
            watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
            dlg_update.get_window().set_cursor(watch)
            for c in dlg_update.get_children():
                c.props.sensitive = False
            # idle_callback defined above
            gobject.idle_add(idle_callback)
        else:
            dlg_update.destroy()
            self.win_main.show()