summaryrefslogtreecommitdiffstats
path: root/mountconfig/sizeview.py
diff options
context:
space:
mode:
Diffstat (limited to 'mountconfig/sizeview.py')
-rw-r--r--mountconfig/sizeview.py504
1 files changed, 504 insertions, 0 deletions
diff --git a/mountconfig/sizeview.py b/mountconfig/sizeview.py
new file mode 100644
index 0000000..bbb1f5b
--- /dev/null
+++ b/mountconfig/sizeview.py
@@ -0,0 +1,504 @@
+#!/usr/bin/env python
+
+from qt import *
+from kdecore 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(QApplication):
+ """ Boilerplate """
+ def __init__(self,devicename,devicepath,args=[]):
+ QApplication.__init__(self,args)
+
+ self.maindialog = SizeView(None,devicename,devicepath)
+ self.setMainWidget(self.maindialog)
+ self.maindialog.show()
+ self.exec_loop()
+
+class SizeView(QDialog):
+ """ 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 = []
+ QDialog.__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(QSizePolicy(QSizePolicy.MinimumExpanding,QSizePolicy.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 = QGridLayout(self,total_rows,2,5)
+ #self.setSizeGripEnabled(1)
+
+ self.buttonCancel = QPushButton(i18n("Close"),self,"buttonCancel")
+ self.buttonCancel.setAutoDefault(1)
+ self.buttonCancel.setFixedWidth(80)
+ self.grid.addWidget(self.buttonCancel,total_rows-1,1,Qt.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(Qt.WState_Polished)
+ self.connect(self.buttonCancel,SIGNAL("clicked()"),self.hide)
+
+ #self.mainlabel = QLabel("<font size=+2><b>"+self.dialogtitle+"</b></font>",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(QGroupBox):
+ """ 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):
+
+ QGroupBox.__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,Qt.Vertical)
+ self.layout().setSpacing(6)
+ self.layout().setMargin(11)
+ DiskViewGroupLayout = QVBoxLayout(self.layout())
+ DiskViewGroupLayout.setAlignment(Qt.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 = QGridLayout(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] = QLabel(self,lbl+'<br /> ('+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(QGroupBox):
+ """ 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):
+ QGroupBox.__init__(self,parent)
+ self.part_types = part_types
+ self.dev_path = dev_path
+ self.setGeometry(QRect(110,100,370,203))
+ self.setColumnLayout(0,Qt.Vertical)
+ self.layout().setSpacing(3)
+ self.layout().setMargin(5)
+ self.setMinimumSize(280,120)
+
+ partitiongroup_layout = QGridLayout(self.layout())
+ partitiongroup_layout.setAlignment(Qt.AlignTop)
+ self.available = QLabel(i18n("available"),self)
+ partitiongroup_layout.addWidget(self.available,3,4)
+
+ self.device = QLabel(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 = QLabel("textLabel1_3",self)
+ partitiongroup_layout.addWidget(self.textLabel1_3,3,0)
+ self.totalsize = QLabel("totalsize",self)
+ partitiongroup_layout.addWidget(self.totalsize,2,1)
+ self.textLabel1_2 = QLabel(self,"textLabel1_2")
+ partitiongroup_layout.addWidget(self.textLabel1_2,2,0)
+ self.textLabel1 = QLabel(self,"textLabel1")
+ partitiongroup_layout.addWidget(self.textLabel1,1,0)
+ self.textLabel3_2 = QLabel(self,"textLabel3_2")
+ partitiongroup_layout.addMultiCellWidget(self.textLabel3_2,2,2,2,3)
+ self.percentfilled = QLabel(self,"percentfree")
+ partitiongroup_layout.addWidget(self.percentfilled,2,4)
+ self.textLabel3_3 = QLabel(self,"textLabel3_3")
+ partitiongroup_layout.addWidget(self.textLabel3_3,3,2)
+ self.textLabel3 = QLabel(self,"textLabel3")
+ partitiongroup_layout.addWidget(self.textLabel3,1,2)
+ self.used = QLabel(self,"used")
+ partitiongroup_layout.addWidget(self.used,3,1)
+ self.mountpoint = QLabel(self,"mountpoint")
+ self.mountpoint.setMinimumSize(QSize(60,0))
+ partitiongroup_layout.addWidget(self.mountpoint,1,1)
+ self.clearWState(Qt.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(QLabel):
+ """ Show some color in the DiskView legend """
+
+ def __init__(self,parent,color="green",style=QBrush.SolidPattern):
+ QLabel.__init__(self,parent,"bla")
+ self.w = 40
+ self.h = 20
+ self.pmsize = QSize(self.w,self.h)
+ self.pm = QPixmap(self.pmsize)
+ self.linewidth = 2
+ self.color = QColor(color)
+ self.style = style
+ self.framecolor = QColor("black")
+ self.paintMe()
+ self.setPixmap(self.pm)
+ self.setScaledContents(1)
+ self.setSizePolicy(QSizePolicy(QSizePolicy.Fixed,QSizePolicy.Fixed,0,0,
+ self.sizePolicy().hasHeightForWidth()))
+
+ def paintMe(self):
+ p = QPainter(self.pm)
+ p.fillRect(0,0,self.w,self.h,QBrush(self.color,self.style))
+ p.setPen(QPen(QColor("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(QLabel):
+ """ 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
+ QLabel.__init__(self,parent,"pview")
+ self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding,0,0,
+ self.sizePolicy().hasHeightForWidth()))
+ self.setMinimumSize(QSize(self.w,self.h))
+ self.setPixmap(PartitionPixmap(QSize(self.w,self.h),self.fill_percent,self.part_types,device))
+ self.setScaledContents(1)
+ self.setAlignment(QLabel.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):
+ QLabel.__init__(self,parent)
+
+ self.setSizePolicy(QSizePolicy(QSizePolicy.Expanding,QSizePolicy.Expanding,0,0,
+ self.sizePolicy().hasHeightForWidth()))
+ self.setPixmap(DiskPixmap(percents,colors,(self.w,self.h)))
+ self.setScaledContents(1)
+ self.setAlignment(QLabel.AlignCenter)
+
+class DiskPixmap(QPixmap):
+
+ 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
+ QPixmap.__init__(self,w,h)
+ self.paintMe()
+
+ def paintMe(self):
+ p = QPainter(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,QBrush(QColor("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,QBrush(QColor(self.colors[i])))
+ i += 1
+ x0 += W
+
+ # Paint Frame around it.
+ p.setPen(QPen(QColor("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(QPixmap):
+ """ 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):
+ QPixmap.__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 = QPainter(self)
+ try:
+ fill_percent = int(self.fill_percent)
+ if self.part_types[self.device] == "swap":
+ # Swap partitions get blueish colors.
+ color_used = QColor("blue")
+ color_free = QColor("lightblue")
+ else:
+ # Regular partitions get a red / green color combo.
+ color_used = QColor("red")
+ color_free = QColor("forest green")
+ except (KeyError,TypeError):
+ # Partition has no fillsize, might be empty or not mounted partition
+ p.fillRect(0,0,self.w,self.h,QBrush(QColor("darkgrey")))
+ p.setPen(QPen(QColor("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,QBrush(color_used))
+
+ # Paint green part == space left
+ x = w
+ w = W - w
+ p.fillRect(x,y,w,h,QBrush(color_free))
+
+ # Paint Frame around it.
+ p.setPen(QPen(QColor("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)