| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | |
|---|
| 3 | """ Panohead remote control. |
|---|
| 4 | |
|---|
| 5 | License |
|---|
| 6 | ======= |
|---|
| 7 | |
|---|
| 8 | - B{Papywizard} (U{http://www.papywizard.org}) is Copyright: |
|---|
| 9 | - (C) 2007-2009 Frédéric Mantegazza |
|---|
| 10 | |
|---|
| 11 | This software is governed by the B{CeCILL} license under French law and |
|---|
| 12 | abiding by the rules of distribution of free software. You can use, |
|---|
| 13 | modify and/or redistribute the software under the terms of the CeCILL |
|---|
| 14 | license as circulated by CEA, CNRS and INRIA at the following URL |
|---|
| 15 | U{http://www.cecill.info}. |
|---|
| 16 | |
|---|
| 17 | As a counterpart to the access to the source code and rights to copy, |
|---|
| 18 | modify and redistribute granted by the license, users are provided only |
|---|
| 19 | with a limited warranty and the software's author, the holder of the |
|---|
| 20 | economic rights, and the successive licensors have only limited |
|---|
| 21 | liability. |
|---|
| 22 | |
|---|
| 23 | In this respect, the user's attention is drawn to the risks associated |
|---|
| 24 | with loading, using, modifying and/or developing or reproducing the |
|---|
| 25 | software by the user in light of its specific status of free software, |
|---|
| 26 | that may mean that it is complicated to manipulate, and that also |
|---|
| 27 | therefore means that it is reserved for developers and experienced |
|---|
| 28 | professionals having in-depth computer knowledge. Users are therefore |
|---|
| 29 | encouraged to load and test the software's suitability as regards their |
|---|
| 30 | requirements in conditions enabling the security of their systems and/or |
|---|
| 31 | data to be ensured and, more generally, to use and operate it in the |
|---|
| 32 | same conditions as regards security. |
|---|
| 33 | |
|---|
| 34 | The fact that you are presently reading this means that you have had |
|---|
| 35 | knowledge of the CeCILL license and that you accept its terms. |
|---|
| 36 | |
|---|
| 37 | Module purpose |
|---|
| 38 | ============== |
|---|
| 39 | |
|---|
| 40 | Graphical toolkit controller |
|---|
| 41 | |
|---|
| 42 | Implements |
|---|
| 43 | ========== |
|---|
| 44 | |
|---|
| 45 | - PreferencesController |
|---|
| 46 | |
|---|
| 47 | @author: Frédéric Mantegazza |
|---|
| 48 | @copyright: (C) 2007-2009 Frédéric Mantegazza |
|---|
| 49 | @license: CeCILL |
|---|
| 50 | |
|---|
| 51 | @todo: check what type(s) of driver(s) a plugin can use |
|---|
| 52 | """ |
|---|
| 53 | |
|---|
| 54 | __revision__ = "$Id$" |
|---|
| 55 | |
|---|
| 56 | from PyQt4 import QtCore, QtGui |
|---|
| 57 | |
|---|
| 58 | from papywizard.common import config |
|---|
| 59 | from papywizard.common.configManager import ConfigManager |
|---|
| 60 | from papywizard.common.loggingServices import Logger |
|---|
| 61 | from papywizard.hardware.bluetoothTransport import BluetoothTransport |
|---|
| 62 | from papywizard.plugins.pluginsManager import PluginsManager |
|---|
| 63 | from papywizard.controller.abstractController import AbstractModalDialogController |
|---|
| 64 | from papywizard.controller.bluetoothChooserController import BluetoothChooserController |
|---|
| 65 | from papywizard.view.messageDialog import WarningMessageDialog, ExceptionMessageDialog |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | class PluginsController(AbstractModalDialogController): |
|---|
| 69 | """ Plugins controller object. |
|---|
| 70 | """ |
|---|
| 71 | def _init(self): |
|---|
| 72 | self._uiFile = "pluginsDialog.ui" |
|---|
| 73 | |
|---|
| 74 | def _retreiveWidgets(self): |
|---|
| 75 | """ Get widgets from widget tree. |
|---|
| 76 | """ |
|---|
| 77 | AbstractModalDialogController._retreiveWidgets(self) |
|---|
| 78 | |
|---|
| 79 | def _initWidgets(self): |
|---|
| 80 | pass |
|---|
| 81 | |
|---|
| 82 | def _connectSignals(self): |
|---|
| 83 | AbstractModalDialogController._connectSignals(self) |
|---|
| 84 | self.connect(self._view.yawAxisComboBox, QtCore.SIGNAL("activated(const QString&)"), self.__onYawAxisComboBoxActivated) |
|---|
| 85 | self.connect(self._view.pitchAxisComboBox, QtCore.SIGNAL("activated(const QString&)"), self.__onPitchAxisComboBoxActivated) |
|---|
| 86 | self.connect(self._view.shutterComboBox, QtCore.SIGNAL("activated(const QString&)"), self.__onShutterComboBoxActivated) |
|---|
| 87 | self.connect(self._view.bluetoothChoosePushButton, QtCore.SIGNAL("clicked()"), self.__onBluetoothChoosePushButtonClicked) |
|---|
| 88 | |
|---|
| 89 | def _disconnectSignals(self): |
|---|
| 90 | AbstractModalDialogController._disconnectSignals(self) |
|---|
| 91 | self.disconnect(self._view.yawAxisComboBox, QtCore.SIGNAL("activated(const QString&)"), self.__onYawAxisComboBoxActivated) |
|---|
| 92 | self.disconnect(self._view.pitchAxisComboBox, QtCore.SIGNAL("activated(const QString&)"), self.__onPitchAxisComboBoxActivated) |
|---|
| 93 | self.disconnect(self._view.shutterComboBox, QtCore.SIGNAL("activated(const QString&)"), self.__onShutterComboBoxActivated) |
|---|
| 94 | self.disconnect(self._view.bluetoothChoosePushButton, QtCore.SIGNAL("clicked()"), self.__onBluetoothChoosePushButtonClicked) |
|---|
| 95 | |
|---|
| 96 | # Callbacks |
|---|
| 97 | def _onAccepted(self): |
|---|
| 98 | """ Ok button has been clicked. |
|---|
| 99 | |
|---|
| 100 | Save back values to model. |
|---|
| 101 | """ |
|---|
| 102 | Logger().trace("PluginsController._onAccepted()") |
|---|
| 103 | |
|---|
| 104 | # Plugins tab |
|---|
| 105 | previousPluginName = ConfigManager().get('Plugins/PLUGIN_YAW_AXIS') |
|---|
| 106 | ConfigManager().set('Plugins/PLUGIN_YAW_AXIS', unicode(self._view.yawAxisComboBox.currentText())) |
|---|
| 107 | newPluginName = ConfigManager().get('Plugins/PLUGIN_YAW_AXIS') |
|---|
| 108 | newPlugin = PluginsManager ().get('yawAxis', newPluginName)[0] |
|---|
| 109 | if previousPluginName != newPluginName: |
|---|
| 110 | previousPlugin = PluginsManager ().get('yawAxis', previousPluginName)[0] |
|---|
| 111 | previousPlugin.deactivate() |
|---|
| 112 | newPlugin.activate() |
|---|
| 113 | if hasattr(newPlugin, '_driver'): |
|---|
| 114 | newPlugin._config['DRIVER_TYPE'] = config.DRIVER_INDEX[self._view.yawAxisDriverComboBox.currentIndex()] |
|---|
| 115 | # todo: set config in a callback |
|---|
| 116 | newPlugin._saveConfig() |
|---|
| 117 | |
|---|
| 118 | previousPluginName = ConfigManager().get('Plugins/PLUGIN_PITCH_AXIS') |
|---|
| 119 | ConfigManager().set('Plugins/PLUGIN_PITCH_AXIS', unicode(self._view.pitchAxisComboBox.currentText())) |
|---|
| 120 | newPluginName = ConfigManager().get('Plugins/PLUGIN_PITCH_AXIS') |
|---|
| 121 | newPlugin = PluginsManager ().get('pitchAxis', newPluginName)[0] |
|---|
| 122 | if previousPluginName != newPluginName: |
|---|
| 123 | previousPlugin = PluginsManager ().get('pitchAxis', previousPluginName)[0] |
|---|
| 124 | previousPlugin.deactivate() |
|---|
| 125 | newPlugin.activate() |
|---|
| 126 | if hasattr(newPlugin, '_driver'): |
|---|
| 127 | newPlugin._config['DRIVER_TYPE'] = config.DRIVER_INDEX[self._view.pitchAxisDriverComboBox.currentIndex()] |
|---|
| 128 | # todo: set config in a callback |
|---|
| 129 | newPlugin._saveConfig() |
|---|
| 130 | |
|---|
| 131 | previousPluginName = ConfigManager().get('Plugins/PLUGIN_SHUTTER') |
|---|
| 132 | ConfigManager().set('Plugins/PLUGIN_SHUTTER', unicode(self._view.shutterComboBox.currentText())) |
|---|
| 133 | newPluginName = ConfigManager().get('Plugins/PLUGIN_SHUTTER') |
|---|
| 134 | newPlugin = PluginsManager ().get('shutter', newPluginName)[0] |
|---|
| 135 | if previousPluginName != newPluginName: |
|---|
| 136 | previousPlugin = PluginsManager ().get('shutter', previousPluginName)[0] |
|---|
| 137 | previousPlugin.deactivate() |
|---|
| 138 | newPlugin.activate() |
|---|
| 139 | if hasattr(newPlugin, '_driver'): |
|---|
| 140 | newPlugin._config['DRIVER_TYPE'] = config.DRIVER_INDEX[self._view.shutterDriverComboBox.currentIndex()] |
|---|
| 141 | # todo: set config in a callback |
|---|
| 142 | newPlugin._saveConfig() |
|---|
| 143 | |
|---|
| 144 | # Drivers tab |
|---|
| 145 | ConfigManager().set('Plugins/HARDWARE_BLUETOOTH_DEVICE_ADDRESS', unicode(self._view.bluetoothDeviceAddressLineEdit.text())) |
|---|
| 146 | ConfigManager().set('Plugins/HARDWARE_SERIAL_PORT', unicode(self._view.serialPortLineEdit.text())) |
|---|
| 147 | ConfigManager().set('Plugins/HARDWARE_ETHERNET_HOST', unicode(self._view.ethernetHostLineEdit.text())) |
|---|
| 148 | ConfigManager().setInt('Plugins/HARDWARE_ETHERNET_PORT', self._view.ethernetPortSpinBox.value()) |
|---|
| 149 | |
|---|
| 150 | # Communication tab |
|---|
| 151 | ConfigManager().setFloat('Plugins/HARDWARE_COM_TIMEOUT', self._view.comTimeoutDoubleSpinBox.value(), 1) |
|---|
| 152 | ConfigManager().setInt('Plugins/HARDWARE_COM_RETRY', self._view.comRetrySpinBox.value()) |
|---|
| 153 | |
|---|
| 154 | ConfigManager().save() |
|---|
| 155 | |
|---|
| 156 | def __onYawAxisComboBoxActivated(self, pluginName): |
|---|
| 157 | """ Yaw axis combo box. |
|---|
| 158 | """ |
|---|
| 159 | Logger().debug("PluginsController.__onYawAxisComboBoxActivated(): plugin=%s" % pluginName) |
|---|
| 160 | model, controllerClass = PluginsManager ().get('yawAxis', pluginName) |
|---|
| 161 | if hasattr(model, '_driver'): |
|---|
| 162 | self._view.yawAxisDriverComboBox.setEnabled(True) |
|---|
| 163 | self._view.yawAxisDriverComboBox.setCurrentIndex(self._view.yawAxisDriverComboBox.findText(model._config['DRIVER_TYPE'])) |
|---|
| 164 | else: |
|---|
| 165 | self._view.yawAxisDriverComboBox.setEnabled(False) |
|---|
| 166 | #self._view.yawAxisDriverComboBox.setCurrentIndex(-1) |
|---|
| 167 | |
|---|
| 168 | def __onPitchAxisComboBoxActivated(self, pluginName): |
|---|
| 169 | """ Pitch axis combo box. |
|---|
| 170 | """ |
|---|
| 171 | Logger().debug("PluginsController.__onPitchAxisComboBoxActivated(): plugin=%s" % pluginName) |
|---|
| 172 | model, controllerClass = PluginsManager ().get('pitchAxis', pluginName) |
|---|
| 173 | if hasattr(model, '_driver'): |
|---|
| 174 | self._view.pitchAxisDriverComboBox.setEnabled(True) |
|---|
| 175 | self._view.pitchAxisDriverComboBox.setCurrentIndex(self._view.pitchAxisDriverComboBox.findText(model._config['DRIVER_TYPE'])) |
|---|
| 176 | else: |
|---|
| 177 | self._view.pitchAxisDriverComboBox.setEnabled(False) |
|---|
| 178 | #self._view.pitchAxisDriverComboBox.setCurrentIndex(-1) |
|---|
| 179 | |
|---|
| 180 | def __onShutterComboBoxActivated(self, pluginName): |
|---|
| 181 | """ Shutter combo box. |
|---|
| 182 | """ |
|---|
| 183 | Logger().debug("PluginsController.__onShutterComboBoxActivated(): plugin=%s" % pluginName) |
|---|
| 184 | model, controllerClass = PluginsManager ().get('shutter', pluginName) |
|---|
| 185 | if hasattr(model, '_driver'): |
|---|
| 186 | self._view.shutterDriverComboBox.setEnabled(True) |
|---|
| 187 | self._view.shutterDriverComboBox.setCurrentIndex(self._view.shutterDriverComboBox.findText(model._config['DRIVER_TYPE'])) |
|---|
| 188 | else: |
|---|
| 189 | self._view.shutterDriverComboBox.setEnabled(False) |
|---|
| 190 | #self._view.shutterDriverComboBox.setCurrentIndex(-1) |
|---|
| 191 | |
|---|
| 192 | def __onBluetoothChoosePushButtonClicked(self): |
|---|
| 193 | """ Choose bluetooth button clicked. |
|---|
| 194 | |
|---|
| 195 | Open the bluetooth chooser dialog. |
|---|
| 196 | """ |
|---|
| 197 | Logger().trace("PluginsController.__onBluetoothChoosePushButtonClicked()") |
|---|
| 198 | QtGui.qApp.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor)) |
|---|
| 199 | while QtGui.QApplication.hasPendingEvents(): |
|---|
| 200 | QtGui.QApplication.processEvents() #QtCore.QEventLoop.ExcludeUserInputEvents) |
|---|
| 201 | |
|---|
| 202 | bluetoothTransport = BluetoothTransport() |
|---|
| 203 | try: |
|---|
| 204 | bluetoothDevices = bluetoothTransport.discoverDevices() |
|---|
| 205 | except Exception, msg: |
|---|
| 206 | QtGui.qApp.restoreOverrideCursor() |
|---|
| 207 | Logger().exception("PluginsController.__onBluetoothChoosePushButtonClicked()") |
|---|
| 208 | Logger().error("Can't scan bluetooth\n%s" % unicode(msg)) |
|---|
| 209 | dialog = ExceptionMessageDialog(self.tr("Can't scan bluetooth"), unicode(msg)) |
|---|
| 210 | dialog.exec_() |
|---|
| 211 | else: |
|---|
| 212 | QtGui.qApp.restoreOverrideCursor() |
|---|
| 213 | controller = BluetoothChooserController(self, model=bluetoothDevices) |
|---|
| 214 | response = controller.exec_() |
|---|
| 215 | if response: |
|---|
| 216 | address, name = controller.getSelectedBluetoothAddress() |
|---|
| 217 | Logger().debug("PluginsController.__onChooseBluetoothButtonClicked(): address=%s, name=%s" % (address, name)) |
|---|
| 218 | self._view.bluetoothDeviceAddressLineEdit.setText(address) |
|---|
| 219 | controller.shutdown() |
|---|
| 220 | |
|---|
| 221 | # Interface |
|---|
| 222 | def selectTab(self, tabIndex, disable=False): |
|---|
| 223 | """ Select the specified tab. |
|---|
| 224 | |
|---|
| 225 | @param tabIndex: page num |
|---|
| 226 | @type tabIndex: int |
|---|
| 227 | |
|---|
| 228 | @param disable: if True, disable all other pages |
|---|
| 229 | @type disable: bool |
|---|
| 230 | """ |
|---|
| 231 | self._view.tabWidget.setCurrentIndex(tabIndex) |
|---|
| 232 | for index in xrange(self._view.tabWidget.count()): |
|---|
| 233 | self._view.tabWidget.setTabEnabled(index, tabIndex == index) |
|---|
| 234 | |
|---|
| 235 | def refreshView(self): |
|---|
| 236 | |
|---|
| 237 | # Plugins tab |
|---|
| 238 | yawAxisPlugins = PluginsManager ().getList('yawAxis') |
|---|
| 239 | if yawAxisPlugins: |
|---|
| 240 | for model, controller in yawAxisPlugins: |
|---|
| 241 | self._view.yawAxisComboBox.addItem(model.name) |
|---|
| 242 | selectedPluginName = ConfigManager().get('Plugins/PLUGIN_YAW_AXIS') |
|---|
| 243 | self._view.yawAxisComboBox.setCurrentIndex(self._view.yawAxisComboBox.findText(selectedPluginName)) |
|---|
| 244 | selectedPlugin = PluginsManager ().get('yawAxis', selectedPluginName)[0] |
|---|
| 245 | if hasattr(selectedPlugin, '_driver'): |
|---|
| 246 | self._view.yawAxisDriverComboBox.setEnabled(True) |
|---|
| 247 | driverType = selectedPlugin._config['DRIVER_TYPE'] |
|---|
| 248 | self._view.yawAxisDriverComboBox.setCurrentIndex(config.DRIVER_INDEX[driverType]) |
|---|
| 249 | else: |
|---|
| 250 | self._view.yawAxisDriverComboBox.setEnabled(False) |
|---|
| 251 | #self._view.yawAxisDriverComboBox.setCurrentIndex(-1) |
|---|
| 252 | |
|---|
| 253 | pitchAxisPlugins = PluginsManager ().getList('pitchAxis') |
|---|
| 254 | if pitchAxisPlugins: |
|---|
| 255 | for model, controller in pitchAxisPlugins: |
|---|
| 256 | self._view.pitchAxisComboBox.addItem(model.name) |
|---|
| 257 | selectedPluginName = ConfigManager().get('Plugins/PLUGIN_PITCH_AXIS') |
|---|
| 258 | self._view.pitchAxisComboBox.setCurrentIndex(self._view.pitchAxisComboBox.findText(selectedPluginName)) |
|---|
| 259 | selectedPlugin = PluginsManager ().get('pitchAxis', selectedPluginName)[0] |
|---|
| 260 | if hasattr(selectedPlugin, '_driver'): |
|---|
| 261 | self._view.pitchAxisDriverComboBox.setEnabled(True) |
|---|
| 262 | driverType = selectedPlugin._config['DRIVER_TYPE'] |
|---|
| 263 | self._view.pitchAxisDriverComboBox.setCurrentIndex(config.DRIVER_INDEX[driverType]) |
|---|
| 264 | else: |
|---|
| 265 | self._view.pitchAxisDriverComboBox.setEnabled(False) |
|---|
| 266 | #self._view.pitchAxisDriverComboBox.setCurrentIndex(-1) |
|---|
| 267 | |
|---|
| 268 | shutterPlugins = PluginsManager ().getList('shutter') |
|---|
| 269 | if shutterPlugins: |
|---|
| 270 | for model, controller in shutterPlugins: |
|---|
| 271 | self._view.shutterComboBox.addItem(model.name) |
|---|
| 272 | selectedPluginName = ConfigManager().get('Plugins/PLUGIN_SHUTTER') |
|---|
| 273 | self._view.shutterComboBox.setCurrentIndex(self._view.shutterComboBox.findText(selectedPluginName)) |
|---|
| 274 | selectedPlugin = PluginsManager ().get('shutter', selectedPluginName)[0] |
|---|
| 275 | if hasattr(selectedPlugin, '_driver'): |
|---|
| 276 | self._view.shutterDriverComboBox.setEnabled(True) |
|---|
| 277 | driverType = selectedPlugin._config['DRIVER_TYPE'] |
|---|
| 278 | self._view.shutterDriverComboBox.setCurrentIndex(config.DRIVER_INDEX[driverType]) |
|---|
| 279 | else: |
|---|
| 280 | self._view.shutterDriverComboBox.setEnabled(False) |
|---|
| 281 | #self._view.shutterDriverComboBox.setCurrentIndex(-1) |
|---|
| 282 | |
|---|
| 283 | # Drivers tab |
|---|
| 284 | self._view.bluetoothDeviceAddressLineEdit.setText(ConfigManager().get('Plugins/HARDWARE_BLUETOOTH_DEVICE_ADDRESS')) |
|---|
| 285 | self._view.serialPortLineEdit.setText(ConfigManager().get('Plugins/HARDWARE_SERIAL_PORT')) |
|---|
| 286 | self._view.ethernetHostLineEdit.setText(ConfigManager().get('Plugins/HARDWARE_ETHERNET_HOST')) |
|---|
| 287 | self._view.ethernetPortSpinBox.setValue(ConfigManager().getInt('Plugins/HARDWARE_ETHERNET_PORT')) |
|---|
| 288 | |
|---|
| 289 | # Communication tab |
|---|
| 290 | self._view.comTimeoutDoubleSpinBox.setValue(ConfigManager().getFloat('Plugins/HARDWARE_COM_TIMEOUT')) |
|---|
| 291 | self._view.comRetrySpinBox.setValue(ConfigManager().getInt('Plugins/HARDWARE_COM_RETRY')) |
|---|
| 292 | |
|---|
| 293 | def getSelectedTab(self): |
|---|
| 294 | """ Return the selected tab. |
|---|
| 295 | """ |
|---|
| 296 | return self._view.tabWidget.currentIndex() |
|---|
| 297 | |
|---|
| 298 | def setSelectedTab(self, index): |
|---|
| 299 | """ Set the tab to be selected. |
|---|
| 300 | """ |
|---|
| 301 | self._view.tabWidget.setCurrentIndex(index) |
|---|