chiark / gitweb /
Increment version number
[cura.git] / Cura / gui / app.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import sys
4 import os
5 import platform
6 import shutil
7 import glob
8 import subprocess
9 import warnings
10
11 try:
12         #Only try to import the _core to save import time
13         import wx._core
14 except ImportError:
15         import wx
16
17
18 class CuraApp(wx.App):
19         def __init__(self, files):
20                 if platform.system() == "Windows" and not 'PYCHARM_HOSTED' in os.environ:
21                         from Cura.util import profile
22                         super(CuraApp, self).__init__(redirect=True, filename=os.path.join(profile.getBasePath(), 'output_log.txt'))
23                 else:
24                         super(CuraApp, self).__init__(redirect=False)
25
26                 self.mainWindow = None
27                 self.splash = None
28                 self.loadFiles = files
29
30                 if platform.system() == "Darwin":
31                         self.Bind(wx.EVT_ACTIVATE_APP, self.OnActivate)
32
33                 if sys.platform.startswith('win'):
34                         #Check for an already running instance, if another instance is running load files in there
35                         from Cura.util import version
36                         from ctypes import windll
37                         import ctypes
38                         import socket
39                         import threading
40
41                         portNr = 0xCA00 + sum(map(ord, version.getVersion(False)))
42                         if len(files) > 0:
43                                 try:
44                                         other_hwnd = windll.user32.FindWindowA(None, ctypes.c_char_p('Cura - ' + version.getVersion()))
45                                         if other_hwnd != 0:
46                                                 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
47                                                 sock.sendto('\0'.join(files), ("127.0.0.1", portNr))
48
49                                                 windll.user32.SetForegroundWindow(other_hwnd)
50                                                 return
51                                 except:
52                                         pass
53
54                         socketListener = threading.Thread(target=self.Win32SocketListener, args=(portNr,))
55                         socketListener.daemon = True
56                         socketListener.start()
57
58                 if sys.platform.startswith('darwin'):
59                         #Do not show a splashscreen on OSX, as by Apple guidelines
60                         self.afterSplashCallback()
61                 else:
62                         from Cura.gui import splashScreen
63                         self.splash = splashScreen.splashScreen(self.afterSplashCallback)
64
65         def MacOpenFile(self, path):
66                 try:
67                         self.mainWindow.OnDropFiles([path])
68                 except Exception as e:
69                         warnings.warn("File at {p} cannot be read: {e}".format(p=path, e=str(e)))
70
71         def MacReopenApp(self, event):
72                 self.GetTopWindow().Raise()
73
74         def MacHideApp(self, event):
75                 self.GetTopWindow().Show(False)
76
77         def MacNewFile(self):
78                 pass
79
80         def MacPrintFile(self, file_path):
81                 pass
82
83         def OnActivate(self, e):
84                 if e.GetActive():
85                         self.GetTopWindow().Raise()
86                 e.Skip()
87
88         def Win32SocketListener(self, port):
89                 import socket
90                 try:
91                         sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
92                         sock.bind(("127.0.0.1", port))
93                         while True:
94                                 data, addr = sock.recvfrom(2048)
95                                 try:
96                                         wx.CallAfter(self.mainWindow.OnDropFiles, data.split('\0'))
97                                 except Exception as e:
98                                         warnings.warn("File at {p} cannot be read: {e}".format(p=data, e=str(e)))
99                 except:
100                         pass
101
102         def destroySplashScreen(self):
103                 if self.splash is not None:
104                         self.splash.Show(False)
105                         self.splash.Destroy()
106                         self.splash = None
107
108         def afterSplashCallback(self):
109                 #These imports take most of the time and thus should be done after showing the splashscreen
110                 import webbrowser
111                 from Cura.gui import mainWindow
112                 from Cura.gui import configWizard
113                 from Cura.gui import newVersionDialog
114                 from Cura.util import profile
115                 from Cura.util import resources
116                 from Cura.util import version
117                 from distutils.version import LooseVersion
118
119                 resources.setupLocalization(profile.getPreference('language'))  # it's important to set up localization at very beginning to install _
120
121                 if LooseVersion(wx.__version__) < LooseVersion('3.0'):
122                         wx.MessageBox(_("This version of Cura requires WxPython version 3.0 or newer.\nYour current WxPython version is %s.") % wx.__version__,
123                                                   _("WxPython version is too old"), wx.OK | wx.ICON_ERROR)
124                         return
125
126                 #If we do not have preferences yet, try to load it from a previous Cura install
127                 if profile.getMachineSetting('machine_type') == 'unknown':
128                         try:
129                                 otherCuraInstalls = profile.getAlternativeBasePaths()
130                                 for path in otherCuraInstalls[::-1]:
131                                         try:
132                                                 print 'Loading old settings from %s' % (path)
133                                                 profile.loadPreferences(os.path.join(path, 'preferences.ini'))
134                                                 profile.loadProfile(os.path.join(path, 'current_profile.ini'))
135                                                 break
136                                         except:
137                                                 import traceback
138                                                 print traceback.print_exc()
139                         except:
140                                 import traceback
141                                 print traceback.print_exc()
142
143                 #If we haven't run it before, run the configuration wizard.
144                 if profile.getMachineSetting('machine_type') == 'unknown':
145                         #Check if we need to copy our examples
146                         exampleFile = os.path.normpath(os.path.join(resources.resourceBasePath, 'example', 'Rocktopus.stl'))
147
148                         self.loadFiles = [exampleFile]
149                         self.destroySplashScreen()
150                         configWizard.ConfigWizard()
151
152                 if profile.getPreference('check_for_updates') == 'True':
153                         newVersion = version.checkForNewerVersion()
154                         if newVersion is not None:
155                                 self.destroySplashScreen()
156                                 if wx.MessageBox(_("A new version of Cura is available, would you like to download?"), _("New version available"), wx.YES_NO | wx.ICON_INFORMATION) == wx.YES:
157                                         webbrowser.open(newVersion)
158                                         return
159                 if profile.getMachineSetting('machine_name') == '':
160                         return
161                 if profile.getPreference('last_run_version') != version.getVersion(False):
162                         profile.performVersionUpgrade()
163
164                 # Must happen before the main window is created, in case there are changes
165                 # that would affect it (such as machine name changes)
166                 if version.isDevVersion():
167                         profile.performVersionUpgrade()
168
169                 self.mainWindow = mainWindow.mainWindow()
170                 self.destroySplashScreen()
171                 self.SetTopWindow(self.mainWindow)
172                 self.mainWindow.Show()
173                 self.mainWindow.OnDropFiles(self.loadFiles)
174                 setFullScreenCapable(self.mainWindow)
175
176                 if profile.getPreference('last_run_version') != version.getVersion(False):
177                         profile.putPreference('last_run_version', version.getVersion(False))
178                         newVersionDialog.newVersionDialog().Show()
179
180                 # Must come after creating the main window
181                 #if version.isDevVersion():
182                         #import wx.lib.inspection
183                         # Show the WX widget inspection tool
184                         #wx.lib.inspection.InspectionTool().Show()
185
186                 if sys.platform.startswith('darwin'):
187                         wx.CallAfter(self.StupidMacOSWorkaround)
188
189         def StupidMacOSWorkaround(self):
190                 subprocess.Popen(['osascript', '-e', '''\
191                 tell application "System Events"
192                 set procName to name of first process whose unix id is %s
193                 end tell
194                 tell application procName to activate
195                 ''' % os.getpid()])
196
197 if platform.system() == "Darwin": #Mac magic. Dragons live here. THis sets full screen options.
198         try:
199                 import ctypes, objc
200                 _objc = ctypes.PyDLL(objc._objc.__file__)
201
202                 # PyObject *PyObjCObject_New(id objc_object, int flags, int retain)
203                 _objc.PyObjCObject_New.restype = ctypes.py_object
204                 _objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
205
206                 def setFullScreenCapable(frame):
207                         frameobj = _objc.PyObjCObject_New(frame.GetHandle(), 0, 1)
208
209                         NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7
210                         window = frameobj.window()
211                         newBehavior = window.collectionBehavior() | NSWindowCollectionBehaviorFullScreenPrimary
212                         window.setCollectionBehavior_(newBehavior)
213         except:
214                 def setFullScreenCapable(frame):
215                         pass
216
217 else:
218         def setFullScreenCapable(frame):
219                 pass