def __init__(self, core: ApartCore, z_options: List[str]): Gtk.Stack.__init__(self) self.core = core self.z_options = z_options self.get_style_context().add_class('progress-view') self.next_notification = NotificationHelper() self.nothing_label = Gtk.Label('Select a partition to clone', xalign=0.5, vexpand=True) self.nothing_label.get_style_context().add_class('dim-label') self.add(self.nothing_label) self.content = Gtk.VBox(valign=Gtk.Align.START) self.add(self.content) self.running_jobs_label = Gtk.Label('Running', halign=Gtk.Align.START) self.running_jobs_label.get_style_context().add_class('section-title') self.content.add(self.running_jobs_label) # self.running_jobs: Dict[str, RunningJob] = {} <- not compatible with 3.5 self.running_jobs = {} self.running_jobs_grid = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL, column_spacing=6, row_spacing=6) self.running_jobs_grid.get_style_context().add_class('jobs') self.content.add(self.running_jobs_grid) # self.finished_jobs: Dict[str, FinishedJob] = {} <- not compatible with 3.5 self.finished_jobs = {} self.finished_jobs_label = Gtk.Label('History', halign=Gtk.Align.START) self.finished_jobs_label.get_style_context().add_class('section-title') self.content.add(self.finished_jobs_label) self.finished_jobs_grid = Gtk.Grid( orientation=Gtk.Orientation.VERTICAL, column_spacing=6) self.finished_jobs_grid.get_style_context().add_class('finished-jobs') self.content.add(self.finished_jobs_grid) self.show_all() self.listener = MessageListener( message_predicate=lambda m: m['type'] in ['clone', 'restore', 'clone-failed', 'restore-failed'], on_message=lambda m: GLib.idle_add(self.on_job_message, m), listen_to=core) GLib.timeout_add(interval=1000, function=self.update_jobs) self.connect('destroy', self.save_history) GLib.idle_add(self.read_history)
def __init__(self): Gtk.Window.__init__(self, title='apart') self.dying = False self.status_listener = MessageListener( on_message=lambda m: GLib.idle_add(self.on_status_msg, m), message_predicate=lambda m: m['type'] == 'status') self.core = ApartCore( listeners=[self.status_listener], on_finish=lambda code: GLib.idle_add(self.on_delete)) self.sources = None self.sources_interest = [] # array of callbacks on sources update self.set_default_size(height=300, width=300 * 16 / 9) self.loading_body = LoadingBody() self.clone_body = None self.add(self.loading_body) self.connect('delete-event', self.on_delete) self.set_icon_name('apart')
def delete_image(self, arg=None): filename = self.msg['destination'] dialog = OkCancelDialog(self.delete_image_btn.get_toplevel(), header='Delete image file', text="Delete {}?".format(filename), message_type=Gtk.MessageType.WARNING) user_response = dialog.run() dialog.destroy() if user_response != Gtk.ResponseType.OK: return for btn in self.buttons.get_children(): btn.set_sensitive(False) btn.set_tooltip_text('Deleting...') def on_response(msg: Dict): if msg['type'] == 'deleted-clone': self.forget() else: # failed err_dialog = OkDialog(self.delete_image_btn.get_toplevel(), header='Delete failed', text='Could not delete {}: {}'.format( filename, msg['error']), message_type=Gtk.MessageType.ERROR) err_dialog.run() err_dialog.destroy() for btn in self.buttons.get_children(): btn.set_sensitive(True) self.forget_btn.set_tooltip_text(FORGET_TIP) self.rerun_btn.set_tooltip_text(RERUN_TIP) self.delete_image_btn.set_tooltip_text(DELETE_TIP) MessageListener( message_predicate=lambda m: m['type'] in ['deleted-clone', 'delete-clone-failed'] and m['file'] == filename, on_message=lambda m: GLib.idle_add(on_response, m), listen_to=self.core, one_time=True) self.core.send('type: delete-clone\nfile: ' + filename)
class Window(Gtk.Window): def __init__(self): Gtk.Window.__init__(self, title='apart') self.dying = False self.status_listener = MessageListener( on_message=lambda m: GLib.idle_add(self.on_status_msg, m), message_predicate=lambda m: m['type'] == 'status') self.core = ApartCore( listeners=[self.status_listener], on_finish=lambda code: GLib.idle_add(self.on_delete)) self.sources = None self.sources_interest = [] # array of callbacks on sources update self.set_default_size(height=300, width=300 * 16 / 9) self.loading_body = LoadingBody() self.clone_body = None self.add(self.loading_body) self.connect('delete-event', self.on_delete) self.set_icon_name('apart') def register_interest_in_sources(self, on_update_callback: Callable[[Dict], None]): """ Register a callback to be run every time a new sources message is received Note callbacks are run on the GTK main thread Run callback immediately if sources are available """ if self.sources: on_update_callback(self.sources) self.sources_interest.append(on_update_callback) def on_status_msg(self, msg: Dict): if msg['status'] == 'dying': self.on_delete() elif msg['status'] == 'started': if msg['sources']: self.sources = msg['sources'] self.clone_body = CloneBody( self.core, sources=msg['sources'], z_options=msg['compression_options']) self.remove(self.loading_body) self.add(self.clone_body) self.clone_body.show_all() else: err_dialog = OkDialog(self, text='No partitions found', ok_button_text='Exit', message_type=Gtk.MessageType.ERROR) err_dialog.run() err_dialog.destroy() self.on_delete() elif self.clone_body and msg['status'] == 'running': self.sources = msg['sources'] # TODO move to sources_interest with a reliable way of getting toplevel self.clone_body.update_sources(msg['sources']) for callback in self.sources_interest: callback(self.sources) def on_delete(self, *args): if self.dying: return self.status_listener.stop_listening() if self.clone_body: self.remove(self.clone_body) self.clone_body.destroy() self.add(self.loading_body) self.core.kill() self.destroy() Gtk.main_quit() self.dying = True