1#!/usr/bin/env python
2# Copyright (c) 2012 The Chromium Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6'''Interface for all gatherers.
7'''
8
9
10import os.path
11import types
12
13from grit import clique
14from grit import util
15
16
17class GathererBase(object):
18  '''Interface for all gatherer implementations.  Subclasses must implement
19  all methods that raise NotImplemented.'''
20
21  def __init__(self, rc_file, extkey=None, encoding='cp1252', is_skeleton=False):
22    '''Initializes the gatherer object's attributes, but does not attempt to
23    read the input file.
24
25    Args:
26      rc_file: The 'file' attribute of the <structure> node (usually the
27               relative path to the source file).
28      extkey: e.g. 'ID_MY_DIALOG'
29      encoding: e.g. 'utf-8'
30      is_skeleton: Indicates whether this gatherer is a skeleton gatherer, in
31                   which case we should not do some types of processing on the
32                   translateable bits.
33    '''
34    self.rc_file = rc_file
35    self.extkey = extkey
36    self.encoding = encoding
37    # A default uberclique that is local to this object.  Users can override
38    # this with the uberclique they are using.
39    self.uberclique = clique.UberClique()
40    # Indicates whether this gatherer is a skeleton gatherer, in which case
41    # we should not do some types of processing on the translateable bits.
42    self.is_skeleton = is_skeleton
43    # Stores the grd node on which this gatherer is running. This allows
44    # evaluating expressions.
45    self.grd_node = None
46
47  def SetAttributes(self, attrs):
48    '''Sets node attributes used by the gatherer.
49
50    By default, this does nothing.  If special handling is desired, it should be
51    overridden by the child gatherer.
52
53    Args:
54      attrs: The mapping of node attributes.
55    '''
56    pass
57
58  def SetDefines(self, defines):
59    '''Sets global defines used by the gatherer.
60
61    By default, this does nothing.  If special handling is desired, it should be
62    overridden by the child gatherer.
63
64    Args:
65      defines: The mapping of define values.
66    '''
67    pass
68
69  def SetGrdNode(self, node):
70    '''Sets the grd node on which this gatherer is running.
71    '''
72    self.grd_node = node
73
74  def SetUberClique(self, uberclique):
75    '''Overrides the default uberclique so that cliques created by this object
76    become part of the uberclique supplied by the user.
77    '''
78    self.uberclique = uberclique
79
80  def Parse(self):
81    '''Reads and parses the contents of what is being gathered.'''
82    raise NotImplementedError()
83
84  def GetData(self, lang, encoding):
85    '''Returns the data to be added to the DataPack for this node or None if
86    this node does not add a DataPack entry.
87    '''
88    return None
89
90  def GetText(self):
91    '''Returns the text of what is being gathered.'''
92    raise NotImplementedError()
93
94  def GetTextualIds(self):
95    '''Returns the mnemonic IDs that need to be defined for the resource
96    being gathered to compile correctly.'''
97    return []
98
99  def GetCliques(self):
100    '''Returns the MessageClique objects for all translateable portions.'''
101    return []
102
103  def GetInputPath(self):
104    return self.rc_file
105
106  def GetHtmlResourceFilenames(self):
107    """Returns a set of all filenames inlined by this gatherer."""
108    return []
109
110  def Translate(self, lang, pseudo_if_not_available=True,
111                skeleton_gatherer=None, fallback_to_english=False):
112    '''Returns the resource being gathered, with translateable portions filled
113    with the translation for language 'lang'.
114
115    If pseudo_if_not_available is true, a pseudotranslation will be used for any
116    message that doesn't have a real translation available.
117
118    If no translation is available and pseudo_if_not_available is false,
119    fallback_to_english controls the behavior.  If it is false, throw an error.
120    If it is true, use the English version of the message as its own
121    "translation".
122
123    If skeleton_gatherer is specified, the translation will use the nontranslateable
124    parts from the gatherer 'skeleton_gatherer', which must be of the same type
125    as 'self'.
126
127    If fallback_to_english
128
129    Args:
130      lang: 'en'
131      pseudo_if_not_available: True | False
132      skeleton_gatherer: other_gatherer
133      fallback_to_english: True | False
134
135    Return:
136      e.g. 'ID_THIS_SECTION TYPE\n...BEGIN\n  "Translated message"\n......\nEND'
137
138    Raises:
139      grit.exception.NotReady() if used before Parse() has been successfully
140      called.
141      grit.exception.NoSuchTranslation() if 'pseudo_if_not_available' and
142      fallback_to_english are both false and there is no translation for the
143      requested language.
144    '''
145    raise NotImplementedError()
146
147  def SubstituteMessages(self, substituter):
148    '''Applies substitutions to all messages in the gatherer.
149
150    Args:
151      substituter: a grit.util.Substituter object.
152    '''
153    pass
154
155  def SetFilenameExpansionFunction(self, fn):
156    '''Sets a function for rewriting filenames before gathering.'''
157    pass
158
159  # TODO(benrg): Move this elsewhere, since it isn't part of the interface.
160  def _LoadInputFile(self):
161    '''A convenience function for subclasses that loads the contents of the
162    input file.
163    '''
164    if isinstance(self.rc_file, types.StringTypes):
165      path = self.GetInputPath()
166      # Hack: some unit tests supply an absolute path and no root node.
167      if not os.path.isabs(path):
168        path = self.grd_node.ToRealPath(path)
169      return util.ReadFile(path, self.encoding)
170    else:
171      return self.rc_file.read()
172