Skip to content

Commit

Permalink
NXDRIVE-1385: Missing translations
Browse files Browse the repository at this point in the history
- Register the context menu with Python on Windows, to be able to modify it when the language settings change.
- Send the context menu entries to the FinderSync extension through the Notification Center when the language settings change.
  • Loading branch information
LKleinNux committed Nov 27, 2018
1 parent eafb8c0 commit fa55386
Show file tree
Hide file tree
Showing 19 changed files with 348 additions and 212 deletions.
12 changes: 12 additions & 0 deletions docs/changes/4.0.2.md
Expand Up @@ -8,4 +8,16 @@ Changes in command line arguments:

## Core

- [NXDRIVE-1385](https://jira.nuxeo.com/browse/NXDRIVE-1385): Missing translations
- [NXDRIVE-1433](https://jira.nuxeo.com/browse/NXDRIVE-1433): Handle custom SSL certificates

## Technical Changes

- Moved `CliHandler.get_value()` to utils.py::`get_value()`
- Added `DarwinIntegration.register_contextual_menu()`
- Changed `DriveSystrayIcon.context_menu` property to `DriveSystrayIcon.get_context_menu()` function
- Added `Translator.on_change()`
- Added `WindowsIntegration.register_contextual_menu()`
- Added `WindowsIntegration.register_contextual_menu_entry()`
- Added `WindowsIntegration.unregister_contextual_menu()`
- Added osi/windows/registry.py
5 changes: 3 additions & 2 deletions docs/configuration.md
Expand Up @@ -16,9 +16,10 @@ Each of these ways overrides the previous one.

### Names and Values

Parameters' names are quite flexible. For instance you can specify `ssl-no-verify`, `ssl_no_verify` or `ssl_no-verify`: same result.
Parameter names are quite flexible. There is no differentiation between lowercase and uppercase, nor between hyphens and underscores.
For instance, you can specify `ssl-no-verify`, `ssl_no_verify`, `ssl_no-verify` or `SSL_No_verify`, it will be the same result.

Parameters' values are even more flexible. If the value is a boolean, you can specify (case insensitive):
Parameter values are taken as is, except for booleans. In that case, you can specify, in lowercase or uppercase:

- `true`, `1`, `on`, `yes` or `oui` to enable
- `false`, `0`, `off`, `no` or `non` to disable
Expand Down
53 changes: 18 additions & 35 deletions nxdrive/commandline.py
Expand Up @@ -9,14 +9,19 @@
from configparser import DEFAULTSECT, ConfigParser
from datetime import datetime
from logging import getLogger
from typing import List, TYPE_CHECKING, Tuple, Union
from typing import List, TYPE_CHECKING, Union

from . import __version__
from .constants import APP_NAME
from .logging_config import configure
from .options import Options
from .osi import AbstractOSIntegration
from .utils import force_encode, get_default_nuxeo_drive_folder, normalized_path
from .utils import (
force_encode,
get_default_nuxeo_drive_folder,
get_value,
normalized_path,
)

try:
import ipdb as pdb
Expand Down Expand Up @@ -394,19 +399,6 @@ def info(etype, value, tb):

return options

@staticmethod
def get_value(name: str, value: str) -> Union[bool, str, Tuple[str, ...]]:
"""Handle a given parameter from config.ini."""

if value.lower() in {"true", "1", "on", "yes", "oui"}:
return True
elif value.lower() in {"false", "0", "off", "no", "non"}:
return False
elif "\n" in value:
return tuple(sorted(value.split()))

return value

def load_config(
self, parser: ArgumentParser, conf_name: str = "config.ini"
) -> None:
Expand Down Expand Up @@ -439,7 +431,7 @@ def load_config(
if name == "env" or value == "":
continue

conf_args[name.replace("-", "_")] = self.get_value(name, value)
conf_args[name.replace("-", "_").lower()] = get_value(value)

if conf_args:
file = os.path.abspath(conf_file)
Expand Down Expand Up @@ -468,8 +460,8 @@ def _configure_logger(self, command: str, options: Namespace) -> None:
force_configure=True,
)

def uninstall(self) -> None:
self.manager.osi.uninstall()
def uninstall(self, options: Namespace = None) -> None:
AbstractOSIntegration.get(None).uninstall()

def handle(self, argv: List[str]) -> int:
""" Parse options, setup logs and manager and dispatch execution. """
Expand All @@ -478,39 +470,30 @@ def handle(self, argv: List[str]) -> int:
if getattr(options, "local_folder", ""):
options.local_folder = normalized_path(options.local_folder)

# 'launch' is the default command if None is provided
log.debug(f"Command line: argv={argv!r}, options={options!r}")
log.info(f"Running on version {self.get_version()}")

command = getattr(options, "command", "launch")
handler = getattr(self, command, None)
if not handler:
raise NotImplementedError(f"No handler implemented for command {command}")

if command != "uninstall":
# Configure the logging framework, except for the tests as they
# configure their own.
# Don't need uninstall logs either for now.
self._configure_logger(command, options)
self._configure_logger(command, options)

log.debug(f"Command line: argv={argv!r}, options={options!r}")
if QSslSocket:
has_ssl_support = QSslSocket.supportsSsl()
log.info(f"SSL support: {has_ssl_support!r}")
if not has_ssl_support:
options.ca_bundle = None
options.ssl_no_verify = True

# Update default options
# We cannot use fail_on_error=True because options is a namespace
# and contains a lot of inexistant Options values.
Options.update(options, setter="cli", fail_on_error=False)

if command != "uninstall":
# Install utility to help debugging segmentation faults
self._install_faulthandler()

# Initialize a manager for this process
self.manager = self.get_manager()

# Find the command to execute based on the
handler = getattr(self, command, None)
if not handler:
raise NotImplementedError(f"No handler implemented for command {command}")
self.manager = self.get_manager()

return handler(options)

Expand Down
1 change: 1 addition & 0 deletions nxdrive/data/i18n/i18n.json
Expand Up @@ -35,6 +35,7 @@
"CONNECTION_UNKNOWN": "Unknown error occured while trying to connect",
"CONTEXT_MENU_1": "Access online",
"CONTEXT_MENU_2": "Copy share-link",
"CONTEXT_MENU_3": "Edit metadata",
"CONTINUE": "Continue",
"CONTINUE_USING": "Continue using Drive %1",
"CREATE_REPORT": "Generate a bug report",
Expand Down
10 changes: 10 additions & 0 deletions nxdrive/gui/application.py
Expand Up @@ -271,6 +271,11 @@ def _init_translator(self) -> None:
find_resource("i18n"),
self.manager.get_config("locale", locale),
)
# Make sure that a language change changes external values like
# the text in the contextual menu
Translator.on_change(self._handle_language_change)
# Trigger it now
self.osi.register_contextual_menu()
self.installTranslator(Translator._singleton)

@staticmethod
Expand Down Expand Up @@ -890,6 +895,11 @@ def setup_systray(self) -> None:
self.set_icon_state("disabled")
self.tray_icon.show()

def _handle_language_change(self) -> None:
if not MAC:
self.tray_icon.setContextMenu(self.tray_icon.get_context_menu())
self.osi.register_contextual_menu()

def event(self, event: QEvent) -> bool:
""" Handle URL scheme events under macOS. """

Expand Down
49 changes: 23 additions & 26 deletions nxdrive/gui/systray.py
Expand Up @@ -34,7 +34,7 @@ def __init__(self, application: "Application") -> None:
# On macOS, only the left click is detected, so the context
# menu is useless. It is better to not define it else it
# will show up every click on the systray icon.
self.setContextMenu(self.context_menu)
self.setContextMenu(self.get_context_menu())

def handle_mouse_click(self, reason: int) -> None:
"""
Expand All @@ -56,8 +56,7 @@ def handle_mouse_click(self, reason: int) -> None:
# On middle click, open settings. Yeah, it rocks!
self.application.show_settings()

@property
def context_menu(self) -> QMenu:
def get_context_menu(self) -> QMenu:
"""
Create the context menu.
It shows up on left click.
Expand All @@ -66,29 +65,27 @@ def context_menu(self) -> QMenu:
distributions, it depends on the graphical environment.
"""

if not self.__context_menu:
style = QApplication.style()
menu = QMenu()
menu.addAction(
style.standardIcon(QStyle.SP_FileDialogInfoView),
Translator.get("SETTINGS"),
self.application.show_settings,
)
menu.addSeparator()
menu.addAction(
style.standardIcon(QStyle.SP_MessageBoxQuestion),
Translator.get("HELP"),
self.application.open_help,
)
menu.addSeparator()
menu.addAction(
style.standardIcon(QStyle.SP_DialogCloseButton),
Translator.get("QUIT"),
self.application.quit,
)
self.__context_menu = menu

return self.__context_menu
style = QApplication.style()
menu = QMenu()
menu.addAction(
style.standardIcon(QStyle.SP_FileDialogInfoView),
Translator.get("SETTINGS"),
self.application.show_settings,
)
menu.addSeparator()
menu.addAction(
style.standardIcon(QStyle.SP_MessageBoxQuestion),
Translator.get("HELP"),
self.application.open_help,
)
menu.addSeparator()
menu.addAction(
style.standardIcon(QStyle.SP_DialogCloseButton),
Translator.get("QUIT"),
self.application.quit,
)

return menu


class SystrayWindow(QQuickView):
Expand Down
1 change: 1 addition & 0 deletions nxdrive/gui/view.py
Expand Up @@ -15,6 +15,7 @@
if TYPE_CHECKING:
from .api import QMLDriveApi # noqa
from .application import Application # noqa
from ..engine.engine import Engine # noqa

__all__ = ("FileModel", "LanguageModel")

Expand Down
7 changes: 7 additions & 0 deletions nxdrive/osi/__init__.py
Expand Up @@ -40,6 +40,7 @@ def uninstall(self) -> None:
"""
self.unregister_startup()
self.unregister_folder_link(None)
self.unregister_contextual_menu()

def register_protocol_handlers(self) -> None:
pass
Expand All @@ -56,6 +57,12 @@ def send_sync_status(self, state: DocPair, path: str) -> None:
def send_content_sync_status(self, states: List[DocPair], path: str) -> None:
pass

def register_contextual_menu(self) -> None:
pass

def unregister_contextual_menu(self) -> None:
pass

def register_folder_link(self, folder_path: str, name: str = None) -> None:
pass

Expand Down
9 changes: 9 additions & 0 deletions nxdrive/osi/darwin/darwin.py
Expand Up @@ -29,6 +29,7 @@
from ...constants import APP_NAME, BUNDLE_IDENTIFIER
from ...objects import DocPair
from ...options import Options
from ...translator import Translator
from ...utils import force_decode, if_frozen, normalized_path

if TYPE_CHECKING:
Expand Down Expand Up @@ -257,6 +258,14 @@ def _formatted_status(self, state: DocPair, path: str) -> Dict[str, str]:
status = "syncing"
return {"status": status, "path": path}

@if_frozen
def register_contextual_menu(self) -> None:
name = f"{BUNDLE_IDENTIFIER}.setConfig"

log.trace(f"Sending menu to FinderSync")
entries = [Translator.get(f"CONTEXT_MENU_{i}") for i in range(1, 4)]
self._send_notification(name, {"entries": entries})

def register_folder_link(self, folder_path: str, name: str = None) -> None:
favorites = self._get_favorite_list() or []
if not favorites:
Expand Down

0 comments on commit fa55386

Please sign in to comment.