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