9 from __future__ import absolute_import |
9 from __future__ import absolute_import |
10 import os |
10 import os |
11 import hashlib |
11 import hashlib |
12 import weakref |
12 import weakref |
13 import re |
13 import re |
|
14 import tempfile |
14 from threading import Thread, Lock |
15 from threading import Thread, Lock |
15 from functools import reduce |
16 from functools import reduce |
16 from itertools import izip |
17 from itertools import izip |
17 from operator import or_ |
18 from operator import or_ |
18 from tempfile import NamedTemporaryFile |
19 from tempfile import NamedTemporaryFile |
24 from lxml.etree import XSLTApplyError |
25 from lxml.etree import XSLTApplyError |
25 from XSLTransform import XSLTransform |
26 from XSLTransform import XSLTransform |
26 |
27 |
27 import util.paths as paths |
28 import util.paths as paths |
28 from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath |
29 from IDEFrame import EncodeFileSystemPath, DecodeFileSystemPath |
29 from docutil import get_inkscape_path |
30 from docutil import get_inkscape_path, get_inkscape_version |
30 |
31 |
31 from util.ProcessLogger import ProcessLogger |
32 from util.ProcessLogger import ProcessLogger |
32 |
33 |
33 ScriptDirectory = paths.AbsDir(__file__) |
34 ScriptDirectory = paths.AbsDir(__file__) |
34 |
35 |
274 txt.split("\n\n"))) |
275 txt.split("\n\n"))) |
275 |
276 |
276 _conf_key = "SVGHMIWidgetLib" |
277 _conf_key = "SVGHMIWidgetLib" |
277 _preview_height = 200 |
278 _preview_height = 200 |
278 _preview_margin = 5 |
279 _preview_margin = 5 |
|
280 thumbnail_temp_path = None |
|
281 |
279 class WidgetLibBrowser(wx.SplitterWindow): |
282 class WidgetLibBrowser(wx.SplitterWindow): |
280 def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, |
283 def __init__(self, parent, controler, id=wx.ID_ANY, pos=wx.DefaultPosition, |
281 size=wx.DefaultSize): |
284 size=wx.DefaultSize): |
282 |
285 |
283 wx.SplitterWindow.__init__(self, parent, |
286 wx.SplitterWindow.__init__(self, parent, |
284 style=wx.SUNKEN_BORDER | wx.SP_3D) |
287 style=wx.SUNKEN_BORDER | wx.SP_3D) |
285 |
288 |
286 self.bmp = None |
289 self.bmp = None |
287 self.msg = None |
290 self.msg = None |
288 self.hmitree_nodes = [] |
291 self.hmitree_nodes = [] |
289 self.selected_SVG = None |
292 self.selected_SVG = None |
|
293 self.Controler = controler |
290 |
294 |
291 self.Config = wx.ConfigBase.Get() |
295 self.Config = wx.ConfigBase.Get() |
292 self.libdir = self.RecallLibDir() |
296 self.libdir = self.RecallLibDir() |
293 if self.libdir is None: |
297 if self.libdir is None: |
294 self.libdir = os.path.join(ScriptDirectory, "widgetlib") |
298 self.libdir = os.path.join(ScriptDirectory, "widgetlib") |
453 def GenThumbnail(self, svgpath, thumbpath): |
457 def GenThumbnail(self, svgpath, thumbpath): |
454 inkpath = get_inkscape_path() |
458 inkpath = get_inkscape_path() |
455 if inkpath is None: |
459 if inkpath is None: |
456 self.msg = _("Inkscape is not installed.") |
460 self.msg = _("Inkscape is not installed.") |
457 return False |
461 return False |
|
462 |
|
463 export_opt = "-o" if get_inkscape_version()[0] > 0 else "-e" |
|
464 |
458 # TODO: spawn a thread, to decouple thumbnail gen |
465 # TODO: spawn a thread, to decouple thumbnail gen |
459 status, result, _err_result = ProcessLogger( |
466 status, result, _err_result = ProcessLogger( |
460 None, |
467 self.Controler.GetCTRoot().logger, |
461 '"' + inkpath + '" "' + svgpath + '" -e "' + thumbpath + |
468 '"' + inkpath + '" "' + svgpath + '" ' + |
|
469 export_opt + ' "' + thumbpath + |
462 '" -D -h ' + str(_preview_height)).spin() |
470 '" -D -h ' + str(_preview_height)).spin() |
463 if status != 0: |
471 if status != 0: |
464 self.msg = _("Inkscape couldn't generate thumbnail.") |
472 self.msg = _("Inkscape couldn't generate thumbnail.") |
465 return False |
473 return False |
466 return True |
474 return True |
468 def OnWidgetSelection(self, event): |
476 def OnWidgetSelection(self, event): |
469 """ |
477 """ |
470 Called when tree item is selected |
478 Called when tree item is selected |
471 @param event: wx.TreeEvent |
479 @param event: wx.TreeEvent |
472 """ |
480 """ |
|
481 global thumbnail_temp_path |
|
482 event.Skip() |
473 item_pydata = self.widgetpicker.GetPyData(event.GetItem()) |
483 item_pydata = self.widgetpicker.GetPyData(event.GetItem()) |
474 if item_pydata is not None: |
484 if item_pydata is not None: |
475 svgpath = item_pydata |
485 svgpath = item_pydata |
476 dname = os.path.dirname(svgpath) |
486 |
|
487 if thumbnail_temp_path is None: |
|
488 try: |
|
489 dname = os.path.dirname(svgpath) |
|
490 thumbdir = os.path.join(dname, ".svghmithumbs") |
|
491 if not os.path.exists(thumbdir): |
|
492 os.mkdir(thumbdir) |
|
493 except Exception : |
|
494 # library not writable : use temp dir |
|
495 thumbnail_temp_path = os.path.join( |
|
496 tempfile.gettempdir(), "svghmithumbs") |
|
497 thumbdir = thumbnail_temp_path |
|
498 if not os.path.exists(thumbdir): |
|
499 os.mkdir(thumbdir) |
|
500 else: |
|
501 thumbdir = thumbnail_temp_path |
|
502 |
477 fname = os.path.basename(svgpath) |
503 fname = os.path.basename(svgpath) |
478 hasher = hashlib.new('md5') |
504 hasher = hashlib.new('md5') |
479 with open(svgpath, 'rb') as afile: |
505 with open(svgpath, 'rb') as afile: |
480 while True: |
506 while True: |
481 buf = afile.read(65536) |
507 buf = afile.read(65536) |
483 hasher.update(buf) |
509 hasher.update(buf) |
484 else: |
510 else: |
485 break |
511 break |
486 digest = hasher.hexdigest() |
512 digest = hasher.hexdigest() |
487 thumbfname = os.path.splitext(fname)[0]+"_"+digest+".png" |
513 thumbfname = os.path.splitext(fname)[0]+"_"+digest+".png" |
488 thumbdir = os.path.join(dname, ".svghmithumbs") |
|
489 thumbpath = os.path.join(thumbdir, thumbfname) |
514 thumbpath = os.path.join(thumbdir, thumbfname) |
490 |
515 |
491 have_thumb = os.path.exists(thumbpath) |
516 have_thumb = os.path.exists(thumbpath) |
492 |
517 |
493 try: |
518 if not have_thumb: |
494 if not have_thumb: |
519 self.Controler.GetCTRoot().logger.write( |
495 if not os.path.exists(thumbdir): |
520 "Rendering preview of " + fname + " widget.\n") |
496 os.mkdir(thumbdir) |
521 have_thumb = self.GenThumbnail(svgpath, thumbpath) |
497 have_thumb = self.GenThumbnail(svgpath, thumbpath) |
522 |
498 |
523 self.bmp = wx.Bitmap(thumbpath) if have_thumb else None |
499 self.bmp = wx.Bitmap(thumbpath) if have_thumb else None |
524 |
500 |
525 self.selected_SVG = svgpath if have_thumb else None |
501 self.selected_SVG = svgpath if have_thumb else None |
526 |
502 |
527 self.AnalyseWidgetAndUpdateUI(fname) |
503 self.AnalyseWidgetAndUpdateUI(fname) |
528 |
504 |
529 self.SetMessage(self.msg) |
505 self.SetMessage(self.msg) |
|
506 |
|
507 except IOError: |
|
508 self.msg = _("Widget library must be writable") |
|
509 |
530 |
510 self.Refresh() |
531 self.Refresh() |
511 event.Skip() |
|
512 |
532 |
513 def OnHMITreeNodeSelection(self, hmitree_nodes): |
533 def OnHMITreeNodeSelection(self, hmitree_nodes): |
514 self.hmitree_nodes = hmitree_nodes |
534 self.hmitree_nodes = hmitree_nodes |
515 |
535 |
516 def OnLeftDown(self, evt): |
536 def OnLeftDown(self, evt): |
685 if self.tempf is not None: |
705 if self.tempf is not None: |
686 os.unlink(self.tempf.name) |
706 os.unlink(self.tempf.name) |
687 |
707 |
688 class SVGHMI_UI(wx.SplitterWindow): |
708 class SVGHMI_UI(wx.SplitterWindow): |
689 |
709 |
690 def __init__(self, parent, register_for_HMI_tree_updates): |
710 def __init__(self, parent, controler, register_for_HMI_tree_updates): |
691 wx.SplitterWindow.__init__(self, parent, |
711 wx.SplitterWindow.__init__(self, parent, |
692 style=wx.SUNKEN_BORDER | wx.SP_3D) |
712 style=wx.SUNKEN_BORDER | wx.SP_3D) |
693 |
713 |
694 self.SelectionTree = HMITreeSelector(self) |
714 self.SelectionTree = HMITreeSelector(self) |
695 self.Staging = WidgetLibBrowser(self) |
715 self.Staging = WidgetLibBrowser(self, controler) |
696 self.SplitVertically(self.SelectionTree, self.Staging, 300) |
716 self.SplitVertically(self.SelectionTree, self.Staging, 300) |
697 register_for_HMI_tree_updates(weakref.ref(self)) |
717 register_for_HMI_tree_updates(weakref.ref(self)) |
698 |
718 |
699 def HMITreeUpdate(self, hmi_tree_root): |
719 def HMITreeUpdate(self, hmi_tree_root): |
700 self.SelectionTree.MakeTree(hmi_tree_root) |
720 self.SelectionTree.MakeTree(hmi_tree_root) |