Subversion Repositories blueman

[/] [trunk/] [apps/] [blueman-sendto] - Rev 615

Compare with Previous | Blame | Download | View Log

#!/usr/bin/python
# coding=utf-8
# Copyright (C) 2008 Valmantas Paliksa <walmis at balticum-tv dot lt>
# Copyright (C) 2008 Tadas Dailyda <tadas at dailyda dot com>
#
# Licensed under the GNU General Public License Version 3
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 

import os, sys

#support running uninstalled
_dirname = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if os.path.exists(os.path.join(_dirname,"ChangeLog")):
    sys.path.insert(0, _dirname)
    
import gtk
import gobject
import dbus.glib
from optparse import OptionParser
import gettext
import urllib
import time

from blueman.bluez.Adapter import Adapter
from blueman.main.Device import Device
from blueman.main.FakeDevice import FakeDevice
from blueman.bluez.Manager import Manager
from blueman.Functions import *
from blueman.Constants import *
from blueman.gui.DeviceSelectorDialog import DeviceSelectorDialog
from blueman.main.SpeedCalc import SpeedCalc
from blueman.main.AppletService import AppletService

from blueman.ods.OdsManager import OdsManager

enable_rgba_colormap()

class Sender(gobject.GObject):
    __gsignals__ = {
        'result' : (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_BOOLEAN,)),
    }
    def __init__(self, device, adapter, files):
        gobject.GObject.__init__(self)
        self.Builder = gtk.Builder()
        self.Builder.set_translation_domain("blueman")
        self.Builder.add_from_file(UI_PATH +"/send-dialog.ui")
        self.window = self.Builder.get_object("window")
        
        self.l_dest = self.Builder.get_object("l_dest")
        self.l_file = self.Builder.get_object("l_file")
        
        self.pb = self.Builder.get_object("pb")
        
        self.b_cancel = self.Builder.get_object("b_cancel")
        self.b_cancel.connect("clicked", self.on_cancel)
        
        self.pb.props.text = _("Connecting")
        
        self.device = device
        self.adapter = Adapter(adapter)
        self.files = files
        self.session = None
        
        self.total_bytes = 0
        self.total_transferred = 0
        
        self._last_bytes = 0
        self._last_update = 0
        
        self.error_dialog = None
        self.cancelling = False
        
        #bytes transferred on a current transfer
        self.transferred = 0
        
        self.speed = SpeedCalc(6)

        for i in range(len(self.files)-1,-1,-1):
            f = self.files[i]
            match = re.match("file://(.*)", f)
            if match:
                f = self.files[i] = urllib.unquote(match.groups(1)[0])
                
            if os.path.exists(f) and not os.path.isdir(f):
                f =  os.path.abspath(f)
                self.total_bytes += os.path.getsize(f)
            else:
                self.files.remove(f)

        
        self.num_files = len(self.files)
        try:
            self.manager = OdsManager()
        except:
            d = gtk.MessageDialog(  self.window,
            type=gtk.MESSAGE_ERROR, buttons=gtk.BUTTONS_OK)
            d.props.text = _("obex-data-server not available")
            d.props.secondary_text = _("obex-data-server is probably not installed")
            d.run()
            d.destroy()
            exit(1)
        
        if self.num_files == 0:
            exit(1)
        
        self.l_file.props.label = os.path.basename(self.files[-1])
        
        self.manager.GHandle("session-created", self.on_session_created)
        self.manager.GHandle("session-destroyed", self.on_session_destroyed)
        
        print "Sending to", device.Address
        self.l_dest.props.label = device.Alias
        
        self.create_session()
        
        self.window.show()

        
        
    def create_session(self):
        dprint("Creating session")
        def on_error(msg):
            dprint("Failed to create session")
            d = gtk.MessageDialog(  self.window,
            type=gtk.MESSAGE_ERROR, buttons=(gtk.BUTTONS_CLOSE))
            d.props.text = _("Error occurred")
            d.props.icon_name = "blueman"
            d.props.secondary_text = str(msg).split(":")[1].strip(" ")
        
            resp = d.run()
            d.destroy()
            exit(1)
        
        props = self.adapter.GetProperties()
        self.manager.create_session(self.device.Address, props["Address"], error_handler=on_error)
        
    def on_cancel(self, button):
        def reply(*args):
            self.session.Disconnect()
            self.emit("result", False)
        
        self.pb.props.text = _("Cancelling")
        button.props.sensitive = False
        
        if self.session:
            if self.session.Connected:
                self.session.Cancel(reply_handler=reply, error_handler=reply)
            else:
                print self.session.object_path
                self.manager.CancelSessionConnect(self.session.object_path)
                self.emit("result", False)
        else:
            self.emit("result", False)
            
        
        
    def on_transfer_started(self, session, filename, path, size):
        dprint("transfer started")
        
        #first transfer
        if self.total_transferred == 0:
            self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % {"1": self.num_files, 
                                        "0": (self.num_files - len(self.files)+1),
                                        "2": 0.0,
                                        "3": "B/s",
                                        "4": "∞" }
        
        self.l_file.props.label = filename
        self._last_bytes = 0
        self.transferred = 0
        
        
    def on_transfer_progress(self, session, progress):
        self.transferred = progress
        if self._last_bytes == 0:
            self.total_transferred += progress
        else:
            self.total_transferred += (progress - self._last_bytes) 
        
        self._last_bytes = progress
        
        tm = time.time()
        if tm - self._last_update > 0.5:
            spd = self.speed.calc(self.total_transferred)
            (size, units) = format_bytes(spd)
            try:
                x = ((self.total_bytes-self.total_transferred) / spd)+1
                if x > 60:
                    x = x / 60
                    eta = ngettext("%.0f Minute", "%.0f Minutes", round(x)) % x
                else:
                    eta = ngettext("%.0f Second", "%.0f Seconds", round(x)) % x
            except ZeroDivisionError:
                eta = "∞"

            self.pb.props.text = _("Sending File") + (" %(0)s/%(1)s (%(2).2f %(3)s/s) " + _("ETA:") + " %(4)s") % {"1": self.num_files, 
                                    "0": (self.num_files - len(self.files)+1),
                                    "2": size,
                                    "3": units,
                                    "4": eta}
            self._last_update = tm
        
        self.pb.props.fraction = float(self.total_transferred) / self.total_bytes

        
    def on_transfer_completed(self, session):
        del self.files[-1]
        
        self.process_queue()
        
    def process_queue(self):
        if len(self.files) > 0:
            self.send_file(self.files[-1])
        else:
            self.emit("result", True)
        
        
    def send_file(self, file_path):
        dprint(file_path)
        if self.session and self.session.Connected:
            self.session.SendFile(file_path)
        
        
    def on_session_disconnected(self, session):
        if self.session:
            try:
                self.session.Close()
            except:
                dprint("Warning: Session already closed")
        
    def on_session_destroyed(self, manager, path):
        if self.session.object_path == path:
            self.session = None
        
    def on_session_connected(self, session):
        dprint("commence transfer")
        self.sesion = session
        self.process_queue()
        
    def on_session_error(self, session, name, msg):
        dprint("session err", name, msg)
        if not self.error_dialog:   
            self.speed.reset()
            d = gtk.MessageDialog(  self.window,
                        type=gtk.MESSAGE_ERROR)
            d.props.text = msg
            d.props.modal = True
            d.props.secondary_text = _("Error occurred while sending file %s") % os.path.basename(self.files[-1])
            d.props.icon_name = "blueman"
        
            if len(self.files) > 1:
                d.add_button(_("Skip"), gtk.RESPONSE_NO)
            d.add_button(_("Retry"), gtk.RESPONSE_YES)
            d.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
        
        
            def on_response(dialog, resp):
                dialog.destroy()
                self.error_dialog = None
                
                if resp == gtk.STOCK_CANCEL:
                    self.on_cancel(None)
                elif resp == gtk.RESPONSE_NO:
                    self.total_bytes -= os.path.getsize(self.files[-1])
                    self.total_transferred -= self.transferred
                    self.transferred = 0
                    del self.files[-1]
                    if not self.session or not self.session.Connected:
                        self.create_session()
                    self.process_queue()
                elif resp == gtk.RESPONSE_YES:
                    self.total_transferred -= self.transferred
                    self.transferred = 0
                    if not self.session or not self.session.Connected:
                        self.create_session()

                    self.process_queue()
                else:
                    self.on_cancel(None)        
        
            d.connect("response", on_response)
            d.show()
            self.error_dialog = d
        
        
    def on_session_created(self, manager, session):
        dprint()
        self.session = session
        session.GHandle("connected", self.on_session_connected)
        session.GHandle("disconnected", self.on_session_disconnected)
        session.GHandle("error-occurred", self.on_session_error)
        session.GHandle("transfer-started", self.on_transfer_started)
        session.GHandle("transfer-progress", self.on_transfer_progress)
        session.GHandle("transfer-completed", self.on_transfer_completed)
    
class SendTo:
    def __init__(self):
        setup_icon_path()
    
        usage = "Usage: %prog [options] file1 file2 ... fileN"
        parser = OptionParser(usage)
        parser.add_option("-d", "--device", dest="device",
                action="store", help=_("Send files to this device"), metavar="ADDRESS")
        
        parser.add_option("", "--dest", dest="device",
                action="store", help="Same as --device", metavar="ADDRESS") 
        
        (options, args) = parser.parse_args()
        
        check_bluetooth_status(_("Bluetooth needs to be turned on for file sending to work"), lambda: exit())
        
        self.options = options
        self.args = args
        
        self.device = None
        self.adapter = None
        self.files = []
        
        if options.device == None:
            if not self.select_device():
                exit()

            self.do_send()
            
        else:
            m = Manager("gobject")
            try:
                adapter = m.GetAdapter()
            except:
                print "Error: No Adapters present"
                exit()
            try:
                d = adapter.FindDevice(options.device)
            except:
                info = {}
                info["Address"] = options.device
                info["Name"] = info["Address"].replace(":", "-")
                info["Alias"] = info["Name"]
                info["Fake"] = True
                
                d = FakeDevice(info)

            self.device = Device(d)
            self.adapter = adapter.GetObjectPath()
            self.do_send()
        
        gtk.main()
        
    def do_send(self):
        if len(self.args) == 0:
            if not self.select_files():
                exit()
            else:
                sender = Sender(self.device, self.adapter, self.files)
        else:
            sender = Sender(self.device, self.adapter, self.args)
            
        def on_result(sender, res):
            gtk.main_quit()
        sender.connect("result", on_result)
        
        
    def select_files(self):
        d = gtk.FileChooserDialog(_("Select files to send"), buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
                                            gtk.STOCK_OK, gtk.RESPONSE_ACCEPT))
        d.props.icon_name = "blueman-send-file"                                 
        d.set_select_multiple(True)
        resp = d.run()
        
        if resp == gtk.RESPONSE_ACCEPT:
            self.files = d.get_filenames()
            d.destroy()
            return True
        else:
            d.destroy()
            return False

    
    def select_device(self):
        d = DeviceSelectorDialog()
        resp = d.run()
        d.destroy()
        if resp == gtk.RESPONSE_ACCEPT:
            sel = d.GetSelection()
            if sel:
                self.device = sel[1]
                self.adapter = sel[0]
                return True
            else:
                return False
        else:
            return False
    

    
SendTo()

Compare with Previous | Blame | Download | View Log