chiark / gitweb /
91bea92d5daf8a3c74d9b4a5760ca8bf870b9f7f
[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
118                 resources.setupLocalization(profile.getPreference('language'))  # it's important to set up localization at very beginning to install _
119
120                 #If we do not have preferences yet, try to load it from a previous Cura install
121                 if profile.getMachineSetting('machine_type') == 'unknown':
122                         try:
123                                 otherCuraInstalls = profile.getAlternativeBasePaths()
124                                 for path in otherCuraInstalls[::-1]:
125                                         try:
126                                                 print 'Loading old settings from %s' % (path)
127                                                 profile.loadPreferences(os.path.join(path, 'preferences.ini'))
128                                                 profile.loadProfile(os.path.join(path, 'current_profile.ini'))
129                                                 break
130                                         except:
131                                                 import traceback
132                                                 print traceback.print_exc()
133                         except:
134                                 import traceback
135                                 print traceback.print_exc()
136
137                 #If we haven't run it before, run the configuration wizard.
138                 if profile.getMachineSetting('machine_type') == 'unknown':
139                         #Check if we need to copy our examples
140                         exampleFile = os.path.normpath(os.path.join(resources.resourceBasePath, 'example', 'Rocktopus.stl'))
141
142                         self.loadFiles = [exampleFile]
143                         self.destroySplashScreen()
144                         configWizard.ConfigWizard()
145
146                 if profile.getPreference('check_for_updates') == 'True':
147                         newVersion = version.checkForNewerVersion()
148                         if newVersion is not None:
149                                 self.destroySplashScreen()
150                                 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:
151                                         webbrowser.open(newVersion)
152                                         return
153                 if profile.getMachineSetting('machine_name') == '':
154                         return
155                 if profile.getPreference('last_run_version') != version.getVersion(False):
156                         profile.putPreference('last_run_version', version.getVersion(False))
157                         profile.performVersionUpgrade()
158                         newVersionDialog.newVersionDialog().Show()
159
160                 # Must happen before the main window is created, in case there are changes
161                 # that would affect it (such as machine name changes)
162                 if version.isDevVersion():
163                         profile.performVersionUpgrade()
164
165                 self.mainWindow = mainWindow.mainWindow()
166                 self.destroySplashScreen()
167                 self.SetTopWindow(self.mainWindow)
168                 self.mainWindow.Show()
169                 self.mainWindow.OnDropFiles(self.loadFiles)
170                 setFullScreenCapable(self.mainWindow)
171
172                 # Must come after creating the main window
173                 if version.isDevVersion():
174                         import wx.lib.inspection
175                         # Show the WX widget inspection tool
176                         #wx.lib.inspection.InspectionTool().Show()
177
178                 if sys.platform.startswith('darwin'):
179                         wx.CallAfter(self.StupidMacOSWorkaround)
180
181         def StupidMacOSWorkaround(self):
182                 subprocess.Popen(['osascript', '-e', '''\
183                 tell application "System Events"
184                 set procName to name of first process whose unix id is %s
185                 end tell
186                 tell application procName to activate
187                 ''' % os.getpid()])
188
189 if platform.system() == "Darwin": #Mac magic. Dragons live here. THis sets full screen options.
190         try:
191                 import ctypes, objc
192                 _objc = ctypes.PyDLL(objc._objc.__file__)
193
194                 # PyObject *PyObjCObject_New(id objc_object, int flags, int retain)
195                 _objc.PyObjCObject_New.restype = ctypes.py_object
196                 _objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
197
198                 def setFullScreenCapable(frame):
199                         frameobj = _objc.PyObjCObject_New(frame.GetHandle(), 0, 1)
200
201                         NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7
202                         window = frameobj.window()
203                         newBehavior = window.collectionBehavior() | NSWindowCollectionBehaviorFullScreenPrimary
204                         window.setCollectionBehavior_(newBehavior)
205         except:
206                 def setFullScreenCapable(frame):
207                         pass
208
209 else:
210         def setFullScreenCapable(frame):
211                 pass