#!/usr/bin/env python from python_tqt.qt import * from tdecore import * import sys, os def getLabel(blocks): """ Translates blocksize into human readable labels, such as 17.3 Gb, 2.1 Mb. """ try: blocks = int(blocks) # 1K blocks now. except ValueError: return i18n("n/a") if blocks<1024: return i18n("%1 Kb").arg(blocks) if blocks<1024*1024: return i18n("%1 Mb").arg(round(float(blocks)/1024.0,1)) blocks /= 1024 if blocks<1024*1024: return i18n("%1 Gb").arg(round(float(blocks)/1024.0,1)) blocks /= 1024 return i18n("%1 Tb").arg(round(float(blocks)/1024.0,1)) class SizeViewApplication(TQApplication): """ Boilerplate """ def __init__(self,devicename,devicepath,args=[]): TQApplication.__init__(self,args) self.maindialog = SizeView(None,devicename,devicepath) self.setMainWidget(self.maindialog) self.maindialog.show() self.exec_loop() class SizeView(TQDialog): """ A SizeView represents a horizontal list of PartitionGroupWidgets. It supplies the code to read the sizes and the values that have to be filled in, using the /proc filesystem and the program "df". """ dev_path = "/dev/" # Where to look for the partitions devicename = "" # Such as hda1 partitions = {} # List of partitions sizes = {} # Maps devicenames to blocksizes mountpoints = {} # Maps devicenames to mountpoints used = {} # Blocks used on a partition available = {} # Blocks available part_types = {} # Maps devicenames to partitiontypes partitionwidgets = [] # Holds a list of the PartitionGroup widgets def __init__(self,parent,devicename,devicepath=None): self.partitionwidgets = [] TQDialog.__init__(self,None,None,0,0) self.dialogtitle = i18n("Diskspace & Partitions") self.setCaption(self.dialogtitle) self.devicename = devicename if devicepath: self.dev_path = devicepath # Retrieve all information from the system. self.readMounts() self.readSize() self.readSwaps() partitions = self.partitions.keys() partitions.sort() number=1 for part in partitions: try: fill = self.sizes[part] mountpoint = self.mountpoints[part] used = self.used[part] available = self.available[part] except KeyError: # Handles empty or not-mounted partitions fill = None mountpoint = i18n("n/a") used = str(i18n("n/a")) available = str(i18n("n/a")) pwidg = PartitionGroup(part,self,fill,number,self.part_types,self.dev_path) pwidg.setSize(self.partitions[part]) pwidg.setMountPoint(mountpoint) pwidg.setUsed(used) pwidg.setAvailable(available) pwidg.setSizePolicy(TQSizePolicy(TQSizePolicy.MinimumExpanding,TQSizePolicy.MinimumExpanding,0,0, pwidg.sizePolicy().hasHeightForWidth())) self.partitionwidgets.append(pwidg) number += 1 n = len(partitions) r = 2 c = 0 cols = 1 # Compute number of rows needed for partitions. if n%cols > 0: rows = int(n/cols)+1 else: rows = int(n/cols) if n is 1: rows = 2 # Build main Gridlayout. total_rows = rows+2 self.grid = TQGridLayout(self,total_rows,2,5) #self.setSizeGripEnabled(1) self.buttonCancel = TQPushButton(i18n("Close"),self,"buttonCancel") self.buttonCancel.setAutoDefault(1) self.buttonCancel.setFixedWidth(80) self.grid.addWidget(self.buttonCancel,total_rows-1,1,TQt.AlignRight) self.grid.setRowStretch(0,0) self.grid.setRowStretch(total_rows-1,0) # Stretch all but first and last rows. for row in range(1,total_rows-1): self.grid.setRowStretch(row,5) self.clearWState(TQt.WState_Polished) self.connect(self.buttonCancel,SIGNAL("clicked()"),self.hide) #self.mainlabel = TQLabel(""+self.dialogtitle+"",self) #self.grid.addWidget(self.mainlabel,0,0) self.diskgroup = DiskGroup(self,self.devicename,self.dev_path,self.partitions,self.totalsize,self.mountpoints) self.grid.addMultiCellWidget(self.diskgroup,1,1,0,1) for pw in self.partitionwidgets: self.grid.addWidget(pw,r,c) if c is cols: r += 1 c = 0 else: c += 1 def readSize(self): fhandle = open("/proc/partitions","r") self.partitions = {} self.totalsize = 0 for line in fhandle.readlines(): try: major,minor,blocks,name = line.split() if name == self.devicename: self.totalsize = blocks if name[:len(self.devicename)] == self.devicename and len(name) > len(self.devicename): self.partitions[name] = blocks except ValueError: pass fhandle.close() def readMounts(self): fhandle = os.popen("/bin/df") for l in fhandle.readlines(): v = l.split() try: p,s = v[0].split("/")[2],v[4][:-1] self.sizes[p] = s self.mountpoints[p] = v[5] self.used[p] = v[2] self.available[p] = v[3] self.part_types[p] = "filesystem" except IndexError: pass fhandle.close() def readSwaps(self): fhandle = open("/proc/swaps") for line in fhandle.readlines(): try: device,type,size,used,priority = line.split() device = device[len(self.dev_path):] self.used[device] = used self.sizes[device] = round(float(used)/float(size)*100 ,1) self.available[device] = str(int(size)-int(used)) self.mountpoints[device] = "swap" self.part_types[device] = "swap" except: pass fhandle.close() """ def __show__(self): print self.partitions print "Device", self.devicename, self.totalsize for p in self.partitions: print p, self.partitions[p], self.partitions[p] """ class DiskGroup(TQGroupBox): """ Shows an overview of the physical layout of the disks, with the different partitions on it. """ def __init__(self,parent,device,dev_path,partitions,totalsize,mountpoints): TQGroupBox.__init__(self,parent,"DiskViewGroup") self.setTitle(i18n("Disk %1%2").arg(dev_path).arg(device)) self.mountpoints = mountpoints self.partitions = partitions self.totalsize = totalsize self.setColumnLayout(0,TQt.Vertical) self.layout().setSpacing(6) self.layout().setMargin(11) DiskViewGroupLayout = TQVBoxLayout(self.layout()) DiskViewGroupLayout.setAlignment(TQt.AlignTop) colors = ["dark orange","dodger blue","gold","green","firebrick","navy","darkorange","darkblue"] self.diskview = DiskView(self,self.percentages(),colors) self.diskview.setScaledContents(1) DiskViewGroupLayout.addWidget(self.diskview) parts = self.partitions.keys() parts.sort() self.percentages() cols = 3 # Number of columns to use for colorlabels. rows = len(parts)/cols mod = len(parts)%cols if mod > 0: rows += cols-mod # We multiply the number of cols by 3, first for the colorlabel, second for the name, third for spacing. cols = cols*3 DiskViewPartitionListLayout = TQGridLayout(DiskViewGroupLayout,rows,cols) i = cl = r = c = 0 ps = ls = {} for dev in parts: ps[i] = LegendLabel(self,colors[cl]) DiskViewPartitionListLayout.addWidget(ps[i],r,c) try: lbl = self.mountpoints[dev] except KeyError: lbl = "not mounted" ls[i] = TQLabel(self,lbl+'
('+dev_path+dev+')',self) DiskViewPartitionListLayout.addWidget(ls[i],r,c+1) cl += 1 if cl == len(colors): cl = 0 i += 1 if c is cols: c = 0 r += 1 else: c += 3 def percentages(self): p_t = 0 for p in self.partitions.values(): p_t += int(p) self.perc = {} for p in self.partitions.keys(): self.perc[p] = float(float(self.partitions[p])/float(p_t)) return self.perc class PartitionGroup(TQGroupBox): """ Represents a groupbox with the filled bar and a couple of labels with information about the partition in it.""" blocksize = 0 title = str(i18n("Partition")) def __init__(self,device,parent,fill_percent,number,part_types,dev_path): TQGroupBox.__init__(self,parent) self.part_types = part_types self.dev_path = dev_path self.setGeometry(TQRect(110,100,370,203)) self.setColumnLayout(0,TQt.Vertical) self.layout().setSpacing(3) self.layout().setMargin(5) self.setMinimumSize(280,120) partitiongroup_layout = TQGridLayout(self.layout()) partitiongroup_layout.setAlignment(TQt.AlignTop) self.available = TQLabel(i18n("available"),self) partitiongroup_layout.addWidget(self.available,3,4) self.device = TQLabel(i18n("device"),self) partitiongroup_layout.addMultiCellWidget(self.device,1,1,3,4) self.partpixmap = PartitionView(self,fill_percent,self.part_types,device) self.partpixmap.setScaledContents(1) partitiongroup_layout.addMultiCellWidget(self.partpixmap,0,0,0,4) self.textLabel1_3 = TQLabel("textLabel1_3",self) partitiongroup_layout.addWidget(self.textLabel1_3,3,0) self.totalsize = TQLabel("totalsize",self) partitiongroup_layout.addWidget(self.totalsize,2,1) self.textLabel1_2 = TQLabel(self,"textLabel1_2") partitiongroup_layout.addWidget(self.textLabel1_2,2,0) self.textLabel1 = TQLabel(self,"textLabel1") partitiongroup_layout.addWidget(self.textLabel1,1,0) self.textLabel3_2 = TQLabel(self,"textLabel3_2") partitiongroup_layout.addMultiCellWidget(self.textLabel3_2,2,2,2,3) self.percentfilled = TQLabel(self,"percentfree") partitiongroup_layout.addWidget(self.percentfilled,2,4) self.textLabel3_3 = TQLabel(self,"textLabel3_3") partitiongroup_layout.addWidget(self.textLabel3_3,3,2) self.textLabel3 = TQLabel(self,"textLabel3") partitiongroup_layout.addWidget(self.textLabel3,1,2) self.used = TQLabel(self,"used") partitiongroup_layout.addWidget(self.used,3,1) self.mountpoint = TQLabel(self,"mountpoint") self.mountpoint.setMinimumSize(TQSize(60,0)) partitiongroup_layout.addWidget(self.mountpoint,1,1) self.clearWState(TQt.WState_Polished) self.setTitle(i18n("%1. Partition").arg(number)) self.textLabel1_3.setText(i18n("Used:")) self.textLabel1_2.setText(i18n("Total Size:")) self.textLabel1.setText(i18n("Mountpoint:")) self.textLabel3_2.setText(i18n("% Used:")) self.textLabel3_3.setText(i18n("Available:")) self.textLabel3.setText(i18n("Device:")) self.setDevice(self.dev_path+device) self.setFillPercentage(fill_percent) def setSize(self,label): self.totalsize.setText(getLabel(label)) def setDevice(self,device): self.device.setText(device) def setMountPoint(self,mountpoint): self.mountpoint.setText(mountpoint) self.setTitle(i18n("Partition %1").arg(mountpoint)) def setTotalSize(self,totalsize): self.totalsize.setText(getLabel(totalsize)) def setFillPercentage(self,fill_percent): self.fill_percent = self.partpixmap.fill_percent = fill_percent if fill_percent is not None: self.percentfilled.setText("%s%%" % fill_percent) else: self.percentfilled.setText(i18n("Unknown")) def setUsed(self,used): self.used.setText(getLabel(used)) def setAvailable(self,available): self.available.setText(getLabel(available)) class LegendLabel(TQLabel): """ Show some color in the DiskView legend """ def __init__(self,parent,color="green",style=TQBrush.SolidPattern): TQLabel.__init__(self,parent,"bla") self.w = 40 self.h = 20 self.pmsize = TQSize(self.w,self.h) self.pm = TQPixmap(self.pmsize) self.linewidth = 2 self.color = TQColor(color) self.style = style self.framecolor = TQColor("black") self.paintMe() self.setPixmap(self.pm) self.setScaledContents(1) self.setSizePolicy(TQSizePolicy(TQSizePolicy.Fixed,TQSizePolicy.Fixed,0,0, self.sizePolicy().hasHeightForWidth())) def paintMe(self): p = TQPainter(self.pm) p.fillRect(0,0,self.w,self.h,TQBrush(self.color,self.style)) p.setPen(TQPen(TQColor("black"),self.linewidth)) p.drawRect(self.linewidth/2,self.linewidth/2,self.w-self.linewidth/2,self.h-self.linewidth/2) p.end() class PartitionView(TQLabel): """ PartitionView is a label carryig a pixmap. This class's main purpose is handlig layout of the underlying pixmap.""" w = 250 h = 35 def __init__(self,parent,fill_percent,part_types,device): self.part_types = part_types self.fill_percent = fill_percent TQLabel.__init__(self,parent,"pview") self.setSizePolicy(TQSizePolicy(TQSizePolicy.Expanding,TQSizePolicy.Expanding,0,0, self.sizePolicy().hasHeightForWidth())) self.setMinimumSize(TQSize(self.w,self.h)) self.setPixmap(PartitionPixmap(TQSize(self.w,self.h),self.fill_percent,self.part_types,device)) self.setScaledContents(1) self.setAlignment(TQLabel.AlignCenter) class DiskView(PartitionView): """ PartitionView is a label carryig a pixmap. This class's main purpose is handlig layout of the underlying pixmap.""" w = 540 h = 50 linewidth = 2 def __init__(self,parent,percents,colors): TQLabel.__init__(self,parent) self.setSizePolicy(TQSizePolicy(TQSizePolicy.Expanding,TQSizePolicy.Expanding,0,0, self.sizePolicy().hasHeightForWidth())) self.setPixmap(DiskPixmap(percents,colors,(self.w,self.h))) self.setScaledContents(1) self.setAlignment(TQLabel.AlignCenter) class DiskPixmap(TQPixmap): linewidth = 2 # Width of surrounding frame def __init__(self,percents,colors,(w,h)): self.percents = percents self.w,self.h = w,h self.colors = colors TQPixmap.__init__(self,w,h) self.paintMe() def paintMe(self): p = TQPainter(self) w,h = self.w,self.h i = 0 x0 = 0 y = 0 # Paint background, this is interesting for empty partitions. p.fillRect(0,0,w,h,TQBrush(TQColor("white"))) parts = self.percents.keys() parts.sort() xa = wa = 0 for part in parts: W = (w * self.percents[part]) # We need to adjust a little to avoid to get wholes. if x0>0: xa = 2 if W < self.w: wa = 2 p.fillRect(x0-xa,0,W+wa,h,TQBrush(TQColor(self.colors[i]))) i += 1 x0 += W # Paint Frame around it. p.setPen(TQPen(TQColor("black"),self.linewidth)) p.drawRect(self.linewidth/2,self.linewidth/2,self.width()-self.linewidth/2,self.height()-self.linewidth/2) p.end() class PartitionPixmap(TQPixmap): """ A PartitionPixmap is a two colored bar with a black frame. The first color represents the percentage that's used, the second one the free percentage.""" linewidth = 2 # Width of surrounding frame def __init__(self,pmsize,fill_percent,part_types,device): TQPixmap.__init__(self,pmsize) self.pmsize = pmsize # Size of the pixmap self.part_types = part_types # Array to look up the type of the partition self.fill_percent = fill_percent self.device = device # Device name of the partition self.w = self.pmsize.width() self.h = self.pmsize.height() self.paintMe() def paintMe(self): p = TQPainter(self) try: fill_percent = int(self.fill_percent) if self.part_types[self.device] == "swap": # Swap partitions get blueish colors. color_used = TQColor("blue") color_free = TQColor("lightblue") else: # Regular partitions get a red / green color combo. color_used = TQColor("red") color_free = TQColor("forest green") except (KeyError,TypeError): # Partition has no fillsize, might be empty or not mounted partition p.fillRect(0,0,self.w,self.h,TQBrush(TQColor("darkgrey"))) p.setPen(TQPen(TQColor("black"),self.linewidth)) p.drawRect(self.linewidth/2,self.linewidth/2,self.w-self.linewidth/2,self.h-self.linewidth/2) p.end() return # Total width of the pixmap W,H = float(self.w),float(self.h) # Paint filled == red part of the bar. x = y = 0 w = W - (W*(1-(fill_percent/100.00))) h = H p.fillRect(x,y,w,h,TQBrush(color_used)) # Paint green part == space left x = w w = W - w p.fillRect(x,y,w,h,TQBrush(color_free)) # Paint Frame around it. p.setPen(TQPen(TQColor("black"),self.linewidth)) p.drawRect(self.linewidth/2,self.linewidth/2,W-self.linewidth/2,H-self.linewidth/2) p.end() if __name__ == "__main__": device = "sdc" app = SizeViewApplication(device,None,sys.argv)