StoreObjFrames.py 11.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
# -*- coding: utf-8 -*-

"""
 TK Frames for Representation of Storage Abstraction
 (C) 2014 Martin Süfke
 License: GPLv3 or newer: http://www.gnu.org/licenses/gpl.html
"""
# Proper logging
from pprint import pprint, pformat
import logging
#import os         # A dirty hack here 
import subprocess 
import shlex
import signal      # future


if __name__ == "__main__":
  #logging.basicConfig(level=logging.WARN)
  raise Exception("{0} cannot run as the main python program".format(__file__))

if len(logging.root.handlers) == 0:
# SPE compatible logging format
  logging.basicConfig(level=logging.DEBUG,format='%(levelno)2d:%(funcName)s:%(message)s:File "%(filename)s", line %(lineno)d')
logger = logging.getLogger(__name__)

import inspect

import StorageObjects

import  Tkinter as Tk
#from    Tkinter import BooleanVar, IntVar, DoubleVar, StringVar
#import  tkMessageBox as dialog
#import  tkFileDialog as filedialog
from    Tkconstants import N, E, S, W, HORIZONTAL, LEFT, RIGHT, TOP, BOTTOM, \
                           BOTH, NORMAL, DISABLED, X, Y

def Implement(msg=""):
  logger.warn('Implement File "%s", line %s, %s'+msg,*inspect.stack()[1][1:4])

def SizeStr(size):
  """ Print size with thousands separators """
  return "{0:,d} bytes".format(size)
    
class TkFStorage(StorageObjects.Storage):
  """ Tk Frame for Storage """
  def __init__(self, ParentFrame):
    #logger.debug(self.__class__.__name__)
    super(self.__class__,self).__init__()
    self._ChildClass = TkFDrive
    self.TKFrame = Tk.Frame(ParentFrame, borderwidth=2, relief='groove')
    self.TKFrame.pack(side=TOP, fill=X)
    #Tk.Label(self.TKFrame,text=self.__class__.__name__).pack(side=LEFT, fill=X)    

  def FilterViewDriveAdd(self, MoreFiltersAsDict):
    """ Adds view filters on drives 
      example: FilterViewDriveAdd(self, {'Removable': True})
    """
    #logger.debug("Num Drives %d", len(self.StorageDrives))
    for k,v in self.StorageDrives.iteritems():
#      logger.debug("\nDrive %s %s", k, str(v))
      v.FilterViewAdd(MoreFiltersAsDict)
# TODO: Idea here is to retain the order of hidden/visible drives. 
#       That may not be possible in all circumstances
#       Also, is may not be desirable. When showing devices, add them at the TOP
#      f = v.TKFrame
#      x = f.tk.call('pack', 'info', str(f))
##      f._saved_w = f._w
##      f._w = str(f)
##      logger.debug("repr(f) %s",repr(f))
##      logger.debug(" str(f) %s", str(f))
##      x = f.pack_info()
##      f._saved_w = f._w
##      v.TKFrame.pack_forget()
#      logger.debug("Pack_info: %s", x)
#      
#    logger.debug("Slave Frames %s", self.TKFrame.pack_slaves())

  def FilterViewDriveRemove(self, FilterKeysAsList):
    """ Removes view filters from drives 
      example: FilterViewDriveRemove(self, ['Removable', 'Ejectable']})
    """
    for k,v in self.StorageDrives.iteritems():
      v.FilterViewRemove(FilterKeysAsList)

class TkFDrive(StorageObjects.StorageDrive):
  """ Tk Frame for Drive """
  def __init__(self, *args, **kwargs):
    """
      Pass argment to StorageObjects.StoragedDrive

      FilterView = {} :
        Dictionary of Key = Value pairs that make this entry invisible if found inside UDisks2Dict
    """
    #logger.debug(self.__class__.__name__)
    self.ViewFilter = kwargs.pop('FilterView', {})
    super(self.__class__,self).__init__(*args, **kwargs)
    self._ChildClass = TkFBlockdevice
    self.TKFrame = Tk.Frame(self.Parent.TKFrame, borderwidth=2, relief='groove', background='light blue')
    self.visible = False    # Not pack()'ed yet
    self.FilterView() # leads to self.TKFrame.Pack() if visible
    Tk.Label(self.TKFrame,text="Drive", background='light blue').pack(side=LEFT, anchor="nw")    
    InfoFrame = Tk.Frame(self.TKFrame, borderwidth=2)
    Tk.Button(InfoFrame,text="ignore", command = self.OnBtnIgnore, background='light blue').pack(side=RIGHT, anchor="e")
    if self.UDisks2Dict.get('Ejectable',False):
      Tk.Button(InfoFrame,text="Eject", command = self.OnBtnEject).pack(side=RIGHT, anchor="e")
    if self.UDisks2Dict.get('CanPowerOff',False):
      Tk.Button(InfoFrame,text="PowerOff", command = self.OnBtnPowerOff).pack(side=RIGHT, anchor="e")
    Tk.Label( InfoFrame,text=self.Id).pack(anchor="nw")
    # Size as a str ?!?
    try:
      Tk.Label( InfoFrame,text=SizeStr(self.Size)).pack(anchor="nw")
    except ValueError:
      logger.debug("self.Size: s:%s r:%s",str(self.Size), repr(self.Size))
    InfoFrame.pack(side=TOP, fill=X, padx=5, pady=5)

  def _close(self):
    """ A manual destructor"""
    self.TKFrame.pack_forget()  # Remove visible component
    self.TKFrame.destroy()      # Kill visible component
    self.TKFrame = None
    super(self.__class__,self)._close()

  def OnBtnEject(self):
    self.Eject()
 
  def OnBtnPowerOff(self):
    self.PowerOff()

  def OnBtnIgnore(self):
    #self.Ignore = True   # Make a Filter that always makes thisone ingnore itself.
    self.FilterViewAdd({'Id':self.UDisks2Dict['Id']})
    #logger.debug("UDisk2Dict: %s", pformat(self.UDisks2Dict))
    #self.FilterMakeInvisible()

  def FilterViewAdd(self, MoreFiltersAsDict):
    """ Adds view filters on this drive 
      Filtered drives will not show themselves in the main gui.
      example: FilterViewDriveAdd(self, {'Removable': True})
      see also: FilterViewRemove, FilterView
    """
    self.ViewFilter.update(MoreFiltersAsDict)
    self.FilterView()

  def FilterViewRemove(self, FilterKeysAsList):
    """ Removes view filters from this drive
      example: FilterViewDriveRemove(self, ['Removable', 'Ejectable']})
      see also: FilterViewAdd, FilterView
    """
    for k in FilterKeysAsList:    
      if k in self.ViewFilter:
        del self.ViewFilter[k]
    self.FilterView()

  def FilterView(self):
    """ Apply Filter against this drive 
      see also: FilterViewAdd, FilterViewRemove
    """
    visible = True
    for key, test in self.ViewFilter.iteritems():
      # A little suprising, but self.UDisks2Dict[dbus.String(u'Foo')] is as 
      # good as self.UDisks2Dict['Foo']
      #logger.debug("Testing key %s",key)
      if self.UDisks2Dict.has_key(key):
        #logger.debug("key found, value is %s", self.UDisks2Dict[key])
        #logger.debug("Testing %s == %s", test, self.UDisks2Dict[key] == test)
        if self.UDisks2Dict[key] == test:
          visible = False
    if visible:
      self.FilterMakeVisible()
    else:
      self.FilterMakeInvisible()

  def FilterMakeVisible(self):
    if not self.visible:
      #logger.debug("")
      self.TKFrame.pack(side=BOTTOM, fill=X)  # Pack on  Bottom, so that new entries end up on top.
      self.visible = True
    
  def FilterMakeInvisible(self):
    if self.visible:
      #logger.debug("")
      self.TKFrame.pack_forget()
      self.visible = False
    
class TkFBlockdevice(StorageObjects.StorageBlockDevice):
  """ Tk Frame for Blockdevice """
  def __init__(self, *args, **kwargs):
    #logger.debug(self.__class__.__name__)
    #logger.debug("args %s kwargs %s", args, kwargs)
    kwargs['ChildClass'] = TkFFilesystem
    super(self.__class__,self).__init__(*args, **kwargs)
    self.TKFrame = Tk.Frame(self.Parent.TKFrame, borderwidth=2, relief='groove', background='light green')
    self.TKFrame.pack(side=BOTTOM, fill=X)
    Tk.Label(self.TKFrame,text="BlkDev", background='light green').pack(side=LEFT, anchor="nw")    
    InfoFrame = Tk.Frame(self.TKFrame, borderwidth=2, relief='flat')
    #Tk.Label(self.TKFrame,text=self.__class__.__name__).pack(side=TOP, fill=X)    
    Tk.Button(InfoFrame, text="Write", command=self.TkCmdWrite).pack(side=RIGHT)
    Tk.Label( InfoFrame, text="{0:s}".format(self.PreferredDevice)).pack(anchor="nw")    
    Tk.Label( InfoFrame, text="Size "+SizeStr(self.Size)).pack(anchor="nw")    
    InfoFrame.pack(side=TOP, fill=X, padx=5, pady=5)

  def _close(self):
    """ A manual destructor"""
    self.TKFrame.pack_forget()  # Remove visible component
    self.TKFrame.destroy()      # Kill visible component
    self.TKFrame = None
    super(self.__class__,self)._close()
    
  def TkCmdWrite(self):
    logger.debug("Write to %s  -> execute write.sh %s", self.PreferredDevice, self.PreferredDevice)
    # TODO: This would need a nice subprocess.popen() ... 
    #os.system("./write.sh %s"%(self.PreferredDevice))

    if True: #not self.proc:
      cmdarray=" ".join( [
                      "./write.sh %s"%(self.PreferredDevice),
                    ] )

      args = shlex.split(cmdarray)
  
      self.proc = subprocess.Popen(args,
                                   #bufsize = 1, # line buffered
                                   bufsize = 4096, # byte buffered
                                   stdin = None,
                                   stdout = None, #subprocess.PIPE,
                                   stderr = None, #subprocess.STDOUT,
                                   # preexec_fn unneeded
                                   close_fds = True, # Do not leak file descriptors
                                   #cwd = Current Working Directory
                                   #env Environment mapping
                                   )

    logger.debug("write.sh executed")

class TkFFilesystem(StorageObjects.StorageFileSystem):
  """ Tk Frame for Filesystem """
  def __init__(self, *args, **kwargs):
    #logger.debug(self.__class__.__name__)
    super(self.__class__,self).__init__(*args, **kwargs)
    self._ChildClass = TkFMountpoint
    self.TKFrame = Tk.Frame(self.Parent.TKFrame, borderwidth=2, relief='groove')
    self.TKFrame.pack(side=TOP, fill=X)
    InfoFrame = Tk.Frame(self.TKFrame, borderwidth=2, relief='flat')
    #Tk.Label(self.TKFrame,text="Filesystem").pack(anchor="nw")    
    Tk.Button(InfoFrame,text="Mount", command=self.TkCmdMount).pack(side=RIGHT)
    Tk.Label( InfoFrame,text=self.IdUsage + " " + self.IdType + " " + self.IdVersion).pack(anchor="nw")    
    Tk.Label( InfoFrame,text=self.IdUUID + " " + self.IdLabel).pack(anchor="nw")    
    InfoFrame.pack(side=TOP, fill=X)

  def _close(self):
    """ A manual destructor"""
    self.TKFrame.pack_forget()  # Remove visible component
    self.TKFrame.destroy()      # Kill visible component
    self.TKFrame = None
    super(self.__class__,self)._close()

  def TkCmdMount(self, *args, **kwargs):
    #logger.debug("TkFFilesystem args:%s %s",args,kwargs)
    self.Mount()

    #logger.debug("TkFFilesystem args:%s %s",args,kwargs)

class TkFMountpoint(StorageObjects.StorageMountPoint):
  """ Tk Frame for Mountpoint """
  def __init__(self, *args, **kwargs):
    #logger.debug("args %s kwargs %s", args, kwargs)
    #logger.debug(self.__class__.__name__)
    super(self.__class__,self).__init__(*args, **kwargs)
    self.TKFrame = Tk.Frame(self.Parent.TKFrame, borderwidth=2, relief='groove', background='#FFC4C4')
    self.TKFrame.pack(side=TOP, fill=X, ipadx=5, ipady=2)
    Tk.Button(self.TKFrame,text="Unmount", command=self.TkCmdUnmount).pack(side=RIGHT)
    Tk.Label(self.TKFrame,text="mounted on " + self.MountPoint).pack(side=LEFT)

#  def __del__(self):
#    logger.debug("%s.__del__()",self.__class__.__name__)
#    super(self.__class__,self).__del__()

  def _close(self):
    """ A 'manual' destructor"""
    #logger.debug("%s _close for %s",self.__class__.__name__,str(self))
    self.TKFrame.pack_forget()  # Remove visible component
    self.TKFrame.destroy()      # Kill visible component
    self.TKFrame = None
    super(self.__class__,self)._close()
    
  def TkCmdUnmount(self, *args, **kwargs):
    #logger.debug("TkFMountpoint args:%s %s",args,kwargs)
    self.Unmount()
  
  
#end;