[Pkg-anonymity-tools] [onionshare] 34/140: beginning to refactor onionshare_gui to work with multiple files (#66)

Ulrike Uhlig u-guest at moszumanska.debian.org
Mon Sep 29 20:33:45 UTC 2014


This is an automated email from the git hooks/post-receive script.

u-guest pushed a commit to branch master
in repository onionshare.

commit 78f6c310617e1ee936918484977d6766141e6e8f
Author: Micah Lee <micah at micahflee.com>
Date:   Wed Aug 27 14:21:08 2014 -0700

    beginning to refactor onionshare_gui to work with multiple files (#66)
---
 MANIFEST.in                      |   1 +
 onionshare/strings.json          |   8 ++-
 onionshare_gui/common.py         |  10 +++
 onionshare_gui/drop_files.png    | Bin 0 -> 2035 bytes
 onionshare_gui/file_selection.py | 145 +++++++++++++++++++++++++++++++++++++++
 onionshare_gui/onionshare_gui.py |  87 ++++++++++++-----------
 setup/onionshare-osx.spec        |   1 +
 setup/onionshare.nsi             |   2 +
 8 files changed, 214 insertions(+), 40 deletions(-)

diff --git a/MANIFEST.in b/MANIFEST.in
index 8af755d..d054d40 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -6,5 +6,6 @@ include onionshare/index.html
 include onionshare/404.html
 include onionshare/strings.json
 include onionshare_gui/logo.png
+include onionshare_gui/drop_files.png
 include setup/onionshare.desktop
 include setup/onionshare80.xpm
diff --git a/onionshare/strings.json b/onionshare/strings.json
index 312e86b..8207fc4 100644
--- a/onionshare/strings.json
+++ b/onionshare/strings.json
@@ -26,7 +26,13 @@
     "help_local_only": "Do not attempt to use tor: for development only",
     "help_stay_open": "Keep hidden service running after download has finished",
     "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": {
     "calculating_sha1": "Kalkulerer SHA1 sjekksum.",
     "connecting_ctrlport": "Kobler til Tors kontroll-port for å sette opp en gjemt tjeneste på port {0}.",
diff --git a/onionshare_gui/common.py b/onionshare_gui/common.py
new file mode 100644
index 0000000..4394a26
--- /dev/null
+++ b/onionshare_gui/common.py
@@ -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()
diff --git a/onionshare_gui/drop_files.png b/onionshare_gui/drop_files.png
new file mode 100644
index 0000000..1e2ea7d
Binary files /dev/null and b/onionshare_gui/drop_files.png differ
diff --git a/onionshare_gui/file_selection.py b/onionshare_gui/file_selection.py
new file mode 100644
index 0000000..ea8e882
--- /dev/null
+++ b/onionshare_gui/file_selection.py
@@ -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()
+
diff --git a/onionshare_gui/onionshare_gui.py b/onionshare_gui/onionshare_gui.py
index 35780c5..84d0262 100644
--- a/onionshare_gui/onionshare_gui.py
+++ b/onionshare_gui/onionshare_gui.py
@@ -2,20 +2,17 @@ from __future__ import division
 import os, sys, subprocess, inspect, platform, argparse, threading, time, math, inspect, platform
 from PyQt4 import QtCore, QtGui
 
-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
+import common
 
 try:
     import onionshare
 except ImportError:
-    sys.path.append(os.path.abspath(__file__+"/.."))
+    sys.path.append(os.path.abspath(common.onionshare_gui_dir+"/.."))
     import onionshare
 from onionshare import strings, helpers, web
 
+from file_selection import FileSelection
+
 class Application(QtGui.QApplication):
     def __init__(self):
         platform = helpers.get_platform()
@@ -24,10 +21,28 @@ class Application(QtGui.QApplication):
         QtGui.QApplication.__init__(self, sys.argv)
 
 class OnionShareGui(QtGui.QWidget):
-    def __init__(self, app, filename, basename):
+    def __init__(self, app, filenames=None):
         super(OnionShareGui, self).__init__()
         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
         self.init_ui(filename, basename)
         # check for requests every 1000ms
@@ -64,7 +79,7 @@ class OnionShareGui(QtGui.QWidget):
 
         # logo
         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.header.addWidget(self.logoLabel)
 
@@ -268,6 +283,7 @@ class OnionShareGui(QtGui.QWidget):
         else:
             web.set_stay_open(True)
         return
+"""
 
 def alert(msg, icon=QtGui.QMessageBox.NoIcon):
     dialog = QtGui.QMessageBox()
@@ -277,24 +293,6 @@ def alert(msg, icon=QtGui.QMessageBox.NoIcon):
     dialog.setIcon(icon)
     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():
     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('--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('filename', nargs='?', help=strings._("help_filename"))
+    parser.add_argument('--filenames', metavar='filenames', nargs='+', help=strings._('help_filename'))
     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)
     stay_open = bool(args.stay_open)
     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
     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
-    try:
-        app = onionshare.OnionShare(debug, local_only, stay_open)
+    web.set_stay_open(stay_open)
+    app = onionshare.OnionShare(debug, local_only, stay_open)
+
+    """try:
         app.start_hidden_service(gui=True)
     except onionshare.NoTor as e:
         alert(e.args[0], QtGui.QMessageBox.Warning)
@@ -331,11 +343,7 @@ def main():
     except onionshare.TailsError as e:
         alert(e.args[0], QtGui.QMessageBox.Warning)
         sys.exit()
-
-    # select file to share
-    filename, basename = select_file(filename)
-    if not filename:
-        return
+    """
 
     # clean up when app quits
     def shutdown():
@@ -343,7 +351,8 @@ def main():
     qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown)
 
     # launch the gui
-    gui = OnionShareGui(app, filename, basename)
+    gui = OnionShareGui(app, filenames)
+    gui.start_send()
 
     # all done
     sys.exit(qtapp.exec_())
diff --git a/setup/onionshare-osx.spec b/setup/onionshare-osx.spec
index d0ee763..8ba11b7 100644
--- a/setup/onionshare-osx.spec
+++ b/setup/onionshare-osx.spec
@@ -9,6 +9,7 @@ a.datas += [
     ('onionshare/index.html', 'onionshare/index.html', 'DATA'),
     ('onionshare/404.html', 'onionshare/404.html', '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)
 exe = EXE(pyz,
diff --git a/setup/onionshare.nsi b/setup/onionshare.nsi
index 842ac80..ceab6a4 100644
--- a/setup/onionshare.nsi
+++ b/setup/onionshare.nsi
@@ -59,6 +59,7 @@ Section "install"
     File "${BINPATH}\onionshare_gui\__init__.py"
     File "${BINPATH}\onionshare_gui\__init__.pyc"
     File "${BINPATH}\onionshare_gui\logo.png"
+    File "${BINPATH}\onionshare_gui\drop_files.png"
 
     # dependencies
     SetOutPath $INSTDIR
@@ -162,6 +163,7 @@ Section "uninstall"
     Delete "$INSTDIR\onionshare_gui\__init__.py"
     Delete "$INSTDIR\onionshare_gui\__init__.pyc"
     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.pyc"
     Delete "$INSTDIR\qt4_plugins\accessible\qtaccessiblewidgets4.dll"

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/collab-maint/onionshare.git



More information about the Pkg-anonymity-tools mailing list