Salome HOME
Sphinx portability
[modules/yacs.git] / src / AppQuickStart / app-quickstart.py
1 #! /usr/bin/env python
2 #  -*- coding: iso-8859-1 -*-
3 # Copyright (C) 2007-2015  CEA/DEN, EDF R&D, OPEN CASCADE
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18 #
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #
21
22 import os
23 import shutil
24 import optparse
25
26 # Options of this script
27 def profileQuickStartParser() :
28
29     parser = optparse.OptionParser( usage = "usage: python app-quickstart.py [options]" )
30
31     parser.add_option('-p',
32                       "--prefix",
33                       metavar="</Path/to/the/sources/of/application>",
34                       type="string",
35                       action="store",
36                       dest="prefix",
37                       default='.',
38                       help="Where the application's sources will be generated. [Default : '.']")
39
40     parser.add_option('-m',
41                       "--modules",
42                       metavar="<module1,module2,...>",
43                       type="string",
44                       action="store",
45                       dest="modules",
46                       default='KERNEL,GUI',
47                       help="List of the application's modules. [Default : KERNEL,GUI]")
48
49     parser.add_option('-n',
50                       "--name",
51                       type="string",
52                       action="store",
53                       dest="name",
54                       help="Name of the application")
55
56     parser.add_option('-v',
57                       "--version",
58                       type="string",
59                       action="store",
60                       dest="version",
61                       default='1.0',
62                       help="Version of the application. [Default : 1.0]")
63
64     parser.add_option('-s',
65                       "--slogan",
66                       type="string",
67                       action="store",
68                       dest="slogan",
69                       default='',
70                       help="Slogan of the application.")
71
72     parser.add_option('-f',
73                       "--force",
74                       action="store_true",
75                       dest="force",
76                       help="Overwrites existing sources")
77
78     return parser
79
80
81
82 #Create the splash screen
83 def profileGenerateSplash( resources_dir, appname, version, subtext ):
84     import Image
85     import ImageDraw
86     import ImageFont
87
88     uname = unicode(appname, 'UTF-8')
89     uversion = unicode(version, 'UTF-8')
90
91     # fonts
92     fontbig = ImageFont.truetype( os.path.join( resources_dir, 'Anita semi square.ttf' ), 64)
93     fontsmall = ImageFont.truetype( os.path.join( resources_dir, 'Anita semi square.ttf' ), 20)
94     textColor = "rgb(255, 250, 250)"
95     shadowColor = "rgb(0, 0, 0)"
96
97     # dimensions
98     nbcar = len(uname)
99     width = 600
100     if nbcar > 12:
101         width = min( width*nbcar/12, 1024) #a little more
102     height = 300
103     borderX = 30 #50
104     borderY = 3 #30
105     shadowX = 2
106     shadowY = shadowX
107
108     # load background image 
109     f0 = os.path.join( resources_dir, "background.png" )
110     im = Image.open(f0)
111     im = im.resize( ( width, height ) )
112     draw = ImageDraw.Draw(im)
113
114     # add the name of the application
115     iw, ih = draw.textsize(uname, font=fontbig)
116     x = (width - iw) / 2.0 # horizontal center
117     y = (height - ih) / 2.0 # vertical center
118     draw.text((x+shadowX, y+shadowY), uname, font=fontbig, fill=shadowColor)
119     draw.text((x, y), uname, font=fontbig, fill=textColor)
120
121     # add subtext
122     if len(subtext) > 0:
123         iw, ih = draw.textsize(subtext, font=fontsmall)
124         draw.text((borderX+shadowX, height+shadowY-borderY-ih),
125                   subtext, font=fontsmall, fill=shadowColor)
126         draw.text((borderX, height-borderY-ih),
127                   subtext, font=fontsmall, fill=textColor)
128
129     # add the version if any
130     if len(version) > 0:
131         iw, ih = draw.textsize(uversion, font=fontsmall)
132         draw.text((width+shadowX-borderX-iw, height+shadowY-borderY-ih),
133                   uversion, font=fontsmall, fill=shadowColor)
134         draw.text((width-borderX-iw, height-borderY-ih),
135                   uversion, font=fontsmall, fill=textColor)
136
137     del draw
138     return im
139
140
141 #Create the application logo
142 def profileGenerateLogo( appname, font ):
143     import Image
144     import ImageDraw
145
146     uname = unicode(appname, 'UTF-8')
147
148     # evaluate size before deleting draw
149     im = Image.new( "RGBA", (1, 1), (0, 0, 0, 0) )
150     draw = ImageDraw.Draw( im )
151
152     im = Image.new( "RGBA", draw.textsize( uname, font=font ), (0, 0, 0, 0) )
153     draw = ImageDraw.Draw(im)
154     draw.text( (0+1, 0), uname, font=font, fill="rgb(0, 0, 0)" )
155     draw.text( (0, -1), uname, font=font, fill="rgb(191, 191, 191)" )
156
157     del draw
158     return im
159
160    
161 #Replace strings in the template
162 def profileReplaceStrings( src, dst, options ) :
163     with open( dst, "wt" ) as fout:
164         with open( src, "rt" ) as fin:
165             for line in fin:
166                 if options.modules == '_NO_' and '[LIST_OF_MODULES]' in line:
167                     line = ''
168                 l = line.replace( '[LIST_OF_MODULES]', options.modules )
169                 l = l.replace( '[VERSION]', options.version )
170                 l = l.replace( '[SLOGAN]', options.slogan )
171                 l = l.replace( '[NAME_OF_APPLICATION]', options.name.upper() )
172                 l = l.replace( '[Name_of_Application]', options.name )
173                 l = l.replace( '(name_of_application)', options.name.lower() )
174                 fout.write( l )
175
176
177 #Generation of a template profile sources
178 def profileGenerateSources( options, args ) :
179
180     #Set name of several directories
181     app_dir = options.prefix
182     app_resources_dir = os.path.join( app_dir, "resources" )
183     kernel_root_dir = os.environ["KERNEL_ROOT_DIR"]
184     bin_salome_dir = os.path.join( kernel_root_dir, "bin", "salome" )
185     kernel_resources_dir = os.path.join( kernel_root_dir, "share", "salome", "resources", "kernel" )
186     template_dir = os.path.join( kernel_resources_dir, "app-template" )
187
188     #Check if the directory of the sources already exists and delete it
189     if os.path.exists( app_dir ) :
190         if not options.force :
191             print "Directory %s already exists." %app_dir
192             print "Use option --force to overwrite it."
193             return
194         else :
195             shutil.rmtree( app_dir )
196
197     #Copy template directory
198     os.mkdir( app_dir )
199     for root, dirs, files in os.walk( template_dir ) :
200         dst_dir = root.replace( template_dir, app_dir ) 
201         for d in dirs :
202             os.mkdir( os.path.join( dst_dir, d ) )
203         for f in files :
204             profileReplaceStrings( os.path.join( root, f ), os.path.join( dst_dir, f ), options )
205
206     #Complete source directory
207     contextFiles = [ "salomeContext.py", "salomeContextUtils.py", "parseConfigFile.py" ]
208     for f in contextFiles :
209         shutil.copy( os.path.join( bin_salome_dir, f ), os.path.join( app_dir, "src" ) )
210
211     #Search for python modules Image, ImageDraw and ImageFont
212     try:
213         import imp
214         imp.find_module('Image')
215         imp.find_module('ImageDraw')
216         imp.find_module('ImageFont')
217         found = True
218     except ImportError:
219         found = False
220
221     #Generate logo and splash
222     logo_destination = os.path.join( app_resources_dir, 'app_logo.png')
223     splash_destination = os.path.join( app_resources_dir, 'splash.png')
224     about_destination = os.path.join( app_resources_dir, 'about.png')
225     if found :
226         import ImageFont
227         font = ImageFont.truetype( os.path.join( kernel_resources_dir, "Anita semi square.ttf" ) , 18 )
228
229         #Generate and save logo
230         app_logo = profileGenerateLogo( options.name, font )
231         app_logo.save( logo_destination, "PNG" )
232
233         #Generate and splash screen and about image
234         if options.slogan :
235             subtext = options.slogan
236         else :
237             subtext = "Powered by SALOME"
238         im = profileGenerateSplash( kernel_resources_dir, options.name, options.version, subtext )
239         im.save( splash_destination, "PNG" )
240         im.save( about_destination, "PNG" )
241     else :
242         gui_resources_dir = os.path.join( os.environ["GUI_ROOT_DIR"], "share", "salome", "resources", "gui" )
243         logo_name = os.path.join( gui_resources_dir, "icon_applogo.png" )
244         if os.path.exists( logo_name ) :
245             shutil.copy( logo_name, logo_destination )
246         about_name = os.path.join( gui_resources_dir, "icon_about.png" )
247         if os.path.exists( about_name ) :
248             shutil.copy( about_name, about_destination )
249             shutil.copy( about_name, splash_destination )
250
251     #End of script
252     print "Sources of %s were generated in %s." %( options.name, app_dir )
253
254
255 # -----------------------------------------------------------------------------
256
257 if __name__ == '__main__':
258     #Get options and args
259     (options, args) = profileQuickStartParser().parse_args()
260
261     #Check name of the application
262     if not options.name :
263         raise RuntimeError( "A name must be given to the application. Please use option --name." )
264
265     #Check if the prefix's parent is a directory
266     if not os.path.isdir( os.path.dirname( options.prefix ) ) :
267         raise RuntimeError( "%s is not a directory." % os.path.dirname( options.prefix ) )
268
269     #Generate sources of the profile
270     profileGenerateSources( options, args )