Source

filesnake / filesnake / gui / transfers.py

# -*- coding=utf-8 -*-

from ..pygtkhelpers.ui.objectlist import ObjectList, Column
from ..pygtkhelpers.delegates import SlaveView,ToplevelView
from ..pygtkhelpers.utils import gsignal,refresh_gui

from gobject import GObject
import datetime
import time

class TransferList(SlaveView):
    '''
    The widget that displays the filesnake transfers
    '''

    def create_ui(self):        
        listing = ObjectList([
                Column("filename", str, resizable = True),
                Column("status", str),
                Column("size", str),
                Column("complete", int, use_progress=True),
                Column("speed",str),
                Column("ETA",str),
                Column("peer", str)
                ])

        self.objectlist = listing
        self.widget.add(listing)

    def append(self, item):
        item.connect("changed", self.objectlist.update)
        self.objectlist.append(item)
        
class TransfersDialog(ToplevelView):
    
    builder_file="transfers.glade"
    
    def create_ui(self):
        
        self.transferlist = TransferList()
        self.add_slave(self.transferlist, "transferlist_cont")
    
    def on_widget__delete_event(self, w, e): 
        self.widget.hide_all()
        return True

    def add_transfer(self, name, filename, size):
        '''
        Add a new transfer and return the object connected with the GUI
        '''
        newmon = TransferMonitor(filename, size)
        newmon.peer = name
        self.transferlist.append(newmon)
        self.widget.show_all()
        return newmon

    def append(self, item):
        # Item must be a TransferMonitor
        item.connect("changed", self.objectlist.update)
        self.objectlist.append(item)
        
    def remove_completed(self):
        
        for item in self.objectlist:
            if item.completed == 100:
                self.objectlist.remove(item)

def prettify_byte_size(size):
    '''Makes a nice representation of sizes:
    - 10 b
    - 10.2 Kb
    - 56.1 Mb
    - 3.6 Gb
    '''
    if size < 1024:
        return "{0} b".format(size)
    elif 1024 <= size <  1048576:
        return "{0:.1f} Kb".format(size/1024.0)
    elif 1048576 <= size < 1073741824:
        return "{0:.1f} Mb".format(size/1048576.0)  
    elif size >= 1073741824:
        return "{0:.1f} Gb".format(size/1073741824.0)  




class TransferMonitor(GObject):
    '''
    This class monitors a transfer, and updates the info associated
    with the transfer, it's observed by the GUI
    '''

    gsignal("changed")

    def __init__(self, filename, size):
        super(TransferMonitor, self).__init__()
        self.filename = filename
        self.size = size        # Total size of the transfer
        self.progress = 0       # bytes transferred
        self.status = "waiting" # status of the transfer
        self.speed = 0          # Speed in byte/sec
        #self.ETA = 0            # Estimate of the time
        self.complete = 0
        self._count = 0
    
    @property
    def ETA(self):
        if self._speed==0:
            return u"∞"
        else:
            # Seconds remaining
            s = (self._size - self.progress) / self._speed
            # Formatting a nice string
            hours, remainder = divmod(s, 3600)
            minutes, seconds = divmod(remainder, 60)
            return "%dh:%dm:%ds"%(hours,minutes,seconds)
            

    @property
    def size(self):
        return prettify_byte_size(self._size)
    
    @size.setter
    def size(self, value):
        self._size = value

    @property
    def speed(self):
        value = self._speed
        return prettify_byte_size(value)+"/s"
    
    @speed.setter
    def speed(self, value):
        '''
        Set speed in byte/s
        '''
        self._speed = value


    def update_speed(self):
        '''This function keep tracks of the time between two
        "producing" calls, letting displaying the speed
        '''
        
        if not hasattr(self, "_old_progress"):
            self._old_progress = self.progress

        prog =  self.progress - self._old_progress 
        self._old_progress = self.progress
        
        self.speed = prog/self.time_interval()
        

    def time_interval(self):
        '''
        Keeps a time interval between two calls
        '''
        
        if not hasattr(self,"_prec"):
            self._prec=time.time()
            
        cur = time.time()
        
                                # Avoid zero division error
        ret = cur - self._prec
        self._prec=cur
        return ret

    def producing(self,data):
        '''
        Called when the source is producing data
        '''
        self.status = "receiving"
        
        chunk = len(data)
        # self._size is the size in byte
        if self.progress + chunk > self._size:
            raise ValueError("Producing more data that the declared one")
        
        self.progress += chunk        
        self.complete = self.progress*100/self._size 

        self._count+=1
        if self._count%100 == 0:
            self.update_speed()
            self.emit("changed")

        if self.progress == self.size:
            self.finish()
        
    def pause(self):
        '''
        Called when the source is paused
        '''
        self.status = "pause"
        
    def stop(self):
        '''
        Called when the source has stopped sending files, ungracefully
        '''
        self.status = "stop"
        
    def finish(self):
        '''
        The source has finished to do its stuff
        '''
        self.emit("changed")
        self.status = "finished"


def test():
    a = TransfersDialog()
    a.show()
    
    for i in range(3):
        mon = a.add_transfer("galois", "filename%d"%i, 1024)
        refresh_gui()
    for i in range(100):
        mon.producing("hello")
        refresh_gui()


def test_monitor():
    tm = TransferMonitor("hello.pdf", 1400)
    
    tm.speed = 15
    res = tm.speed 
    assert (res == "15 b/s")
    
    tm.speed = 0
    res = tm.speed
    assert (res == "0 b/s")
    
    tm.speed = 10000
    res = tm.speed
    assert (res== "9.8 Kb/s")

def test_eta():
    tm = TransferMonitor("hello.pdf", 1400)
    
    tm.speed = 15
    eta = tm.ETA
    assert eta == "0h:1m:33s"
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.