mirror of
https://github.com/onionshare/onionshare.git
synced 2025-01-13 16:29:31 -05:00
Merge pull request #800 from micahflee/690_language_dropdown
Add language dropdown
This commit is contained in:
commit
48654895ea
@ -33,7 +33,15 @@ def main(cwd=None):
|
||||
"""
|
||||
common = Common()
|
||||
|
||||
# Load the default settings and strings early, for the sake of being able to parse options.
|
||||
# These won't be in the user's chosen locale necessarily, but we need to parse them
|
||||
# early in order to even display the option to pass alternate settings (which might
|
||||
# contain a preferred locale).
|
||||
# If an alternate --config is passed, we'll reload strings later.
|
||||
common.load_settings()
|
||||
strings.load_strings(common)
|
||||
|
||||
# Display OnionShare banner
|
||||
print(strings._('version_string').format(common.version))
|
||||
|
||||
# OnionShare CLI in OSX needs to change current working directory (#132)
|
||||
@ -88,8 +96,11 @@ def main(cwd=None):
|
||||
if not valid:
|
||||
sys.exit()
|
||||
|
||||
# Load settings
|
||||
common.load_settings(config)
|
||||
# Re-load settings, if a custom config was passed in
|
||||
if config:
|
||||
common.load_settings(config)
|
||||
# Re-load the strings, in case the provided config has changed locale
|
||||
strings.load_strings(common)
|
||||
|
||||
# Debug mode?
|
||||
common.debug = debug
|
||||
|
@ -247,7 +247,7 @@ class Onion(object):
|
||||
self.c = Controller.from_socket_file(path=self.tor_control_socket)
|
||||
self.c.authenticate()
|
||||
except Exception as e:
|
||||
raise BundledTorBroken(strings._('settings_error_bundled_tor_broken', True).format(e.args[0]))
|
||||
raise BundledTorBroken(strings._('settings_error_bundled_tor_broken').format(e.args[0]))
|
||||
|
||||
while True:
|
||||
try:
|
||||
|
@ -21,6 +21,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import locale
|
||||
|
||||
from . import strings
|
||||
|
||||
@ -47,6 +48,25 @@ class Settings(object):
|
||||
else:
|
||||
self.common.log('Settings', '__init__', 'Supplied config does not exist or is unreadable. Falling back to default location')
|
||||
|
||||
# Dictionary of available languages in this version of OnionShare,
|
||||
# mapped to the language name, in that language
|
||||
self.available_locales = {
|
||||
'cs': 'Hrvatski', # Croatian
|
||||
'da': 'Dansk', # Danish
|
||||
'de': 'Deutsch', # German
|
||||
'en': 'English', # English
|
||||
'eo': 'Esperanto', # Esperanto
|
||||
'es': 'Español', # Spanish
|
||||
'fi': 'Suomi', # Finnish
|
||||
'fr': 'Français', # French
|
||||
'it': 'Italiano', # Italian
|
||||
'nl': 'Nederlands', # Dutch
|
||||
'no': 'Norsk', # Norweigan
|
||||
'pt': 'Português', # Portuguese
|
||||
'ru': 'Русский', # Russian
|
||||
'tr': 'Türkçe' # Turkish
|
||||
}
|
||||
|
||||
# These are the default settings. They will get overwritten when loading from disk
|
||||
self.default_settings = {
|
||||
'version': self.common.version,
|
||||
@ -74,7 +94,8 @@ class Settings(object):
|
||||
'slug': '',
|
||||
'hidservauth_string': '',
|
||||
'downloads_dir': self.build_default_downloads_dir(),
|
||||
'receive_allow_receiver_shutdown': True
|
||||
'receive_allow_receiver_shutdown': True,
|
||||
'locale': None # this gets defined in fill_in_defaults()
|
||||
}
|
||||
self._settings = {}
|
||||
self.fill_in_defaults()
|
||||
@ -88,14 +109,26 @@ class Settings(object):
|
||||
if key not in self._settings:
|
||||
self._settings[key] = self.default_settings[key]
|
||||
|
||||
# Choose the default locale based on the OS preference, and fall-back to English
|
||||
if self._settings['locale'] is None:
|
||||
default_locale = locale.getdefaultlocale()[0][:2]
|
||||
if default_locale not in self.available_locales:
|
||||
default_locale = 'en'
|
||||
self._settings['locale'] = default_locale
|
||||
|
||||
def build_filename(self):
|
||||
"""
|
||||
Returns the path of the settings file.
|
||||
"""
|
||||
p = platform.system()
|
||||
if p == 'Windows':
|
||||
appdata = os.environ['APPDATA']
|
||||
return '{}\\OnionShare\\onionshare.json'.format(appdata)
|
||||
try:
|
||||
appdata = os.environ['APPDATA']
|
||||
return '{}\\OnionShare\\onionshare.json'.format(appdata)
|
||||
except:
|
||||
# If for some reason we don't have the 'APPDATA' environment variable
|
||||
# (like running tests in Linux while pretending to be in Windows)
|
||||
return os.path.expanduser('~/.config/onionshare/onionshare.json')
|
||||
elif p == 'Darwin':
|
||||
return os.path.expanduser('~/Library/Application Support/OnionShare/onionshare.json')
|
||||
else:
|
||||
@ -136,7 +169,7 @@ class Settings(object):
|
||||
except:
|
||||
pass
|
||||
open(self.filename, 'w').write(json.dumps(self._settings))
|
||||
print(strings._('settings_saved').format(self.filename))
|
||||
self.common.log('Settings', 'save', 'Settings saved in {}'.format(self.filename))
|
||||
|
||||
def get(self, key):
|
||||
return self._settings[key]
|
||||
|
@ -22,39 +22,36 @@ import locale
|
||||
import os
|
||||
|
||||
strings = {}
|
||||
translations = {}
|
||||
|
||||
|
||||
def load_strings(common, default="en"):
|
||||
def load_strings(common):
|
||||
"""
|
||||
Loads translated strings and fallback to English
|
||||
if the translation does not exist.
|
||||
"""
|
||||
global strings
|
||||
global strings, translations
|
||||
|
||||
# find locale dir
|
||||
locale_dir = common.get_resource_path('locale')
|
||||
|
||||
# load all translations
|
||||
# Load all translations
|
||||
translations = {}
|
||||
for filename in os.listdir(locale_dir):
|
||||
abs_filename = os.path.join(locale_dir, filename)
|
||||
lang, ext = os.path.splitext(filename)
|
||||
if ext == '.json':
|
||||
with open(abs_filename, encoding='utf-8') as f:
|
||||
translations[lang] = json.load(f)
|
||||
for locale in common.settings.available_locales:
|
||||
locale_dir = common.get_resource_path('locale')
|
||||
filename = os.path.join(locale_dir, "{}.json".format(locale))
|
||||
with open(filename, encoding='utf-8') as f:
|
||||
translations[locale] = json.load(f)
|
||||
|
||||
strings = translations[default]
|
||||
lc, enc = locale.getdefaultlocale()
|
||||
if lc:
|
||||
lang = lc[:2]
|
||||
if lang in translations:
|
||||
# if a string doesn't exist, fallback to English
|
||||
for key in translations[default]:
|
||||
if key in translations[lang]:
|
||||
strings[key] = translations[lang][key]
|
||||
# Build strings
|
||||
default_locale = 'en'
|
||||
current_locale = common.settings.get('locale')
|
||||
strings = {}
|
||||
for s in translations[default_locale]:
|
||||
if s in translations[current_locale]:
|
||||
strings[s] = translations[current_locale][s]
|
||||
else:
|
||||
strings[s] = translations[default_locale][s]
|
||||
|
||||
|
||||
def translated(k, gui=False):
|
||||
def translated(k):
|
||||
"""
|
||||
Returns a translated string.
|
||||
"""
|
||||
|
@ -59,7 +59,15 @@ def main():
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Load the default settings and strings early, for the sake of being able to parse options.
|
||||
# These won't be in the user's chosen locale necessarily, but we need to parse them
|
||||
# early in order to even display the option to pass alternate settings (which might
|
||||
# contain a preferred locale).
|
||||
# If an alternate --config is passed, we'll reload strings later.
|
||||
common.load_settings()
|
||||
strings.load_strings(common)
|
||||
|
||||
# Display OnionShare banner
|
||||
print(strings._('version_string').format(common.version))
|
||||
|
||||
# Allow Ctrl-C to smoothly quit the program instead of throwing an exception
|
||||
@ -84,6 +92,10 @@ def main():
|
||||
filenames[i] = os.path.abspath(filenames[i])
|
||||
|
||||
config = args.config
|
||||
if config:
|
||||
# Re-load the strings, in case the provided config has changed locale
|
||||
common.load_settings(config)
|
||||
strings.load_strings(common)
|
||||
|
||||
local_only = bool(args.local_only)
|
||||
debug = bool(args.debug)
|
||||
@ -96,10 +108,10 @@ def main():
|
||||
valid = True
|
||||
for filename in filenames:
|
||||
if not os.path.isfile(filename) and not os.path.isdir(filename):
|
||||
Alert(common, strings._("not_a_file", True).format(filename))
|
||||
Alert(common, strings._("not_a_file").format(filename))
|
||||
valid = False
|
||||
if not os.access(filename, os.R_OK):
|
||||
Alert(common, strings._("not_a_readable_file", True).format(filename))
|
||||
Alert(common, strings._("not_a_readable_file").format(filename))
|
||||
valid = False
|
||||
if not valid:
|
||||
sys.exit()
|
||||
|
@ -196,7 +196,7 @@ class UploadHistoryItem(HistoryItem):
|
||||
self.started = datetime.now()
|
||||
|
||||
# Label
|
||||
self.label = QtWidgets.QLabel(strings._('gui_upload_in_progress', True).format(self.started.strftime("%b %d, %I:%M%p")))
|
||||
self.label = QtWidgets.QLabel(strings._('gui_upload_in_progress').format(self.started.strftime("%b %d, %I:%M%p")))
|
||||
|
||||
# Progress bar
|
||||
self.progress_bar = QtWidgets.QProgressBar()
|
||||
@ -274,16 +274,16 @@ class UploadHistoryItem(HistoryItem):
|
||||
self.ended = self.started = datetime.now()
|
||||
if self.started.year == self.ended.year and self.started.month == self.ended.month and self.started.day == self.ended.day:
|
||||
if self.started.hour == self.ended.hour and self.started.minute == self.ended.minute:
|
||||
text = strings._('gui_upload_finished', True).format(
|
||||
text = strings._('gui_upload_finished').format(
|
||||
self.started.strftime("%b %d, %I:%M%p")
|
||||
)
|
||||
else:
|
||||
text = strings._('gui_upload_finished_range', True).format(
|
||||
text = strings._('gui_upload_finished_range').format(
|
||||
self.started.strftime("%b %d, %I:%M%p"),
|
||||
self.ended.strftime("%I:%M%p")
|
||||
)
|
||||
else:
|
||||
text = strings._('gui_upload_finished_range', True).format(
|
||||
text = strings._('gui_upload_finished_range').format(
|
||||
self.started.strftime("%b %d, %I:%M%p"),
|
||||
self.ended.strftime("%b %d, %I:%M%p")
|
||||
)
|
||||
@ -380,7 +380,7 @@ class History(QtWidgets.QWidget):
|
||||
# Header
|
||||
self.header_label = QtWidgets.QLabel(header_text)
|
||||
self.header_label.setStyleSheet(self.common.css['downloads_uploads_label'])
|
||||
clear_button = QtWidgets.QPushButton(strings._('gui_clear_history', True))
|
||||
clear_button = QtWidgets.QPushButton(strings._('gui_clear_history'))
|
||||
clear_button.setStyleSheet(self.common.css['downloads_uploads_clear'])
|
||||
clear_button.setFlat(True)
|
||||
clear_button.clicked.connect(self.reset)
|
||||
@ -486,7 +486,7 @@ class History(QtWidgets.QWidget):
|
||||
else:
|
||||
image = self.common.get_resource_path('images/share_in_progress.png')
|
||||
self.in_progress_label.setText('<img src="{0:s}" /> {1:d}'.format(image, self.in_progress_count))
|
||||
self.in_progress_label.setToolTip(strings._('history_in_progress_tooltip', True).format(self.in_progress_count))
|
||||
self.in_progress_label.setToolTip(strings._('history_in_progress_tooltip').format(self.in_progress_count))
|
||||
|
||||
|
||||
class ToggleHistory(QtWidgets.QPushButton):
|
||||
|
@ -63,7 +63,7 @@ class ReceiveMode(Mode):
|
||||
)
|
||||
|
||||
# Receive mode warning
|
||||
receive_warning = QtWidgets.QLabel(strings._('gui_receive_mode_warning', True))
|
||||
receive_warning = QtWidgets.QLabel(strings._('gui_receive_mode_warning'))
|
||||
receive_warning.setMinimumHeight(80)
|
||||
receive_warning.setWordWrap(True)
|
||||
|
||||
@ -90,7 +90,7 @@ class ReceiveMode(Mode):
|
||||
"""
|
||||
Return the string to put on the stop server button, if there's a shutdown timeout
|
||||
"""
|
||||
return strings._('gui_receive_stop_server_shutdown_timeout', True)
|
||||
return strings._('gui_receive_stop_server_shutdown_timeout')
|
||||
|
||||
def timeout_finished_should_stop_server(self):
|
||||
"""
|
||||
@ -128,7 +128,7 @@ class ReceiveMode(Mode):
|
||||
"""
|
||||
Handle REQUEST_LOAD event.
|
||||
"""
|
||||
self.system_tray.showMessage(strings._('systray_page_loaded_title', True), strings._('systray_upload_page_loaded_message', True))
|
||||
self.system_tray.showMessage(strings._('systray_page_loaded_title'), strings._('systray_upload_page_loaded_message'))
|
||||
|
||||
def handle_request_started(self, event):
|
||||
"""
|
||||
@ -140,7 +140,7 @@ class ReceiveMode(Mode):
|
||||
self.history.in_progress_count += 1
|
||||
self.history.update_in_progress()
|
||||
|
||||
self.system_tray.showMessage(strings._('systray_upload_started_title', True), strings._('systray_upload_started_message', True))
|
||||
self.system_tray.showMessage(strings._('systray_upload_started_title'), strings._('systray_upload_started_message'))
|
||||
|
||||
def handle_request_progress(self, event):
|
||||
"""
|
||||
@ -156,7 +156,7 @@ class ReceiveMode(Mode):
|
||||
Handle REQUEST_CLOSE_SERVER event.
|
||||
"""
|
||||
self.stop_server()
|
||||
self.system_tray.showMessage(strings._('systray_close_server_title', True), strings._('systray_close_server_message', True))
|
||||
self.system_tray.showMessage(strings._('systray_close_server_title'), strings._('systray_close_server_message'))
|
||||
|
||||
def handle_request_upload_file_renamed(self, event):
|
||||
"""
|
||||
|
@ -125,7 +125,7 @@ class ShareMode(Mode):
|
||||
"""
|
||||
Return the string to put on the stop server button, if there's a shutdown timeout
|
||||
"""
|
||||
return strings._('gui_share_stop_server_shutdown_timeout', True)
|
||||
return strings._('gui_share_stop_server_shutdown_timeout')
|
||||
|
||||
def timeout_finished_should_stop_server(self):
|
||||
"""
|
||||
@ -134,11 +134,11 @@ class ShareMode(Mode):
|
||||
# If there were no attempts to download the share, or all downloads are done, we can stop
|
||||
if self.web.share_mode.download_count == 0 or self.web.done:
|
||||
self.server_status.stop_server()
|
||||
self.server_status_label.setText(strings._('close_on_timeout', True))
|
||||
self.server_status_label.setText(strings._('close_on_timeout'))
|
||||
return True
|
||||
# A download is probably still running - hold off on stopping the share
|
||||
else:
|
||||
self.server_status_label.setText(strings._('timeout_download_still_running', True))
|
||||
self.server_status_label.setText(strings._('timeout_download_still_running'))
|
||||
return False
|
||||
|
||||
def start_server_custom(self):
|
||||
@ -185,7 +185,7 @@ class ShareMode(Mode):
|
||||
|
||||
# Warn about sending large files over Tor
|
||||
if self.web.share_mode.download_filesize >= 157286400: # 150mb
|
||||
self.filesize_warning.setText(strings._("large_filesize", True))
|
||||
self.filesize_warning.setText(strings._("large_filesize"))
|
||||
self.filesize_warning.show()
|
||||
|
||||
def start_server_error_custom(self):
|
||||
@ -229,7 +229,7 @@ class ShareMode(Mode):
|
||||
"""
|
||||
Handle REQUEST_LOAD event.
|
||||
"""
|
||||
self.system_tray.showMessage(strings._('systray_page_loaded_title', True), strings._('systray_download_page_loaded_message', True))
|
||||
self.system_tray.showMessage(strings._('systray_page_loaded_title'), strings._('systray_download_page_loaded_message'))
|
||||
|
||||
def handle_request_started(self, event):
|
||||
"""
|
||||
@ -246,7 +246,7 @@ class ShareMode(Mode):
|
||||
self.history.in_progress_count += 1
|
||||
self.history.update_in_progress()
|
||||
|
||||
self.system_tray.showMessage(strings._('systray_download_started_title', True), strings._('systray_download_started_message', True))
|
||||
self.system_tray.showMessage(strings._('systray_download_started_title'), strings._('systray_download_started_message'))
|
||||
|
||||
def handle_request_progress(self, event):
|
||||
"""
|
||||
@ -256,7 +256,7 @@ class ShareMode(Mode):
|
||||
|
||||
# Is the download complete?
|
||||
if event["data"]["bytes"] == self.web.share_mode.filesize:
|
||||
self.system_tray.showMessage(strings._('systray_download_completed_title', True), strings._('systray_download_completed_message', True))
|
||||
self.system_tray.showMessage(strings._('systray_download_completed_title'), strings._('systray_download_completed_message'))
|
||||
|
||||
# Update completed and in progress labels
|
||||
self.history.completed_count += 1
|
||||
@ -268,7 +268,7 @@ class ShareMode(Mode):
|
||||
if self.common.settings.get('close_after_first_download'):
|
||||
self.server_status.stop_server()
|
||||
self.status_bar.clearMessage()
|
||||
self.server_status_label.setText(strings._('closing_automatically', True))
|
||||
self.server_status_label.setText(strings._('closing_automatically'))
|
||||
else:
|
||||
if self.server_status.status == self.server_status.STATUS_STOPPED:
|
||||
self.history.cancel(event["data"]["id"])
|
||||
@ -312,9 +312,9 @@ class ShareMode(Mode):
|
||||
total_size_readable = self.common.human_readable_filesize(total_size_bytes)
|
||||
|
||||
if file_count > 1:
|
||||
self.info_label.setText(strings._('gui_file_info', True).format(file_count, total_size_readable))
|
||||
self.info_label.setText(strings._('gui_file_info').format(file_count, total_size_readable))
|
||||
else:
|
||||
self.info_label.setText(strings._('gui_file_info_single', True).format(file_count, total_size_readable))
|
||||
self.info_label.setText(strings._('gui_file_info_single').format(file_count, total_size_readable))
|
||||
|
||||
else:
|
||||
self.primary_action.hide()
|
||||
|
@ -41,7 +41,7 @@ class DropHereLabel(QtWidgets.QLabel):
|
||||
if image:
|
||||
self.setPixmap(QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/logo_transparent.png'))))
|
||||
else:
|
||||
self.setText(strings._('gui_drag_and_drop', True))
|
||||
self.setText(strings._('gui_drag_and_drop'))
|
||||
self.setStyleSheet(self.common.css['share_file_selection_drop_here_label'])
|
||||
|
||||
self.hide()
|
||||
@ -65,7 +65,7 @@ class DropCountLabel(QtWidgets.QLabel):
|
||||
|
||||
self.setAcceptDrops(True)
|
||||
self.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.setText(strings._('gui_drag_and_drop', True))
|
||||
self.setText(strings._('gui_drag_and_drop'))
|
||||
self.setStyleSheet(self.common.css['share_file_selection_drop_count_label'])
|
||||
self.hide()
|
||||
|
||||
@ -216,7 +216,7 @@ class FileList(QtWidgets.QListWidget):
|
||||
|
||||
if filename not in filenames:
|
||||
if not os.access(filename, os.R_OK):
|
||||
Alert(self.common, strings._("not_a_readable_file", True).format(filename))
|
||||
Alert(self.common, strings._("not_a_readable_file").format(filename))
|
||||
return
|
||||
|
||||
fileinfo = QtCore.QFileInfo(filename)
|
||||
@ -302,9 +302,9 @@ class FileSelection(QtWidgets.QVBoxLayout):
|
||||
self.file_list.files_updated.connect(self.update)
|
||||
|
||||
# Buttons
|
||||
self.add_button = QtWidgets.QPushButton(strings._('gui_add', True))
|
||||
self.add_button = QtWidgets.QPushButton(strings._('gui_add'))
|
||||
self.add_button.clicked.connect(self.add)
|
||||
self.delete_button = QtWidgets.QPushButton(strings._('gui_delete', True))
|
||||
self.delete_button = QtWidgets.QPushButton(strings._('gui_delete'))
|
||||
self.delete_button.clicked.connect(self.delete)
|
||||
button_layout = QtWidgets.QHBoxLayout()
|
||||
button_layout.addStretch()
|
||||
@ -341,7 +341,7 @@ class FileSelection(QtWidgets.QVBoxLayout):
|
||||
"""
|
||||
Add button clicked.
|
||||
"""
|
||||
file_dialog = AddFileDialog(self.common, caption=strings._('gui_choose_items', True))
|
||||
file_dialog = AddFileDialog(self.common, caption=strings._('gui_choose_items'))
|
||||
if file_dialog.exec_() == QtWidgets.QDialog.Accepted:
|
||||
for filename in file_dialog.selectedFiles():
|
||||
self.file_list.add_file(filename)
|
||||
|
@ -58,17 +58,18 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
self.setWindowTitle('OnionShare')
|
||||
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||
|
||||
# Load settings
|
||||
# Load settings, if a custom config was passed in
|
||||
self.config = config
|
||||
self.common.load_settings(self.config)
|
||||
if self.config:
|
||||
self.common.load_settings(self.config)
|
||||
|
||||
# System tray
|
||||
menu = QtWidgets.QMenu()
|
||||
self.settings_action = menu.addAction(strings._('gui_settings_window_title', True))
|
||||
self.settings_action = menu.addAction(strings._('gui_settings_window_title'))
|
||||
self.settings_action.triggered.connect(self.open_settings)
|
||||
help_action = menu.addAction(strings._('gui_settings_button_help', True))
|
||||
help_action.triggered.connect(SettingsDialog.open_help)
|
||||
exit_action = menu.addAction(strings._('systray_menu_exit', True))
|
||||
help_action = menu.addAction(strings._('gui_settings_button_help'))
|
||||
help_action.triggered.connect(SettingsDialog.help_clicked)
|
||||
exit_action = menu.addAction(strings._('systray_menu_exit'))
|
||||
exit_action.triggered.connect(self.close)
|
||||
|
||||
self.system_tray = QtWidgets.QSystemTrayIcon(self)
|
||||
@ -81,10 +82,10 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
self.system_tray.show()
|
||||
|
||||
# Mode switcher, to switch between share files and receive files
|
||||
self.share_mode_button = QtWidgets.QPushButton(strings._('gui_mode_share_button', True));
|
||||
self.share_mode_button = QtWidgets.QPushButton(strings._('gui_mode_share_button'));
|
||||
self.share_mode_button.setFixedHeight(50)
|
||||
self.share_mode_button.clicked.connect(self.share_mode_clicked)
|
||||
self.receive_mode_button = QtWidgets.QPushButton(strings._('gui_mode_receive_button', True));
|
||||
self.receive_mode_button = QtWidgets.QPushButton(strings._('gui_mode_receive_button'));
|
||||
self.receive_mode_button.setFixedHeight(50)
|
||||
self.receive_mode_button.clicked.connect(self.receive_mode_clicked)
|
||||
self.settings_button = QtWidgets.QPushButton()
|
||||
@ -224,24 +225,24 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
# Share mode
|
||||
if self.share_mode.server_status.status == ServerStatus.STATUS_STOPPED:
|
||||
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_stopped))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_share_stopped', True))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_share_stopped'))
|
||||
elif self.share_mode.server_status.status == ServerStatus.STATUS_WORKING:
|
||||
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_working))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_share_working', True))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_share_working'))
|
||||
elif self.share_mode.server_status.status == ServerStatus.STATUS_STARTED:
|
||||
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_started))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_share_started', True))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_share_started'))
|
||||
else:
|
||||
# Receive mode
|
||||
if self.receive_mode.server_status.status == ServerStatus.STATUS_STOPPED:
|
||||
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_stopped))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_receive_stopped', True))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_receive_stopped'))
|
||||
elif self.receive_mode.server_status.status == ServerStatus.STATUS_WORKING:
|
||||
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_working))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_receive_working', True))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_receive_working'))
|
||||
elif self.receive_mode.server_status.status == ServerStatus.STATUS_STARTED:
|
||||
self.server_status_image_label.setPixmap(QtGui.QPixmap.fromImage(self.server_status_image_started))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_receive_started', True))
|
||||
self.server_status_label.setText(strings._('gui_status_indicator_receive_started'))
|
||||
|
||||
def stop_server_finished(self):
|
||||
# When the server stopped, cleanup the ephemeral onion service
|
||||
@ -255,9 +256,9 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
self.common.log('OnionShareGui', '_tor_connection_canceled')
|
||||
|
||||
def ask():
|
||||
a = Alert(self.common, strings._('gui_tor_connection_ask', True), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False)
|
||||
settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings', True))
|
||||
quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit', True))
|
||||
a = Alert(self.common, strings._('gui_tor_connection_ask'), QtWidgets.QMessageBox.Question, buttons=QtWidgets.QMessageBox.NoButton, autostart=False)
|
||||
settings_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_open_settings'))
|
||||
quit_button = QtWidgets.QPushButton(strings._('gui_tor_connection_ask_quit'))
|
||||
a.addButton(settings_button, QtWidgets.QMessageBox.AcceptRole)
|
||||
a.addButton(quit_button, QtWidgets.QMessageBox.RejectRole)
|
||||
a.setDefaultButton(settings_button)
|
||||
@ -328,7 +329,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
if self.common.platform == 'Windows' or self.common.platform == 'Darwin':
|
||||
if self.common.settings.get('use_autoupdate'):
|
||||
def update_available(update_url, installed_version, latest_version):
|
||||
Alert(self.common, strings._("update_available", True).format(update_url, installed_version, latest_version))
|
||||
Alert(self.common, strings._("update_available").format(update_url, installed_version, latest_version))
|
||||
|
||||
self.update_thread = UpdateThread(self.common, self.onion, self.config)
|
||||
self.update_thread.update_available.connect(update_available)
|
||||
@ -345,8 +346,8 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
# Have we lost connection to Tor somehow?
|
||||
if not self.onion.is_authenticated():
|
||||
self.timer.stop()
|
||||
self.status_bar.showMessage(strings._('gui_tor_connection_lost', True))
|
||||
self.system_tray.showMessage(strings._('gui_tor_connection_lost', True), strings._('gui_tor_connection_error_settings', True))
|
||||
self.status_bar.showMessage(strings._('gui_tor_connection_lost'))
|
||||
self.system_tray.showMessage(strings._('gui_tor_connection_lost'), strings._('gui_tor_connection_error_settings'))
|
||||
|
||||
self.share_mode.handle_tor_broke()
|
||||
self.receive_mode.handle_tor_broke()
|
||||
@ -400,7 +401,7 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
|
||||
if event["type"] == Web.REQUEST_OTHER:
|
||||
if event["path"] != '/favicon.ico' and event["path"] != "/{}/shutdown".format(mode.web.shutdown_slug):
|
||||
self.status_bar.showMessage('[#{0:d}] {1:s}: {2:s}'.format(mode.web.error404_count, strings._('other_page_loaded', True), event["path"]))
|
||||
self.status_bar.showMessage('[#{0:d}] {1:s}: {2:s}'.format(mode.web.error404_count, strings._('other_page_loaded'), event["path"]))
|
||||
|
||||
mode.timer_callback()
|
||||
|
||||
@ -409,14 +410,14 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
When the URL gets copied to the clipboard, display this in the status bar.
|
||||
"""
|
||||
self.common.log('OnionShareGui', 'copy_url')
|
||||
self.system_tray.showMessage(strings._('gui_copied_url_title', True), strings._('gui_copied_url', True))
|
||||
self.system_tray.showMessage(strings._('gui_copied_url_title'), strings._('gui_copied_url'))
|
||||
|
||||
def copy_hidservauth(self):
|
||||
"""
|
||||
When the stealth onion service HidServAuth gets copied to the clipboard, display this in the status bar.
|
||||
"""
|
||||
self.common.log('OnionShareGui', 'copy_hidservauth')
|
||||
self.system_tray.showMessage(strings._('gui_copied_hidservauth_title', True), strings._('gui_copied_hidservauth', True))
|
||||
self.system_tray.showMessage(strings._('gui_copied_hidservauth_title'), strings._('gui_copied_hidservauth'))
|
||||
|
||||
def clear_message(self):
|
||||
"""
|
||||
@ -454,14 +455,14 @@ class OnionShareGui(QtWidgets.QMainWindow):
|
||||
if server_status.status != server_status.STATUS_STOPPED:
|
||||
self.common.log('OnionShareGui', 'closeEvent, opening warning dialog')
|
||||
dialog = QtWidgets.QMessageBox()
|
||||
dialog.setWindowTitle(strings._('gui_quit_title', True))
|
||||
dialog.setWindowTitle(strings._('gui_quit_title'))
|
||||
if self.mode == OnionShareGui.MODE_SHARE:
|
||||
dialog.setText(strings._('gui_share_quit_warning', True))
|
||||
dialog.setText(strings._('gui_share_quit_warning'))
|
||||
else:
|
||||
dialog.setText(strings._('gui_receive_quit_warning', True))
|
||||
dialog.setText(strings._('gui_receive_quit_warning'))
|
||||
dialog.setIcon(QtWidgets.QMessageBox.Critical)
|
||||
quit_button = dialog.addButton(strings._('gui_quit_warning_quit', True), QtWidgets.QMessageBox.YesRole)
|
||||
dont_quit_button = dialog.addButton(strings._('gui_quit_warning_dont_quit', True), QtWidgets.QMessageBox.NoRole)
|
||||
quit_button = dialog.addButton(strings._('gui_quit_warning_quit'), QtWidgets.QMessageBox.YesRole)
|
||||
dont_quit_button = dialog.addButton(strings._('gui_quit_warning_dont_quit'), QtWidgets.QMessageBox.NoRole)
|
||||
dialog.setDefaultButton(dont_quit_button)
|
||||
reply = dialog.exec_()
|
||||
|
||||
|
320
onionshare_gui/receive_mode/uploads.py
Normal file
320
onionshare_gui/receive_mode/uploads.py
Normal file
@ -0,0 +1,320 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
OnionShare | https://onionshare.org/
|
||||
|
||||
Copyright (C) 2014-2018 Micah Lee <micah@micahflee.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import os
|
||||
import subprocess
|
||||
import textwrap
|
||||
from datetime import datetime
|
||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||
|
||||
from onionshare import strings
|
||||
from ..widgets import Alert
|
||||
|
||||
|
||||
class File(QtWidgets.QWidget):
|
||||
def __init__(self, common, filename):
|
||||
super(File, self).__init__()
|
||||
self.common = common
|
||||
|
||||
self.common.log('File', '__init__', 'filename: {}'.format(filename))
|
||||
|
||||
self.filename = filename
|
||||
self.started = datetime.now()
|
||||
|
||||
# Filename label
|
||||
self.filename_label = QtWidgets.QLabel(self.filename)
|
||||
self.filename_label_width = self.filename_label.width()
|
||||
|
||||
# File size label
|
||||
self.filesize_label = QtWidgets.QLabel()
|
||||
self.filesize_label.setStyleSheet(self.common.css['receive_file_size'])
|
||||
self.filesize_label.hide()
|
||||
|
||||
# Folder button
|
||||
folder_pixmap = QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/open_folder.png')))
|
||||
folder_icon = QtGui.QIcon(folder_pixmap)
|
||||
self.folder_button = QtWidgets.QPushButton()
|
||||
self.folder_button.clicked.connect(self.open_folder)
|
||||
self.folder_button.setIcon(folder_icon)
|
||||
self.folder_button.setIconSize(folder_pixmap.rect().size())
|
||||
self.folder_button.setFlat(True)
|
||||
self.folder_button.hide()
|
||||
|
||||
# Layouts
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.addWidget(self.filename_label)
|
||||
layout.addWidget(self.filesize_label)
|
||||
layout.addStretch()
|
||||
layout.addWidget(self.folder_button)
|
||||
self.setLayout(layout)
|
||||
|
||||
def update(self, uploaded_bytes, complete):
|
||||
self.filesize_label.setText(self.common.human_readable_filesize(uploaded_bytes))
|
||||
self.filesize_label.show()
|
||||
|
||||
if complete:
|
||||
self.folder_button.show()
|
||||
|
||||
def rename(self, new_filename):
|
||||
self.filename = new_filename
|
||||
self.filename_label.setText(self.filename)
|
||||
|
||||
def open_folder(self):
|
||||
"""
|
||||
Open the downloads folder, with the file selected, in a cross-platform manner
|
||||
"""
|
||||
self.common.log('File', 'open_folder')
|
||||
|
||||
abs_filename = os.path.join(self.common.settings.get('downloads_dir'), self.filename)
|
||||
|
||||
# Linux
|
||||
if self.common.platform == 'Linux' or self.common.platform == 'BSD':
|
||||
try:
|
||||
# If nautilus is available, open it
|
||||
subprocess.Popen(['nautilus', abs_filename])
|
||||
except:
|
||||
Alert(self.common, strings._('gui_open_folder_error_nautilus').format(abs_filename))
|
||||
|
||||
# macOS
|
||||
elif self.common.platform == 'Darwin':
|
||||
# TODO: Implement opening folder with file selected in macOS
|
||||
# This seems helpful: https://stackoverflow.com/questions/3520493/python-show-in-finder
|
||||
self.common.log('File', 'open_folder', 'not implemented for Darwin yet')
|
||||
|
||||
# Windows
|
||||
elif self.common.platform == 'Windows':
|
||||
# TODO: Implement opening folder with file selected in Windows
|
||||
# This seems helpful: https://stackoverflow.com/questions/6631299/python-opening-a-folder-in-explorer-nautilus-mac-thingie
|
||||
self.common.log('File', 'open_folder', 'not implemented for Windows yet')
|
||||
|
||||
|
||||
class Upload(QtWidgets.QWidget):
|
||||
def __init__(self, common, upload_id, content_length):
|
||||
super(Upload, self).__init__()
|
||||
self.common = common
|
||||
self.upload_id = upload_id
|
||||
self.content_length = content_length
|
||||
self.started = datetime.now()
|
||||
|
||||
# Label
|
||||
self.label = QtWidgets.QLabel(strings._('gui_upload_in_progress').format(self.started.strftime("%b %d, %I:%M%p")))
|
||||
|
||||
# Progress bar
|
||||
self.progress_bar = QtWidgets.QProgressBar()
|
||||
self.progress_bar.setTextVisible(True)
|
||||
self.progress_bar.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
self.progress_bar.setMinimum(0)
|
||||
self.progress_bar.setValue(0)
|
||||
self.progress_bar.setStyleSheet(self.common.css['downloads_uploads_progress_bar'])
|
||||
|
||||
# This layout contains file widgets
|
||||
self.files_layout = QtWidgets.QVBoxLayout()
|
||||
self.files_layout.setContentsMargins(0, 0, 0, 0)
|
||||
files_widget = QtWidgets.QWidget()
|
||||
files_widget.setStyleSheet(self.common.css['receive_file'])
|
||||
files_widget.setLayout(self.files_layout)
|
||||
|
||||
# Layout
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(self.label)
|
||||
layout.addWidget(self.progress_bar)
|
||||
layout.addWidget(files_widget)
|
||||
layout.addStretch()
|
||||
self.setLayout(layout)
|
||||
|
||||
# We're also making a dictionary of file widgets, to make them easier to access
|
||||
self.files = {}
|
||||
|
||||
def update(self, progress):
|
||||
"""
|
||||
Using the progress from Web, update the progress bar and file size labels
|
||||
for each file
|
||||
"""
|
||||
total_uploaded_bytes = 0
|
||||
for filename in progress:
|
||||
total_uploaded_bytes += progress[filename]['uploaded_bytes']
|
||||
|
||||
# Update the progress bar
|
||||
self.progress_bar.setMaximum(self.content_length)
|
||||
self.progress_bar.setValue(total_uploaded_bytes)
|
||||
|
||||
elapsed = datetime.now() - self.started
|
||||
if elapsed.seconds < 10:
|
||||
pb_fmt = strings._('gui_download_upload_progress_starting').format(
|
||||
self.common.human_readable_filesize(total_uploaded_bytes))
|
||||
else:
|
||||
estimated_time_remaining = self.common.estimated_time_remaining(
|
||||
total_uploaded_bytes,
|
||||
self.content_length,
|
||||
self.started.timestamp())
|
||||
pb_fmt = strings._('gui_download_upload_progress_eta').format(
|
||||
self.common.human_readable_filesize(total_uploaded_bytes),
|
||||
estimated_time_remaining)
|
||||
|
||||
# Using list(progress) to avoid "RuntimeError: dictionary changed size during iteration"
|
||||
for filename in list(progress):
|
||||
# Add a new file if needed
|
||||
if filename not in self.files:
|
||||
self.files[filename] = File(self.common, filename)
|
||||
self.files_layout.addWidget(self.files[filename])
|
||||
|
||||
# Update the file
|
||||
self.files[filename].update(progress[filename]['uploaded_bytes'], progress[filename]['complete'])
|
||||
|
||||
def rename(self, old_filename, new_filename):
|
||||
self.files[old_filename].rename(new_filename)
|
||||
self.files[new_filename] = self.files.pop(old_filename)
|
||||
|
||||
def finished(self):
|
||||
# Hide the progress bar
|
||||
self.progress_bar.hide()
|
||||
|
||||
# Change the label
|
||||
self.ended = self.started = datetime.now()
|
||||
if self.started.year == self.ended.year and self.started.month == self.ended.month and self.started.day == self.ended.day:
|
||||
if self.started.hour == self.ended.hour and self.started.minute == self.ended.minute:
|
||||
text = strings._('gui_upload_finished').format(
|
||||
self.started.strftime("%b %d, %I:%M%p")
|
||||
)
|
||||
else:
|
||||
text = strings._('gui_upload_finished_range').format(
|
||||
self.started.strftime("%b %d, %I:%M%p"),
|
||||
self.ended.strftime("%I:%M%p")
|
||||
)
|
||||
else:
|
||||
text = strings._('gui_upload_finished_range').format(
|
||||
self.started.strftime("%b %d, %I:%M%p"),
|
||||
self.ended.strftime("%b %d, %I:%M%p")
|
||||
)
|
||||
self.label.setText(text)
|
||||
|
||||
|
||||
class Uploads(QtWidgets.QScrollArea):
|
||||
"""
|
||||
The uploads chunk of the GUI. This lists all of the active upload
|
||||
progress bars, as well as information about each upload.
|
||||
"""
|
||||
def __init__(self, common):
|
||||
super(Uploads, self).__init__()
|
||||
self.common = common
|
||||
self.common.log('Uploads', '__init__')
|
||||
|
||||
self.resizeEvent = None
|
||||
|
||||
self.uploads = {}
|
||||
|
||||
self.setWindowTitle(strings._('gui_uploads'))
|
||||
self.setWidgetResizable(True)
|
||||
self.setMinimumHeight(150)
|
||||
self.setMinimumWidth(350)
|
||||
self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
||||
self.setWindowFlags(QtCore.Qt.Sheet | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.CustomizeWindowHint)
|
||||
self.vbar = self.verticalScrollBar()
|
||||
self.vbar.rangeChanged.connect(self.resizeScroll)
|
||||
|
||||
uploads_label = QtWidgets.QLabel(strings._('gui_uploads'))
|
||||
uploads_label.setStyleSheet(self.common.css['downloads_uploads_label'])
|
||||
self.no_uploads_label = QtWidgets.QLabel(strings._('gui_no_uploads'))
|
||||
self.clear_history_button = QtWidgets.QPushButton(strings._('gui_clear_history'))
|
||||
self.clear_history_button.clicked.connect(self.reset)
|
||||
self.clear_history_button.hide()
|
||||
|
||||
|
||||
self.uploads_layout = QtWidgets.QVBoxLayout()
|
||||
|
||||
widget = QtWidgets.QWidget()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(uploads_label)
|
||||
layout.addWidget(self.no_uploads_label)
|
||||
layout.addWidget(self.clear_history_button)
|
||||
layout.addLayout(self.uploads_layout)
|
||||
layout.addStretch()
|
||||
widget.setLayout(layout)
|
||||
self.setWidget(widget)
|
||||
|
||||
def resizeScroll(self, minimum, maximum):
|
||||
"""
|
||||
Scroll to the bottom of the window when the range changes.
|
||||
"""
|
||||
self.vbar.setValue(maximum)
|
||||
|
||||
def add(self, upload_id, content_length):
|
||||
"""
|
||||
Add a new upload.
|
||||
"""
|
||||
self.common.log('Uploads', 'add', 'upload_id: {}, content_length: {}'.format(upload_id, content_length))
|
||||
# Hide the no_uploads_label
|
||||
self.no_uploads_label.hide()
|
||||
# Show the clear_history_button
|
||||
self.clear_history_button.show()
|
||||
|
||||
# Add it to the list
|
||||
upload = Upload(self.common, upload_id, content_length)
|
||||
self.uploads[upload_id] = upload
|
||||
self.uploads_layout.addWidget(upload)
|
||||
|
||||
def update(self, upload_id, progress):
|
||||
"""
|
||||
Update the progress of an upload.
|
||||
"""
|
||||
self.uploads[upload_id].update(progress)
|
||||
|
||||
def rename(self, upload_id, old_filename, new_filename):
|
||||
"""
|
||||
Rename a file, which happens if the filename already exists in downloads_dir.
|
||||
"""
|
||||
self.uploads[upload_id].rename(old_filename, new_filename)
|
||||
|
||||
def finished(self, upload_id):
|
||||
"""
|
||||
An upload has finished.
|
||||
"""
|
||||
self.uploads[upload_id].finished()
|
||||
|
||||
def cancel(self, upload_id):
|
||||
"""
|
||||
Update an upload progress bar to show that it has been canceled.
|
||||
"""
|
||||
self.common.log('Uploads', 'cancel', 'upload_id: {}'.format(upload_id))
|
||||
self.uploads[upload_id].cancel()
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the uploads back to zero
|
||||
"""
|
||||
self.common.log('Uploads', 'reset')
|
||||
for upload in self.uploads.values():
|
||||
upload.close()
|
||||
self.uploads_layout.removeWidget(upload)
|
||||
self.uploads = {}
|
||||
|
||||
self.no_uploads_label.show()
|
||||
self.clear_history_button.hide()
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
def resizeEvent(self, event):
|
||||
width = self.frameGeometry().width()
|
||||
try:
|
||||
for upload in self.uploads.values():
|
||||
for item in upload.files.values():
|
||||
item.filename_label.setText(textwrap.fill(item.filename, 30))
|
||||
item.adjustSize()
|
||||
except:
|
||||
pass
|
@ -61,7 +61,7 @@ class ServerStatus(QtWidgets.QWidget):
|
||||
self.resizeEvent(None)
|
||||
|
||||
# Shutdown timeout layout
|
||||
self.shutdown_timeout_label = QtWidgets.QLabel(strings._('gui_settings_shutdown_timeout', True))
|
||||
self.shutdown_timeout_label = QtWidgets.QLabel(strings._('gui_settings_shutdown_timeout'))
|
||||
self.shutdown_timeout = QtWidgets.QDateTimeEdit()
|
||||
self.shutdown_timeout.setDisplayFormat("hh:mm A MMM d, yy")
|
||||
if self.local_only:
|
||||
@ -100,12 +100,12 @@ class ServerStatus(QtWidgets.QWidget):
|
||||
self.url.setMinimumSize(self.url.sizeHint())
|
||||
self.url.setStyleSheet(self.common.css['server_status_url'])
|
||||
|
||||
self.copy_url_button = QtWidgets.QPushButton(strings._('gui_copy_url', True))
|
||||
self.copy_url_button = QtWidgets.QPushButton(strings._('gui_copy_url'))
|
||||
self.copy_url_button.setFlat(True)
|
||||
self.copy_url_button.setStyleSheet(self.common.css['server_status_url_buttons'])
|
||||
self.copy_url_button.setMinimumHeight(65)
|
||||
self.copy_url_button.clicked.connect(self.copy_url)
|
||||
self.copy_hidservauth_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True))
|
||||
self.copy_hidservauth_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth'))
|
||||
self.copy_hidservauth_button.setFlat(True)
|
||||
self.copy_hidservauth_button.setStyleSheet(self.common.css['server_status_url_buttons'])
|
||||
self.copy_hidservauth_button.clicked.connect(self.copy_hidservauth)
|
||||
@ -174,21 +174,21 @@ class ServerStatus(QtWidgets.QWidget):
|
||||
info_image = self.common.get_resource_path('images/info.png')
|
||||
|
||||
if self.mode == ServerStatus.MODE_SHARE:
|
||||
self.url_description.setText(strings._('gui_share_url_description', True).format(info_image))
|
||||
self.url_description.setText(strings._('gui_share_url_description').format(info_image))
|
||||
else:
|
||||
self.url_description.setText(strings._('gui_receive_url_description', True).format(info_image))
|
||||
self.url_description.setText(strings._('gui_receive_url_description').format(info_image))
|
||||
|
||||
# Show a Tool Tip explaining the lifecycle of this URL
|
||||
if self.common.settings.get('save_private_key'):
|
||||
if self.mode == ServerStatus.MODE_SHARE and self.common.settings.get('close_after_first_download'):
|
||||
self.url_description.setToolTip(strings._('gui_url_label_onetime_and_persistent', True))
|
||||
self.url_description.setToolTip(strings._('gui_url_label_onetime_and_persistent'))
|
||||
else:
|
||||
self.url_description.setToolTip(strings._('gui_url_label_persistent', True))
|
||||
self.url_description.setToolTip(strings._('gui_url_label_persistent'))
|
||||
else:
|
||||
if self.mode == ServerStatus.MODE_SHARE and self.common.settings.get('close_after_first_download'):
|
||||
self.url_description.setToolTip(strings._('gui_url_label_onetime', True))
|
||||
self.url_description.setToolTip(strings._('gui_url_label_onetime'))
|
||||
else:
|
||||
self.url_description.setToolTip(strings._('gui_url_label_stay_open', True))
|
||||
self.url_description.setToolTip(strings._('gui_url_label_stay_open'))
|
||||
|
||||
self.url.setText(self.get_url())
|
||||
self.url.show()
|
||||
@ -223,9 +223,9 @@ class ServerStatus(QtWidgets.QWidget):
|
||||
self.server_button.setStyleSheet(self.common.css['server_status_button_stopped'])
|
||||
self.server_button.setEnabled(True)
|
||||
if self.mode == ServerStatus.MODE_SHARE:
|
||||
self.server_button.setText(strings._('gui_share_start_server', True))
|
||||
self.server_button.setText(strings._('gui_share_start_server'))
|
||||
else:
|
||||
self.server_button.setText(strings._('gui_receive_start_server', True))
|
||||
self.server_button.setText(strings._('gui_receive_start_server'))
|
||||
self.server_button.setToolTip('')
|
||||
if self.common.settings.get('shutdown_timeout'):
|
||||
self.shutdown_timeout_container.show()
|
||||
@ -233,15 +233,15 @@ class ServerStatus(QtWidgets.QWidget):
|
||||
self.server_button.setStyleSheet(self.common.css['server_status_button_started'])
|
||||
self.server_button.setEnabled(True)
|
||||
if self.mode == ServerStatus.MODE_SHARE:
|
||||
self.server_button.setText(strings._('gui_share_stop_server', True))
|
||||
self.server_button.setText(strings._('gui_share_stop_server'))
|
||||
else:
|
||||
self.server_button.setText(strings._('gui_receive_stop_server', True))
|
||||
self.server_button.setText(strings._('gui_receive_stop_server'))
|
||||
if self.common.settings.get('shutdown_timeout'):
|
||||
self.shutdown_timeout_container.hide()
|
||||
if self.mode == ServerStatus.MODE_SHARE:
|
||||
self.server_button.setToolTip(strings._('gui_share_stop_server_shutdown_timeout_tooltip', True).format(self.timeout))
|
||||
self.server_button.setToolTip(strings._('gui_share_stop_server_shutdown_timeout_tooltip').format(self.timeout))
|
||||
else:
|
||||
self.server_button.setToolTip(strings._('gui_receive_stop_server_shutdown_timeout_tooltip', True).format(self.timeout))
|
||||
self.server_button.setToolTip(strings._('gui_receive_stop_server_shutdown_timeout_tooltip').format(self.timeout))
|
||||
|
||||
elif self.status == self.STATUS_WORKING:
|
||||
self.server_button.setStyleSheet(self.common.css['server_status_button_working'])
|
||||
|
@ -47,7 +47,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.local_only = local_only
|
||||
|
||||
self.setModal(True)
|
||||
self.setWindowTitle(strings._('gui_settings_window_title', True))
|
||||
self.setWindowTitle(strings._('gui_settings_window_title'))
|
||||
self.setWindowIcon(QtGui.QIcon(self.common.get_resource_path('images/logo.png')))
|
||||
|
||||
self.system = platform.system()
|
||||
@ -57,8 +57,8 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Use a slug or not ('public mode')
|
||||
self.public_mode_checkbox = QtWidgets.QCheckBox()
|
||||
self.public_mode_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.public_mode_checkbox.setText(strings._("gui_settings_public_mode_checkbox", True))
|
||||
public_mode_label = QtWidgets.QLabel(strings._("gui_settings_whats_this", True).format("https://github.com/micahflee/onionshare/wiki/Public-Mode"))
|
||||
self.public_mode_checkbox.setText(strings._("gui_settings_public_mode_checkbox"))
|
||||
public_mode_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Public-Mode"))
|
||||
public_mode_label.setStyleSheet(self.common.css['settings_whats_this'])
|
||||
public_mode_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
public_mode_label.setOpenExternalLinks(True)
|
||||
@ -74,8 +74,8 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Whether or not to use a shutdown ('auto-stop') timer
|
||||
self.shutdown_timeout_checkbox = QtWidgets.QCheckBox()
|
||||
self.shutdown_timeout_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
self.shutdown_timeout_checkbox.setText(strings._("gui_settings_shutdown_timeout_checkbox", True))
|
||||
shutdown_timeout_label = QtWidgets.QLabel(strings._("gui_settings_whats_this", True).format("https://github.com/micahflee/onionshare/wiki/Using-the-Auto-Stop-Timer"))
|
||||
self.shutdown_timeout_checkbox.setText(strings._("gui_settings_shutdown_timeout_checkbox"))
|
||||
shutdown_timeout_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Using-the-Auto-Stop-Timer"))
|
||||
shutdown_timeout_label.setStyleSheet(self.common.css['settings_whats_this'])
|
||||
shutdown_timeout_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
shutdown_timeout_label.setOpenExternalLinks(True)
|
||||
@ -91,9 +91,9 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Whether or not to use legacy v2 onions
|
||||
self.use_legacy_v2_onions_checkbox = QtWidgets.QCheckBox()
|
||||
self.use_legacy_v2_onions_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.use_legacy_v2_onions_checkbox.setText(strings._("gui_use_legacy_v2_onions_checkbox", True))
|
||||
self.use_legacy_v2_onions_checkbox.setText(strings._("gui_use_legacy_v2_onions_checkbox"))
|
||||
self.use_legacy_v2_onions_checkbox.clicked.connect(self.use_legacy_v2_onions_checkbox_clicked)
|
||||
use_legacy_v2_onions_label = QtWidgets.QLabel(strings._("gui_settings_whats_this", True).format("https://github.com/micahflee/onionshare/wiki/Legacy-Addresses"))
|
||||
use_legacy_v2_onions_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Legacy-Addresses"))
|
||||
use_legacy_v2_onions_label.setStyleSheet(self.common.css['settings_whats_this'])
|
||||
use_legacy_v2_onions_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
use_legacy_v2_onions_label.setOpenExternalLinks(True)
|
||||
@ -108,9 +108,9 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Whether or not to save the Onion private key for reuse (persistent URL mode)
|
||||
self.save_private_key_checkbox = QtWidgets.QCheckBox()
|
||||
self.save_private_key_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.save_private_key_checkbox.setText(strings._("gui_save_private_key_checkbox", True))
|
||||
self.save_private_key_checkbox.setText(strings._("gui_save_private_key_checkbox"))
|
||||
self.save_private_key_checkbox.clicked.connect(self.save_private_key_checkbox_clicked)
|
||||
save_private_key_label = QtWidgets.QLabel(strings._("gui_settings_whats_this", True).format("https://github.com/micahflee/onionshare/wiki/Using-a-Persistent-URL"))
|
||||
save_private_key_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Using-a-Persistent-URL"))
|
||||
save_private_key_label.setStyleSheet(self.common.css['settings_whats_this'])
|
||||
save_private_key_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
save_private_key_label.setOpenExternalLinks(True)
|
||||
@ -125,9 +125,9 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Stealth
|
||||
self.stealth_checkbox = QtWidgets.QCheckBox()
|
||||
self.stealth_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.stealth_checkbox.setText(strings._("gui_settings_stealth_option", True))
|
||||
self.stealth_checkbox.setText(strings._("gui_settings_stealth_option"))
|
||||
self.stealth_checkbox.clicked.connect(self.stealth_checkbox_clicked_connect)
|
||||
use_stealth_label = QtWidgets.QLabel(strings._("gui_settings_whats_this", True).format("https://github.com/micahflee/onionshare/wiki/Stealth-Onion-Services"))
|
||||
use_stealth_label = QtWidgets.QLabel(strings._("gui_settings_whats_this").format("https://github.com/micahflee/onionshare/wiki/Stealth-Onion-Services"))
|
||||
use_stealth_label.setStyleSheet(self.common.css['settings_whats_this'])
|
||||
use_stealth_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
use_stealth_label.setOpenExternalLinks(True)
|
||||
@ -140,12 +140,12 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.use_stealth_widget = QtWidgets.QWidget()
|
||||
self.use_stealth_widget.setLayout(use_stealth_layout)
|
||||
|
||||
hidservauth_details = QtWidgets.QLabel(strings._('gui_settings_stealth_hidservauth_string', True))
|
||||
hidservauth_details = QtWidgets.QLabel(strings._('gui_settings_stealth_hidservauth_string'))
|
||||
hidservauth_details.setWordWrap(True)
|
||||
hidservauth_details.setMinimumSize(hidservauth_details.sizeHint())
|
||||
hidservauth_details.hide()
|
||||
|
||||
self.hidservauth_copy_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth', True))
|
||||
self.hidservauth_copy_button = QtWidgets.QPushButton(strings._('gui_copy_hidservauth'))
|
||||
self.hidservauth_copy_button.clicked.connect(self.hidservauth_copy_button_clicked)
|
||||
self.hidservauth_copy_button.hide()
|
||||
|
||||
@ -159,7 +159,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
general_group_layout.addWidget(hidservauth_details)
|
||||
general_group_layout.addWidget(self.hidservauth_copy_button)
|
||||
|
||||
general_group = QtWidgets.QGroupBox(strings._("gui_settings_general_label", True))
|
||||
general_group = QtWidgets.QGroupBox(strings._("gui_settings_general_label"))
|
||||
general_group.setLayout(general_group_layout)
|
||||
|
||||
# Sharing options
|
||||
@ -167,19 +167,19 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Close after first download
|
||||
self.close_after_first_download_checkbox = QtWidgets.QCheckBox()
|
||||
self.close_after_first_download_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
self.close_after_first_download_checkbox.setText(strings._("gui_settings_close_after_first_download_option", True))
|
||||
self.close_after_first_download_checkbox.setText(strings._("gui_settings_close_after_first_download_option"))
|
||||
|
||||
# Sharing options layout
|
||||
sharing_group_layout = QtWidgets.QVBoxLayout()
|
||||
sharing_group_layout.addWidget(self.close_after_first_download_checkbox)
|
||||
sharing_group = QtWidgets.QGroupBox(strings._("gui_settings_sharing_label", True))
|
||||
sharing_group = QtWidgets.QGroupBox(strings._("gui_settings_sharing_label"))
|
||||
sharing_group.setLayout(sharing_group_layout)
|
||||
|
||||
# Downloads dir
|
||||
downloads_label = QtWidgets.QLabel(strings._('gui_settings_downloads_label', True));
|
||||
downloads_label = QtWidgets.QLabel(strings._('gui_settings_downloads_label'));
|
||||
self.downloads_dir_lineedit = QtWidgets.QLineEdit()
|
||||
self.downloads_dir_lineedit.setReadOnly(True)
|
||||
downloads_button = QtWidgets.QPushButton(strings._('gui_settings_downloads_button', True))
|
||||
downloads_button = QtWidgets.QPushButton(strings._('gui_settings_downloads_button'))
|
||||
downloads_button.clicked.connect(self.downloads_button_clicked)
|
||||
downloads_layout = QtWidgets.QHBoxLayout()
|
||||
downloads_layout.addWidget(downloads_label)
|
||||
@ -189,13 +189,13 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Allow the receiver to shutdown the server
|
||||
self.receive_allow_receiver_shutdown_checkbox = QtWidgets.QCheckBox()
|
||||
self.receive_allow_receiver_shutdown_checkbox.setCheckState(QtCore.Qt.Checked)
|
||||
self.receive_allow_receiver_shutdown_checkbox.setText(strings._("gui_settings_receive_allow_receiver_shutdown_checkbox", True))
|
||||
self.receive_allow_receiver_shutdown_checkbox.setText(strings._("gui_settings_receive_allow_receiver_shutdown_checkbox"))
|
||||
|
||||
# Receiving options layout
|
||||
receiving_group_layout = QtWidgets.QVBoxLayout()
|
||||
receiving_group_layout.addLayout(downloads_layout)
|
||||
receiving_group_layout.addWidget(self.receive_allow_receiver_shutdown_checkbox)
|
||||
receiving_group = QtWidgets.QGroupBox(strings._("gui_settings_receiving_label", True))
|
||||
receiving_group = QtWidgets.QGroupBox(strings._("gui_settings_receiving_label"))
|
||||
receiving_group.setLayout(receiving_group_layout)
|
||||
|
||||
# Automatic updates options
|
||||
@ -203,13 +203,13 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Autoupdate
|
||||
self.autoupdate_checkbox = QtWidgets.QCheckBox()
|
||||
self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked)
|
||||
self.autoupdate_checkbox.setText(strings._("gui_settings_autoupdate_option", True))
|
||||
self.autoupdate_checkbox.setText(strings._("gui_settings_autoupdate_option"))
|
||||
|
||||
# Last update time
|
||||
self.autoupdate_timestamp = QtWidgets.QLabel()
|
||||
|
||||
# Check for updates button
|
||||
self.check_for_updates_button = QtWidgets.QPushButton(strings._('gui_settings_autoupdate_check_button', True))
|
||||
self.check_for_updates_button = QtWidgets.QPushButton(strings._('gui_settings_autoupdate_check_button'))
|
||||
self.check_for_updates_button.clicked.connect(self.check_for_updates)
|
||||
# We can't check for updates if not connected to Tor
|
||||
if not self.onion.connected_to_tor:
|
||||
@ -220,17 +220,32 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
autoupdate_group_layout.addWidget(self.autoupdate_checkbox)
|
||||
autoupdate_group_layout.addWidget(self.autoupdate_timestamp)
|
||||
autoupdate_group_layout.addWidget(self.check_for_updates_button)
|
||||
autoupdate_group = QtWidgets.QGroupBox(strings._("gui_settings_autoupdate_label", True))
|
||||
autoupdate_group = QtWidgets.QGroupBox(strings._("gui_settings_autoupdate_label"))
|
||||
autoupdate_group.setLayout(autoupdate_group_layout)
|
||||
|
||||
# Autoupdate is only available for Windows and Mac (Linux updates using package manager)
|
||||
if self.system != 'Windows' and self.system != 'Darwin':
|
||||
autoupdate_group.hide()
|
||||
|
||||
# Language settings
|
||||
language_label = QtWidgets.QLabel(strings._("gui_settings_language_label"))
|
||||
self.language_combobox = QtWidgets.QComboBox()
|
||||
# Populate the dropdown with all of OnionShare's available languages
|
||||
language_names_to_locales = {v: k for k, v in self.common.settings.available_locales.items()}
|
||||
language_names = list(language_names_to_locales)
|
||||
language_names.sort()
|
||||
for language_name in language_names:
|
||||
locale = language_names_to_locales[language_name]
|
||||
self.language_combobox.addItem(language_name, QtCore.QVariant(locale))
|
||||
language_layout = QtWidgets.QHBoxLayout()
|
||||
language_layout.addWidget(language_label)
|
||||
language_layout.addWidget(self.language_combobox)
|
||||
language_layout.addStretch()
|
||||
|
||||
# Connection type: either automatic, control port, or socket file
|
||||
|
||||
# Bundled Tor
|
||||
self.connection_type_bundled_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_bundled_option', True))
|
||||
self.connection_type_bundled_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_bundled_option'))
|
||||
self.connection_type_bundled_radio.toggled.connect(self.connection_type_bundled_toggled)
|
||||
|
||||
# Bundled Tor doesn't work on dev mode in Windows or Mac
|
||||
@ -240,27 +255,27 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Bridge options for bundled tor
|
||||
|
||||
# No bridges option radio
|
||||
self.tor_bridges_no_bridges_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_no_bridges_radio_option', True))
|
||||
self.tor_bridges_no_bridges_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_no_bridges_radio_option'))
|
||||
self.tor_bridges_no_bridges_radio.toggled.connect(self.tor_bridges_no_bridges_radio_toggled)
|
||||
|
||||
# obfs4 option radio
|
||||
# if the obfs4proxy binary is missing, we can't use obfs4 transports
|
||||
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths()
|
||||
if not os.path.isfile(self.obfs4proxy_file_path):
|
||||
self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy', True))
|
||||
self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option_no_obfs4proxy'))
|
||||
self.tor_bridges_use_obfs4_radio.setEnabled(False)
|
||||
else:
|
||||
self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option', True))
|
||||
self.tor_bridges_use_obfs4_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_obfs4_radio_option'))
|
||||
self.tor_bridges_use_obfs4_radio.toggled.connect(self.tor_bridges_use_obfs4_radio_toggled)
|
||||
|
||||
# meek_lite-azure option radio
|
||||
# if the obfs4proxy binary is missing, we can't use meek_lite-azure transports
|
||||
(self.tor_path, self.tor_geo_ip_file_path, self.tor_geo_ipv6_file_path, self.obfs4proxy_file_path) = self.common.get_tor_paths()
|
||||
if not os.path.isfile(self.obfs4proxy_file_path):
|
||||
self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy', True))
|
||||
self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option_no_obfs4proxy'))
|
||||
self.tor_bridges_use_meek_lite_azure_radio.setEnabled(False)
|
||||
else:
|
||||
self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option', True))
|
||||
self.tor_bridges_use_meek_lite_azure_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_meek_lite_azure_radio_option'))
|
||||
self.tor_bridges_use_meek_lite_azure_radio.toggled.connect(self.tor_bridges_use_meek_lite_azure_radio_toggled)
|
||||
|
||||
# meek_lite currently not supported on the version of obfs4proxy bundled with TorBrowser
|
||||
@ -268,10 +283,10 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.tor_bridges_use_meek_lite_azure_radio.hide()
|
||||
|
||||
# Custom bridges radio and textbox
|
||||
self.tor_bridges_use_custom_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_custom_radio_option', True))
|
||||
self.tor_bridges_use_custom_radio = QtWidgets.QRadioButton(strings._('gui_settings_tor_bridges_custom_radio_option'))
|
||||
self.tor_bridges_use_custom_radio.toggled.connect(self.tor_bridges_use_custom_radio_toggled)
|
||||
|
||||
self.tor_bridges_use_custom_label = QtWidgets.QLabel(strings._('gui_settings_tor_bridges_custom_label', True))
|
||||
self.tor_bridges_use_custom_label = QtWidgets.QLabel(strings._('gui_settings_tor_bridges_custom_label'))
|
||||
self.tor_bridges_use_custom_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
|
||||
self.tor_bridges_use_custom_label.setOpenExternalLinks(True)
|
||||
self.tor_bridges_use_custom_textbox = QtWidgets.QPlainTextEdit()
|
||||
@ -298,14 +313,14 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.bridges.setLayout(bridges_layout)
|
||||
|
||||
# Automatic
|
||||
self.connection_type_automatic_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_automatic_option', True))
|
||||
self.connection_type_automatic_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_automatic_option'))
|
||||
self.connection_type_automatic_radio.toggled.connect(self.connection_type_automatic_toggled)
|
||||
|
||||
# Control port
|
||||
self.connection_type_control_port_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_control_port_option', True))
|
||||
self.connection_type_control_port_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_control_port_option'))
|
||||
self.connection_type_control_port_radio.toggled.connect(self.connection_type_control_port_toggled)
|
||||
|
||||
connection_type_control_port_extras_label = QtWidgets.QLabel(strings._('gui_settings_control_port_label', True))
|
||||
connection_type_control_port_extras_label = QtWidgets.QLabel(strings._('gui_settings_control_port_label'))
|
||||
self.connection_type_control_port_extras_address = QtWidgets.QLineEdit()
|
||||
self.connection_type_control_port_extras_port = QtWidgets.QLineEdit()
|
||||
connection_type_control_port_extras_layout = QtWidgets.QHBoxLayout()
|
||||
@ -318,10 +333,10 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.connection_type_control_port_extras.hide()
|
||||
|
||||
# Socket file
|
||||
self.connection_type_socket_file_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_socket_file_option', True))
|
||||
self.connection_type_socket_file_radio = QtWidgets.QRadioButton(strings._('gui_settings_connection_type_socket_file_option'))
|
||||
self.connection_type_socket_file_radio.toggled.connect(self.connection_type_socket_file_toggled)
|
||||
|
||||
connection_type_socket_file_extras_label = QtWidgets.QLabel(strings._('gui_settings_socket_file_label', True))
|
||||
connection_type_socket_file_extras_label = QtWidgets.QLabel(strings._('gui_settings_socket_file_label'))
|
||||
self.connection_type_socket_file_extras_path = QtWidgets.QLineEdit()
|
||||
connection_type_socket_file_extras_layout = QtWidgets.QHBoxLayout()
|
||||
connection_type_socket_file_extras_layout.addWidget(connection_type_socket_file_extras_label)
|
||||
@ -332,7 +347,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.connection_type_socket_file_extras.hide()
|
||||
|
||||
# Tor SOCKS address and port
|
||||
gui_settings_socks_label = QtWidgets.QLabel(strings._('gui_settings_socks_label', True))
|
||||
gui_settings_socks_label = QtWidgets.QLabel(strings._('gui_settings_socks_label'))
|
||||
self.connection_type_socks_address = QtWidgets.QLineEdit()
|
||||
self.connection_type_socks_port = QtWidgets.QLineEdit()
|
||||
connection_type_socks_layout = QtWidgets.QHBoxLayout()
|
||||
@ -347,14 +362,14 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
# Authentication options
|
||||
|
||||
# No authentication
|
||||
self.authenticate_no_auth_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_no_auth_option', True))
|
||||
self.authenticate_no_auth_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_no_auth_option'))
|
||||
self.authenticate_no_auth_radio.toggled.connect(self.authenticate_no_auth_toggled)
|
||||
|
||||
# Password
|
||||
self.authenticate_password_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_password_option', True))
|
||||
self.authenticate_password_radio = QtWidgets.QRadioButton(strings._('gui_settings_authenticate_password_option'))
|
||||
self.authenticate_password_radio.toggled.connect(self.authenticate_password_toggled)
|
||||
|
||||
authenticate_password_extras_label = QtWidgets.QLabel(strings._('gui_settings_password_label', True))
|
||||
authenticate_password_extras_label = QtWidgets.QLabel(strings._('gui_settings_password_label'))
|
||||
self.authenticate_password_extras_password = QtWidgets.QLineEdit('')
|
||||
authenticate_password_extras_layout = QtWidgets.QHBoxLayout()
|
||||
authenticate_password_extras_layout.addWidget(authenticate_password_extras_label)
|
||||
@ -369,7 +384,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
authenticate_group_layout.addWidget(self.authenticate_no_auth_radio)
|
||||
authenticate_group_layout.addWidget(self.authenticate_password_radio)
|
||||
authenticate_group_layout.addWidget(self.authenticate_password_extras)
|
||||
self.authenticate_group = QtWidgets.QGroupBox(strings._("gui_settings_authenticate_label", True))
|
||||
self.authenticate_group = QtWidgets.QGroupBox(strings._("gui_settings_authenticate_label"))
|
||||
self.authenticate_group.setLayout(authenticate_group_layout)
|
||||
|
||||
# Put the radios into their own group so they are exclusive
|
||||
@ -378,18 +393,18 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
connection_type_radio_group_layout.addWidget(self.connection_type_automatic_radio)
|
||||
connection_type_radio_group_layout.addWidget(self.connection_type_control_port_radio)
|
||||
connection_type_radio_group_layout.addWidget(self.connection_type_socket_file_radio)
|
||||
connection_type_radio_group = QtWidgets.QGroupBox(strings._("gui_settings_connection_type_label", True))
|
||||
connection_type_radio_group = QtWidgets.QGroupBox(strings._("gui_settings_connection_type_label"))
|
||||
connection_type_radio_group.setLayout(connection_type_radio_group_layout)
|
||||
|
||||
# The Bridges options are not exclusive (enabling Bridges offers obfs4 or custom bridges)
|
||||
connection_type_bridges_radio_group_layout = QtWidgets.QVBoxLayout()
|
||||
connection_type_bridges_radio_group_layout.addWidget(self.bridges)
|
||||
self.connection_type_bridges_radio_group = QtWidgets.QGroupBox(strings._("gui_settings_tor_bridges", True))
|
||||
self.connection_type_bridges_radio_group = QtWidgets.QGroupBox(strings._("gui_settings_tor_bridges"))
|
||||
self.connection_type_bridges_radio_group.setLayout(connection_type_bridges_radio_group_layout)
|
||||
self.connection_type_bridges_radio_group.hide()
|
||||
|
||||
# Test tor settings button
|
||||
self.connection_type_test_button = QtWidgets.QPushButton(strings._('gui_settings_connection_type_test_button', True))
|
||||
self.connection_type_test_button = QtWidgets.QPushButton(strings._('gui_settings_connection_type_test_button'))
|
||||
self.connection_type_test_button.clicked.connect(self.test_tor_clicked)
|
||||
connection_type_test_button_layout = QtWidgets.QHBoxLayout()
|
||||
connection_type_test_button_layout.addWidget(self.connection_type_test_button)
|
||||
@ -405,13 +420,13 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
connection_type_layout.addLayout(connection_type_test_button_layout)
|
||||
|
||||
# Buttons
|
||||
self.save_button = QtWidgets.QPushButton(strings._('gui_settings_button_save', True))
|
||||
self.save_button = QtWidgets.QPushButton(strings._('gui_settings_button_save'))
|
||||
self.save_button.clicked.connect(self.save_clicked)
|
||||
self.cancel_button = QtWidgets.QPushButton(strings._('gui_settings_button_cancel', True))
|
||||
self.cancel_button = QtWidgets.QPushButton(strings._('gui_settings_button_cancel'))
|
||||
self.cancel_button.clicked.connect(self.cancel_clicked)
|
||||
version_label = QtWidgets.QLabel('OnionShare {0:s}'.format(self.common.version))
|
||||
version_label.setStyleSheet(self.common.css['settings_version'])
|
||||
self.help_button = QtWidgets.QPushButton(strings._('gui_settings_button_help', True))
|
||||
self.help_button = QtWidgets.QPushButton(strings._('gui_settings_button_help'))
|
||||
self.help_button.clicked.connect(self.help_clicked)
|
||||
buttons_layout = QtWidgets.QHBoxLayout()
|
||||
buttons_layout.addWidget(version_label)
|
||||
@ -431,6 +446,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
left_col_layout.addWidget(sharing_group)
|
||||
left_col_layout.addWidget(receiving_group)
|
||||
left_col_layout.addWidget(autoupdate_group)
|
||||
left_col_layout.addLayout(language_layout)
|
||||
left_col_layout.addStretch()
|
||||
|
||||
right_col_layout = QtWidgets.QVBoxLayout()
|
||||
@ -524,6 +540,10 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
autoupdate_timestamp = self.old_settings.get('autoupdate_timestamp')
|
||||
self._update_autoupdate_timestamp(autoupdate_timestamp)
|
||||
|
||||
locale = self.old_settings.get('locale')
|
||||
locale_index = self.language_combobox.findData(QtCore.QVariant(locale))
|
||||
self.language_combobox.setCurrentIndex(locale_index)
|
||||
|
||||
connection_type = self.old_settings.get('connection_type')
|
||||
if connection_type == 'bundled':
|
||||
if self.connection_type_bundled_radio.isEnabled():
|
||||
@ -603,7 +623,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
self.tor_bridges_use_custom_textbox_options.hide()
|
||||
# Alert the user about meek's costliness if it looks like they're turning it on
|
||||
if not self.old_settings.get('tor_bridges_use_meek_lite_azure'):
|
||||
Alert(self.common, strings._('gui_settings_meek_lite_expensive_warning', True), QtWidgets.QMessageBox.Warning)
|
||||
Alert(self.common, strings._('gui_settings_meek_lite_expensive_warning'), QtWidgets.QMessageBox.Warning)
|
||||
|
||||
def tor_bridges_use_custom_radio_toggled(self, checked):
|
||||
"""
|
||||
@ -716,7 +736,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
downloads_dir = self.downloads_dir_lineedit.text()
|
||||
selected_dir = QtWidgets.QFileDialog.getExistingDirectory(self,
|
||||
strings._('gui_settings_downloads_label', True), downloads_dir)
|
||||
strings._('gui_settings_downloads_label'), downloads_dir)
|
||||
|
||||
if selected_dir:
|
||||
self.common.log('SettingsDialog', 'downloads_button_clicked', 'selected dir: {}'.format(selected_dir))
|
||||
@ -746,7 +766,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
onion.connect(custom_settings=settings, config=self.config, tor_status_update_func=tor_status_update_func)
|
||||
|
||||
# If an exception hasn't been raised yet, the Tor settings work
|
||||
Alert(self.common, strings._('settings_test_success', True).format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth, onion.supports_next_gen_onions))
|
||||
Alert(self.common, strings._('settings_test_success').format(onion.tor_version, onion.supports_ephemeral, onion.supports_stealth, onion.supports_next_gen_onions))
|
||||
|
||||
# Clean up
|
||||
onion.cleanup()
|
||||
@ -782,19 +802,19 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
|
||||
# Check for updates
|
||||
def update_available(update_url, installed_version, latest_version):
|
||||
Alert(self.common, strings._("update_available", True).format(update_url, installed_version, latest_version))
|
||||
Alert(self.common, strings._("update_available").format(update_url, installed_version, latest_version))
|
||||
close_forced_update_thread()
|
||||
|
||||
def update_not_available():
|
||||
Alert(self.common, strings._('update_not_available', True))
|
||||
Alert(self.common, strings._('update_not_available'))
|
||||
close_forced_update_thread()
|
||||
|
||||
def update_error():
|
||||
Alert(self.common, strings._('update_error_check_error', True), QtWidgets.QMessageBox.Warning)
|
||||
Alert(self.common, strings._('update_error_check_error'), QtWidgets.QMessageBox.Warning)
|
||||
close_forced_update_thread()
|
||||
|
||||
def update_invalid_version(latest_version):
|
||||
Alert(self.common, strings._('update_error_invalid_latest_version', True).format(latest_version), QtWidgets.QMessageBox.Warning)
|
||||
Alert(self.common, strings._('update_error_invalid_latest_version').format(latest_version), QtWidgets.QMessageBox.Warning)
|
||||
close_forced_update_thread()
|
||||
|
||||
forced_update_thread = UpdateThread(self.common, self.onion, self.config, force=True)
|
||||
@ -810,8 +830,29 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
self.common.log('SettingsDialog', 'save_clicked')
|
||||
|
||||
def changed(s1, s2, keys):
|
||||
"""
|
||||
Compare the Settings objects s1 and s2 and return true if any values
|
||||
have changed for the given keys.
|
||||
"""
|
||||
for key in keys:
|
||||
if s1.get(key) != s2.get(key):
|
||||
return True
|
||||
return False
|
||||
|
||||
settings = self.settings_from_fields()
|
||||
if settings:
|
||||
# If language changed, inform user they need to restart OnionShare
|
||||
if changed(settings, self.old_settings, ['locale']):
|
||||
# Look up error message in different locale
|
||||
new_locale = settings.get('locale')
|
||||
if new_locale in strings.translations and 'gui_settings_language_changed_notice' in strings.translations[new_locale]:
|
||||
notice = strings.translations[new_locale]['gui_settings_language_changed_notice']
|
||||
else:
|
||||
notice = strings._('gui_settings_language_changed_notice')
|
||||
Alert(self.common, notice, QtWidgets.QMessageBox.Information)
|
||||
|
||||
# Save the new settings
|
||||
settings.save()
|
||||
|
||||
# If Tor isn't connected, or if Tor settings have changed, Reinitialize
|
||||
@ -820,15 +861,6 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
if not self.local_only:
|
||||
if self.onion.is_authenticated():
|
||||
self.common.log('SettingsDialog', 'save_clicked', 'Connected to Tor')
|
||||
def changed(s1, s2, keys):
|
||||
"""
|
||||
Compare the Settings objects s1 and s2 and return true if any values
|
||||
have changed for the given keys.
|
||||
"""
|
||||
for key in keys:
|
||||
if s1.get(key) != s2.get(key):
|
||||
return True
|
||||
return False
|
||||
|
||||
if changed(settings, self.old_settings, [
|
||||
'connection_type', 'control_port_address',
|
||||
@ -873,7 +905,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
self.common.log('SettingsDialog', 'cancel_clicked')
|
||||
if not self.local_only and not self.onion.is_authenticated():
|
||||
Alert(self.common, strings._('gui_tor_connection_canceled', True), QtWidgets.QMessageBox.Warning)
|
||||
Alert(self.common, strings._('gui_tor_connection_canceled'), QtWidgets.QMessageBox.Warning)
|
||||
sys.exit()
|
||||
else:
|
||||
self.close()
|
||||
@ -940,6 +972,12 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
if not self.stealth_checkbox.isChecked():
|
||||
settings.set('hidservauth_string', '')
|
||||
|
||||
# Language
|
||||
locale_index = self.language_combobox.currentIndex()
|
||||
locale = self.language_combobox.itemData(locale_index)
|
||||
settings.set('locale', locale)
|
||||
|
||||
# Tor connection
|
||||
if self.connection_type_bundled_radio.isChecked():
|
||||
settings.set('connection_type', 'bundled')
|
||||
if self.connection_type_automatic_radio.isChecked():
|
||||
@ -1013,7 +1051,7 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
new_bridges = ''.join(new_bridges)
|
||||
settings.set('tor_bridges_use_custom_bridges', new_bridges)
|
||||
else:
|
||||
Alert(self.common, strings._('gui_settings_tor_bridges_invalid', True))
|
||||
Alert(self.common, strings._('gui_settings_tor_bridges_invalid'))
|
||||
settings.set('no_bridges', True)
|
||||
return False
|
||||
|
||||
@ -1037,11 +1075,11 @@ class SettingsDialog(QtWidgets.QDialog):
|
||||
dt = datetime.datetime.fromtimestamp(autoupdate_timestamp)
|
||||
last_checked = dt.strftime('%B %d, %Y %H:%M')
|
||||
else:
|
||||
last_checked = strings._('gui_settings_autoupdate_timestamp_never', True)
|
||||
self.autoupdate_timestamp.setText(strings._('gui_settings_autoupdate_timestamp', True).format(last_checked))
|
||||
last_checked = strings._('gui_settings_autoupdate_timestamp_never')
|
||||
self.autoupdate_timestamp.setText(strings._('gui_settings_autoupdate_timestamp').format(last_checked))
|
||||
|
||||
def _tor_status_update(self, progress, summary):
|
||||
self.tor_status.setText('<strong>{}</strong><br>{}% {}'.format(strings._('connecting_to_tor', True), progress, summary))
|
||||
self.tor_status.setText('<strong>{}</strong><br>{}% {}'.format(strings._('connecting_to_tor'), progress, summary))
|
||||
self.qtapp.processEvents()
|
||||
if 'Done' in summary:
|
||||
self.tor_status.hide()
|
||||
|
163
onionshare_gui/share_mode/downloads.py
Normal file
163
onionshare_gui/share_mode/downloads.py
Normal file
@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
OnionShare | https://onionshare.org/
|
||||
|
||||
Copyright (C) 2014-2018 Micah Lee <micah@micahflee.com>
|
||||
|
||||
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 <http://www.gnu.org/licenses/>.
|
||||
"""
|
||||
import time
|
||||
from PyQt5 import QtCore, QtWidgets, QtGui
|
||||
|
||||
from onionshare import strings
|
||||
|
||||
|
||||
class Download(object):
|
||||
def __init__(self, common, download_id, total_bytes):
|
||||
self.common = common
|
||||
|
||||
self.download_id = download_id
|
||||
self.started = time.time()
|
||||
self.total_bytes = total_bytes
|
||||
self.downloaded_bytes = 0
|
||||
|
||||
# Progress bar
|
||||
self.progress_bar = QtWidgets.QProgressBar()
|
||||
self.progress_bar.setTextVisible(True)
|
||||
self.progress_bar.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
self.progress_bar.setAlignment(QtCore.Qt.AlignHCenter)
|
||||
self.progress_bar.setMinimum(0)
|
||||
self.progress_bar.setMaximum(total_bytes)
|
||||
self.progress_bar.setValue(0)
|
||||
self.progress_bar.setStyleSheet(self.common.css['downloads_uploads_progress_bar'])
|
||||
self.progress_bar.total_bytes = total_bytes
|
||||
|
||||
# Start at 0
|
||||
self.update(0)
|
||||
|
||||
def update(self, downloaded_bytes):
|
||||
self.downloaded_bytes = downloaded_bytes
|
||||
|
||||
self.progress_bar.setValue(downloaded_bytes)
|
||||
if downloaded_bytes == self.progress_bar.total_bytes:
|
||||
pb_fmt = strings._('gui_download_upload_progress_complete').format(
|
||||
self.common.format_seconds(time.time() - self.started))
|
||||
else:
|
||||
elapsed = time.time() - self.started
|
||||
if elapsed < 10:
|
||||
# Wait a couple of seconds for the download rate to stabilize.
|
||||
# This prevents a "Windows copy dialog"-esque experience at
|
||||
# the beginning of the download.
|
||||
pb_fmt = strings._('gui_download_upload_progress_starting').format(
|
||||
self.common.human_readable_filesize(downloaded_bytes))
|
||||
else:
|
||||
pb_fmt = strings._('gui_download_upload_progress_eta').format(
|
||||
self.common.human_readable_filesize(downloaded_bytes),
|
||||
self.estimated_time_remaining)
|
||||
|
||||
self.progress_bar.setFormat(pb_fmt)
|
||||
|
||||
def cancel(self):
|
||||
self.progress_bar.setFormat(strings._('gui_canceled'))
|
||||
|
||||
@property
|
||||
def estimated_time_remaining(self):
|
||||
return self.common.estimated_time_remaining(self.downloaded_bytes,
|
||||
self.total_bytes,
|
||||
self.started)
|
||||
|
||||
|
||||
class Downloads(QtWidgets.QScrollArea):
|
||||
"""
|
||||
The downloads chunk of the GUI. This lists all of the active download
|
||||
progress bars.
|
||||
"""
|
||||
def __init__(self, common):
|
||||
super(Downloads, self).__init__()
|
||||
self.common = common
|
||||
|
||||
self.downloads = {}
|
||||
|
||||
self.setWindowTitle(strings._('gui_downloads'))
|
||||
self.setWidgetResizable(True)
|
||||
self.setMinimumHeight(150)
|
||||
self.setMinimumWidth(350)
|
||||
self.setWindowIcon(QtGui.QIcon(common.get_resource_path('images/logo.png')))
|
||||
self.setWindowFlags(QtCore.Qt.Sheet | QtCore.Qt.WindowTitleHint | QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.CustomizeWindowHint)
|
||||
self.vbar = self.verticalScrollBar()
|
||||
self.vbar.rangeChanged.connect(self.resizeScroll)
|
||||
|
||||
downloads_label = QtWidgets.QLabel(strings._('gui_downloads'))
|
||||
downloads_label.setStyleSheet(self.common.css['downloads_uploads_label'])
|
||||
self.no_downloads_label = QtWidgets.QLabel(strings._('gui_no_downloads'))
|
||||
self.clear_history_button = QtWidgets.QPushButton(strings._('gui_clear_history'))
|
||||
self.clear_history_button.clicked.connect(self.reset)
|
||||
self.clear_history_button.hide()
|
||||
|
||||
self.downloads_layout = QtWidgets.QVBoxLayout()
|
||||
|
||||
widget = QtWidgets.QWidget()
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.addWidget(downloads_label)
|
||||
layout.addWidget(self.no_downloads_label)
|
||||
layout.addWidget(self.clear_history_button)
|
||||
layout.addLayout(self.downloads_layout)
|
||||
layout.addStretch()
|
||||
widget.setLayout(layout)
|
||||
self.setWidget(widget)
|
||||
|
||||
def resizeScroll(self, minimum, maximum):
|
||||
"""
|
||||
Scroll to the bottom of the window when the range changes.
|
||||
"""
|
||||
self.vbar.setValue(maximum)
|
||||
|
||||
def add(self, download_id, total_bytes):
|
||||
"""
|
||||
Add a new download progress bar.
|
||||
"""
|
||||
# Hide the no_downloads_label
|
||||
self.no_downloads_label.hide()
|
||||
# Show the clear_history_button
|
||||
self.clear_history_button.show()
|
||||
|
||||
# Add it to the list
|
||||
download = Download(self.common, download_id, total_bytes)
|
||||
self.downloads[download_id] = download
|
||||
self.downloads_layout.addWidget(download.progress_bar)
|
||||
|
||||
def update(self, download_id, downloaded_bytes):
|
||||
"""
|
||||
Update the progress of a download progress bar.
|
||||
"""
|
||||
self.downloads[download_id].update(downloaded_bytes)
|
||||
|
||||
def cancel(self, download_id):
|
||||
"""
|
||||
Update a download progress bar to show that it has been canceled.
|
||||
"""
|
||||
self.downloads[download_id].cancel()
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the downloads back to zero
|
||||
"""
|
||||
for download in self.downloads.values():
|
||||
self.downloads_layout.removeWidget(download.progress_bar)
|
||||
download.progress_bar.close()
|
||||
self.downloads = {}
|
||||
|
||||
self.no_downloads_label.show()
|
||||
self.clear_history_button.hide()
|
||||
self.resize(self.sizeHint())
|
@ -51,7 +51,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
||||
self.setFixedSize(400, 150)
|
||||
|
||||
# Label
|
||||
self.setLabelText(strings._('connecting_to_tor', True))
|
||||
self.setLabelText(strings._('connecting_to_tor'))
|
||||
|
||||
# Progress bar ticks from 0 to 100
|
||||
self.setRange(0, 100)
|
||||
@ -81,7 +81,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
||||
|
||||
def _tor_status_update(self, progress, summary):
|
||||
self.setValue(int(progress))
|
||||
self.setLabelText("<strong>{}</strong><br>{}".format(strings._('connecting_to_tor', True), summary))
|
||||
self.setLabelText("<strong>{}</strong><br>{}".format(strings._('connecting_to_tor'), summary))
|
||||
|
||||
def _connected_to_tor(self):
|
||||
self.common.log('TorConnectionDialog', '_connected_to_tor')
|
||||
@ -104,7 +104,7 @@ class TorConnectionDialog(QtWidgets.QProgressDialog):
|
||||
|
||||
def alert_and_open_settings():
|
||||
# Display the exception in an alert box
|
||||
Alert(self.common, "{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings', True)), QtWidgets.QMessageBox.Warning)
|
||||
Alert(self.common, "{}\n\n{}".format(msg, strings._('gui_tor_connection_error_settings')), QtWidgets.QMessageBox.Warning)
|
||||
|
||||
# Open settings
|
||||
self.open_settings.emit()
|
||||
|
@ -106,7 +106,6 @@
|
||||
"gui_settings_button_help": "Help",
|
||||
"gui_settings_shutdown_timeout_checkbox": "Use auto-stop timer",
|
||||
"gui_settings_shutdown_timeout": "Stop the share at:",
|
||||
"settings_saved": "Settings saved in {}",
|
||||
"settings_error_unknown": "Can't connect to Tor controller because your settings don't make sense.",
|
||||
"settings_error_automatic": "Could not connect to the Tor controller. Is Tor Browser (available from torproject.org) running in the background?",
|
||||
"settings_error_socket_port": "Can't connect to the Tor controller at {}:{}.",
|
||||
@ -181,5 +180,7 @@
|
||||
"gui_upload_finished_range": "Uploaded {} to {}",
|
||||
"gui_upload_finished": "Uploaded {}",
|
||||
"gui_download_in_progress": "Download Started {}",
|
||||
"gui_open_folder_error_nautilus": "Cannot open folder because nautilus is not available. The file is here: {}"
|
||||
"gui_open_folder_error_nautilus": "Cannot open folder because nautilus is not available. The file is here: {}",
|
||||
"gui_settings_language_label": "Preferred language",
|
||||
"gui_settings_language_changed_notice": "Restart OnionShare for your change in language to take effect."
|
||||
}
|
||||
|
@ -29,5 +29,6 @@
|
||||
"gui_please_wait": "Attendez-vous...",
|
||||
"gui_quit_warning_quit": "Quitter",
|
||||
"gui_quit_warning_dont_quit": "Ne quitter pas",
|
||||
"gui_settings_autoupdate_timestamp_never": "Jamais"
|
||||
"gui_settings_autoupdate_timestamp_never": "Jamais",
|
||||
"gui_settings_language_changed_notice": "Redémarrez OnionShare pour que votre changement de langue prenne effet"
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
from onionshare import common, web, settings
|
||||
from onionshare import common, web, settings, strings
|
||||
|
||||
@pytest.fixture
|
||||
def temp_dir_1024():
|
||||
@ -151,7 +151,10 @@ def time_strftime(monkeypatch):
|
||||
|
||||
@pytest.fixture
|
||||
def common_obj():
|
||||
return common.Common()
|
||||
_common = common.Common()
|
||||
_common.settings = settings.Settings(_common)
|
||||
strings.load_strings(_common)
|
||||
return _common
|
||||
|
||||
@pytest.fixture
|
||||
def settings_obj(sys_onionshare_dev_mode, platform_linux):
|
||||
|
@ -40,7 +40,7 @@ def settings_obj(sys_onionshare_dev_mode, platform_linux):
|
||||
|
||||
class TestSettings:
|
||||
def test_init(self, settings_obj):
|
||||
assert settings_obj._settings == settings_obj.default_settings == {
|
||||
expected_settings = {
|
||||
'version': 'DUMMY_VERSION_1.2.3',
|
||||
'connection_type': 'bundled',
|
||||
'control_port_address': '127.0.0.1',
|
||||
@ -68,6 +68,11 @@ class TestSettings:
|
||||
'receive_allow_receiver_shutdown': True,
|
||||
'public_mode': False
|
||||
}
|
||||
for key in settings_obj._settings:
|
||||
# Skip locale, it will not always default to the same thing
|
||||
if key != 'locale':
|
||||
assert settings_obj._settings[key] == settings_obj.default_settings[key]
|
||||
assert settings_obj._settings[key] == expected_settings[key]
|
||||
|
||||
def test_fill_in_defaults(self, settings_obj):
|
||||
del settings_obj._settings['version']
|
||||
|
@ -32,12 +32,6 @@ from onionshare import strings
|
||||
# return path
|
||||
# common.get_resource_path = get_resource_path
|
||||
|
||||
|
||||
def test_starts_with_empty_strings():
|
||||
""" Creates an empty strings dict by default """
|
||||
assert strings.strings == {}
|
||||
|
||||
|
||||
def test_underscore_is_function():
|
||||
assert callable(strings._) and isinstance(strings._, types.FunctionType)
|
||||
|
||||
@ -53,11 +47,13 @@ class TestLoadStrings:
|
||||
def test_load_strings_loads_other_languages(
|
||||
self, common_obj, locale_fr, sys_onionshare_dev_mode):
|
||||
""" load_strings() loads other languages in different locales """
|
||||
strings.load_strings(common_obj, "fr")
|
||||
common_obj.settings.set('locale', 'fr')
|
||||
strings.load_strings(common_obj)
|
||||
assert strings._('preparing_files') == "Préparation des fichiers à partager."
|
||||
|
||||
def test_load_invalid_locale(
|
||||
self, common_obj, locale_invalid, sys_onionshare_dev_mode):
|
||||
""" load_strings() raises a KeyError for an invalid locale """
|
||||
with pytest.raises(KeyError):
|
||||
strings.load_strings(common_obj, 'XX')
|
||||
common_obj.settings.set('locale', 'XX')
|
||||
strings.load_strings(common_obj)
|
||||
|
@ -3,14 +3,62 @@ import requests
|
||||
import socket
|
||||
import socks
|
||||
import zipfile
|
||||
import json
|
||||
import shutil
|
||||
|
||||
from PyQt5 import QtCore, QtTest
|
||||
|
||||
from onionshare import strings
|
||||
from onionshare_gui.mode.receive_mode import ReceiveMode
|
||||
from onionshare.common import Common
|
||||
from onionshare.settings import Settings
|
||||
from onionshare.onion import Onion
|
||||
from onionshare.web import Web
|
||||
from onionshare_gui import Application, OnionShare, OnionShareGui
|
||||
from onionshare_gui.mode.share_mode import ShareMode
|
||||
from onionshare_gui.mode.receive_mode import ReceiveMode
|
||||
|
||||
|
||||
class CommonTests(object):
|
||||
@staticmethod
|
||||
def set_up(test_settings):
|
||||
'''Create GUI with given settings'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
|
||||
common = Common()
|
||||
common.settings = Settings(common)
|
||||
common.define_css()
|
||||
strings.load_strings(common)
|
||||
|
||||
# Get all of the settings in test_settings
|
||||
test_settings['downloads_dir'] = '/tmp/OnionShare'
|
||||
for key, val in common.settings.default_settings.items():
|
||||
if key not in test_settings:
|
||||
test_settings[key] = val
|
||||
|
||||
# Start the Onion
|
||||
testonion = Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
settings_filename = '/tmp/testsettings.json'
|
||||
open(settings_filename, 'w').write(json.dumps(test_settings))
|
||||
|
||||
gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], settings_filename, True)
|
||||
return gui
|
||||
|
||||
@staticmethod
|
||||
def tear_down():
|
||||
try:
|
||||
os.remove('/tmp/test.txt')
|
||||
shutil.rmtree('/tmp/OnionShare')
|
||||
except:
|
||||
pass
|
||||
|
||||
def test_gui_loaded(self):
|
||||
'''Test that the GUI actually is shown'''
|
||||
self.assertTrue(self.gui.show)
|
||||
@ -190,12 +238,12 @@ class CommonTests(object):
|
||||
def test_server_status_indicator_says_closed(self, mode, stay_open):
|
||||
'''Test that the Server Status indicator shows we closed'''
|
||||
if type(mode) == ReceiveMode:
|
||||
self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped', True))
|
||||
self.assertEquals(self.gui.receive_mode.server_status_label.text(), strings._('gui_status_indicator_receive_stopped'))
|
||||
if type(mode) == ShareMode:
|
||||
if stay_open:
|
||||
self.assertEqual(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_stopped', True))
|
||||
self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('gui_status_indicator_share_stopped'))
|
||||
else:
|
||||
self.assertEqual(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically', True))
|
||||
self.assertEquals(self.gui.share_mode.server_status_label.text(), strings._('closing_automatically'))
|
||||
|
||||
# Auto-stop timer tests
|
||||
def test_set_timeout(self, mode, timeout):
|
||||
|
@ -15,68 +15,17 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": True,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": False,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": False,
|
||||
"shutdown_timeout": False,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"receive_allow_receiver_shutdown": True
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
os.remove('/tmp/test.txt')
|
||||
os.remove('/tmp/OnionShare/test.txt')
|
||||
os.remove('/tmp/OnionShare/test-2.txt')
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -8,6 +8,7 @@ import json
|
||||
from PyQt5 import QtWidgets
|
||||
|
||||
from onionshare.common import Common
|
||||
from onionshare.settings import Settings
|
||||
from onionshare.web import Web
|
||||
from onionshare import onion, strings
|
||||
from onionshare_gui import *
|
||||
@ -15,71 +16,17 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": True,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": True,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": False,
|
||||
"shutdown_timeout": False,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"receive_allow_receiver_shutdown": True
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
try:
|
||||
os.remove('/tmp/test.txt')
|
||||
os.remove('/tmp/OnionShare/test.txt')
|
||||
os.remove('/tmp/OnionShare/test-2.txt')
|
||||
except:
|
||||
pass
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -15,66 +15,17 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": True,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": False,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": False,
|
||||
"shutdown_timeout": False,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"close_after_first_download": True
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
os.remove('/tmp/test.txt')
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -15,66 +15,16 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": True,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": True,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": False,
|
||||
"shutdown_timeout": False,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"public_mode": True
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
os.remove('/tmp/test.txt')
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -15,66 +15,17 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": False,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": True,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": False,
|
||||
"shutdown_timeout": False,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"close_after_first_download": False
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
os.remove('/tmp/test.txt')
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -15,68 +15,18 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
slug = ''
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": True,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": False,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": True,
|
||||
"shutdown_timeout": False,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"save_private_key": True
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
os.remove('/tmp/test.txt')
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -15,66 +15,17 @@ from onionshare_gui import *
|
||||
from .commontests import CommonTests
|
||||
|
||||
class OnionShareGuiTest(unittest.TestCase):
|
||||
'''Test the OnionShare GUI'''
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
'''Create the GUI'''
|
||||
# Create our test file
|
||||
testfile = open('/tmp/test.txt', 'w')
|
||||
testfile.write('onionshare')
|
||||
testfile.close()
|
||||
common = Common()
|
||||
common.define_css()
|
||||
|
||||
# Start the Onion
|
||||
strings.load_strings(common)
|
||||
|
||||
testonion = onion.Onion(common)
|
||||
global qtapp
|
||||
qtapp = Application(common)
|
||||
app = OnionShare(common, testonion, True, 0)
|
||||
|
||||
web = Web(common, False, True)
|
||||
|
||||
test_settings = {
|
||||
"auth_password": "",
|
||||
"auth_type": "no_auth",
|
||||
"autoupdate_timestamp": "",
|
||||
"close_after_first_download": True,
|
||||
"connection_type": "bundled",
|
||||
"control_port_address": "127.0.0.1",
|
||||
"control_port_port": 9051,
|
||||
"downloads_dir": "/tmp/OnionShare",
|
||||
"hidservauth_string": "",
|
||||
"no_bridges": True,
|
||||
"private_key": "",
|
||||
"public_mode": False,
|
||||
"receive_allow_receiver_shutdown": True,
|
||||
"save_private_key": False,
|
||||
"shutdown_timeout": True,
|
||||
"slug": "",
|
||||
"socks_address": "127.0.0.1",
|
||||
"socks_port": 9050,
|
||||
"socket_file_path": "/var/run/tor/control",
|
||||
"systray_notifications": True,
|
||||
"tor_bridges_use_meek_lite_azure": False,
|
||||
"tor_bridges_use_meek_lite_amazon": False,
|
||||
"tor_bridges_use_custom_bridges": "",
|
||||
"tor_bridges_use_obfs4": False,
|
||||
"use_stealth": False,
|
||||
"use_legacy_v2_onions": False,
|
||||
"use_autoupdate": True,
|
||||
"version": "1.3.1"
|
||||
"shutdown_timeout": True
|
||||
}
|
||||
testsettings = '/tmp/testsettings.json'
|
||||
open(testsettings, 'w').write(json.dumps(test_settings))
|
||||
|
||||
cls.gui = OnionShareGui(common, testonion, qtapp, app, ['/tmp/test.txt'], testsettings, True)
|
||||
cls.gui = CommonTests.set_up(test_settings)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
'''Clean up after tests'''
|
||||
os.remove('/tmp/test.txt')
|
||||
CommonTests.tear_down()
|
||||
|
||||
@pytest.mark.run(order=1)
|
||||
def test_gui_loaded(self):
|
||||
|
@ -56,6 +56,6 @@ class CommonTests(LocalCommonTests):
|
||||
self.gui.app.onion.cleanup(stop_tor=True)
|
||||
QtTest.QTest.qWait(2500)
|
||||
if mode == 'share':
|
||||
self.assertTrue(self.gui.share_mode.status_bar.currentMessage(), strings._('gui_tor_connection_lost', True))
|
||||
self.assertTrue(self.gui.share_mode.status_bar.currentMessage(), strings._('gui_tor_connection_lost'))
|
||||
if mode == 'receive':
|
||||
self.assertTrue(self.gui.receive_mode.status_bar.currentMessage(), strings._('gui_tor_connection_lost', True))
|
||||
self.assertTrue(self.gui.receive_mode.status_bar.currentMessage(), strings._('gui_tor_connection_lost'))
|
||||
|
@ -8,7 +8,7 @@ import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
from onionshare import common, web, settings
|
||||
from onionshare import common, web, settings, strings
|
||||
|
||||
@pytest.fixture
|
||||
def temp_dir_1024():
|
||||
@ -151,7 +151,10 @@ def time_strftime(monkeypatch):
|
||||
|
||||
@pytest.fixture
|
||||
def common_obj():
|
||||
return common.Common()
|
||||
_common = common.Common()
|
||||
_common.settings = settings.Settings(_common)
|
||||
strings.load_strings(_common)
|
||||
return _common
|
||||
|
||||
@pytest.fixture
|
||||
def settings_obj(sys_onionshare_dev_mode, platform_linux):
|
||||
|
Loading…
Reference in New Issue
Block a user