/*
* 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.
*/
package org.jkiss.dbeaver.ui;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProduct;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.*;
import org.eclipse.jface.bindings.keys.KeyStroke;
import org.eclipse.jface.bindings.keys.ParseException;
import org.eclipse.jface.commands.ActionHandler;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.fieldassist.ContentProposalAdapter;
import org.eclipse.jface.fieldassist.IContentProposalProvider;
import org.eclipse.jface.fieldassist.IControlContentAdapter;
import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.window.IShellProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.*;
import org.eclipse.ui.contexts.IContextService;
import org.eclipse.ui.dialogs.PreferencesUtil;
import org.eclipse.ui.handlers.IHandlerActivation;
import org.eclipse.ui.handlers.IHandlerService;
import org.eclipse.ui.services.IServiceLocator;
import org.eclipse.ui.swt.IFocusService;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverActivator;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.connection.DBPConnectionType;
import org.jkiss.dbeaver.model.meta.IPropertyValueListProvider;
import org.jkiss.dbeaver.model.preferences.DBPPropertyDescriptor;
import org.jkiss.dbeaver.model.preferences.DBPPropertySource;
import org.jkiss.dbeaver.model.runtime.AbstractJob;
import org.jkiss.dbeaver.ui.actions.datasource.DataSourceInvalidateHandler;
import org.jkiss.dbeaver.ui.controls.*;
import org.jkiss.dbeaver.ui.dialogs.StandardErrorDialog;
import org.jkiss.dbeaver.ui.dialogs.driver.DriverEditDialog;
import org.jkiss.dbeaver.ui.editors.text.BaseTextEditor;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.BeanUtils;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.text.DecimalFormatSymbols;
import java.text.MessageFormat;
import java.util.Collection;
import java.util.Comparator;
import java.util.Locale;
import java.util.SortedMap;
/**
* UI Utils
*/
public class UIUtils {
private static final Log log = Log.getLog(UIUtils.class);
public static final String INLINE_WIDGET_EDITOR_ID = "org.jkiss.dbeaver.ui.InlineWidgetEditor";
public static VerifyListener getIntegerVerifyListener(Locale locale)
{
final DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
return new VerifyListener() {
@Override
public void verifyText(VerifyEvent e)
{
for (int i = 0; i < e.text.length(); i++) {
char ch = e.text.charAt(i);
if (!Character.isDigit(ch) && ch != symbols.getMinusSign() && ch != symbols.getGroupingSeparator()) {
e.doit = false;
return;
}
}
e.doit = true;
}
};
}
public static VerifyListener getNumberVerifyListener(Locale locale)
{
DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(locale);
final char[] allowedChars = new char[] { symbols.getDecimalSeparator(), symbols.getGroupingSeparator(),
symbols.getMinusSign(), symbols.getZeroDigit(), symbols.getMonetaryDecimalSeparator(), '+' };
final String exponentSeparator = symbols.getExponentSeparator();
return new VerifyListener() {
@Override
public void verifyText(VerifyEvent e)
{
for (int i = 0; i < e.text.length(); i++) {
char ch = e.text.charAt(i);
if (!Character.isDigit(ch) && !ArrayUtils.contains(allowedChars, ch) && exponentSeparator.indexOf(ch) == -1) {
e.doit = false;
return;
}
}
e.doit = true;
}
};
}
public static void createToolBarSeparator(ToolBar toolBar, int style) {
Label label = new Label(toolBar, SWT.NONE);
label.setImage(DBeaverIcons.getImage(UIIcon.DRAG_HANDLE));
new ToolItem(toolBar, SWT.SEPARATOR).setControl(label);
}
public static TableColumn createTableColumn(Table table, int style, String text)
{
TableColumn column = new TableColumn(table, style);
column.setText(text);
return column;
}
public static TreeColumn createTreeColumn(Tree tree, int style, String text)
{
TreeColumn column = new TreeColumn(tree, style);
column.setText(text);
return column;
}
public static void packColumns(Table table)
{
packColumns(table, false);
}
public static void packColumns(Table table, boolean fit)
{
table.setRedraw(false);
try {
int totalWidth = 0;
final TableColumn[] columns = table.getColumns();
for (TableColumn column : columns) {
column.pack();
totalWidth += column.getWidth();
}
final Rectangle clientArea = table.getBounds();
if (clientArea.width > 0 && totalWidth > clientArea.width) {
for (TableColumn column : columns) {
int colWidth = column.getWidth();
if (colWidth > totalWidth / 3) {
// If some columns are too big (more than 33% of total width)
// Then shrink them to 30%
column.setWidth(totalWidth / 3);
totalWidth -= colWidth;
totalWidth += column.getWidth();
}
}
int extraSpace = totalWidth - clientArea.width;
GC gc = new GC(table);
try {
for (TableColumn tc : columns) {
double ratio = (double) tc.getWidth() / totalWidth;
int newWidth = (int) (tc.getWidth() - extraSpace * ratio);
int minWidth = gc.stringExtent(tc.getText()).x;
minWidth += 5;
if (newWidth < minWidth) {
newWidth = minWidth;
}
tc.setWidth(newWidth);
}
}
finally {
gc.dispose();
}
}
if (fit && totalWidth < clientArea.width) {
int sbWidth = 0;
if (table.getVerticalBar() != null) {
sbWidth = table.getVerticalBar().getSize().x;
}
if (columns.length > 0) {
float extraSpace = (clientArea.width - totalWidth - sbWidth) / columns.length;
for (TableColumn tc : columns) {
tc.setWidth((int) (tc.getWidth() + extraSpace));
}
}
}
} finally {
table.setRedraw(true);
}
}
public static void packColumns(@NotNull Tree tree)
{
packColumns(tree, false, null);
}
public static void packColumns(@NotNull Tree tree, boolean fit, @Nullable float[] ratios)
{
tree.setRedraw(false);
try {
// Check for disposed items
// TODO: it looks like SWT error. Sometimes tree items are disposed and NPE is thrown from column.pack
for (TreeItem item : tree.getItems()) {
if (item.isDisposed()) {
return;
}
}
Rectangle clientArea = tree.getClientArea();
if (clientArea.isEmpty()) {
return;
}
int totalWidth = 0;
final TreeColumn[] columns = tree.getColumns();
for (TreeColumn column : columns) {
column.pack();
totalWidth += column.getWidth();
}
if (fit) {
int areaWidth = clientArea.width;
// if (tree.getVerticalBar() != null) {
// areaWidth -= tree.getVerticalBar().getSize().x;
// }
if (totalWidth > areaWidth) {
GC gc = new GC(tree);
try {
int extraSpace = totalWidth - areaWidth;
for (TreeColumn tc : columns) {
double ratio = (double) tc.getWidth() / totalWidth;
int newWidth = (int) (tc.getWidth() - extraSpace * ratio);
int minWidth = gc.stringExtent(tc.getText()).x;
minWidth += 5;
if (newWidth < minWidth) {
newWidth = minWidth;
}
tc.setWidth((int) newWidth);
}
} finally {
gc.dispose();
}
} else if (totalWidth < areaWidth) {
float extraSpace = areaWidth - totalWidth;
if (columns.length > 0) {
if (ratios == null || ratios.length < columns.length) {
extraSpace /= columns.length;
extraSpace--;
for (TreeColumn tc : columns) {
tc.setWidth((int) (tc.getWidth() + extraSpace));
}
} else {
for (int i = 0; i < columns.length; i++) {
TreeColumn tc = columns[i];
tc.setWidth((int) (tc.getWidth() + extraSpace * ratios[i]));
}
}
}
}
}
} finally {
tree.setRedraw(true);
}
}
public static void maxTableColumnsWidth(Table table)
{
table.setRedraw(false);
try {
int columnCount = table.getColumnCount();
if (columnCount > 0) {
int totalWidth = 0;
final TableColumn[] columns = table.getColumns();
for (TableColumn tc : columns) {
tc.pack();
totalWidth += tc.getWidth();
}
final Rectangle clientArea = table.getClientArea();
if (totalWidth < clientArea.width) {
int extraSpace = clientArea.width - totalWidth;
extraSpace /= columnCount;
for (TableColumn tc : columns) {
tc.setWidth(tc.getWidth() + extraSpace);
}
}
}
} finally {
table.setRedraw(true);
}
}
public static int getColumnAtPos(TableItem item, int x, int y)
{
int columnCount = item.getParent().getColumnCount();
for (int i = 0; i < columnCount; i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(x, y)) {
return i;
}
}
return -1;
}
public static int getColumnAtPos(TreeItem item, int x, int y)
{
int columnCount = item.getParent().getColumnCount();
for (int i = 0; i < columnCount; i++) {
Rectangle rect = item.getBounds(i);
if (rect.contains(x, y)) {
return i;
}
}
return -1;
}
public static void sortTable(Table table, Comparator<TableItem> comparator)
{
int columnCount = table.getColumnCount();
String[] values = new String[columnCount];
TableItem[] items = table.getItems();
for (int i = 1; i < items.length; i++) {
for (int j = 0; j < i; j++) {
TableItem item = items[i];
if (comparator.compare(item, items[j]) < 0) {
for (int k = 0; k < columnCount; k++) {
values[k] = item.getText(k);
}
Object data = item.getData();
boolean checked = item.getChecked();
item.dispose();
item = new TableItem(table, SWT.NONE, j);
item.setText(values);
item.setData(data);
item.setChecked(checked);
items = table.getItems();
break;
}
}
}
}
public static TableItem getNextTableItem(Table table, TableItem item) {
TableItem[] items = table.getItems();
for (int i = 0; i < items.length - 1; i++) {
if (items[i] == item) {
return items[i + 1];
}
}
return null;
}
public static TreeItem getNextTreeItem(Tree tree, TreeItem item) {
TreeItem[] items = tree.getItems();
for (int i = 0; i < items.length - 1; i++) {
if (items[i] == item) {
return items[i + 1];
}
}
return null;
}
public static void dispose(Widget widget)
{
if (widget != null && !widget.isDisposed()) {
try {
widget.dispose();
} catch (Exception e) {
log.debug("widget dispose error", e);
}
}
}
public static void dispose(Resource resource)
{
if (resource != null && !resource.isDisposed()) {
try {
resource.dispose();
} catch (Exception e) {
log.debug("Resource dispose error", e);
}
}
}
public static void showMessageBox(final Shell shell, final String title, final String info, final int messageType)
{
Runnable runnable = new Runnable() {
@Override
public void run()
{
Shell activeShell = shell != null ? shell : DBeaverUI.getActiveWorkbenchShell();
MessageBox messageBox = new MessageBox(activeShell, messageType | SWT.OK);
messageBox.setMessage(info);
messageBox.setText(title);
messageBox.open();
}
};
DBeaverUI.syncExec(runnable);
}
public static boolean confirmAction(final String title, final String question)
{
return confirmAction(null, title, question);
}
public static boolean confirmAction(final Shell shell, final String title, final String question)
{
return new UIConfirmation() {
@Override
public Boolean runTask() {
Shell activeShell = shell != null ? shell : DBeaverUI.getActiveWorkbenchShell();
MessageBox messageBox = new MessageBox(activeShell, SWT.ICON_QUESTION | SWT.YES | SWT.NO);
messageBox.setMessage(question);
messageBox.setText(title);
int response = messageBox.open();
return (response == SWT.YES);
}
}.confirm();
}
public static int getFontHeight(Control control) {
return getFontHeight(control.getFont());
}
public static int getFontHeight(Font font) {
FontData[] fontData = font.getFontData();
if (fontData.length == 0) {
return 20;
}
return fontData[0].getHeight();
}
public static Font makeBoldFont(Font normalFont)
{
return modifyFont(normalFont, SWT.BOLD);
}
public static Font modifyFont(Font normalFont, int style)
{
FontData[] fontData = normalFont.getFontData();
fontData[0].setStyle(fontData[0].getStyle() | style);
return new Font(normalFont.getDevice(), fontData[0]);
}
public static Group createControlGroup(Composite parent, String label, int columns, int layoutStyle, int widthHint)
{
Group group = new Group(parent, SWT.NONE);
group.setText(label);
GridData gd = new GridData(layoutStyle);
if (widthHint > 0) {
gd.widthHint = widthHint;
}
group.setLayoutData(gd);
GridLayout gl = new GridLayout(columns, false);
group.setLayout(gl);
return group;
}
public static Label createControlLabel(Composite parent, String label)
{
Label textLabel = new Label(parent, SWT.NONE);
textLabel.setText(label + ": "); //$NON-NLS-1$
textLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_CENTER));
return textLabel;
}
public static Label createLabel(Composite parent, String label)
{
Label textLabel = new Label(parent, SWT.NONE);
textLabel.setText(label);
return textLabel;
}
public static Label createLabel(Composite parent, @NotNull DBPImage image)
{
Label imageLabel = new Label(parent, SWT.NONE);
imageLabel.setImage(DBeaverIcons.getImage(image));
return imageLabel;
}
public static CLabel createInfoLabel(Composite parent, String text) {
CLabel tipLabel = new CLabel(parent, SWT.NONE);
tipLabel.setImage(JFaceResources.getImage(org.eclipse.jface.dialogs.Dialog.DLG_IMG_MESSAGE_INFO));
tipLabel.setText(text);
return tipLabel;
}
public static Text createLabelText(Composite parent, String label, String value)
{
return createLabelText(parent, label, value, SWT.BORDER);
}
public static Text createLabelText(Composite parent, String label, String value, int style)
{
return createLabelText(parent, label, value, style, new GridData(GridData.FILL_HORIZONTAL));
}
@NotNull
public static Text createLabelText(@NotNull Composite parent, @NotNull String label, @Nullable String value, int style,
@Nullable Object layoutData)
{
createControlLabel(parent, label);
Text text = new Text(parent, style);
fixReadonlyTextBackground(text);
if (value != null) {
text.setText(value);
}
if (layoutData != null) {
text.setLayoutData(layoutData);
}
return text;
}
@NotNull
public static Spinner createLabelSpinner(@NotNull Composite parent, @NotNull String label, @Nullable String tooltip, int value, int minimum, int maximum) {
final Label l = createControlLabel(parent, label);
if (tooltip != null) {
l.setToolTipText(tooltip);
}
return createSpinner(parent, tooltip, value, minimum, maximum);
}
@NotNull
public static Spinner createSpinner(Composite parent, String tooltip, int value, int minimum, int maximum) {
Spinner spinner = new Spinner(parent, SWT.BORDER);
spinner.setMinimum(minimum);
spinner.setMaximum(maximum);
spinner.setSelection(value);
if (tooltip != null) {
spinner.setToolTipText(tooltip);
}
return spinner;
}
@NotNull
public static Spinner createLabelSpinner(@NotNull Composite parent, @NotNull String label, int value, int minimum, int maximum)
{
return createLabelSpinner(parent, label, null, value, minimum, maximum);
}
@NotNull
public static Button createLabelCheckbox(Composite parent, String label, boolean checked)
{
return createLabelCheckbox(parent, label, null, checked, SWT.NONE);
}
@NotNull
public static Button createLabelCheckbox(Composite parent, String label, String tooltip, boolean checked)
{
return createLabelCheckbox(parent, label, tooltip, checked, SWT.NONE);
}
@NotNull
public static Button createLabelCheckbox(@NotNull Composite parent, @NotNull String label, @Nullable String tooltip,
boolean checked, int style)
{
Label labelControl = createControlLabel(parent, label);
// labelControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
final Button button = new Button(parent, SWT.CHECK | style);
if (checked) {
button.setSelection(true);
}
labelControl.addMouseListener(new MouseAdapter() {
@Override
public void mouseUp(MouseEvent e)
{
if (!button.isDisposed() && button.isVisible() && button.isEnabled()) {
button.setSelection(!button.getSelection());
button.notifyListeners(SWT.Selection, new Event());
}
}
});
if (tooltip != null) {
labelControl.setToolTipText(tooltip);
button.setToolTipText(tooltip);
}
return button;
}
public static Button createCheckbox(Composite parent, String label, String tooltip, boolean checked, int hSpan) {
Button checkbox = createCheckbox(parent, label, checked);
if (tooltip != null) {
checkbox.setToolTipText(tooltip);
}
if (hSpan > 1) {
GridData gd = new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING);
gd.horizontalSpan = hSpan;
checkbox.setLayoutData(gd);
}
return checkbox;
}
public static Button createCheckbox(Composite parent, String label, boolean checked)
{
final Button button = new Button(parent, SWT.CHECK);
button.setText(label);
if (checked) {
button.setSelection(true);
}
return button;
}
public static Combo createLabelCombo(Composite parent, String label, int style)
{
return createLabelCombo(parent, label, null, style);
}
public static Combo createLabelCombo(Composite parent, String label, String tooltip, int style)
{
Label labelControl = createControlLabel(parent, label);
if (tooltip != null) {
labelControl.setToolTipText(tooltip);
}
final Combo combo = new Combo(parent, style);
combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (tooltip != null) {
combo.setToolTipText(tooltip);
}
return combo;
}
public static Button createToolButton(Composite parent, String text, SelectionListener selectionListener)
{
Button button = new Button(parent, SWT.PUSH);
button.setText(text);
button.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
if (selectionListener != null) {
button.addSelectionListener(selectionListener);
}
return button;
}
public static void updateContributionItems(IContributionManager manager) {
for (IContributionItem item : manager.getItems()) {
item.update();
}
}
@Nullable
public static Shell getActiveShell()
{
IWorkbench workbench = PlatformUI.getWorkbench();
return workbench == null ? null : getShell(workbench.getActiveWorkbenchWindow());
}
@Nullable
public static Shell getShell(IShellProvider provider)
{
return provider == null ? null : provider.getShell();
}
@Nullable
public static Shell getShell(IWorkbenchPart part)
{
return part == null ? null : getShell(part.getSite());
}
@Nullable
public static Integer getTextInteger(Text text)
{
String str = text.getText();
str = str.trim();
if (str.length() == 0) {
return null;
}
try {
return Integer.valueOf(str);
} catch (NumberFormatException e) {
log.debug(e);
return null;
}
}
@Nullable
public static IHandlerActivation registerKeyBinding(IServiceLocator serviceLocator, IAction action)
{
IHandlerService handlerService = serviceLocator.getService(IHandlerService.class);
if (handlerService != null) {
return handlerService.activateHandler(action.getActionDefinitionId(), new ActionHandler(action));
} else {
return null;
}
}
public static Composite createPlaceholder(Composite parent, int columns)
{
return createPlaceholder(parent, columns, 0);
}
public static Composite createPlaceholder(Composite parent, int columns, int spacing)
{
Composite ph = new Composite(parent, SWT.NONE);
GridLayout gl = new GridLayout(columns, false);
gl.verticalSpacing = spacing;
gl.horizontalSpacing = spacing;
gl.marginHeight = 0;
gl.marginWidth = 0;
ph.setLayout(gl);
return ph;
}
public static void setGridSpan(Control control, int horizontalSpan, int verticalSpan) {
GridData gd;
final Object layoutData = control.getLayoutData();
if (layoutData == null) {
if (control.getParent().getLayout() instanceof GridLayout) {
gd = new GridData();
control.setLayoutData(gd);
} else {
log.debug("Can't set grid span for layout: " + control.getParent().getLayout());
return;
}
} else if (layoutData instanceof GridData) {
gd = (GridData) layoutData;
} else {
log.debug("Can't set grid span for non-grid layout: " + layoutData.getClass().getName());
return;
}
gd.horizontalSpan = horizontalSpan;
gd.verticalSpan = verticalSpan;
}
public static Label createHorizontalLine(Composite parent)
{
Label horizontalLine = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
horizontalLine.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, false, 1, 1));
return horizontalLine;
}
@Nullable
public static String getComboSelection(Combo combo)
{
int selectionIndex = combo.getSelectionIndex();
if (selectionIndex < 0) {
return null;
}
return combo.getItem(selectionIndex);
}
public static boolean setComboSelection(Combo combo, String value)
{
if (value == null) {
return false;
}
int count = combo.getItemCount();
for (int i = 0; i < count; i++) {
if (value.equals(combo.getItem(i))) {
combo.select(i);
return true;
}
}
return false;
}
// public static Combo createEncodingCombo(Composite parent, String curCharset)
// {
//
// }
public static Combo createEncodingCombo(Composite parent, @Nullable String curCharset)
{
Combo encodingCombo = new Combo(parent, SWT.DROP_DOWN);
encodingCombo.setVisibleItemCount(30);
SortedMap<String, Charset> charsetMap = Charset.availableCharsets();
int index = 0;
int defIndex = -1;
for (String csName : charsetMap.keySet()) {
Charset charset = charsetMap.get(csName);
encodingCombo.add(charset.displayName());
if (curCharset != null) {
if (charset.displayName().equalsIgnoreCase(curCharset)) {
defIndex = index;
}
if (defIndex < 0) {
for (String alias : charset.aliases()) {
if (alias.equalsIgnoreCase(curCharset)) {
defIndex = index;
}
}
}
}
index++;
}
if (defIndex >= 0) {
encodingCombo.select(defIndex);
} else if (curCharset != null) {
log.warn("Charset '" + curCharset + "' is not recognized"); //$NON-NLS-1$ //$NON-NLS-2$
}
return encodingCombo;
}
@NotNull
public static SashForm createPartDivider(final IWorkbenchPart workbenchPart, Composite parent, int style)
{
final CustomSashForm sash = new CustomSashForm(parent, style);
return sash;
}
public static void showErrorDialog(@Nullable Shell shell, @NotNull String title, @Nullable String message, @Nullable Throwable error)
{
if (error != null) {
log.error(error);
}
showErrorDialog(shell, title, error == null ? null : message, error == null ? new Status(IStatus.ERROR,
DBeaverCore.PLUGIN_ID, message) : GeneralUtils.makeExceptionStatus(error));
}
public static void showErrorDialog(@Nullable Shell shell, @NotNull String title, @Nullable String message)
{
showErrorDialog(shell, title, message, (Throwable) null);
}
public static void showErrorDialog(@Nullable final Shell shell, @NotNull final String title, @Nullable final String message, @NotNull final IStatus status)
{
for (IStatus s = status; s != null; ) {
if (s.getException() instanceof DBException) {
if (showDatabaseError(shell, message, (DBException) s.getException())) {
// If this DB error was handled by some DB-specific way then just don't care about it
return;
}
break;
}
if (s.getChildren() != null && s.getChildren().length > 0) {
s = s.getChildren()[0];
} else {
break;
}
}
// log.debug(message);
Runnable runnable = new Runnable() {
@Override
public void run()
{
// Display the dialog
StandardErrorDialog dialog = new StandardErrorDialog(shell == null ? DBeaverUI.getActiveWorkbenchShell() : shell,
title, message, RuntimeUtils.stripStack(status), IStatus.ERROR);
dialog.open();
}
};
DBeaverUI.syncExec(runnable);
}
@NotNull
public static String formatMessage(@Nullable String message, @Nullable Object... args)
{
if (message == null) {
return ""; //$NON-NLS-1$
} else {
return MessageFormat.format(message, args);
}
}
@NotNull
public static Button createPushButton(@NotNull Composite parent, @Nullable String label, @Nullable Image image)
{
Button button = new Button(parent, SWT.PUSH);
if (label != null) {
button.setText(label);
}
if (image != null) {
button.setImage(image);
}
return button;
}
public static void setHelp(Control control, String pluginId, String helpContextID)
{
PlatformUI.getWorkbench().getHelpSystem().setHelp(control, pluginId + "." + helpContextID); //$NON-NLS-1$
}
public static void setHelp(Control control, String helpContextID)
{
setHelp(control, DBeaverCore.PLUGIN_ID, helpContextID);
}
public static String makeAnchor(String text)
{
return "<a>" + text + "</a>"; //$NON-NLS-1$ //$NON-NLS-2$
}
@Nullable
public static <T> T findView(IWorkbenchWindow workbenchWindow, Class<T> viewClass)
{
IViewReference[] references = workbenchWindow.getActivePage().getViewReferences();
for (IViewReference ref : references) {
IViewPart view = ref.getView(false);
if (view != null && viewClass.isAssignableFrom(view.getClass())) {
return viewClass.cast(view);
}
}
return null;
}
@Nullable
public static IViewPart findView(IWorkbenchWindow workbenchWindow, String viewId)
{
IViewReference[] references = workbenchWindow.getActivePage().getViewReferences();
for (IViewReference ref : references) {
if (ref.getId().equals(viewId)) {
return ref.getView(false);
}
}
return null;
}
public static void setClipboardContents(Display display, Transfer transfer, Object contents)
{
Clipboard clipboard = new Clipboard(display);
clipboard.setContents(new Object[] { contents }, new Transfer[] { transfer });
clipboard.dispose();
}
public static void updateMainWindowTitle(IWorkbenchWindow window)
{
if (window == null) {
return;
}
Shell shell = window.getShell();
if (shell == null) {
return;
}
IProject activeProject = DBeaverCore.getInstance().getProjectRegistry().getActiveProject();
IProduct product = Platform.getProduct();
String title = product == null ? "Unknown" : product.getName(); //$NON-NLS-1$
if (activeProject != null) {
title += " - " + activeProject.getName(); //$NON-NLS-1$
}
IWorkbenchPage activePage = window.getActivePage();
if (activePage != null) {
IEditorPart activeEditor = activePage.getActiveEditor();
if (activeEditor != null) {
title += " - [ " + activeEditor.getTitle() + " ]";
}
}
shell.setText(title);
}
public static void showPreferencesFor(Shell shell, Object element, String ... defPageID)
{
PreferenceDialog propDialog;
if (element == null) {
propDialog = PreferencesUtil.createPreferenceDialogOn(shell, defPageID[0], defPageID, null, PreferencesUtil.OPTION_NONE);
} else {
propDialog = PreferencesUtil.createPropertyDialogOn(shell, element, defPageID[0], null, null, PreferencesUtil.OPTION_NONE);
}
if (propDialog != null) {
propDialog.open();
}
}
public static void addFocusTracker(IServiceLocator serviceLocator, String controlID, Control control)
{
final IFocusService focusService = serviceLocator.getService(IFocusService.class);
if (focusService != null) {
focusService.addFocusTracker(control, controlID);
} else {
log.debug("Focus service not found in " + serviceLocator);
}
}
public static void removeFocusTracker(IServiceLocator serviceLocator, Control control)
{
if (PlatformUI.getWorkbench().isClosing()) {
// TODO: it is a bug in eclipse. During workbench shutdown disposed service returned.
return;
}
final IFocusService focusService = serviceLocator.getService(IFocusService.class);
if (focusService != null) {
focusService.removeFocusTracker(control);
} else {
log.debug("Focus service not found in " + serviceLocator);
}
}
@NotNull
public static IDialogSettings getDialogSettings(@NotNull String dialogId)
{
IDialogSettings workbenchSettings = DBeaverActivator.getInstance().getDialogSettings();
return getSettingsSection(workbenchSettings, dialogId);
}
@NotNull
public static IDialogSettings getSettingsSection(@NotNull IDialogSettings parent, @NotNull String sectionId)
{
IDialogSettings section = parent.getSection(sectionId);
if (section == null) {
section = parent.addNewSection(sectionId);
}
return section;
}
@Nullable
public static IWorkbenchPartSite getWorkbenchPartSite(IServiceLocator serviceLocator)
{
IWorkbenchPartSite partSite = serviceLocator.getService(IWorkbenchPartSite.class);
if (partSite == null) {
IWorkbenchPart activePart = serviceLocator.getService(IWorkbenchPart.class);
if (activePart == null) {
IWorkbenchWindow workbenchWindow = DBeaverUI.getActiveWorkbenchWindow();
if (workbenchWindow != null) {
IWorkbenchPage activePage = workbenchWindow.getActivePage();
if (activePage != null) {
activePart = activePage.getActivePart();
}
}
}
if (activePart != null) {
partSite = activePart.getSite();
}
}
return partSite;
}
public static boolean isContextActive(String contextId)
{
Collection<?> contextIds = DBeaverUI.getActiveWorkbenchWindow().getService(IContextService.class).getActiveContextIds();
for (Object id : contextIds) {
if (contextId.equals(id)) {
return true;
}
}
return false;
}
@Nullable
public static ISelectionProvider getSelectionProvider(IServiceLocator serviceLocator)
{
ISelectionProvider selectionProvider = serviceLocator.getService(ISelectionProvider.class);
if (selectionProvider != null) {
return selectionProvider;
}
IWorkbenchPartSite partSite = getWorkbenchPartSite(serviceLocator);
if (partSite == null) {
IWorkbenchPart activePart = serviceLocator.getService(IWorkbenchPart.class);
if (activePart == null) {
IWorkbenchWindow activeWindow = DBeaverUI.getActiveWorkbenchWindow();
if (activeWindow != null) {
activePart = activeWindow.getActivePage().getActivePart();
}
}
if (activePart != null) {
partSite = activePart.getSite();
}
}
if (partSite != null) {
return partSite.getSelectionProvider();
} else {
return null;
}
}
public static void enableWithChildren(Control control, boolean enable)
{
control.setEnabled(enable);
if (control instanceof Composite) {
for (Control child : ((Composite)control).getChildren()) {
if (child instanceof Composite) {
enableWithChildren(child, enable);
} else {
child.setEnabled(enable);
}
}
}
}
/**
* Determine whether this control or any of it's child has focus
*
* @param control
* control to check
* @return true if it has focus
*/
public static boolean hasFocus(Control control)
{
Control focusControl = control.getDisplay().getFocusControl();
if (focusControl == null) {
return false;
}
for (Control fc = focusControl; fc != null; fc = fc.getParent()) {
if (fc == control) {
return true;
}
}
return false;
}
/**
* Eclipse hack. Disables/enabled all key bindings in specified site's part. Works only if host editor is extender of
* AbstractTextEditor Uses reflection because setActionActivation is private method
* TODO: find better way to disable key bindings or prioritize event handling to widgets
*
* @param partSite workbench part site
* @param enable enable or disable
*/
@Deprecated
public static void enableHostEditorKeyBindings(IWorkbenchPartSite partSite, boolean enable)
{
IWorkbenchPart part = partSite.getPart();
if (part instanceof AbstractTextEditor) {
AbstractTextEditor hostEditor = (AbstractTextEditor) part;
if (hostEditor instanceof BaseTextEditor) {
StyledText textWidget = ((BaseTextEditor) hostEditor).getTextViewer().getTextWidget();
if (textWidget == null || textWidget.isDisposed()) {
return;
}
}
try {
Method activatorMethod = AbstractTextEditor.class.getDeclaredMethod("setActionActivation", Boolean.TYPE);
activatorMethod.setAccessible(true);
activatorMethod.invoke(hostEditor, enable);
} catch (Throwable e) {
if (e instanceof InvocationTargetException) {
e = ((InvocationTargetException) e).getTargetException();
}
log.warn("Can't disable text editor action activations", e);
}
//hostEditor.getEditorSite().getActionBarContributor().setActiveEditor(hostEditor);
}
}
public static void enableHostEditorKeyBindingsSupport(final IWorkbenchPartSite partSite, Control control)
{
if (!(partSite.getPart() instanceof AbstractTextEditor)) {
return;
}
final boolean[] activated = new boolean[] {false};
control.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
if (!activated[0]) {
UIUtils.enableHostEditorKeyBindings(partSite, false);
activated[0] = true;
}
}
@Override
public void focusLost(FocusEvent e) {
if (activated[0]) {
UIUtils.enableHostEditorKeyBindings(partSite, true);
activated[0] = false;
}
}
});
control.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
if (activated[0]) {
UIUtils.enableHostEditorKeyBindings(partSite, true);
activated[0] = false;
}
}
});
}
public static CTabItem getTabItem(CTabFolder tabFolder, Object data)
{
for (CTabItem item : tabFolder.getItems()) {
if (item.getData() == data) {
return item;
}
}
return null;
}
public static void disposeControlOnItemDispose(final CTabItem tabItem) {
tabItem.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
final Control control = tabItem.getControl();
if (!control.isDisposed()) {
control.dispose();
}
}
});
}
public static TreeItem getTreeItem(Tree tree, Object data)
{
for (TreeItem item : tree.getItems()) {
if (item.getData() == data) {
return item;
}
}
return null;
}
public static int blend(int v1, int v2, int ratio)
{
return (ratio * v1 + (100 - ratio) * v2) / 100;
}
public static RGB blend(RGB c1, RGB c2, int ratio)
{
int r = blend(c1.red, c2.red, ratio);
int g = blend(c1.green, c2.green, ratio);
int b = blend(c1.blue, c2.blue, ratio);
return new RGB(r, g, b);
}
public static boolean isParent(Control parent, Control child) {
for (Control c = child; c != null; c = c.getParent()) {
if (c == parent) {
return true;
}
}
return false;
}
public static boolean isInDialog(Control control) {
return control.getShell().getData() instanceof org.eclipse.jface.dialogs.Dialog;
}
public static Link createLink(Composite parent, String text, SelectionListener listener) {
Link link = new Link(parent, SWT.NONE);
link.setText(text);
link.addSelectionListener(listener);
return link;
}
public static CellEditor createPropertyEditor(final IServiceLocator serviceLocator, Composite parent, DBPPropertySource source, DBPPropertyDescriptor property)
{
if (source == null) {
return null;
}
final Object object = source.getEditableValue();
if (!property.isEditable(object)) {
return null;
}
CellEditor cellEditor = UIUtils.createCellEditor(parent, object, property);
if (cellEditor != null) {
final Control editorControl = cellEditor.getControl();
UIUtils.addFocusTracker(serviceLocator, UIUtils.INLINE_WIDGET_EDITOR_ID, editorControl);
editorControl.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
UIUtils.removeFocusTracker(serviceLocator, editorControl);
}
});
}
return cellEditor;
}
public static CellEditor createCellEditor(Composite parent, Object object, DBPPropertyDescriptor property)
{
// List
if (property instanceof IPropertyValueListProvider) {
final IPropertyValueListProvider listProvider = (IPropertyValueListProvider) property;
final Object[] items = listProvider.getPossibleValues(object);
if (items != null) {
final String[] strings = new String[items.length];
for (int i = 0, itemsLength = items.length; i < itemsLength; i++) {
strings[i] = items[i] instanceof DBPNamedObject ? ((DBPNamedObject)items[i]).getName() : CommonUtils.toString(items[i]);
}
final CustomComboBoxCellEditor editor = new CustomComboBoxCellEditor(
parent,
strings,
SWT.DROP_DOWN | (listProvider.allowCustomValue() ? SWT.NONE : SWT.READ_ONLY));
return editor;
}
}
Class<?> propertyType = property.getDataType();
if (propertyType == null || CharSequence.class.isAssignableFrom(propertyType)) {
return new CustomTextCellEditor(parent);
} else if (BeanUtils.isNumericType(propertyType)) {
return new CustomNumberCellEditor(parent, propertyType);
} else if (BeanUtils.isBooleanType(propertyType)) {
return new CustomCheckboxCellEditor(parent);
//return new CheckboxCellEditor(parent);
} else if (propertyType.isEnum()) {
final Object[] enumConstants = propertyType.getEnumConstants();
final String[] strings = new String[enumConstants.length];
for (int i = 0, itemsLength = enumConstants.length; i < itemsLength; i++) {
strings[i] = ((Enum)enumConstants[i]).name();
}
return new CustomComboBoxCellEditor(
parent,
strings,
SWT.DROP_DOWN | SWT.READ_ONLY);
} else {
log.warn("Unsupported property type: " + propertyType.getName());
return null;
}
}
public static boolean showDatabaseError(Shell shell, String message, DBException error)
{
DBPDataSource dataSource = error.getDataSource();
DBPErrorAssistant.ErrorType errorType = dataSource == null ? DBPErrorAssistant.ErrorType.NORMAL : DBUtils.discoverErrorType(dataSource, error);
switch (errorType) {
case CONNECTION_LOST:
DataSourceInvalidateHandler.showConnectionLostDialog(shell, message, error);
return true;
case DRIVER_CLASS_MISSING:
DriverEditDialog.showBadConfigDialog(shell, message, error);
return true;
}
return false;
}
public static void postEvent(Control ownerControl, final Event event) {
final Display display = ownerControl.getDisplay();
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
display.post(event);
}
});
}
public static void drawMessageOverControl(Control control, PaintEvent e, String message, int offset) {
Rectangle bounds = control.getBounds();
Point ext = e.gc.textExtent(message);
e.gc.drawText(message, (bounds.width - ext.x) / 2, bounds.height / 3 + offset);
}
public static void launchProgram(String path)
{
Program.launch(path);
}
public static void fillDefaultStyledTextContextMenu(final StyledText text) {
MenuManager menuMgr = new MenuManager();
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager)
{
UIUtils.fillDefaultStyledTextContextMenu(manager, text);
}
});
menuMgr.setRemoveAllWhenShown(true);
text.setMenu(menuMgr.createContextMenu(text));
}
public static void fillDefaultStyledTextContextMenu(IMenuManager menu, final StyledText text) {
final Point selectionRange = text.getSelectionRange();
menu.add(new StyledTextAction(IWorkbenchCommandConstants.EDIT_COPY, selectionRange.y > 0, text, ST.COPY));
menu.add(new StyledTextAction(IWorkbenchCommandConstants.EDIT_PASTE, text.getEditable(), text, ST.PASTE));
menu.add(new StyledTextAction(IWorkbenchCommandConstants.EDIT_CUT, selectionRange.y > 0, text, ST.CUT));
menu.add(new StyledTextAction(IWorkbenchCommandConstants.EDIT_SELECT_ALL, true, text, ST.SELECT_ALL));
menu.add(new GroupMarker("styled_text_additions"));
}
public static void fillDefaultTableContextMenu(IMenuManager menu, final Table table) {
menu.add(new Action(CoreMessages.controls_itemlist_action_copy) {
@Override
public void run() {
StringBuilder text = new StringBuilder();
for (TableItem item : table.getSelection()) {
if (text.length() > 0) text.append("\n");
text.append(item.getText());
}
UIUtils.setClipboardContents(table.getDisplay(), TextTransfer.getInstance(), text.toString());
}
});
}
public static void addFileOpenOverlay(Text text, SelectionListener listener) {
final Image browseImage = DBeaverIcons.getImage(DBIcon.TREE_FOLDER);
final Rectangle iconBounds = browseImage.getBounds();
text.addPaintListener(new PaintListener() {
@Override
public void paintControl(PaintEvent e) {
final Rectangle bounds = ((Text) e.widget).getBounds();
e.gc.drawImage(browseImage, bounds.width - iconBounds.width - 2, 0);
}
});
}
private static class StyledTextAction extends Action {
private final StyledText styledText;
private final int action;
public StyledTextAction(String actionId, boolean enabled, StyledText styledText, int action) {
super(ActionUtils.findCommandName(actionId));
this.setActionDefinitionId(actionId);
this.setEnabled(enabled);
this.styledText = styledText;
this.action = action;
}
@Override
public void run() {
styledText.invokeAction(action);
}
}
@Nullable
public static Color getSharedColor(@Nullable String rgbString) {
if (CommonUtils.isEmpty(rgbString)) {
return null;
}
return DBeaverUI.getSharedTextColors().getColor(rgbString);
}
public static Color getConnectionColor(DBPConnectionConfiguration connectionInfo) {
String rgbString = connectionInfo.getConnectionColor();
if (CommonUtils.isEmpty(rgbString)) {
rgbString = connectionInfo.getConnectionType().getColor();
}
if (CommonUtils.isEmpty(rgbString)) {
return null;
}
Color connectionColor = DBeaverUI.getSharedTextColors().getColor(rgbString);
if (connectionColor.getBlue() == 255 && connectionColor.getRed() == 255 && connectionColor.getGreen() == 255) {
// For white color return just null to avoid explicit color set.
// It is important for dark themes
return null;
}
return connectionColor;
}
public static Color getConnectionTypeColor(DBPConnectionType connectionType) {
String rgbString = connectionType.getColor();
if (CommonUtils.isEmpty(rgbString)) {
return null;
}
return DBeaverUI.getSharedTextColors().getColor(StringConverter.asRGB(rgbString));
}
public static Shell createCenteredShell(Shell parent) {
final Rectangle bounds = parent.getBounds();
final int x = bounds.x + bounds.width / 2 - 120;
final int y = bounds.y + bounds.height / 2 - 170;
final Shell shell = new Shell( parent );
shell.setBounds( x, y, 0, 0 );
return shell;
}
public static Image getShardImage(String id) {
return PlatformUI.getWorkbench().getSharedImages().getImage(id);
}
public static ImageDescriptor getShardImageDescriptor(String id) {
return PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(id);
}
public static void installContentProposal(Control control, IControlContentAdapter contentAdapter, IContentProposalProvider provider) {
installContentProposal(control, contentAdapter, provider, false);
}
public static void installContentProposal(Control control, IControlContentAdapter contentAdapter, IContentProposalProvider provider, boolean autoActivation) {
try {
KeyStroke keyStroke = autoActivation ? null : KeyStroke.getInstance("Ctrl+Space");
final ContentProposalAdapter proposalAdapter = new ContentProposalAdapter(
control,
contentAdapter,
provider,
keyStroke,
autoActivation ? ".abcdefghijklmnopqrstuvwxyz_$(".toCharArray() : ".(".toCharArray());
proposalAdapter.setPopupSize(new Point(300, 200));
} catch (ParseException e) {
log.error("Error installing filters content assistant");
}
}
public static void setContentProposalToolTip(Control control, String toolTip, String ... variables) {
StringBuilder varsTip = new StringBuilder();
for (String var : variables) {
if (varsTip.length() > 0) varsTip.append(", ");
varsTip.append(GeneralUtils.variablePattern(var));
}
varsTip.append(".");
control.setToolTipText(toolTip + ".\nAllowed variables: " + varsTip);
}
public static CoolItem createCoolItem(CoolBar coolBar, Control control) {
CoolItem item = new CoolItem(coolBar, SWT.NONE);
item.setControl(control);
Point size = control.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Point preferred = item.computeSize(size.x, size.y);
item.setPreferredSize(preferred);
return item;
}
public static void resizeShell(Shell shell) {
Point shellSize = shell.getSize();
Point compSize = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT);
compSize.y += 20;
if (shellSize.y < compSize.y) {
shell.setSize(compSize);
shell.layout(true);
}
}
public static void waitJobCompletion(AbstractJob job) {
// Wait until job finished
Display display = Display.getCurrent();
while (!job.isFinished()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.update();
}
public static void fixReadonlyTextBackground(Text textField) {
if ((textField.getStyle() & SWT.READ_ONLY) == SWT.READ_ONLY) {
// Do nothing because in E4.6 there is no good solution: https://bugs.eclipse.org/bugs/show_bug.cgi?id=340889
//textField.setBackground(textField.getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
} else {
textField.setBackground(null);
}
}
}