File: C:/Program Files/MySQL/MySQL Workbench 8.0/workbench/database_schema_selector_widget.py
# Copyright (c) 2012, 2020, Oracle and/or its affiliates.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License, version 2.0,
# as published by the Free Software Foundation.
#
# This program is also distributed with certain software (including
# but not limited to OpenSSL) that is licensed under separate terms, as
# designated in a particular file or component or in included license
# documentation. The authors of MySQL hereby grant you an additional
# permission to link the program and your derivative works with the
# separately licensed software that they have included with MySQL.
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
# the GNU General Public License, version 2.0, for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import functools
import mforms
class DatabaseSchemaSelector(mforms.Box):
'''Widget to select database schemata within a collection of catalogs (optional) and schemata
This wigdet will help you to display a set of schemata in a nice tree structure, grouping them
by catalogs (if the catalog information is supported/available). Next to each listed schema is
a checkbox for the selection/unselection of the schema. The user can quickly select all of the
schemata for a given catalog by clicking on the checkbox next to the catalog name.
.. image:: ../../../library/python/workbench/doc/images/schema_selection_widget.png
:param database_objects: Pass a list/tuple of schema names if you don't use catalogs.
If you do use catalogs then pass a list of tuples of the form
``(catalog_name, schema_list)`` where :attr:`schema_list` is a
list/tuple with the schemata that belongs to the given :attr:`catalog_name`.
:type database_objects: list/tuple
:param tree_checked_callback: A function object that will be called by this widget whenever
a schema is checked/unchecked. It should accept an integer
argument with the number of selected schemata.
:type tree_checked_callback: callable
:param ui_settings: A dictionary to customize the appearance of the widget. In
case you need to customize something, just pass the relevant
modifications in this dict. The other (default) settings are
kept. Check the definition of :attr:`self.ui_settings` in the
class implementation to see the configurable settings.
:type ui_settings: dict
.. rubric:: Sample usage:
::
db_objects = [ ('catalog1', ('schema1', 'schema2')),
('catalog2', ('schema3', 'schema4'))
]
content = mforms.newBox()
object_selector = DatabaseObjectSelector(db_objects)
content.add(object_selector, True)
'''
def __init__(self, database_objects, tree_checked_callback=lambda n:None, ui_settings={}):
'''Constructor.
'''
super(DatabaseSchemaSelector, self).__init__(False)
self.database_objects = database_objects
self.tree_checked_callback = tree_checked_callback
# Check if we should use catalogs:
self.use_catalogs = ( isinstance(database_objects, (list, tuple)) and
len(database_objects) > 0 and
all( isinstance(item, (list, tuple)) and
len(item) == 2 and
isinstance(item[0], str) and
isinstance(item[1], (list, tuple))
for item in database_objects
)
)
self.ui_settings = {
'catalogs' : { 'icon': 'workbench.physical.Layer.16x16.png',
'should_expand': True,
},
'schemas' : { 'icon': 'db.Schema.16x16.png',
},
'general' : { 'summary_text': '%(nSchemata)d schemas selected',
'show_select_all_button': not self.use_catalogs,
'show_unselect_all_button': True,
},
}
# Update the ui settings dict with the custom settings supplied by the user (if any):
if isinstance(ui_settings, dict):
for key, value in list(ui_settings.items()):
if key not in self.ui_settings or not isinstance(value, dict):
continue
self.ui_settings[key].update(value)
if self.use_catalogs:
self._catalogs = tuple(item[0] for item in database_objects)
self._schemata = dict(database_objects)
else:
self._catalogs = None
self._schemata = database_objects
self._schema_nodes = []
self._catalog_nodes = []
# Create UI:
self.set_spacing(8)
self.schema_list_tree = mforms.newTreeView(mforms.TreeDefault)
self.schema_list_tree.set_name('Schema List')
self.schema_list_tree.add_column(mforms.CheckColumnType, 'Include', 60, True)
self.schema_list_tree.add_column(mforms.IconColumnType, 'Catalog/Schema' if self.use_catalogs else 'Schema', 300, False)
self.schema_list_tree.end_columns()
self.schema_list_tree.set_cell_edited_callback(self._schema_tree_checked)
self.schema_list_tree.set_allow_sorting(False)
self.add(self.schema_list_tree, True, True)
helper_buttons_box = mforms.newBox(True)
helper_buttons_box.set_spacing(12)
self.select_summary_label = mforms.newLabel('')
self.select_summary_label.set_name('Summary')
helper_buttons_box.add(self.select_summary_label, False, True)
if self.ui_settings['general']['show_unselect_all_button']:
self.unselect_all_btn = mforms.newButton()
self.unselect_all_btn.set_text('Unselect All')
self.unselect_all_btn.add_clicked_callback(functools.partial(self._mark_all_schemata, checked=False))
helper_buttons_box.add_end(self.unselect_all_btn, False)
if self.ui_settings['general']['show_select_all_button']:
self.select_all_btn = mforms.newButton()
self.select_all_btn.set_text('Select All')
self.select_all_btn.add_clicked_callback(functools.partial(self._mark_all_schemata, checked=True))
helper_buttons_box.add_end(self.select_all_btn, False)
self.add(helper_buttons_box, False, True)
self._fill_schema_tree()
def _fill_schema_tree(self):
self._schema_nodes = []
self._catalog_nodes = []
if self.use_catalogs:
for catalog_name in self._catalogs:
catalog_node = self.schema_list_tree.add_node()
catalog_node.set_bool(0, False)
catalog_node.set_icon_path(1, self.ui_settings['catalogs']['icon'])
catalog_node.set_string(1, catalog_name)
catalog_node.set_tag(catalog_name)
self._catalog_nodes.append(catalog_node)
for schema_name in self._schemata[catalog_name]:
schema_node = catalog_node.add_child()
schema_node.set_bool(0, False)
schema_node.set_icon_path(1, self.ui_settings['schemas']['icon'])
schema_node.set_string(1, schema_name)
schema_node.set_tag(catalog_name + '.' + schema_name)
self._schema_nodes.append(schema_node)
if self.ui_settings['catalogs']['should_expand']:
catalog_node.expand()
else: # Not using catalogs
for schema_name in self._schemata:
schema_node = self.schema_list_tree.add_node()
schema_node.set_bool(0, False)
schema_node.set_icon_path(1, self.ui_settings['schemas']['icon'])
schema_node.set_string(1, schema_name)
schema_node.set_tag(schema_name)
self._schema_nodes.append(schema_node)
if len(self._schemata) == 1:
self.schema_list_tree.select_node(schema_node)
self.select_summary_label.set_text(self.ui_settings['general']['summary_text'] % {'nSchemata':0})
def _schema_tree_checked(self, node_list, col, data):
# This allows to change the status of several nodes at once too:
if not isinstance(node_list, list):
node_list = [node_list]
for node in node_list:
if col == 0:
checked = data == '1'
node.set_bool(0, checked)
if self.use_catalogs:
parent_node = node.get_parent()
is_catalog = parent_node == self.schema_list_tree.root_node()
catalog_name = node.get_string(1) if is_catalog else parent_node.get_string(1)
schema_count = len(self._schemata[catalog_name])
if is_catalog:
for idx in range(schema_count):
node.get_child(idx).set_bool(0, checked)
else:
# Check/uncheck parent catalog if all of its schemata are checked/unchecked:
parent_node.set_bool(0, checked and all( schema_node.get_bool(0) for schema_node in ( parent_node.get_child(idx) for idx in range(schema_count) ) ) )
selected_schema_count = len(tuple(schema_node for schema_node in self._schema_nodes if schema_node.get_bool(0)))
self.select_summary_label.set_text(self.ui_settings['general']['summary_text'] % {'nSchemata':selected_schema_count})
self.tree_checked_callback(selected_schema_count)
def _select_objects(self, checked):
if self.use_catalogs:
catalog_schemata = {}
for schema_node in self._schema_nodes:
if schema_node.get_bool(0) != checked:
continue
catalog_name, dot, schema_name = schema_node.get_tag().rpartition('.')
catalog_schemata.setdefault(catalog_name, []).append(schema_name)
return catalog_schemata
else:
return [ schema_node.get_string(1) for schema_node in self._schema_nodes if schema_node.get_bool(0) == checked ]
def get_selected(self):
return self._select_objects(True)
def get_ignored(self):
return self._select_objects(False)
def _mark_all_schemata(self, checked):
nodes = self._catalog_nodes if self.use_catalogs else self._schema_nodes
self._schema_tree_checked(nodes, 0, '1' if checked else '0')