Merge pull request #688 from glubsy/tab_window

Use tabs instead of floating windows
This commit is contained in:
Andrew Senetar 2020-07-31 22:11:31 -05:00 committed by GitHub
commit ab402d4024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 536 additions and 58 deletions

View File

@ -35,6 +35,7 @@ from .se.preferences_dialog import PreferencesDialog as PreferencesDialogStandar
from .me.preferences_dialog import PreferencesDialog as PreferencesDialogMusic
from .pe.preferences_dialog import PreferencesDialog as PreferencesDialogPicture
from .pe.photo import File as PlatSpecificPhoto
from .tabbed_window import TabBarWindow, TabWindow
tr = trget("ui")
@ -47,6 +48,9 @@ class DupeGuru(QObject):
super().__init__(**kwargs)
self.prefs = Preferences()
self.prefs.load()
# Enable tabs instead of separate floating windows for each dialog
# Could be passed as an argument to this class if we wanted
self.use_tabs = True
self.model = DupeGuruModel(view=self)
self._setup()
@ -59,22 +63,42 @@ class DupeGuru(QObject):
self.recentResults.mustOpenItem.connect(self.model.load_from)
self.resultWindow = None
self.details_dialog = None
self.directories_dialog = DirectoriesDialog(self)
if self.use_tabs:
self.main_window = TabBarWindow(self) if not self.prefs.tabs_default_pos else TabWindow(self)
parent_window = self.main_window
self.directories_dialog = self.main_window.createPage("DirectoriesDialog", app=self)
self.main_window.addTab(
self.directories_dialog, "Directories", switch=False)
self.actionDirectoriesWindow.setEnabled(False)
else: # floating windows only
self.main_window = None
self.directories_dialog = DirectoriesDialog(self)
parent_window = self.directories_dialog
self.progress_window = ProgressWindow(
self.directories_dialog, self.model.progress_window
parent_window, self.model.progress_window
)
self.problemDialog = ProblemDialog(
parent=self.directories_dialog, model=self.model.problem_dialog
parent=parent_window, model=self.model.problem_dialog
)
self.ignoreListDialog = IgnoreListDialog(
parent=self.directories_dialog, model=self.model.ignore_list_dialog
)
self.deletionOptions = DeletionOptions(
parent=self.directories_dialog, model=self.model.deletion_options
)
self.about_box = AboutBox(self.directories_dialog, self)
if self.use_tabs:
self.ignoreListDialog = self.main_window.createPage(
"IgnoreListDialog",
parent=self.main_window,
model=self.model.ignore_list_dialog)
self.ignoreListDialog.accepted.connect(self.main_window.onDialogAccepted)
else:
self.ignoreListDialog = IgnoreListDialog(
parent=parent_window, model=self.model.ignore_list_dialog
)
self.directories_dialog.show()
self.deletionOptions = DeletionOptions(
parent=parent_window,
model=self.model.deletion_options
)
self.about_box = AboutBox(parent_window, self)
parent_window.show()
self.model.load()
self.SIGTERM.connect(self.handleSIGTERM)
@ -98,6 +122,7 @@ class DupeGuru(QObject):
self.preferencesTriggered,
),
("actionIgnoreList", "", "", tr("Ignore List"), self.ignoreListTriggered),
("actionDirectoriesWindow", "", "", tr("Directories"), self.showDirectoriesWindow),
(
"actionClearPictureCache",
"Ctrl+Shift+P",
@ -191,7 +216,20 @@ class DupeGuru(QObject):
def showResultsWindow(self):
if self.resultWindow is not None:
self.resultWindow.show()
if self.use_tabs:
self.main_window.addTab(
self.resultWindow, "Results", switch=True)
else:
self.resultWindow.show()
def showDirectoriesWindow(self):
if self.directories_dialog is not None:
if self.use_tabs:
index = self.main_window.indexOfWidget(self.directories_dialog)
self.main_window.setTabVisible(index, True)
self.main_window.setCurrentIndex(index)
else:
self.directories_dialog.show()
def shutdown(self):
self.willSavePrefs.emit()
@ -212,7 +250,9 @@ class DupeGuru(QObject):
"scanning have accented letters, you'll probably get a crash. It is advised that "
"you set your system locale properly."
)
QMessageBox.warning(self.directories_dialog, "Wrong Locale", msg)
QMessageBox.warning(self.main_window if self.main_window
else self.directories_dialog,
"Wrong Locale", msg)
def clearPictureCacheTriggered(self):
title = tr("Clear Picture Cache")
@ -223,7 +263,19 @@ class DupeGuru(QObject):
QMessageBox.information(active, title, tr("Picture cache cleared."))
def ignoreListTriggered(self):
self.model.ignore_list_dialog.show()
if self.use_tabs:
# Fetch the index in the TabWidget or the StackWidget (depends on class):
index = self.main_window.indexOfWidget(self.ignoreListDialog)
if index < 0:
# we have not instantiated and populated it in their internal list yet
index = self.main_window.addTab(
self.ignoreListDialog, "Ignore List", switch=True)
# if not self.main_window.tabWidget.isTabVisible(index):
self.main_window.setTabVisible(index, True)
self.main_window.setCurrentIndex(index)
return
else:
self.model.ignore_list_dialog.show()
def openDebugLogTriggered(self):
debugLogPath = op.join(self.model.appdata, "debug.log")
@ -231,7 +283,8 @@ class DupeGuru(QObject):
def preferencesTriggered(self):
preferences_dialog = self._get_preferences_dialog_class()(
self.directories_dialog, self
self.main_window if self.main_window else self.directories_dialog,
self
)
preferences_dialog.load()
result = preferences_dialog.exec()
@ -242,7 +295,10 @@ class DupeGuru(QObject):
preferences_dialog.setParent(None)
def quitTriggered(self):
self.directories_dialog.close()
if self.main_window:
self.main_window.close()
else:
self.directories_dialog.close()
def showAboutBoxTriggered(self):
self.about_box.show()
@ -282,8 +338,12 @@ class DupeGuru(QObject):
if self.resultWindow is not None:
self.resultWindow.close()
self.resultWindow.setParent(None)
self.resultWindow = ResultWindow(self.directories_dialog, self)
self.directories_dialog._updateActionsState()
if self.use_tabs:
self.resultWindow = self.main_window.createPage(
"ResultWindow", parent=self.main_window, app=self)
else: # We don't use a tab widget, regular floating QMainWindow
self.resultWindow = ResultWindow(self.directories_dialog, self)
self.directories_dialog._updateActionsState()
self.details_dialog = self._get_details_dialog_class()(self.resultWindow, self)
def show_results_window(self):

View File

@ -40,6 +40,7 @@ class DirectoriesDialog(QMainWindow):
def __init__(self, app, **kwargs):
super().__init__(None, **kwargs)
self.app = app
self.specific_actions = set()
self.lastAddedFolder = platform.INITIAL_FOLDER_IN_DIALOGS
self.recentFolders = Recent(self.app, "recentFolders")
self._setupUi()
@ -87,25 +88,39 @@ class DirectoriesDialog(QMainWindow):
"actionShowResultsWindow",
"",
"",
tr("Results Window"),
tr("Scan Results"),
self.app.showResultsWindow,
),
("actionAddFolder", "", "", tr("Add Folder..."), self.addFolderTriggered),
]
createActions(ACTIONS, self)
# if self.app.use_tabs:
# # Keep track of actions which should only be accessible from this class
# for action, _, _, _, _ in ACTIONS:
# self.specific_actions.add(getattr(self, action))
def _setupMenu(self):
self.menubar = QMenuBar(self)
self.menubar.setGeometry(QRect(0, 0, 42, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle(tr("File"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle(tr("Help"))
if not self.app.use_tabs:
# we are our own QMainWindow, we need our own menu bar
self.menubar = QMenuBar(self)
self.menubar.setGeometry(QRect(0, 0, 42, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle(tr("File"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle(tr("Help"))
self.setMenuBar(self.menubar)
menubar = self.menubar
else:
# we are part of a tab widget, we populate its window's menubar instead
self.menuFile = self.app.main_window.menuFile
self.menuView = self.app.main_window.menuView
self.menuHelp = self.app.main_window.menuHelp
menubar = self.app.main_window.menubar
self.menuLoadRecent = QMenu(self.menuFile)
self.menuLoadRecent.setTitle(tr("Load Recent Results"))
self.setMenuBar(self.menubar)
self.menuFile.addAction(self.actionLoadResults)
self.menuFile.addAction(self.menuLoadRecent.menuAction())
@ -113,16 +128,20 @@ class DirectoriesDialog(QMainWindow):
self.menuFile.addAction(self.app.actionClearPictureCache)
self.menuFile.addSeparator()
self.menuFile.addAction(self.app.actionQuit)
self.menuView.addAction(self.app.actionPreferences)
self.menuView.addAction(self.app.actionDirectoriesWindow)
self.menuView.addAction(self.actionShowResultsWindow)
self.menuView.addAction(self.app.actionIgnoreList)
self.menuView.addSeparator()
self.menuView.addAction(self.app.actionPreferences)
self.menuHelp.addAction(self.app.actionShowHelp)
self.menuHelp.addAction(self.app.actionOpenDebugLog)
self.menuHelp.addAction(self.app.actionAbout)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuView.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
menubar.addAction(self.menuFile.menuAction())
menubar.addAction(self.menuView.menuAction())
menubar.addAction(self.menuHelp.menuAction())
# Recent folders menu
self.menuRecentFolders = QMenu()
@ -139,6 +158,8 @@ class DirectoriesDialog(QMainWindow):
self.resize(420, 338)
self.centralwidget = QWidget(self)
self.verticalLayout = QVBoxLayout(self.centralwidget)
self.verticalLayout.setContentsMargins(4, 0, 4, 0)
self.verticalLayout.setSpacing(0)
hl = QHBoxLayout()
label = QLabel(tr("Application Mode:"), self)
label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)

View File

@ -26,6 +26,7 @@ class IgnoreListDialog(QDialog):
def __init__(self, parent, model, **kwargs):
flags = Qt.CustomizeWindowHint | Qt.WindowTitleHint | Qt.WindowSystemMenuHint
super().__init__(parent, flags, **kwargs)
self.specific_actions = frozenset()
self._setupUi()
self.model = model
self.model.view = self
@ -39,6 +40,7 @@ class IgnoreListDialog(QDialog):
self.setWindowTitle(tr("Ignore List"))
self.resize(540, 330)
self.verticalLayout = QVBoxLayout(self)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.tableView = QTableView()
self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.tableView.setSelectionMode(QAbstractItemView.ExtendedSelection)

View File

@ -35,12 +35,17 @@ class Preferences(PreferencesBase):
"ResultWindowIsMaximized", self.resultWindowIsMaximized
)
self.resultWindowRect = self.get_rect("ResultWindowRect", self.resultWindowRect)
self.mainWindowIsMaximized = get(
"MainWindowIsMaximized", self.mainWindowIsMaximized
)
self.mainWindowRect = self.get_rect("MainWindowRect", self.mainWindowRect)
self.directoriesWindowRect = self.get_rect(
"DirectoriesWindowRect", self.directoriesWindowRect
)
self.recentResults = get("RecentResults", self.recentResults)
self.recentFolders = get("RecentFolders", self.recentFolders)
self.tabs_default_pos = get("TabsDefaultPosition", self.tabs_default_pos)
self.word_weighting = get("WordWeighting", self.word_weighting)
self.match_similar = get("MatchSimilar", self.match_similar)
self.ignore_small_files = get("IgnoreSmallFiles", self.ignore_small_files)
@ -70,9 +75,12 @@ class Preferences(PreferencesBase):
self.resultWindowIsMaximized = False
self.resultWindowRect = None
self.directoriesWindowRect = None
self.mainWindowRect = None
self.mainWindowIsMaximized = False
self.recentResults = []
self.recentFolders = []
self.tabs_default_pos = True
self.word_weighting = True
self.match_similar = False
self.ignore_small_files = True
@ -101,11 +109,14 @@ class Preferences(PreferencesBase):
set_("TableFontSize", self.tableFontSize)
set_('ReferenceBoldFont', self.reference_bold_font)
set_("ResultWindowIsMaximized", self.resultWindowIsMaximized)
set_("MainWindowIsMaximized", self.mainWindowIsMaximized)
self.set_rect("ResultWindowRect", self.resultWindowRect)
self.set_rect("MainWindowRect", self.mainWindowRect)
self.set_rect("DirectoriesWindowRect", self.directoriesWindowRect)
set_("RecentResults", self.recentResults)
set_("RecentFolders", self.recentFolders)
set_("TabsDefaultPosition", self.tabs_default_pos)
set_("WordWeighting", self.word_weighting)
set_("MatchSimilar", self.match_similar)
set_("IgnoreSmallFiles", self.ignore_small_files)

View File

@ -117,8 +117,12 @@ class PreferencesDialogBase(QDialog):
self.widgetsVLayout.addLayout(
horizontalWrap([self.fontSizeLabel, self.fontSizeSpinBox, None])
)
self._setupAddCheckbox("reference_bold_font", tr("Bold font for reference."))
self._setupAddCheckbox("reference_bold_font", tr("Bold font for reference"))
self.widgetsVLayout.addWidget(self.reference_bold_font)
self._setupAddCheckbox("tabs_default_pos", tr("Use default position for tab bar (requires restart)"))
self.tabs_default_pos.setToolTip(tr("Place the tab bar below the main menu instead of next to it"))
self.widgetsVLayout.addWidget(self.tabs_default_pos)
self.languageLabel = QLabel(tr("Language:"), self)
self.languageComboBox = QComboBox(self)
for lang in self.supportedLanguages:
@ -190,6 +194,7 @@ class PreferencesDialogBase(QDialog):
setchecked(self.ignoreHardlinkMatches, prefs.ignore_hardlink_matches)
setchecked(self.debugModeBox, prefs.debug_mode)
setchecked(self.reference_bold_font, prefs.reference_bold_font)
setchecked(self.tabs_default_pos, prefs.tabs_default_pos)
self.copyMoveDestinationComboBox.setCurrentIndex(prefs.destination_type)
self.customCommandEdit.setText(prefs.custom_command)
self.fontSizeSpinBox.setValue(prefs.tableFontSize)
@ -213,6 +218,7 @@ class PreferencesDialogBase(QDialog):
prefs.destination_type = self.copyMoveDestinationComboBox.currentIndex()
prefs.custom_command = str(self.customCommandEdit.text())
prefs.tableFontSize = self.fontSizeSpinBox.value()
prefs.tabs_default_pos = ischecked(self.tabs_default_pos)
lang = self.supportedLanguages[self.languageComboBox.currentIndex()]
oldlang = self.app.prefs.language
if oldlang not in self.supportedLanguages:

View File

@ -42,6 +42,7 @@ class ResultWindow(QMainWindow):
def __init__(self, parent, app, **kwargs):
super().__init__(parent, **kwargs)
self.app = app
self.specific_actions = set()
self._setupUi()
if app.model.app_mode == AppMode.Picture:
MODEL_CLASS = ResultsModelPicture
@ -207,22 +208,39 @@ class ResultWindow(QMainWindow):
self.actionDelta.setCheckable(True)
self.actionPowerMarker.setCheckable(True)
if self.app.main_window: # We use tab widgets in this case
# Keep track of actions which should only be accessible from this class
for action, _, _, _, _ in ACTIONS:
self.specific_actions.add(getattr(self, action))
def _setupMenu(self):
self.menubar = QMenuBar()
self.menubar.setGeometry(QRect(0, 0, 630, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle(tr("File"))
self.menuMark = QMenu(self.menubar)
self.menuMark.setTitle(tr("Mark"))
self.menuActions = QMenu(self.menubar)
self.menuActions.setTitle(tr("Actions"))
self.menuColumns = QMenu(self.menubar)
self.menuColumns.setTitle(tr("Columns"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle(tr("Help"))
self.setMenuBar(self.menubar)
if not self.app.use_tabs:
# we are our own QMainWindow, we need our own menu bar
self.menubar = QMenuBar() # self.menuBar() works as well here
self.menubar.setGeometry(QRect(0, 0, 630, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle(tr("File"))
self.menuMark = QMenu(self.menubar)
self.menuMark.setTitle(tr("Mark"))
self.menuActions = QMenu(self.menubar)
self.menuActions.setTitle(tr("Actions"))
self.menuColumns = QMenu(self.menubar)
self.menuColumns.setTitle(tr("Columns"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle(tr("Help"))
self.setMenuBar(self.menubar)
menubar = self.menubar
else:
# we are part of a tab widget, we populate its window's menubar instead
self.menuFile = self.app.main_window.menuFile
self.menuMark = self.app.main_window.menuMark
self.menuActions = self.app.main_window.menuActions
self.menuColumns = self.app.main_window.menuColumns
self.menuView = self.app.main_window.menuView
self.menuHelp = self.app.main_window.menuHelp
menubar = self.app.main_window.menubar
self.menuActions.addAction(self.actionDeleteMarked)
self.menuActions.addAction(self.actionMoveMarked)
@ -242,12 +260,18 @@ class ResultWindow(QMainWindow):
self.menuMark.addAction(self.actionMarkNone)
self.menuMark.addAction(self.actionInvertMarking)
self.menuMark.addAction(self.actionMarkSelected)
self.menuView.addAction(self.actionDetails)
self.menuView.addSeparator()
self.menuView.addAction(self.actionPowerMarker)
self.menuView.addAction(self.actionDelta)
self.menuView.addSeparator()
self.menuView.addAction(self.actionDetails)
self.menuView.addAction(self.app.actionIgnoreList)
if not self.app.use_tabs:
self.menuView.addAction(self.app.actionIgnoreList)
# This also pushes back the options entry to the bottom of the menu
self.menuView.addSeparator()
self.menuView.addAction(self.app.actionPreferences)
self.menuHelp.addAction(self.app.actionShowHelp)
self.menuHelp.addAction(self.app.actionOpenDebugLog)
self.menuHelp.addAction(self.app.actionAbout)
@ -257,15 +281,19 @@ class ResultWindow(QMainWindow):
self.menuFile.addSeparator()
self.menuFile.addAction(self.app.actionQuit)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuMark.menuAction())
self.menubar.addAction(self.menuActions.menuAction())
self.menubar.addAction(self.menuColumns.menuAction())
self.menubar.addAction(self.menuView.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
menubar.addAction(self.menuFile.menuAction())
menubar.addAction(self.menuMark.menuAction())
menubar.addAction(self.menuActions.menuAction())
menubar.addAction(self.menuColumns.menuAction())
menubar.addAction(self.menuView.menuAction())
menubar.addAction(self.menuHelp.menuAction())
# Columns menu
menu = self.menuColumns
# Avoid adding duplicate actions in tab widget menu in case we recreated
# the Result Window instance.
if menu.actions():
menu.clear()
self._column_actions = []
for index, (display, visible) in enumerate(
self.app.model.result_table.columns.menu_items()
@ -280,7 +308,7 @@ class ResultWindow(QMainWindow):
action.item_index = -1
# Action menu
actionMenu = QMenu(tr("Actions"), self.menubar)
actionMenu = QMenu(tr("Actions"), menubar)
actionMenu.addAction(self.actionDeleteMarked)
actionMenu.addAction(self.actionMoveMarked)
actionMenu.addAction(self.actionCopyMarked)

350
qt/tabbed_window.py Normal file
View File

@ -0,0 +1,350 @@
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.gnu.org/licenses/gpl-3.0.html
from PyQt5.QtCore import QRect, pyqtSlot, Qt
from PyQt5.QtWidgets import (
QWidget,
QVBoxLayout,
QHBoxLayout,
QMainWindow,
QTabWidget,
QMenu,
QTabBar,
QStackedWidget,
)
from hscommon.trans import trget
from qtlib.util import moveToScreenCenter, createActions
from .directories_dialog import DirectoriesDialog
from .result_window import ResultWindow
from .ignore_list_dialog import IgnoreListDialog
tr = trget("ui")
class TabWindow(QMainWindow):
def __init__(self, app, **kwargs):
super().__init__(None, **kwargs)
self.app = app
self.pages = {}
self.menubar = None
self.menuList = set()
self.last_index = -1
self.previous_widget_actions = set()
self._setupUi()
self.app.willSavePrefs.connect(self.appWillSavePrefs)
def _setupActions(self):
# (name, shortcut, icon, desc, func)
ACTIONS = [
(
"actionToggleTabs",
"",
"",
tr("Show tab bar"),
self.toggleTabBar,
),
]
createActions(ACTIONS, self)
self.actionToggleTabs.setCheckable(True)
self.actionToggleTabs.setChecked(True)
def _setupUi(self):
self.setWindowTitle(self.app.NAME)
self.resize(640, 480)
self.tabWidget = QTabWidget()
# self.tabWidget.setTabPosition(QTabWidget.South)
self.tabWidget.setContentsMargins(0, 0, 0, 0)
# self.tabWidget.setTabBarAutoHide(True)
# This gets rid of the annoying margin around the TabWidget:
self.tabWidget.setDocumentMode(True)
self._setupActions()
self._setupMenu()
# This should be the same as self.centralWidget.setLayout(self.verticalLayout)
self.verticalLayout = QVBoxLayout(self.tabWidget)
# self.verticalLayout.addWidget(self.tabWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.tabWidget.setTabsClosable(True)
self.setCentralWidget(self.tabWidget) # only for QMainWindow
self.tabWidget.currentChanged.connect(self.updateMenuBar)
self.tabWidget.tabCloseRequested.connect(self.onTabCloseRequested)
self.updateMenuBar(self.tabWidget.currentIndex())
self.restoreGeometry()
def restoreGeometry(self):
if self.app.prefs.mainWindowRect is not None:
self.setGeometry(self.app.prefs.mainWindowRect)
else:
moveToScreenCenter(self)
def _setupMenu(self):
"""Setup the menubar boiler plates which will be filled by the underlying
tab's widgets whenever they are instantiated."""
self.menubar = self.menuBar() # QMainWindow, similar to just QMenuBar() here
# self.setMenuBar(self.menubar) # already set if QMainWindow class
self.menubar.setGeometry(QRect(0, 0, 100, 22))
self.menuFile = QMenu(self.menubar)
self.menuFile.setTitle(tr("File"))
self.menuMark = QMenu(self.menubar)
self.menuMark.setTitle(tr("Mark"))
self.menuActions = QMenu(self.menubar)
self.menuActions.setTitle(tr("Actions"))
self.menuColumns = QMenu(self.menubar)
self.menuColumns.setTitle(tr("Columns"))
self.menuView = QMenu(self.menubar)
self.menuView.setTitle(tr("View"))
self.menuHelp = QMenu(self.menubar)
self.menuHelp.setTitle(tr("Help"))
self.menuView.addAction(self.actionToggleTabs)
self.menuView.addSeparator()
self.menuList.add(self.menuFile)
self.menuList.add(self.menuMark)
self.menuList.add(self.menuActions)
self.menuList.add(self.menuColumns)
self.menuList.add(self.menuView)
self.menuList.add(self.menuHelp)
@pyqtSlot(int)
def updateMenuBar(self, page_index=None):
if page_index < 0:
return
current_index = self.getCurrentIndex()
active_widget = self.getWidgetAtIndex(current_index)
if self.last_index < 0:
self.last_index = current_index
self.previous_widget_actions = active_widget.specific_actions
return
page_type = type(active_widget).__name__
for menu in self.menuList:
if menu is self.menuColumns or menu is self.menuActions or menu is self.menuMark:
if not isinstance(active_widget, ResultWindow):
menu.setEnabled(False)
continue
else:
menu.setEnabled(True)
for action in menu.actions():
if action not in active_widget.specific_actions:
if action in self.previous_widget_actions:
action.setEnabled(False)
continue
action.setEnabled(True)
self.app.directories_dialog.actionShowResultsWindow.setEnabled(
False if page_type == "ResultWindow"
else self.app.resultWindow is not None)
self.app.actionIgnoreList.setEnabled(
True if self.app.ignoreListDialog is not None
and not page_type == "IgnoreListDialog" else False)
self.app.actionDirectoriesWindow.setEnabled(
False if page_type == "DirectoriesDialog" else True)
self.previous_widget_actions = active_widget.specific_actions
self.last_index = current_index
def createPage(self, cls, **kwargs):
app = kwargs.get("app", self.app)
page = None
if cls == "DirectoriesDialog":
page = DirectoriesDialog(app)
elif cls == "ResultWindow":
parent = kwargs.get("parent", self)
page = ResultWindow(parent, app)
elif cls == "IgnoreListDialog":
parent = kwargs.get("parent", self)
model = kwargs.get("model")
page = IgnoreListDialog(parent, model)
self.pages[cls] = page
return page
def addTab(self, page, title, switch=False):
# Warning: this supposedly takes ownership of the page
index = self.tabWidget.addTab(page, title)
# index = self.tabWidget.insertTab(-1, page, title)
if isinstance(page, DirectoriesDialog):
self.tabWidget.tabBar().setTabButton(
index, QTabBar.RightSide, None)
if switch:
self.setCurrentIndex(index)
return index
def indexOfWidget(self, widget):
return self.tabWidget.indexOf(widget)
def setCurrentIndex(self, index):
return self.tabWidget.setCurrentIndex(index)
def setTabVisible(self, index, value):
return self.tabWidget.setTabVisible(index, value)
def removeTab(self, index):
return self.tabWidget.removeTab(index)
def isTabVisible(self, index):
return self.tabWidget.isTabVisible(index)
def getCurrentIndex(self):
return self.tabWidget.currentIndex()
def getWidgetAtIndex(self, index):
return self.tabWidget.widget(index)
def getCount(self):
return self.tabWidget.count()
# --- Events
def appWillSavePrefs(self):
# Right now this is useless since the first spawn dialog inside the
# QTabWidget will assign its geometry after restoring it
prefs = self.app.prefs
prefs.mainWindowIsMaximized = self.isMaximized()
prefs.mainWindowRect = self.geometry()
def closeEvent(self, close_event):
# Force closing of our tabbed widgets in reverse order so that the
# directories dialog (which usually is at index 0) will be called last
for index in range(self.getCount() - 1, -1, -1):
self.getWidgetAtIndex(index).closeEvent(close_event)
self.appWillSavePrefs()
@pyqtSlot(int)
def onTabCloseRequested(self, index):
current_widget = self.getWidgetAtIndex(index)
if isinstance(current_widget, DirectoriesDialog):
# if we close this one, the application quits. Force user to use the
# menu or shortcut. But this is useless if we don't have a button
# set up to make a close request anyway. This check could be removed.
return
current_widget.close()
self.setTabVisible(index, False)
# self.tabWidget.widget(index).hide()
self.removeTab(index)
@pyqtSlot()
def onDialogAccepted(self):
"""Remove tabbed dialog when Accepted/Done."""
widget = self.sender()
index = self.indexOfWidget(widget)
if index > -1:
self.removeTab(index)
@pyqtSlot()
def toggleTabBar(self):
value = self.sender().isChecked()
self.actionToggleTabs.setChecked(value)
self.tabWidget.tabBar().setVisible(value)
class TabBarWindow(TabWindow):
"""Implementation which uses a separate QTabBar and QStackedWidget.
The Tab bar is placed next to the menu bar to save real estate."""
def __init__(self, app, **kwargs):
super().__init__(app, **kwargs)
def _setupUi(self):
self.setWindowTitle(self.app.NAME)
self.resize(640, 480)
self.tabBar = QTabBar()
self.verticalLayout = QVBoxLayout()
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self._setupActions()
self._setupMenu()
self.centralWidget = QWidget(self)
self.setCentralWidget(self.centralWidget)
self.stackedWidget = QStackedWidget()
self.centralWidget.setLayout(self.verticalLayout)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.addWidget(self.menubar, 0, Qt.AlignTop)
self.horizontalLayout.addWidget(self.tabBar, 0, Qt.AlignTop)
self.verticalLayout.addLayout(self.horizontalLayout)
self.verticalLayout.addWidget(self.stackedWidget)
self.tabBar.currentChanged.connect(self.showWidget)
self.tabBar.tabCloseRequested.connect(self.onTabCloseRequested)
self.stackedWidget.currentChanged.connect(self.updateMenuBar)
self.stackedWidget.widgetRemoved.connect(self.onRemovedWidget)
self.tabBar.setTabsClosable(True)
self.restoreGeometry()
def addTab(self, page, title, switch=True):
stack_index = self.stackedWidget.insertWidget(-1, page)
tab_index = self.tabBar.addTab(title)
if isinstance(page, DirectoriesDialog):
self.tabBar.setTabButton(
tab_index, QTabBar.RightSide, None)
if switch: # switch to the added tab immediately upon creation
self.setTabIndex(tab_index)
self.stackedWidget.setCurrentWidget(page)
return stack_index
@pyqtSlot(int)
def showWidget(self, index):
if index >= 0 and index <= self.stackedWidget.count() - 1:
self.stackedWidget.setCurrentIndex(index)
# if not self.tabBar.isTabVisible(index):
self.setTabVisible(index, True)
def indexOfWidget(self, widget):
# Warning: this may return -1 if widget is not a child of stackedwidget
return self.stackedWidget.indexOf(widget)
def setCurrentIndex(self, tab_index):
# The signal will handle switching the stackwidget's widget
self.setTabIndex(tab_index)
# self.stackedWidget.setCurrentWidget(self.stackedWidget.widget(tab_index))
@pyqtSlot(int)
def setTabIndex(self, index):
if not index:
return
self.tabBar.setCurrentIndex(index)
def setTabVisible(self, index, value):
return self.tabBar.setTabVisible(index, value)
@pyqtSlot(int)
def onRemovedWidget(self, index):
self.removeTab(index)
@pyqtSlot(int)
def removeTab(self, index):
# No need to remove the widget here:
# self.stackedWidget.removeWidget(self.stackedWidget.widget(index))
return self.tabBar.removeTab(index)
@pyqtSlot(int)
def removeWidget(self, widget):
return self.stackedWidget.removeWidget(widget)
def isTabVisible(self, index):
return self.tabBar.isTabVisible(index)
def getCurrentIndex(self):
return self.stackedWidget.currentIndex()
def getWidgetAtIndex(self, index):
return self.stackedWidget.widget(index)
def getCount(self):
return self.stackedWidget.count()
@pyqtSlot()
def toggleTabBar(self):
value = self.sender().isChecked()
self.actionToggleTabs.setChecked(value)
self.tabBar.setVisible(value)
@pyqtSlot(int)
def onTabCloseRequested(self, index):
current_widget = self.getWidgetAtIndex(index)
current_widget.close()
self.stackedWidget.removeWidget(current_widget)
# In this case the signal will take care of the tab itself after removing the widget
# self.removeTab(index)