File: database_schema_selector_widget.py

package info (click to toggle)
mysql-workbench 6.3.8%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 113,932 kB
  • ctags: 87,814
  • sloc: ansic: 955,521; cpp: 427,465; python: 59,728; yacc: 59,129; xml: 54,204; sql: 7,091; objc: 965; makefile: 638; sh: 613; java: 237; perl: 30; ruby: 6; php: 1
file content (225 lines) | stat: -rw-r--r-- 10,883 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; version 2 of the
# License.
# 
# 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 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, unicode)) 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 schemata 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 ui_settings.iteritems():
                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.newTreeNodeView(mforms.TreeDefault)
        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('')
        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')