# # partition_gui.py: allows the user to choose how to partition their disks # # Copyright (C) 2001, 2002 Red Hat, Inc. All rights reserved. # # 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, see . # # Author(s): Matt Wilson # Michael Fulbright # import gobject import gtk import gtk.glade try: import gnomecanvas except ImportError: import gnome.canvas as gnomecanvas import pango import gui import parted import string import types import copy import storage from iw_gui import * from flags import flags import datacombo import lvm_dialog_gui as l_d_g import raid_dialog_gui as r_d_g import partition_dialog_gui as p_d_g from partIntfHelpers import * from constants import * from partition_ui_helpers_gui import * from storage.partitioning import doPartitioning from storage.partitioning import hasFreeDiskSpace from storage.devicelibs import lvm from storage.devices import devicePathToName, PartitionDevice import gettext _ = lambda x: gettext.ldgettext("anaconda", x) P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z) import logging log = logging.getLogger("anaconda") STRIPE_HEIGHT = 35.0 LOGICAL_INSET = 3.0 TREE_SPACING = 2 # XXX hack but will work for now if gtk.gdk.screen_width() > 640: CANVAS_WIDTH = 490 else: CANVAS_WIDTH = 390 CANVAS_HEIGHT = 200 MODE_ADD = 1 MODE_EDIT = 2 class Slice: """Class representing a slice of a stripe. parent -- the stripe that the slice belongs too. text -- what will appear in the slice type -- either SLICE or SUBSLICE xoffset -- start percentage xlength -- a length percentage dcCB -- function that is called on a double click. cCB -- function that is called when one click (selected) sel_col -- color when selected unsel_col -- color when unselected obj -- some python object that is related to this slice. selected -- initial state of slice. """ SLICE = 0 SUBSLICE = 1 CONTAINERSLICE = 2 def __init__(self, parent, text, type, xoffset, xlength, dcCB=lambda: None, cCB=lambda x: None, sel_col="cornsilk1", unsel_col="white", obj = None, selected = False): self.text = text self.type = type self.xoffset = xoffset self.xlength = xlength self.parent = parent self.dcCB = dcCB self.cCB = cCB self.sel_col = sel_col self.unsel_col = unsel_col self.obj = obj self.selected = selected def eventHandler(self, widget, event): if event.type == gtk.gdk.BUTTON_PRESS: if event.button == 1: self.select() self.cCB(self.obj) elif event.type == gtk.gdk._2BUTTON_PRESS: #self.select() self.dcCB() return True def putOnCanvas(self): pgroup = self.parent.getGroup() self.group = pgroup.add(gnomecanvas.CanvasGroup) self.box = self.group.add(gnomecanvas.CanvasRect) self.group.connect("event", self.eventHandler) canvas_text = self.group.add(gnomecanvas.CanvasText, font="sans", size_points=8) xoffset = self.xoffset * CANVAS_WIDTH xlength = self.xlength * CANVAS_WIDTH if self.type == Slice.SUBSLICE: yoffset = 0.0 + LOGICAL_INSET yheight = STRIPE_HEIGHT - (LOGICAL_INSET * 2) texty = 0.0 else: yoffset = 0.0 yheight = STRIPE_HEIGHT texty = LOGICAL_INSET if self.selected: fill_color = self.sel_col else: fill_color = self.unsel_col self.group.set(x=xoffset, y=yoffset) self.box.set(x1=0.0, y1=0.0, x2=xlength, y2=yheight, fill_color=fill_color, outline_color='black', width_units=1.0) canvas_text.set(x=2.0, y=texty + 2.0, text=self.text, fill_color='black', anchor=gtk.ANCHOR_NW, clip=True, clip_width=xlength-1, clip_height=yheight-1) def shutDown(self): self.parent = None if self.group: self.group.destroy() self.group = None def select(self): for slice in self.parent.slices: slice.deselect() self.selected = True if self.group and self.box: if self.type != Slice.CONTAINERSLICE: self.group.raise_to_top() self.box.set(outline_color="red") self.box.set(fill_color=self.sel_col) def deselect(self): self.selected = False if self.box: self.box.set(outline_color="black", fill_color=self.unsel_col) class Stripe(object): """ canvas -- the canvas where everything goes text -- the text that will appear on top of the stripe yoff -- its the position in the y axis where this stripe should be drawn dcCB -- function that should be called on a double click obj -- some python object that is related to this stripe """ def __init__(self, canvas, text, dcCB, obj = None): self.canvas_text = None self.canvas = canvas self.text = text self.group = None self._slices = [] self.dcCB = dcCB self.selected = None self.obj = obj def putOnCanvas(self, yoff): """ returns the yposition after drawhing this stripe. """ # We set the text for the stripe. self.canvas_text = self.canvas.root().add(gnomecanvas.CanvasText, x=0.0, y=yoff, font="sans", size_points=9) self.canvas_text.set(text=self.text, fill_color='black', anchor=gtk.ANCHOR_NW, weight=pango.WEIGHT_BOLD) (xxx1, yyy1, xxx2, yyy2) = self.canvas_text.get_bounds() textheight = yyy2 - yyy1 + 2 self.group = self.canvas.root().add(gnomecanvas.CanvasGroup, x=0, y=yoff+textheight) self.group.add(gnomecanvas.CanvasRect, x1=0.0, y1=0.0, x2=CANVAS_WIDTH, y2=STRIPE_HEIGHT, fill_color='green', outline_color='grey71', width_units=1.0) self.group.lower_to_bottom() # We paint all the container slices first. So the contained slices # actually show up. for slice in [s for s in self.slices if s.type == Slice.CONTAINERSLICE]: slice.putOnCanvas() # After painting the containers we paint the rest. for slice in [s for s in self.slices if s.type != Slice.CONTAINERSLICE]: slice.putOnCanvas() # 10 is a separator space. return yoff + STRIPE_HEIGHT+textheight+10 def shutDown(self): for slice in self.slices: slice.shutDown() self._slices = [] if self.canvas_text: self.canvas_text.destroy() if self.group: self.group.destroy() self.group = None def getGroup(self): return self.group @property def slices(self): return self._slices def addSlice(self, new_slice): # check to see if they overlap. for slice in self.slices: # Container slices and subslices can overlap. if new_slice.type+slice.type == Slice.CONTAINERSLICE+Slice.SUBSLICE: continue if new_slice.xoffset > slice.xoffset \ and new_slice.xoffset < slice.xoffset + slice.xlength: # there is a colission, we cannot add. return self._slices.append(new_slice) def getSelectedSlice(self): for slice in self.slices: if slice.selected: return slice return None class StripeGraph: """ This class will only handle one stripe.""" __canvas = None def __init__(self): self.stripe = None self.next_ypos = 0.0 def __del__(self): self.shutDown() def shutDown(self): if self.stripe: self.stripe.shutDown() self.stripe = None self.next_ypos = 0.0 @classmethod def getCanvas(cls): if not StripeGraph.__canvas: StripeGraph.__canvas = gnomecanvas.Canvas() return StripeGraph.__canvas def setDisplayed(self, obj): # Check to see if we already have the correct obj displayed. if self.getDisplayed() and self.getDisplayed().obj == obj: return if self.stripe: self.stripe.shutDown() self.stripe = self._createStripe(obj) self.stripe.putOnCanvas(0) # Trying to center the picture. apply(self.getCanvas().set_scroll_region, self.getCanvas().root().get_bounds()) def getDisplayed(self): return self.stripe def selectSliceFromObj(self, obj): """Search for obj in the slices """ stripe = self.getDisplayed() if not stripe: return for slice in stripe.slices: # There is a part object in each slice. if not slice.obj: continue if obj == slice.obj and not slice.selected: slice.select() break def _createStripe(self, obj): #This method needs to be overridden pass def getSelectedSlice(self): return self.stripe.getSelectedSlice() class DiskStripeGraph(StripeGraph): """Handles the creation of a bar view for the 'normal' devies. storage -- the storage object cCB -- call back function used when the user clicks on a slice. This function is passed a device object when its executed. dcCB -- call back function used when the user double clicks on a slice. drive -- drive to display """ def __init__(self, storage, drive=None, cCB=lambda x:None, dcCB=lambda:None): StripeGraph.__init__(self) self.storage = storage self.cCB = cCB self.dcCB = dcCB # Define the default colors per partition type. self.part_type_colors = \ {"sel_logical": "cornsilk1", "unsel_logical": "white", "sel_extended": "cornsilk1", "unsel_extended": "white", "sel_normal": "cornsilk1", "unsel_normal": "white", "sel_freespace": "grey88", "unsel_freespace": "grey88"} if drive: self.setDisplayed(drive) def _createStripe(self, drive): # Create the stripe drivetext = _("Drive %(drive)s (%(size)-0.f MB) (Model: %(model)s)") \ % {'drive': drive.path, 'size': drive.size, 'model': drive.model} stripe = Stripe(self.getCanvas(), drivetext, self.dcCB, obj = drive) # Free Extended Calculation # Free slice/partition in the extended partition "free space". If there # is space between the last logical partition and the ending of the # extended partition we create a "free space" in the extended part. # Create the slices. # These offsets are where the partition/slices end. 0