Porting onionshare GUI from python2 to python3, and also from PyQt4 to PyQt5 (#261). This commit ports onionshare_gui.

This commit is contained in:
Micah Lee 2016-02-12 15:12:27 -08:00
parent 170811f450
commit 62c69c4c0b
8 changed files with 63 additions and 67 deletions

View File

@ -17,4 +17,4 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
from onionshare_gui import * from .onionshare_gui import *

View File

@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import os, sys, inspect, platform import os, sys, inspect, platform
from onionshare import helpers from onionshare import helpers

View File

@ -19,11 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import time import time
from PyQt4 import QtCore, QtGui from PyQt5 import QtCore, QtWidgets
import common
from onionshare import strings, helpers from onionshare import strings, helpers
from . import common
class Download(object): class Download(object):
@ -34,7 +34,7 @@ class Download(object):
self.downloaded_bytes = 0 self.downloaded_bytes = 0
# make a new progress bar # make a new progress bar
self.progress_bar = QtGui.QProgressBar() self.progress_bar = QtWidgets.QProgressBar()
self.progress_bar.setTextVisible(True) self.progress_bar.setTextVisible(True)
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter) self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
self.progress_bar.setMinimum(0) self.progress_bar.setMinimum(0)
@ -79,7 +79,7 @@ class Download(object):
self.started) self.started)
class Downloads(QtGui.QVBoxLayout): class Downloads(QtWidgets.QVBoxLayout):
""" """
The downloads chunk of the GUI. This lists all of the active download The downloads chunk of the GUI. This lists all of the active download
progress bars. progress bars.
@ -90,7 +90,7 @@ class Downloads(QtGui.QVBoxLayout):
self.downloads = {} self.downloads = {}
# downloads label # downloads label
self.downloads_label = QtGui.QLabel(strings._('gui_downloads', True)) self.downloads_label = QtWidgets.QLabel(strings._('gui_downloads', True))
self.downloads_label.hide() self.downloads_label.hide()
# add the widgets # add the widgets

View File

@ -18,13 +18,13 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import os import os
from PyQt4 import QtCore, QtGui from PyQt5 import QtCore, QtWidgets, QtGui
import common
from onionshare import strings, helpers from onionshare import strings, helpers
from . import common
class FileList(QtGui.QListWidget): class FileList(QtWidgets.QListWidget):
""" """
The list of files and folders in the GUI. The list of files and folders in the GUI.
""" """
@ -37,7 +37,7 @@ class FileList(QtGui.QListWidget):
self.setIconSize(QtCore.QSize(32, 32)) self.setIconSize(QtCore.QSize(32, 32))
self.setSortingEnabled(True) self.setSortingEnabled(True)
class DropHereLabel(QtGui.QLabel): class DropHereLabel(QtWidgets.QLabel):
""" """
When there are no files or folders in the FileList yet, display the When there are no files or folders in the FileList yet, display the
'drop files here' message and graphic. 'drop files here' message and graphic.
@ -51,7 +51,7 @@ class FileList(QtGui.QListWidget):
if image: if image:
self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(common.get_image_path('drop_files.png')))) self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(common.get_image_path('drop_files.png'))))
else: else:
self.setText(QtCore.QString(strings._('gui_drag_and_drop', True))) self.setText(strings._('gui_drag_and_drop', True))
self.setStyleSheet('color: #999999;') self.setStyleSheet('color: #999999;')
self.hide() self.hide()
@ -131,23 +131,20 @@ class FileList(QtGui.QListWidget):
Add a file or directory to this widget. Add a file or directory to this widget.
""" """
if filename not in self.filenames: if filename not in self.filenames:
# make filenames unicode-safe for Qt (#141)
filename = filename.encode('utf-8').decode('utf-8', 'replace')
self.filenames.append(filename) self.filenames.append(filename)
fileinfo = QtCore.QFileInfo(filename) fileinfo = QtCore.QFileInfo(filename)
basename = os.path.basename(filename.rstrip('/')) basename = os.path.basename(filename.rstrip('/'))
ip = QtGui.QFileIconProvider() ip = QtWidgets.QFileIconProvider()
icon = ip.icon(fileinfo) icon = ip.icon(fileinfo)
if os.path.isfile(filename): if os.path.isfile(filename):
size = helpers.human_readable_filesize(fileinfo.size()) size = helpers.human_readable_filesize(fileinfo.size())
else: else:
size = helpers.human_readable_filesize(helpers.dir_size(filename)) size = helpers.human_readable_filesize(helpers.dir_size(filename))
item_name = unicode('{0:s} ({1:s})'.format(basename, size)) item_name = '{0:s} ({1:s})'.format(basename, size)
item = QtGui.QListWidgetItem(item_name) item = QtWidgets.QListWidgetItem(item_name)
item.setToolTip(QtCore.QString(size)) item.setToolTip(size)
item.setIcon(icon) item.setIcon(icon)
self.addItem(item) self.addItem(item)
@ -155,7 +152,7 @@ class FileList(QtGui.QListWidget):
self.files_updated.emit() self.files_updated.emit()
class FileSelection(QtGui.QVBoxLayout): class FileSelection(QtWidgets.QVBoxLayout):
""" """
The list of files and folders in the GUI, as well as buttons to add and The list of files and folders in the GUI, as well as buttons to add and
delete the files and folders. delete the files and folders.
@ -170,13 +167,13 @@ class FileSelection(QtGui.QVBoxLayout):
self.file_list.files_dropped.connect(self.update) self.file_list.files_dropped.connect(self.update)
# buttons # buttons
self.add_files_button = QtGui.QPushButton(strings._('gui_add_files', True)) self.add_files_button = QtWidgets.QPushButton(strings._('gui_add_files', True))
self.add_files_button.clicked.connect(self.add_files) self.add_files_button.clicked.connect(self.add_files)
self.add_dir_button = QtGui.QPushButton(strings._('gui_add_folder', True)) self.add_dir_button = QtWidgets.QPushButton(strings._('gui_add_folder', True))
self.add_dir_button.clicked.connect(self.add_dir) self.add_dir_button.clicked.connect(self.add_dir)
self.delete_button = QtGui.QPushButton(strings._('gui_delete', True)) self.delete_button = QtWidgets.QPushButton(strings._('gui_delete', True))
self.delete_button.clicked.connect(self.delete_file) self.delete_button.clicked.connect(self.delete_file)
button_layout = QtGui.QHBoxLayout() button_layout = QtWidgets.QHBoxLayout()
button_layout.addWidget(self.add_files_button) button_layout.addWidget(self.add_files_button)
button_layout.addWidget(self.add_dir_button) button_layout.addWidget(self.add_dir_button)
button_layout.addWidget(self.delete_button) button_layout.addWidget(self.delete_button)
@ -214,19 +211,19 @@ class FileSelection(QtGui.QVBoxLayout):
""" """
Add files button clicked. Add files button clicked.
""" """
filenames = QtGui.QFileDialog.getOpenFileNames( filenames = QtWidgets.QFileDialog.getOpenFileNames(
caption=strings._('gui_choose_files', True), options=QtGui.QFileDialog.ReadOnly) caption=strings._('gui_choose_files', True), options=QtWidgets.QFileDialog.ReadOnly)
if filenames: if filenames:
for filename in filenames: for filename in filenames[0]:
self.file_list.add_file(str(filename)) self.file_list.add_file(filename)
self.update() self.update()
def add_dir(self): def add_dir(self):
""" """
Add folder button clicked. Add folder button clicked.
""" """
filename = QtGui.QFileDialog.getExistingDirectory( filename = QtWidgets.QFileDialog.getExistingDirectory(
caption=strings._('gui_choose_folder', True), options=QtGui.QFileDialog.ReadOnly) caption=strings._('gui_choose_folder', True), options=QtWidgets.QFileDialog.ReadOnly)
if filename: if filename:
self.file_list.add_file(str(filename)) self.file_list.add_file(str(filename))
self.update() self.update()

View File

@ -19,9 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
from __future__ import division 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 PyQt5 import QtCore, QtWidgets, QtGui
import common from . import common
try: try:
import onionshare import onionshare
@ -30,13 +30,13 @@ except ImportError:
import onionshare import onionshare
from onionshare import strings, helpers, web from onionshare import strings, helpers, web
from file_selection import FileSelection from .file_selection import FileSelection
from server_status import ServerStatus from .server_status import ServerStatus
from downloads import Downloads from .downloads import Downloads
from options import Options from .options import Options
class Application(QtGui.QApplication): class Application(QtWidgets.QApplication):
""" """
This is Qt's QApplication class. It has been overridden to support threads This is Qt's QApplication class. It has been overridden to support threads
and the quick keyboard shortcut. and the quick keyboard shortcut.
@ -45,7 +45,7 @@ class Application(QtGui.QApplication):
platform = helpers.get_platform() platform = helpers.get_platform()
if platform == 'Linux': if platform == 'Linux':
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True) self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
QtGui.QApplication.__init__(self, sys.argv) QtWidgets.QApplication.__init__(self, sys.argv)
self.installEventFilter(self) self.installEventFilter(self)
def eventFilter(self, obj, event): def eventFilter(self, obj, event):
@ -56,7 +56,7 @@ class Application(QtGui.QApplication):
return False return False
class OnionShareGui(QtGui.QWidget): class OnionShareGui(QtWidgets.QWidget):
""" """
OnionShareGui is the main window for the GUI that contains all of the OnionShareGui is the main window for the GUI that contains all of the
GUI elements. GUI elements.
@ -98,7 +98,7 @@ class OnionShareGui(QtGui.QWidget):
self.starting_server_step2.connect(self.start_server_step2) self.starting_server_step2.connect(self.start_server_step2)
# filesize warning # filesize warning
self.filesize_warning = QtGui.QLabel() self.filesize_warning = QtWidgets.QLabel()
self.filesize_warning.setStyleSheet('padding: 10px 0; font-weight: bold; color: #333333;') self.filesize_warning.setStyleSheet('padding: 10px 0; font-weight: bold; color: #333333;')
self.filesize_warning.hide() self.filesize_warning.hide()
@ -109,14 +109,14 @@ class OnionShareGui(QtGui.QWidget):
self.options = Options(web, self.app) self.options = Options(web, self.app)
# status bar # status bar
self.status_bar = QtGui.QStatusBar() self.status_bar = QtWidgets.QStatusBar()
self.status_bar.setSizeGripEnabled(False) self.status_bar.setSizeGripEnabled(False)
version_label = QtGui.QLabel('v{0:s}'.format(helpers.get_version())) version_label = QtWidgets.QLabel('v{0:s}'.format(helpers.get_version()))
version_label.setStyleSheet('color: #666666;') version_label.setStyleSheet('color: #666666;')
self.status_bar.addPermanentWidget(version_label) self.status_bar.addPermanentWidget(version_label)
# main layout # main layout
self.layout = QtGui.QVBoxLayout() self.layout = QtWidgets.QVBoxLayout()
self.layout.addLayout(self.file_selection) self.layout.addLayout(self.file_selection)
self.layout.addLayout(self.server_status) self.layout.addLayout(self.server_status)
self.layout.addWidget(self.filesize_warning) self.layout.addWidget(self.filesize_warning)
@ -128,7 +128,7 @@ class OnionShareGui(QtGui.QWidget):
# check for requests frequently # check for requests frequently
self.timer = QtCore.QTimer() self.timer = QtCore.QTimer()
QtCore.QObject.connect(self.timer, QtCore.SIGNAL("timeout()"), self.check_for_requests) self.timer.timeout.connect(self.check_for_requests)
self.timer.start(500) self.timer.start(500)
def start_server_step2(self): def start_server_step2(self):
@ -152,7 +152,7 @@ class OnionShareGui(QtGui.QWidget):
try: try:
self.app.start_hidden_service(gui=True) self.app.start_hidden_service(gui=True)
except onionshare.hs.NoTor as e: except onionshare.hs.NoTor as e:
alert(e.args[0], QtGui.QMessageBox.Warning) alert(e.args[0], QtWidgets.QMessageBox.Warning)
self.server_status.stop_server() self.server_status.stop_server()
self.status_bar.clearMessage() self.status_bar.clearMessage()
return return
@ -208,7 +208,7 @@ class OnionShareGui(QtGui.QWidget):
try: try:
r = web.q.get(False) r = web.q.get(False)
events.append(r) events.append(r)
except web.Queue.Empty: except web.queue.Empty:
done = True done = True
for event in events: for event in events:
@ -246,11 +246,11 @@ class OnionShareGui(QtGui.QWidget):
self.status_bar.clearMessage() self.status_bar.clearMessage()
def alert(msg, icon=QtGui.QMessageBox.NoIcon): def alert(msg, icon=QtWidgets.QMessageBox.NoIcon):
""" """
Pop up a message in a dialog window. Pop up a message in a dialog window.
""" """
dialog = QtGui.QMessageBox() dialog = QtWidgets.QMessageBox()
dialog.setWindowTitle("OnionShare") dialog.setWindowTitle("OnionShare")
dialog.setWindowIcon(window_icon) dialog.setWindowIcon(window_icon)
dialog.setText(msg) dialog.setText(msg)
@ -263,7 +263,7 @@ def main():
The main() function implements all of the logic that the GUI version of onionshare uses. The main() function implements all of the logic that the GUI version of onionshare uses.
""" """
strings.load_strings() strings.load_strings()
print strings._('version_string').format(helpers.get_version()) print(strings._('version_string').format(helpers.get_version()))
# start the Qt app # start the Qt app
global qtapp global qtapp
@ -310,7 +310,7 @@ def main():
# clean up when app quits # clean up when app quits
def shutdown(): def shutdown():
app.cleanup() app.cleanup()
qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown) qtapp.aboutToQuit.connect(shutdown)
# launch the gui # launch the gui
gui = OnionShareGui(qtapp, app) gui = OnionShareGui(qtapp, app)

View File

@ -17,13 +17,13 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
from PyQt4 import QtCore, QtGui from PyQt5 import QtCore, QtWidgets
import common
from onionshare import strings, helpers from onionshare import strings, helpers
from . import common
class Options(QtGui.QHBoxLayout): class Options(QtWidgets.QHBoxLayout):
""" """
The extra onionshare options in the GUI. The extra onionshare options in the GUI.
""" """
@ -34,13 +34,13 @@ class Options(QtGui.QHBoxLayout):
self.app = app self.app = app
# close automatically # close automatically
self.close_automatically = QtGui.QCheckBox() self.close_automatically = QtWidgets.QCheckBox()
if self.web.stay_open: if self.web.stay_open:
self.close_automatically.setCheckState(QtCore.Qt.Unchecked) self.close_automatically.setCheckState(QtCore.Qt.Unchecked)
else: else:
self.close_automatically.setCheckState(QtCore.Qt.Checked) self.close_automatically.setCheckState(QtCore.Qt.Checked)
self.close_automatically.setText(strings._("close_on_finish", True)) self.close_automatically.setText(strings._("close_on_finish", True))
self.connect(self.close_automatically, QtCore.SIGNAL('stateChanged(int)'), self.stay_open_changed) self.close_automatically.stateChanged.connect(self.stay_open_changed)
# add the widgets # add the widgets
self.addWidget(self.close_automatically) self.addWidget(self.close_automatically)

View File

@ -18,13 +18,13 @@ You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
""" """
import platform import platform
from PyQt4 import QtCore, QtGui from PyQt5 import QtCore, QtWidgets, QtGui
import common
from onionshare import strings, helpers from onionshare import strings, helpers
from . import common
class ServerStatus(QtGui.QVBoxLayout): class ServerStatus(QtWidgets.QVBoxLayout):
""" """
The server status chunk of the GUI. The server status chunk of the GUI.
""" """
@ -49,23 +49,23 @@ class ServerStatus(QtGui.QVBoxLayout):
self.status_image_stopped = QtGui.QImage(common.get_image_path('server_stopped.png')) self.status_image_stopped = QtGui.QImage(common.get_image_path('server_stopped.png'))
self.status_image_working = QtGui.QImage(common.get_image_path('server_working.png')) self.status_image_working = QtGui.QImage(common.get_image_path('server_working.png'))
self.status_image_started = QtGui.QImage(common.get_image_path('server_started.png')) self.status_image_started = QtGui.QImage(common.get_image_path('server_started.png'))
self.status_image_label = QtGui.QLabel() self.status_image_label = QtWidgets.QLabel()
self.status_image_label.setFixedWidth(30) self.status_image_label.setFixedWidth(30)
self.server_button = QtGui.QPushButton() self.server_button = QtWidgets.QPushButton()
self.server_button.clicked.connect(self.server_button_clicked) self.server_button.clicked.connect(self.server_button_clicked)
server_layout = QtGui.QHBoxLayout() server_layout = QtWidgets.QHBoxLayout()
server_layout.addWidget(self.status_image_label) server_layout.addWidget(self.status_image_label)
server_layout.addWidget(self.server_button) server_layout.addWidget(self.server_button)
# url layout # url layout
url_font = QtGui.QFont() url_font = QtGui.QFont()
self.url_label = QtGui.QLabel() self.url_label = QtWidgets.QLabel()
self.url_label.setFont(url_font) self.url_label.setFont(url_font)
self.url_label.setWordWrap(True) self.url_label.setWordWrap(True)
self.url_label.setAlignment(QtCore.Qt.AlignCenter) self.url_label.setAlignment(QtCore.Qt.AlignCenter)
self.copy_url_button = QtGui.QPushButton(strings._('gui_copy_url', True)) self.copy_url_button = QtWidgets.QPushButton(strings._('gui_copy_url', True))
self.copy_url_button.clicked.connect(self.copy_url) self.copy_url_button.clicked.connect(self.copy_url)
url_layout = QtGui.QHBoxLayout() url_layout = QtWidgets.QHBoxLayout()
url_layout.addWidget(self.url_label) url_layout.addWidget(self.url_label)
url_layout.addWidget(self.copy_url_button) url_layout.addWidget(self.copy_url_button)

View File

@ -83,11 +83,9 @@ if system == 'Linux':
url='https://github.com/micahflee/onionshare', url='https://github.com/micahflee/onionshare',
license="GPL v3", license="GPL v3",
keywords='onion, share, onionshare, tor, anonymous, web server', keywords='onion, share, onionshare, tor, anonymous, web server',
#packages=['onionshare', 'onionshare_gui'], packages=['onionshare', 'onionshare_gui'],
packages=['onionshare'],
include_package_data=True, include_package_data=True,
#scripts=['install/linux_scripts/onionshare', 'install/linux_scripts/onionshare-gui'], scripts=['install/linux_scripts/onionshare', 'install/linux_scripts/onionshare-gui'],
scripts=['install/linux_scripts/onionshare'],
data_files=[ data_files=[
(os.path.join(sys.prefix, 'share/applications'), ['install/onionshare.desktop']), (os.path.join(sys.prefix, 'share/applications'), ['install/onionshare.desktop']),
(os.path.join(sys.prefix, 'share/appdata'), ['install/onionshare.appdata.xml']), (os.path.join(sys.prefix, 'share/appdata'), ['install/onionshare.appdata.xml']),