Module callirhoe
[hide private]
[frames] | no frames]

Source Code for Module callirhoe

  1  #!/usr/bin/env python2.7 
  2  # -*- coding: utf-8 -*- 
  3   
  4  #    callirhoe - high quality calendar rendering 
  5  #    Copyright (C) 2012-2014 George M. Tzoumas 
  6   
  7  #    This program is free software: you can redistribute it and/or modify 
  8  #    it under the terms of the GNU General Public License as published by 
  9  #    the Free Software Foundation, either version 3 of the License, or 
 10  #    (at your option) any later version. 
 11  # 
 12  #    This program is distributed in the hope that it will be useful, 
 13  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 14  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 15  #    GNU General Public License for more details. 
 16  # 
 17  #    You should have received a copy of the GNU General Public License 
 18  #    along with this program.  If not, see http://www.gnu.org/licenses/ 
 19   
 20  """high quality calendar rendering""" 
 21   
 22  # TODO: 
 23   
 24  # fix auto-measure rendering (cairo) 
 25  # fix plugin loading (without global vars) 
 26  # week markers selectable 
 27  # test layouts 
 28   
 29  # allow to change background color (fill), other than white 
 30  # page spec parse errors 
 31  # mobile themes (e.g. 800x480) 
 32  # photo support (like ImageMagick's polaroid effect) 
 33  # .callirhoe/config : default values for plugins (styles/layouts/lang...) and cmdline 
 34   
 35  # MAYBE-TODO: 
 36  # implement various data sources 
 37  # auto-landscape? should aim for matrix or bars? 
 38  # allow /usr/bin/date-like formatting %x...  
 39  # improve file matching with __init__ when lang known 
 40  # styles and geometries could be merged, css-like 
 41  #  then we can apply a chain of --style a --style b ... 
 42  #  and b inherits from a and so on 
 43  #  however, this would require dynamically creating a class that inherits from others... 
 44   
 45  # CANNOT UPGRADE TO argparse !!! -- how to handle [[month] year] form? 
 46   
 47  import calendar 
 48  import sys 
 49  import time 
 50  import optparse 
 51  import lib.xcairo as xcairo 
 52  import lib.holiday as holiday 
 53  import lib 
 54   
 55  from lib.plugin import * 
 56  # TODO: SEE IF IT CAN BE MOVED INTO lib.plugin ... 
57 -def import_plugin(plugin_paths, cat, longcat, longcat2, listopt, preset):
58 """import a plugin making it visible 59 60 I{Example:} 61 62 >>> Language = import_plugin(get_plugin_paths(), "lang", "language", "languages", "--list-languages", "EN") 63 64 @param plugin_paths: list of plugin search paths 65 @param cat: short category name (for folder name) 66 @param longcat: long category name 67 @param longcat2: long category name in plural form 68 @param listopt: option name 69 @param preset: default value 70 @rtype: module 71 72 @note: Aimed for internal use with I{lang}, I{style}, I{geom}, I{layouts}. 73 """ 74 try: 75 found = [] 76 for path in plugin_paths: 77 found += available_files(path, cat, preset) 78 if len(found) == 0: raise IOError 79 if found[0][1] == "resource:": 80 m = __import__("%s.%s" % (cat,preset), globals(), locals(), [ "*" ]) 81 else: 82 sys.path.insert(0, found[0][1]) 83 m = __import__("%s.%s" % (cat,preset), globals(), locals(), [ "*" ]) 84 sys.path.pop(0) 85 return m 86 except IOError: 87 sys.exit("callirhoe: %s definition '%s' not found, use %s to see available definitions" % (longcat, 88 preset,listopt)) 89 except ImportError: 90 sys.exit("callirhoe: error loading %s definition '%s'" % (longcat, preset))
91 126
127 -def add_list_option(parser, opt):
128 """add a --list-I{plugins} option to parser 129 130 @note: To be used with I{languages}, I{layouts}, I{styles} and I{geometries}. 131 """ 132 parser.add_option("--list-%s" % opt, action="store_true", dest="list_%s" % opt, default=False, 133 help="list available %s" % opt)
134
135 -def get_parser():
136 """get the argument parser object 137 138 @rtype: optparse.OptionParser 139 """ 140 parser = optparse.OptionParser(usage="usage: %prog [options] [[MONTH[-MONTH2|:SPAN]] YEAR] FILE", 141 description="High quality calendar rendering with vector graphics. " 142 "By default, a calendar of the current year in pdf format is written to FILE. " 143 "Alternatively, you can select a specific YEAR (0=current), " 144 "and a month range from MONTH (0-12, 0=current) to MONTH2 or for SPAN months.", 145 version="callirhoe " + lib._version + '\n' + lib._copyright) 146 parser.add_option("-l", "--lang", dest="lang", default="EN", 147 help="choose language [%default]") 148 parser.add_option("-t", "--layout", dest="layout", default="classic", 149 help="choose layout [%default]") 150 parser.add_option("-?", "--layout-help", dest="layouthelp", action="store_true", default=False, 151 help="show layout-specific help") 152 parser.add_option("--examples", dest="examples", action="store_true", 153 help="display some usage examples") 154 parser.add_option("-s", "--style", dest="style", default="default", 155 help="choose style [%default]") 156 parser.add_option("-g", "--geometry", dest="geom", default="default", 157 help="choose geometry [%default]") 158 parser.add_option("--landscape", action="store_true", dest="landscape", default=False, 159 help="landscape mode") 160 parser.add_option("--dpi", type="float", default=72.0, 161 help="set DPI (for raster output) [%default]") 162 parser.add_option("--paper", default="a4", 163 help="set paper type; PAPER can be an ISO paper type (a0..a9 or a0w..a9w) or of the " 164 "form W:H; positive values correspond to W or H mm, negative values correspond to " 165 "-W or -H pixels; 'w' suffix swaps width & height [%default]") 166 parser.add_option("--border", type="float", default=3, 167 help="set border size (in mm) [%default]") 168 parser.add_option("-H", "--with-holidays", action="append", dest="holidays", 169 help="load holiday file (can be used multiple times)") 170 parser.add_option("--short-monthnames", action="store_true", default=False, 171 help="user the short version of month names (defined in language file) [%default]") 172 parser.add_option("--long-daynames", action="store_true", default=False, 173 help="user the long version of day names (defined in language file) [%default]") 174 parser.add_option("-T", "--terse-holidays", action="store_false", dest="multiday_holidays", 175 default=True, help="do not print holiday end markers and omit dots") 176 177 for x in ["languages", "layouts", "styles", "geometries"]: 178 add_list_option(parser, x) 179 180 parser.add_option("--lang-var", action="append", dest="lang_assign", 181 help="modify a language variable") 182 parser.add_option("--style-var", action="append", dest="style_assign", 183 help="modify a style variable, e.g. dom.frame_thickness=0") 184 parser.add_option("--geom-var", action="append", dest="geom_assign", 185 help="modify a geometry variable") 186 return parser
187
188 -def main_program():
189 parser = get_parser() 190 191 sys.argv,argv2 = lib.extract_parser_args(sys.argv,parser) 192 (options,args) = parser.parse_args() 193 194 list_and_exit = False 195 if options.list_languages: 196 for x in plugin_list("lang"): print x[0], 197 print 198 list_and_exit = True 199 if options.list_styles: 200 for x in plugin_list("style"): print x[0], 201 print 202 list_and_exit = True 203 if options.list_geometries: 204 for x in plugin_list("geom"): print x[0], 205 print 206 list_and_exit = True 207 if options.list_layouts: 208 for x in plugin_list("layouts"): print x[0], 209 print 210 list_and_exit = True 211 if list_and_exit: return 212 213 plugin_paths = get_plugin_paths() 214 Language = import_plugin(plugin_paths, "lang", "language", "languages", "--list-languages", options.lang) 215 Style = import_plugin(plugin_paths, "style", "style", "styles", "--list-styles", options.style) 216 Geometry = import_plugin(plugin_paths, "geom", "geometry", "geometries", "--list-geometries", options.geom) 217 Layout = import_plugin(plugin_paths, "layouts", "layout", "layouts", "--list-layouts", options.layout) 218 219 for x in argv2: 220 if '=' in x: x = x[0:x.find('=')] 221 if not Layout.parser.has_option(x): 222 parser.error("invalid option %s; use --help (-h) or --layout-help (-?) to see available options" % x) 223 224 (loptions,largs) = Layout.parser.parse_args(argv2) 225 226 if options.layouthelp: 227 #print "Help for layout:", options.layout 228 Layout.parser.print_help() 229 return 230 231 if options.examples: 232 print_examples() 233 return 234 235 # we can put it separately together with Layout; but we load Layout *after* lang,style,geom 236 if len(args) < 1 or len(args) > 3: 237 parser.print_help() 238 return 239 240 #if (len(args[-1]) == 4 and args[-1].isdigit()): 241 # print "WARNING: file name '%s' looks like a year, writing anyway..." % args[-1] 242 243 # the usual "beware of exec()" crap applies here... but come on, 244 # this is a SCRIPTING language, you can always hack the source code!!! 245 if options.lang_assign: 246 for x in options.lang_assign: exec "Language.%s" % x 247 if options.style_assign: 248 for x in options.style_assign: exec "Style.%s" % x 249 if options.geom_assign: 250 for x in options.geom_assign: exec "Geometry.%s" % x 251 252 calendar.long_month_name = Language.long_month_name 253 calendar.long_day_name = Language.long_day_name 254 calendar.short_month_name = Language.short_month_name 255 calendar.short_day_name = Language.short_day_name 256 257 if len(args) == 1: 258 Year = time.localtime()[0] 259 Month, MonthSpan = 1, 12 260 Outfile = args[0] 261 elif len(args) == 2: 262 Year = lib.parse_year(args[0]) 263 Month, MonthSpan = 1, 12 264 Outfile = args[1] 265 elif len(args) == 3: 266 Month, MonthSpan = lib.parse_month_range(args[0]) 267 Year = lib.parse_year(args[1]) 268 Outfile = args[2] 269 270 if MonthSpan == 0: 271 raise lib.Abort("callirhoe: empty calendar requested, aborting") 272 273 Geometry.landscape = options.landscape 274 xcairo.XDPI = options.dpi 275 Geometry.pagespec = options.paper 276 Geometry.border = options.border 277 278 hprovider = holiday.HolidayProvider(Style.dom, Style.dom_weekend, 279 Style.dom_holiday, Style.dom_weekend_holiday, 280 Style.dom_multi, Style.dom_weekend_multi, options.multiday_holidays) 281 282 if options.holidays: 283 for f in options.holidays: 284 hprovider.load_holiday_file(f) 285 286 if options.long_daynames: 287 Language.day_name = Language.long_day_name 288 else: 289 Language.day_name = Language.short_day_name 290 291 if options.short_monthnames: 292 Language.month_name = Language.short_month_name 293 else: 294 Language.month_name = Language.long_month_name 295 296 renderer = Layout.CalendarRenderer(Outfile, Year, Month, MonthSpan, 297 (Style,Geometry,Language), hprovider, lib._version, loptions) 298 renderer.render()
299 300 if __name__ == "__main__": 301 try: 302 main_program() 303 except lib.Abort as e: 304 sys.exit(e.args[0]) 305