aboutsummaryrefslogtreecommitdiff
path: root/desktop/onionshare/settings_tab.py
diff options
context:
space:
mode:
Diffstat (limited to 'desktop/onionshare/settings_tab.py')
-rw-r--r--desktop/onionshare/settings_tab.py354
1 files changed, 354 insertions, 0 deletions
diff --git a/desktop/onionshare/settings_tab.py b/desktop/onionshare/settings_tab.py
new file mode 100644
index 00000000..cfa3261e
--- /dev/null
+++ b/desktop/onionshare/settings_tab.py
@@ -0,0 +1,354 @@
+# -*- coding: utf-8 -*-
+"""
+OnionShare | https://onionshare.org/
+
+Copyright (C) 2014-2021 Micah Lee, et al. <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/>.
+"""
+
+from PySide2 import QtCore, QtWidgets, QtGui
+import platform
+import datetime
+from onionshare_cli.settings import Settings
+
+from . import strings
+from .widgets import Alert
+from .update_checker import UpdateThread
+
+
+class SettingsTab(QtWidgets.QWidget):
+ """
+ Settings dialog.
+ """
+
+ close_this_tab = QtCore.Signal()
+
+ def __init__(self, common, tab_id):
+ super(SettingsTab, self).__init__()
+
+ self.common = common
+ self.common.log("SettingsTab", "__init__")
+
+ self.system = platform.system()
+ self.tab_id = tab_id
+
+ # Automatic updates options
+
+ # Autoupdate
+ self.autoupdate_checkbox = QtWidgets.QCheckBox()
+ self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked)
+ 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")
+ )
+ 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.common.gui.onion.connected_to_tor:
+ self.check_for_updates_button.setEnabled(False)
+
+ # Autoupdate options layout
+ autoupdate_group_layout = QtWidgets.QVBoxLayout()
+ 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")
+ )
+ autoupdate_group.setLayout(autoupdate_group_layout)
+
+ autoupdate_layout = QtWidgets.QHBoxLayout()
+ autoupdate_layout.addStretch()
+ autoupdate_layout.addWidget(autoupdate_group)
+ autoupdate_layout.addStretch()
+ autoupdate_widget = QtWidgets.QWidget()
+ autoupdate_widget.setLayout(autoupdate_layout)
+
+ # Autoupdate is only available for Windows and Mac (Linux updates using package manager)
+ if self.system != "Windows" and self.system != "Darwin":
+ autoupdate_widget.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, locale)
+ language_layout = QtWidgets.QHBoxLayout()
+ language_layout.addStretch()
+ language_layout.addWidget(language_label)
+ language_layout.addWidget(self.language_combobox)
+ language_layout.addStretch()
+
+ # Theme Settings
+ theme_label = QtWidgets.QLabel(strings._("gui_settings_theme_label"))
+ self.theme_combobox = QtWidgets.QComboBox()
+ theme_choices = [
+ strings._("gui_settings_theme_auto"),
+ strings._("gui_settings_theme_light"),
+ strings._("gui_settings_theme_dark"),
+ ]
+ self.theme_combobox.addItems(theme_choices)
+ theme_layout = QtWidgets.QHBoxLayout()
+ theme_layout.addStretch()
+ theme_layout.addWidget(theme_label)
+ theme_layout.addWidget(self.theme_combobox)
+ theme_layout.addStretch()
+
+ # Version and help
+ version_label = QtWidgets.QLabel(
+ strings._("gui_settings_version_label").format(self.common.version)
+ )
+ version_label.setAlignment(QtCore.Qt.AlignHCenter)
+ help_label = QtWidgets.QLabel(strings._("gui_settings_help_label"))
+ help_label.setAlignment(QtCore.Qt.AlignHCenter)
+ help_label.setTextInteractionFlags(QtCore.Qt.TextBrowserInteraction)
+ help_label.setOpenExternalLinks(True)
+
+ # Buttons
+ self.save_button = QtWidgets.QPushButton(strings._("gui_settings_button_save"))
+ self.save_button.clicked.connect(self.save_clicked)
+ buttons_layout = QtWidgets.QHBoxLayout()
+ buttons_layout.addStretch()
+ buttons_layout.addWidget(self.save_button)
+ buttons_layout.addStretch()
+
+ # Layout
+ layout = QtWidgets.QVBoxLayout()
+ layout.addStretch()
+ layout.addWidget(autoupdate_widget)
+ if autoupdate_widget.isVisible():
+ layout.addSpacing(20)
+ layout.addLayout(language_layout)
+ layout.addLayout(theme_layout)
+ layout.addSpacing(20)
+ layout.addWidget(version_label)
+ layout.addWidget(help_label)
+ layout.addSpacing(20)
+ layout.addLayout(buttons_layout)
+ layout.addStretch()
+
+ self.setLayout(layout)
+
+ self.reload_settings()
+
+ if self.common.gui.onion.connected_to_tor:
+ self.tor_is_connected()
+ else:
+ self.tor_is_disconnected()
+
+ def reload_settings(self):
+ # Load settings, and fill them in
+ self.old_settings = Settings(self.common)
+ self.old_settings.load()
+
+ use_autoupdate = self.old_settings.get("use_autoupdate")
+ if use_autoupdate:
+ self.autoupdate_checkbox.setCheckState(QtCore.Qt.Checked)
+ else:
+ self.autoupdate_checkbox.setCheckState(QtCore.Qt.Unchecked)
+
+ 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(locale)
+ self.language_combobox.setCurrentIndex(locale_index)
+
+ theme_choice = self.old_settings.get("theme")
+ self.theme_combobox.setCurrentIndex(theme_choice)
+
+ def check_for_updates(self):
+ """
+ Check for Updates button clicked. Manually force an update check.
+ """
+ self.common.log("SettingsTab", "check_for_updates")
+ # Disable buttons
+ self._disable_buttons()
+ self.common.gui.qtapp.processEvents()
+
+ def update_timestamp():
+ # Update the last checked label
+ settings = Settings(self.common)
+ settings.load()
+ autoupdate_timestamp = settings.get("autoupdate_timestamp")
+ self._update_autoupdate_timestamp(autoupdate_timestamp)
+
+ def close_forced_update_thread():
+ forced_update_thread.quit()
+ # Enable buttons
+ self._enable_buttons()
+ # Update timestamp
+ update_timestamp()
+
+ # Check for updates
+ def update_available(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"))
+ close_forced_update_thread()
+
+ def update_error():
+ 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").format(latest_version),
+ QtWidgets.QMessageBox.Warning,
+ )
+ close_forced_update_thread()
+
+ forced_update_thread = UpdateThread(
+ self.common, self.common.gui.onion, force=True
+ )
+ forced_update_thread.update_available.connect(update_available)
+ forced_update_thread.update_not_available.connect(update_not_available)
+ forced_update_thread.update_error.connect(update_error)
+ forced_update_thread.update_invalid_version.connect(update_invalid_version)
+ forced_update_thread.start()
+
+ def save_clicked(self):
+ """
+ Save button clicked. Save current settings to disk.
+ """
+ self.common.log("SettingsTab", "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)
+
+ # If color mode changed, inform user they need to restart OnionShare
+ if changed(settings, self.old_settings, ["theme"]):
+ notice = strings._("gui_color_mode_changed_notice")
+ Alert(self.common, notice, QtWidgets.QMessageBox.Information)
+
+ # Save the new settings
+ settings.save()
+ self.close_this_tab.emit()
+
+ def help_clicked(self):
+ """
+ Help button clicked.
+ """
+ self.common.log("SettingsTab", "help_clicked")
+ SettingsTab.open_help()
+
+ @staticmethod
+ def open_help():
+ help_url = "https://docs.onionshare.org/"
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(help_url))
+
+ def settings_from_fields(self):
+ """
+ Return a Settings object that's full of values from the settings dialog.
+ """
+ self.common.log("SettingsTab", "settings_from_fields")
+ settings = Settings(self.common)
+ settings.load() # To get the last update timestamp
+
+ # Theme
+ theme_index = self.theme_combobox.currentIndex()
+ settings.set("theme", theme_index)
+
+ # Language
+ locale_index = self.language_combobox.currentIndex()
+ locale = self.language_combobox.itemData(locale_index)
+ settings.set("locale", locale)
+
+ return settings
+
+ def settings_have_changed(self):
+ # Global settings have changed
+ self.common.log("SettingsTab", "settings_have_changed")
+
+ def _update_autoupdate_timestamp(self, autoupdate_timestamp):
+ self.common.log("SettingsTab", "_update_autoupdate_timestamp")
+
+ if autoupdate_timestamp:
+ dt = datetime.datetime.fromtimestamp(autoupdate_timestamp)
+ last_checked = dt.strftime("%B %d, %Y %H:%M")
+ else:
+ last_checked = strings._("gui_settings_autoupdate_timestamp_never")
+ self.autoupdate_timestamp.setText(
+ strings._("gui_settings_autoupdate_timestamp").format(last_checked)
+ )
+
+ def _disable_buttons(self):
+ self.common.log("SettingsTab", "_disable_buttons")
+
+ self.check_for_updates_button.setEnabled(False)
+ self.save_button.setEnabled(False)
+
+ def _enable_buttons(self):
+ self.common.log("SettingsTab", "_enable_buttons")
+ # We can't check for updates if we're still not connected to Tor
+ if not self.common.gui.onion.connected_to_tor:
+ self.check_for_updates_button.setEnabled(False)
+ else:
+ self.check_for_updates_button.setEnabled(True)
+ self.save_button.setEnabled(True)
+
+ def tor_is_connected(self):
+ self.check_for_updates_button.show()
+
+ def tor_is_disconnected(self):
+ self.check_for_updates_button.hide()