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
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/>.
"""
import os, sys, inspect, platform
from onionshare import helpers

View file

@ -19,11 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
import time
from PyQt4 import QtCore, QtGui
from PyQt5 import QtCore, QtWidgets
import common
from onionshare import strings, helpers
from . import common
class Download(object):
@ -34,7 +34,7 @@ class Download(object):
self.downloaded_bytes = 0
# make a new progress bar
self.progress_bar = QtGui.QProgressBar()
self.progress_bar = QtWidgets.QProgressBar()
self.progress_bar.setTextVisible(True)
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
self.progress_bar.setMinimum(0)
@ -79,7 +79,7 @@ class Download(object):
self.started)
class Downloads(QtGui.QVBoxLayout):
class Downloads(QtWidgets.QVBoxLayout):
"""
The downloads chunk of the GUI. This lists all of the active download
progress bars.
@ -90,7 +90,7 @@ class Downloads(QtGui.QVBoxLayout):
self.downloads = {}
# downloads label
self.downloads_label = QtGui.QLabel(strings._('gui_downloads', True))
self.downloads_label = QtWidgets.QLabel(strings._('gui_downloads', True))
self.downloads_label.hide()
# 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/>.
"""
import os
from PyQt4 import QtCore, QtGui
from PyQt5 import QtCore, QtWidgets, QtGui
import common
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.
"""
@ -37,7 +37,7 @@ class FileList(QtGui.QListWidget):
self.setIconSize(QtCore.QSize(32, 32))
self.setSortingEnabled(True)
class DropHereLabel(QtGui.QLabel):
class DropHereLabel(QtWidgets.QLabel):
"""
When there are no files or folders in the FileList yet, display the
'drop files here' message and graphic.
@ -51,7 +51,7 @@ class FileList(QtGui.QListWidget):
if image:
self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(common.get_image_path('drop_files.png'))))
else:
self.setText(QtCore.QString(strings._('gui_drag_and_drop', True)))
self.setText(strings._('gui_drag_and_drop', True))
self.setStyleSheet('color: #999999;')
self.hide()
@ -131,23 +131,20 @@ class FileList(QtGui.QListWidget):
Add a file or directory to this widget.
"""
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)
fileinfo = QtCore.QFileInfo(filename)
basename = os.path.basename(filename.rstrip('/'))
ip = QtGui.QFileIconProvider()
ip = QtWidgets.QFileIconProvider()
icon = ip.icon(fileinfo)
if os.path.isfile(filename):
size = helpers.human_readable_filesize(fileinfo.size())
else:
size = helpers.human_readable_filesize(helpers.dir_size(filename))
item_name = unicode('{0:s} ({1:s})'.format(basename, size))
item = QtGui.QListWidgetItem(item_name)
item.setToolTip(QtCore.QString(size))
item_name = '{0:s} ({1:s})'.format(basename, size)
item = QtWidgets.QListWidgetItem(item_name)
item.setToolTip(size)
item.setIcon(icon)
self.addItem(item)
@ -155,7 +152,7 @@ class FileList(QtGui.QListWidget):
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
delete the files and folders.
@ -170,13 +167,13 @@ class FileSelection(QtGui.QVBoxLayout):
self.file_list.files_dropped.connect(self.update)
# 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_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.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)
button_layout = QtGui.QHBoxLayout()
button_layout = QtWidgets.QHBoxLayout()
button_layout.addWidget(self.add_files_button)
button_layout.addWidget(self.add_dir_button)
button_layout.addWidget(self.delete_button)
@ -214,19 +211,19 @@ class FileSelection(QtGui.QVBoxLayout):
"""
Add files button clicked.
"""
filenames = QtGui.QFileDialog.getOpenFileNames(
caption=strings._('gui_choose_files', True), options=QtGui.QFileDialog.ReadOnly)
filenames = QtWidgets.QFileDialog.getOpenFileNames(
caption=strings._('gui_choose_files', True), options=QtWidgets.QFileDialog.ReadOnly)
if filenames:
for filename in filenames:
self.file_list.add_file(str(filename))
for filename in filenames[0]:
self.file_list.add_file(filename)
self.update()
def add_dir(self):
"""
Add folder button clicked.
"""
filename = QtGui.QFileDialog.getExistingDirectory(
caption=strings._('gui_choose_folder', True), options=QtGui.QFileDialog.ReadOnly)
filename = QtWidgets.QFileDialog.getExistingDirectory(
caption=strings._('gui_choose_folder', True), options=QtWidgets.QFileDialog.ReadOnly)
if filename:
self.file_list.add_file(str(filename))
self.update()

View file

@ -19,9 +19,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
from __future__ import division
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:
import onionshare
@ -30,13 +30,13 @@ except ImportError:
import onionshare
from onionshare import strings, helpers, web
from file_selection import FileSelection
from server_status import ServerStatus
from downloads import Downloads
from options import Options
from .file_selection import FileSelection
from .server_status import ServerStatus
from .downloads import Downloads
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
and the quick keyboard shortcut.
@ -45,7 +45,7 @@ class Application(QtGui.QApplication):
platform = helpers.get_platform()
if platform == 'Linux':
self.setAttribute(QtCore.Qt.AA_X11InitThreads, True)
QtGui.QApplication.__init__(self, sys.argv)
QtWidgets.QApplication.__init__(self, sys.argv)
self.installEventFilter(self)
def eventFilter(self, obj, event):
@ -56,7 +56,7 @@ class Application(QtGui.QApplication):
return False
class OnionShareGui(QtGui.QWidget):
class OnionShareGui(QtWidgets.QWidget):
"""
OnionShareGui is the main window for the GUI that contains all of the
GUI elements.
@ -98,7 +98,7 @@ class OnionShareGui(QtGui.QWidget):
self.starting_server_step2.connect(self.start_server_step2)
# 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.hide()
@ -109,14 +109,14 @@ class OnionShareGui(QtGui.QWidget):
self.options = Options(web, self.app)
# status bar
self.status_bar = QtGui.QStatusBar()
self.status_bar = QtWidgets.QStatusBar()
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;')
self.status_bar.addPermanentWidget(version_label)
# main layout
self.layout = QtGui.QVBoxLayout()
self.layout = QtWidgets.QVBoxLayout()
self.layout.addLayout(self.file_selection)
self.layout.addLayout(self.server_status)
self.layout.addWidget(self.filesize_warning)
@ -128,7 +128,7 @@ class OnionShareGui(QtGui.QWidget):
# check for requests frequently
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)
def start_server_step2(self):
@ -152,7 +152,7 @@ class OnionShareGui(QtGui.QWidget):
try:
self.app.start_hidden_service(gui=True)
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.status_bar.clearMessage()
return
@ -208,7 +208,7 @@ class OnionShareGui(QtGui.QWidget):
try:
r = web.q.get(False)
events.append(r)
except web.Queue.Empty:
except web.queue.Empty:
done = True
for event in events:
@ -246,11 +246,11 @@ class OnionShareGui(QtGui.QWidget):
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.
"""
dialog = QtGui.QMessageBox()
dialog = QtWidgets.QMessageBox()
dialog.setWindowTitle("OnionShare")
dialog.setWindowIcon(window_icon)
dialog.setText(msg)
@ -263,7 +263,7 @@ def main():
The main() function implements all of the logic that the GUI version of onionshare uses.
"""
strings.load_strings()
print strings._('version_string').format(helpers.get_version())
print(strings._('version_string').format(helpers.get_version()))
# start the Qt app
global qtapp
@ -310,7 +310,7 @@ def main():
# clean up when app quits
def shutdown():
app.cleanup()
qtapp.connect(qtapp, QtCore.SIGNAL("aboutToQuit()"), shutdown)
qtapp.aboutToQuit.connect(shutdown)
# launch the gui
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
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 . import common
class Options(QtGui.QHBoxLayout):
class Options(QtWidgets.QHBoxLayout):
"""
The extra onionshare options in the GUI.
"""
@ -34,13 +34,13 @@ class Options(QtGui.QHBoxLayout):
self.app = app
# close automatically
self.close_automatically = QtGui.QCheckBox()
self.close_automatically = QtWidgets.QCheckBox()
if self.web.stay_open:
self.close_automatically.setCheckState(QtCore.Qt.Unchecked)
else:
self.close_automatically.setCheckState(QtCore.Qt.Checked)
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
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/>.
"""
import platform
from PyQt4 import QtCore, QtGui
from PyQt5 import QtCore, QtWidgets, QtGui
import common
from onionshare import strings, helpers
from . import common
class ServerStatus(QtGui.QVBoxLayout):
class ServerStatus(QtWidgets.QVBoxLayout):
"""
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_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_label = QtGui.QLabel()
self.status_image_label = QtWidgets.QLabel()
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)
server_layout = QtGui.QHBoxLayout()
server_layout = QtWidgets.QHBoxLayout()
server_layout.addWidget(self.status_image_label)
server_layout.addWidget(self.server_button)
# url layout
url_font = QtGui.QFont()
self.url_label = QtGui.QLabel()
self.url_label = QtWidgets.QLabel()
self.url_label.setFont(url_font)
self.url_label.setWordWrap(True)
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)
url_layout = QtGui.QHBoxLayout()
url_layout = QtWidgets.QHBoxLayout()
url_layout.addWidget(self.url_label)
url_layout.addWidget(self.copy_url_button)

View file

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