| 1 | #!/usr/bin/env python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | |
|---|
| 4 | """ Panohead remote control. |
|---|
| 5 | |
|---|
| 6 | License |
|---|
| 7 | ======= |
|---|
| 8 | |
|---|
| 9 | - B{Papywizard} (U{http://www.papywizard.org}) is Copyright: |
|---|
| 10 | - (C) 2007-2010 Frédéric Mantegazza |
|---|
| 11 | |
|---|
| 12 | This software is governed by the B{CeCILL} license under French law and |
|---|
| 13 | abiding by the rules of distribution of free software. You can use, |
|---|
| 14 | modify and/or redistribute the software under the terms of the CeCILL |
|---|
| 15 | license as circulated by CEA, CNRS and INRIA at the following URL |
|---|
| 16 | U{http://www.cecill.info}. |
|---|
| 17 | |
|---|
| 18 | As a counterpart to the access to the source code and rights to copy, |
|---|
| 19 | modify and redistribute granted by the license, users are provided only |
|---|
| 20 | with a limited warranty and the software's author, the holder of the |
|---|
| 21 | economic rights, and the successive licensors have only limited |
|---|
| 22 | liability. |
|---|
| 23 | |
|---|
| 24 | In this respect, the user's attention is drawn to the risks associated |
|---|
| 25 | with loading, using, modifying and/or developing or reproducing the |
|---|
| 26 | software by the user in light of its specific status of free software, |
|---|
| 27 | that may mean that it is complicated to manipulate, and that also |
|---|
| 28 | therefore means that it is reserved for developers and experienced |
|---|
| 29 | professionals having in-depth computer knowledge. Users are therefore |
|---|
| 30 | encouraged to load and test the software's suitability as regards their |
|---|
| 31 | requirements in conditions enabling the security of their systems and/or |
|---|
| 32 | data to be ensured and, more generally, to use and operate it in the |
|---|
| 33 | same conditions as regards security. |
|---|
| 34 | |
|---|
| 35 | The fact that you are presently reading this means that you have had |
|---|
| 36 | knowledge of the CeCILL license and that you accept its terms. |
|---|
| 37 | |
|---|
| 38 | Module purpose |
|---|
| 39 | ============== |
|---|
| 40 | |
|---|
| 41 | Main script |
|---|
| 42 | |
|---|
| 43 | @author: Frédéric Mantegazza |
|---|
| 44 | @copyright: (C) 2007-2010 Frédéric Mantegazza |
|---|
| 45 | @license: CeCILL |
|---|
| 46 | """ |
|---|
| 47 | |
|---|
| 48 | __revision__ = "$Id$" |
|---|
| 49 | |
|---|
| 50 | import sys |
|---|
| 51 | import threading |
|---|
| 52 | |
|---|
| 53 | from PyQt4 import QtCore, QtGui |
|---|
| 54 | |
|---|
| 55 | from papywizard.common import config |
|---|
| 56 | from papywizard.common.loggingServices import Logger |
|---|
| 57 | from papywizard.common.qLoggingFormatter import QSpaceColorFormatter |
|---|
| 58 | from papywizard.plugins.pluginsManager import PluginsManager |
|---|
| 59 | from papywizard.view.logBuffer import LogBuffer |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | class BlackHole: |
|---|
| 63 | """ Dummy class for stderr redirection. |
|---|
| 64 | """ |
|---|
| 65 | softspace = 0 |
|---|
| 66 | |
|---|
| 67 | def write(self, text): |
|---|
| 68 | pass |
|---|
| 69 | |
|---|
| 70 | |
|---|
| 71 | def main(): |
|---|
| 72 | try: |
|---|
| 73 | # Give a name to the main trhead |
|---|
| 74 | threading.currentThread().setName("Main") |
|---|
| 75 | |
|---|
| 76 | # Init the logger |
|---|
| 77 | if hasattr(sys, "frozen"): |
|---|
| 78 | |
|---|
| 79 | # Forbid all console outputs |
|---|
| 80 | sys.stderr = BlackHole() |
|---|
| 81 | Logger(defaultStreamHandler=False) |
|---|
| 82 | else: |
|---|
| 83 | Logger() |
|---|
| 84 | |
|---|
| 85 | # Create the buffer for GUI log |
|---|
| 86 | logStream = LogBuffer() |
|---|
| 87 | Logger().addStreamHandler(logStream, QSpaceColorFormatter) |
|---|
| 88 | |
|---|
| 89 | Logger().info("Starting Papywizard...") |
|---|
| 90 | |
|---|
| 91 | # Init global Qt application |
|---|
| 92 | qtApp = QtGui.QApplication(sys.argv) |
|---|
| 93 | qtApp.setApplicationName("Papywizard") |
|---|
| 94 | qtApp.setApplicationVersion(config.VERSION) |
|---|
| 95 | |
|---|
| 96 | # Create the splashscreen |
|---|
| 97 | from papywizard.common import pixmaps |
|---|
| 98 | pixmap = QtGui.QPixmap() |
|---|
| 99 | pixmap.load(":/pixmaps/%s" % config.SPLASHCREEN_FILE) |
|---|
| 100 | splash = QtGui.QSplashScreen(pixmap, QtCore.Qt.WindowStaysOnTopHint) |
|---|
| 101 | splash.show() |
|---|
| 102 | qtApp.processEvents() |
|---|
| 103 | |
|---|
| 104 | # Addtional imports |
|---|
| 105 | Logger().info("Importing modules...") |
|---|
| 106 | splash.showMessage("Importing modules...") |
|---|
| 107 | qtApp.processEvents() |
|---|
| 108 | from papywizard.common import i18n |
|---|
| 109 | from papywizard.common.configManager import ConfigManager |
|---|
| 110 | #from papywizard.common.publisher import Publisher |
|---|
| 111 | from papywizard.model.shooting import Shooting |
|---|
| 112 | from papywizard.controller.mainController import MainController |
|---|
| 113 | from papywizard.controller.spy import Spy |
|---|
| 114 | from papywizard.view import icons |
|---|
| 115 | |
|---|
| 116 | # i18n stuff |
|---|
| 117 | Logger().info("Loading i18n files...") |
|---|
| 118 | splash.showMessage("Loading i18n files...") |
|---|
| 119 | qtApp.processEvents() |
|---|
| 120 | locale = QtCore.QLocale.system().name() |
|---|
| 121 | Logger().debug("Papywizard.i18n(): locale=%s" % locale) |
|---|
| 122 | qtTranslator = QtCore.QTranslator() |
|---|
| 123 | if qtTranslator.load("qt_%s" % locale, |
|---|
| 124 | QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.TranslationsPath)): |
|---|
| 125 | qtApp.installTranslator(qtTranslator) |
|---|
| 126 | else: |
|---|
| 127 | Logger().warning("Can't find qt translation file") |
|---|
| 128 | appTranslator = QtCore.QTranslator() |
|---|
| 129 | if appTranslator.load("papywizard_%s" % locale, ":/i18n"): |
|---|
| 130 | qtApp.installTranslator(appTranslator) |
|---|
| 131 | else: |
|---|
| 132 | Logger().warning("Can't find papywizard translation file") |
|---|
| 133 | |
|---|
| 134 | # Load Qt stylesheet |
|---|
| 135 | Logger().info("Loading Style Sheets...") |
|---|
| 136 | splash.showMessage("Loading Style Sheets...") |
|---|
| 137 | qtApp.processEvents() |
|---|
| 138 | try: |
|---|
| 139 | styleSheet = file(config.USER_STYLESHEET_FILE) |
|---|
| 140 | qtApp.setStyleSheet(styleSheet.read()) |
|---|
| 141 | styleSheet.close() |
|---|
| 142 | except IOError: |
|---|
| 143 | Logger().warning("No user Style Sheet found") |
|---|
| 144 | styleSheet = qtApp.styleSheet() |
|---|
| 145 | if styleSheet: |
|---|
| 146 | if styleSheet.startsWith("file://"): |
|---|
| 147 | Logger().debug("Style Sheet loaded from command line param.") |
|---|
| 148 | else: |
|---|
| 149 | Logger().debug("User Style Sheet loaded") |
|---|
| 150 | |
|---|
| 151 | # Load user configuration |
|---|
| 152 | Logger().info("Loading configuration...") |
|---|
| 153 | splash.showMessage("Loading configuration...") |
|---|
| 154 | qtApp.processEvents() |
|---|
| 155 | ConfigManager().load() |
|---|
| 156 | |
|---|
| 157 | # Load plugins (move to shooting?) |
|---|
| 158 | Logger().info("Load plugins...") |
|---|
| 159 | splash.showMessage("Load plugins...") |
|---|
| 160 | from papywizard.plugins.simulationPlugins import register |
|---|
| 161 | register() |
|---|
| 162 | from papywizard.plugins.merlinOrionPlugins import register |
|---|
| 163 | register() |
|---|
| 164 | from papywizard.plugins.genericTetheredPlugins import register |
|---|
| 165 | register() |
|---|
| 166 | from papywizard.plugins.timelordPlugins import register |
|---|
| 167 | register() |
|---|
| 168 | from papywizard.plugins.pololuServoPlugins import register |
|---|
| 169 | register() |
|---|
| 170 | from papywizard.plugins.eosUtilityPlugins import register |
|---|
| 171 | register() |
|---|
| 172 | from papywizard.plugins.ursaMinorUsbPlugins import register |
|---|
| 173 | register() |
|---|
| 174 | #from papywizard.plugins.ursaMinorBt2Plugins import register |
|---|
| 175 | #register() |
|---|
| 176 | from papywizard.plugins.gphotoPlugins import register |
|---|
| 177 | register() |
|---|
| 178 | from papywizard.plugins.pixOrbPlugins import register |
|---|
| 179 | register() |
|---|
| 180 | from papywizard.plugins.dslrRemoteProPlugins import register |
|---|
| 181 | register() |
|---|
| 182 | from papywizard.plugins.nkRemotePlugins import register |
|---|
| 183 | register() |
|---|
| 184 | from papywizard.plugins.gigaPanBotPlugins import register |
|---|
| 185 | register() |
|---|
| 186 | PluginsManager ().load() |
|---|
| 187 | |
|---|
| 188 | # Activate selected plugins (move to PluginsManager ?) |
|---|
| 189 | Logger().info("Activate plugins...") |
|---|
| 190 | plugin = ConfigManager().get('Plugins/PLUGIN_YAW_AXIS') |
|---|
| 191 | PluginsManager ().get('yawAxis', plugin)[0].activate() |
|---|
| 192 | plugin = ConfigManager().get('Plugins/PLUGIN_PITCH_AXIS') |
|---|
| 193 | PluginsManager ().get('pitchAxis', plugin)[0].activate() |
|---|
| 194 | plugin = ConfigManager().get('Plugins/PLUGIN_SHUTTER') |
|---|
| 195 | PluginsManager ().get('shutter', plugin)[0].activate() |
|---|
| 196 | |
|---|
| 197 | # Create model |
|---|
| 198 | Logger().info("Creating model...") |
|---|
| 199 | splash.showMessage("Creating model...") |
|---|
| 200 | qtApp.processEvents() |
|---|
| 201 | model = Shooting() |
|---|
| 202 | |
|---|
| 203 | # Create spy thread |
|---|
| 204 | Logger().info("Starting Spy...") |
|---|
| 205 | Spy(model).start() |
|---|
| 206 | |
|---|
| 207 | # Create main controller |
|---|
| 208 | Logger().info("Creating GUI...") |
|---|
| 209 | splash.showMessage("Creating GUI...") |
|---|
| 210 | qtApp.processEvents() |
|---|
| 211 | mainController = MainController(model, logStream) |
|---|
| 212 | |
|---|
| 213 | # Set user logger level |
|---|
| 214 | Logger().setLevel(ConfigManager().get('Configuration/LOGGER_LEVEL')) |
|---|
| 215 | |
|---|
| 216 | # Terminate splashscreen |
|---|
| 217 | splash.finish(mainController._view) |
|---|
| 218 | |
|---|
| 219 | # Check if teh configuration is set |
|---|
| 220 | if not ConfigManager().isConfigured(): |
|---|
| 221 | from papywizard.view.messageDialog import InfoMessageDialog |
|---|
| 222 | #dialog = WarningMessageDialog(QtCore.QObject().tr("Configuration"), |
|---|
| 223 | #QtCore.QObject().tr("Papywizard needs to be configured")) |
|---|
| 224 | dialog = InfoMessageDialog(QtGui.QApplication.translate("main", "Plugins selection"), |
|---|
| 225 | QtGui.QApplication.translate("main", "Before you can use Papywizard, you must choose what " \ |
|---|
| 226 | "plugins to use to control your hardware.\n\n" \ |
|---|
| 227 | "After closing this dialog, you will be prompt to select " \ |
|---|
| 228 | "these plugins. Once it is done, you can configure them " |
|---|
| 229 | "in the global Configuration dialog")) |
|---|
| 230 | dialog.exec_() |
|---|
| 231 | from papywizard.controller.pluginsController import PluginsController |
|---|
| 232 | controller = PluginsController(None, model) |
|---|
| 233 | controller.exec_() |
|---|
| 234 | controller.shutdown() |
|---|
| 235 | |
|---|
| 236 | # Enter Qt main loop |
|---|
| 237 | qtApp.exec_() |
|---|
| 238 | |
|---|
| 239 | # Shutdown controller |
|---|
| 240 | Logger().info("Shuting down GUI...") |
|---|
| 241 | mainController.shutdown() |
|---|
| 242 | |
|---|
| 243 | # Stop spy thread |
|---|
| 244 | Logger().info("Shuting down Spy...") |
|---|
| 245 | Spy().stop() |
|---|
| 246 | Logger().debug("Waiting Spy thread to terminate...") |
|---|
| 247 | Spy().wait() |
|---|
| 248 | |
|---|
| 249 | # Shutdown model |
|---|
| 250 | Logger().info("Shuting down model...") |
|---|
| 251 | model.shutdown() |
|---|
| 252 | |
|---|
| 253 | # Cleanup resources |
|---|
| 254 | Logger().info("Cleaning up resources...") |
|---|
| 255 | i18n.qCleanupResources() |
|---|
| 256 | pixmaps.qCleanupResources() |
|---|
| 257 | icons.qCleanupResources() |
|---|
| 258 | |
|---|
| 259 | Logger().info("Papywizard stopped") |
|---|
| 260 | |
|---|
| 261 | except Exception, msg: |
|---|
| 262 | Logger().exception("main()") |
|---|
| 263 | if 'splash' in locals(): |
|---|
| 264 | splash.finish(None) |
|---|
| 265 | from papywizard.view.messageDialog import ExceptionMessageDialog |
|---|
| 266 | try: |
|---|
| 267 | msg = msg.message # Windows exception? |
|---|
| 268 | except AttributeError: |
|---|
| 269 | pass |
|---|
| 270 | dialog = ExceptionMessageDialog("Unhandled exception", unicode(msg)) |
|---|
| 271 | dialog.exec_() |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | if __name__ == "__main__": |
|---|
| 275 | sys.argv[0] = "Papywizard" |
|---|
| 276 | main() |
|---|