diff options
Diffstat (limited to 'onionshare_gui/mode/share_mode')
-rw-r--r-- | onionshare_gui/mode/share_mode/__init__.py | 92 | ||||
-rw-r--r-- | onionshare_gui/mode/share_mode/file_selection.py | 430 | ||||
-rw-r--r-- | onionshare_gui/mode/share_mode/threads.py | 21 |
3 files changed, 69 insertions, 474 deletions
diff --git a/onionshare_gui/mode/share_mode/__init__.py b/onionshare_gui/mode/share_mode/__init__.py index 6cb50b2b..d0cc6a04 100644 --- a/onionshare_gui/mode/share_mode/__init__.py +++ b/onionshare_gui/mode/share_mode/__init__.py @@ -25,7 +25,7 @@ from onionshare.onion import * from onionshare.common import Common from onionshare.web import Web -from .file_selection import FileSelection +from ..file_selection import FileSelection from .threads import CompressThread from .. import Mode from ..history import History, ToggleHistory, ShareHistoryItem @@ -36,6 +36,7 @@ class ShareMode(Mode): """ Parts of the main window UI for sharing files. """ + def init(self): """ Custom initialization for ReceiveMode. @@ -44,7 +45,7 @@ class ShareMode(Mode): self.compress_thread = None # Create the Web object - self.web = Web(self.common, True, 'share') + self.web = Web(self.common, True, "share") # File selection self.file_selection = FileSelection(self.common, self) @@ -53,7 +54,7 @@ class ShareMode(Mode): self.file_selection.file_list.add_file(filename) # Server status - self.server_status.set_mode('share', self.file_selection) + self.server_status.set_mode("share", self.file_selection) self.server_status.server_started.connect(self.file_selection.server_started) self.server_status.server_stopped.connect(self.file_selection.server_stopped) self.server_status.server_stopped.connect(self.update_primary_action) @@ -68,15 +69,19 @@ class ShareMode(Mode): # Filesize warning self.filesize_warning = QtWidgets.QLabel() self.filesize_warning.setWordWrap(True) - self.filesize_warning.setStyleSheet(self.common.css['share_filesize_warning']) + self.filesize_warning.setStyleSheet(self.common.css["share_filesize_warning"]) self.filesize_warning.hide() # Download history self.history = History( self.common, - QtGui.QPixmap.fromImage(QtGui.QImage(self.common.get_resource_path('images/share_icon_transparent.png'))), - strings._('gui_share_mode_no_files'), - strings._('gui_all_modes_history') + QtGui.QPixmap.fromImage( + QtGui.QImage( + self.common.get_resource_path("images/share_icon_transparent.png") + ) + ), + strings._("gui_share_mode_no_files"), + strings._("gui_all_modes_history"), ) self.history.hide() @@ -86,9 +91,13 @@ class ShareMode(Mode): # Toggle history self.toggle_history = ToggleHistory( - self.common, self, self.history, - QtGui.QIcon(self.common.get_resource_path('images/share_icon_toggle.png')), - QtGui.QIcon(self.common.get_resource_path('images/share_icon_toggle_selected.png')) + self.common, + self, + self.history, + QtGui.QIcon(self.common.get_resource_path("images/share_icon_toggle.png")), + QtGui.QIcon( + self.common.get_resource_path("images/share_icon_toggle_selected.png") + ), ) # Top bar @@ -125,20 +134,22 @@ class ShareMode(Mode): """ Return the string to put on the stop server button, if there's an auto-stop timer """ - return strings._('gui_share_stop_server_autostop_timer') + return strings._("gui_share_stop_server_autostop_timer") def autostop_timer_finished_should_stop_server(self): """ The auto-stop timer expired, should we stop the server? Returns a bool """ # 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: + if self.web.share_mode.cur_history_id == 0 or self.web.done: self.server_status.stop_server() - self.server_status_label.setText(strings._('close_on_autostop_timer')) + self.server_status_label.setText(strings._("close_on_autostop_timer")) return True # A download is probably still running - hold off on stopping the share else: - self.server_status_label.setText(strings._('gui_share_mode_autostop_timer_waiting')) + self.server_status_label.setText( + strings._("gui_share_mode_autostop_timer_waiting") + ) return False def start_server_custom(self): @@ -146,8 +157,8 @@ class ShareMode(Mode): Starting the server. """ # Reset web counters - self.web.share_mode.download_count = 0 - self.web.error404_count = 0 + self.web.share_mode.cur_history_id = 0 + self.web.reset_invalid_passwords() # Hide and reset the downloads if we have previously shared self.reset_info_counters() @@ -162,7 +173,9 @@ class ShareMode(Mode): for index in range(self.file_selection.file_list.count()): self.filenames.append(self.file_selection.file_list.item(index).filename) - self._zip_progress_bar.total_files_size = ShareMode._compute_total_size(self.filenames) + self._zip_progress_bar.total_files_size = ShareMode._compute_total_size( + self.filenames + ) self.status_bar.insertWidget(0, self._zip_progress_bar) # prepare the files for sending in a new thread @@ -216,7 +229,7 @@ class ShareMode(Mode): Stop the compression thread on cancel """ if self.compress_thread: - self.common.log('ShareMode', 'cancel_server: quitting compress thread') + self.common.log("ShareMode", "cancel_server: quitting compress thread") self.compress_thread.quit() def handle_tor_broke_custom(self): @@ -225,12 +238,6 @@ class ShareMode(Mode): """ self.primary_action.hide() - def handle_request_load(self, event): - """ - Handle REQUEST_LOAD event. - """ - self.system_tray.showMessage(strings._('systray_page_loaded_title'), strings._('systray_page_loaded_message')) - def handle_request_started(self, event): """ Handle REQUEST_STARTED event. @@ -246,7 +253,10 @@ class ShareMode(Mode): self.history.in_progress_count += 1 self.history.update_in_progress() - self.system_tray.showMessage(strings._('systray_share_started_title'), strings._('systray_share_started_message')) + self.system_tray.showMessage( + strings._("systray_share_started_title"), + strings._("systray_share_started_message"), + ) def handle_request_progress(self, event): """ @@ -256,7 +266,10 @@ class ShareMode(Mode): # Is the download complete? if event["data"]["bytes"] == self.web.share_mode.filesize: - self.system_tray.showMessage(strings._('systray_share_completed_title'), strings._('systray_share_completed_message')) + self.system_tray.showMessage( + strings._("systray_share_completed_title"), + strings._("systray_share_completed_message"), + ) # Update completed and in progress labels self.history.completed_count += 1 @@ -265,10 +278,10 @@ class ShareMode(Mode): self.history.update_in_progress() # Close on finish? - if self.common.settings.get('close_after_first_download'): + 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')) + 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"]) @@ -284,7 +297,10 @@ class ShareMode(Mode): # Update in progress count self.history.in_progress_count -= 1 self.history.update_in_progress() - self.system_tray.showMessage(strings._('systray_share_canceled_title'), strings._('systray_share_canceled_message')) + self.system_tray.showMessage( + strings._("systray_share_canceled_title"), + strings._("systray_share_canceled_message"), + ) def on_reload_settings(self): """ @@ -296,7 +312,7 @@ class ShareMode(Mode): self.info_label.show() def update_primary_action(self): - self.common.log('ShareMode', 'update_primary_action') + self.common.log("ShareMode", "update_primary_action") # Show or hide primary action layout file_count = self.file_selection.file_list.count() @@ -312,9 +328,15 @@ 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').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').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() @@ -325,6 +347,8 @@ class ShareMode(Mode): Set the info counters back to zero. """ self.history.reset() + self.toggle_history.indicator_count = 0 + self.toggle_history.update_indicator() @staticmethod def _compute_total_size(filenames): @@ -347,8 +371,8 @@ class ZipProgressBar(QtWidgets.QProgressBar): self.setMaximumHeight(20) self.setMinimumWidth(200) self.setValue(0) - self.setFormat(strings._('zip_progress_bar_format')) - self.setStyleSheet(self.common.css['share_zip_progess_bar']) + self.setFormat(strings._("zip_progress_bar_format")) + self.setStyleSheet(self.common.css["share_zip_progess_bar"]) self._total_files_size = total_files_size self._processed_size = 0 diff --git a/onionshare_gui/mode/share_mode/file_selection.py b/onionshare_gui/mode/share_mode/file_selection.py deleted file mode 100644 index 0d4229fe..00000000 --- a/onionshare_gui/mode/share_mode/file_selection.py +++ /dev/null @@ -1,430 +0,0 @@ -# -*- 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 -from PyQt5 import QtCore, QtWidgets, QtGui - -from onionshare import strings - -from ...widgets import Alert, AddFileDialog - -class DropHereLabel(QtWidgets.QLabel): - """ - When there are no files or folders in the FileList yet, display the - 'drop files here' message and graphic. - """ - def __init__(self, common, parent, image=False): - self.parent = parent - super(DropHereLabel, self).__init__(parent=parent) - - self.common = common - - self.setAcceptDrops(True) - self.setAlignment(QtCore.Qt.AlignCenter) - - 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')) - self.setStyleSheet(self.common.css['share_file_selection_drop_here_label']) - - self.hide() - - def dragEnterEvent(self, event): - self.parent.drop_here_image.hide() - self.parent.drop_here_text.hide() - event.accept() - - -class DropCountLabel(QtWidgets.QLabel): - """ - While dragging files over the FileList, this counter displays the - number of files you're dragging. - """ - def __init__(self, common, parent): - self.parent = parent - super(DropCountLabel, self).__init__(parent=parent) - - self.common = common - - self.setAcceptDrops(True) - self.setAlignment(QtCore.Qt.AlignCenter) - self.setText(strings._('gui_drag_and_drop')) - self.setStyleSheet(self.common.css['share_file_selection_drop_count_label']) - self.hide() - - def dragEnterEvent(self, event): - self.hide() - event.accept() - - -class FileList(QtWidgets.QListWidget): - """ - The list of files and folders in the GUI. - """ - files_dropped = QtCore.pyqtSignal() - files_updated = QtCore.pyqtSignal() - - def __init__(self, common, parent=None): - super(FileList, self).__init__(parent) - - self.common = common - - self.setAcceptDrops(True) - self.setIconSize(QtCore.QSize(32, 32)) - self.setSortingEnabled(True) - self.setMinimumHeight(160) - self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - self.drop_here_image = DropHereLabel(self.common, self, True) - self.drop_here_text = DropHereLabel(self.common, self, False) - self.drop_count = DropCountLabel(self.common, self) - self.resizeEvent(None) - self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - - def update(self): - """ - Update the GUI elements based on the current state. - """ - # file list should have a background image if empty - if self.count() == 0: - self.drop_here_image.show() - self.drop_here_text.show() - else: - self.drop_here_image.hide() - self.drop_here_text.hide() - - def server_started(self): - """ - Update the GUI when the server starts, by hiding delete buttons. - """ - self.setAcceptDrops(False) - self.setCurrentItem(None) - self.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection) - for index in range(self.count()): - self.item(index).item_button.hide() - - def server_stopped(self): - """ - Update the GUI when the server stops, by showing delete buttons. - """ - self.setAcceptDrops(True) - self.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection) - for index in range(self.count()): - self.item(index).item_button.show() - - def resizeEvent(self, event): - """ - When the widget is resized, resize the drop files image and text. - """ - offset = 70 - self.drop_here_image.setGeometry(0, 0, self.width(), self.height() - offset) - self.drop_here_text.setGeometry(0, offset, self.width(), self.height() - offset) - - if self.count() > 0: - # Add and delete an empty item, to force all items to get redrawn - # This is ugly, but the only way I could figure out how to proceed - item = QtWidgets.QListWidgetItem('fake item') - self.addItem(item) - self.takeItem(self.row(item)) - self.update() - - # Extend any filenames that were truncated to fit the window - # We use 200 as a rough guess at how wide the 'file size + delete button' widget is - # and extend based on the overall width minus that amount. - for index in range(self.count()): - metrics = QtGui.QFontMetrics(self.item(index).font()) - elided = metrics.elidedText(self.item(index).basename, QtCore.Qt.ElideRight, self.width() - 200) - self.item(index).setText(elided) - - - def dragEnterEvent(self, event): - """ - dragEnterEvent for dragging files and directories into the widget. - """ - if event.mimeData().hasUrls: - self.setStyleSheet(self.common.css['share_file_list_drag_enter']) - count = len(event.mimeData().urls()) - self.drop_count.setText('+{}'.format(count)) - - size_hint = self.drop_count.sizeHint() - self.drop_count.setGeometry(self.width() - size_hint.width() - 10, self.height() - size_hint.height() - 10, size_hint.width(), size_hint.height()) - self.drop_count.show() - event.accept() - else: - event.ignore() - - def dragLeaveEvent(self, event): - """ - dragLeaveEvent for dragging files and directories into the widget. - """ - self.setStyleSheet(self.common.css['share_file_list_drag_leave']) - self.drop_count.hide() - event.accept() - self.update() - - def dragMoveEvent(self, event): - """ - dragMoveEvent for dragging files and directories into the widget. - """ - if event.mimeData().hasUrls: - event.setDropAction(QtCore.Qt.CopyAction) - event.accept() - else: - event.ignore() - - def dropEvent(self, event): - """ - dropEvent for dragging files and directories into the widget. - """ - if event.mimeData().hasUrls: - event.setDropAction(QtCore.Qt.CopyAction) - event.accept() - for url in event.mimeData().urls(): - filename = str(url.toLocalFile()) - self.add_file(filename) - else: - event.ignore() - - self.setStyleSheet(self.common.css['share_file_list_drag_leave']) - self.drop_count.hide() - - self.files_dropped.emit() - - def add_file(self, filename): - """ - Add a file or directory to this widget. - """ - filenames = [] - for index in range(self.count()): - filenames.append(self.item(index).filename) - - if filename not in filenames: - if not os.access(filename, os.R_OK): - Alert(self.common, strings._("not_a_readable_file").format(filename)) - return - - fileinfo = QtCore.QFileInfo(filename) - ip = QtWidgets.QFileIconProvider() - icon = ip.icon(fileinfo) - - if os.path.isfile(filename): - size_bytes = fileinfo.size() - size_readable = self.common.human_readable_filesize(size_bytes) - else: - size_bytes = self.common.dir_size(filename) - size_readable = self.common.human_readable_filesize(size_bytes) - - # Create a new item - item = QtWidgets.QListWidgetItem() - item.setIcon(icon) - item.size_bytes = size_bytes - - # Item's filename attribute and size labels - item.filename = filename - item_size = QtWidgets.QLabel(size_readable) - item_size.setStyleSheet(self.common.css['share_file_list_item_size']) - - item.basename = os.path.basename(filename.rstrip('/')) - # Use the basename as the method with which to sort the list - metrics = QtGui.QFontMetrics(item.font()) - elided = metrics.elidedText(item.basename, QtCore.Qt.ElideRight, self.sizeHint().width()) - item.setData(QtCore.Qt.DisplayRole, elided) - - # Item's delete button - def delete_item(): - itemrow = self.row(item) - self.takeItem(itemrow) - self.files_updated.emit() - - item.item_button = QtWidgets.QPushButton() - item.item_button.setDefault(False) - item.item_button.setFlat(True) - item.item_button.setIcon( QtGui.QIcon(self.common.get_resource_path('images/file_delete.png')) ) - item.item_button.clicked.connect(delete_item) - item.item_button.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) - - # Item info widget, with a white background - item_info_layout = QtWidgets.QHBoxLayout() - item_info_layout.setContentsMargins(0, 0, 0, 0) - item_info_layout.addWidget(item_size) - item_info_layout.addWidget(item.item_button) - item_info = QtWidgets.QWidget() - item_info.setObjectName('item-info') - item_info.setLayout(item_info_layout) - - # Create the item's widget and layouts - item_hlayout = QtWidgets.QHBoxLayout() - item_hlayout.addStretch() - item_hlayout.addWidget(item_info) - widget = QtWidgets.QWidget() - widget.setLayout(item_hlayout) - - item.setSizeHint(widget.sizeHint()) - - self.addItem(item) - self.setItemWidget(item, widget) - - self.files_updated.emit() - - -class FileSelection(QtWidgets.QVBoxLayout): - """ - The list of files and folders in the GUI, as well as buttons to add and - delete the files and folders. - """ - def __init__(self, common, parent): - super(FileSelection, self).__init__() - - self.common = common - self.parent = parent - - self.server_on = False - - # File list - self.file_list = FileList(self.common) - self.file_list.itemSelectionChanged.connect(self.update) - self.file_list.files_dropped.connect(self.update) - self.file_list.files_updated.connect(self.update) - - # Buttons - if self.common.platform == 'Darwin': - # The macOS sandbox makes it so the Mac version needs separate add files - # and folders buttons, in order to use native file selection dialogs - self.add_files_button = QtWidgets.QPushButton(strings._('gui_add_files')) - self.add_files_button.clicked.connect(self.add_files) - self.add_folder_button = QtWidgets.QPushButton(strings._('gui_add_folder')) - self.add_folder_button.clicked.connect(self.add_folder) - else: - self.add_button = QtWidgets.QPushButton(strings._('gui_add')) - self.add_button.clicked.connect(self.add) - self.delete_button = QtWidgets.QPushButton(strings._('gui_delete')) - self.delete_button.clicked.connect(self.delete) - button_layout = QtWidgets.QHBoxLayout() - button_layout.addStretch() - if self.common.platform == 'Darwin': - button_layout.addWidget(self.add_files_button) - button_layout.addWidget(self.add_folder_button) - else: - button_layout.addWidget(self.add_button) - button_layout.addWidget(self.delete_button) - - # Add the widgets - self.addWidget(self.file_list) - self.addLayout(button_layout) - - self.update() - - def update(self): - """ - Update the GUI elements based on the current state. - """ - # All buttons should be hidden if the server is on - if self.server_on: - if self.common.platform == 'Darwin': - self.add_files_button.hide() - self.add_folder_button.hide() - else: - self.add_button.hide() - self.delete_button.hide() - else: - if self.common.platform == 'Darwin': - self.add_files_button.show() - self.add_folder_button.show() - else: - self.add_button.show() - - # Delete button should be hidden if item isn't selected - if len(self.file_list.selectedItems()) == 0: - self.delete_button.hide() - else: - self.delete_button.show() - - # Update the file list - self.file_list.update() - - def add(self): - """ - Add button clicked. - """ - 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) - - self.file_list.setCurrentItem(None) - self.update() - - def add_files(self): - """ - Add files button clicked. - """ - files = QtWidgets.QFileDialog.getOpenFileNames(self.parent, caption=strings._('gui_choose_items')) - filenames = files[0] - for filename in filenames: - self.file_list.add_file(filename) - - def add_folder(self): - """ - Add folder button clicked. - """ - filename = QtWidgets.QFileDialog.getExistingDirectory(self.parent, - caption=strings._('gui_choose_items'), - options=QtWidgets.QFileDialog.ShowDirsOnly) - self.file_list.add_file(filename) - - def delete(self): - """ - Delete button clicked - """ - selected = self.file_list.selectedItems() - for item in selected: - itemrow = self.file_list.row(item) - self.file_list.takeItem(itemrow) - self.file_list.files_updated.emit() - - self.file_list.setCurrentItem(None) - self.update() - - def server_started(self): - """ - Gets called when the server starts. - """ - self.server_on = True - self.file_list.server_started() - self.update() - - def server_stopped(self): - """ - Gets called when the server stops. - """ - self.server_on = False - self.file_list.server_stopped() - self.update() - - def get_num_files(self): - """ - Returns the total number of files and folders in the list. - """ - return len(range(self.file_list.count())) - - def setFocus(self): - """ - Set the Qt app focus on the file selection box. - """ - self.file_list.setFocus() diff --git a/onionshare_gui/mode/share_mode/threads.py b/onionshare_gui/mode/share_mode/threads.py index 24e2c242..414c7be1 100644 --- a/onionshare_gui/mode/share_mode/threads.py +++ b/onionshare_gui/mode/share_mode/threads.py @@ -24,13 +24,14 @@ class CompressThread(QtCore.QThread): """ Compresses files to be shared """ + success = QtCore.pyqtSignal() error = QtCore.pyqtSignal(str) def __init__(self, mode): super(CompressThread, self).__init__() self.mode = mode - self.mode.common.log('CompressThread', '__init__') + self.mode.common.log("CompressThread", "__init__") # prepare files to share def set_processed_size(self, x): @@ -38,21 +39,21 @@ class CompressThread(QtCore.QThread): self.mode._zip_progress_bar.update_processed_size_signal.emit(x) def run(self): - self.mode.common.log('CompressThread', 'run') + self.mode.common.log("CompressThread", "run") try: - if self.mode.web.share_mode.set_file_info(self.mode.filenames, processed_size_callback=self.set_processed_size): - self.success.emit() - else: - # Cancelled - pass - - self.mode.app.cleanup_filenames += self.mode.web.share_mode.cleanup_filenames + self.mode.web.share_mode.set_file_info( + self.mode.filenames, processed_size_callback=self.set_processed_size + ) + self.success.emit() + self.mode.app.cleanup_filenames += ( + self.mode.web.share_mode.cleanup_filenames + ) except OSError as e: self.error.emit(e.strerror) def cancel(self): - self.mode.common.log('CompressThread', 'cancel') + self.mode.common.log("CompressThread", "cancel") # Let the Web and ZipWriter objects know that we're canceling compression early self.mode.web.cancel_compression = True |