def initialize(self): """ The initialize method that is called after the instance is created. The difference between __init__ and this method is that this may take a long time and thus could be called in a separated thread. :see: pyanaconda.ui.common.UIObject.initialize """ NormalSpoke.initialize(self) self.initialize_start() config.log_dir = "/tmp" box = self.builder.get_object("BlivetGuiViewport") self._label_actions = self.builder.get_object("summary_label") self._button_reset = self.builder.get_object("resetAllButton") self._button_undo = self.builder.get_object("undoLastActionButton") self._client = BlivetGUIAnacondaClient() self._blivetgui = BlivetGUIAnaconda(self._client, self, box) # this needs to be done when the spoke is already "realized" self.entered.connect(self._blivetgui.ui_refresh) # set up keyboard shurtcuts for blivet-gui (and unset them after # user lefts the spoke) self.entered.connect(self._blivetgui.set_keyboard_shortcuts) self.exited.connect(self._blivetgui.unset_keyboard_shortcuts) self.initialize_done()
class BlivetGuiSpoke(NormalSpoke, StorageCheckHandler): ### class attributes defined by API ### # list all top-level objects from the .glade file that should be exposed # to the spoke or leave empty to extract everything builderObjects = ["blivetGuiSpokeWindow"] # the name of the main window widget mainWidgetName = "blivetGuiSpokeWindow" # name of the .glade file in the same directory as this source uiFile = "spokes/blivet_gui.glade" # category this spoke belongs to category = SystemCategory # title of the spoke (will be displayed on the hub) title = CN_("GUI|Spoke", "_Blivet-GUI Partitioning") helpFile = "blivet-gui/index.page" ### methods defined by API ### def __init__(self, data, storage, payload): """ :see: pyanaconda.ui.common.Spoke.__init__ :param data: data object passed to every spoke to load/store data from/to it :type data: pykickstart.base.BaseHandler :param storage: object storing storage-related information (disks, partitioning, bootloader, etc.) :type storage: blivet.Blivet :param payload: object storing payload-related information :type payload: pyanaconda.payload.Payload """ self._error = None self._back_already_clicked = False self._label_actions = None self._button_reset = None self._button_undo = None self._client = None self._blivetgui = None self._partitioning = None self._device_tree = None self._storage_module = STORAGE.get_proxy() StorageCheckHandler.__init__(self) NormalSpoke.__init__(self, data, storage, payload) @property def label_actions(self): """The summary label. This property is required by Blivet-GUI. """ return self._label_actions def initialize(self): """ The initialize method that is called after the instance is created. The difference between __init__ and this method is that this may take a long time and thus could be called in a separated thread. :see: pyanaconda.ui.common.UIObject.initialize """ NormalSpoke.initialize(self) self.initialize_start() config.log_dir = "/tmp" box = self.builder.get_object("BlivetGuiViewport") self._label_actions = self.builder.get_object("summary_label") self._button_reset = self.builder.get_object("resetAllButton") self._button_undo = self.builder.get_object("undoLastActionButton") self._client = BlivetGUIAnacondaClient() self._blivetgui = BlivetGUIAnaconda(self._client, self, box) # this needs to be done when the spoke is already "realized" self.entered.connect(self._blivetgui.ui_refresh) # set up keyboard shurtcuts for blivet-gui (and unset them after # user lefts the spoke) self.entered.connect(self._blivetgui.set_keyboard_shortcuts) self.exited.connect(self._blivetgui.unset_keyboard_shortcuts) self.initialize_done() def refresh(self): """ The refresh method that is called every time the spoke is displayed. It should update the UI elements according to the contents of self.data. :see: pyanaconda.ui.common.UIObject.refresh """ for thread_name in [THREAD_EXECUTE_STORAGE, THREAD_STORAGE]: threadMgr.wait(thread_name) if not self._partitioning: # Create the partitioning now. It cannot by done earlier, because # the storage spoke would use it as a default partitioning. self._partitioning = create_partitioning( PARTITIONING_METHOD_BLIVET) self._device_tree = STORAGE.get_proxy( self._partitioning.GetDeviceTree()) self._back_already_clicked = False self._client.initialize(self._partitioning.SendRequest) self._blivetgui.initialize() # if we re-enter blivet-gui spoke, actions from previous visit were # not removed, we need to update number of blivet-gui actions self._blivetgui.set_actions(self._client.get_actions()) def apply(self): """ The apply method that is called when the spoke is left. It should update the contents of self.data with values set in the GUI elements. """ pass @property def indirect(self): return True # This spoke has no status since it's not in a hub @property def status(self): return None def clear_errors(self): self._error = None self.clear_info() def _do_check(self): self.clear_errors() StorageCheckHandler.errors = [] StorageCheckHandler.warnings = [] try: log.debug("Generating updated storage configuration") task_path = self._partitioning.ConfigureWithTask() task_proxy = STORAGE.get_proxy(task_path) sync_run_task(task_proxy) except BootloaderConfigurationError as e: log.error("Storage configuration failed: %s", e) StorageCheckHandler.errors = [str(e)] reset_bootloader() else: log.debug("Checking storage configuration...") task_path = self._partitioning.ValidateWithTask() task_proxy = STORAGE.get_proxy(task_path) sync_run_task(task_proxy) result = unwrap_variant(task_proxy.GetResult()) report = ValidationReport.from_structure(result) log.debug("Validation has been completed: %s", report) StorageCheckHandler.errors = report.error_messages StorageCheckHandler.warnings = report.warning_messages if report.is_valid(): self._storage_module.ApplyPartitioning( get_object_path(self._partitioning)) if self.errors: self.set_warning( _("Error checking storage configuration. <a href=\"\">Click for details</a> or press Done again to continue." )) elif self.warnings: self.set_warning( _("Warning checking storage configuration. <a href=\"\">Click for details</a> or press Done again to continue." )) # on_info_bar_clicked requires self._error to be set, so set it to the # list of all errors and warnings that storage checking found. self._error = "\n".join(self.errors + self.warnings) return self._error == "" def activate_action_buttons(self, activate): self._button_undo.set_sensitive(activate) self._button_reset.set_sensitive(activate) ### handlers ### def on_info_bar_clicked(self, *args): log.debug("info bar clicked: %s (%s)", self._error, args) if not self._error: return dlg = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CLOSE, message_format=str(self._error)) dlg.set_decorated(False) with self.main_window.enlightbox(dlg): dlg.run() dlg.destroy() def on_back_clicked(self, button): # Clear any existing errors self.clear_errors() # If back has been clicked on once already and no other changes made on the screen, # run the storage check now. This handles displaying any errors in the info bar. if not self._back_already_clicked: self._back_already_clicked = True # If we hit any errors while saving things above, stop and let the # user think about what they have done if self._error is not None: return if not self._do_check(): return dialog = ActionSummaryDialog(self.data, self._device_tree) dialog.refresh() if dialog.actions: with self.main_window.enlightbox(dialog.window): rc = dialog.run() if rc != 1: # Cancel. Stay on the blivet-gui screen. return NormalSpoke.on_back_clicked(self, button) def on_summary_button_clicked(self, _button): self._blivetgui.show_actions() def on_undo_action_button_clicked(self, _button): self._blivetgui.actions_undo() # This callback is for the button that just resets the UI to anaconda's # current understanding of the disk layout. def on_reset_button_clicked(self, *args): msg = _( "Continuing with this action will reset all your partitioning selections " "to their current on-disk state.") dlg = Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL, message_type=Gtk.MessageType.WARNING, buttons=Gtk.ButtonsType.NONE, message_format=msg) dlg.set_decorated(False) dlg.add_buttons( C_("GUI|Custom Partitioning|Reset Dialog", "_Reset selections"), 0, C_("GUI|Custom Partitioning|Reset Dialog", "_Preserve current selections"), 1) dlg.set_default_response(1) with self.main_window.enlightbox(dlg): rc = dlg.run() dlg.destroy() if rc == 0: self.refresh() self._blivetgui.reload() # XXX: Reset currently preserves actions set in previous runs # of the spoke, so we need to 're-add' these to the ui self._blivetgui.set_actions(self._client.get_actions())