/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * Created on Jul 13, 2004 */ package org.jkiss.dbeaver.ext.erd.model; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.jface.preference.IPreferenceStore; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.ext.erd.ERDActivator; import org.jkiss.dbeaver.ext.erd.editor.ERDAttributeStyle; import org.jkiss.dbeaver.ext.erd.editor.ERDAttributeVisibility; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.struct.DBSEntity; import org.jkiss.dbeaver.model.struct.DBSObject; import org.jkiss.utils.ArrayUtils; import java.util.*; /** * Represents a Schema in the model. Note that this class also includes * diagram specific information (layoutManualDesired and layoutManualAllowed fields) * although ideally these should be in a separate model hierarchy * @author Serge Rider */ public class EntityDiagram extends ERDObject<DBSObject> { private String name; private List<ERDEntity> entities = new ArrayList<>(); private boolean layoutManualDesired = true; private boolean layoutManualAllowed = false; private Map<DBSEntity, ERDEntity> tableMap = new IdentityHashMap<>(); private Map<ERDObject, Rectangle> initBounds = new IdentityHashMap<>(); private List<ERDNote> notes = new ArrayList<>(); private boolean needsAutoLayout; private ERDAttributeVisibility attributeVisibility = ERDAttributeVisibility.PRIMARY; private ERDAttributeStyle[] attributeStyles = new ERDAttributeStyle[] { ERDAttributeStyle.ICONS }; private List<String> errorMessages = new ArrayList<>(); public EntityDiagram(DBSObject container, String name) { super(container); if (name == null) throw new IllegalArgumentException("Name cannot be null"); this.name = name; IPreferenceStore store = ERDActivator.getDefault().getPreferenceStore(); this.attributeVisibility = ERDAttributeVisibility.getDefaultVisibility(store); this.attributeStyles = ERDAttributeStyle.getDefaultStyles(store); } public boolean hasAttributeStyle(ERDAttributeStyle style) { return ArrayUtils.contains(attributeStyles, style); } public void setAttributeStyle(ERDAttributeStyle style, boolean enable) { if (enable) { attributeStyles = ArrayUtils.add(ERDAttributeStyle.class, attributeStyles, style); } else { attributeStyles = ArrayUtils.remove(ERDAttributeStyle.class, attributeStyles, style); } ERDAttributeStyle.setDefaultStyles(ERDActivator.getDefault().getPreferences(), attributeStyles); } public ERDAttributeVisibility getAttributeVisibility() { return attributeVisibility; } public void setAttributeVisibility(ERDAttributeVisibility attributeVisibility) { this.attributeVisibility = attributeVisibility; ERDAttributeVisibility.setDefaultVisibility(ERDActivator.getDefault().getPreferences(), attributeVisibility); } public synchronized void addTable(ERDEntity entity, boolean reflect) { addTable(entity, -1, reflect); } public synchronized void addTable(ERDEntity entity, int i, boolean reflect) { if (i < 0) { entities.add(entity); } else { entities.add(i, entity); } tableMap.put(entity.getObject(), entity); if (reflect) { firePropertyChange(CHILD, null, entity); /* for (ERDAssociation rel : entity.getPrimaryKeyRelationships()) { entity.firePropertyChange(INPUT, null, rel); } for (ERDAssociation rel : entity.getForeignKeyRelationships()) { entity.firePropertyChange(OUTPUT, null, rel); } */ } resolveRelations(reflect); if (reflect) { for (ERDAssociation rel : entity.getPrimaryKeyRelationships()) { rel.getForeignKeyEntity().firePropertyChange(OUTPUT, null, rel); } } } private void resolveRelations(boolean reflect) { // Resolve incomplete relations for (ERDEntity erdEntity : getEntities()) { erdEntity.resolveRelations(tableMap, reflect); } } public synchronized void removeTable(ERDEntity entity, boolean reflect) { tableMap.remove(entity.getObject()); entities.remove(entity); if (reflect) { firePropertyChange(CHILD, entity, null); } } /** * @return the Tables for the current schema */ public synchronized List<ERDEntity> getEntities() { return entities; } public synchronized List<ERDNote> getNotes() { return notes; } public synchronized void addNote(ERDNote note, boolean reflect) { notes.add(note); if (reflect) { firePropertyChange(CHILD, null, note); } } public synchronized void removeNote(ERDNote note, boolean reflect) { notes.remove(note); if (reflect) { firePropertyChange(CHILD, note, null); } } /** * @return the name of the schema */ @NotNull @Override public String getName() { return name; } public void setName(String name) { this.name = name; } /** * @param layoutManualAllowed * The layoutManualAllowed to set. */ public void setLayoutManualAllowed(boolean layoutManualAllowed) { this.layoutManualAllowed = layoutManualAllowed; } /** * @return Returns the layoutManualDesired. */ public boolean isLayoutManualDesired() { return layoutManualDesired; } /** * @param layoutManualDesired * The layoutManualDesired to set. */ public void setLayoutManualDesired(boolean layoutManualDesired) { this.layoutManualDesired = layoutManualDesired; } /** * @return Returns whether we can lay out individual entities manually using the XYLayout */ public boolean isLayoutManualAllowed() { return layoutManualAllowed; } public int getEntityCount() { return entities.size(); } public EntityDiagram copy() { EntityDiagram copy = new EntityDiagram(getObject(), getName()); copy.entities.addAll(this.entities); copy.tableMap.putAll(this.tableMap); copy.layoutManualDesired = this.layoutManualDesired; copy.layoutManualAllowed = this.layoutManualAllowed; copy.initBounds = initBounds; return copy; } public void fillTables(DBRProgressMonitor monitor, Collection<DBSEntity> tables, DBSObject dbObject) { // Load entities monitor.beginTask("Load entities metadata", tables.size()); for (DBSEntity table : tables) { if (monitor.isCanceled()) { break; } monitor.subTask("Load " + table.getName()); ERDEntity erdEntity = ERDEntity.fromObject(monitor, this, table); erdEntity.setPrimary(table == dbObject); addTable(erdEntity, false); tableMap.put(table, erdEntity); monitor.worked(1); } monitor.done(); // Load relations monitor.beginTask("Load entities' relations", tables.size()); for (DBSEntity table : tables) { if (monitor.isCanceled()) { break; } monitor.subTask("Load " + table.getName()); final ERDEntity erdEntity = tableMap.get(table); if (erdEntity != null) { erdEntity.addRelations(monitor, tableMap, false); } monitor.worked(1); } monitor.done(); } public boolean containsTable(DBSEntity table) { for (ERDEntity erdEntity : entities) { if (erdEntity.getObject() == table) { return true; } } return false; } public Map<DBSEntity,ERDEntity> getTableMap() { return tableMap; } public ERDEntity getERDTable(DBSEntity table) { return tableMap.get(table); } public void clear() { this.entities.clear(); this.tableMap.clear(); this.initBounds.clear(); } public Rectangle getInitBounds(ERDObject erdObject) { return initBounds.get(erdObject); } public void addInitBounds(ERDObject erdTable, Rectangle bounds) { initBounds.put(erdTable, bounds); } public boolean isNeedsAutoLayout() { return needsAutoLayout; } public void setNeedsAutoLayout(boolean needsAutoLayout) { this.needsAutoLayout = needsAutoLayout; } public void addInitRelationBends(ERDEntity sourceEntity, ERDEntity targetEntity, String relName, List<Point> bends) { for (ERDAssociation rel : sourceEntity.getPrimaryKeyRelationships()) { if (rel.getForeignKeyEntity() == targetEntity && relName.equals(rel.getObject().getName())) { rel.setInitBends(bends); } } } public List<ERDObject> getContents() { List<ERDObject> children = new ArrayList<>(entities.size() + notes.size()); children.addAll(entities); children.addAll(notes); return children; } public List<String> getErrorMessages() { return errorMessages; } public void addErrorMessage(String message) { errorMessages.add(message); } }