/*
* 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 19, 2004
*/
package org.jkiss.dbeaver.ext.erd.editor;
import org.eclipse.gef.DefaultEditDomain;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.Tool;
import org.eclipse.gef.palette.PaletteContainer;
import org.eclipse.gef.palette.PaletteDrawer;
import org.eclipse.gef.palette.PaletteRoot;
import org.eclipse.gef.palette.ToolEntry;
import org.eclipse.gef.tools.SelectionTool;
import org.eclipse.gef.ui.parts.AbstractEditPartViewer;
import org.eclipse.gef.ui.parts.ScrollingGraphicalViewer;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.themes.ITheme;
import org.eclipse.ui.themes.IThemeManager;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.ext.erd.ERDConstants;
import org.jkiss.dbeaver.ext.erd.directedit.ValidationMessageHandler;
import org.jkiss.dbeaver.ext.erd.part.DiagramPart;
import org.jkiss.dbeaver.ext.erd.part.EntityPart;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.struct.DBSEntity;
import org.jkiss.dbeaver.ui.DBeaverIcons;
import org.jkiss.dbeaver.ui.UIUtils;
import java.util.*;
/**
* GraphicalViewer which also knows about ValidationMessageHandler to output
* error messages to
* @author Serge Rider
*/
public class ERDGraphicalViewer extends ScrollingGraphicalViewer implements IPropertyChangeListener, DBPEventListener {
private static final Log log = Log.getLog(ERDGraphicalViewer.class);
private ERDEditorPart editor;
private ValidationMessageHandler messageHandler;
private IThemeManager themeManager;
private boolean loadContents = false;
private static class DataSourceInfo {
int tableCount = 0;
}
private final Map<DBPDataSourceContainer, DataSourceInfo> usedDataSources = new IdentityHashMap<>();
/**
* ValidationMessageHandler to receive messages
* @param messageHandler message handler
*/
public ERDGraphicalViewer(ERDEditorPart editor, ValidationMessageHandler messageHandler)
{
super();
this.editor = editor;
this.messageHandler = messageHandler;
themeManager = editor.getSite().getWorkbenchWindow().getWorkbench().getThemeManager();
themeManager.addPropertyChangeListener(this);
}
public ERDEditorPart getEditor()
{
return editor;
}
@Override
public void setControl(Control control)
{
super.setControl(control);
if (control != null) {
ERDEditorAdapter.mapControl(control, editor);
UIUtils.addFocusTracker(editor.getSite(), ERDConstants.ERD_CONTROL_ID, control);
applyThemeSettings();
}
}
@Override
protected void handleDispose(DisposeEvent e) {
if (themeManager != null) {
themeManager.removePropertyChangeListener(this);
}
if (getControl() != null) {
ERDEditorAdapter.unmapControl(getControl());
UIUtils.removeFocusTracker(editor.getSite(), getControl());
}
super.handleDispose(e);
}
/**
* @return Returns the messageLabel.
*/
public ValidationMessageHandler getValidationHandler()
{
return messageHandler;
}
/**
* This method is invoked when this viewer's control loses focus. It removes
* focus from the {@link AbstractEditPartViewer#focusPart focusPart}, if
* there is one.
*
* @param fe
* the focusEvent received by this viewer's control
*/
@Override
protected void handleFocusLost(FocusEvent fe)
{
//give the superclass a chance to handle this first
super.handleFocusLost(fe);
//call reset on the MessageHandler itself
messageHandler.reset();
}
@Override
public void propertyChange(PropertyChangeEvent event)
{
if (event.getProperty().equals(IThemeManager.CHANGE_CURRENT_THEME)
|| event.getProperty().equals("org.jkiss.dbeaver.erd.diagram.font"))
{
applyThemeSettings();
}
}
private void applyThemeSettings()
{
ITheme currentTheme = themeManager.getCurrentTheme();
Font erdFont = currentTheme.getFontRegistry().get("org.jkiss.dbeaver.erd.diagram.font");
if (erdFont != null) {
this.getControl().setFont(erdFont);
}
editor.refreshDiagram(true);
/*
DiagramPart diagramPart = editor.getDiagramPart();
if (diagramPart != null) {
diagramPart.resetFonts();
diagramPart.refresh();
}
*/
}
@Override
public void setContents(EditPart editpart)
{
loadContents = true;
try {
super.setContents(editpart);
// Reset palette contents
if (editpart instanceof DiagramPart) {
List<DBSEntity> tables = new ArrayList<>();
for (Object child : editpart.getChildren()) {
if (child instanceof EntityPart) {
tables.add(((EntityPart) child).getTable().getObject());
}
}
Collections.sort(tables, DBUtils.<DBSEntity>nameComparator());
Map<PaletteDrawer, List<ToolEntryTable>> toolMap = new LinkedHashMap<>();
for (DBSEntity table : tables) {
DBPDataSourceContainer container = table.getDataSource().getContainer();
PaletteDrawer drawer = getContainerPaletteDrawer(container);
if (drawer != null) {
List<ToolEntryTable> tools = toolMap.get(drawer);
if (tools == null) {
tools = new ArrayList<>(tables.size());
toolMap.put(drawer, tools);
}
tools.add(new ToolEntryTable(table));
}
}
for (Map.Entry<PaletteDrawer, List<ToolEntryTable>> entry : toolMap.entrySet()) {
entry.getKey().setChildren(entry.getValue());
}
//editor.getPaletteContents().setChildren(tools);
}
}
finally {
loadContents = false;
}
}
public void handleTableActivate(DBSEntity table)
{
if (table.getDataSource() != null) {
DBPDataSourceContainer container = table.getDataSource().getContainer();
if (container != null) {
synchronized (usedDataSources) {
DataSourceInfo dataSourceInfo = usedDataSources.get(container);
if (dataSourceInfo == null) {
dataSourceInfo = new DataSourceInfo();
usedDataSources.put(container, dataSourceInfo);
acquireContainer(container);
}
dataSourceInfo.tableCount++;
}
}
}
if (!loadContents) {
final PaletteContainer drawer = getContainerPaletteDrawer(table.getDataSource().getContainer());
if (drawer != null) {
// Add entry (with right order)
List children = drawer.getChildren();
int index = 0;
for (int i = 0, childrenSize = children.size(); i < childrenSize; i++) {
Object child = children.get(i);
if (child instanceof ToolEntryTable) {
if (((ToolEntryTable) child).table.getName().compareTo(table.getName()) > 0) {
index = i;
break;
}
}
}
drawer.add(index, new ToolEntryTable(table));
}
}
}
public void handleTableDeactivate(DBSEntity table)
{
final PaletteContainer drawer = getContainerPaletteDrawer(table.getDataSource().getContainer());
if (drawer != null) {
for (Object entry : drawer.getChildren()) {
if (entry instanceof ToolEntryTable && ((ToolEntryTable)entry).table == table) {
drawer.remove((ToolEntryTable)entry);
break;
}
}
}
if (table.getDataSource() != null) {
DBPDataSourceContainer container = table.getDataSource().getContainer();
if (container != null) {
synchronized (usedDataSources) {
DataSourceInfo dataSourceInfo = usedDataSources.get(container);
if (dataSourceInfo == null) {
log.warn("Datasource '" + container + "' not registered in ERD viewer");
} else {
dataSourceInfo.tableCount--;
if (dataSourceInfo.tableCount <= 0) {
usedDataSources.remove(container);
releaseContainer(container);
}
}
}
}
}
}
private void acquireContainer(DBPDataSourceContainer container)
{
container.acquire(editor);
container.getRegistry().addDataSourceListener(this);
PaletteRoot paletteRoot = editor.getPaletteRoot();
PaletteDrawer dsDrawer = new PaletteDrawer(
container.getName(),
DBeaverIcons.getImageDescriptor(container.getDriver().getIcon()));
dsDrawer.setDescription(container.getDescription());
dsDrawer.setId(container.getId());
paletteRoot.add(dsDrawer);
}
private void releaseContainer(DBPDataSourceContainer container)
{
PaletteDrawer drawer = getContainerPaletteDrawer(container);
if (drawer != null) {
editor.getPaletteRoot().remove(drawer);
}
container.getRegistry().removeDataSourceListener(this);
container.release(editor);
}
PaletteDrawer getContainerPaletteDrawer(DBPDataSourceContainer container)
{
for (Object child : editor.getPaletteRoot().getChildren()) {
if (child instanceof PaletteDrawer && container.getId().equals(((PaletteDrawer) child).getId())) {
return (PaletteDrawer) child;
}
}
return null;
}
@Override
public void handleDataSourceEvent(DBPEvent event)
{
if (!(event.getObject() instanceof DBPDataSourceContainer)) {
return;
}
DBPDataSourceContainer container = (DBPDataSourceContainer)event.getObject();
if (usedDataSources.containsKey(container) &&
event.getAction() == DBPEvent.Action.OBJECT_UPDATE &&
Boolean.FALSE.equals(event.getEnabled()) &&
!DBeaverCore.isClosing())
{
// Close editor only if it is simple disconnect
// Workbench shutdown doesn't close editor
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
editor.getSite().getWorkbenchWindow().getActivePage().closeEditor(editor, false);
}
});
}
}
private class ToolEntryTable extends ToolEntry {
private final DBSEntity table;
public ToolEntryTable(DBSEntity table)
{
super(table.getName(), table.getDescription(), DBeaverIcons.getImageDescriptor(DBIcon.TREE_TABLE), null);
this.setUserModificationPermission(PERMISSION_NO_MODIFICATION);
setDescription(DBUtils.getObjectFullName(table, DBPEvaluationContext.UI));
this.table = table;
}
@Override
public Tool createTool()
{
return new ToolSelectTable(table);
}
}
public static class ToolSelectTable extends SelectionTool {
private final DBSEntity table;
public ToolSelectTable(DBSEntity table)
{
this.table = table;
}
@Override
public void activate()
{
//ERDGraphicalViewer.this.reveal(part);
DefaultEditDomain editDomain = (DefaultEditDomain) getDomain();
final ERDEditorPart editorPart = (ERDEditorPart)editDomain.getEditorPart();
final GraphicalViewer viewer = editorPart.getViewer();
for (Object child : editorPart.getDiagramPart().getChildren()) {
if (child instanceof EntityPart) {
if (((EntityPart)child).getTable().getObject() == table) {
viewer.reveal((EditPart) child);
viewer.select((EditPart) child);
break;
}
}
}
super.activate();
}
}
}