# -*- coding: utf-8 -*-
# This file is part of emesene.
#
# Emesene 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 2 of the License, or
# (at your option) any later version.
#
# emesene 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 emesene; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import gtk
import pango
import gobject
import desktop
class FtBarWidget(gtk.HBox):
'''bar which represents active file transfers'''
def __init__(self, controller, parentUI, parentConversation):
gtk.HBox.__init__(self)
self.set_spacing(3)
self.controller = controller
self.parentUI = parentUI
self.parentConversation = parentConversation
self.hbox = gtk.HBox()
self.hbox.set_spacing(3)
self.layout = gtk.Layout()
self.layout.put(self.hbox, 0, 0)
self.layout.set_size(self.hbox.get_allocation().width, \
self.hbox.get_allocation().height + 100)
self.current = 0
self.speed = 5
self.page = 0
self.twidth = 150
self.num_transfers = 0
arrowLeft = gtk.Arrow(gtk.ARROW_LEFT, gtk.SHADOW_IN)
arrowRight = gtk.Arrow(gtk.ARROW_RIGHT, gtk.SHADOW_IN)
self.btnLeft = gtk.Button()
self.btnLeft.add(arrowLeft)
self.btnLeft.set_sensitive(False)
self.btnLeft.set_relief(gtk.RELIEF_NONE)
self.btnLeft.connect("clicked", self.onbtnLeft)
self.btnRight = gtk.Button()
self.btnRight.add(arrowRight)
self.btnRight.set_sensitive(False)
self.btnRight.set_relief(gtk.RELIEF_NONE)
self.btnRight.connect("clicked", self.onbtnRight)
self.pack_start(self.btnLeft, False, False)
self.pack_start(self.layout)
self.pack_start(self.btnRight, False, False)
def add(self, transfer):
self.newBar = FtWidget(self.controller, self, transfer)
transfer.ui = self.newBar
self.hbox.pack_start(self.newBar, False, False)
self.num_transfers += 1
if self.num_transfers > 1:
self.btnRight.set_sensitive(True)
else:
self.btnRight.set_sensitive(False)
self.set_no_show_all(False)
self.show_all()
def onbtnLeft(self, widget):
self.twidth = self.newBar.get_allocation().width
self.page -= 1
self.dest = -self.twidth * self.page
gobject.timeout_add(5, self.onSmoothLeft)
def onbtnRight(self, widget):
if self.num_transfers == 1:
self.btnRight.set_sensitive(False)
return False
self.twidth = self.newBar.get_allocation().width
self.btnLeft.set_sensitive(True)
self.page += 1
self.dest = -self.twidth * self.page
gobject.timeout_add(5, self.onSmoothRight)
def onSmoothRight(self, *args):
self.div = self.num_transfers - 1
if self.dest == (self.dest * self.page) / self.div:
self.btnRight.set_sensitive(False)
if self.current > self.dest:
self.current -= self.speed
self.layout.move(self.hbox, self.current, 0)
return True
return False
def onSmoothLeft(self, *args):
if self.dest == 0:
self.btnLeft.set_sensitive(False)
if self.dest >= 0:
self.btnRight.set_sensitive(True)
if self.current < self.dest:
self.current += self.speed
self.layout.move(self.hbox, self.current, 0)
return True
return False
class FtWidget(gtk.HBox):
'''this class represents the ui widget for one filetransfer'''
def __init__(self, controller, transferBar, transfer):
gtk.HBox.__init__(self)
self.controller = controller
self.transferBar = transferBar
self.transfer = transfer
self.eventBox = gtk.EventBox()
self.progress = gtk.ProgressBar()
self.progress.set_ellipsize(pango.ELLIPSIZE_END)
self.progress.add_events(gtk.gdk.BUTTON_PRESS_MASK)
self.progress.connect("button-press-event",self.onDoubleClickTransfer)
self.menu = gtk.Menu()
fileImage = gtk.image_new_from_stock(gtk.STOCK_FILE, \
gtk.ICON_SIZE_BUTTON)
folderImage = gtk.image_new_from_stock(gtk.STOCK_OPEN, \
gtk.ICON_SIZE_BUTTON)
menuOpenFile = gtk.ImageMenuItem(_("Open file"))
menuOpenFile.connect("activate", self.on_menu_file_clicked)
menuOpenFile.set_image(fileImage)
menuOpenDir = gtk.ImageMenuItem(_("Open folder"))
menuOpenDir.connect("activate", self.on_menu_folder_clicked)
menuOpenDir.set_image(folderImage)
self.menu.add(menuOpenFile)
self.menu.add(menuOpenDir)
self.menu.show_all()
self.eventBox.add(self.progress)
self.pack_start(self.eventBox, False, False)
self.pack_start(self.menu)
self.buttons = []
self.show_all()
self.tooltip = FileTransferTooltip(self.eventBox, self.transfer)
self.eventBox.connect('event', self.onProgressBarEvent)
self.updateProgress()
self.stateChanged()
def onDoubleClickTransfer(self, widget, event):
if event.button == 1 and event.type == gtk.gdk._2BUTTON_PRESS:
if self.transfer.state == self.transfer.RECEIVED:
self.transfer.open()
def onProgressBarEvent(self, widget, event):
if event.type == gtk.gdk.BUTTON_PRESS:
if self.transfer.state == self.transfer.RECEIVED:
if event.button == 3:
self.menu.popup(None, None, None, event.button, event.time)
def on_menu_file_clicked(self, widget):
self.transfer.open()
def on_menu_folder_clicked(self, widget):
self.transfer.opendir()
def updateProgress(self):
if self.transfer.state == self.transfer.RECEIVED:
self.progress.set_fraction(1) # 100%
else:
self.progress.set_fraction(self.transfer.getFraction())
self.progress.set_text(self.transfer.getFilename())
self.tooltip.update()
def stateChanged(self):
state = self.transfer.state
# remove existing buttons
for button in self.buttons:
self.remove(button)
self.buttons = []
if state == self.transfer.WAITING and self.transfer.sender != 'Me':
button = gtk.Button(None, None)
button.set_image(self.getButtonImage(gtk.STOCK_APPLY))
button.connect('clicked', self.onAcceptClicked)
self.buttons.append(button)
if state in (self.transfer.RECEIVED, self.transfer.FAILED):
button = gtk.Button(None, None)
button.set_image(self.getButtonImage(gtk.STOCK_CLEAR))
button.connect('clicked', self.onCloseClicked)
self.buttons.append(button)
if state == self.transfer.WAITING or state == self.transfer.TRANSFERING:
cancelButton = gtk.Button(None, None)
cancelButton.connect('clicked', self.onCancelClicked)
cancelButton.set_image(self.getButtonImage(gtk.STOCK_CANCEL))
self.buttons.append(cancelButton)
for button in self.buttons:
self.pack_start(button, False, False)
self.show_all()
self.updateProgress()
def getButtonImage(self, stockImage):
img = gtk.Image()
img.set_from_stock(stockImage, gtk.ICON_SIZE_MENU)
return img
def onCancelClicked(self, widget):
self.transfer.cancel()
self.transferBar.hbox.remove(self)
self.transferBar.num_transfers -= 1
if self.transferBar.num_transfers == 0:
self.transferBar.hide()
def onAcceptClicked(self, widget):
self.transfer.accept()
def onCloseClicked(self, widget):
self.transfer.remove()
self.transferBar.hbox.remove(self)
self.transferBar.num_transfers -= 1
if self.transferBar.num_transfers == 0:
self.transferBar.hide()
DELAY = 500
class FileTransferTooltip(gtk.Window):
'''Class that implements the filetransfer tooltip'''
def __init__(self, parentWidget, transfer):
gtk.Window.__init__(self, gtk.WINDOW_POPUP)
self.transfer = transfer
self.set_name('gtk-tooltips')
self.set_position(gtk.WIN_POS_MOUSE)
self.set_resizable(False)
self.set_border_width(4)
self.set_app_paintable(True)
self.image = gtk.Image()
self.details = gtk.Label()
self.details.set_alignment(0, 0)
self.table = gtk.Table(3, 2, False)
self.table.set_col_spacings(5)
self.addLabel(_('Status:'), 0, 1, 0, 1)
self.addLabel(_('Average speed:'), 0, 1, 1, 2)
self.addLabel(_('Time elapsed:'), 0, 1, 2, 3)
self.addLabel(_('Estimated time left:'), 0, 1, 3, 4)
self.status = gtk.Label()
self.speed = gtk.Label()
self.elapsed = gtk.Label()
self.etl = gtk.Label()
self.addLabel('', 1, 2, 0, 1, self.status)
self.addLabel('', 1, 2, 1, 2, self.speed)
self.addLabel('', 1, 2, 2, 3, self.elapsed)
self.addLabel('', 1, 2, 3, 4, self.etl)
vbox = gtk.VBox(False, 5)
vbox.pack_start(self.details, False, False)
vbox.pack_start(self.table, False, False)
hbox = gtk.HBox(False, 5)
hbox.pack_start(self.image, False, False)
hbox.pack_start(vbox, True, True)
self.add(hbox)
self.connect('expose-event', self.on_expose_event)
parentWidget.connect('enter-notify-event', self.on_motion)
parentWidget.connect('leave-notify-event', self.on_leave)
self.mouseOverWidget = False
def addLabel(self, s, left, right, top, bottom, label = None):
if label == None:
label = gtk.Label(s)
label.set_alignment(0, 0)
self.table.attach(label, left, right, top, bottom)
def on_motion(self, view, event):
self.mouseOverWidget = True
eventCoords = (event.x_root, event.y_root, int(event.y))
gobject.timeout_add(DELAY, self.show_tooltip, \
view, eventCoords)
def show_tooltip(self, view, origCoords):
# tooltip is shown after a delay, so we have to check
# if mouse is still over parent widget
if not self.mouseOverWidget:
return
pixbuf = self.transfer.getPreviewImage()
#amsn sends a big. black preview? :S
if pixbuf and pixbuf.get_height() <= 96 and pixbuf.get_width() <= 96:
self.image.set_from_pixbuf(pixbuf)
# set the location of the tooltip
x, y = self.computePosition(origCoords, view.window)
self.move(x, y)
self.update()
self.show_all()
return False
def update(self):
self.details.set_markup('<b>' + self.transfer.getFilename() + '</b>')
time_left = self.transfer.getEstimatedTimeLeft()
bps = self.transfer.getAverageSpeed()
seconds = self.transfer.getElapsedTime()
received, total = self.transfer.getBytes()
percentage = int(self.transfer.getFraction() * 100)
self.status.set_text('%d%% (%d/%d KB)' % (percentage, \
int(received)/1024, int(total) / 1024))
self.elapsed.set_text('%.2d:%.2d' % (int(seconds / 60), \
int(seconds % 60)))
self.speed.set_text('%.2f KiB/s' % (float(bps) / 1024.0))
self.etl.set_text('%.2d:%.2d' % (int(time_left / 60), \
int(time_left % 60)))
def on_leave(self, view, event):
self.mouseOverWidget = False
self.hide()
# display a border around the tooltip
def on_expose_event(self, tooltip_window, event):
width, height = tooltip_window.get_size()
tooltip_window.style.paint_flat_box(tooltip_window.window, \
gtk.STATE_NORMAL, gtk.SHADOW_OUT, \
None, tooltip_window, 'tooltip', \
0, 0, width, height)
def computePosition(self, origCoords, viewWindow):
x_root, y_root, origY = origCoords
currentY = viewWindow.get_pointer()[1]
width, height = self.get_size()
s_width, s_height = gtk.gdk.screen_width(), gtk.gdk.screen_height()
x = int(x_root) - width/2
if currentY >= origY:
y = int(y_root) + 24
else:
y = int(y_root) + 6
# check if over the screen
if x + width > s_width:
x = s_width - width
elif x < 0:
x = 0
if y + height > s_height:
y = y - height - 24
elif y < 0:
y = 0
return (x, y)
|