# -*- coding: utf-8 -*-
# coding=utf-8
# Copyright (C) 2009 quinox. All rights reserved.
#
# 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 .
import gtk
import gobject
import os, sys
import thread
from os.path import exists, join
from time import time
from pynicotine.utils import _
from dirchooser import ChooseDir
from utils import OpenUri, InitialiseColumns, recode, HumanSize
dir_location = os.path.dirname(os.path.realpath(__file__))
def dirstats(directory):
from os.path import join, getsize
totaldirs = 0
totalfiles = 0
totalsize = 0
extensions = {}
for root, dirs, files in os.walk(directory):
totaldirs += len(dirs)
totalfiles += len(files)
for f in files:
try:
totalsize += getsize(join(root, f))
except OSError:
pass
parts = f.rsplit('.', 1)
if len(parts) == 2 and len(parts[1]) < 5:
try:
extensions[parts[1]] += 1
except KeyError:
extensions[parts[1]] = 1
return totaldirs, totalfiles, totalsize, extensions
def widgetname(widget):
"""Raises AttributeError if given widget has no name property whatsoever."""
try:
return gtk.Buildable.get_name(widget) # New GTK way
except TypeError:
return widget.get_name() # Old GTK way
class FastConfigureAssistant(object):
def __init__(self, frame):
self.frame = frame
self.initphase = True # don't respond to signals unless False
self.config = frame.np.config
builder = gtk.Builder()
builder.add_from_file(join(dir_location, "fastconfigure.glade"))
self.window = builder.get_object("FastConfigureAssistant")
builder.connect_signals(self)
self.kids = {}
for i in builder.get_objects():
try:
self.kids[widgetname(i)] = i
except AttributeError:
pass
numpages = self.window.get_n_pages()
for n in xrange(numpages):
page = self.window.get_nth_page(n)
template = self.window.get_page_title(page)
self.window.set_page_title(page, template % {'page':(n+1), 'pages':numpages})
self.templates = {
'listenport': self.kids['listenport'].get_text(),
}
# Page specific, sharepage
# the lsat column is the raw byte/unicode object for the folder (not shown)
self.sharelist = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
columns = InitialiseColumns(self.kids['shareddirectoriestree'],
[_("Directory"), 0, "text"],
[_("Size"), 0, "text"],
[_("Files"), 0, "text"],
[_("Dirs"), 0, "text"],
[_("File types"), 0, "text"],
)
self.kids['shareddirectoriestree'].set_model(self.sharelist)
self.kids['shareddirectoriestree'].get_selection().set_mode(gtk.SELECTION_MULTIPLE)
self.initphase = False
#self.show() # DEBUG
#self.window.set_current_page(3) # DEBUG
def show(self):
self.initphase = True
self._populate()
self.initphase = False
self.window.show()
def _populate(self):
# userpasspage
self.kids['username'].set_text(self.config.sections["server"]["login"])
self.kids['password'].set_text(self.config.sections["server"]["passw"])
# portpage
self.kids['advancedports'].set_expanded(self.config.sections["server"]["upnp"])
if (time() - self.config.sections["server"]["lastportstatuscheck"]) > (60 * 60 * 24 * 31) or self.config.sections["server"]["upnp"]:
# More than a month ago since our last port status check
self.kids['portopen'].set_active(False)
self.kids['portclosed'].set_active(False)
self.kids['porthidden'].set_active(True)
else:
if self.config.sections["server"]["firewalled"]:
self.kids['portclosed'].set_active(True)
else:
self.kids['portopen'].set_active(True)
self.kids['lowerport'].set_value(self.config.sections["server"]["portrange"][0])
self.kids['upperport'].set_value(self.config.sections["server"]["portrange"][1])
self.kids['useupnp'].set_active(self.config.sections["server"]["upnp"])
# sharepage
if self.config.sections['transfers']['downloaddir']:
self.kids['downloaddir'].set_current_folder(self.config.sections['transfers']['downloaddir'])
self.sharelist.clear()
if self.config.sections["transfers"]["friendsonly"] and self.config.sections["transfers"]["enablebuddyshares"]:
for directory in self.config.sections["transfers"]["buddyshared"]:
self.addshareddir(directory)
else:
for directory in self.config.sections["transfers"]["shared"]:
self.addshareddir(directory)
self.kids['onlysharewithfriends'].set_active(self.config.sections["transfers"]["friendsonly"])
# If the user has a public share and a buddy share we cannot update this from FastConfigure (we only have 1 list of dirs)
self.caneditshare = (not self.config.sections["transfers"]["enablebuddyshares"] or self.config.sections["transfers"]["friendsonly"])
self.kids['onlysharewithfriends'].set_sensitive(self.caneditshare)
self.kids['addshare'].set_sensitive(self.caneditshare)
self.kids['removeshares'].set_sensitive(self.caneditshare)
self.kids['shareddirectoriestree'].set_sensitive(self.caneditshare)
def store(self):
# userpasspage
self.config.sections["server"]["login"] = self.kids['username'].get_text()
self.config.sections["server"]["passw"] = self.kids['password'].get_text()
# portpage
self.config.sections['server']['firewalled'] = not self.kids['portopen'].get_active()
self.config.sections['server']['lastportstatuscheck'] = time()
# sharepage
self.config.sections['transfers']['downloaddir'] = self.kids['downloaddir'].get_current_folder()
if self.caneditshare:
self.config.sections["transfers"]["friendsonly"] = self.kids['onlysharewithfriends'].get_active()
if self.config.sections["transfers"]["friendsonly"] and self.config.sections["transfers"]["enablebuddyshares"]:
self.config.sections["transfers"]["buddyshared"] = self.getshareddirs()
else:
self.config.sections["transfers"]["shared"] = self.getshareddirs()
def OnClose(self, widget):
self.window.hide()
def OnApply(self, widget):
self.store()
self.window.hide()
if not self.frame.np.serverconn:
self.frame.OnFirstConnect(-1)
def OnCancel(self, widget):
self.window.hide()
def updatepage(self, page):
"""Updates information on the given page with. Use _populate if possible"""
if not page:
return
name = widgetname(page)
if name == 'portpage':
self.kids['listenport'].set_markup(_(self.templates['listenport']) % {'listenport':''+str(self.frame.np.waitport)+''})
#else:
# print "Unknown page %s" % (name,)
def resetcompleteness(self, page = None):
"""Turns on the complete flag if everything required is filled in."""
# Never use self.config.sections here, only self.kids.
complete = False
if not page:
pageid = self.window.get_current_page()
page = self.window.get_nth_page(pageid)
if not page:
return
name = widgetname(page)
if name == 'welcomepage':
complete = True
elif name == 'userpasspage':
if (len(self.kids['username'].get_text()) > 0 and
len(self.kids['password'].get_text()) > 0):
complete = True
elif name == 'portpage':
if self.kids['useupnp'].get_active():
complete = True
else:
if self.kids['portopen'].get_active() or self.kids['portclosed'].get_active():
complete = True
elif name == 'sharepage':
if exists(self.kids['downloaddir'].get_filename()):
complete = True
elif name == 'summarypage':
complete = True
showcpwarning = (self.kids['portclosed'].get_active() and not self.kids['useupnp'].get_active())
if showcpwarning:
self.kids['labelclosedport'].show()
self.kids['warningclosedport'].show()
else:
self.kids['labelclosedport'].hide()
self.kids['warningclosedport'].hide()
shownfwarning = (self.kids['onlysharewithfriends'].get_active() or len(self.getshareddirs()) == 0)
if shownfwarning:
self.kids['labelnoshare'].show()
self.kids['warningnoshare'].show()
else:
self.kids['labelnoshare'].hide()
self.kids['warningnoshare'].hide()
#else:
# print "Unknown page with name " + name
self.window.set_page_complete(page, complete)
def OnPrepare(self, widget, page):
self.window.set_page_complete(page, False)
self.updatepage(page)
self.resetcompleteness(page)
def OnEntryChanged(self, widget, param1 = None, param2 = None, param3 = None):
name = widgetname(widget)
#print "Changed %s, %s" % (widget, name)
self.resetcompleteness()
def getshareddirs(self):
iter = self.sharelist.get_iter_root()
dirs = []
while iter is not None:
dirs.append(self.sharelist.get_value(iter, 5))
iter = self.sharelist.iter_next(iter)
return dirs
def addshareddir(self, directory):
iter = self.sharelist.get_iter_root()
while iter is not None:
if directory == self.sharelist.get_value(iter, 5):
return
iter = self.sharelist.iter_next(iter)
self.sharelist.append([recode(directory), "", "", "", _("Counting files..."), directory])
thread.start_new_thread(self._addsharedir, (directory,))
def _addsharedir(self, directory):
subdirs, files, size, extensions = dirstats(directory)
exts = []
for ext, count in extensions.iteritems():
exts.append((count, ext))
exts.sort(reverse=True)
extstring = ", ".join(["%s %s" % (count, ext) for count, ext in exts[:5]])
if len(exts) > 5:
extstring += ", ..."
gobject.idle_add(self._updatedirstats, directory, recode(directory), HumanSize(size), files, subdirs, extstring)
def _updatedirstats(self, directory, directorystring, size, files, subdirs, extensions):
iter = self.sharelist.get_iter_root()
while iter is not None:
if directory == self.sharelist.get_value(iter, 5):
self.sharelist.insert_after(iter, [recode(directory), HumanSize(size), files, subdirs, extensions, directory])
self.sharelist.remove(iter)
return
iter = self.sharelist.iter_next(iter)
def OnButtonPressed(self, widget):
if self.initphase:
return
name = widgetname(widget)
#print "Pressed %s" % (name)
if name == "checkmyport":
OpenUri('='.join(['http://tools.slsknet.org/porttest.php?port', str(self.frame.np.waitport)]))
if name == "addshare":
selected = ChooseDir(self.window.get_toplevel(), title=_("Nicotine+")+": "+_("Add a shared directory"))
if selected:
for directory in selected:
self.addshareddir(directory)
if name == "removeshares":
model, paths = self.kids['shareddirectoriestree'].get_selection().get_selected_rows()
refs = [gtk.TreeRowReference(model, x) for x in paths]
for i in refs:
self.sharelist.remove(self.sharelist.get_iter(i.get_path()))
self.resetcompleteness()
def OnToggled(self, widget):
name = widgetname(widget)
if name == 'useupnp':
# Setting active state
if widget.get_active():
self.kids['portopen'].set_inconsistent(True)
self.kids['portclosed'].set_inconsistent(True)
else:
self.kids['portopen'].set_inconsistent(False)
self.kids['portclosed'].set_inconsistent(False)
# Setting sensitive state
inverse = not widget.get_active()
self.kids['portopen'].set_sensitive(inverse)
self.kids['portclosed'].set_sensitive(inverse)
self.kids['checkmyport'].set_sensitive(inverse)
self.resetcompleteness()
if self.initphase:
return
# Setting changing
#print "toggled on " + name
self.resetcompleteness()
def OnSpinbuttonChangeValue(self, widget, scrolltype):
if self.initphase:
return
name = widgetname(widget)
#print "pre spinval on " + name
self.resetcompleteness()
def OnSpinbuttonValueChanged(self, widget):
if self.initphase:
return
name = widgetname(widget)
#print "post spinval on " + name
if name == "lowerport":
if widget.get_value() > self.kids['upperport'].get_value():
self.kids['upperport'].set_value(widget.get_value())
if name == "upperport":
if widget.get_value() < self.kids['lowerport'].get_value():
self.kids['lowerport'].set_value(widget.get_value())
self.resetcompleteness()
def OnKeyPress(self, widget, event):
if event.keyval == gtk.gdk.keyval_from_name("Esc"):
self.OnCancel(None)