diff options
author | Micah Lee <micah@micahflee.com> | 2020-10-13 17:28:54 -0700 |
---|---|---|
committer | Micah Lee <micah@micahflee.com> | 2020-10-13 17:28:54 -0700 |
commit | b42f92d714145dcc6282773e61f68c00b4b79a28 (patch) | |
tree | ee4443ab3c5300db279a3cf0686380074d98c973 /desktop/src/onionshare/tab_widget.py | |
parent | f4abcf1be9122a28005dc3e0949bf5952192e982 (diff) | |
download | onionshare-b42f92d714145dcc6282773e61f68c00b4b79a28.tar.gz onionshare-b42f92d714145dcc6282773e61f68c00b4b79a28.zip |
Move docs back to root, move onionshare_gui into briefcase app, and make modifications so briefcase app will work
Diffstat (limited to 'desktop/src/onionshare/tab_widget.py')
-rw-r--r-- | desktop/src/onionshare/tab_widget.py | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/desktop/src/onionshare/tab_widget.py b/desktop/src/onionshare/tab_widget.py new file mode 100644 index 00000000..911fbc2e --- /dev/null +++ b/desktop/src/onionshare/tab_widget.py @@ -0,0 +1,268 @@ +# -*- coding: utf-8 -*- +""" +OnionShare | https://onionshare.org/ + +Copyright (C) 2014-2020 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 PyQt5 import QtCore, QtWidgets, QtGui + +from onionshare_cli.mode_settings import ModeSettings + +from . import strings +from .tab import Tab +from .threads import EventHandlerThread +from .gui_common import GuiCommon + + +class TabWidget(QtWidgets.QTabWidget): + """ + A custom tab widget, that has a "+" button for adding new tabs + """ + + bring_to_front = QtCore.pyqtSignal() + + def __init__(self, common, system_tray, status_bar): + super(TabWidget, self).__init__() + self.common = common + self.common.log("TabWidget", "__init__") + + self.system_tray = system_tray + self.status_bar = status_bar + + # Keep track of tabs in a dictionary + self.tabs = {} + self.current_tab_id = 0 # Each tab has a unique id + + # Define the new tab button + self.new_tab_button = QtWidgets.QPushButton("+", parent=self) + self.new_tab_button.setFlat(True) + self.new_tab_button.setFixedSize(40, 30) + self.new_tab_button.clicked.connect(self.new_tab_clicked) + self.new_tab_button.setStyleSheet( + self.common.gui.css["tab_widget_new_tab_button"] + ) + self.new_tab_button.setToolTip(strings._("gui_new_tab_tooltip")) + + # Use a custom tab bar + tab_bar = TabBar() + tab_bar.move_new_tab_button.connect(self.move_new_tab_button) + tab_bar.currentChanged.connect(self.tab_changed) + self.setTabBar(tab_bar) + + # Set up the tab widget + self.setMovable(True) + self.setTabsClosable(True) + self.setUsesScrollButtons(True) + self.setDocumentMode(True) + self.setStyleSheet(self.common.gui.css["tab_widget"]) + + self.tabCloseRequested.connect(self.close_tab) + + self.move_new_tab_button() + + # Watch the events file for changes + self.event_handler_t = EventHandlerThread(common) + self.event_handler_t.new_tab.connect(self.add_tab) + self.event_handler_t.new_share_tab.connect(self.new_share_tab) + self.event_handler_t.start() + + def cleanup(self): + # Stop the event thread + self.event_handler_t.should_quit = True + self.event_handler_t.quit() + self.event_handler_t.wait(50) + + # Clean up each tab + for index in range(self.count()): + tab = self.widget(index) + tab.cleanup() + + def move_new_tab_button(self): + # Find the width of all tabs + tabs_width = sum( + [self.tabBar().tabRect(i).width() for i in range(self.count())] + ) + + # The current position of the new tab button + pos = self.new_tab_button.pos() + + # If there are so many tabs it scrolls, move the button to the left of the scroll buttons + if tabs_width > self.width(): + pos.setX(self.width() - 65) + else: + # Otherwise move the button to the right of the tabs + pos.setX(self.tabBar().sizeHint().width()) + + self.new_tab_button.move(pos) + self.new_tab_button.raise_() + + def tab_changed(self): + # Active tab was changed + tab_id = self.currentIndex() + self.common.log("TabWidget", "tab_changed", f"Tab was changed to {tab_id}") + try: + mode = self.tabs[tab_id].get_mode() + if mode: + # Update the server status indicator to reflect that of the current tab + self.tabs[tab_id].update_server_status_indicator() + else: + # If this tab doesn't have a mode set yet, blank the server status indicator + self.status_bar.server_status_image_label.clear() + self.status_bar.server_status_label.clear() + except KeyError: + # When all current tabs are closed, index briefly drops to -1 before resetting to 0 + # which will otherwise trigger a KeyError on tab.get_mode() above. + pass + + def new_tab_clicked(self): + # Create a new tab + self.add_tab() + + def load_tab(self, mode_settings_id): + # Load the tab's mode settings + mode_settings = ModeSettings(self.common, id=mode_settings_id) + self.add_tab(mode_settings) + + def new_share_tab(self, filenames): + mode_settings = ModeSettings(self.common) + mode_settings.set("persistent", "mode", "share") + mode_settings.set("share", "filenames", filenames) + self.add_tab(mode_settings) + + def add_tab(self, mode_settings=None): + tab = Tab(self.common, self.current_tab_id, self.system_tray, self.status_bar) + tab.change_title.connect(self.change_title) + tab.change_icon.connect(self.change_icon) + tab.change_persistent.connect(self.change_persistent) + + self.tabs[self.current_tab_id] = tab + self.current_tab_id += 1 + + index = self.addTab(tab, strings._("gui_new_tab")) + self.setCurrentIndex(index) + + # Create a close button + def close_tab(): + self.tabBar().tabCloseRequested.emit(self.indexOf(tab)) + + close_button = QtWidgets.QPushButton() + close_button.setFlat(True) + close_button.setFixedWidth(40) + close_button.setIcon( + QtGui.QIcon(GuiCommon.get_resource_path("images/close_tab.png")) + ) + close_button.clicked.connect(close_tab) + self.tabBar().setTabButton(index, QtWidgets.QTabBar.RightSide, close_button) + + tab.init(mode_settings) + # If it's persistent, set the persistent image in the tab + self.change_persistent(tab.tab_id, tab.settings.get("persistent", "enabled")) + + # Bring the window to front, in case this is being added by an event + self.bring_to_front.emit() + + def change_title(self, tab_id, title): + index = self.indexOf(self.tabs[tab_id]) + self.setTabText(index, title) + + def change_icon(self, tab_id, icon_path): + index = self.indexOf(self.tabs[tab_id]) + self.setTabIcon(index, QtGui.QIcon(GuiCommon.get_resource_path(icon_path))) + + def change_persistent(self, tab_id, is_persistent): + index = self.indexOf(self.tabs[tab_id]) + if is_persistent: + self.tabBar().setTabButton( + index, + QtWidgets.QTabBar.LeftSide, + self.tabs[tab_id].persistent_image_label, + ) + else: + invisible_widget = QtWidgets.QWidget() + invisible_widget.setFixedSize(0, 0) + self.tabBar().setTabButton( + index, QtWidgets.QTabBar.LeftSide, invisible_widget + ) + + self.save_persistent_tabs() + + def save_persistent_tabs(self): + # Figure out the order of persistent tabs to save in settings + persistent_tabs = [] + for index in range(self.count()): + tab = self.widget(index) + if tab.settings.get("persistent", "enabled"): + persistent_tabs.append(tab.settings.id) + # Only save if tabs have actually moved + if persistent_tabs != self.common.settings.get("persistent_tabs"): + self.common.settings.set("persistent_tabs", persistent_tabs) + self.common.settings.save() + + def close_tab(self, index): + self.common.log("TabWidget", "close_tab", f"{index}") + tab = self.widget(index) + if tab.close_tab(): + # If the tab is persistent, delete the settings file from disk + if tab.settings.get("persistent", "enabled"): + tab.settings.delete() + + # Remove the tab + self.removeTab(index) + del self.tabs[tab.tab_id] + + # If the last tab is closed, open a new one + if self.count() == 0: + self.new_tab_clicked() + + self.save_persistent_tabs() + + def are_tabs_active(self): + """ + See if there are active servers in any open tabs + """ + for tab_id in self.tabs: + mode = self.tabs[tab_id].get_mode() + if mode: + if mode.server_status.status != mode.server_status.STATUS_STOPPED: + return True + return False + + def paintEvent(self, event): + super(TabWidget, self).paintEvent(event) + # Save the order of persistent tabs whenever a new tab is switched to -- ideally we would + # do this whenever tabs gets moved, but paintEvent is the only event that seems to get triggered + # when this happens + self.save_persistent_tabs() + + def resizeEvent(self, event): + # Make sure to move new tab button on each resize + super(TabWidget, self).resizeEvent(event) + self.move_new_tab_button() + + +class TabBar(QtWidgets.QTabBar): + """ + A custom tab bar + """ + + move_new_tab_button = QtCore.pyqtSignal() + + def __init__(self): + super(TabBar, self).__init__() + + def tabLayoutChange(self): + self.move_new_tab_button.emit() |