File: C:/Program Files/MySQL/MySQL Workbench 8.0/modules/table_templates.py
# Copyright (c) 2014, 2021, 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, 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 grt
import mforms
import sys
class TemplateEditor(mforms.Form):
def __init__(self, owner):
mforms.Form.__init__(self, None, mforms.FormDialogFrame|mforms.FormResizable|mforms.FormMinimizable)
self.owner = owner
# We need to have some default catalog and schema so parser is happy
self.tmpCatalog = grt.classes.db_mysql_Catalog()
self.tmpCatalog.name = 'tmpCatalog'
self.tmpCatalog.oldName = self.tmpCatalog.name
self.tmpCatalog.simpleDatatypes.extend(grt.root.wb.rdbmsMgmt.rdbms[0].simpleDatatypes)
self.tmpSchema= grt.classes.db_mysql_Schema()
self.tmpSchema.name = "tmpSchema"
self.tmpSchema.oldName = self.tmpSchema.name
self.tmpSchema.owner = self.tmpCatalog
self.tmpCatalog.schemata.append(self.tmpSchema)
self.tables_by_id = {}
self.set_title("Table Templates")
box = mforms.newBox(False)
box.set_padding(12)
box.set_spacing(12)
label = mforms.newLabel("Manage templates of tables with pre-defined columns, for frequently used table structures.")
box.add(label, False, True)
top = mforms.newBox(True)
box.add(top, False, True)
#top.set_padding(12)
top.set_spacing(12)
self.template_list = mforms.newTreeView(mforms.TreeFlatList)
self.template_list.add_column(mforms.IconStringColumnType, "Table Template", 200, True)
self.template_list.end_columns()
self.template_list.add_changed_callback(self.table_selected)
self.template_list.set_cell_edited_callback(self.table_edited)
top.add(self.template_list, True, True)
if sys.platform.lower() != "darwin":
self.template_list.set_size(-1, 150)
bbox = mforms.newBox(False)
bbox.set_spacing(8)
top.add(bbox, False, True)
self.add = mforms.newButton()
self.add.set_text("New Template")
self.add.add_clicked_callback(self.add_templ)
bbox.add(self.add, False, True)
self.duplicate = mforms.newButton()
self.duplicate.set_text("Duplicate")
self.duplicate.add_clicked_callback(self.dup_templ)
self.duplicate.set_enabled(False)
bbox.add(self.duplicate, False, True)
self.delete = mforms.newButton()
self.delete.set_text("Delete")
self.delete.add_clicked_callback(self.del_templ)
self.delete.set_enabled(False)
bbox.add(self.delete, False, True)
hbox = mforms.newBox(True)
hbox.set_spacing(12)
self.column_list = mforms.newTreeView(mforms.TreeFlatList)
self.column_list.add_column(mforms.IconStringColumnType, "Column", 100, True)
self.column_list.add_column(mforms.StringColumnType, "Datatype", 100, True)
self.column_list.add_column(mforms.StringColumnType, "Default", 150, True)
self.column_list.add_column(mforms.CheckColumnType, "PK", 25, True)
self.column_list.add_column(mforms.CheckColumnType, "NN", 25, True)
self.column_list.add_column(mforms.CheckColumnType, "UQ", 25, True)
self.column_list.add_column(mforms.CheckColumnType, "AI", 25, True)
self.column_list.end_columns()
self.column_list.set_cell_edited_callback(self.column_edited)
self.column_list.add_changed_callback(self.column_selected)
hbox.add(self.column_list, True, True)
vbox = mforms.newBox(False)
vbox.set_spacing(8)
vbox.add(mforms.newLabel("Column Collation:"), False, True)
self.charset = mforms.newSelector(mforms.SelectorPopup)
self.charset.add_changed_callback(self.collation_changed)
collations = ["Table Default"]
for ch in grt.root.wb.rdbmsMgmt.rdbms[0].characterSets:
collations += ch.collations
self.charset.add_items(collations)
vbox.add(self.charset, False, True)
vbox.add(mforms.newLabel("Additional Flags:"), False, True)
self.flag_checkboxes = []
hbox.add(vbox, False, True)
self.column_details = vbox
box.add(hbox, True, True)
self.column_menu = mforms.newContextMenu()
self.column_menu.add_item_with_title("Delete", self.delete_column)
self.column_list.set_context_menu(self.column_menu)
bbox = mforms.newBox(True)
self.ok = mforms.newButton()
self.ok.set_text("Close")
bbox.add_end(self.ok, False, True)
box.add(bbox, False, True)
self.set_content(box)
self.set_size(800, 500)
self.center()
self.refresh_tables()
def add_templ(self):
table = grt.classes.db_mysql_Table()
table.name = "template %i" % (len(self.owner.templates)+1)
table.owner = self.tmpSchema
self.tmpSchema.tables.append(table)
self.tables_by_id[table.__id__] = table
self.owner.templates.append(table)
node = self.template_list.add_node()
node.set_icon_path(0, mforms.App.get().get_resource_path("db.Table.16x16.png"))
node.set_string(0, table.name)
node.set_tag(table.__id__)
self.template_list.select_node(node)
self.table_selected()
def del_templ(self):
node = self.template_list.get_selected_node()
if node:
table = self.tables_by_id[node.get_tag()]
del self.tables_by_id[node.get_tag()]
self.owner.templates.remove(table)
self.tmpSchema.tables.remove(table)
node.remove_from_parent()
def dup_templ(self):
orig = self.selected_table()
table = self.owner.copy_table(orig)
table.owner = self.tmpSchema
self.tmpSchema.tables.append(table)
self.tables_by_id[table.__id__] = table
self.owner.templates.append(table)
node = self.template_list.add_node()
node.set_icon_path(0, mforms.App.get().get_resource_path("db.Table.16x16.png"))
node.set_string(0, table.name)
node.set_tag(table.__id__)
self.template_list.select_node(node)
self.table_selected()
def delete_column(self):
table = self.selected_table()
node = self.column_list.get_selected_node()
if node and table:
i = self.column_list.row_for_node(node)
if i < len(table.columns):
del table.columns[i]
node.remove_from_parent()
def select_template(self, name):
for i in range(self.template_list.count()):
node = self.template_list.node_at_row(i)
if node.get_string(0) == name:
self.template_list.select_node(node)
self.table_selected()
break
def table_edited(self, node, column, new_value):
table = self.selected_table()
if table:
node.set_string(column, new_value)
table.name = new_value
def table_selected(self):
self.refresh_columns()
self.duplicate.set_enabled(self.template_list.get_selected_node())
self.delete.set_enabled(self.template_list.get_selected_node())
def refresh_tables(self):
self.tables_by_id = {}
icon = mforms.App.get().get_resource_path("db.Table.16x16.png")
for table in self.owner.templates:
node = self.template_list.add_node()
node.set_icon_path(0, icon)
node.set_string(0, table.name)
node.set_tag(table.__id__)
table.owner = self.tmpSchema
self.tmpSchema.tables.append(table)
self.tables_by_id[table.__id__] = table
def selected_table(self):
node = self.template_list.get_selected_node()
if node:
return self.tables_by_id[node.get_tag()]
return None
def selected_column(self):
node = self.column_list.get_selected_node()
table = self.selected_table()
if node and table:
row = self.column_list.row_for_node(node)
if row < len(table.columns):
return table.columns[row]
return None
def show_column_node(self, node, column):
node.set_icon_path(0, mforms.App.get().get_resource_path("db.Column.16x16.png"))
node.set_string(0, column.name)
node.set_string(1, column.formattedType)
node.set_string(2, "NULL" if column.defaultValue is None else column.defaultValue)
node.set_int(3, column.owner.isPrimaryKeyColumn(column))
node.set_int(4, column.isNotNull)
node.set_int(5, "UNIQUE" in column.flags)
node.set_int(6, column.autoIncrement)
return node
def refresh_columns(self):
self.column_list.clear()
table = self.selected_table()
if table:
for column in table.columns:
node = self.column_list.add_node()
self.show_column_node(node, column)
node = self.column_list.add_node()
node.set_string(0, "Click to add")
node.set_tag("placeholder")
def column_selected(self):
column = self.selected_column()
if column:
self.column_details.set_enabled(True)
for c in self.flag_checkboxes:
self.column_details.remove(c)
self.flag_checkboxes = []
if column.simpleType:
for flag in column.simpleType.flags:
check = mforms.newCheckBox()
check.set_text(flag)
check.set_active(flag in column.flags)
self.column_details.add(check, False, True)
self.flag_checkboxes.append(check)
check.add_clicked_callback(lambda check=check, flag=flag:self.flag_checked(check, flag))
if column.simpleType.group.name != "string" and not column.simpleType.name.lower().endswith("text"):
self.charset.set_selected(0)
self.charset.set_enabled(False)
else:
self.charset.set_enabled(True)
if not column.collationName:
self.charset.set_selected(0)
else:
self.charset.set_value(column.collationName)
else:
self.charset.set_selected(0)
self.column_details.set_enabled(False)
for c in self.flag_checkboxes:
self.column_details.remove(c)
self.flag_checkboxes = []
def flag_checked(self, check, flag):
column = self.selected_column()
if column:
if check.get_active():
if flag not in column.flags:
column.flags.append(flag)
else:
if flag in column.flags:
column.flags.remove(flag)
def collation_changed(self):
column = self.selected_column()
if column:
if self.charset.get_selected_index() < 1:
column.characterSetName = ""
column.collationName = ""
else:
collation = self.charset.get_string_value()
column.collationName = collation
column.characterSetName = collation.partition("_")[0]
def column_edited(self, node, tree_column, new_value):
table = self.selected_table()
if not table or node.get_string(0) == new_value:
return
if node.get_tag() == "placeholder":
node.set_tag("")
node.set_icon_path(0, mforms.App.get().get_resource_path("db.Column.16x16.png"))
child = self.column_list.add_node()
child.set_string(0, "Click to add")
child.set_tag("placeholder")
self.column_list.select_node(node)
column = grt.classes.db_mysql_Column()
column.owner = table
table.columns.append(column)
self.show_column_node(node, column)
else:
row = self.column_list.row_for_node(node)
if row < len(table.columns):
column = table.columns[row]
else:
return
if tree_column == 0:
column.name = new_value
elif tree_column == 1:
column.setParseType(new_value, grt.root.wb.rdbmsMgmt.rdbms[0].simpleDatatypes)
elif tree_column == 2:
if new_value == 'NULL':
column.defaultValueIsNull = True
column.defaultValue = None
else:
column.defaultValueIsNull = False
column.defaultValue = new_value
elif tree_column == 3:
if new_value == '1':
table.addPrimaryKeyColumn(column)
else:
table.removePrimaryKeyColumn(column)
elif tree_column == 4:
column.isNotNull = new_value == '1'
elif tree_column == 5:
if new_value == '1' and "UNIQUE" not in column.flags:
column.flags.append("UNIQUE")
elif new_value != '1' and "UNIQUE" in column.flags:
column.flags.remove("UNIQUE")
elif tree_column == 6:
column.autoIncrement = new_value == '1'
node.set_string(tree_column, new_value)
def run(self):
self.run_modal(None, self.ok)
class TableTemplateManager:
@property
def templates(self):
tlist = grt.root.wb.options.options.get("TableTemplates", None)
if not tlist:
tlist = grt.List()
grt.root.wb.options.options["TableTemplates"] = tlist
return tlist
def export_templates(self):
dlg = mforms.FileChooser(mforms.SaveFile)
dlg.set_title("Export Table Templates")
if dlg.run_modal():
grt.serialize(self.templates, dlg.get_path())
def copy_table(self, orig):
table = grt.classes.db_mysql_Table()
table.name = orig.name+"copy"
for col in orig.columns:
colcopy = col.shallow_copy()
colcopy.owner = table
table.columns.append(colcopy)
if orig.isPrimaryKeyColumn(col):
table.addPrimaryKeyColumn(colcopy)
return table
def edit_templates(self):
ed = TemplateEditor(self)
ed.run()
def edit_template(self, name):
ed = TemplateEditor(self)
ed.select_template(name)
ed.run()
def create_table_like_template_in_schema(self, schema, template_name):
template = None
for t in self.templates:
if t.name == template_name:
template = t
break
if template:
copy = self.copy_table(template)
new_name = template_name
i = 1
while any(t.name == new_name for t in schema.tables):
new_name = "%s_%i" % (template_name, i)
i += 1
copy.name = new_name
copy.owner = schema
schema.tables.append(copy)
return copy
return None
def create_table_like_template(self, editor, schema_name, template):
copy = self.copy_table(template)
copy.name = template.name
ocatalog = grt.classes.db_mysql_Catalog()
ocatalog.name = 'default'
ocatalog.oldName = ocatalog.name
ocatalog.simpleDatatypes.extend(grt.root.wb.rdbmsMgmt.rdbms[0].simpleDatatypes)
oschema = grt.classes.db_mysql_Schema()
oschema.name = schema_name
oschema.oldName = oschema.name
oschema.owner = ocatalog
ocatalog.schemata.append(oschema)
catalog = grt.classes.db_mysql_Catalog()
catalog.name = 'default'
catalog.oldName = catalog.name
catalog.simpleDatatypes.extend(grt.root.wb.rdbmsMgmt.rdbms[0].simpleDatatypes)
schema = grt.classes.db_mysql_Schema()
schema.name = schema_name
schema.oldName = schema.name
schema.owner = catalog
catalog.schemata.append(schema)
copy.owner = schema
schema.tables.append(copy)
if editor:
editor.editLiveObject(copy, ocatalog)
def create_table_like(self, editor, schema_name, table_name):
pass