| OLD | NEW | 
|---|
|  | (Empty) | 
| 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 '''The 'grit resize' tool. |  | 
| 7 ''' |  | 
| 8 |  | 
| 9 import getopt |  | 
| 10 import os |  | 
| 11 |  | 
| 12 from grit import grd_reader |  | 
| 13 from grit import pseudo |  | 
| 14 from grit import util |  | 
| 15 from grit.format import rc |  | 
| 16 from grit.format import rc_header |  | 
| 17 from grit.node import include |  | 
| 18 from grit.tool import interface |  | 
| 19 |  | 
| 20 |  | 
| 21 # Template for the .vcproj file, with a couple of [[REPLACEABLE]] parts. |  | 
| 22 PROJECT_TEMPLATE = '''\ |  | 
| 23 <?xml version="1.0" encoding="Windows-1252"?> |  | 
| 24 <VisualStudioProject |  | 
| 25         ProjectType="Visual C++" |  | 
| 26         Version="7.10" |  | 
| 27         Name="[[DIALOG_NAME]]" |  | 
| 28         ProjectGUID="[[PROJECT_GUID]]" |  | 
| 29         Keyword="Win32Proj"> |  | 
| 30         <Platforms> |  | 
| 31                 <Platform |  | 
| 32                         Name="Win32"/> |  | 
| 33         </Platforms> |  | 
| 34         <Configurations> |  | 
| 35                 <Configuration |  | 
| 36                         Name="Debug|Win32" |  | 
| 37                         OutputDirectory="Debug" |  | 
| 38                         IntermediateDirectory="Debug" |  | 
| 39                         ConfigurationType="1" |  | 
| 40                         CharacterSet="2"> |  | 
| 41                 </Configuration> |  | 
| 42         </Configurations> |  | 
| 43         <References> |  | 
| 44         </References> |  | 
| 45         <Files> |  | 
| 46                 <Filter |  | 
| 47                         Name="Resource Files" |  | 
| 48                         Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;
     jpe;resx" |  | 
| 49                         UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
     "> |  | 
| 50                         <File |  | 
| 51                                 RelativePath=".\[[DIALOG_NAME]].rc"> |  | 
| 52                         </File> |  | 
| 53                 </Filter> |  | 
| 54         </Files> |  | 
| 55         <Globals> |  | 
| 56         </Globals> |  | 
| 57 </VisualStudioProject>''' |  | 
| 58 |  | 
| 59 |  | 
| 60 # Template for the .rc file with a couple of [[REPLACEABLE]] parts. |  | 
| 61 # TODO(joi) Improve this (and the resource.h template) to allow saving and then |  | 
| 62 # reopening of the RC file in Visual Studio.  Currently you can only open it |  | 
| 63 # once and change it, then after you close it you won't be able to reopen it. |  | 
| 64 RC_TEMPLATE = '''\ |  | 
| 65 // This file is automatically generated by GRIT and intended for editing |  | 
| 66 // the layout of the dialogs contained in it.  Do not edit anything but the |  | 
| 67 // dialogs.  Any changes made to translateable portions of the dialogs will |  | 
| 68 // be ignored by GRIT. |  | 
| 69 |  | 
| 70 #include "resource.h" |  | 
| 71 #include <winresrc.h> |  | 
| 72 #ifdef IDC_STATIC |  | 
| 73 #undef IDC_STATIC |  | 
| 74 #endif |  | 
| 75 #define IDC_STATIC (-1) |  | 
| 76 |  | 
| 77 LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL |  | 
| 78 |  | 
| 79 #pragma code_page([[CODEPAGE_NUM]]) |  | 
| 80 |  | 
| 81 [[INCLUDES]] |  | 
| 82 |  | 
| 83 [[DIALOGS]] |  | 
| 84 ''' |  | 
| 85 |  | 
| 86 |  | 
| 87 # Template for the resource.h file with a couple of [[REPLACEABLE]] parts. |  | 
| 88 HEADER_TEMPLATE = '''\ |  | 
| 89 // This file is automatically generated by GRIT.  Do not edit. |  | 
| 90 |  | 
| 91 #pragma once |  | 
| 92 |  | 
| 93 // Edit commands |  | 
| 94 #define ID_EDIT_CLEAR                   0xE120 |  | 
| 95 #define ID_EDIT_CLEAR_ALL               0xE121 |  | 
| 96 #define ID_EDIT_COPY                    0xE122 |  | 
| 97 #define ID_EDIT_CUT                     0xE123 |  | 
| 98 #define ID_EDIT_FIND                    0xE124 |  | 
| 99 #define ID_EDIT_PASTE                   0xE125 |  | 
| 100 #define ID_EDIT_PASTE_LINK              0xE126 |  | 
| 101 #define ID_EDIT_PASTE_SPECIAL           0xE127 |  | 
| 102 #define ID_EDIT_REPEAT                  0xE128 |  | 
| 103 #define ID_EDIT_REPLACE                 0xE129 |  | 
| 104 #define ID_EDIT_SELECT_ALL              0xE12A |  | 
| 105 #define ID_EDIT_UNDO                    0xE12B |  | 
| 106 #define ID_EDIT_REDO                    0xE12C |  | 
| 107 |  | 
| 108 |  | 
| 109 [[DEFINES]] |  | 
| 110 ''' |  | 
| 111 |  | 
| 112 |  | 
| 113 class ResizeDialog(interface.Tool): |  | 
| 114   '''Generates an RC file, header and Visual Studio project that you can use |  | 
| 115 with Visual Studio's GUI resource editor to modify the layout of dialogs for |  | 
| 116 the language of your choice.  You then use the RC file, after you resize the |  | 
| 117 dialog, for the language or languages of your choice, using the <skeleton> child |  | 
| 118 of the <structure> node for the dialog.  The translateable bits of the dialog |  | 
| 119 will be ignored when you use the <skeleton> node (GRIT will instead use the |  | 
| 120 translateable bits from the original dialog) but the layout changes you make |  | 
| 121 will be used.  Note that your layout changes must preserve the order of the |  | 
| 122 translateable elements in the RC file. |  | 
| 123 |  | 
| 124 Usage: grit resize [-f BASEFOLDER] [-l LANG] [-e RCENCODING] DIALOGID* |  | 
| 125 |  | 
| 126 Arguments: |  | 
| 127   DIALOGID        The 'name' attribute of a dialog to output for resizing.  Zero |  | 
| 128                   or more of these parameters can be used.  If none are |  | 
| 129                   specified, all dialogs from the input .grd file are output. |  | 
| 130 |  | 
| 131 Options: |  | 
| 132 |  | 
| 133   -f BASEFOLDER   The project will be created in a subfolder of BASEFOLDER. |  | 
| 134                   The name of the subfolder will be the first DIALOGID you |  | 
| 135                   specify.  Defaults to '.' |  | 
| 136 |  | 
| 137   -l LANG         Specifies that the RC file should contain a dialog translated |  | 
| 138                   into the language LANG.  The default is a cp1252-representable |  | 
| 139                   pseudotranslation, because Visual Studio's GUI RC editor only |  | 
| 140                   supports single-byte encodings. |  | 
| 141 |  | 
| 142   -c CODEPAGE     Code page number to indicate to the RC compiler the encoding |  | 
| 143                   of the RC file, default is something reasonable for the |  | 
| 144                   language you selected (but this does not work for every single |  | 
| 145                   language).  See details on codepages below.  NOTE that you do |  | 
| 146                   not need to specify the codepage unless the tool complains |  | 
| 147                   that it's not sure which codepage to use.  See the following |  | 
| 148                   page for codepage numbers supported by Windows: |  | 
| 149                   http://www.microsoft.com/globaldev/reference/wincp.mspx |  | 
| 150 |  | 
| 151   -D NAME[=VAL]   Specify a C-preprocessor-like define NAME with optional |  | 
| 152                   value VAL (defaults to 1) which will be used to control |  | 
| 153                   conditional inclusion of resources. |  | 
| 154 |  | 
| 155 |  | 
| 156 IMPORTANT NOTE:  For now, the tool outputs a UTF-8 encoded file for any language |  | 
| 157 that can not be represented in cp1252 (i.e. anything other than Western |  | 
| 158 European languages).  You will need to open this file in a text editor and |  | 
| 159 save it using the codepage indicated in the #pragma code_page(XXXX) command |  | 
| 160 near the top of the file, before you open it in Visual Studio. |  | 
| 161 |  | 
| 162 ''' |  | 
| 163 |  | 
| 164   # TODO(joi) It would be cool to have this tool note the Perforce revision |  | 
| 165   # of the original RC file somewhere, such that the <skeleton> node could warn |  | 
| 166   # if the original RC file gets updated without the skeleton file being updated
     . |  | 
| 167 |  | 
| 168   # TODO(joi) Would be cool to have option to add the files to Perforce |  | 
| 169 |  | 
| 170   def __init__(self): |  | 
| 171     self.lang = pseudo.PSEUDO_LANG |  | 
| 172     self.defines = {} |  | 
| 173     self.base_folder = '.' |  | 
| 174     self.codepage_number = 1252 |  | 
| 175     self.codepage_number_specified_explicitly = False |  | 
| 176 |  | 
| 177   def SetLanguage(self, lang): |  | 
| 178     '''Sets the language code to output things in. |  | 
| 179     ''' |  | 
| 180     self.lang = lang |  | 
| 181     if not self.codepage_number_specified_explicitly: |  | 
| 182       self.codepage_number = util.LanguageToCodepage(lang) |  | 
| 183 |  | 
| 184   def GetEncoding(self): |  | 
| 185     if self.codepage_number == 1200: |  | 
| 186       return 'utf_16' |  | 
| 187     if self.codepage_number == 65001: |  | 
| 188       return 'utf_8' |  | 
| 189     return 'cp%d' % self.codepage_number |  | 
| 190 |  | 
| 191   def ShortDescription(self): |  | 
| 192     return 'Generate a file where you can resize a given dialog.' |  | 
| 193 |  | 
| 194   def Run(self, opts, args): |  | 
| 195     self.SetOptions(opts) |  | 
| 196 |  | 
| 197     own_opts, args = getopt.getopt(args, 'l:f:c:D:') |  | 
| 198     for key, val in own_opts: |  | 
| 199       if key == '-l': |  | 
| 200         self.SetLanguage(val) |  | 
| 201       if key == '-f': |  | 
| 202         self.base_folder = val |  | 
| 203       if key == '-c': |  | 
| 204         self.codepage_number = int(val) |  | 
| 205         self.codepage_number_specified_explicitly = True |  | 
| 206       if key == '-D': |  | 
| 207         name, val = util.ParseDefine(val) |  | 
| 208         self.defines[name] = val |  | 
| 209 |  | 
| 210     res_tree = grd_reader.Parse(opts.input, debug=opts.extra_verbose) |  | 
| 211     res_tree.OnlyTheseTranslations([self.lang]) |  | 
| 212     res_tree.RunGatherers() |  | 
| 213 |  | 
| 214     # Dialog IDs are either explicitly listed, or we output all dialogs from the |  | 
| 215     # .grd file |  | 
| 216     dialog_ids = args |  | 
| 217     if not len(dialog_ids): |  | 
| 218       for node in res_tree: |  | 
| 219         if node.name == 'structure' and node.attrs['type'] == 'dialog': |  | 
| 220           dialog_ids.append(node.attrs['name']) |  | 
| 221 |  | 
| 222     self.Process(res_tree, dialog_ids) |  | 
| 223 |  | 
| 224   def Process(self, grd, dialog_ids): |  | 
| 225     '''Outputs an RC file and header file for the dialog 'dialog_id' stored in |  | 
| 226     resource tree 'grd', to self.base_folder, as discussed in this class's |  | 
| 227     documentation. |  | 
| 228 |  | 
| 229     Arguments: |  | 
| 230       grd: grd = grd_reader.Parse(...); grd.RunGatherers() |  | 
| 231       dialog_ids: ['IDD_MYDIALOG', 'IDD_OTHERDIALOG'] |  | 
| 232     ''' |  | 
| 233     grd.SetOutputLanguage(self.lang) |  | 
| 234     grd.SetDefines(self.defines) |  | 
| 235 |  | 
| 236     project_name = dialog_ids[0] |  | 
| 237 |  | 
| 238     dir_path = os.path.join(self.base_folder, project_name) |  | 
| 239     if not os.path.isdir(dir_path): |  | 
| 240       os.mkdir(dir_path) |  | 
| 241 |  | 
| 242     # If this fails then we're not on Windows (or you don't have the required |  | 
| 243     # win32all Python libraries installed), so what are you doing mucking |  | 
| 244     # about with RC files anyway? :) |  | 
| 245     import pythoncom |  | 
| 246 |  | 
| 247     # Create the .vcproj file |  | 
| 248     project_text = PROJECT_TEMPLATE.replace( |  | 
| 249       '[[PROJECT_GUID]]', str(pythoncom.CreateGuid()) |  | 
| 250       ).replace('[[DIALOG_NAME]]', project_name) |  | 
| 251     fname = os.path.join(dir_path, '%s.vcproj' % project_name) |  | 
| 252     self.WriteFile(fname, project_text) |  | 
| 253     print "Wrote %s" % fname |  | 
| 254 |  | 
| 255     # Create the .rc file |  | 
| 256     # Output all <include> nodes since the dialogs might depend on them (e.g. |  | 
| 257     # for icons and bitmaps). |  | 
| 258     include_items = [] |  | 
| 259     for node in grd.ActiveDescendants(): |  | 
| 260       if isinstance(node, include.IncludeNode): |  | 
| 261         include_items.append(rc.FormatInclude(node, self.lang, '.')) |  | 
| 262     rc_text = RC_TEMPLATE.replace('[[CODEPAGE_NUM]]', |  | 
| 263                                   str(self.codepage_number)) |  | 
| 264     rc_text = rc_text.replace('[[INCLUDES]]', ''.join(include_items)) |  | 
| 265 |  | 
| 266     # Then output the dialogs we have been asked to output. |  | 
| 267     dialogs = [] |  | 
| 268     for dialog_id in dialog_ids: |  | 
| 269       node = grd.GetNodeById(dialog_id) |  | 
| 270       assert node.name == 'structure' and node.attrs['type'] == 'dialog' |  | 
| 271       # TODO(joi) Add exception handling for better error reporting |  | 
| 272       dialogs.append(rc.FormatStructure(node, self.lang, '.')) |  | 
| 273     rc_text = rc_text.replace('[[DIALOGS]]', ''.join(dialogs)) |  | 
| 274 |  | 
| 275     fname = os.path.join(dir_path, '%s.rc' % project_name) |  | 
| 276     self.WriteFile(fname, rc_text, self.GetEncoding()) |  | 
| 277     print "Wrote %s" % fname |  | 
| 278 |  | 
| 279     # Create the resource.h file |  | 
| 280     header_defines = ''.join(rc_header.FormatDefines(grd)) |  | 
| 281     header_text = HEADER_TEMPLATE.replace('[[DEFINES]]', header_defines) |  | 
| 282     fname = os.path.join(dir_path, 'resource.h') |  | 
| 283     self.WriteFile(fname, header_text) |  | 
| 284     print "Wrote %s" % fname |  | 
| 285 |  | 
| 286   def WriteFile(self, filename, contents, encoding='cp1252'): |  | 
| 287     with open(filename, 'wb') as f: |  | 
| 288       writer = util.WrapOutputStream(f, encoding) |  | 
| 289       writer.write(contents) |  | 
| OLD | NEW | 
|---|