chiark / gitweb /
Tell user to connect and power on 3D printer before attempting to flash firmware
[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.performVersionUpgrade()
157
158                 # Must happen before the main window is created, in case there are changes
159                 # that would affect it (such as machine name changes)
160                 if version.isDevVersion():
161                         profile.performVersionUpgrade()
162
163                 self.mainWindow = mainWindow.mainWindow()
164                 self.destroySplashScreen()
165                 self.SetTopWindow(self.mainWindow)
166                 self.mainWindow.Show()
167                 self.mainWindow.OnDropFiles(self.loadFiles)
168                 setFullScreenCapable(self.mainWindow)
169
170                 if profile.getPreference('last_run_version') != version.getVersion(False):
171                         profile.putPreference('last_run_version', version.getVersion(False))
172                         newVersionDialog.newVersionDialog().Show()
173
174                 # Must come after creating the main window
175                 if version.isDevVersion():
176                         import wx.lib.inspection
177                         # Show the WX widget inspection tool
178                         #wx.lib.inspection.InspectionTool().Show()
179
180                 if sys.platform.startswith('darwin'):
181                         wx.CallAfter(self.StupidMacOSWorkaround)
182
183         def StupidMacOSWorkaround(self):
184                 subprocess.Popen(['osascript', '-e', '''\
185                 tell application "System Events"
186                 set procName to name of first process whose unix id is %s
187                 end tell
188                 tell application procName to activate
189                 ''' % os.getpid()])
190
191 if platform.system() == "Darwin": #Mac magic. Dragons live here. THis sets full screen options.
192         try:
193                 import ctypes, objc
194                 _objc = ctypes.PyDLL(objc._objc.__file__)
195
196                 # PyObject *PyObjCObject_New(id objc_object, int flags, int retain)
197                 _objc.PyObjCObject_New.restype = ctypes.py_object
198                 _objc.PyObjCObject_New.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_int]
199
200                 def setFullScreenCapable(frame):
201                         frameobj = _objc.PyObjCObject_New(frame.GetHandle(), 0, 1)
202
203                         NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7
204                         window = frameobj.window()
205                         newBehavior = window.collectionBehavior() | NSWindowCollectionBehaviorFullScreenPrimary
206                         window.setCollectionBehavior_(newBehavior)
207         except:
208                 def setFullScreenCapable(frame):
209                         pass
210
211 else:
212         def setFullScreenCapable(frame):
213                 pass