1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import os
24 import gobject
25 import gtk
26 import gtk.glade
27 try:
28 import gnomecanvas
29 except ImportError:
30 import gnome.canvas as gnomecanvas
31 import pango
32 from pyanaconda import gui
33 import parted
34 import string
35 import types
36 import copy
37 from decimal import Decimal
38
39 from pyanaconda import storage
40 from iw_gui import *
41 from pyanaconda.flags import flags
42
43 import datacombo
44 import lvm_dialog_gui as l_d_g
45 import raid_dialog_gui as r_d_g
46 import partition_dialog_gui as p_d_g
47
48 from pyanaconda.partIntfHelpers import *
49 from pyanaconda.constants import *
50 from partition_ui_helpers_gui import *
51 from pyanaconda.storage.partitioning import doPartitioning
52 from pyanaconda.storage.devicelibs import lvm
53 from pyanaconda.storage.devices import devicePathToName
54 from pyanaconda.storage.devices import PartitionDevice
55 from pyanaconda.storage.devices import BTRFSVolumeDevice
56 from pyanaconda.storage.devices import deviceNameToDiskByPath
57 from pyanaconda.storage.errors import DeviceNotFoundError
58
59 import gettext
60 _ = lambda x: gettext.ldgettext("anaconda", x)
61 P_ = lambda x, y, z: gettext.ldngettext("anaconda", x, y, z)
62
63 import logging
64 log = logging.getLogger("anaconda")
65
66 STRIPE_HEIGHT = 35.0
67 LOGICAL_INSET = 3.0
68 TREE_SPACING = 2
69
70
71 if gtk.gdk.screen_width() > 640:
72 CANVAS_WIDTH = 490
73 else:
74 CANVAS_WIDTH = 390
75 CANVAS_HEIGHT = 200
76
77 MODE_ADD = 1
78 MODE_EDIT = 2
81 """Class representing a slice of a stripe.
82
83 parent -- the stripe that the slice belongs too.
84 text -- what will appear in the slice
85 type -- either SLICE or SUBSLICE
86 xoffset -- start percentage
87 xlength -- a length percentage
88 dcCB -- function that is called on a double click.
89 cCB -- function that is called when one click (selected)
90 sel_col -- color when selected
91 unsel_col -- color when unselected
92 obj -- some python object that is related to this slice.
93 selected -- initial state of slice.
94 """
95 SLICE = 0
96 SUBSLICE = 1
97 CONTAINERSLICE = 2
98
99 - def __init__(self, parent, text, type, xoffset, xlength, dcCB=lambda: None,
100 cCB=lambda x: None, sel_col="cornsilk1", unsel_col="white",
101 obj = None, selected = False):
102 self.text = text
103 self.type = type
104 self.xoffset = xoffset
105 self.xlength = xlength
106 self.parent = parent
107 self.dcCB = dcCB
108 self.cCB = cCB
109 self.sel_col = sel_col
110 self.unsel_col = unsel_col
111 self.obj = obj
112 self.selected = selected
113
115 if event.type == gtk.gdk.BUTTON_PRESS:
116 if event.button == 1:
117 self.select()
118 self.cCB(self.obj)
119 elif event.type == gtk.gdk._2BUTTON_PRESS:
120
121 self.dcCB()
122
123 return True
124
126 pgroup = self.parent.getGroup()
127 self.group = pgroup.add(gnomecanvas.CanvasGroup)
128 self.box = self.group.add(gnomecanvas.CanvasRect)
129 self.group.connect("event", self.eventHandler)
130 canvas_text = self.group.add(gnomecanvas.CanvasText,
131 font="sans", size_points=8)
132
133 xoffset = self.xoffset * CANVAS_WIDTH
134 xlength = self.xlength * CANVAS_WIDTH
135
136 if self.type == Slice.SUBSLICE:
137 yoffset = 0.0 + LOGICAL_INSET
138 yheight = STRIPE_HEIGHT - (LOGICAL_INSET * 2)
139 texty = 0.0
140 else:
141 yoffset = 0.0
142 yheight = STRIPE_HEIGHT
143 texty = LOGICAL_INSET
144
145 if self.selected:
146 fill_color = self.sel_col
147 else:
148 fill_color = self.unsel_col
149
150 self.group.set(x=xoffset, y=yoffset)
151 self.box.set(x1=0.0, y1=0.0, x2=xlength,
152 y2=yheight, fill_color=fill_color,
153 outline_color='black', width_units=1.0)
154 canvas_text.set(x=2.0, y=texty + 2.0, text=self.text,
155 fill_color='black',
156 anchor=gtk.ANCHOR_NW, clip=True,
157 clip_width=xlength-1, clip_height=yheight-1)
158
160 self.parent = None
161 if self.group:
162 self.group.destroy()
163 self.group = None
164
166 for slice in self.parent.slices:
167 slice.deselect()
168 self.selected = True
169
170 if self.group and self.box:
171 if self.type != Slice.CONTAINERSLICE:
172 self.group.raise_to_top()
173 self.box.set(outline_color="red")
174 self.box.set(fill_color=self.sel_col)
175
177 self.selected = False
178 if self.box:
179 self.box.set(outline_color="black", fill_color=self.unsel_col)
180
182 """
183 canvas -- the canvas where everything goes
184 text -- the text that will appear on top of the stripe
185 yoff -- its the position in the y axis where this stripe should be drawn
186 dcCB -- function that should be called on a double click
187 obj -- some python object that is related to this stripe
188
189 """
190 - def __init__(self, canvas, text, dcCB, obj = None):
191 self.canvas_text = None
192 self.canvas = canvas
193 self.text = text
194 self.group = None
195 self._slices = []
196 self.dcCB = dcCB
197 self.selected = None
198 self.obj = obj
199
201 """
202 returns the yposition after drawhing this stripe.
203
204 """
205
206 self.canvas_text = self.canvas.root().add(gnomecanvas.CanvasText,
207 x=0.0, y=yoff, font="sans", size_points=9)
208 self.canvas_text.set(text=self.text, fill_color='black',
209 anchor=gtk.ANCHOR_NW, weight=pango.WEIGHT_BOLD)
210
211 (xxx1, yyy1, xxx2, yyy2) = self.canvas_text.get_bounds()
212 textheight = yyy2 - yyy1 + 2
213 self.group = self.canvas.root().add(gnomecanvas.CanvasGroup,
214 x=0, y=yoff+textheight)
215
216 self.group.add(gnomecanvas.CanvasRect, x1=0.0, y1=0.0, x2=CANVAS_WIDTH,
217 y2=STRIPE_HEIGHT, fill_color='green',
218 outline_color='grey71', width_units=1.0)
219 self.group.lower_to_bottom()
220
221
222
223 for slice in [s for s in self.slices if s.type == Slice.CONTAINERSLICE]:
224 slice.putOnCanvas()
225
226 for slice in [s for s in self.slices if s.type != Slice.CONTAINERSLICE]:
227 slice.putOnCanvas()
228
229
230 return yoff + STRIPE_HEIGHT+textheight+10
231
233 for slice in self.slices:
234 slice.shutDown()
235 self._slices = []
236
237 if self.canvas_text:
238 self.canvas_text.destroy()
239
240 if self.group:
241 self.group.destroy()
242 self.group = None
243
246
247 @property
250
252
253 for slice in self.slices:
254
255 if new_slice.type+slice.type == Slice.CONTAINERSLICE+Slice.SUBSLICE:
256 continue
257
258 if new_slice.xoffset > slice.xoffset \
259 and new_slice.xoffset < slice.xoffset + slice.xlength:
260
261 return
262
263 self._slices.append(new_slice)
264
266 for slice in self.slices:
267 if slice.selected:
268 return slice
269 return None
270
272 """ This class will only handle one stripe."""
273
274 __canvas = None
276 self.stripe = None
277 self.next_ypos = 0.0
278
281
283 if self.stripe:
284 self.stripe.shutDown()
285 self.stripe = None
286
287 self.next_ypos = 0.0
288
289 @classmethod
294
308
311
313 """Search for obj in the slices """
314 stripe = self.getDisplayed()
315 if not stripe:
316 return
317
318 for slice in stripe.slices:
319
320 if not slice.obj:
321 continue
322
323 if obj == slice.obj and not slice.selected:
324 slice.select()
325 break
326
330
333
336 """Handles the creation of a bar view for the 'normal' devies.
337
338 storage -- the storage object
339
340 cCB -- call back function used when the user clicks on a slice. This function
341 is passed a device object when its executed.
342 dcCB -- call back function used when the user double clicks on a slice.
343 drive -- drive to display
344 """
345 - def __init__(self, storage, drive=None, cCB=lambda x:None, dcCB=lambda:None):
346 StripeGraph.__init__(self)
347 self.storage = storage
348 self.cCB = cCB
349 self.dcCB = dcCB
350
351 self.part_type_colors = \
352 {"sel_logical": "cornsilk1", "unsel_logical": "white",
353 "sel_extended": "cornsilk1", "unsel_extended": "white",
354 "sel_normal": "cornsilk1", "unsel_normal": "white",
355 "sel_freespace": "grey88", "unsel_freespace": "grey88"}
356 if drive:
357 self.setDisplayed(drive)
358
360
361 drivetext = _("Drive %(drive)s (%(size)-0.f MB) (Model: %(model)s)") \
362 % {'drive': drive.path,
363 'size': drive.size,
364 'model': drive.model}
365 stripe = Stripe(self.getCanvas(), drivetext, self.dcCB, obj = drive)
366
367
368
369
370 for part in drive.format.partedDisk.getFreeSpacePartitions() \
371 + [d for d in drive.format.partitions]:
372 if part.getSize(unit="MB") <= 1.0 or \
373 part.type & parted.PARTITION_METADATA:
374 continue
375
376
377 xoffset = (Decimal(str(part.geometry.start))
378 / Decimal(str(drive.partedDevice.length)))
379 xlength = (Decimal(str(part.geometry.length))
380 / Decimal(str(drive.partedDevice.length)))
381
382 if part.type & parted.PARTITION_LOGICAL:
383 if part.type & parted.PARTITION_FREESPACE:
384 name = _("Free")
385 unsel_col = self.part_type_colors["unsel_freespace"]
386 sel_col = self.part_type_colors["sel_freespace"]
387 else:
388 name = part.path
389 unsel_col = self.part_type_colors["unsel_logical"]
390 sel_col = self.part_type_colors["sel_logical"]
391
392 partstr = "%s\n%.0f MB" % (name, float(part.getSize()))
393 stype = Slice.SUBSLICE
394
395 elif part.type & parted.PARTITION_FREESPACE:
396 partstr = "%s\n%.0f MB" % (_("Free"), float(part.getSize()))
397 stype = Slice.SLICE
398 unsel_col = self.part_type_colors["unsel_freespace"]
399 sel_col = self.part_type_colors["sel_freespace"]
400
401 elif part.type & parted.PARTITION_EXTENDED:
402 partstr = ""
403 stype = Slice.CONTAINERSLICE
404 unsel_col = self.part_type_colors["unsel_extended"]
405 sel_col = self.part_type_colors["sel_extended"]
406
407 else:
408 partstr = "%s\n%.0f MB" % (part.path, float(part.getSize()))
409 stype = Slice.SLICE
410 unsel_col = self.part_type_colors["unsel_normal"]
411 sel_col = self.part_type_colors["sel_normal"]
412
413
414
415 if part.type != parted.PARTITION_FREESPACE:
416 partName = devicePathToName(part.getDeviceNodeName())
417 o_part = self.storage.devicetree.getDeviceByName(partName)
418 else:
419 o_part = None
420
421 slice = Slice(stripe, partstr, stype, xoffset, xlength,
422 dcCB = self.dcCB, cCB = self.cCB, sel_col = sel_col,
423 unsel_col = unsel_col, obj = o_part)
424 stripe.addSlice(slice)
425
426 return stripe
427
429 """
430 storage -- the storage object
431
432 cCB -- call back function used when the user clicks on a slice. This function
433 is passed a device object when its executed.
434 dcCB -- call back function used when the user double clicks on a slice.
435 vg -- volume group to display
436 """
437 - def __init__(self, storage, vg=None, cCB=lambda x:None, dcCB=lambda:None):
438 StripeGraph.__init__(self)
439 self.storage = storage
440 self.cCB = cCB
441 self.dcCB = dcCB
442
443 self.part_type_colors = \
444 {"sel_lv": "cornsilk1", "unsel_lv": "white",
445 "sel_freespace": "grey88", "unsel_freespace": "grey88"}
446 if vg:
447 self.setDisplayed(vg)
448
450
451 vgtext = _("LVM Volume Group %(vgName)s (%(vgSize)-0.f MB)") % {"vgName": vg.name, "vgSize": vg.size}
452 stripe = Stripe(self.getCanvas(), vgtext, self.dcCB, obj = vg)
453
454
455
456
457 curr_offset = Decimal(0)
458 for lv in vg.lvs:
459 lvstr = "%s\n%.0f MB" % (lv.name, float(lv.size))
460 stype = Slice.SLICE
461 sel_col = self.part_type_colors["sel_lv"]
462 unsel_col = self.part_type_colors["unsel_lv"]
463
464
465 xoffset = curr_offset
466 xlength = Decimal(str(lv.size)) / Decimal(str(vg.size))
467
468 slice = Slice(stripe, lvstr, stype, xoffset, xlength,
469 dcCB = self.dcCB, cCB = self.cCB, sel_col = sel_col,
470 unsel_col = unsel_col, obj = lv)
471 stripe.addSlice(slice)
472
473 curr_offset += xlength
474
475
476 if curr_offset < 1:
477
478 stype = Slice.SLICE
479 sel_col = self.part_type_colors["sel_freespace"]
480 unsel_col = self.part_type_colors["unsel_freespace"]
481
482 xoffset = curr_offset
483 xlength = Decimal(1 - curr_offset)
484
485
486 freestr = "%s\n%.0f MB" % (_("Free"), Decimal(str(vg.size)) * xlength)
487
488
489 slice = Slice(stripe, freestr, stype, xoffset, xlength,
490 dcCB = self.dcCB, cCB = self.cCB, sel_col = sel_col,
491 unsel_col = unsel_col)
492
493 stripe.addSlice(slice)
494
495 return stripe
496
498 desc = "MD"
499 """
500 storage -- the storage object
501
502 cCB -- call back function used when the user clicks on a slice. This function
503 is passed a device object when its executed.
504 dcCB -- call back function used when the user double clicks on a slice.
505 md -- md device to display.
506 """
507 - def __init__(self, storage, device=None, cCB=lambda x:None, dcCB=lambda:None):
516
517 - def _get_text(self, md):
518 return (_("%(desc)s %(mdPath)s (%(mdSize)-0.f MB)")
519 % {"mdPath": md.path, "mdSize": md.size, "desc": self.desc})
520
522 mdtext = self._get_text(md)
523 stripe = Stripe(self.getCanvas(), mdtext, self.dcCB, obj = md)
524
525
526
527 mdstr = "%s\n%.0f MB" % (md.path, float(md.size))
528 stype = Slice.SLICE
529 sel_col = self.part_type_colors["sel_md"]
530 unsel_col = self.part_type_colors["unsel_md"]
531 xoffset = 0
532 xlength = 1
533
534 slice = Slice(stripe, mdstr, stype, xoffset, xlength,
535 dcCB = self.dcCB, cCB = self.cCB, sel_col = sel_col,
536 unsel_col = unsel_col, obj = md)
537 stripe.addSlice(slice)
538
539 return stripe
540
542 desc = "MD RAID Array"
543
545 desc = "BTRFS Pool"
546
547 - def _get_text(self, md):
548 return (_("%(desc)s %(mdUUID)s (%(mdSize)-0.f MB)")
549 % {"mdUUID": md.uuid, "mdSize": md.size, "desc": self.desc})
550
553 self.canvas = canvas
554 self.message = message
555 self.canvas_text = None
556
558 if self.canvas_text != None:
559
560 return
561
562 self.canvas_text = self.canvas.root().add(gnomecanvas.CanvasText,
563 x=0.0, y=20, font="sans", size_points=16)
564 self.canvas_text.set(text=self.message, fill_color='black',
565 anchor=gtk.ANCHOR_CENTER, weight=pango.WEIGHT_BOLD)
566
567
568 apply(self.canvas.set_scroll_region, self.canvas.root().get_bounds())
569
571 if self.canvas_text:
572 self.canvas_text.destroy()
573 self.canvas_text = None
574
576 - def __init__(self, model, columns, iter):
577 self.model = model
578 self.iter = iter
579 self.columns = columns
580
582 if type(key) == types.StringType:
583 key = self.columns[key]
584 try:
585 return self.model.get_value(self.iter, key)
586 except Exception:
587
588 return None
589
591 if type(key) == types.StringType:
592 key = self.columns[key]
593 self.model.set_value(self.iter, key, value)
594
596 isLeaf = -3
597 isFormattable = -2
598
599
600 titles = ((N_("Device"), gobject.TYPE_STRING, 0.0, 0, 0),
601 (N_("Label"), gobject.TYPE_STRING, 0.0, 1, 0),
602 (N_("Size (MB)"), gobject.TYPE_STRING, 1.0, 0, 0),
603 (N_("Mount Point"), gobject.TYPE_STRING, 0.0, 0, isLeaf),
604 (N_("Type"), gobject.TYPE_STRING, 0.0, 0, 0),
605 (N_("Format"), gobject.TYPE_OBJECT, 0.5, 0, isFormattable),
606 ("", gobject.TYPE_STRING, 0.0, 0, 0),
607
608 ("IsLeaf", gobject.TYPE_BOOLEAN, 0.0, 1, 0),
609 ("IsFormattable", gobject.TYPE_BOOLEAN, 0.0, 1, 0),
610 ("PyObject", gobject.TYPE_PYOBJECT, 0.0, 1, 0))
611
613 self.hiddenPartitions = []
614 self.titleSlot = {}
615 i = 0
616 types = [self]
617 self.columns = []
618 for title, kind, alignment, hide, key in self.titles:
619 self.titleSlot[title] = i
620 types.append(kind)
621 if hide:
622 i += 1
623 continue
624 elif kind == gobject.TYPE_OBJECT:
625 renderer = gtk.CellRendererPixbuf()
626 propertyMapping = {'pixbuf': i}
627 elif kind == gobject.TYPE_BOOLEAN:
628 renderer = gtk.CellRendererToggle()
629 propertyMapping = {'active': i}
630 elif (kind == gobject.TYPE_STRING or
631 kind == gobject.TYPE_INT):
632 renderer = gtk.CellRendererText()
633 propertyMapping = {'markup': i}
634
635
636
637 if key < 0:
638 propertyMapping['visible'] = len(self.titles) + key
639
640 renderer.set_property('xalign', alignment)
641 if title == "Mount Point":
642 title = _("Mount Point/\nRAID/Volume")
643 elif title == "Size (MB)":
644 title = _("Size\n(MB)")
645 elif title != "":
646 title = _(title)
647 col = apply(gtk.TreeViewColumn, (title, renderer),
648 propertyMapping)
649 col.set_alignment(0.5)
650 if kind == gobject.TYPE_STRING or kind == gobject.TYPE_INT:
651 col.set_property('sizing', gtk.TREE_VIEW_COLUMN_AUTOSIZE)
652 self.columns.append(col)
653 i += 1
654
655 apply(gtk.TreeStore.__init__, types)
656
657 self.view = gtk.TreeView(self)
658
659 map(self.view.append_column, self.columns)
660
663
665 """Find the row in the tree containing obj and select it.
666
667 obj -- the object that we are searching
668 iter -- an iter from the tree. If None, get the first one.
669
670 Returns the iter where obj was found. None otherwise.
671 """
672 retval = None
673 r_obj = None
674
675
676 if not iter:
677 iter = self.get_iter_first()
678
679 while iter:
680
681 r_obj = self[iter]["PyObject"]
682
683 if obj and r_obj == obj:
684
685 selection = self.view.get_selection()
686 if selection is not None:
687 selection.unselect_all()
688 selection.select_iter(iter)
689
690
691 path = self.get_path(iter)
692 col = self.view.get_column(0)
693 self.view.set_cursor(path, col, False)
694 self.view.scroll_to_cell(path, col, True, 0.5, 0.5)
695 retval = iter
696 break
697
698 if self.iter_has_child(iter):
699
700 rv = self.selectRowFromObj(obj, iter=self.iter_children(iter))
701 if rv != None:
702 retval = rv
703 break
704
705 iter = self.iter_next(iter)
706
707 return iter
708
710 """ Return the device representing the current selection,
711 None otherwise.
712 """
713 selection = self.view.get_selection()
714 model, iter = selection.get_selected()
715 if not iter:
716 return None
717
718 return model[iter]['PyObject']
719
721 """ Return the parent of the selected row. Returns an iter.
722 None if there is no parent.
723 """
724 selection = self.view.get_selection()
725 model, iter = selection.get_selected()
726 if not iter:
727 return None
728
729 return model.iter_parent(iter)
730
733
735 selection = self.view.get_selection()
736 if selection is not None:
737 selection.unselect_all()
738 gtk.TreeStore.clear(self)
739
741 if type(iter) == gtk.TreeIter:
742 return DiskTreeModelHelper(self, self.titleSlot, iter)
743 raise KeyError, iter
744
752
755
835
837 (errors, warnings) = self.storage.sanityCheck()
838 if errors:
839 labelstr1 = _("The partitioning scheme you requested "
840 "caused the following critical errors.")
841 labelstr2 = _("You must correct these errors before "
842 "you continue your installation of "
843 "%s.") % (productName,)
844
845 commentstr = string.join(errors, "\n\n")
846
847 self.presentPartitioningComments(_("Partitioning Errors"),
848 labelstr1, labelstr2,
849 commentstr, type="ok")
850 raise gui.StayOnScreen
851
852 if warnings:
853
854 labelstr1 = _("The partitioning scheme you requested "
855 "generated the following warnings.")
856 labelstr2 = _("Would you like to continue with "
857 "your requested partitioning "
858 "scheme?")
859
860 commentstr = string.join(warnings, "\n\n")
861 rc = self.presentPartitioningComments(_("Partitioning Warnings"),
862 labelstr1, labelstr2,
863 commentstr,
864 type="yesno")
865 if rc != 1:
866 raise gui.StayOnScreen
867
868 formatWarnings = getPreExistFormatWarnings(self.storage)
869 if formatWarnings:
870 labelstr1 = _("The following pre-existing devices have been "
871 "selected to be formatted, destroying all data.")
872
873
874
875
876 labelstr2 = ""
877 commentstr = ""
878 for (dev, type, mntpt) in formatWarnings:
879 commentstr = commentstr + \
880 "%s %s %s\n" % (dev,type,mntpt)
881
882 rc = self.presentPartitioningComments(_("Format Warnings"),
883 labelstr1, labelstr2,
884 commentstr,
885 type="custom",
886 custom_buttons=["gtk-cancel",
887 _("_Format")])
888 if rc != 1:
889 raise gui.StayOnScreen
890
891 self.stripeGraph.shutDown()
892 self.tree.clear()
893 del self.parent
894 return None
895
897 self.stripeGraph.shutDown()
898 self.tree.clear()
899 del self.parent
900 return None
901
903 if device.format.hidden:
904 return
905
906 if device.format.type == "luks":
907
908
909 try:
910 dm_dev = self.storage.devicetree.getChildren(device)[0]
911 except IndexError:
912 format = device.format
913 else:
914 format = dm_dev.format
915 else:
916 format = device.format
917
918
919 if device.format.type == "luks" and not device.format.exists:
920
921 format_icon = self.lock_pixbuf
922 elif not format.exists:
923
924 format_icon = self.checkmark_pixbuf
925 else:
926 format_icon = None
927
928
929 if format.type == "lvmpv":
930 vg = None
931 for _vg in self.storage.vgs:
932 if _vg.dependsOn(device):
933 vg = _vg
934 break
935
936 mnt_str = getattr(vg, "name", "")
937 elif format.type == "mdmember":
938 array = None
939 for _array in self.storage.mdarrays:
940 if _array.dependsOn(device):
941 array = _array
942 break
943
944 mnt_str = getattr(array, "name", "")
945 elif format.type == "btrfs" and not isinstance(device, BTRFSVolumeDevice):
946 btrfs_dev = self.storage.devicetree.getChildren(device)[0]
947 mnt_str = btrfs_dev.name
948 else:
949 mnt_str = getattr(format, "mountpoint", "")
950 if mnt_str is None:
951 mnt_str = ""
952
953 isleaf = True
954
955
956 name_str = getattr(device, "lvname", device.name)
957
958
959 label_str = getattr(format, "label", "")
960 if label_str is None:
961 label_str = ""
962
963 self.tree[treeiter]['Device'] = name_str
964 self.tree[treeiter]['Size (MB)'] = "%Ld" % device.size
965 self.tree[treeiter]['PyObject'] = device
966 self.tree[treeiter]['IsFormattable'] = format.formattable
967 self.tree[treeiter]['Format'] = format_icon
968 self.tree[treeiter]['Mount Point'] = mnt_str
969 self.tree[treeiter]['IsLeaf'] = isleaf
970 self.tree[treeiter]['Type'] = format.name
971 self.tree[treeiter]['Label'] = label_str
972
973
974 if isinstance(device, BTRFSVolumeDevice):
975
976 for s in device.subvolumes:
977 log.debug("%r" % s.format)
978 isleaf = False
979 if s.format.exists:
980 sub_format_icon = None
981 else:
982 sub_format_icon = self.checkmark_pixbuf
983 subvol_iter = self.tree.append(treeiter)
984 self.tree[subvol_iter]['Device'] = s.name
985 self.tree[subvol_iter]['PyObject'] = s
986 self.tree[subvol_iter]['IsFormattable'] = True
987 self.tree[subvol_iter]['Format'] = sub_format_icon
988 self.tree[subvol_iter]['Mount Point'] = s.format.mountpoint
989 self.tree[subvol_iter]['Type'] = s.type
990 self.tree[subvol_iter]['IsLeaf'] = True
991
992
994 self.tree.resetSelection()
995
996
997 vgs = self.storage.vgs
998 if vgs:
999 lvmparent = self.tree.append(None)
1000 self.tree[lvmparent]['Device'] = _("LVM Volume Groups")
1001 for vg in vgs:
1002 vgparent = self.tree.append(lvmparent)
1003 self.addDevice(vg, vgparent)
1004 self.tree[vgparent]['Type'] = ""
1005 for lv in vg.lvs:
1006 iter = self.tree.append(vgparent)
1007 self.addDevice(lv, iter)
1008
1009
1010 if vg.freeSpace > 0:
1011 iter = self.tree.append(vgparent)
1012 self.tree[iter]['Device'] = _("Free")
1013 self.tree[iter]['Size (MB)'] = str(vg.freeSpace)
1014 self.tree[iter]['PyObject'] = None
1015 self.tree[iter]['Mount Point'] = ""
1016 self.tree[iter]['IsLeaf'] = True
1017
1018
1019 mdarrays = self.storage.mdarrays
1020 if mdarrays:
1021 raidparent = self.tree.append(None)
1022 self.tree[raidparent]['Device'] = _("RAID Devices")
1023 for array in mdarrays:
1024 iter = self.tree.append(raidparent)
1025 self.addDevice(array, iter)
1026 name = "%s <span size=\"small\" color=\"gray\">(%s)</span>" % \
1027 (array.name, array.path)
1028 self.tree[iter]['Device'] = name
1029
1030
1031 btrfs_devs = self.storage.btrfsVolumes
1032 if btrfs_devs:
1033 btrfsparent = self.tree.append(None)
1034 self.tree[btrfsparent]['Device'] = _("BTRFS Volumes")
1035 for dev in btrfs_devs:
1036 iter = self.tree.append(btrfsparent)
1037 self.addDevice(dev, iter)
1038
1039
1040 disks = self.storage.partitioned
1041
1042 whole = filter(lambda d: not d.partitioned and not d.format.hidden,
1043 self.storage.disks)
1044 disks.extend(whole)
1045 disks.sort(key=lambda d: d.name)
1046 drvparent = self.tree.append(None)
1047 self.tree[drvparent]['Device'] = _("Hard Drives")
1048 for disk in disks:
1049
1050 parent = self.tree.append(drvparent)
1051
1052 self.tree[parent]['PyObject'] = disk
1053 if disk.partitioned:
1054 part = disk.format.firstPartition
1055 extendedParent = None
1056 while part:
1057 if part.type & parted.PARTITION_METADATA:
1058 part = part.nextPartition()
1059 continue
1060
1061 partName = devicePathToName(part.getDeviceNodeName())
1062 device = self.storage.devicetree.getDeviceByName(partName)
1063 if not device and not part.type & parted.PARTITION_FREESPACE:
1064 log.debug("can't find partition %s in device"
1065 " tree" % partName)
1066
1067
1068
1069 if part.type & parted.PARTITION_FREESPACE:
1070 min_length = disk.format.alignment.grainSize
1071 if part.type & parted.PARTITION_LOGICAL:
1072
1073
1074
1075 min_length *= 2
1076
1077 if part.geometry.length < min_length:
1078 part = part.nextPartition()
1079 continue
1080
1081 if device and device.isExtended:
1082 if extendedParent:
1083 raise RuntimeError, ("can't handle more than "
1084 "one extended partition per disk")
1085 extendedParent = self.tree.append(parent)
1086 iter = extendedParent
1087 elif part.type & parted.PARTITION_LOGICAL:
1088 if not extendedParent:
1089 raise RuntimeError, ("crossed logical partition "
1090 "before extended")
1091 iter = self.tree.append(extendedParent)
1092 else:
1093 iter = self.tree.append(parent)
1094
1095 if device and not device.isExtended:
1096 self.addDevice(device, iter)
1097 else:
1098
1099 if part.type & parted.PARTITION_FREESPACE:
1100 devstring = _("Free")
1101 ptype = ""
1102 else:
1103 devstring = partName
1104 ptype = _("Extended")
1105
1106 self.tree[iter]['Device'] = devstring
1107 self.tree[iter]['Type'] = ptype
1108 size = part.getSize(unit="MB")
1109 if size < 1.0:
1110 sizestr = "< 1"
1111 else:
1112 sizestr = "%Ld" % (size)
1113 self.tree[iter]['Size (MB)'] = sizestr
1114 self.tree[iter]['PyObject'] = device
1115
1116 part = part.nextPartition()
1117 else:
1118
1119 self.addDevice(disk, parent)
1120
1121 ident = None
1122 try:
1123 if disk.type == "dasd" or disk.type == "zfcp":
1124 ident = deviceNameToDiskByPath(disk.name)
1125 if ident.startswith("/dev/disk/by-path/"):
1126 ident = os.path.basename(ident)
1127 elif disk.type == "dm-multipath":
1128 ident = disk.wwid
1129 except DeviceNotFoundError:
1130 ident = None
1131
1132 if not ident:
1133 ident = disk.path
1134
1135
1136
1137 if len(disk.name) + len(ident) > 20:
1138 separator = "\n"
1139 else:
1140 separator= " "
1141 self.tree[parent]['Device'] = \
1142 "%s%s<span size=\"small\" color=\"gray\">(%s)</span>" \
1143 % (disk.name, separator, ident)
1144
1145 self.treeView.expand_all()
1146 self.messageGraph.display()
1147
1149 """ Should be called when we double click on a slice"""
1150
1151
1152
1153
1154
1155
1156 sel_slice = self.stripeGraph.getSelectedSlice()
1157
1158 if sel_slice == None:
1159
1160 return
1161
1162
1163
1164 if sel_slice.obj != None:
1165
1166 return self.treeActivateCB()
1167 else:
1168
1169
1170 disp_stripe = self.stripeGraph.getDisplayed()
1171 if disp_stripe == None:
1172
1173 return
1174
1175
1176 stripe_dev = disp_stripe.obj
1177 if stripe_dev.partitioned:
1178 tempformat = self.storage.defaultFSType
1179 device = self.storage.newPartition(fmt_type=tempformat)
1180 self.editPartition(device, isNew = True)
1181
1182 elif isinstance(stripe_dev, storage.LVMVolumeGroupDevice):
1183 self.editLVMLogicalVolume(vg = stripe_dev)
1184 return
1185
1217
1219
1220
1221 self.deleteButton.set_sensitive(False)
1222 self.editButton.set_sensitive(False)
1223
1224
1225
1226 model, iter = selection.get_selected()
1227 if not iter:
1228 return
1229
1230
1231
1232
1233 iparent = model.iter_parent(iter)
1234 if not iparent:
1235 self.stripeGraph.shutDown()
1236 self.messageGraph.display()
1237 return
1238
1239
1240
1241
1242 self.messageGraph.destroy()
1243
1244 device = model[iter]['PyObject']
1245
1246
1247
1248 if not device:
1249
1250 parent = self.tree[iparent]["PyObject"]
1251 if parent.partitioned:
1252 if not isinstance(self.stripeGraph, DiskStripeGraph):
1253 self.stripeGraph.shutDown()
1254 self.stripeGraph = DiskStripeGraph(self.storage,
1255 drive = parent, cCB = self.tree.selectRowFromObj,
1256 dcCB = self.barviewActivateCB)
1257 self.stripeGraph.setDisplayed(parent)
1258
1259 elif isinstance(parent, storage.LVMVolumeGroupDevice):
1260 if not isinstance(self.stripeGraph, LVMStripeGraph):
1261 self.stripeGraph.shutDown()
1262 self.stripeGraph = LVMStripeGraph(self.storage,
1263 vg = parent, cCB = self.tree.selectRowFromObj,
1264 dcCB = self.barviewActivateCB)
1265 self.stripeGraph.setDisplayed(parent)
1266
1267 elif device.partitioned:
1268 if not isinstance(self.stripeGraph, DiskStripeGraph):
1269 self.stripeGraph.shutDown()
1270 self.stripeGraph = DiskStripeGraph(self.storage,
1271 drive = device,
1272 cCB = self.tree.selectRowFromObj,
1273 dcCB = self.barviewActivateCB)
1274 self.stripeGraph.setDisplayed(device)
1275
1276 self.deleteButton.set_sensitive(True)
1277
1278 elif isinstance(device, storage.PartitionDevice):
1279 if not isinstance(self.stripeGraph, DiskStripeGraph):
1280 self.stripeGraph.shutDown()
1281 self.stripeGraph = DiskStripeGraph(self.storage,
1282 drive = device.parents[0],
1283 cCB = self.tree.selectRowFromObj,
1284 dcCB = self.barviewActivateCB)
1285 self.stripeGraph.setDisplayed(device.parents[0])
1286 self.stripeGraph.selectSliceFromObj(device)
1287 self.deleteButton.set_sensitive(True)
1288 if not device.isExtended:
1289 self.editButton.set_sensitive(True)
1290
1291 elif isinstance(device, storage.LVMVolumeGroupDevice):
1292 if not isinstance(self.stripeGraph, LVMStripeGraph):
1293 self.stripeGraph.shutDown()
1294 self.stripeGraph = LVMStripeGraph(self.storage, vg = device,
1295 cCB = self.tree.selectRowFromObj,
1296 dcCB = self.barviewActivateCB)
1297 self.stripeGraph.setDisplayed(device)
1298 self.deleteButton.set_sensitive(True)
1299 self.editButton.set_sensitive(True)
1300
1301 elif isinstance(device, storage.LVMLogicalVolumeDevice):
1302 if not isinstance(self.stripeGraph, LVMStripeGraph):
1303 self.stripeGraph.shutDown()
1304 self.stripeGraph = LVMStripeGraph(self.storage, vg = device.vg,
1305 cCB = self.tree.selectRowFromObj,
1306 dcCB = self.barviewActivateCB)
1307 self.stripeGraph.setDisplayed(device.vg)
1308 self.stripeGraph.selectSliceFromObj(device)
1309 self.deleteButton.set_sensitive(True)
1310 self.editButton.set_sensitive(True)
1311
1312 elif isinstance(device, storage.MDRaidArrayDevice):
1313 if not isinstance(self.stripeGraph, MDRaidArrayStripeGraph):
1314 self.stripeGraph.shutDown()
1315 self.stripeGraph = MDRaidArrayStripeGraph(self.storage,
1316 device = device,
1317 cCB = self.tree.selectRowFromObj,
1318 dcCB = self.barviewActivateCB)
1319 self.stripeGraph.setDisplayed(device)
1320 self.deleteButton.set_sensitive(True)
1321 self.editButton.set_sensitive(True)
1322
1323 elif isinstance(device, storage.BTRFSDevice):
1324
1325
1326 if not isinstance(self.stripeGraph, BTRFSStripeGraph):
1327 self.stripeGraph.shutDown()
1328 self.stripeGraph = BTRFSStripeGraph(self.storage,
1329 device = device,
1330 cCB = self.tree.selectRowFromObj,
1331 dcCB = self.barviewActivateCB)
1332 self.stripeGraph.setDisplayed(device)
1333 self.deleteButton.set_sensitive(False)
1334 self.editButton.set_sensitive(True)
1335
1336 else:
1337
1338
1339 self.stripeGraph.shutDown()
1340 self.messageGraph.display()
1341 self.deleteButton.set_sensitive(False)
1342 self.editButton.set_sensitive(False)
1343
1367
1369
1370
1371
1372 activate_create_partition = True
1373
1374
1375
1376 activate_create_vg = False
1377 availpvs = len(self.storage.unusedPVs())
1378 if (lvm.has_lvm()
1379 and getFormat("lvmpv").supported
1380 and availpvs > 0):
1381 activate_create_vg = True
1382
1383
1384
1385 activate_create_raid_dev = False
1386 availraidparts = len(self.storage.unusedMDMembers())
1387 availminors = self.storage.unusedMDMinors
1388 if (len(availminors) > 0
1389 and getFormat("software RAID").supported
1390 and availraidparts > 1):
1391 activate_create_raid_dev = True
1392
1393
1394
1395 if (not activate_create_partition
1396 and not activate_create_vg
1397 and not activate_create_raid_dev):
1398 self.intf.messageWindow(_("Cannot perform any creation action"),
1399 _("Note that the creation action requires one of the "
1400 "following:\n\n"
1401 "* Free space in one of the Hard Drives.\n"
1402 "* At least two free Software RAID partitions.\n"
1403 "* At least one free physical volume (LVM) partition.\n"
1404 "* At least one Volume Group with free space."),
1405 custom_icon="warning")
1406 return
1407
1408
1409
1410 activate_create_lv = False
1411 vgs_with_free_space = []
1412 for vg in self.storage.vgs:
1413 if vg.freeSpace > 0:
1414 vgs_with_free_space.append(vg)
1415 if len(vgs_with_free_space) > 0:
1416 activate_create_lv = True
1417
1418
1419 create_storage_xml = gtk.glade.XML(
1420 gui.findGladeFile("create-storage.glade"), domain="anaconda")
1421 self.dialog = create_storage_xml.get_widget("create_storage_dialog")
1422
1423
1424
1425 sp_rb = create_storage_xml.get_widget("create_storage_rb_standard_part")
1426
1427 lp_rb = create_storage_xml.get_widget("create_storage_rb_lvm_part")
1428
1429 rp_rb = create_storage_xml.get_widget("create_storage_rb_raid_part")
1430 if activate_create_partition:
1431 sp_rb.set_sensitive(True)
1432 lp_rb.set_sensitive(True)
1433 rp_rb.set_sensitive(True)
1434
1435
1436
1437 vg_rb = create_storage_xml.get_widget("create_storage_rb_lvm_vg")
1438 if activate_create_vg:
1439 vg_rb.set_sensitive(True)
1440
1441
1442
1443 lv_rb = create_storage_xml.get_widget("create_storage_rb_lvm_lv")
1444 if activate_create_lv:
1445
1446
1447 def toggle_vg_cb_CB(button, vg_cb, selected_dev):
1448 if button.get_active():
1449 vg_cb.set_sensitive(True)
1450
1451
1452
1453
1454 if selected_dev and selected_dev.name \
1455 and vg_cb.set_active_text(selected_dev.name):
1456
1457 pass
1458 else:
1459 vg_cb.set_active_text(vgs_with_free_space[0].name)
1460
1461 else:
1462 vg_cb.set_sensitive(False)
1463
1464 vg_cb_st = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
1465 vg_cb = datacombo.DataComboBox(store = vg_cb_st)
1466 vg_cb.set_sensitive(False)
1467
1468 for vg in vgs_with_free_space:
1469
1470 vg_cb.append(vg.name, vg)
1471 lv_hb = create_storage_xml.get_widget("create_storage_hb_lvm_lv")
1472 lv_hb.pack_start(vg_cb)
1473
1474 lv_rb.set_sensitive(True)
1475 selected_dev = self.tree.getCurrentDevice()
1476 lv_rb.connect("toggled", toggle_vg_cb_CB, vg_cb, selected_dev)
1477
1478
1479
1480 rd_rb = create_storage_xml.get_widget("create_storage_rb_raid_dev")
1481 if activate_create_raid_dev:
1482 rd_rb.set_sensitive(True)
1483
1484
1485
1486 if activate_create_partition:
1487 sp_rb.set_active(True)
1488 sp_rb.grab_focus()
1489 elif activate_create_vg:
1490 vg_rb.set_active(True)
1491 vg_rb.grab_focus()
1492 elif activate_create_raid_dev:
1493 rd_rb.set_active(True)
1494 rd_rb.grab_focus()
1495
1496 gui.addFrame(self.dialog)
1497 self.dialog.show_all()
1498
1499
1500
1501 rinfo_button = create_storage_xml.get_widget("create_storage_info_raid")
1502 whatis_r = _("Software RAID allows you to combine several disks into "
1503 "a larger RAID device. A RAID device can be configured "
1504 "to provide additional speed and reliability compared "
1505 "to using an individual drive. For more information on "
1506 "using RAID devices please consult the %s "
1507 "documentation.\n") % (productName,)
1508 whatneed_r = _("To use RAID you must first create at least two "
1509 "partitions of type 'software RAID'. Then you can create a "
1510 "RAID device that can be formatted and mounted.\n\n")
1511 whathave_r = P_(
1512 "You currently have %d software RAID partition free to use.",
1513 "You currently have %d software RAID partitions free to use.",
1514 availraidparts) % (availraidparts,)
1515 rinfo_message = "%s\n%s%s" % (whatis_r, whatneed_r, whathave_r)
1516 rinfo_cb = lambda x : self.intf.messageWindow(_("About RAID"),
1517 rinfo_message, custom_icon="information")
1518 rinfo_button.connect("clicked", rinfo_cb)
1519
1520
1521 lvminfo_button = create_storage_xml.get_widget("create_storage_info_lvm")
1522 whatis_lvm = _("Logical Volume Manager (LVM) is a 3 level construct. "
1523 "The first level is made up of disks or partitions formatted with "
1524 "LVM metadata called Physical Volumes (PV). A Volume Group "
1525 "(VG) sits on top of one or more PVs. The VG, in turn, is the "
1526 "base to create one or more Logical Volumes (LV). Note that a "
1527 "VG can be an aggregate of PVs from multiple physical disks. For "
1528 "more information on using LVM please consult the %s "
1529 "documentation\n") % (productName, )
1530 whatneed_lvm = _("To create a PV you need a partition with "
1531 "free space. To create a VG you need a PV that is not "
1532 "part of any existing VG. To create an LV you need a VG with "
1533 "free space.\n\n")
1534 whathave_lvm = P_("You currently have %d available PV free to use.\n",
1535 "You currently have %d available PVs free to use.\n",
1536 availpvs) % (availpvs, )
1537 lvminfo_message = "%s\n%s%s" % (whatis_lvm, whatneed_lvm, whathave_lvm)
1538 lvminfo_cb = lambda x : self.intf.messageWindow(_("About LVM"),
1539 lvminfo_message, custom_icon="information")
1540 lvminfo_button.connect("clicked", lvminfo_cb)
1541
1542 dialog_rc = self.dialog.run()
1543
1544
1545 if dialog_rc == 0:
1546 self.dialog.destroy()
1547 return
1548
1549
1550
1551
1552 if dialog_rc != 1:
1553 log.error("I received a dialog_rc != 1 (%d) witch should not "
1554 "happen" % dialog_rc)
1555 self.dialog.destroy()
1556 return
1557
1558 self.dialog.destroy()
1559 if rp_rb.get_active():
1560 member = self.storage.newPartition(fmt_type="mdmember")
1561 self.editPartition(member, isNew = True, restrictfs=["mdmember"])
1562 return
1563
1564 elif rd_rb.get_active():
1565 array = self.storage.newMDArray(fmt_type=self.storage.defaultFSType)
1566 self.editRaidArray(array, isNew = True)
1567 return
1568
1569 elif lp_rb.get_active():
1570 member = self.storage.newPartition(fmt_type="lvmpv")
1571 self.editPartition(member, isNew = True, restrictfs=["lvmpv"])
1572 return
1573
1574 elif vg_rb.get_active():
1575 tempvg = self.storage.newVG()
1576 self.editLVMVolumeGroup(tempvg, isNew = True)
1577 return
1578
1579 elif lv_rb.get_active():
1580 selected_vg = vg_cb.get_active_value()
1581 self.editLVMLogicalVolume(vg = selected_vg)
1582 return
1583
1584 elif sp_rb.get_active():
1585 tempformat = self.storage.defaultFSType
1586 device = self.storage.newPartition(fmt_type=tempformat)
1587 self.editPartition(device, isNew = True)
1588 return
1589
1603
1604 - def refresh(self, justRedraw=None):
1605 log.debug("refresh: justRedraw=%s" % justRedraw)
1606 self.stripeGraph.shutDown()
1607 self.tree.clear()
1608
1609 if justRedraw:
1610 rc = 0
1611 else:
1612 try:
1613 doPartitioning(self.storage)
1614 rc = 0
1615 except PartitioningError as msg:
1616 self.intf.messageWindow(_("Error Partitioning"),
1617 _("Could not allocate requested partitions: %s.") % (msg),
1618 custom_icon="error")
1619 rc = -1
1620 except PartitioningWarning as msg:
1621
1622
1623
1624 dialog = gtk.MessageDialog(self.parent, 0, gtk.MESSAGE_WARNING,
1625 gtk.BUTTONS_NONE,
1626 _("Warning: %s.") % (msg))
1627 gui.addFrame(dialog)
1628 button = gtk.Button(_("_Modify Partition"))
1629 dialog.add_action_widget(button, 1)
1630 button = gtk.Button(_("_Continue"))
1631 dialog.add_action_widget(button, 2)
1632 dialog.set_position(gtk.WIN_POS_CENTER)
1633
1634 dialog.show_all()
1635 rc = dialog.run()
1636 dialog.destroy()
1637
1638 if rc == 1:
1639 rc = -1
1640 else:
1641 rc = 0
1642 all_devices = self.storage.devicetree.devices
1643 bootDevs = [d for d in all_devices if d.bootable]
1644
1645
1646
1647
1648 if not rc == -1:
1649 self.populate()
1650
1651 return rc
1652
1671
1672
1674
1675 raideditor = r_d_g.RaidEditor(self.storage, self.intf, self.parent,
1676 raiddev, isNew)
1677
1678 while True:
1679 actions = raideditor.run()
1680
1681 for action in actions:
1682
1683 self.storage.devicetree.registerAction(action)
1684
1685 if self.refresh(justRedraw=True):
1686 actions.reverse()
1687 for action in actions:
1688 self.storage.devicetree.cancelAction(action)
1689 if self.refresh():
1690 raise RuntimeError, ("Returning partitions to state "
1691 "prior to RAID edit failed")
1692 continue
1693 else:
1694 break
1695
1696 raideditor.destroy()
1697
1698
1699 - def editPartition(self, device, isNew = False, restrictfs = None):
1700
1701 parteditor = p_d_g.PartitionEditor(self.anaconda, self.parent, device,
1702 isNew = isNew, restrictfs = restrictfs)
1703
1704 while True:
1705 orig_device = copy.copy(device)
1706 actions = parteditor.run()
1707
1708 for action in actions:
1709
1710 self.anaconda.storage.devicetree.registerAction(action)
1711
1712 if self.refresh(justRedraw=not actions):
1713
1714
1715 actions.reverse()
1716 for action in actions:
1717 self.anaconda.storage.devicetree.cancelAction(action)
1718
1719
1720 if not isNew:
1721 device.req_size = orig_device.req_size
1722 device.req_base_size = orig_device.req_base_size
1723 device.req_grow = orig_device.req_grow
1724 device.req_max_size = orig_device.req_max_size
1725 device.req_primary = orig_device.req_primary
1726 device.req_disks = orig_device.req_disks
1727
1728 if self.refresh():
1729
1730 raise RuntimeError, ("Returning partitions to state "
1731 "prior to edit failed")
1732 else:
1733 break
1734
1735 parteditor.destroy()
1736 return 1
1737
1739
1740 vgeditor = l_d_g.VolumeGroupEditor(self.anaconda, self.intf, self.parent,
1741 device, isNew)
1742
1743 while True:
1744 actions = vgeditor.run()
1745
1746 for action in actions:
1747
1748 self.storage.devicetree.registerAction(action)
1749
1750 if self.refresh(justRedraw=True):
1751 actions.reverse()
1752 for action in actions:
1753 self.storage.devicetree.cancelAction(action)
1754
1755 if self.refresh():
1756 raise RuntimeError, ("Returning partitions to state "
1757 "prior to edit failed")
1758 continue
1759 else:
1760 break
1761
1762 vgeditor.destroy()
1763
1765 """Will be consistent with the state of things and use this funciton
1766 for creating and editing LVs.
1767
1768 lv -- the logical volume to edit. If this is set there is no need
1769 for the other two arguments.
1770 vg -- the volume group where the new lv is going to be created. This
1771 will only be relevant when we are createing an LV.
1772 """
1773
1774 if lv != None:
1775
1776 vgeditor = l_d_g.VolumeGroupEditor(self.anaconda, self.intf, self.parent,
1777 lv.vg, isNew = False)
1778 lv = vgeditor.lvs[lv.lvname]
1779 isNew = False
1780
1781 elif vg != None:
1782
1783 vgeditor = l_d_g.VolumeGroupEditor(self.anaconda, self.intf, self.parent,
1784 vg, isNew = False)
1785 tempvg = vgeditor.getTempVG()
1786 name = self.storage.suggestDeviceName(parent=tempvg, prefix="lv")
1787 format = getFormat(self.storage.defaultFSType)
1788 vgeditor.lvs[name] = {'name': name,
1789 'size': vg.freeSpace,
1790 'format': format,
1791 'originalFormat': format,
1792 'stripes': 1,
1793 'logSize': 0,
1794 'snapshotSpace': 0,
1795 'exists': False}
1796 lv = vgeditor.lvs[name]
1797 isNew = True
1798
1799 else:
1800
1801 return
1802
1803
1804 while True:
1805 vgeditor.editLogicalVolume(lv, isNew = isNew)
1806 actions = vgeditor.convertToActions()
1807
1808 for action in actions:
1809
1810 self.storage.devicetree.registerAction(action)
1811
1812 if self.refresh(justRedraw=True):
1813 actions.reverse()
1814 for action in actions:
1815 self.storage.devicetree.cancelAction(action)
1816
1817 if self.refresh():
1818 raise RuntimeError, ("Returning partitions to state "
1819 "prior to edit failed")
1820 continue
1821 else:
1822 break
1823
1824 vgeditor.destroy()
1825
1827 self.anaconda = anaconda
1828 self.storage = anaconda.storage
1829 self.intf = anaconda.intf
1830 self.checkmark_pixbuf = gui.getPixbuf("checkMark.png")
1831 self.lock_pixbuf = gui.getPixbuf("gnome-lock.png")
1832
1833 checkForSwapNoMatch(anaconda)
1834
1835
1836
1837 buttonBox = gtk.HButtonBox()
1838 buttonBox.set_spacing(6)
1839 buttonBox.set_layout(gtk.BUTTONBOX_END)
1840
1841 ops = ((_("_Create"), self.createCB),
1842 (_("_Edit"), self.editCB),
1843 (_("_Delete"), self.deleteCB),
1844 (_("Re_set"), self.resetCB))
1845
1846 for label, cb in ops:
1847 button = gtk.Button(label)
1848 buttonBox.add (button)
1849 button.connect ("clicked", cb)
1850
1851
1852 if label == _("_Edit"):
1853 self.editButton = button
1854 self.editButton.set_sensitive(False)
1855 elif label == _("_Delete"):
1856 self.deleteButton = button
1857 self.deleteButton.set_sensitive(False)
1858
1859
1860 self.tree = DiskTreeModel()
1861 self.treeView = self.tree.getTreeView()
1862 self.treeView.connect('row-activated', self.treeActivateCB)
1863 self.treeViewSelection = self.treeView.get_selection()
1864 self.treeViewSelection.connect("changed", self.treeSelectCB)
1865 self.stripeGraph = StripeGraph()
1866 self.messageGraph = MessageGraph(self.stripeGraph.getCanvas(),
1867 _("Please Select A Device"))
1868 self.populate(initial = 1)
1869
1870
1871
1872 hadj = gtk.Adjustment(step_incr = 5.0)
1873 vadj = gtk.Adjustment(step_incr = 5.0)
1874 swt = gtk.ScrolledWindow(hadjustment = hadj, vadjustment = vadj)
1875 swt.add(self.stripeGraph.getCanvas())
1876 swt.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1877 swt.set_shadow_type(gtk.SHADOW_IN)
1878
1879
1880 swb = gtk.ScrolledWindow()
1881 swb.add(self.treeView)
1882 swb.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
1883 swb.set_shadow_type(gtk.SHADOW_IN)
1884
1885
1886 MVbox = gtk.VBox(False, 5)
1887 MVbox.pack_start(swt, False, False)
1888 MVbox.pack_start(swb, True)
1889 MVbox.pack_start(buttonBox, False, False)
1890 MVbox.pack_start(gtk.HSeparator(), False)
1891
1892 return MVbox
1893