Przeglądaj źródła

Qubes Manager with more tabular layout

Agnieszka Kostrzewa 12 lat temu
rodzic
commit
5600056d44
3 zmienionych plików z 725 dodań i 258 usunięć
  1. 2 28
      Makefile
  2. 494 0
      mainwindow.ui
  3. 229 230
      qubesmanager/main.py

+ 2 - 28
Makefile

@@ -1,36 +1,10 @@
-RPMS_DIR=rpm/
 VERSION := $(shell cat version)
-help:
-	@echo "make rpms                  -- generate binary rpm packages"
-	@echo "make res                   -- compile resources"
-	@echo "make update-repo-current   -- copy newly generated rpms to qubes yum repo"
-	@echo "make update-repo-unstable  -- same, but to -testing repo"
-	@echo "make update-repo-installer -- copy dom0 rpms to installer repo"
-
-
-rpms:	
-	rpmbuild --define "_rpmdir $(RPMS_DIR)" -bb rpm_spec/qmgr.spec
-	rpm --addsign $(RPMS_DIR)/x86_64/qubes-manager*$(VERSION)*.rpm
 
 res:
-	pyrcc4 -o qubesmanager/qrc_resources.py resources.qrc
+	pyrcc4 -o qubesmanager/resources_rc.py resources.qrc
+	pyuic4 -o qubesmanager/ui_mainwindow.py mainwindow.ui
 	pyuic4 -o qubesmanager/ui_newappvmdlg.py newappvmdlg.ui
 	pyuic4 -o qubesmanager/ui_editfwrulesdlg.py editfwrulesdlg.ui
 	pyuic4 -o qubesmanager/ui_newfwruledlg.py newfwruledlg.ui
 
-update-repo-current:
-	ln -f $(RPMS_DIR)/x86_64/qubes-manager-*$(VERSION)*.rpm ../yum/current-release/current/dom0/rpm/
-	cd ../yum && ./update_repo.sh
-
-update-repo-current-testing:
-	ln -f $(RPMS_DIR)/x86_64/qubes-manager-*$(VERSION)*.rpm ../yum/current-release/current-testing/dom0/rpm/
-	cd ../yum && ./update_repo.sh
-
-update-repo-unstable:
-	ln -f $(RPMS_DIR)/x86_64/qubes-manager-*$(VERSION)*.rpm ../yum/current-release/unstable/dom0/rpm/
-	cd ../yum && ./update_repo.sh
-
-update-repo-installer:
-	ln -f $(RPMS_DIR)/x86_64/qubes-manager-*$(VERSION)*.rpm ../installer/yum/qubes-dom0/rpm/
-
 clean:

+ 494 - 0
mainwindow.ui

@@ -0,0 +1,494 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VmManagerWindow</class>
+ <widget class="QMainWindow" name="VmManagerWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>821</width>
+    <height>600</height>
+   </rect>
+  </property>
+  <property name="sizePolicy">
+   <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
+  <property name="windowTitle">
+   <string>MainWindow</string>
+  </property>
+  <widget class="QWidget" name="centralwidget">
+   <property name="enabled">
+    <bool>true</bool>
+   </property>
+   <property name="sizePolicy">
+    <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+     <horstretch>1</horstretch>
+     <verstretch>1</verstretch>
+    </sizepolicy>
+   </property>
+   <property name="acceptDrops">
+    <bool>false</bool>
+   </property>
+   <property name="autoFillBackground">
+    <bool>true</bool>
+   </property>
+   <property name="locale">
+    <locale language="English" country="UnitedStates"/>
+   </property>
+   <layout class="QVBoxLayout" name="verticalLayout">
+    <property name="spacing">
+     <number>0</number>
+    </property>
+    <item>
+     <widget class="QTableWidget" name="table">
+      <property name="sizePolicy">
+       <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+        <horstretch>0</horstretch>
+        <verstretch>0</verstretch>
+       </sizepolicy>
+      </property>
+      <property name="minimumSize">
+       <size>
+        <width>0</width>
+        <height>0</height>
+       </size>
+      </property>
+      <property name="maximumSize">
+       <size>
+        <width>16777215</width>
+        <height>16777215</height>
+       </size>
+      </property>
+      <property name="sizeIncrement">
+       <size>
+        <width>150</width>
+        <height>50</height>
+       </size>
+      </property>
+      <property name="alternatingRowColors">
+       <bool>true</bool>
+      </property>
+      <property name="selectionMode">
+       <enum>QAbstractItemView::SingleSelection</enum>
+      </property>
+      <property name="selectionBehavior">
+       <enum>QAbstractItemView::SelectRows</enum>
+      </property>
+      <property name="showGrid">
+       <bool>true</bool>
+      </property>
+      <property name="gridStyle">
+       <enum>Qt::DashLine</enum>
+      </property>
+      <property name="sortingEnabled">
+       <bool>true</bool>
+      </property>
+      <property name="cornerButtonEnabled">
+       <bool>false</bool>
+      </property>
+      <property name="rowCount">
+       <number>4</number>
+      </property>
+      <attribute name="horizontalHeaderCascadingSectionResizes">
+       <bool>false</bool>
+      </attribute>
+      <attribute name="horizontalHeaderDefaultSectionSize">
+       <number>150</number>
+      </attribute>
+      <attribute name="horizontalHeaderMinimumSectionSize">
+       <number>150</number>
+      </attribute>
+      <attribute name="verticalHeaderVisible">
+       <bool>false</bool>
+      </attribute>
+      <attribute name="verticalHeaderCascadingSectionResizes">
+       <bool>false</bool>
+      </attribute>
+      <row>
+       <property name="text">
+        <string>Nowy wiersz</string>
+       </property>
+      </row>
+      <row/>
+      <row/>
+      <row/>
+      <column>
+       <property name="text">
+        <string>Name</string>
+       </property>
+       <property name="font">
+        <font>
+         <weight>50</weight>
+         <bold>false</bold>
+        </font>
+       </property>
+       <property name="background">
+        <color>
+         <red>0</red>
+         <green>0</green>
+         <blue>0</blue>
+        </color>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>Template</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>NetVM</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>CPU</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>CPU Graph</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>MEM</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>MEM Graph</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>Update Info</string>
+       </property>
+      </column>
+      <column>
+       <property name="text">
+        <string>Block Devices</string>
+       </property>
+      </column>
+     </widget>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menubar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>821</width>
+     <height>23</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuOptions">
+    <property name="title">
+     <string>Options</string>
+    </property>
+   </widget>
+   <widget class="QMenu" name="menuView">
+    <property name="title">
+     <string>View</string>
+    </property>
+    <widget class="QMenu" name="menuColumns_visibility">
+     <property name="title">
+      <string>Columns visibility</string>
+     </property>
+     <addaction name="actionTemplate"/>
+     <addaction name="actionNetVM"/>
+     <addaction name="actionCPU"/>
+     <addaction name="actionCPU_Graph"/>
+     <addaction name="actionMEM"/>
+     <addaction name="actionMEM_Graph"/>
+     <addaction name="actionUpdate_Info"/>
+     <addaction name="actionBlock_Devices"/>
+    </widget>
+    <addaction name="menuColumns_visibility"/>
+   </widget>
+   <addaction name="menuOptions"/>
+   <addaction name="menuView"/>
+  </widget>
+  <widget class="QStatusBar" name="statusbar"/>
+  <widget class="QToolBar" name="toolBar">
+   <property name="windowTitle">
+    <string>toolBar</string>
+   </property>
+   <property name="floatable">
+    <bool>false</bool>
+   </property>
+   <attribute name="toolBarArea">
+    <enum>TopToolBarArea</enum>
+   </attribute>
+   <attribute name="toolBarBreak">
+    <bool>false</bool>
+   </attribute>
+   <addaction name="action_createvm"/>
+   <addaction name="separator"/>
+   <addaction name="action_removevm"/>
+   <addaction name="action_resumevm"/>
+   <addaction name="action_pausevm"/>
+   <addaction name="action_shutdownvm"/>
+   <addaction name="action_editfwrules"/>
+   <addaction name="action_appmenus"/>
+   <addaction name="action_updatevm"/>
+   <addaction name="separator"/>
+   <addaction name="action_showallvms"/>
+   <addaction name="action_showgraphs"/>
+  </widget>
+  <action name="action_createvm">
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/createvm.png</normaloff>:/createvm.png</iconset>
+   </property>
+   <property name="text">
+    <string>Create AppVM</string>
+   </property>
+   <property name="toolTip">
+    <string>Create a new AppVM</string>
+   </property>
+  </action>
+  <action name="action_removevm">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/removevm.png</normaloff>:/removevm.png</iconset>
+   </property>
+   <property name="text">
+    <string>remove AppVM</string>
+   </property>
+   <property name="toolTip">
+    <string>Remove an existing AppVM (must be stopped first)</string>
+   </property>
+  </action>
+  <action name="action_resumevm">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/resumevm.png</normaloff>:/resumevm.png</iconset>
+   </property>
+   <property name="text">
+    <string>Start/Resume VM</string>
+   </property>
+   <property name="toolTip">
+    <string>Start/Resume a VM</string>
+   </property>
+  </action>
+  <action name="action_pausevm">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/pausevm.png</normaloff>:/pausevm.png</iconset>
+   </property>
+   <property name="text">
+    <string>Pause VM</string>
+   </property>
+   <property name="toolTip">
+    <string>Pause a running VM</string>
+   </property>
+  </action>
+  <action name="action_shutdownvm">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/shutdownvm.png</normaloff>:/shutdownvm.png</iconset>
+   </property>
+   <property name="text">
+    <string>Shutdown VM</string>
+   </property>
+   <property name="toolTip">
+    <string>Shutdown a running VM</string>
+   </property>
+  </action>
+  <action name="action_appmenus">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/root.png</normaloff>:/root.png</iconset>
+   </property>
+   <property name="text">
+    <string>Select VM applications</string>
+   </property>
+   <property name="toolTip">
+    <string>Select applications present in menu for this VM</string>
+   </property>
+  </action>
+  <action name="action_updatevm">
+   <property name="enabled">
+    <bool>false</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/updateable.png</normaloff>:/updateable.png</iconset>
+   </property>
+   <property name="text">
+    <string>Update VM</string>
+   </property>
+   <property name="toolTip">
+    <string>Update VM system</string>
+   </property>
+  </action>
+  <action name="action_showallvms">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset>
+     <selectedoff>:/showallvms.png</selectedoff>
+    </iconset>
+   </property>
+   <property name="text">
+    <string>Show/Hide inactive VMs</string>
+   </property>
+   <property name="toolTip">
+    <string>Show/Hide inactive VMs</string>
+   </property>
+  </action>
+  <action name="action_editfwrules">
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/firewall.png</normaloff>:/firewall.png</iconset>
+   </property>
+   <property name="text">
+    <string>Edit VM Firewall rules</string>
+   </property>
+   <property name="toolTip">
+    <string>Edit VM Firewall rules</string>
+   </property>
+  </action>
+  <action name="action_showgraphs">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="icon">
+    <iconset resource="resources.qrc">
+     <normaloff>:/showcpuload.png</normaloff>:/showcpuload.png</iconset>
+   </property>
+   <property name="text">
+    <string>Show graphs</string>
+   </property>
+   <property name="toolTip">
+    <string>Show Graphs</string>
+   </property>
+  </action>
+  <action name="actionOptions">
+   <property name="text">
+    <string>Options</string>
+   </property>
+  </action>
+  <action name="actionView">
+   <property name="text">
+    <string>View</string>
+   </property>
+  </action>
+  <action name="actionCPU">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>CPU</string>
+   </property>
+  </action>
+  <action name="actionCPU_Graph">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>CPU Graph</string>
+   </property>
+  </action>
+  <action name="actionMEM">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>MEM</string>
+   </property>
+  </action>
+  <action name="actionMEM_Graph">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>MEM Graph</string>
+   </property>
+  </action>
+  <action name="actionTemplate">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Template</string>
+   </property>
+  </action>
+  <action name="actionNetVM">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>NetVM</string>
+   </property>
+  </action>
+  <action name="actionBlock_Devices">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Block Devices</string>
+   </property>
+  </action>
+  <action name="actionUpdate_Info">
+   <property name="checkable">
+    <bool>true</bool>
+   </property>
+   <property name="checked">
+    <bool>true</bool>
+   </property>
+   <property name="text">
+    <string>Update Info</string>
+   </property>
+  </action>
+ </widget>
+ <resources>
+  <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>

+ 229 - 230
qubesmanager/main.py

@@ -37,6 +37,7 @@ from qubes import qubesutils
 
 import qubesmanager.qrc_resources
 import ui_newappvmdlg
+from ui_mainwindow import *
 from appmenu_select import AppmenuSelectWindow
 
 from firewall import EditFwRulesDlg, QubesFirewallRulesModel
@@ -102,132 +103,114 @@ class VmInfoWidget (QWidget):
     def __init__(self, vm, parent = None):
         super (VmInfoWidget, self).__init__(parent)
 
-        layout0 = QHBoxLayout()
+        layout = QHBoxLayout ()
 
         self.label_name = QLabel (vm.name)
+        self.vm_icon = VmStatusIcon(vm)
 
-        self.vm_running = vm.last_power_state
-        layout0.addWidget(self.label_name, alignment=Qt.AlignLeft)
+        layout.addWidget(self.vm_icon)
+        layout.addSpacing (10)
+        layout.addWidget(self.label_name, alignment=Qt.AlignLeft)
 
-        layout1 = QHBoxLayout()
+        self.setLayout(layout)
+        
+    def update_vm_state (self, vm):
+        self.vm_icon.update()
 
-        if vm.template_vm is not None:
-            self.label_tmpl = QLabel ("<i><font color=\"gray\">" + (vm.template_vm.name) + "</i></font>")
-        elif vm.is_appvm(): # and vm.template_vm is None
-            self.label_tmpl = QLabel ("<i><font color=\"gray\">StandaloneVM</i></font>")
-        elif vm.is_template():
-            self.label_tmpl = QLabel ("<i><font color=\"gray\">TemplateVM</i></font>")
-        elif vm.qid == 0:
-            self.label_tmpl = QLabel ("<i><font color=\"gray\">AdminVM</i></font>")
-        elif vm.is_netvm():
-            self.label_tmpl = QLabel ("<i><font color=\"gray\">NetVM</i></font>")
-        else:
-            self.label_tmpl = QLabel ("")
+   
 
-        label_icon_networked = self.set_icon(":/networking.png", vm.is_networked())
-        layout1.addWidget(label_icon_networked, alignment=Qt.AlignLeft)
 
-        if vm.is_updateable():
-            label_icon_updtbl = self.set_icon(":/updateable.png", True)
-            layout1.addWidget(label_icon_updtbl, alignment=Qt.AlignLeft)
+class VmTemplateWidget (QWidget):
+    def __init__(self, vm, parent=None):
+        super(VmTemplateWidget, self).__init__(parent)
+        
+        layout = QVBoxLayout()
+        self.info_label = None
+        if vm.template_vm is not None:
+            self.label_tmpl = QLabel ("<font color=\"black\">" + (vm.template_vm.name) + "</font>")
+        else:
+            self.label_tmpl = QLabel ("<font color=\"black\">None</font>")
+            if vm.is_appvm(): # and vm.template_vm is None
+                self.info_label = QLabel ("<i><font color=\"gray\">StandaloneVM</i></font>")
+            elif vm.is_template():
+                self.info_label = QLabel ("<i><font color=\"gray\">TemplateVM</i></font>")
+            elif vm.qid == 0:
+                self.info_label = QLabel ("<i><font color=\"gray\">AdminVM</i></font>")
+            elif vm.is_netvm():
+                self.info_label = QLabel ("<i><font color=\"gray\">NetVM</i></font>")
+            else:
+                self.info_label = QLabel ("<i><font color=\"gray\">---</i></font>")
 
-        layout1.addWidget(self.label_tmpl, alignment=Qt.AlignLeft)
 
-        layout1.addStretch()
+        layout.addWidget(self.label_tmpl, alignment=Qt.AlignHCenter)
+        if self.info_label != None:
+            layout.addWidget(self.info_label, alignment=Qt.AlignHCenter)
 
-        layout2 = QVBoxLayout ()
-        layout2.addLayout(layout0)
-        layout2.addLayout(layout1)
+        self.setLayout(layout)
 
-        layout3 = QHBoxLayout ()
-        self.vm_icon = VmStatusIcon(vm)
-        layout3.addWidget(self.vm_icon)
-        layout3.addSpacing (10)
-        layout3.addLayout(layout2)
 
-        self.setLayout(layout3)
 
-        self.previous_outdated = False
-        self.previous_update_recommended = False
+class VmIconWidget (QWidget):
+    def __init__(self, icon_path, enabled=True, parent=None):
+        super(VmIconWidget, self).__init__(parent)
 
-    def set_icon(self, icon_path, enabled = True):
         label_icon = QLabel()
         icon = QIcon (icon_path)
-        icon_sz = QSize (VmManagerWindow.row_height * 0.3, VmManagerWindow.row_height * 0.3)
+        icon_sz = QSize (VmManagerWindow.row_height * 0.8, VmManagerWindow.row_height * 0.3)
         icon_pixmap = icon.pixmap(icon_sz, QIcon.Disabled if not enabled else QIcon.Normal)
         label_icon.setPixmap (icon_pixmap)
         label_icon.setFixedSize (icon_sz)
-        return label_icon
+        
+        layout = QVBoxLayout()
+        layout.addWidget(label_icon)
+        self.setLayout(layout)
 
-    def update_vm_state (self, vm):
-        self.vm_icon.update()
 
-    def update_outdated(self, vm):
-        outdated = vm.is_outdated()
-        if outdated != self.previous_outdated:
-            if outdated:
-                self.label_name.setText(vm.name + "<small><font color=\"red\"> (outdated)</font></small>")
-            else:
-                self.label_name.setText(vm.name)
-        self.previous_outdated = outdated
-        if vm.is_updateable():
-            update_recommended = self.previous_update_recommended
-            stat_file = vm.dir_path + '/' + updates_stat_file
-            if not os.path.exists(stat_file) or \
-                time.time() - os.path.getmtime(stat_file) > \
-                update_suggestion_interval * 24 * 3600:
-                    update_recommended = True
-            else:
-                update_recommended = False
-            if update_recommended != self.previous_update_recommended:
-                if update_recommended:
-                    self.label_name.setText(vm.name + "<small><font color=\"#CCCC00\"> (check updates)</font></small>")
-                else:
-                    self.label_name.setText(vm.name)
-                self.previous_update_recommended = update_recommended
+class VmNetvmWidget (QWidget):
+    def __init__(self, vm, parent=None):
+        super(VmNetvmWidget, self).__init__(parent)
+
+        layout = QHBoxLayout()
+        self.icon = VmIconWidget(":/networking.png", vm.is_networked())
+        
+        if vm.is_netvm():
+            self.label_nvm = QLabel ("<font color=\"black\">self</font>")
+        elif vm.netvm_vm is not None:
+            self.label_nvm = QLabel ("<font color=\"black\">" + (vm.netvm_vm.name) + "</font>")
+        else:
+            self.label_nvm = QLabel ("<font color=\"black\">None</font>")
 
-class VmUsageWidget (QWidget):
-    def __init__(self, vm, cpu_load = 0, parent = None):
-        super (VmUsageWidget, self).__init__(parent)
-
-        self.cpu_widget = QProgressBar()
-        self.mem_widget = QProgressBar()
-        self.cpu_widget.setMinimum(0)
-        self.cpu_widget.setMaximum(100)
-        self.mem_widget.setMinimum(0)
-        self.mem_widget.setMaximum(qubes_host.memory_total/1024)
-        self.mem_widget.setFormat ("%v MB");
-        self.cpu_label = QLabel("CPU")
-        self.mem_label = QLabel("MEM")
-
-        layout_cpu = QHBoxLayout()
-        layout_cpu.addWidget(self.cpu_label)
-        layout_cpu.addWidget(self.cpu_widget)
-
-        layout_mem = QHBoxLayout()
-        layout_mem.addWidget(self.mem_label)
-        layout_mem.addWidget(self.mem_widget)
+        layout.addWidget(self.icon, alignment=Qt.AlignLeft)
+        layout.addWidget(self.label_nvm, alignment=Qt.AlignHCenter)
+        self.setLayout(layout)
+            
 
-        layout = QVBoxLayout()
-        layout.addLayout(layout_cpu)
-        layout.addLayout(layout_mem)
 
-        self.setLayout(layout)
+class VmUsageBarWidget (QWidget):
+    def __init__(self, min, max, format, label, update_func, vm, load, parent = None):
+        super (VmUsageBarWidget, self).__init__(parent)
 
-        self.update_load(vm, cpu_load)
+        self.min = min
+        self.max = max
+        self.update_func = update_func
 
-    def update_load(self, vm, cpu_load):
-        self.cpu_load = cpu_load if vm.last_power_state else 0
-        self.mem_load = vm.get_mem()/1024 if vm.last_power_state else 0
+        self.widget = QProgressBar()
+        self.widget.setMinimum(min)
+        self.widget.setMaximum(max)
+        self.widget.setFormat(format);
+        self.label = QLabel(label)
 
-        self.cpu_widget.setValue(self.cpu_load)
-        self.mem_widget.setValue(self.mem_load)
+        layout = QHBoxLayout()
+        layout.addWidget(self.label)
+        layout.addWidget(self.widget)
+
+        self.setLayout(layout)
+
+        self.update_load(vm, load)
+
+    def update_load(self, vm, load):
+        self.widget.setValue(self.update_func(vm, load))
 
-    def resizeEvent(self, Event = None):
-        label_width = max(self.mem_label.width(), self.cpu_label.width())
-        self.mem_label.setMinimumWidth(label_width)
-        self.cpu_label.setMinimumWidth(label_width)
-        super (VmUsageWidget, self).resizeEvent(Event)
 
 class LoadChartWidget (QWidget):
 
@@ -313,6 +296,54 @@ class MemChartWidget (QWidget):
                 p.drawLine (W - i*dx - dx, H , W - i*dx - dx, H - (H - 5) * val/100)
 
 
+class VmUpdateInfoWidget(QWidget):
+
+    def __init__(self, vm, parent = None):
+        super (VmUpdateInfoWidget, self).__init__(parent)
+        layout = QVBoxLayout ()
+        self.label = QLabel("")
+        layout.addWidget(self.label)
+        if vm.is_updateable():
+            self.updateable_widget = VmIconWidget(":/updateable.png", True)
+            layout.addWidget(self.updateable_widget, alignment=Qt.AlignHCenter)
+        self.setLayout(layout)
+
+        self.previous_outdated = False
+        self.previous_update_recommended = False
+
+    def update_outdated(self, vm):
+        outdated = vm.is_outdated()
+        if outdated and not self.previous_outdated:
+            self.label.setText("<b><font color=\"red\"> (outdated)</font></b>")
+        
+        self.previous_outdated = outdated
+        if vm.is_updateable():
+            update_recommended = self.previous_update_recommended
+            stat_file = vm.dir_path + '/' + updates_stat_file
+            if not os.path.exists(stat_file) or \
+                time.time() - os.path.getmtime(stat_file) > \
+                update_suggestion_interval * 24 * 3600:
+                    update_recommended = True
+            else:
+                update_recommended = False
+            if update_recommended and not self.previous_update_recommended:
+                self.label.setText("<b><font color=\"#CCCC00\"> (check updates)</font></b>")
+                self.previous_update_recommended = update_recommended
+
+
+class VmBlockDevicesWidget(QWidget):
+    def __init__(self, vm, parent=None):
+        super(VmBlockDevicesWidget, self).__init__(parent)
+
+        combo = QComboBox()
+        combo.addItem("USB dummy1")
+        combo.addItem("USB dummy2")
+        combo.addItem("USB dummy3")
+
+        layout = QVBoxLayout()
+        layout.addWidget(combo)
+        self.setLayout(layout)
+
 
 class VmRowInTable(object):
     def __init__(self, vm, row_no, table):
@@ -324,23 +355,41 @@ class VmRowInTable(object):
         self.info_widget = VmInfoWidget(vm)
         table.setCellWidget(row_no, 0, self.info_widget)
 
-        self.usage_widget = VmUsageWidget(vm)
-        table.setCellWidget(row_no, 1, self.usage_widget)
+        self.template_widget = VmTemplateWidget(vm)
+        table.setCellWidget(row_no, 1, self.template_widget)
+
+        self.netvm_widget = VmNetvmWidget(vm)
+        table.setCellWidget(row_no, 2, self.netvm_widget)
+
+        self.cpu_usage_widget = VmUsageBarWidget(0, 100, "", "CPU", 
+                            lambda vm, val: val if vm.last_power_state else 0, vm, 0)
+        table.setCellWidget(row_no, 3, self.cpu_usage_widget)
 
         self.load_widget = LoadChartWidget(vm)
-        table.setCellWidget(row_no, 2, self.load_widget)
+        table.setCellWidget(row_no, 4, self.load_widget)
+
+        self.mem_usage_widget = VmUsageBarWidget(0, qubes_host.memory_total/1024, "%v MB", "MEM", 
+                            lambda vm, val: vm.get_mem()/1024 if vm.last_power_state else 0, vm, 0)
+        table.setCellWidget(row_no, 5, self.mem_usage_widget)
 
         self.mem_widget = MemChartWidget(vm)
-        table.setCellWidget(row_no, 3, self.mem_widget)
+        table.setCellWidget(row_no, 6, self.mem_widget)
+ 
+        self.updateinfo_widget = VmUpdateInfoWidget(vm)
+        table.setCellWidget(row_no, 7, self.updateinfo_widget)
+
+        self.blockdevices_widget = VmBlockDevicesWidget(vm)
+        table.setCellWidget(row_no, 8, self.blockdevices_widget)
 
 
     def update(self, counter, cpu_load = None):
         self.info_widget.update_vm_state(self.vm)
         if cpu_load is not None:
-            self.usage_widget.update_load(self.vm, cpu_load)
+            self.cpu_usage_widget.update_load(self.vm, cpu_load)
+            self.mem_usage_widget.update_load(self.vm, None)
             self.load_widget.update_load(self.vm, cpu_load)
             self.mem_widget.update_load(self.vm)
-            self.info_widget.update_outdated(self.vm)
+            self.updateinfo_widget.update_outdated(self.vm)
 
 class NewAppVmDlg (QDialog, ui_newappvmdlg.Ui_NewAppVMDlg):
     def __init__(self, parent = None):
@@ -388,100 +437,40 @@ class ThreadMonitor(QObject):
         self.event_finished.set()
 
 
-class VmManagerWindow(QMainWindow):
-    columns_widths = [250, 200, 150, 150]
+class VmManagerWindow(Ui_VmManagerWindow, QMainWindow):
     row_height = 50
     max_visible_rows = 14
     update_interval = 1000 # in msec
     show_inactive_vms = True
     columns_states = { 0: [0, 1], 1: [0, 2, 3] }
+    columns_indices = { "Name": 0,
+                        "Template": 1,
+                        "NetVM": 2,
+                        "CPU": 3,
+                        "CPU Graph": 4,
+                        "MEM": 5,
+                        "MEM Graph": 6,
+                        "Update Info": 7,
+                        "Block Device": 8 }
 
-    def __init__(self, parent=None):
-        super(VmManagerWindow, self).__init__(parent)
-
-
-        self.action_createvm = self.createAction ("Create AppVM", slot=self.create_appvm,
-                                             icon="createvm", tip="Create a new AppVM")
-
-        self.action_removevm = self.createAction ("Remove AppVM", slot=self.remove_appvm,
-                                             icon="removevm", tip="Remove an existing AppVM (must be stopped first)")
-
-        self.action_resumevm = self.createAction ("Start/Resume VM", slot=self.resume_vm,
-                                             icon="resumevm", tip="Start/Resume a VM")
-
-        self.action_pausevm = self.createAction ("Pause VM", slot=self.pause_vm,
-                                             icon="pausevm", tip="Pause a running VM")
 
-        self.action_shutdownvm = self.createAction ("Shutdown VM", slot=self.shutdown_vm,
-                                             icon="shutdownvm", tip="Shutdown a running VM")
-
-        self.action_appmenus = self.createAction ("Select VM applications", slot=self.appmenus_select,
-                                             icon="root", tip="Select applications present in menu for this VM")
-
-        self.action_updatevm = self.createAction ("Update VM", slot=self.update_vm,
-                                             icon="updateable", tip="Update VM system")
-
-        self.action_showallvms = self.createAction ("Show/Hide Inactive VMs", slot=self.toggle_inactive_view, checkable=True,
-                                             icon="showallvms", tip="Show/Hide Inactive VMs")
-
-        self.action_showcpuload = self.createAction ("Show/Hide CPU Load chart", slot=self.showcpuload, checkable=True,
-                                             icon="showcpuload", tip="Show/Hide CPU Load chart")
-
-        self.action_editfwrules = self.createAction ("Edit VM Firewall rules", slot=self.edit_fw_rules,
-                                             icon="firewall", tip="Edit VM Firewall rules")
-
-
-        self.action_removevm.setDisabled(True)
-        self.action_resumevm.setDisabled(True)
-        self.action_pausevm.setDisabled(True)
-        self.action_shutdownvm.setDisabled(True)
-        self.action_appmenus.setDisabled(True)
-        self.action_updatevm.setDisabled(True)
-
-        self.action_showallvms.setChecked(self.show_inactive_vms)
-
-        self.toolbar = self.addToolBar ("Toolbar")
-        self.toolbar.setFloatable(False)
-        self.addActions (self.toolbar, (self.action_createvm, self.action_removevm,
-                                   None,
-                                   self.action_resumevm, self.action_shutdownvm,
-                                   self.action_editfwrules, self.action_appmenus,
-                                   self.action_updatevm,
-                                   None,
-                                   self.action_showcpuload,
-                                   self.action_showallvms,
-                                   ))
-
-        self.table = QTableWidget()
-        self.setCentralWidget(self.table)
-        self.table.clear()
-        self.table.setColumnCount(len(VmManagerWindow.columns_widths))
-        for (col, width) in enumerate (VmManagerWindow.columns_widths):
-            self.table.setColumnWidth (col, width)
-
-        self.table.horizontalHeader().setResizeMode(QHeaderView.Stretch)
-        self.table.horizontalHeader().setResizeMode(0, QHeaderView.Fixed)
-        self.table.setAlternatingRowColors(True)
-        self.table.verticalHeader().hide()
-        self.table.horizontalHeader().hide()
-        self.table.setGridStyle(Qt.NoPen)
-        self.table.setSortingEnabled(False)
-        self.table.setSelectionBehavior(QTableWidget.SelectRows)
-        self.table.setSelectionMode(QTableWidget.SingleSelection)
-
-        self.__cpugraphs = self.action_showcpuload.isChecked()
-        self.update_table_columns()
 
+    def __init__(self, parent=None):
+        super(VmManagerWindow, self).__init__()
+        self.setupUi(self)
+        self.toolbar = self.toolBar
+        
         self.qvm_collection = QubesVmCollection()
-        self.setWindowTitle("Qubes VM Manager")
-
+        
         self.connect(self.table, SIGNAL("itemSelectionChanged()"), self.table_selection_changed)
-
+        
         cur_pos = self.pos()
-        self.setFixedWidth (self.get_minimum_table_width())
+        self.table.setColumnWidth(0, 200)
         self.fill_table()
         self.move(cur_pos)
-
+        
+        self.update_table_columns()
+        
         self.counter = 0
         self.shutdown_monitor = {}
         self.last_measure_results = {}
@@ -490,41 +479,25 @@ class VmManagerWindow(QMainWindow):
 
     def set_table_geom_height(self):
         # TODO: '6' -- WTF?!
-        tbl_H = self.toolbar.height() + 6 + \
-                self.table.horizontalHeader().height() + 6
+        tbl_H = self.toolbar.height() + \
+                self.table.horizontalHeader().height() + \
+                self.centralwidget.layout().contentsMargins().top() +\
+                self.centralwidget.layout().contentsMargins().bottom()
 
         n = self.table.rowCount();
-        if n > VmManagerWindow.max_visible_rows:
-            n = VmManagerWindow.max_visible_rows
-        for i in range (0, n):
-            tbl_H += self.table.rowHeight(i)
-
-        self.setFixedHeight(tbl_H)
-
-
-    def addActions(self, target, actions):
-        for action in actions:
-            if action is None:
-                target.addSeparator()
-            else:
-                target.addAction(action)
 
+        if n > 6:
+            for i in range(0,n-1):
+                tbl_H += self.table.rowHeight(i)
+        else:
+            tbl_H += self.table.verticalHeader().height()
+        """
+        if n > self.max_visible_rows:
+            n = self.max_visible_rows
+        for i in range (0, n):
+            tbl_H += self.table.rowHeight(i) """
 
-    def createAction(self, text, slot=None, shortcut=None, icon=None,
-                     tip=None, checkable=False, signal="triggered()"):
-        action = QAction(text, self)
-        if icon is not None:
-            action.setIcon(QIcon(":/%s.png" % icon))
-        if shortcut is not None:
-            action.setShortcut(shortcut)
-        if tip is not None:
-            action.setToolTip(tip)
-            action.setStatusTip(tip)
-        if slot is not None:
-            self.connect(action, SIGNAL(signal), slot)
-        if checkable:
-            action.setCheckable(True)
-        return action
+        self.setMinimumHeight(tbl_H)
 
 
     def get_vms_list(self):
@@ -559,7 +532,7 @@ class VmManagerWindow(QMainWindow):
         return vms_to_display
 
     def fill_table(self):
-        self.table.clear()
+        #self.table.clear()
         vms_list = self.get_vms_list()
         self.table.setRowCount(len(vms_list))
 
@@ -622,14 +595,17 @@ class VmManagerWindow(QMainWindow):
             QTimer.singleShot (self.update_interval, self.update_table)
 
     def update_table_columns(self):
-        state = 1 if self.__cpugraphs else 0
-        columns = self.columns_states[state]
+        #for i in range(0, self.table.columnCount()):
+		#TODO make elegant column visibility actions
+            #self.table.setColumnHidden(i, False)
 
-        for i in range(0, self.table.columnCount()):
-            enabled = columns.count(i) > 0
-            self.table.setColumnHidden(i, not enabled)
+        width = self.table.horizontalHeader().length() +\
+                self.table.verticalScrollBar().width() +\
+                self.centralwidget.layout().contentsMargins().left() +\
+                self.centralwidget.layout().contentsMargins().right()
 
-        self.setMinimumWidth(self.get_minimum_table_width())
+        self.table.setFixedWidth( width )
+        self.setFixedWidth( width)
 
     def table_selection_changed (self):
         vm = self.get_selected_vm()
@@ -644,13 +620,6 @@ class VmManagerWindow(QMainWindow):
         self.action_editfwrules.setEnabled(vm.is_networked() and not (vm.is_netvm() and not vm.is_proxyvm()))
         self.action_updatevm.setEnabled(vm.is_updateable() or vm.qid == 0)
 
-    def get_minimum_table_width(self):
-        tbl_W = 0
-        for (col, w) in enumerate(VmManagerWindow.columns_widths):
-            if not self.table.isColumnHidden(col):
-                tbl_W += w
-
-        return tbl_W
 
     def closeEvent (self, event):
         if event.spontaneous(): # There is something borked in Qt, as the logic here is inverted on X11
@@ -962,6 +931,36 @@ class VmManagerWindow(QMainWindow):
         if dialog.exec_():
             model.apply_rules()
 
+    
+    def showhide_collumn(self, col_num, show):
+        self.table.setColumnHidden( col_num, not show)
+        self.update_table_columns()
+        
+    def on_actionTemplate_toggled(self, checked):
+        self.showhide_collumn( 1, checked)
+
+    def on_actionNetVM_toggled(self, checked):
+        self.showhide_collumn( 2, checked)
+    
+    def on_actionCPU_toggled(self, checked):
+        self.showhide_collumn( 3, checked)
+    
+    def on_actionCPU_Graph_toggled(self, checked):
+        self.showhide_collumn( 4, checked)    
+
+    def on_actionMEM_toggled(self, checked):
+        self.showhide_collumn( 5, checked)   
+    
+    def on_actionMEM_Graph_toggled(self, checked):
+        self.showhide_collumn( 6, checked)
+
+    def on_actionUpdate_Info_toggled(self, checked):
+        self.showhide_collumn( 7, checked)    
+
+    def on_actionBlock_Devices_toggled(self, checked):
+        self.showhide_collumn( 8, checked)    
+
+
 class QubesTrayIcon(QSystemTrayIcon):
     def __init__(self, icon):
         QSystemTrayIcon.__init__(self, icon)