1  """ 
  2  Loader and handler for Scribus descriptor files/headers. 
  3  They help to integrate scripts into Scribus by definining menu-entries,  
  4  shortcuts, etc. Some additional metadata gives useful information and help. 
  5   
  6  See doc/TUTORIAL for a detailed explanation including examples. 
  7  """ 
  8  import sys 
  9  import re 
 10  import os 
 11  from ConfigParser import ConfigParser 
 12  from StringIO import StringIO 
 13  from PyQt4.QtGui import QKeySequence, QIcon 
 14   
 15  import excepthook 
 16  from scripterng_hooks import MenuHooks 
 17  from scripterng_runtime import run_filename 
 22   
 25   
 28      lvalue = value.lower() 
 29      if lvalue in ["0", "no", "false", "off"]: 
 30          return False 
 31      elif lvalue in ["1", "yes", "true", "on"]: 
 32          return True 
  33   
 36      def check(value): 
 37          found = re.match(pattern, value) 
 38          if found: 
 39              return found.group(0) 
 40          raise ValidationError, \ 
 41               "Value %r does not match regular expression pattern %r" % pattern 
  42      return check 
 43   
 44   
 45  validate_ident = validate_regex("[A-Za-z_][A-Za-z_]*") 
 49      return value.split(",") 
  50       
 57   
 60      def check(value): 
 61          if value.lower() in args: 
 62              return value.lower() 
 63          raise ValidationError, "%r not in %r" % (value, args) 
  64      return check 
 65   
 68      def check(value): 
 69          l = [] 
 70          for v in value.split(","): 
 71              l.append(validate_enum(args)(v)) 
 72          return l 
  73      return check 
 74   
 75   
 76 -class Item(object): 
  77       
 78      _counter = 0 
 79   
 80 -    def __init__(self, name, default=None, validate=None, 
 81                         required=False): 
  82          self._item_id = Item._counter 
 83          Item._counter += 1 
 84          self.name = name 
 85          self.default = default 
 86          if isinstance(validate, basestring): 
 87              validate = validate_regex 
 88          self.validate = validate or (lambda v:v) 
 89          self.required = required 
  90   
 91   
 92 -    def __call__(self, value, ignore_errors=False): 
  93          try: 
 94              pyvalue = self.validate(value) 
 95          except ValidationError, e: 
 96              if not ignore_errors: 
 97                  raise 
 98              pyvalue = self.default 
 99          return pyvalue 
  100   
105   
106       
107       
108      items = [ 
109          Item("name"), 
110          Item("title"), 
111          Item("description"), 
112          Item("icon"), 
113           
114          Item("menu", "ScripterNG"), 
115           
116          Item("shortcut"), 
117          Item("filename"), 
118          Item("subroutine"), 
119          Item("author"), 
120          Item("contact"), 
121          Item("homepage"), 
122          Item("version"), 
123          Item("copyright", "Licensed under GPLl 2 or later"), 
124          Item("scribus_version"), 
125           
126           
127           
128           
129          Item("redraw", True, validate_bool), 
130          Item("mode", "interactive", validate_enum("batch", "interactive", "extension")), 
131           
132           
133           
134          Item("language", "python", validate_enum("python", "qtscript")), 
135          Item("separator_before", False, validate_bool), 
136          Item("separator_after", False, validate_bool), 
137          Item("background_mode", False, validate_bool), 
138      ] 
139   
140   
141 -    def __init__(self, _data=None, **kwargs): 
 142          self.data = {} 
143          d = dict(_data or {}, **kwargs) 
144          for item in self.__class__.items: 
145              self.data[item.name] = d.pop(item.name, item.default) 
146          if d: 
147              raise TypeError, "Unknown items: %s" % ", ".join(d.keys()) 
 148   
149   
151          return "<%s %r>" % (self.__class__.__name__, self.data) 
 152   
153   
155          return self.data[name] 
 156           
157           
159          return self.data[name] 
 160   
161       
162 -    def get(self, name, default=None): 
 163          return self.data.get(name, default) 
 164   
165       
167          self.data[name] = value 
 168   
169   
171          """ 
172          currently only can create menu entries and sets shortcuts 
173          """ 
174          if self.menu: 
175              mh = MenuHooks() 
176              menu = mh.findMenu(self.menu) 
177              if not menu: 
178                  menu = mh.createMenu(self.menu) 
179                  mh.appendMenu(menu) 
180              if self.separator_before: 
181                  mh.appendSeparator(menu) 
182              self.action = mh.appendItem(menu, self.title, lambda :self.run()) 
183              if self.separator_after: 
184                  mh.appendSeparator(menu) 
185              if self.icon: 
186                  icon_filename = os.path.join( 
187                     os.path.dirname(self.filename), self.icon) 
188                  if os.path.exists(icon_filename): 
189                      self.action.setIcon(QIcon(icon_filename)) 
190                  else: 
191                      print >> sys.stderr, "Icon %r not found" % icon_filename 
192              if self.shortcut: 
193                  self.action.setShortcut(QKeySequence(self.shortcut)) 
 194   
195   
196 -    def run(self, catch_errors=True): 
 197          """ 
198          uses scripterng_runtime to call a script 
199          """ 
200          try: 
201              win = ScripterNG.activeWindow 
202              if win: 
203                  win.redraw = self.redraw 
204              run_filename(self.filename, self.subroutine, 
205                 extension=(self.mode == "extension"), 
206                 background=self.background_mode) 
207              if win: 
208                  win.redraw = True 
209                  if not self.redraw: 
210                      win.update() 
211          except: 
212              if not catch_errors: 
213                  raise 
214              excepthook.show_current_error("Error running %r" % os.path.basename(self.filename)) 
 215   
216   
217      @classmethod 
219          s = open(filename).read(8192) 
220          name, ext = os.path.splitext(os.path.basename(filename)) 
221          parse = cls.filetypes[ext] 
222          try: 
223              obj = parse(s) 
224          except EmptyDescriptor: 
225              if ext in [".spy"]: 
226                  language = "python" 
227              elif ext in [".sjs", ".sqts"]: 
228                  language = "qtscript" 
229              obj = cls(name=name, title=name.capitalize(), 
230                         language=language) 
231          if not obj.get("filename"): 
232              obj["filename"] = filename 
233          return obj 
 234   
235   
236      @classmethod 
238          s = "[ScribusScript]\nlanguage=python\n" 
239          for line in source.splitlines(): 
240              if not line.startswith("#"): 
241                  break 
242              if line.startswith("##"): 
243                  s += line[2:].strip() + "\n" 
244          return cls.parse(s) 
 245   
246   
247      @classmethod 
249          s = "[ScribusScript]\nlanguage=qtscript\n" 
250          for line in source.splitlines(): 
251              if  not line.startswith("//"): 
252                  break 
253              if line.startswith("///"): 
254                  s += line[3:].strip() + "\n" 
255          return cls.parse(s) 
 256   
257   
258      @classmethod 
260          data = {} 
261          cfg = ConfigParser() 
262          s = "[ScribusScript]\n" + s 
263          cfg.readfp(StringIO(s)) 
264          options = cfg.options("ScribusScript") 
265          if not len(options): 
266              raise EmptyDescriptor 
267          for item in cls.items: 
268              if not item.name in options: 
269                  if item.required: 
270                      raise ValidationError, "Option %r required but not set" % item.name 
271                  else: 
272                      continue 
273              options.remove(item.name) 
274              value = cfg.get("ScribusScript", item.name) 
275              data[item.name] = item(value) 
276          if options: 
277              raise ValidationError, "Invalid options found: %s" % ", ".join(options) 
278           
279          return cls(**data) 
  280   
281   
282   
283  ScribusScript.filetypes = { 
284     
285    ".spy": ScribusScript.parse_python, 
286    ".sjs": ScribusScript.parse_qtscript, 
287    ".sqts": ScribusScript.parse_qtscript, 
288    ".scs": ScribusScript.parse 
289  } 
295   
299      if os.path.isdir(path_or_filename): 
300          path = os.path.abspath(os.path.expanduser(path_or_filename)) 
301          extensions = ScribusScript.filetypes.keys() 
302          files = [ os.path.join(path, name) for name in os.listdir(path) \ 
303                                if os.path.splitext(name)[1] in extensions ] 
304      else: 
305          files = [ os.path.abspath(os.path.expanduser(path_or_filename)) ] 
306      scripts = [] 
307      for filename in files: 
308          try: 
309              sd = load_filename(filename) 
310              scripts.append(sd) 
311          except: 
312              excepthook.show_current_error("Error loading %r" % os.path.basename(filename)) 
313      return scripts 
 314   
315   
316   
317   
318  if __name__ == "__main__": 
319       
320      for filename in sys.argv[1:]: 
321          script = ScribusScript.parse_filename(filename) 
322          print filename 
323          print script 
324      if not sys.argv[1:]: 
325          for sd in load_scripts("."): 
326              print sd 
327