andrej@1663: #!/usr/bin/env python
andrej@1663: # -*- coding: utf-8 -*-
andrej@1663: 
andrej@1663: # This file is part of Beremiz, a Integrated Development Environment for
andrej@1663: # programming IEC 61131-3 automates supporting plcopen standard and CanFestival.
andrej@1663: #
andrej@1663: # Copyright (C) 2016 - 2017: Andrey Skvortsov <andrej.skvortzov@gmail.com>
andrej@1663: #
andrej@1663: # See COPYING file for copyrights details.
andrej@1663: #
andrej@1663: # This program is free software; you can redistribute it and/or
andrej@1663: # modify it under the terms of the GNU General Public License
andrej@1663: # as published by the Free Software Foundation; either version 2
andrej@1663: # of the License, or (at your option) any later version.
andrej@1663: #
andrej@1663: # This program is distributed in the hope that it will be useful,
andrej@1663: # but WITHOUT ANY WARRANTY; without even the implied warranty of
andrej@1663: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
andrej@1663: # GNU General Public License for more details.
andrej@1663: #
andrej@1663: # You should have received a copy of the GNU General Public License
andrej@1663: # along with this program; if not, write to the Free Software
andrej@1663: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
andrej@1663: 
andrej@1663: 
andrej@1732: import os
andrej@1732: import sys
andrej@1732: import getopt
andrej@1872: 
andrej@1872: import wx
edouard@1941: from wx.lib.agw.advancedsplash import AdvancedSplash, AS_NOTIMEOUT, AS_CENTER_ON_SCREEN
andrej@1872: 
andrej@1680: import util.paths as paths
andrej@1663: 
Edouard@1953: 
andrej@1831: class BeremizIDELauncher(object):
andrej@1663:     def __init__(self):
andrej@1796:         self.app = None
andrej@1796:         self.frame = None
andrej@1663:         self.updateinfo_url = None
andrej@1663:         self.extensions = []
andrej@1680:         self.app_dir = paths.AbsDir(__file__)
andrej@1663:         self.projectOpen = None
andrej@1663:         self.buildpath = None
andrej@1663:         self.splash = None
andrej@1663:         self.splashPath = self.Bpath("images", "splash.png")
Edouard@1935:         self.modules = ["BeremizIDE"]
Edouard@1926:         self.debug = os.path.exists("BEREMIZ_DEBUG")
edouard@1960:         self.handle_exception = None
edouard@3423:         self.logf = None
andrej@1663: 
andrej@1663:     def Bpath(self, *args):
andrej@1740:         return os.path.join(self.app_dir, *args)
andrej@1663: 
andrej@1663:     def Usage(self):
andrej@1826:         print("Usage:")
andrej@1826:         print("%s [Options] [Projectpath] [Buildpath]" % sys.argv[0])
andrej@1826:         print("")
andrej@1826:         print("Supported options:")
andrej@1826:         print("-h --help                    Print this help")
andrej@1826:         print("-u --updatecheck URL         Retrieve update information by checking URL")
andrej@1826:         print("-e --extend PathToExtension  Extend IDE functionality by loading at start additional extensions")
edouard@3423:         print("-l --log path                write content of console tab to given file")
andrej@1826:         print("")
andrej@1826:         print("")
andrej@1663: 
andrej@1663:     def SetCmdOptions(self):
edouard@3423:         self.shortCmdOpts = "hu:e:l:"
edouard@3423:         self.longCmdOpts = ["help", "updatecheck=", "extend=", "log="]
andrej@1663: 
andrej@1663:     def ProcessOption(self, o, a):
andrej@1663:         if o in ("-h", "--help"):
andrej@1663:             self.Usage()
andrej@1663:             sys.exit()
andrej@1663:         if o in ("-u", "--updatecheck"):
andrej@1663:             self.updateinfo_url = a
andrej@1663:         if o in ("-e", "--extend"):
andrej@1663:             self.extensions.append(a)
edouard@3423:         if o in ("-l", "--log"):
edouard@3423:             self.logf = open(a, 'a')
andrej@1663: 
andrej@1663:     def ProcessCommandLineArgs(self):
andrej@1663:         self.SetCmdOptions()
andrej@1663:         try:
andrej@1663:             opts, args = getopt.getopt(sys.argv[1:], self.shortCmdOpts, self.longCmdOpts)
andrej@1663:         except getopt.GetoptError:
andrej@1663:             # print help information and exit:
andrej@1663:             self.Usage()
andrej@1663:             sys.exit(2)
andrej@1663: 
andrej@1663:         for o, a in opts:
andrej@1663:             self.ProcessOption(o, a)
andrej@1663: 
andrej@1663:         if len(args) > 2:
andrej@1663:             self.Usage()
andrej@1663:             sys.exit()
andrej@1663: 
andrej@1663:         elif len(args) == 1:
andrej@1663:             self.projectOpen = args[0]
andrej@1663:             self.buildpath = None
andrej@1663:         elif len(args) == 2:
andrej@1663:             self.projectOpen = args[0]
andrej@1663:             self.buildpath = args[1]
andrej@1663: 
andrej@1663:     def CreateApplication(self):
edouard@1941: 
edouard@3793:         BeremizAppType = wx.App
Edouard@1953: 
edouard@1941:         class BeremizApp(BeremizAppType):
Edouard@1953:             def OnInit(_self):  # pylint: disable=no-self-argument
edouard@1941:                 self.ShowSplashScreen()
edouard@1941:                 return True
edouard@1941: 
edouard@1941:         self.app = BeremizApp(redirect=self.debug)
andrej@1663:         self.app.SetAppName('beremiz')
andrej@1663: 
Edouard@1947:     def ShowSplashScreen(self):
Edouard@1947:         class Splash(AdvancedSplash):
edouard@1976:             Painted = False
edouard@1977: 
Edouard@1953:             def OnPaint(_self, event):  # pylint: disable=no-self-argument
Edouard@1947:                 AdvancedSplash.OnPaint(_self, event)
edouard@1976:                 if not _self.Painted:  # trigger app start only once
edouard@1976:                     _self.Painted = True
edouard@1976:                     wx.CallAfter(self.AppStart)
Edouard@1947:         bmp = wx.Image(self.splashPath).ConvertToBitmap()
Edouard@1953:         self.splash = Splash(None,
Edouard@1953:                              bitmap=bmp,
Edouard@1947:                              agwStyle=AS_NOTIMEOUT | AS_CENTER_ON_SCREEN)
Edouard@1947: 
andrej@1663:     def BackgroundInitialization(self):
andrej@1663:         self.InitI18n()
andrej@1663:         self.CheckUpdates()
andrej@1663:         self.LoadExtensions()
andrej@1663:         self.ImportModules()
andrej@1663: 
andrej@1663:     def InitI18n(self):
andrej@1663:         from util.misc import InstallLocalRessources
andrej@1663:         InstallLocalRessources(self.app_dir)
andrej@1663: 
Edouard@1921:     def globals(self):
Edouard@1921:         """
Edouard@1921:         allows customizations to specify what globals
Edouard@1921:         are passed to extensions
Edouard@1921:         """
Edouard@1921:         return globals()
Edouard@1921: 
andrej@1663:     def LoadExtensions(self):
andrej@1663:         for extfilename in self.extensions:
andrej@1663:             from util.TranslationCatalogs import AddCatalog
andrej@1663:             from util.BitmapLibrary import AddBitmapFolder
andrej@1663:             extension_folder = os.path.split(os.path.realpath(extfilename))[0]
andrej@1663:             sys.path.append(extension_folder)
andrej@1663:             AddCatalog(os.path.join(extension_folder, "locale"))
andrej@1663:             AddBitmapFolder(os.path.join(extension_folder, "images"))
kinsamanka@3750:             exec(compile(open(extfilename, "rb").read(), extfilename, 'exec'), self.globals())
andrej@1663: 
andrej@1663:     def CheckUpdates(self):
andrej@1663:         if self.updateinfo_url is not None:
andrej@1874:             self.updateinfo = _("Fetching %s") % self.updateinfo_url
andrej@1663: 
andrej@1663:             def updateinfoproc():
andrej@1739:                 try:
kinsamanka@3750:                     import urllib.request, urllib.error, urllib.parse
kinsamanka@3750:                     self.updateinfo = urllib.request.urlopen(self.updateinfo_url, None).read()
andrej@1780:                 except Exception:
andrej@1874:                     self.updateinfo = _("update info unavailable.")
andrej@1663: 
andrej@1663:             from threading import Thread
andrej@1874:             self.splash.SetText(text=self.updateinfo)
andrej@1663:             updateinfoThread = Thread(target=updateinfoproc)
andrej@1663:             updateinfoThread.start()
andrej@1663:             updateinfoThread.join(2)
andrej@1874:             self.splash.SetText(text=self.updateinfo)
andrej@1663: 
andrej@1663:     def ImportModules(self):
Edouard@1924:         for modname in self.modules:
Edouard@1924:             mod = __import__(modname)
Edouard@1924:             setattr(self, modname, mod)
andrej@1663: 
andrej@1663:     def InstallExceptionHandler(self):
andrej@1663:         import version
andrej@1792:         import util.ExceptionHandler
edouard@3444:         self.handle_exception = util.ExceptionHandler.AddExceptHook(version.app_version, logf=self.logf)
andrej@1663: 
Edouard@1924:     def CreateUI(self):
edouard@3423:         self.frame = self.BeremizIDE.Beremiz(None, self.projectOpen, self.buildpath, logf=self.logf)
Edouard@1924: 
Edouard@1924:     def CloseSplash(self):
andrej@1663:         if self.splash:
andrej@1663:             self.splash.Close()
Edouard@1924: 
Edouard@1924:     def ShowUI(self):
andrej@1663:         self.frame.Show()
andrej@1663: 
andrej@1796:     def PreStart(self):
andrej@1663:         self.ProcessCommandLineArgs()
andrej@1663:         self.CreateApplication()
Edouard@1953: 
edouard@1941:     def AppStart(self):
edouard@1941:         try:
edouard@1941:             self.BackgroundInitialization()
edouard@1941:             self.CreateUI()
edouard@1941:             self.CloseSplash()
edouard@1941:             self.ShowUI()
edouard@1960:         except (KeyboardInterrupt, SystemExit):
edouard@1960:             raise
edouard@1941:         except Exception:
edouard@1960:             if self.handle_exception is not None:
edouard@1960:                 self.handle_exception(*sys.exc_info(), exit=True)
edouard@1960:             else:
edouard@1960:                 raise
andrej@1663: 
andrej@1796:     def MainLoop(self):
andrej@1796:         self.app.MainLoop()
andrej@1796: 
Edouard@1924:     def Start(self):
andrej@1796:         self.PreStart()
edouard@1941:         self.InstallExceptionHandler()
andrej@1796:         self.MainLoop()
andrej@1796: 
andrej@1749: 
andrej@1663: if __name__ == '__main__':
andrej@1663:     beremiz = BeremizIDELauncher()
andrej@1663:     beremiz.Start()