/[gli]/branches/overhaul/src/fe/gtk/Partition.py
Gentoo

Contents of /branches/overhaul/src/fe/gtk/Partition.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1596 - (show annotations) (download) (as text)
Sun Jan 7 02:11:42 2007 UTC (8 years ago) by agaffney
File MIME type: text/x-python
File size: 22163 byte(s)
more cleanups
1 # Copyright 1999-2005 Gentoo Foundation
2 # This source code is distributed under the terms of version 2 of the GNU
3 # General Public License as published by the Free Software Foundation, a copy
4 # of which can be found in the main directory of this project.
5
6 import gtk
7 import GLIScreen
8 import Partitioning
9 from GLIException import *
10 import re
11 import PartitionButton
12 import PartProperties
13 from gettext import gettext as _
14
15 class Panel(GLIScreen.GLIScreen):
16
17 title = _("Partitioning")
18 part_buttons = {}
19 drives = []
20 devices = {}
21 active_device = ""
22 active_device_bytes_in_sector = 0
23 active_part_idx = -1
24 colors = { 'ext2': '#0af2fe', 'ext3': '#0af2fe', 'unalloc': '#a2a2a2', 'unknown': '#ed03e0', 'free': '#ffffff', 'ntfs': '#f20600', 'fat16': '#3d07f9', 'fat32': '#3d07f9', 'reiserfs': '#f0ff00', 'linux-swap': '#12ff09', 'xfs': '#006600', 'jfs': '#ffb400', 'hfs': '#fdb0ff', 'hfs+': '#fdb0ff', 'apple_bootstrap': '#fdb0ff' }
25 supported_filesystems = ["ext2", "ext3", "linux-swap", "xfs", "jfs", "reiserfs", "fat16", "fat32", "ntfs", "hfs", "hfs+"]
26 _helptext = """
27 <b><u>Partitioning</u></b>
28
29 The choices you make on this screen are very important. There are 2 ways to do
30 your partitioning.
31
32 The first method is the Recommended Layout. If you really have no idea how you
33 should lay out your partitions, this is probably the best option. You will need
34 at least 4GB of concurrent disk space to use this option. If you have any
35 existing partitions, they will be kept intact. Three partitions will be created:
36 /boot (100MB), swap (calculated based on physical memory, up to 512MB), and
37 / (remaining concurrent space). The mountpoints and default mount options will
38 be automatically set for you. If you would like to mount any of your previously
39 existing partitions, you will need to edit those manually.
40
41 The second method is the old fashioned one: doing it yourself. The partition
42 edit is fairly straightforward (although, not <i>that</i> straightforward as
43 this help would not need to exist).
44
45 The currently active disk is represented by the bar near the top of the screen.
46 If you have more than one disk present in your system, you can change the
47 active disk by choosing another disk from the drop down box labeled 'Devices'.
48 Along the bottom of the screen, there is a color key for the disk representation
49 above.
50
51 To edit an existing partition, you must first select it by clicking it in the
52 bar above. You will get a brief overview of the partition below the bar. To edit
53 the partition's properties, click the button labeled 'Properties'. To delete it,
54 click the 'Delete' button. You will be asked for confirmation before the
55 partition is removed.
56
57 When you edit a partition's properties, you'll get a popup dialog with a few
58 options. If the installer is able to resize the partition, you will be able to
59 slide the bar at the top or enter a new size in the fields below the slider.
60 You can choose whether or not you want the partition to be formatted. If you
61 to keep the data, you should leave this as No. You can also choose a mountpoint
62 and mount options for the partition. If you don't enter a mountpoint, the
63 partition will not be mounted during the install and will not be added to your
64 /etc/fstab. Click 'OK' to save the changes you have made or 'Cancel' to leave it
65 as it was.
66
67 To create a new partition, select some unallocated space in the bar at the top.
68 The popup dialog that appears is the same one used for editing an existing
69 partition. The difference is that you will be able to select a partition type
70 (primary or logical for x86/amd64) and a filesystem type. If you select logical
71 for the type, an extended partition will be created automatically and take up
72 all of the remaining unallocated space. All partitions created after this will
73 automatically be logical. For a partition for use by Linux, you will want to use
74 ext2, ext3, reiserfs, jfs, or xfs. Ext3 is the recommended type.
75
76 Keep in mind that none of the changes to your partition table and filesystems
77 will be committed until you click the 'Install' button on the last screen of the
78 installer. Also, if your existing partitions are out of disk order, the
79 installer will reorder the partition numbers so that they match the physical
80 disk order.
81 """
82
83 def __init__(self, controller):
84 GLIScreen.GLIScreen.__init__(self, controller, show_title=True)
85
86 vert = gtk.VBox(False, 0)
87 vert.set_border_width(10)
88
89 content_str = _("""
90 On this screen, you will be presented with a list of detected partitionable devices. Selecting
91 a device will show you the current partitions on it (if any) and allow you to add, remove, and
92 resize partitions.""")
93
94 content_label = gtk.Label(content_str)
95 vert.pack_start(content_label, expand=False, fill=False, padding=0) # This was removed for screen space
96 container = gtk.HBox(False, 0)
97 detected_dev_label = gtk.Label(_("Devices:"))
98 container.pack_start(detected_dev_label, expand=False, fill=False, padding=0)
99 self.detected_dev_combo = gtk.combo_box_new_text()
100 self.detected_dev_combo.connect("changed", self.drive_changed)
101 container.pack_start(self.detected_dev_combo, expand=False, fill=False, padding=10)
102 self.part_button_recommended = gtk.Button(_(" Recommended layout "))
103 self.part_button_recommended.connect("clicked", self.part_button_recommended_clicked)
104 container.pack_end(self.part_button_recommended, expand=False, fill=False, padding=0)
105 self.part_button_clear = gtk.Button(_(" Clear partitions "))
106 self.part_button_clear.connect("clicked", self.part_button_clear_clicked)
107 container.pack_end(self.part_button_clear, expand=False, fill=False, padding=10)
108 self.part_button_dump_info = gtk.Button(_(" Dump to console (debug) "))
109 self.part_button_dump_info.connect("clicked", self.dump_part_info_to_console)
110 container.pack_end(self.part_button_dump_info, expand=False, fill=False, padding=0)
111
112 vert.pack_start(container, expand=False, fill=False, padding=10)
113
114 # This builds the container for the "whole disk" display at the top
115 part_table_frame = gtk.Frame()
116 part_table_frame.set_shadow_type(gtk.SHADOW_IN)
117 self.part_table = gtk.Table(1, 1, False)
118 self.part_table.set_size_request(-1, 40)
119 part_table_frame.add(self.part_table)
120 vert.pack_start(part_table_frame, expand=False, fill=False, padding=5)
121
122 # This builds the partition info box
123 self.part_info_box = gtk.HBox(False, 0)
124 part_info_table = gtk.Table(6, 2, False)
125 part_info_table.set_col_spacings(10)
126 info_partition_label = gtk.Label(_("Partition:"))
127 info_partition_label.set_alignment(0.0, 0.5)
128 self.info_partition = gtk.Label()
129 self.info_partition.set_alignment(0.0, 0.5)
130 info_type_label = gtk.Label(_("Type:"))
131 info_type_label.set_alignment(0.0, 0.5)
132 self.info_type = gtk.Label()
133 self.info_type.set_alignment(0.0, 0.5)
134 info_filesystem_label = gtk.Label(_("Filesystem:"))
135 info_filesystem_label.set_alignment(0.0, 0.5)
136 self.info_filesystem = gtk.Label()
137 self.info_filesystem.set_alignment(0.0, 0.5)
138 info_mountpoint_label = gtk.Label(_("Mountpoint:"))
139 info_mountpoint_label.set_alignment(0.0, 0.5)
140 self.info_mountpoint = gtk.Label()
141 self.info_mountpoint.set_alignment(0.0, 0.5)
142 info_size_label = gtk.Label(_("Size:"))
143 info_size_label.set_alignment(0.0, 0.5)
144 self.info_size = gtk.Label()
145 self.info_size.set_alignment(0.0, 0.5)
146 part_info_table.attach(info_partition_label, 0, 1, 0, 1)
147 part_info_table.attach(self.info_partition, 1, 2, 0, 1)
148 part_info_table.attach(info_type_label, 0, 1, 1, 2)
149 part_info_table.attach(self.info_type, 1, 2, 1, 2)
150 part_info_table.attach(info_filesystem_label, 0, 1, 2, 3)
151 part_info_table.attach(self.info_filesystem, 1, 2, 2, 3)
152 part_info_table.attach(info_mountpoint_label, 0, 1, 3, 4)
153 part_info_table.attach(self.info_mountpoint, 1, 2, 3, 4)
154
155 part_info_table.attach(info_size_label, 0, 1, 5, 6)
156 part_info_table.attach(self.info_size, 1, 2, 5, 6)
157 self.part_info_box.pack_start(part_info_table, expand=False, fill=False)
158 vert.pack_start(self.part_info_box, expand=False, fill=False, padding=10)
159
160 # This builds the row of buttons
161 self.part_button_box = gtk.HBox(False, 0)
162 self.part_button_delete = gtk.Button(_(" Delete "))
163 self.part_button_delete.connect("clicked", self.part_button_delete_clicked)
164 self.part_button_box.pack_start(self.part_button_delete, expand=False, fill=False, padding=0)
165 # self.part_button_recommended = gtk.Button(_(" Recommended "))
166 # self.part_button_recommended.connect("clicked", self.part_button_recommended_clicked)
167 # self.part_button_box.pack_start(self.part_button_recommended, expand=False, fill=False, padding=10)
168 self.part_button_properties = gtk.Button(_(" Properties "))
169 self.part_button_properties.connect("clicked", self.part_button_properties_clicked)
170 self.part_button_box.pack_start(self.part_button_properties, expand=False, fill=False, padding=10)
171 vert.pack_start(self.part_button_box, expand=False, fill=False, padding=10)
172
173 # This builds the color key at the bottom
174 color_codes = [ { 'label': "Swap", 'color': '#12ff09' },
175 { 'label': "Ext2/3", 'color': '#0af2fe' },
176 { 'label': "Reiserfs", 'color': '#f0ff00' },
177 { 'label': "JFS", 'color': '#ffb400' },
178 { 'label': "XFS", 'color': '#006600' },
179 { 'label': "FAT", 'color': '#3d07f9' },
180 { 'label': "NTFS", 'color': '#f20600' },
181 { 'label': "HFS", 'color': '#fdb0ff' },
182 { 'label': _("Other"), 'color': '#ed03e0' },
183 # { 'label': "Free space", 'color': '#ffffff' },
184 { 'label': _("Unallocated"), 'color': '#a2a2a2' }
185 ]
186 color_codes_box = gtk.HBox(False, 0)
187 vert.pack_end(color_codes_box, expand=False, fill=False, padding=2)
188 for color in color_codes:
189 temp_xpm = [ "12 12 2 1",
190 "B c #000000",
191 "C c " + color['color'],
192 "BBBBBBBBBBBB",
193 "BCCCCCCCCCCB",
194 "BCCCCCCCCCCB",
195 "BCCCCCCCCCCB",
196 "BCCCCCCCCCCB",
197 "BCCCCCCCCCCB",
198 "BCCCCCCCCCCB",
199 "BCCCCCCCCCCB",
200 "BCCCCCCCCCCB",
201 "BCCCCCCCCCCB",
202 "BCCCCCCCCCCB",
203 "BBBBBBBBBBBB"
204 ]
205 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(self.controller.window.window, None, temp_xpm)
206 tmp_image = gtk.Image()
207 tmp_image.set_from_pixmap(pixmap, mask)
208 tmpbox = gtk.HBox(False, 0)
209 tmpbox.pack_start(tmp_image, expand=False, fill=False, padding=3)
210 tmpbox.pack_start(gtk.Label(color['label']), expand=False, fill=False, padding=3)
211 color_codes_box.pack_start(tmpbox, expand=False, fill=False, padding=6)
212
213 self.add_content(vert)
214 # self.detected_dev_combo.set_active(0)
215
216 def drive_changed(self, combobox, data=None):
217 self.active_device = self.drives[self.detected_dev_combo.get_active()]
218 self.draw_part_box()
219 self.active_device_bytes_in_sector = self.devices[self.active_device].get_geometry()['sector_size']
220 self.info_partition.set_text("")
221 self.info_type.set_text("")
222 self.info_filesystem.set_text("")
223 self.info_mountpoint.set_text("")
224 # self.info_end.set_text("")
225 self.info_size.set_text("")
226 self.part_info_box.hide_all()
227 # self.resize_box.hide_all()
228 self.part_button_box.hide_all()
229 # self.part_mount_info_box.hide_all()
230
231 def part_selected(self, button, dev=None, idx=None):
232 tmppart = self.devices[dev].get_partition(idx)
233 self.info_partition.set_text(tmppart['devnode'])
234 if self.devices[dev]._labelinfo['extended'] and tmppart['minor'] > 4:
235 self.info_type.set_text(_("Logical"))
236 elif tmppart.get_type() == "extended":
237 self.info_type.set_text(_("Extended"))
238 else:
239 self.info_type.set_text(_("Primary"))
240 fstype = tmppart.get_type()
241 if fstype == "extended":
242 self.info_filesystem.set_text(_("N/A"))
243 else:
244 self.info_filesystem.set_text(fstype)
245 # self.info_mountpoint.set_text(tmppart.get_mountpoint() or "none")
246 start = tmppart.get_start()
247 end = tmppart.get_end()
248 # self.info_start.set_text(str(start))
249 # self.info_end.set_text(str(end))
250 # part_size = int(round(float(self.devices[dev].get_sector_size()) * (end - start + 1) / 1024 / 1024))
251 part_size = int(tmppart.get_mb())
252 self.info_size.set_text(str(part_size) + _(" MB"))
253 self.active_part_idx = idx
254 self.part_button_delete.set_sensitive(True)
255 self.part_info_box.show_all()
256 self.part_button_box.show_all()
257
258 def unalloc_selected(self, button, dev=None, extended=False, mb=0, minor=0):
259 props = PartProperties.PartProperties(self, self.active_device, minor, 0, 0, mb, "free", self.active_device_bytes_in_sector)
260 props.run()
261
262 def part_button_delete_clicked(self, button, data=None):
263 msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("Are you sure you want to delete ") + self.devices[self.active_device].get_partition(self.active_part_idx)['devnode'])
264 resp = msgdlg.run()
265 msgdlg.destroy()
266 if resp == gtk.RESPONSE_YES:
267 self.devices[self.active_device].remove_partition(self.active_part_idx)
268 if self.devices[self.active_device]._labelinfo['extended'] and self.active_part_minor > 4:
269 ext_part = self.devices[self.active_device].get_extended_partition()
270 if not len(self.devices[self.active_device].get_partition(ext_part).get_logicals()):
271 self.devices[self.active_device].remove_partition(ext_part)
272 self.drive_changed(None)
273
274 def part_button_recommended_clicked(self, button):
275 try:
276 self.devices[self.active_device].do_recommended()
277 except GLIException, error:
278 msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=error.get_error_msg())
279 msgdlg.run()
280 msgdlg.destroy()
281 self.draw_part_box()
282
283 def part_button_clear_clicked(self, button):
284 msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("Are you sure you wish to clear the partition table for " + self.active_device + "?"))
285 resp = msgdlg.run()
286 msgdlg.destroy()
287 if resp == gtk.RESPONSE_YES:
288 self.devices[self.active_device].clear_partitions()
289 self.drive_changed(self.detected_dev_combo)
290
291 def draw_part_box(self):
292 # partlist = self.devices[self.active_device].get_ordered_partition_list()
293 total_mb = self.devices[self.active_device].get_geometry()['total_mb']
294 for button in self.part_buttons.keys():
295 self.part_table.remove(self.part_buttons[button])
296 self.part_table.resize(1, 100)
297 self.part_buttons = {}
298 last_percent = 0
299 last_log_percent = 0
300 extended_part = 0
301 extended_table = None
302 for idx, tmppart in enumerate(self.devices[self.active_device]):
303 # tmppart = self.devices[self.active_device][part]
304 if tmppart.get_type() == "free":
305 partsize = tmppart.get_mb()
306 percent = (float(partsize) / float(total_mb)) * 100
307 if percent < 1: percent = 1
308 percent = int(percent)
309 # print "minor: " + str(part) + ", mb: " + str(partsize) + ", percent: " + str(percent) + ", last_percent: " + str(last_percent)
310 if tmppart.is_logical():
311 tmpbutton = PartitionButton.Partition(color1=self.colors['unalloc'], color2=self.colors['unalloc'], label="", division=0)
312 tmpbutton.connect("clicked", self.unalloc_selected, self.active_device, False, partsize, tmppart.get_minor())
313 extended_table.attach(tmpbutton, last_log_percent, (last_log_percent + percent), 0, 1)
314 last_log_percent = last_log_percent + percent
315 else:
316 self.part_buttons['free_' + str(tmppart.get_minor())] = PartitionButton.Partition(color1=self.colors['unalloc'], color2=self.colors['unalloc'], label="", division=0)
317 if self.devices[self.active_device]._labelinfo['extended'] and self.devices[self.active_device].get_partition(1) and self.devices[self.active_device].get_partition(2) and self.devices[self.active_device].get_partition(3) and self.devices[self.active_device].get_partition(4):
318 self.part_buttons['free_' + str(tmppart.get_minor())].connect("clicked", self.show_no_more_primary_message)
319 else:
320 self.part_buttons['free_' + str(tmppart.get_minor())].connect("clicked", self.unalloc_selected, self.active_device, False, partsize, tmppart.get_minor())
321 self.part_table.attach(self.part_buttons['free_' + str(tmppart.get_minor())], last_percent, (last_percent + percent), 0, 1)
322 last_percent = last_percent + percent
323 else:
324 partsize = tmppart.get_mb()
325 percent = (float(partsize) / float(total_mb)) * 100
326 if percent < 1: percent = 1
327 percent = int(percent)
328 tmpminor = int(tmppart.get_minor())
329 tmpdevice = self.active_device
330 # print "minor: " + str(tmpminor) + ", mb: " + str(partsize) + ", percent: " + str(percent) + ", last_percent: " + str(last_percent)
331 if tmppart.is_extended():
332 extended_table = gtk.Table(1, percent)
333 extended_table.set_border_width(3)
334 extended_part = tmpminor
335 self.part_buttons[tmpminor] = extended_table
336 self.part_table.attach(self.part_buttons[tmpminor], last_percent, (last_percent + percent), 0, 1)
337 last_percent = last_percent + percent
338 elif tmppart.is_logical():
339 tmpbutton = PartitionButton.Partition(color1=self.colors[tmppart.get_type()], color2=self.colors[tmppart.get_type()], label="", division=0)
340 if percent >= 15:
341 tmpbutton.set_label(tmppart['devnode'])
342 extended_table.attach(tmpbutton, last_log_percent, (last_log_percent + percent), 0, 1)
343 last_log_percent = last_log_percent + percent
344 tmpbutton.connect("clicked", self.part_selected, tmpdevice, idx)
345 else:
346 self.part_buttons[tmpminor] = PartitionButton.Partition(color1=self.colors[tmppart.get_type()], color2=self.colors[tmppart.get_type()], label="", division=0)
347 if percent >= 15:
348 self.part_buttons[tmpminor].set_label(tmppart['devnode'])
349 self.part_buttons[tmpminor].connect("clicked", self.part_selected, tmpdevice, idx)
350 self.part_table.attach(self.part_buttons[tmpminor], last_percent, (last_percent + percent), 0, 1)
351 last_percent = last_percent + percent
352 self.part_table.show_all()
353
354 def show_no_more_primary_message(self, button, data=None):
355 msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK, message_format=_("You cannot create more than 4 primary partitions. If you need more partitions, delete one or more and create logical partitions."))
356 msgdlg.run()
357 msgdlg.destroy()
358
359 def dump_part_info_to_console(self, button, data=None):
360 import pprint
361 pp = pprint.PrettyPrinter(indent=4)
362 pp.pprint(self.devices[self.active_device].get_install_profile_structure())
363
364 def part_button_properties_clicked(self, widget, data=None):
365 tmppart = self.devices[self.active_device].get_partition(self.active_part_idx)
366 props = PartProperties.PartProperties(self, self.active_device, self.active_part_idx)
367 props.run()
368
369 def activate(self):
370 self.controller.SHOW_BUTTON_EXIT = True
371 self.controller.SHOW_BUTTON_HELP = True
372 self.controller.SHOW_BUTTON_BACK = False
373 self.controller.SHOW_BUTTON_FORWARD = True
374 self.controller.SHOW_BUTTON_FINISH = False
375
376 # self.devices = self.controller.install_profile.get_partition_tables()
377 # if not self.devices:
378 part_load_error = 0
379 tmp_drives = Partitioning.detect_devices()
380 tmp_drives.sort()
381 for drive in tmp_drives:
382 try:
383 self.devices[drive] = Partitioning.Device(drive, arch="x86")
384 # self.devices[drive].set_partitions_from_disk()
385 self.detected_dev_combo.append_text(drive)
386 self.drives.append(drive)
387 except:
388 print _("Exception received while loading partitions from device " + drive)
389 if self.devices.has_key(drive): del self.devices[drive]
390 part_load_error = 1
391 if part_load_error:
392 msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_OK, message_format="There was an error loading one or more drives' partition table. Possible causes are running as a normal user or partitions being out of disk order.")
393 msgdlg.run()
394 msgdlg.destroy()
395 # return
396
397 if not self.drives:
398 tmp_drives = self.devices.keys()
399 tmp_drives.sort()
400 self.drives = tmp_drives
401 for drive in self.drives:
402 self.detected_dev_combo.append_text(drive)
403
404 if self.devices:
405 self.active_device = self.drives[0]
406 self.detected_dev_combo.set_active(0)
407 self.drive_changed(None)
408
409 # for device in self.devices:
410 # for tmppart in self.devices[device].get_partitions():
411 # if tmppart.get_type() == "unknown":
412 # msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_WARNING, buttons=gtk.BUTTONS_OK, message_format="One of your disks (%s) contains a partition (minor %s) of a type that the installer cannot currently handle. If you continue, you risk damaging your partition table. You have been warned!" % (device, str(tmppart.get_minor())))
413 # msgdlg.run()
414 # msgdlg.destroy()
415 # return
416
417 def deactivate(self):
418 parts_tmp = {}
419 for device in self.devices.keys():
420 parts_tmp[device] = self.devices[device].get_install_profile_structure()
421 for device in parts_tmp:
422 for part in parts_tmp[device]:
423 if part['mountpoint'] == "/":
424 self.controller.install_profile.set_partition_tables(self.devices)
425 return True
426 msgdlg = gtk.MessageDialog(parent=self.controller.window, type=gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_YES_NO, message_format=_("You have not specified a partition to mount as /. Do you want to continue?"))
427 resp = msgdlg.run()
428 msgdlg.destroy()
429 if resp == gtk.RESPONSE_YES:
430 self.controller.install_profile.set_partition_tables(self.devices)
431 return True
432 else:
433 return False

Properties

Name Value
svn:eol-style native

  ViewVC Help
Powered by ViewVC 1.1.20