beginning to refactor onionshare_gui to work with multiple files (#66)

This commit is contained in:
Micah Lee 2014-08-27 14:21:08 -07:00
parent 3f59fe7af0
commit 78f6c31061
8 changed files with 214 additions and 40 deletions

View File

@ -6,5 +6,6 @@ include onionshare/index.html
include onionshare/404.html include onionshare/404.html
include onionshare/strings.json include onionshare/strings.json
include onionshare_gui/logo.png include onionshare_gui/logo.png
include onionshare_gui/drop_files.png
include setup/onionshare.desktop include setup/onionshare.desktop
include setup/onionshare80.xpm include setup/onionshare80.xpm

View File

@ -26,7 +26,13 @@
"help_local_only": "Do not attempt to use tor: for development only", "help_local_only": "Do not attempt to use tor: for development only",
"help_stay_open": "Keep hidden service running after download has finished", "help_stay_open": "Keep hidden service running after download has finished",
"help_debug": "Log errors to disk", "help_debug": "Log errors to disk",
"help_filename": "List of files or folders to share" "help_filename": "List of files or folders to share",
"gui_drag_and_drop": "Drag and drop\nfiles here",
"gui_add_files": "Add Files",
"gui_add_folder": "Add Folder",
"gui_delete": "Delete",
"gui_choose_files": "Choose files",
"gui_choose_folder": "Choose folder"
}, "no": { }, "no": {
"calculating_sha1": "Kalkulerer SHA1 sjekksum.", "calculating_sha1": "Kalkulerer SHA1 sjekksum.",
"connecting_ctrlport": "Kobler til Tors kontroll-port for å sette opp en gjemt tjeneste på port {0}.", "connecting_ctrlport": "Kobler til Tors kontroll-port for å sette opp en gjemt tjeneste på port {0}.",

10
onionshare_gui/common.py Normal file
View File

@ -0,0 +1,10 @@
import os, inspect, platform
def get_onionshare_gui_dir():
if platform.system() == 'Darwin':
onionshare_gui_dir = os.path.dirname(__file__)
else:
onionshare_gui_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
return onionshare_gui_dir
onionshare_gui_dir = get_onionshare_gui_dir()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,145 @@
import os
from PyQt4 import QtCore, QtGui
import common
from onionshare import strings, helpers
class FileList(QtGui.QListWidget):
files_dropped = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(FileList, self).__init__(parent)
self.setAcceptDrops(True)
self.setIconSize(QtCore.QSize(32, 32))
# drag and drop label
self.drop_label = QtGui.QLabel(QtCore.QString(strings._('gui_drag_and_drop')), parent=self)
self.drop_label.setAlignment(QtCore.Qt.AlignCenter)
self.drop_label.setStyleSheet('background: url({0}/drop_files.png) no-repeat center center; color: #999999;'.format(common.onionshare_gui_dir))
self.drop_label.hide()
self.filenames = []
self.update()
def update(self):
# file list should have a background image if empty
if len(self.filenames) == 0:
self.drop_label.show()
else:
self.drop_label.hide()
def resizeEvent(self, event):
self.drop_label.setGeometry(0, 0, self.width(), self.height())
def dragEnterEvent(self, event):
if event.mimeData().hasUrls:
event.accept()
else:
event.ignore()
def dragMoveEvent(self, event):
if event.mimeData().hasUrls:
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
else:
event.ignore()
def dropEvent(self, event):
if event.mimeData().hasUrls:
event.setDropAction(QtCore.Qt.CopyAction)
event.accept()
for url in event.mimeData().urls():
filename = str(url.toLocalFile())
self.add_file(filename)
else:
event.ignore()
self.files_dropped.emit()
def add_file(self, filename):
if filename not in self.filenames:
self.filenames.append(filename)
basename = os.path.basename(filename)
fileinfo = QtCore.QFileInfo(filename)
ip = QtGui.QFileIconProvider()
icon = ip.icon(fileinfo)
if os.path.isfile(filename):
size = self.human_readable_filesize(fileinfo.size())
else:
size = self.human_readable_filesize(helpers.dir_size(filename))
item = QtGui.QListWidgetItem('{0} ({1})'.format(basename, size))
item.setToolTip(QtCore.QString(size))
item.setIcon(icon)
self.addItem(item)
def human_readable_filesize(self, b):
thresh = 1024.0
if b < thresh:
return '{0} B'.format(b)
units = ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']
u = 0
b /= thresh
while b >= thresh:
b /= thresh
u += 1
return '{0} {1}'.format(round(b, 1), units[u])
class FileSelection(QtGui.QVBoxLayout):
def __init__(self):
super(FileSelection, self).__init__()
# file list
self.file_list = FileList()
self.file_list.currentItemChanged.connect(self.update)
self.file_list.files_dropped.connect(self.update)
# buttons
self.add_files_button = QtGui.QPushButton(strings._('gui_add_files'))
self.add_files_button.clicked.connect(self.add_files)
self.add_dir_button = QtGui.QPushButton(strings._('gui_add_folder'))
self.add_dir_button.clicked.connect(self.add_dir)
self.delete_button = QtGui.QPushButton(strings._('gui_delete'))
self.delete_button.clicked.connect(self.delete_file)
button_layout = QtGui.QHBoxLayout()
button_layout.addWidget(self.add_files_button)
button_layout.addWidget(self.add_dir_button)
button_layout.addWidget(self.delete_button)
# add the widgets
self.addWidget(self.file_list)
self.addLayout(button_layout)
self.update()
def update(self):
# delete button should be disabled if item isn't selected
current_item = self.file_list.currentItem()
if not current_item:
self.delete_button.setEnabled(False)
else:
self.delete_button.setEnabled(True)
# update the file list
self.file_list.update()
def add_files(self):
filenames = QtGui.QFileDialog.getOpenFileNames(caption=strings._('gui_choose_files'), options=QtGui.QFileDialog.ReadOnly)
if filenames:
for filename in filenames:
self.file_list.add_file(str(filename))
self.update()
def add_dir(self):
filename = QtGui.QFileDialog.getExistingDirectory(caption=strings._('gui_choose_folder'), options=QtGui.QFileDialog.ReadOnly)
if filename:
self.file_list.add_file(str(filename))
self.update()
def delete_file(self):
current_row = self.file_list.currentRow()
self.file_list.filenames.pop(current_row)
self.file_list.takeItem(current_row)
self.update()

View File

@ -2,20 +2,17 @@ from __future__ import division
import os, sys, subprocess, inspect, platform, argparse, threading, time, math, inspect, platform import os, sys, subprocess, inspect, platform, argparse, threading, time, math, inspect, platform
from PyQt4 import QtCore, QtGui from PyQt4 import QtCore, QtGui
def get_onionshare_gui_dir(): import common
if platform.system() == 'Darwin':
onionshare_gui_dir = os.path.dirname(__file__)
else:
onionshare_gui_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
return onionshare_gui_dir
try: try:
import onionshare import onionshare
except ImportError: except ImportError:
sys.path.append(os.path.abspath(__file__+"/..")) sys.path.append(os.path.abspath(common.onionshare_gui_dir+"/.."))
import onionshare import onionshare
from onionshare import strings, helpers, web from onionshare import strings, helpers, web
from file_selection import FileSelection
class Application(QtGui.QApplication): class Application(QtGui.QApplication):
def __init__(self): def __init__(self):
platform = helpers.get_platform() platform = helpers.get_platform()
@ -24,10 +21,28 @@ class Application(QtGui.QApplication):
QtGui.QApplication.__init__(self, sys.argv) QtGui.QApplication.__init__(self, sys.argv)
class OnionShareGui(QtGui.QWidget): class OnionShareGui(QtGui.QWidget):
def __init__(self, app, filename, basename): def __init__(self, app, filenames=None):
super(OnionShareGui, self).__init__() super(OnionShareGui, self).__init__()
self.app = app self.app = app
self.filenames = filenames
self.setWindowTitle('OnionShare')
self.setWindowIcon(window_icon)
def start_send(self):
# file selection
file_selection = FileSelection()
if self.filenames:
for filename in self.filenames:
file_selection.file_list.add_file(filename)
# main layout
self.layout = QtGui.QVBoxLayout()
self.layout.addLayout(file_selection)
self.setLayout(self.layout)
self.show()
"""
# initialize ui # initialize ui
self.init_ui(filename, basename) self.init_ui(filename, basename)
# check for requests every 1000ms # check for requests every 1000ms
@ -64,7 +79,7 @@ class OnionShareGui(QtGui.QWidget):
# logo # logo
self.logoLabel = QtGui.QLabel(self.widget) self.logoLabel = QtGui.QLabel(self.widget)
self.logo = QtGui.QPixmap("{0}/static/logo.png".format(get_onionshare_gui_dir())) self.logo = QtGui.QPixmap("{0}/static/logo.png".format(common.onionshare_gui_dir))
self.logoLabel.setPixmap(self.logo) self.logoLabel.setPixmap(self.logo)
self.header.addWidget(self.logoLabel) self.header.addWidget(self.logoLabel)
@ -268,6 +283,7 @@ class OnionShareGui(QtGui.QWidget):
else: else:
web.set_stay_open(True) web.set_stay_open(True)
return return
"""
def alert(msg, icon=QtGui.QMessageBox.NoIcon): def alert(msg, icon=QtGui.QMessageBox.NoIcon):
dialog = QtGui.QMessageBox() dialog = QtGui.QMessageBox()
@ -277,24 +293,6 @@ def alert(msg, icon=QtGui.QMessageBox.NoIcon):
dialog.setIcon(icon) dialog.setIcon(icon)
dialog.exec_() dialog.exec_()
def select_file(filename=None):
# get filename, either from argument or file chooser dialog
if not filename:
filename = QtGui.QFileDialog.getOpenFileName(caption=strings._('choose_file'), options=QtGui.QFileDialog.ReadOnly)
if not filename:
return False, False
filename = str(unicode(filename).encode("utf-8"))
# validate filename
if not os.path.isfile(filename):
alert(strings._("not_a_file").format(filename), QtGui.QMessageBox.Warning)
return False, False
filename = os.path.abspath(filename)
basename = os.path.basename(filename)
return filename, basename
def main(): def main():
strings.load_strings() strings.load_strings()
@ -307,23 +305,37 @@ def main():
parser.add_argument('--local-only', action='store_true', dest='local_only', help=strings._("help_local_only")) parser.add_argument('--local-only', action='store_true', dest='local_only', help=strings._("help_local_only"))
parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open")) parser.add_argument('--stay-open', action='store_true', dest='stay_open', help=strings._("help_stay_open"))
parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug")) parser.add_argument('--debug', action='store_true', dest='debug', help=strings._("help_debug"))
parser.add_argument('filename', nargs='?', help=strings._("help_filename")) parser.add_argument('--filenames', metavar='filenames', nargs='+', help=strings._('help_filename'))
args = parser.parse_args() args = parser.parse_args()
filename = args.filename filenames = args.filenames
if filenames:
for i in range(len(filenames)):
filenames[i] = os.path.abspath(filenames[i])
local_only = bool(args.local_only) local_only = bool(args.local_only)
stay_open = bool(args.stay_open) stay_open = bool(args.stay_open)
debug = bool(args.debug) debug = bool(args.debug)
web.set_stay_open(stay_open) # validation
if filenames:
valid = True
for filename in filenames:
if not os.path.exists(filename):
alert(strings._("not_a_file").format(filename))
valid = False
if not valid:
sys.exit()
# create the onionshare icon # create the onionshare icon
global window_icon global window_icon
window_icon = QtGui.QIcon("{0}/static/logo.png".format(get_onionshare_gui_dir())) window_icon = QtGui.QIcon("{0}/static/logo.png".format(common.onionshare_gui_dir))
# start the onionshare app # start the onionshare app
try: web.set_stay_open(stay_open)
app = onionshare.OnionShare(debug, local_only, stay_open) app = onionshare.OnionShare(debug, local_only, stay_open)
"""try:
app.start_hidden_service(gui=True) app.start_hidden_service(gui=True)
except onionshare.NoTor as e: except onionshare.NoTor as e:
alert(e.args[0], QtGui.QMessageBox.Warning) alert(e.args[0], QtGui.QMessageBox.Warning)
@ -331,11 +343,7 @@ def main():
except onionshare.TailsError as e: except onionshare.TailsError as e:
alert(e.args[0], QtGui.QMessageBox.Warning) alert(e.args[0], QtGui.QMessageBox.Warning)
sys.exit() sys.exit()
"""
# select file to share
filename, basename = select_file(filename)
if not filename:
return
# clean up when app quits # clean up when app quits
def shutdown(): def shutdown():
@ -343,7 +351,8 @@ def main():
qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown) qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown)
# launch the gui # launch the gui
gui = OnionShareGui(app, filename, basename) gui = OnionShareGui(app, filenames)
gui.start_send()
# all done # all done
sys.exit(qtapp.exec_()) sys.exit(qtapp.exec_())

View File

@ -9,6 +9,7 @@ a.datas += [
('onionshare/index.html', 'onionshare/index.html', 'DATA'), ('onionshare/index.html', 'onionshare/index.html', 'DATA'),
('onionshare/404.html', 'onionshare/404.html', 'DATA'), ('onionshare/404.html', 'onionshare/404.html', 'DATA'),
('onionshare_gui/logo.png', 'onionshare_gui/logo.png', 'DATA'), ('onionshare_gui/logo.png', 'onionshare_gui/logo.png', 'DATA'),
('onionshare_gui/drop_files.png', 'onionshare_gui/drop_files.png', 'DATA'),
] ]
pyz = PYZ(a.pure) pyz = PYZ(a.pure)
exe = EXE(pyz, exe = EXE(pyz,

View File

@ -59,6 +59,7 @@ Section "install"
File "${BINPATH}\onionshare_gui\__init__.py" File "${BINPATH}\onionshare_gui\__init__.py"
File "${BINPATH}\onionshare_gui\__init__.pyc" File "${BINPATH}\onionshare_gui\__init__.pyc"
File "${BINPATH}\onionshare_gui\logo.png" File "${BINPATH}\onionshare_gui\logo.png"
File "${BINPATH}\onionshare_gui\drop_files.png"
# dependencies # dependencies
SetOutPath $INSTDIR SetOutPath $INSTDIR
@ -162,6 +163,7 @@ Section "uninstall"
Delete "$INSTDIR\onionshare_gui\__init__.py" Delete "$INSTDIR\onionshare_gui\__init__.py"
Delete "$INSTDIR\onionshare_gui\__init__.pyc" Delete "$INSTDIR\onionshare_gui\__init__.pyc"
Delete "$INSTDIR\onionshare_gui\logo.png" Delete "$INSTDIR\onionshare_gui\logo.png"
Delete "$INSTDIR\onionshare_gui\drop_files.png"
Delete "$INSTDIR\onionshare_gui\onionshare_gui.py" Delete "$INSTDIR\onionshare_gui\onionshare_gui.py"
Delete "$INSTDIR\onionshare_gui\onionshare_gui.pyc" Delete "$INSTDIR\onionshare_gui\onionshare_gui.pyc"
Delete "$INSTDIR\qt4_plugins\accessible\qtaccessiblewidgets4.dll" Delete "$INSTDIR\qt4_plugins\accessible\qtaccessiblewidgets4.dll"