#!/usr/bin/python
#
# Copyright (C) 2013 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see .
#
# Author: David Shea
import sys
import argparse
import re
import os.path
import copy
import collections
import locale
try:
from lxml import etree
except ImportError:
print("You need to install the python-lxml package to use check_accelerators.py")
sys.exit(1)
accel_re = re.compile(r'_(?P.)')
success = True
# Only used when --translate is requested.
class PODict(collections.Mapping):
def __init__(self, filename):
try:
import polib
except ImportError:
print("You need to install the python-polib package to check translations")
sys.exit(1)
self._dict = {}
pofile = polib.pofile(filename)
self.metadata = pofile.metadata
for entry in pofile.translated_entries():
self._dict[entry.msgid] = entry.msgstr
def __getitem__(self, key):
return self._dict[key]
def __iter__(self):
return self._dict.__iter__()
def __len__(self):
return len(self._dict)
def is_exception(node, language=None):
if language:
comment_str = "check_accelerators(%s)" % language
else:
comment_str = "check_accelerators"
return bool(node.xpath("./parent::*/comment()[contains(., '%s')]" % comment_str))
def add_check_accel(glade_filename, accels, label, po_map):
"""Check whether an accelerator conflicts with existing accelerators.
and add it to the current accelerator context.
"""
global success
language = None
if po_map:
if label.text not in po_map:
return
label.text = po_map[label.text]
language = po_map.metadata['Language']
match = accel_re.search(label.text)
if match:
accel = match.group('accel').lower()
if accel in accels:
# Check for an exception comment
if is_exception(label, language):
return
if language:
lang_str = " for language %s" % language
else:
lang_str = ""
print(("Accelerator collision for key %s in %s%s\n line %d: %s\n line %d: %s" %\
(accel, os.path.normpath(glade_filename), lang_str,
accels[accel].sourceline, accels[accel].text,
label.sourceline, label.text)).encode("utf-8"))
success = False
else:
accels[accel] = label
def combine_accels(glade_filename, list_a, list_b, po_map):
if not list_a:
return list_b
if not list_b:
return list_a
newlist = []
for accels_a in list_a:
for accels_b in list_b:
new_accels = copy.copy(accels_a)
for accel in accels_b.keys():
add_check_accel(glade_filename, new_accels, accels_b[accel], po_map)
newlist.append(new_accels)
return newlist
# GtkNotebook widgets define several child widgets, not all of which are active
# at the same time. To further complicate things, an object can have more than
# one GtkNotebook child, and a GtkNotebook can have GtkNotebook children.
#
# To handle this, GtkNotebook objects are processed separately.
# process_object returns a list of possible accelerator dictionaries, and each of
# these is compared against the list of accelerators returned for the object's
# other GtkNotebook children.
def process_object(glade_filename, interface_object, po_map):
"""Process keyboard shortcuts for a given glade object.
The return value from this function is a list of accelerator
dictionaries, with each consiting of accelerator shortcut characters
as keys and the corresponding