Package node_manager_fkie :: Module settings_widget
[frames] | no frames]

Source Code for Module node_manager_fkie.settings_widget

  1  # Software License Agreement (BSD License) 
  2  # 
  3  # Copyright (c) 2012, Fraunhofer FKIE/US, Alexander Tiderko 
  4  # All rights reserved. 
  5  # 
  6  # Redistribution and use in source and binary forms, with or without 
  7  # modification, are permitted provided that the following conditions 
  8  # are met: 
  9  # 
 10  #  * Redistributions of source code must retain the above copyright 
 11  #    notice, this list of conditions and the following disclaimer. 
 12  #  * Redistributions in binary form must reproduce the above 
 13  #    copyright notice, this list of conditions and the following 
 14  #    disclaimer in the documentation and/or other materials provided 
 15  #    with the distribution. 
 16  #  * Neither the name of Fraunhofer nor the names of its 
 17  #    contributors may be used to endorse or promote products derived 
 18  #    from this software without specific prior written permission. 
 19  # 
 20  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 21  # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 22  # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 23  # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
 24  # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 25  # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
 26  # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 27  # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
 28  # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
 29  # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
 30  # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 31  # POSSIBILITY OF SUCH DAMAGE. 
 32  import os 
 33   
 34  from python_qt_binding import QtGui 
 35  from python_qt_binding import QtCore 
 36  from python_qt_binding import loadUi 
 37   
 38  import node_manager_fkie as nm 
 39   
 40  from .settings_model import SettingsModel, SettingsValueItem 
 41   
 42   
43 -class SettingsWidget(QtGui.QDockWidget):
44 ''' 45 Settings widget to handle the settings changes. The changes will direct change 46 the settings of the GUI. 47 ''' 48
49 - def __init__(self, parent=None):
50 ''' 51 Creates the window, connects the signals and init the class. 52 ''' 53 QtGui.QDockWidget.__init__(self, parent) 54 # load the UI file 55 settings_dock_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'SettingsDockWidget.ui') 56 loadUi(settings_dock_file, self) 57 # initialize the settings view model 58 self.settings_model = SettingsModel() 59 self.settings_proxyModel = QtGui.QSortFilterProxyModel(self) 60 self.settings_proxyModel.setSourceModel(self.settings_model) 61 self.settingsTreeView.setModel(self.settings_proxyModel) 62 self.settingsTreeView.setAlternatingRowColors(True) 63 for i, (_, width) in enumerate(SettingsModel.header): 64 self.settingsTreeView.setColumnWidth(i, width) 65 self.item_delegate = ItemDelegate() 66 self.item_delegate.settings_path_changed_signal.connect(self.reload_settings) 67 self.settingsTreeView.setItemDelegateForColumn(1, self.item_delegate) 68 self.reload_settings()
69
70 - def reload_settings(self):
71 ''' 72 Load the current settings data into the model. The settings itself will not 73 be loaded. 74 ''' 75 settings = {'Default user:' : ({ 76 'value' : nm.settings().default_user, 77 'settings' : nm.settings(), 78 'attrname' : 'default_user', 79 'value_default' : nm.settings().USER_DEFAULT, 80 'tooltip' : '<p>The user used for ssh connection to remote hosts</p>' 81 },), 82 'Launch history length:' : ({ 83 'value' : nm.settings().launch_history_length, 84 'settings' : nm.settings(), 85 'attrname' : 'launch_history_length', 86 'value_default' : nm.settings().LAUNCH_HISTORY_LENGTH, 87 'value_min' : 0, 88 'value_max' : 25, 89 'tooltip' : '<p>The count of recent ' 90 'loaded launch files displayed in the root ' 91 'of the <span style=" font-weight:600;">launch ' 92 'files</span> view.</p>' 93 },), 94 'Param history length:' : ({ 95 'value' : nm.settings().param_history_length, 96 'settings' : nm.settings(), 97 'attrname' : 'param_history_length', 98 'value_default' : nm.settings().PARAM_HISTORY_LENGTH, 99 'value_min' : 0, 100 'value_max' : 25, 101 'tooltip' : '<p>The count of parameters stored which ' 102 'are entered in a parameter dialog (Launch file arguments, ' 103 'paramter server, publishing to a topic, service call)</p>' 104 },), 105 106 'Settings path:' : ({ 107 'value' : nm.settings().cfg_path, 108 'settings' : nm.settings(), 109 'attrname' : 'cfg_path', 110 'edit_type' : SettingsValueItem.EDIT_TYPE_FOLDER, 111 'value_default' : nm.settings().CFG_PATH, 112 'tooltip' : '' 113 },), 114 'Robot icon path:' : ({ 115 'value' : nm.settings().robots_path, 116 'settings' : nm.settings(), 117 'attrname' : 'robots_path', 118 'edit_type' : SettingsValueItem.EDIT_TYPE_FOLDER, 119 'value_default' : nm.settings().ROBOTS_DIR, 120 'tooltip' : '<p>The path to the folder with robot images ' 121 '(<span style=" font-weight:600;">.png</span>).' 122 'The images with robot name will be displayed in the ' 123 'info bar.</p>' 124 },), 125 'Show files extensions:' : ({ 126 'value' : ', '.join(nm.settings().launch_view_file_ext), 127 'settings' : nm.settings(), 128 'attrname' : 'launch_view_file_ext', 129 'value_default' : ', '.join(nm.settings().LAUNCH_VIEW_EXT), 130 'tooltip' : '<p>Files that are displayed next to Launch ' 131 'files in the <span style="font-weight:600;">' 132 'launch files</span> view</p>' 133 },), 134 'Store window layout:' : ({ 135 'value' : nm.settings().store_geometry, 136 'settings' : nm.settings(), 137 'attrname' : 'store_geometry', 138 'value_default' : nm.settings().STORE_GEOMETRY, 139 'tooltip' : '' 140 },), 141 'Autoupdate:' : ({ 142 'value' : nm.settings().autoupdate, 143 'settings' : nm.settings(), 144 'attrname' : 'autoupdate', 145 'value_default' : nm.settings().AUTOUPDATE, 146 'tooltip' : '<p>By default node manager updates the current ' 147 'state on changes. You can deactivate this behavior to ' 148 'reduce the network load. If autoupdate is deactivated ' 149 'you must refresh the state manually.</p>' 150 },) 151 } 152 self.settings_model.init_settings(settings) 153 # self.settingsTreeView.setSortingEnabled(True) 154 self.settingsTreeView.sortByColumn(0, QtCore.Qt.AscendingOrder) 155 self.settingsTreeView.expandAll()
156 157
158 -class ItemDelegate(QtGui.QStyledItemDelegate):
159 ''' 160 This ItemDelegate provides editors for different setting types in settings view. 161 ''' 162 163 settings_path_changed_signal = QtCore.Signal() 164 165 reload_settings = False 166
167 - def createEditor(self, parent, option, index):
168 ''' 169 Creates a editor in the TreeView depending on type of the settings data. 170 ''' 171 item = self._itemFromIndex(index) 172 if item.edit_type() == SettingsValueItem.EDIT_TYPE_AUTODETECT: 173 if isinstance(item.value(), bool): 174 box = QtGui.QCheckBox(parent) 175 box.setFocusPolicy(QtCore.Qt.StrongFocus) 176 box.setAutoFillBackground(True) 177 box.stateChanged.connect(self.edit_finished) 178 return box 179 elif isinstance(item.value(), int): 180 box = QtGui.QSpinBox(parent) 181 box.setValue(item.value()) 182 if not item.value_min() is None: 183 box.setMinimum(item.value_min()) 184 if not item.value_max() is None: 185 box.setMaximum(item.value_max()) 186 return box 187 elif item.edit_type() == SettingsValueItem.EDIT_TYPE_FOLDER: 188 editor = PathEditor(item.value(), parent) 189 editor.editing_finished_signal.connect(self.edit_finished) 190 return editor 191 return QtGui.QStyledItemDelegate.createEditor(self, parent, option, index)
192 193 # def setEditorData(self, editor, index): 194 # print "setEditorData" 195 # QtGui.QStyledItemDelegate.setEditorData(self, editor, index) 196 197 # def updateEditorGeometry(self, editor, option, index): 198 # print "updateEditorGeometry", option.rect.width() 199 # editor.setMaximumSize(option.rect.width(), option.rect.height()) 200 # QtGui.QStyledItemDelegate.updateEditorGeometry(self, editor, option, index) 201
202 - def setModelData(self, editor, model, index):
203 if isinstance(editor, PathEditor): 204 cfg_path = nm.settings().cfg_path 205 model.setData(index, editor.path) 206 self.reload_settings = (cfg_path != nm.settings().cfg_path) 207 else: 208 QtGui.QStyledItemDelegate.setModelData(self, editor, model, index)
209
210 - def sizeHint(self, option, index):
211 ''' 212 Determines and returns the size of the text after the format. 213 @see: U{http://www.pyside.org/docs/pyside/PySide/QtGui/QAbstractItemDelegate.html#PySide.QtGui.QAbstractItemDelegate} 214 ''' 215 options = QtGui.QStyleOptionViewItemV4(option) 216 self.initStyleOption(options,index) 217 return QtCore.QSize(options.rect.width(), 25)
218
219 - def edit_finished(self, arg=None):
220 editor = self.sender() 221 # The commitData signal must be emitted when we've finished editing 222 # and need to write our changed back to the model. 223 self.commitData.emit(editor) 224 self.closeEditor.emit(editor, QtGui.QAbstractItemDelegate.NoHint) 225 if self.reload_settings: 226 self.reload_settings = False 227 self.settings_path_changed_signal.emit()
228
229 - def _itemFromIndex(self, index):
230 if isinstance(index.model(), QtGui.QSortFilterProxyModel): 231 sindex = index.model().mapToSource(index) 232 return index.model().sourceModel().itemFromIndex(sindex) 233 else: 234 return index.model().itemFromIndex(index)
235 236
237 -class PathEditor(QtGui.QWidget):
238 ''' 239 This is a path editor used as ItemDeligate in settings view. This editor 240 provides an additional button for directory selection dialog. 241 ''' 242 243 editing_finished_signal = QtCore.Signal() 244
245 - def __init__(self, path, parent=None):
246 QtGui.QWidget.__init__(self, parent) 247 self.path = path 248 self._layout = QtGui.QHBoxLayout(self) 249 self._layout.setContentsMargins(0, 0, 0, 0) 250 self._layout.setSpacing(0) 251 self._button = QtGui.QPushButton('...') 252 self._button.setMaximumSize(QtCore.QSize(24, 20)) 253 self._button.clicked.connect(self._on_path_select_clicked) 254 self._layout.addWidget(self._button) 255 self._lineedit = QtGui.QLineEdit(path) 256 self._lineedit.returnPressed.connect(self._on_editing_finished) 257 self._layout.addWidget(self._lineedit) 258 self.setLayout(self._layout) 259 self.setFocusProxy(self._button) 260 self.setAutoFillBackground(True)
261
262 - def _on_path_select_clicked(self):
263 # Workaround for QtGui.QFileDialog.getExistingDirectory because it do not 264 # select the configuration folder in the dialog 265 self.dialog = QtGui.QFileDialog(self, caption='Select a new settings folder') 266 self.dialog.setOption(QtGui.QFileDialog.HideNameFilterDetails, True) 267 self.dialog.setFileMode(QtGui.QFileDialog.Directory) 268 self.dialog.setDirectory(self.path) 269 if self.dialog.exec_(): 270 fileNames = self.dialog.selectedFiles() 271 path = fileNames[0] 272 if os.path.isfile(path): 273 path = os.path.basename(path) 274 self._lineedit.setText(path) 275 self.path = dir 276 self.editing_finished_signal.emit()
277
278 - def _on_editing_finished(self):
279 if self._lineedit.text(): 280 self.path = self._lineedit.text() 281 self.editing_finished_signal.emit()
282