34 from python_qt_binding 
import loadUi
 
   35 from python_qt_binding.QtCore 
import QByteArray, qDebug, QObject, QSignalMapper, Signal, Slot
 
   36 from python_qt_binding.QtGui 
import QIcon, QValidator
 
   37 from python_qt_binding.QtWidgets 
import QAction, QFileDialog, QInputDialog, QMessageBox
 
   45     """Check if the argument is a string which works for both Python 2 and 3.""" 
   47         return isinstance(s, basestring)
 
   49         return isinstance(s, str)
 
   53     """Manager for perspectives associated with specific sets of `Settings`.""" 
   55     perspective_changed_signal = Signal(str)
 
   56     save_settings_signal = Signal(Settings, Settings)
 
   57     restore_settings_signal = Signal(Settings, Settings)
 
   58     restore_settings_without_plugin_changes_signal = Signal(Settings, Settings)
 
   62     def __init__(self, settings, application_context):
 
   63         super(PerspectiveManager, self).
__init__()
 
   64         self.setObjectName(
'PerspectiveManager')
 
   89         if application_context.provide_app_dbus_interfaces:
 
   91             self.
_dbus_server = PerspectiveManagerDBusInterface(self, application_context)
 
   99         create_action = QAction(
'&Create perspective...', self.
_menu_manager.menu)
 
  100         create_action.setIcon(QIcon.fromTheme(
'list-add'))
 
  112         import_action = QAction(
'&Import...', self.
_menu_manager.menu)
 
  113         import_action.setIcon(QIcon.fromTheme(
'document-open'))
 
  117         export_action = QAction(
'&Export...', self.
_menu_manager.menu)
 
  118         export_action.setIcon(QIcon.fromTheme(
'document-save-as'))
 
  129             name = self.
_settings_proxy.value(
'', 
'current-perspective', 
'Default')
 
  130         elif hide_and_without_plugin_changes:
 
  133                                 without_plugin_changes=hide_and_without_plugin_changes)
 
  137     @Slot(str, bool, bool)
 
  139             self, name, settings_changed=True, save_before=True, without_plugin_changes=False):
 
  150             self, name, settings_changed, save_before, without_plugin_changes=False):
 
  152         name = str(name.replace(
'/', 
'__'))
 
  154         qDebug(
'PerspectiveManager.switch_perspective() switching to perspective "%s"' % name)
 
  175             if not without_plugin_changes:
 
  188             callback(*callback_args)
 
  199                 name, settings_changed=
not clone_perspective, save_before=
False)
 
  204             ui_file = os.path.join(self.
_qtgui_path, 
'resource', 
'perspective_create.ui')
 
  208             class CustomValidator(QValidator):
 
  211                     super(CustomValidator, self).
__init__(parent)
 
  213                 def fixup(self, value):
 
  214                     value = value.replace(
'/', 
'')
 
  216                 def validate(self, value, pos):
 
  217                     if value.find(
'/') != -1:
 
  218                         pos = value.find(
'/')
 
  219                         return (QValidator.Invalid, value, pos)
 
  221                         return (QValidator.Intermediate, value, pos)
 
  222                     return (QValidator.Acceptable, value, pos)
 
  240                 self.tr(
'Empty perspective name'),
 
  241                 self.tr(
'The name of the perspective must be non-empty.'))
 
  246                 self.tr(
'Duplicate perspective name'),
 
  247                 self.tr(
'A perspective with the same name already exists.'))
 
  254         if name.find(
'/') != -1:
 
  256                 'PerspectiveManager._create_perspective() name cannot contain forward slashes (/)')
 
  258         qDebug(
'PerspectiveManager._create_perspective(%s, %s)' % (name, clone_perspective))
 
  273         if clone_perspective:
 
  278                 new_settings.set_value(key, value)
 
  288             action.setCheckable(
True)
 
  302         name, return_value = QInputDialog.getItem(
 
  304             self.
_menu_manager.tr(
'Select the perspective'), names, 0, 
False)
 
  307         if return_value == QInputDialog.Rejected:
 
  313             raise UserWarning(
'unknown perspective: %s' % name)
 
  314         qDebug(
'PerspectiveManager._remove_perspective(%s)' % str(name))
 
  332         file_name, _ = QFileDialog.getOpenFileName(
 
  333             self.
_menu_manager.menu, self.tr(
'Import perspective from file'),
 
  334             self.
_file_path, self.tr(
'Perspectives (*.perspective)'))
 
  335         if file_name 
is None or file_name == 
'':
 
  338         perspective_name = os.path.basename(file_name)
 
  339         suffix = 
'.perspective' 
  340         if perspective_name.endswith(suffix):
 
  341             perspective_name = perspective_name[:-len(suffix)]
 
  344             if perspective_name 
is None:
 
  357         file_handle = open(path, 
'r')
 
  359         data = json.loads(file_handle.read())
 
  368         """Set dictionary key-value pairs on Settings instance.""" 
  369         keys = data.get(
'keys', {})
 
  371             settings.set_value(key, keys[key])
 
  372         groups = data.get(
'groups', {})
 
  374             sub = settings.get_settings(group)
 
  378         save_file_name = os.path.join(
 
  380         suffix = 
'.perspective' 
  381         if not save_file_name.endswith(suffix):
 
  382             save_file_name += suffix
 
  383         file_name, _ = QFileDialog.getSaveFileName(
 
  384             self.
_menu_manager.menu, self.tr(
'Export perspective to file'),
 
  385             save_file_name, self.tr(
'Perspectives (*.perspective)'))
 
  386         if file_name 
is None or file_name == 
'':
 
  401         file_handle = open(file_name, 
'w')
 
  402         file_handle.write(json.dumps(data, indent=2, separators=(
',', 
': ')))
 
  406         """Convert data of Settings instance to dictionary.""" 
  408         for key 
in settings.child_keys():
 
  409             keys[str(key)] = settings.value(key)
 
  411         for group 
in settings.child_groups():
 
  412             sub = settings.get_settings(group)
 
  414         return {
'keys': keys, 
'groups': groups}
 
  417         keys = data.get(
'keys', {})
 
  419             keys[key] = convert_function(keys[key])
 
  420         groups = data.get(
'groups', {})
 
  426         if value[
'type'] == 
'repr':
 
  427             return eval(value[
'repr'])
 
  428         elif value[
'type'] == 
'repr(QByteArray.hex)':
 
  429             return QByteArray.fromHex(eval(value[
'repr(QByteArray.hex)']))
 
  431             'PerspectiveManager._import_value() unknown serialization type (%s)' % value[
'type'])
 
  435         if value.__class__.__name__ == 
'QByteArray':
 
  436             hex_value = value.toHex()
 
  437             data[
'repr(QByteArray.hex)'] = \
 
  439             data[
'type'] = 
'repr(QByteArray.hex)' 
  443             for i 
in range(1, value.size(), 2):
 
  445                     character = value.at(i)
 
  446                     if isinstance(character, bytes):
 
  447                         character = character.decode(
'utf-8')
 
  449                     if character >= 
' ' and character <= 
'~':
 
  450                         characters += character
 
  453                 except UnicodeDecodeError:
 
  455             data[
'pretty-print'] = characters
 
  459             data[
'type'] = 
'repr' 
  463         if reimported != value:
 
  465                 'PerspectiveManager._export_value() stored value can not be restored (%s)' %
 
  471         """Strip binding specific prefix from type string.""" 
  472         parts = obj.__class__.__module__.split(
'.')
 
  473         if len(parts) > 1 
and parts[1] == 
'QtCore':
 
  474             prefix = 
'.'.join(parts[:2])
 
  475             data = data.replace(prefix, 
'QtCore', 1)