Skip to content

Commit

Permalink
Merge pull request #2 from T1petitti/Give-option-to-display-text-in-t…
Browse files Browse the repository at this point in the history
…oolbar-items

Give option to display text in toolbar items
  • Loading branch information
vozellad committed Apr 27, 2024
2 parents 4a96d13 + 796b749 commit 0dbb000
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 29 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,6 @@ common/doc-dev/_build/html

# Linter configuration
.flake8

# Preferences files
qt/main_preferences
66 changes: 66 additions & 0 deletions common/test/test_app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# TODO: add copyright text


import unittest
import os
import sys
import itertools
#from test import generic
import json

sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
from qt import app

from qt import qttools_path
qttools_path.registerBackintimePath('common')

# Workaround until the codebase is rectified/equalized.
from common import tools
tools.initiate_translation(None)

from common import logger
from qt import qttools
from common import backintime
from common import guiapplicationinstance


class TestSavePreferences(unittest.TestCase):
def setUp(self):
cfg = backintime.startApp('backintime-qt')

raiseCmd = ''
if len(sys.argv) > 1:
raiseCmd = '\n'.join(sys.argv[1:])

appInstance = guiapplicationinstance.GUIApplicationInstance(cfg.appInstanceFile(), raiseCmd)
cfg.PLUGIN_MANAGER.load(cfg=cfg)
cfg.PLUGIN_MANAGER.appStart()

logger.openlog()
qapp = qttools.createQApplication(cfg.APP_NAME)
translator = qttools.initiate_translator(cfg.language())
qapp.installTranslator(translator)

self.mainWindow = app.MainWindow(cfg, appInstance, qapp)

def tearDown(self):
#cfg.PLUGIN_MANAGER.appExit()
#appInstance.exitApplication()
#logger.closelog()
pass

def test_save_preferences_writes_file(self):
self.mainWindow.save_preferences()
self.assertTrue(os.path.exists('main_preferences'))

def test_save_preferences_writes_correct_data(self):
test_preferences = {'key1': 'value1', 'key2': 'value2'}
self.mainWindow.main_preferences = test_preferences
self.mainWindow.save_preferences()
with open('main_preferences', 'r') as file:
saved_preferences = json.load(file)
self.assertEqual(saved_preferences, test_preferences)


if __name__ == '__main__':
unittest.main()
125 changes: 96 additions & 29 deletions qt/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import signal
from contextlib import contextmanager
from tempfile import TemporaryDirectory
import json

# We need to import common/tools.py
import qttools_path
Expand Down Expand Up @@ -133,6 +134,17 @@ def __init__(self, config, appInstance, qapp):
# shortcuts without buttons
self._create_shortcuts_without_actions()

# get user preferences
self.main_preferences = self.get_preferences()
if self.main_preferences is None:
self.main_preferences = {'show_toolbar_text': False}
self.save_preferences()

# GUI elements to use throughout class
self.actions_for_toolbar = None
self.icon_text_actions = []
self.toolbar = None

self._create_actions()
self._create_menubar()
self._create_main_toolbar()
Expand Down Expand Up @@ -241,7 +253,7 @@ def __init__(self, config, appInstance, qapp):
self.filesView.header().sortIndicatorSection(),
self.filesView.header().sortIndicatorOrder())
self.filesView.header() \
.sortIndicatorChanged.connect(self.filesViewModel.sort)
.sortIndicatorChanged.connect(self.filesViewModel.sort)

self.stackFilesView.setCurrentWidget(self.filesView)

Expand All @@ -251,7 +263,7 @@ def __init__(self, config, appInstance, qapp):
# context menu for Files View
self.filesView.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
self.filesView.customContextMenuRequested \
.connect(self.contextMenuClicked)
.connect(self.contextMenuClicked)
self.contextMenu = QMenu(self)
self.contextMenu.addAction(self.act_restore)
self.contextMenu.addAction(self.act_restore_to)
Expand Down Expand Up @@ -393,7 +405,7 @@ def __init__(self, config, appInstance, qapp):
# populate lists
self.updateProfiles()
self.comboProfiles.currentIndexChanged \
.connect(self.comboProfileChanged)
.connect(self.comboProfileChanged)

self.filesView.setFocus()

Expand Down Expand Up @@ -593,6 +605,11 @@ def _create_actions(self):
'act_snapshots_dialog': (
icon.SNAPSHOTS, _('Compare snapshots…'),
self.btnSnapshotsClicked, None, None),

# Could be moved into dedicated preferences window in the future
'act_show_toolbar_text': (
None, _('Show toolbar text'),
self.btnShowToolbarTextClicked, None, None),
}

for attr in action_dict:
Expand All @@ -605,6 +622,14 @@ def _create_actions(self):
action = QAction(ico, txt, self) if ico else \
QAction(txt, self)

# Save action to use elsewhere in class
self.icon_text_actions.append([attr, action, ico, txt])

# Make items checkboxes
if attr == 'act_show_toolbar_text':
action.setCheckable(True)
action.setChecked(self.main_preferences['show_toolbar_text'])

# Connect handler function
if slot:
action.triggered.connect(slot)
Expand Down Expand Up @@ -677,6 +702,9 @@ def _create_menubar(self):
self.act_restore_parent,
self.act_restore_parent_to,
),
_('&Preferences'): (
self.act_show_toolbar_text
),
_('&Help'): (
self.act_help_help,
self.act_help_configfile,
Expand All @@ -692,9 +720,10 @@ def _create_menubar(self):
# Filter out 'None' from 'Back In &Time'
menu_dict['Back In &Time'] = tuple(a for a in menu_dict['Back In &Time'] if a is not None)

for key in menu_dict:
for key, actions in menu_dict.items():
menu = self.menuBar().addMenu(key)
menu.addActions(menu_dict[key])
menu.addActions(actions) if isinstance(actions, tuple) else \
menu.addAction(actions)
menu.setToolTipsVisible(True)

# The action of the restore menu. It is used by the menuBar and by the
Expand All @@ -719,14 +748,14 @@ def _create_menubar(self):
def _create_main_toolbar(self):
"""Create the main toolbar and connect it to actions."""

toolbar = self.addToolBar('main')
toolbar.setFloatable(False)
self.toolbar = self.addToolBar('main')
self.toolbar.setFloatable(False)

# Drop-Down: Profiles
self.comboProfiles = qttools.ProfileCombo(self)
self.comboProfilesAction = toolbar.addWidget(self.comboProfiles)
self.comboProfilesAction = self.toolbar.addWidget(self.comboProfiles)

actions_for_toolbar = [
self.actions_for_toolbar = [
self.act_take_snapshot,
self.act_pause_take_snapshot,
self.act_resume_take_snapshot,
Expand All @@ -743,21 +772,22 @@ def _create_main_toolbar(self):
actions_for_toolbar.append(self.act_suspend)

# Add each action to toolbar
for act in actions_for_toolbar:
toolbar.addAction(act)
for act in self.actions_for_toolbar:
self.toolbar.addAction(act)

# Assume an explicit tooltip if it is different from "text()".
# Note that Qt use "text()" as "toolTip()" by default.
if act.toolTip() != act.text():
if act.toolTip() == act.text():
continue

if QApplication.instance().isRightToLeft():
# RTL/BIDI language like Hebrew
button_tip = f'{act.toolTip()} :{act.text()}'
else:
# (default) LTR language (e.g. English)
button_tip = f'{act.text()}: {act.toolTip()}'
if QApplication.instance().isRightToLeft():
# RTL/BIDI language like Hebrew
button_tip = f'{act.toolTip()} :{act.text()}'
else:
# (default) LTR language (e.g. English)
button_tip = f'{act.text()}: {act.toolTip()}'

toolbar.widgetForAction(act).setToolTip(button_tip)
self.toolbar.widgetForAction(act).setToolTip(button_tip)

# toolbar sub menu: take snapshot
submenu_take_snapshot = QMenu(self)
Expand All @@ -766,7 +796,7 @@ def _create_main_toolbar(self):
submenu_take_snapshot.setToolTipsVisible(True)

# get the toolbar buttons widget...
button_take_snapshot = toolbar.widgetForAction(self.act_take_snapshot)
button_take_snapshot = self.toolbar.widgetForAction(self.act_take_snapshot)
# ...and add the menu to it
button_take_snapshot.setMenu(submenu_take_snapshot)
button_take_snapshot.setPopupMode(
Expand All @@ -777,6 +807,8 @@ def _create_main_toolbar(self):
toolbar.insertSeparator(self.act_shutdown)
if self.shutdown.canSuspend():
toolbar.insertSeparator(self.act_suspend)

self.set_toolbar_icon_text()

def _create_and_get_filesview_toolbar(self):
"""Create the filesview toolbar object, connect it to actions and
Expand Down Expand Up @@ -994,8 +1026,8 @@ def updateTakeSnapshot(self, force_wait_lock=False):

if not self.act_stop_take_snapshot.isVisible():
for action in (self.act_pause_take_snapshot,
self.act_resume_take_snapshot,
self.act_stop_take_snapshot):
self.act_resume_take_snapshot,
self.act_stop_take_snapshot):
action.setEnabled(True)
self.act_take_snapshot.setVisible(False)
self.act_pause_take_snapshot.setVisible(not paused)
Expand Down Expand Up @@ -1186,6 +1218,9 @@ def updateSnapshotActions(self, item = None):
self.act_remove_snapshot.setEnabled(enabled)
self.act_snapshot_logview.setEnabled(enabled)

# setEnabled returns icon, which is not ideal if buttons should only show text
self.set_toolbar_icon_text()

def timeLineChanged(self):
item = self.timeLine.currentItem()
self.updateSnapshotActions(item)
Expand Down Expand Up @@ -1394,17 +1429,17 @@ def backupOnRestore(self):
cb = QCheckBox(_(
'Create backup copies with trailing {suffix}\n'
'before overwriting or removing local elements.').format(
suffix=self.snapshots.backupSuffix()))
suffix=self.snapshots.backupSuffix()))

cb.setChecked(self.config.backupOnRestore())
cb.setToolTip(_(
"Newer versions of files will be renamed with trailing "
"{suffix} before restoring.\n"
"If you don't need them anymore you can remove them with {cmd}")
.format(suffix=self.snapshots.backupSuffix(),
cmd='find ./ -name "*{suffix}" -delete'
.format(suffix=self.snapshots.backupSuffix()))
)
.format(suffix=self.snapshots.backupSuffix(),
cmd='find ./ -name "*{suffix}" -delete'
.format(suffix=self.snapshots.backupSuffix()))
)
return {
'widget': cb,
'retFunc': cb.isChecked,
Expand Down Expand Up @@ -1685,8 +1720,8 @@ def openPath(self, rel_path):
# The class "GenericNonSnapshot" indicates that "Now" is selected
# in the snapshots timeline widget.
if (os.path.exists(full_path)
and (isinstance(self.sid, snapshots.GenericNonSnapshot) # "Now"
or self.sid.isExistingPathInsideSnapshotFolder(rel_path))):
and (isinstance(self.sid, snapshots.GenericNonSnapshot) # "Now"
or self.sid.isExistingPathInsideSnapshotFolder(rel_path))):

if os.path.isdir(full_path):
self.path = rel_path
Expand Down Expand Up @@ -1928,6 +1963,38 @@ def slot_setup_language(self):
def slot_help_translation(self):
self._open_approach_translator_dialog()

def btnShowToolbarTextClicked(self, checked):
self.main_preferences['show_toolbar_text'] = checked
self.save_preferences()
self.set_toolbar_icon_text()

def set_toolbar_icon_text(self):
"""Based on user preference, this sets the toolbar buttons to display either text or icons."""
for action in self.actions_for_toolbar:
attr, act, ico, txt = [a for a in self.icon_text_actions if a[1] == action][0]
widget = self.toolbar.widgetForAction(act)

if self.main_preferences['show_toolbar_text'] or not ico:
widget.setIcon(QIcon())
else:
widget.setIcon(ico)

setattr(self, attr, act)

def get_preferences(self):
"""Returns a dictionary of the main user-preferences from a json-formatted text file."""
file = 'main_preferences'
if not os.path.exists(file) or os.path.getsize(file) == 0:
return

with open('main_preferences', 'r') as file:
return json.load(file)

def save_preferences(self):
"""Writes user-preferences to a text file."""
with open('main_preferences', 'w') as file:
json.dump(self.main_preferences, file, indent=4)


class ExtraMouseButtonEventFilter(QObject):
"""
Expand Down

0 comments on commit 0dbb000

Please sign in to comment.