/*
* 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.controls.resultset;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.jface.action.*;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.text.IFindReplaceTarget;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.*;
import org.eclipse.ui.*;
import org.eclipse.ui.actions.CompoundContributionItem;
import org.eclipse.ui.menus.CommandContributionItem;
import org.eclipse.ui.menus.CommandContributionItemParameter;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.DBeaverPreferences;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.CoreCommands;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.data.*;
import org.jkiss.dbeaver.model.edit.DBEPersistAction;
import org.jkiss.dbeaver.model.exec.*;
import org.jkiss.dbeaver.model.impl.AbstractExecutionSource;
import org.jkiss.dbeaver.model.impl.local.StatResultSet;
import org.jkiss.dbeaver.model.navigator.DBNDatabaseNode;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.model.runtime.load.DatabaseLoadService;
import org.jkiss.dbeaver.model.runtime.load.ILoadService;
import org.jkiss.dbeaver.model.sql.SQLUtils;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.dbeaver.model.virtual.*;
import org.jkiss.dbeaver.tools.transfer.IDataTransferProducer;
import org.jkiss.dbeaver.tools.transfer.database.DatabaseTransferProducer;
import org.jkiss.dbeaver.tools.transfer.wizard.DataTransferWizard;
import org.jkiss.dbeaver.ui.*;
import org.jkiss.dbeaver.ui.actions.navigator.NavigatorHandlerObjectOpen;
import org.jkiss.dbeaver.ui.controls.resultset.view.EmptyPresentation;
import org.jkiss.dbeaver.ui.controls.resultset.view.StatisticsPresentation;
import org.jkiss.dbeaver.ui.data.IValueController;
import org.jkiss.dbeaver.ui.dialogs.ActiveWizardDialog;
import org.jkiss.dbeaver.ui.dialogs.ConfirmationDialog;
import org.jkiss.dbeaver.ui.editors.data.DatabaseDataEditor;
import org.jkiss.dbeaver.ui.editors.object.struct.EditConstraintPage;
import org.jkiss.dbeaver.ui.editors.object.struct.EditDictionaryPage;
import org.jkiss.dbeaver.ui.preferences.PrefPageDataFormat;
import org.jkiss.dbeaver.ui.preferences.PrefPageDatabaseGeneral;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
import java.lang.reflect.InvocationTargetException;
import java.text.DecimalFormat;
import java.util.*;
import java.util.List;
/**
* ResultSetViewer
*
* TODO: fix copy multiple cells - tabulation broken
* TODO: links in both directions, multiple links support (context menu)
* TODO: not-editable cells (struct owners in record mode)
* TODO: PROBLEM. Multiple occurrences of the same struct type in a single table.
* Need to make wrapper over DBSAttributeBase or something. Or maybe it is not a problem
* because we search for binding by attribute only in constraints and for unique key columns which are unique?
* But what PK has struct type?
*
*/
public class ResultSetViewer extends Viewer
implements DBPContextProvider, IResultSetController, ISaveablePart2, IAdaptable
{
private static final Log log = Log.getLog(ResultSetViewer.class);
private static final String SETTINGS_SECTION_PRESENTATIONS = "presentations";
private static final DecimalFormat ROW_COUNT_FORMAT = new DecimalFormat("###,###,###,###,###,##0");
@NotNull
private static IResultSetFilterManager filterManager = new SimpleFilterManager();
@NotNull
private final IWorkbenchPartSite site;
private final Composite viewerPanel;
private ResultSetFilterPanel filtersPanel;
private SashForm viewerSash;
private CTabFolder panelFolder;
private ToolBarManager panelToolBar;
private final Composite presentationPanel;
private final List<ToolBarManager> toolbarList = new ArrayList<>();
private Composite statusBar;
private StatusLabel statusLabel;
private ActiveStatusMessage rowCountLabel;
private final DynamicFindReplaceTarget findReplaceTarget;
// Presentation
private IResultSetPresentation activePresentation;
private ResultSetPresentationDescriptor activePresentationDescriptor;
private List<ResultSetPresentationDescriptor> availablePresentations;
private ToolBar presentationSwitchToolbar;
private final List<ResultSetPanelDescriptor> availablePanels = new ArrayList<>();
private final Map<ResultSetPresentationDescriptor, PresentationSettings> presentationSettings = new HashMap<>();
private final Map<String, IResultSetPanel> activePanels = new HashMap<>();
@NotNull
private final IResultSetContainer container;
@NotNull
private final ResultSetDataReceiver dataReceiver;
// Current row/col number
@Nullable
private ResultSetRow curRow;
// Mode
private boolean recordMode;
private final List<IResultSetListener> listeners = new ArrayList<>();
private volatile ResultSetJobDataRead dataPumpJob;
private final ResultSetModel model = new ResultSetModel();
private HistoryStateItem curState = null;
private final List<HistoryStateItem> stateHistory = new ArrayList<>();
private int historyPosition = -1;
private boolean actionsDisabled;
public ResultSetViewer(@NotNull Composite parent, @NotNull IWorkbenchPartSite site, @NotNull IResultSetContainer container)
{
super();
this.site = site;
this.recordMode = false;
this.container = container;
this.dataReceiver = new ResultSetDataReceiver(this);
loadPresentationSettings();
this.viewerPanel = UIUtils.createPlaceholder(parent, 1);
UIUtils.setHelp(this.viewerPanel, IHelpContextIds.CTX_RESULT_SET_VIEWER);
this.viewerPanel.setRedraw(false);
try {
this.filtersPanel = new ResultSetFilterPanel(this);
this.findReplaceTarget = new DynamicFindReplaceTarget();
this.viewerSash = UIUtils.createPartDivider(site.getPart(), viewerPanel, SWT.HORIZONTAL | SWT.SMOOTH);
this.viewerSash.setLayoutData(new GridData(GridData.FILL_BOTH));
this.presentationPanel = UIUtils.createPlaceholder(this.viewerSash, 1);
this.presentationPanel.setLayoutData(new GridData(GridData.FILL_BOTH));
this.panelFolder = new CTabFolder(this.viewerSash, SWT.FLAT | SWT.TOP);
this.panelFolder.marginWidth = 0;
this.panelFolder.marginHeight = 0;
this.panelFolder.setMinimizeVisible(true);
this.panelFolder.setMRUVisible(true);
this.panelFolder.setLayoutData(new GridData(GridData.FILL_BOTH));
this.panelToolBar = new ToolBarManager(SWT.HORIZONTAL | SWT.RIGHT | SWT.FLAT);
ToolBar panelToolbarControl = this.panelToolBar.createControl(panelFolder);
this.panelFolder.setTopRight(panelToolbarControl, SWT.RIGHT | SWT.WRAP);
this.panelFolder.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
CTabItem activeTab = panelFolder.getSelection();
if (activeTab != null) {
setActivePanel((String) activeTab.getData());
}
}
});
this.panelFolder.addListener(SWT.Resize, new Listener() {
@Override
public void handleEvent(Event event)
{
if (!viewerSash.isDisposed()) {
int[] weights = viewerSash.getWeights();
getPresentationSettings().panelRatio = weights[1];
}
}
});
this.panelFolder.addCTabFolder2Listener(new CTabFolder2Adapter() {
@Override
public void close(CTabFolderEvent event) {
CTabItem item = (CTabItem) event.item;
String panelId = (String) item.getData();
removePanel(panelId);
}
@Override
public void minimize(CTabFolderEvent event) {
showPanels(false);
}
@Override
public void maximize(CTabFolderEvent event) {
}
});
setActivePresentation(new EmptyPresentation());
createStatusBar();
this.viewerPanel.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
dispose();
}
});
changeMode(false);
} finally {
this.viewerPanel.setRedraw(true);
}
updateFiltersText();
}
@Override
@NotNull
public IResultSetContainer getContainer() {
return container;
}
////////////////////////////////////////////////////////////
// Filters
boolean supportsDataFilter()
{
DBSDataContainer dataContainer = getDataContainer();
return dataContainer != null &&
(dataContainer.getSupportedFeatures() & DBSDataContainer.DATA_FILTER) == DBSDataContainer.DATA_FILTER;
}
public void resetDataFilter(boolean refresh)
{
setDataFilter(model.createDataFilter(), refresh);
}
void switchFilterFocus() {
boolean filterFocused = filtersPanel.getEditControl().isFocusControl();
if (filterFocused) {
if (activePresentation != null) {
activePresentation.getControl().setFocus();
}
} else {
filtersPanel.getEditControl().setFocus();
}
}
private void updateFiltersText()
{
updateFiltersText(true);
}
public void updateFiltersText(boolean resetFilterValue)
{
if (this.viewerPanel.isDisposed()) {
return;
}
this.viewerPanel.setRedraw(false);
try {
boolean enableFilters = false;
DBCExecutionContext context = getExecutionContext();
if (context != null) {
if (activePresentation instanceof StatisticsPresentation) {
enableFilters = false;
} else {
StringBuilder where = new StringBuilder();
SQLUtils.appendConditionString(model.getDataFilter(), context.getDataSource(), null, where, true);
String whereCondition = where.toString().trim();
if (resetFilterValue) {
filtersPanel.setFilterValue(whereCondition);
if (!whereCondition.isEmpty()) {
filtersPanel.addFiltersHistory(whereCondition);
}
}
if (container.isReadyToRun() && !model.isUpdateInProgress()) {
enableFilters = true;
}
}
}
filtersPanel.enableFilters(enableFilters);
//presentationSwitchToolbar.setEnabled(enableFilters);
} finally {
this.viewerPanel.setRedraw(true);
}
}
void setDataFilter(final DBDDataFilter dataFilter, boolean refreshData)
{
if (!model.getDataFilter().equals(dataFilter)) {
//model.setDataFilter(dataFilter);
if (refreshData) {
refreshWithFilter(dataFilter);
} else {
model.setDataFilter(dataFilter);
activePresentation.refreshData(true, false, true);
updateFiltersText();
}
}
}
////////////////////////////////////////////////////////////
// Misc
@NotNull
public DBPPreferenceStore getPreferenceStore()
{
DBCExecutionContext context = getExecutionContext();
if (context != null) {
return context.getDataSource().getContainer().getPreferenceStore();
}
return DBeaverCore.getGlobalPreferenceStore();
}
@NotNull
@Override
public Color getDefaultBackground() {
return filtersPanel.getEditControl().getBackground();
}
@NotNull
@Override
public Color getDefaultForeground() {
return filtersPanel.getEditControl().getForeground();
}
private void persistConfig() {
DBCExecutionContext context = getExecutionContext();
if (context != null) {
context.getDataSource().getContainer().persistConfiguration();
}
}
////////////////////////////////////////
// Presentation & panels
List<ResultSetPresentationDescriptor> getAvailablePresentations() {
return availablePresentations;
}
@Override
@NotNull
public IResultSetPresentation getActivePresentation() {
return activePresentation;
}
void updatePresentation(final DBCResultSet resultSet) {
if (getControl().isDisposed()) {
return;
}
boolean changed = false;
try {
if (resultSet instanceof StatResultSet) {
// Statistics - let's use special presentation for it
availablePresentations = Collections.emptyList();
setActivePresentation(new StatisticsPresentation());
activePresentationDescriptor = null;
changed = true;
} else {
// Regular results
IResultSetContext context = new IResultSetContext() {
@Override
public boolean supportsAttributes() {
DBDAttributeBinding[] attrs = model.getAttributes();
return attrs.length > 0 &&
(attrs[0].getDataKind() != DBPDataKind.DOCUMENT || !CommonUtils.isEmpty(attrs[0].getNestedBindings()));
}
@Override
public boolean supportsDocument() {
return model.getDocumentAttribute() != null;
}
@Override
public String getDocumentContentType() {
DBDAttributeBinding docAttr = model.getDocumentAttribute();
return docAttr == null ? null : docAttr.getValueHandler().getValueContentType(docAttr);
}
};
final List<ResultSetPresentationDescriptor> newPresentations = ResultSetPresentationRegistry.getInstance().getAvailablePresentations(resultSet, context);
changed = CommonUtils.isEmpty(this.availablePresentations) || !newPresentations.equals(this.availablePresentations);
this.availablePresentations = newPresentations;
if (!this.availablePresentations.isEmpty()) {
for (ResultSetPresentationDescriptor pd : this.availablePresentations) {
if (pd == activePresentationDescriptor) {
// Keep the same presentation
return;
}
}
String defaultPresentationId = getPreferenceStore().getString(DBeaverPreferences.RESULT_SET_PRESENTATION);
ResultSetPresentationDescriptor newPresentation = null;
if (!CommonUtils.isEmpty(defaultPresentationId)) {
for (ResultSetPresentationDescriptor pd : this.availablePresentations) {
if (pd.getId().equals(defaultPresentationId)) {
newPresentation = pd;
break;
}
}
}
changed = true;
if (newPresentation == null) {
newPresentation = this.availablePresentations.get(0);
}
try {
IResultSetPresentation instance = newPresentation.createInstance();
activePresentationDescriptor = newPresentation;
setActivePresentation(instance);
} catch (Throwable e) {
log.error(e);
}
}
}
} finally {
if (changed) {
// Update combo
statusBar.setRedraw(false);
try {
boolean pVisible = activePresentationDescriptor != null;
((RowData)presentationSwitchToolbar.getLayoutData()).exclude = !pVisible;
presentationSwitchToolbar.setVisible(pVisible);
if (!pVisible) {
presentationSwitchToolbar.setEnabled(false);
} else {
presentationSwitchToolbar.setEnabled(true);
for (ToolItem item : presentationSwitchToolbar.getItems()) item.dispose();
for (ResultSetPresentationDescriptor pd : availablePresentations) {
ToolItem item = new ToolItem(presentationSwitchToolbar, SWT.CHECK);
item.setImage(DBeaverIcons.getImage(pd.getIcon()));
item.setText(pd.getLabel());
item.setToolTipText(pd.getDescription());
item.setData(pd);
if (pd == activePresentationDescriptor) {
item.setSelection(true);
}
item.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (e.widget != null && e.widget.getData() != null) {
switchPresentation((ResultSetPresentationDescriptor) e.widget.getData());
}
}
});
}
}
statusBar.layout();
} finally {
// Enable redraw
statusBar.setRedraw(true);
}
}
}
}
private void setActivePresentation(@NotNull IResultSetPresentation presentation) {
boolean focusInPresentation = UIUtils.isParent(presentationPanel, viewerPanel.getDisplay().getFocusControl());
// Dispose previous presentation and panels
for (Control child : presentationPanel.getChildren()) {
child.dispose();
}
for (CTabItem panelItem : panelFolder.getItems()) {
panelItem.dispose();
}
// Set new presentation
activePresentation = presentation;
availablePanels.clear();
activePanels.clear();
if (activePresentationDescriptor != null) {
availablePanels.addAll(ResultSetPresentationRegistry.getInstance().getSupportedPanels(
getDataSource(), activePresentationDescriptor.getId(), activePresentationDescriptor.getPresentationType()));
} else {
// Stats presentation
availablePanels.addAll(ResultSetPresentationRegistry.getInstance().getSupportedPanels(
getDataSource(), null, IResultSetPresentation.PresentationType.COLUMNS));
}
activePresentation.createPresentation(this, presentationPanel);
// Activate panels
{
boolean panelsVisible = false;
int[] panelWeights = new int[]{700, 300};
if (activePresentationDescriptor != null) {
PresentationSettings settings = getPresentationSettings();
panelsVisible = settings.panelsVisible;
if (settings.panelRatio > 0) {
panelWeights = new int[] {1000 - settings.panelRatio, settings.panelRatio};
}
activateDefaultPanels(settings);
}
showPanels(panelsVisible);
viewerSash.setWeights(panelWeights);
}
presentationPanel.layout();
// Update dynamic find/replace target
{
IFindReplaceTarget nested = null;
if (presentation instanceof IAdaptable) {
nested = ((IAdaptable) presentation).getAdapter(IFindReplaceTarget.class);
}
findReplaceTarget.setTarget(nested);
}
if (!toolbarList.isEmpty()) {
for (ToolBarManager tb : toolbarList) {
tb.update(true);
}
}
// Set focus in presentation control
// Use async exec to avoid focus switch after user UI interaction (e.g. combo)
if (focusInPresentation) {
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
Control control = activePresentation.getControl();
if (control != null && !control.isDisposed()) {
control.setFocus();
}
}
});
}
}
/**
* Switch to the next presentation
*/
void switchPresentation() {
if (availablePresentations.size() < 2) {
return;
}
int index = availablePresentations.indexOf(activePresentationDescriptor);
if (index < availablePresentations.size() - 1) {
index++;
} else {
index = 0;
}
switchPresentation(availablePresentations.get(index));
}
private void switchPresentation(ResultSetPresentationDescriptor selectedPresentation) {
try {
IResultSetPresentation instance = selectedPresentation.createInstance();
activePresentationDescriptor = selectedPresentation;
setActivePresentation(instance);
instance.refreshData(true, false, false);
for (ToolItem item : presentationSwitchToolbar.getItems()) {
item.setSelection(item.getData() == activePresentationDescriptor);
}
// Save in global preferences
DBeaverCore.getGlobalPreferenceStore().setValue(DBeaverPreferences.RESULT_SET_PRESENTATION, activePresentationDescriptor.getId());
savePresentationSettings();
} catch (Throwable e1) {
UIUtils.showErrorDialog(
viewerPanel.getShell(),
"Presentation switch",
"Can't switch presentation",
e1);
}
}
private void loadPresentationSettings() {
IDialogSettings pSections = ResultSetUtils.getViewerSettings(SETTINGS_SECTION_PRESENTATIONS);
for (IDialogSettings pSection : ArrayUtils.safeArray(pSections.getSections())) {
String pId = pSection.getName();
ResultSetPresentationDescriptor presentation = ResultSetPresentationRegistry.getInstance().getPresentation(pId);
if (presentation == null) {
log.warn("Presentation '" + pId + "' not found. ");
continue;
}
PresentationSettings settings = new PresentationSettings();
String panelIdList = pSection.get("enabledPanelIds");
if (panelIdList != null) {
Collections.addAll(settings.enabledPanelIds, panelIdList.split(","));
}
settings.activePanelId = pSection.get("activePanelId");
settings.panelRatio = pSection.getInt("panelRatio");
settings.panelsVisible = pSection.getBoolean("panelsVisible");
presentationSettings.put(presentation, settings);
}
}
private PresentationSettings getPresentationSettings() {
PresentationSettings settings = this.presentationSettings.get(activePresentationDescriptor);
if (settings == null) {
settings = new PresentationSettings();
this.presentationSettings.put(activePresentationDescriptor, settings);
}
return settings;
}
private void savePresentationSettings() {
IDialogSettings pSections = ResultSetUtils.getViewerSettings(SETTINGS_SECTION_PRESENTATIONS);
for (Map.Entry<ResultSetPresentationDescriptor, PresentationSettings> pEntry : presentationSettings.entrySet()) {
if (pEntry.getKey() == null) {
continue;
}
String pId = pEntry.getKey().getId();
PresentationSettings settings = pEntry.getValue();
IDialogSettings pSection = UIUtils.getSettingsSection(pSections, pId);
pSection.put("enabledPanelIds", CommonUtils.joinStrings(",", settings.enabledPanelIds));
pSection.put("activePanelId", settings.activePanelId);
pSection.put("panelRatio", settings.panelRatio);
pSection.put("panelsVisible", settings.panelsVisible);
}
}
public IResultSetPanel getVisiblePanel() {
return isPanelsVisible() ? activePanels.get(getPresentationSettings().activePanelId) : null;
}
@Override
public IResultSetPanel[] getActivePanels() {
return activePanels.values().toArray(new IResultSetPanel[activePanels.size()]);
}
@Override
public void activatePanel(String id, boolean setActive, boolean showPanels) {
if (showPanels && !isPanelsVisible()) {
showPanels(true);
}
PresentationSettings presentationSettings = getPresentationSettings();
IResultSetPanel panel = activePanels.get(id);
if (panel != null) {
CTabItem panelTab = getPanelTab(id);
if (panelTab != null) {
if (setActive) {
panelFolder.setSelection(panelTab);
presentationSettings.activePanelId = id;
}
return;
} else {
log.warn("Panel '" + id + "' tab not found");
}
}
// Create panel
ResultSetPanelDescriptor panelDescriptor = getPanelDescriptor(id);
if (panelDescriptor == null) {
log.error("Panel '" + id + "' not found");
return;
}
try {
panel = panelDescriptor.createInstance();
} catch (DBException e) {
UIUtils.showErrorDialog(getSite().getShell(), "Can't show panel", "Can't create panel '" + id + "'", e);
return;
}
activePanels.put(id, panel);
// Create control and tab item
Control panelControl = panel.createContents(activePresentation, panelFolder);
boolean firstPanel = panelFolder.getItemCount() == 0;
CTabItem panelTab = new CTabItem(panelFolder, SWT.CLOSE);
panelTab.setData(id);
panelTab.setText(panel.getPanelTitle());
panelTab.setImage(DBeaverIcons.getImage(panelDescriptor.getIcon()));
panelTab.setToolTipText(panel.getPanelDescription());
panelTab.setControl(panelControl);
if (setActive || firstPanel) {
panelFolder.setSelection(panelTab);
}
presentationSettings.enabledPanelIds.add(id);
if (setActive) {
setActivePanel(id);
}
}
private void activateDefaultPanels(PresentationSettings settings) {
// Cleanup unavailable panels
for (Iterator<String> iter = settings.enabledPanelIds.iterator(); iter.hasNext(); ) {
if (CommonUtils.isEmpty(iter.next())) {
iter.remove();
}
}
// Add default panels if needed
if (settings.enabledPanelIds.isEmpty()) {
for (ResultSetPanelDescriptor pd : availablePanels) {
if (pd.isShowByDefault()) {
settings.enabledPanelIds.add(pd.getId());
}
}
}
if (!settings.enabledPanelIds.contains(settings.activePanelId)) {
settings.activePanelId = null;
}
if (!settings.enabledPanelIds.isEmpty()) {
if (settings.activePanelId == null) {
// Set first panel active
settings.activePanelId = settings.enabledPanelIds.iterator().next();
}
for (String panelId : settings.enabledPanelIds) {
if (!CommonUtils.isEmpty(panelId)) {
activatePanel(panelId, panelId.equals(settings.activePanelId), false);
}
}
}
}
private void setActivePanel(String panelId) {
PresentationSettings settings = getPresentationSettings();
settings.activePanelId = panelId;
IResultSetPanel panel = activePanels.get(panelId);
if (panel != null) {
panel.activatePanel();
updatePanelActions();
}
}
private void removePanel(String panelId) {
IResultSetPanel panel = activePanels.remove(panelId);
if (panel != null) {
panel.deactivatePanel();
}
getPresentationSettings().enabledPanelIds.remove(panelId);
if (activePanels.isEmpty()) {
showPanels(false);
}
}
private ResultSetPanelDescriptor getPanelDescriptor(String id) {
for (ResultSetPanelDescriptor panel : availablePanels) {
if (panel.getId().equals(id)) {
return panel;
}
}
return null;
}
private CTabItem getPanelTab(String panelId) {
for (CTabItem tab : panelFolder.getItems()) {
if (CommonUtils.equalObjects(tab.getData(), panelId)) {
return tab;
}
}
return null;
}
boolean isPanelsVisible() {
return viewerSash.getMaximizedControl() == null;
}
void showPanels(boolean show) {
if (show == isPanelsVisible()) {
return;
}
CTabItem activePanelTab = panelFolder.getSelection();
if (!show) {
viewerSash.setMaximizedControl(presentationPanel);
if (activePanelTab != null && !activePanelTab.getControl().isDisposed() && UIUtils.hasFocus(activePanelTab.getControl())) {
// Set focus to presentation
activePresentation.getControl().setFocus();
}
} else {
activateDefaultPanels(getPresentationSettings());
viewerSash.setMaximizedControl(null);
updatePanelActions();
updatePanelsContent(false);
activePresentation.updateValueView();
// Set focus to panel
if (activePanelTab != null && !activePanelTab.getControl().isDisposed() && UIUtils.hasFocus(activePresentation.getControl())) {
activePanelTab.getControl().setFocus();
}
}
getPresentationSettings().panelsVisible = show;
savePresentationSettings();
}
private List<IContributionItem> fillPanelsMenu() {
List<IContributionItem> items = new ArrayList<>();
for (final ResultSetPanelDescriptor panel : availablePanels) {
Action panelAction = new Action(panel.getLabel(), Action.AS_CHECK_BOX) {
@Override
public boolean isChecked() {
return activePanels.containsKey(panel.getId());
}
@Override
public void run() {
if (isPanelsVisible() && isChecked()) {
CTabItem panelTab = getPanelTab(panel.getId());
if (panelTab != null) {
panelTab.dispose();
removePanel(panel.getId());
}
} else {
activatePanel(panel.getId(), true, true);
}
}
};
//panelAction.setImageDescriptor(DBeaverIcons.getImageDescriptor(panel.getIcon()));
items.add(new ActionContributionItem(panelAction));
}
return items;
}
private void addDefaultPanelActions() {
panelToolBar.add(new Action("View Menu", ImageDescriptor.createFromImageData(DBeaverIcons.getViewMenuImage().getImageData())) {
@Override
public void run() {
ToolBar tb = panelToolBar.getControl();
for (ToolItem item : tb.getItems()) {
if (item.getData() instanceof ActionContributionItem && ((ActionContributionItem) item.getData()).getAction() == this) {
MenuManager panelMenu = new MenuManager();
for (IContributionItem menuItem : fillPanelsMenu()) {
panelMenu.add(menuItem);
}
final Menu swtMenu = panelMenu.createContextMenu(panelToolBar.getControl());
Rectangle ib = item.getBounds();
Point displayAt = item.getParent().toDisplay(ib.x, ib.y + ib.height);
swtMenu.setLocation(displayAt);
swtMenu.setVisible(true);
return;
}
}
}
});
}
////////////////////////////////////////
// Actions
boolean isActionsDisabled() {
return actionsDisabled;
}
@Override
public void lockActionsByControl(Control lockedBy) {
if (checkDoubleLock(lockedBy)) {
return;
}
actionsDisabled = true;
lockedBy.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
actionsDisabled = false;
}
});
}
@Override
public void lockActionsByFocus(final Control lockedBy) {
lockedBy.addFocusListener(new FocusListener() {
@Override
public void focusGained(FocusEvent e) {
checkDoubleLock(lockedBy);
actionsDisabled = true;
}
@Override
public void focusLost(FocusEvent e) {
actionsDisabled = false;
}
});
lockedBy.addDisposeListener(new DisposeListener() {
@Override
public void widgetDisposed(DisposeEvent e) {
actionsDisabled = false;
}
});
}
public boolean isPresentationInFocus() {
Control activeControl = getActivePresentation().getControl();
return !activeControl.isDisposed() && activeControl.isFocusControl();
}
private boolean checkDoubleLock(Control lockedBy) {
if (actionsDisabled) {
log.debug("Internal error: actions double-lock by [" + lockedBy + "]");
return true;
}
return false;
}
@Nullable
@Override
public <T> T getAdapter(Class<T> adapter)
{
if (adapter.isAssignableFrom(activePresentation.getClass())) {
return adapter.cast(activePresentation);
}
// Try to get it from adapter
if (activePresentation instanceof IAdaptable) {
T adapted = ((IAdaptable) activePresentation).getAdapter(adapter);
if (adapted != null) {
return adapted;
}
}
IResultSetPanel visiblePanel = getVisiblePanel();
if (visiblePanel instanceof IAdaptable) {
T adapted = ((IAdaptable) visiblePanel).getAdapter(adapter);
if (adapted != null) {
return adapted;
}
}
if (adapter == IFindReplaceTarget.class) {
return adapter.cast(findReplaceTarget);
}
return null;
}
public void addListener(IResultSetListener listener)
{
synchronized (listeners) {
listeners.add(listener);
}
}
public void removeListener(IResultSetListener listener)
{
synchronized (listeners) {
listeners.remove(listener);
}
}
public void updateEditControls()
{
ResultSetPropertyTester.firePropertyChange(ResultSetPropertyTester.PROP_EDITABLE);
ResultSetPropertyTester.firePropertyChange(ResultSetPropertyTester.PROP_CHANGED);
updateToolbar();
}
/**
* It is a hack function. Generally all command associated widgets should be updated automatically by framework.
* Freaking E4 do not do it. I've spent a couple of days fighting it. Guys, you owe me.
*/
private void updateToolbar()
{
for (ToolBarManager tb : toolbarList) {
UIUtils.updateContributionItems(tb);
}
UIUtils.updateContributionItems(panelToolBar);
}
public void redrawData(boolean attributesChanged, boolean rowsChanged)
{
if (viewerPanel.isDisposed()) {
return;
}
if (rowsChanged) {
int rowCount = model.getRowCount();
if (curRow == null || curRow.getVisualNumber() >= rowCount) {
curRow = rowCount == 0 ? null : model.getRow(rowCount - 1);
}
// Set cursor on new row
if (!recordMode) {
this.updateFiltersText();
}
}
activePresentation.refreshData(attributesChanged || (rowsChanged && recordMode), false, true);
this.updateStatusMessage();
}
private void createStatusBar()
{
UIUtils.createHorizontalLine(viewerPanel);
statusBar = new Composite(viewerPanel, SWT.NONE);
statusBar.setBackgroundMode(SWT.INHERIT_FORCE);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
statusBar.setLayoutData(gd);
RowLayout toolbarsLayout = new RowLayout(SWT.HORIZONTAL);
toolbarsLayout.marginTop = 0;
toolbarsLayout.marginBottom = 0;
toolbarsLayout.center = true;
toolbarsLayout.wrap = true;
toolbarsLayout.pack = true;
//toolbarsLayout.fill = true;
statusBar.setLayout(toolbarsLayout);
{
ToolBarManager editToolbar = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT);
// handle own commands
editToolbar.add(new Separator());
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_APPLY_CHANGES, "Save", null, null, true));
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_REJECT_CHANGES, "Cancel", null, null, true));
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_GENERATE_SCRIPT, "Script", null, null, true));
editToolbar.add(new Separator());
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_EDIT));
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_ADD));
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_COPY));
editToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_DELETE));
editToolbar.createControl(statusBar);
toolbarList.add(editToolbar);
}
{
ToolBarManager navToolbar = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT);
navToolbar.add(new Separator());
navToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_FIRST));
navToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_PREVIOUS));
navToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_NEXT));
navToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_LAST));
navToolbar.add(new Separator());
navToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_FETCH_PAGE));
navToolbar.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_FETCH_ALL));
navToolbar.createControl(statusBar);
toolbarList.add(navToolbar);
}
{
ToolBarManager configToolbar = new ToolBarManager(SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT);
configToolbar.add(new Separator());
{
//configToolbar.add(new ToggleModeAction());
ActionContributionItem item = new ActionContributionItem(new ToggleModeAction());
item.setMode(ActionContributionItem.MODE_FORCE_TEXT);
configToolbar.add(item);
}
{
CommandContributionItemParameter ciParam = new CommandContributionItemParameter(
site,
"org.jkiss.dbeaver.core.resultset.panels",
ResultSetCommandHandler.CMD_TOGGLE_PANELS,
CommandContributionItem.STYLE_PULLDOWN);
ciParam.label = "Panels";
ciParam.mode = CommandContributionItem.MODE_FORCE_TEXT;
configToolbar.add(new CommandContributionItem(ciParam));
}
configToolbar.add(new Separator());
configToolbar.add(new ConfigAction());
configToolbar.add(new Separator());
configToolbar.createControl(statusBar);
toolbarList.add(configToolbar);
}
{
presentationSwitchToolbar = new ToolBar(statusBar, SWT.FLAT | SWT.HORIZONTAL | SWT.RIGHT);
RowData rd = new RowData();
rd.exclude = true;
presentationSwitchToolbar.setLayoutData(rd);
}
{
final int fontHeight = UIUtils.getFontHeight(statusBar);
statusLabel = new StatusLabel(statusBar, SWT.NONE, this);
statusLabel.setLayoutData(new RowData(40 * fontHeight, SWT.DEFAULT));
rowCountLabel = new ActiveStatusMessage(statusBar, DBeaverIcons.getImage(UIIcon.RS_REFRESH), "Calculate total row count", this) {
@Override
protected boolean isActionEnabled() {
return hasData() && isHasMoreData();
}
@Override
protected ILoadService<String> createLoadService() {
return new DatabaseLoadService<String>("Load row count", getExecutionContext()) {
@Override
public String evaluate(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
long rowCount = readRowCount(monitor);
return ROW_COUNT_FORMAT.format(rowCount);
} catch (DBException e) {
log.error(e);
return e.getMessage();
}
}
};
}
};
rowCountLabel.setLayoutData(new RowData(10 * fontHeight, SWT.DEFAULT));
rowCountLabel.setMessage("Row Count");
}
}
@Nullable
public DBSDataContainer getDataContainer()
{
return curState != null ? curState.dataContainer : container.getDataContainer();
}
////////////////////////////////////////////////////////////
// Grid/Record mode
@Override
public boolean isRecordMode() {
return recordMode;
}
void toggleMode()
{
changeMode(!recordMode);
updateEditControls();
}
private void changeMode(boolean recordMode)
{
//Object state = savePresentationState();
this.recordMode = recordMode;
//redrawData(false);
activePresentation.refreshData(true, false, false);
activePresentation.changeMode(recordMode);
updateStatusMessage();
//restorePresentationState(state);
}
////////////////////////////////////////////////////////////
// Misc
private void dispose()
{
savePresentationSettings();
clearData();
for (ToolBarManager tb : toolbarList) {
try {
tb.dispose();
} catch (Throwable e) {
// ignore
log.debug("Error disposing toolbar " + tb, e);
}
}
toolbarList.clear();
}
public boolean isAttributeReadOnly(DBDAttributeBinding attribute)
{
if (isReadOnly()) {
return true;
}
if (!model.isAttributeReadOnly(attribute)) {
return false;
}
boolean newRow = (curRow != null && curRow.getState() == ResultSetRow.STATE_ADDED);
return !newRow;
}
private Object savePresentationState() {
if (activePresentation instanceof IStatefulControl) {
return ((IStatefulControl) activePresentation).saveState();
} else {
return null;
}
}
private void restorePresentationState(Object state) {
if (activePresentation instanceof IStatefulControl) {
((IStatefulControl) activePresentation).restoreState(state);
}
}
///////////////////////////////////////
// History
List<HistoryStateItem> getStateHistory() {
return stateHistory;
}
private void setNewState(DBSDataContainer dataContainer, @Nullable DBDDataFilter dataFilter) {
// Create filter copy to avoid modifications
dataFilter = new DBDDataFilter(dataFilter == null ? model.getDataFilter() : dataFilter);
// Search in history
for (int i = 0; i < stateHistory.size(); i++) {
HistoryStateItem item = stateHistory.get(i);
if (item.dataContainer == dataContainer && item.filter != null && item.filter.equalFilters(dataFilter, false)) {
item.filter = dataFilter; // Update data filter - it may contain some orderings
curState = item;
historyPosition = i;
return;
}
}
// Save current state in history
while (historyPosition < stateHistory.size() - 1) {
stateHistory.remove(stateHistory.size() - 1);
}
curState = new HistoryStateItem(
dataContainer,
dataFilter,
curRow == null ? -1 : curRow.getVisualNumber());
stateHistory.add(curState);
historyPosition = stateHistory.size() - 1;
}
public void resetHistory() {
curState = null;
stateHistory.clear();
historyPosition = -1;
}
///////////////////////////////////////
// Misc
@Nullable
public ResultSetRow getCurrentRow()
{
return curRow;
}
@Override
public void setCurrentRow(@Nullable ResultSetRow curRow) {
this.curRow = curRow;
if (curState != null && curRow != null) {
curState.rowNumber = curRow.getVisualNumber();
}
// if (recordMode) {
// updateRecordMode();
// }
}
///////////////////////////////////////
// Status
public void setStatus(String status)
{
setStatus(status, DBPMessageType.INFORMATION);
}
public void setStatus(String status, DBPMessageType messageType)
{
if (statusLabel == null || statusLabel.isDisposed()) {
return;
}
statusLabel.setStatus(status, messageType);
rowCountLabel.updateActionState();
}
public void updateStatusMessage()
{
String statusMessage;
if (model.getRowCount() == 0) {
if (model.getVisibleAttributeCount() == 0) {
statusMessage = CoreMessages.controls_resultset_viewer_status_empty + getExecutionTimeMessage();
} else {
statusMessage = CoreMessages.controls_resultset_viewer_status_no_data + getExecutionTimeMessage();
}
} else {
if (recordMode) {
statusMessage =
CoreMessages.controls_resultset_viewer_status_row + (curRow == null ? 0 : curRow.getVisualNumber() + 1) +
"/" + model.getRowCount() +
(curRow == null ? getExecutionTimeMessage() : "");
} else {
statusMessage =
String.valueOf(model.getRowCount()) +
CoreMessages.controls_resultset_viewer_status_rows_fetched + getExecutionTimeMessage();
}
}
boolean hasWarnings = !dataReceiver.getErrorList().isEmpty();
if (hasWarnings) {
statusMessage += " - " + dataReceiver.getErrorList().size() + " warning(s)";
}
setStatus(statusMessage, hasWarnings ? DBPMessageType.WARNING : DBPMessageType.INFORMATION);
// Update row count label
if (!hasData()) {
rowCountLabel.setMessage("No Data");
} else if (!isHasMoreData()) {
rowCountLabel.setMessage(ROW_COUNT_FORMAT.format(model.getRowCount()));
} else {
if (model.getTotalRowCount() == null) {
rowCountLabel.setMessage(ROW_COUNT_FORMAT.format(model.getRowCount()) + "+");
} else {
// We know actual row count
rowCountLabel.setMessage(ROW_COUNT_FORMAT.format(model.getTotalRowCount()));
}
}
rowCountLabel.updateActionState();
}
private String getExecutionTimeMessage()
{
DBCStatistics statistics = model.getStatistics();
if (statistics == null || statistics.isEmpty()) {
return "";
}
long fetchTime = statistics.getFetchTime();
long totalTime = statistics.getTotalTime();
if (fetchTime <= 0) {
return " - " + RuntimeUtils.formatExecutionTime(totalTime);
} else {
return " - " + RuntimeUtils.formatExecutionTime(statistics.getExecuteTime()) + " (+" + RuntimeUtils.formatExecutionTime(fetchTime) + ")";
}
}
///////////////////////////////////////
// Data & metadata
/**
* Sets new metadata of result set
* @param resultSet resultset
* @param attributes attributes metadata
*/
void setMetaData(@NotNull DBCResultSet resultSet, @NotNull DBDAttributeBinding[] attributes)
{
model.setMetaData(resultSet, attributes);
activePresentation.clearMetaData();
}
void setData(List<Object[]> rows)
{
if (viewerPanel.isDisposed()) {
return;
}
this.curRow = null;
this.model.setData(rows);
this.curRow = (this.model.getRowCount() > 0 ? this.model.getRow(0) : null);
{
if (model.isMetadataChanged() && getPreferenceStore().getBoolean(DBeaverPreferences.RESULT_SET_AUTO_SWITCH_MODE)) {
boolean newRecordMode = (rows.size() == 1);
if (newRecordMode != recordMode) {
toggleMode();
}
}
}
}
void appendData(List<Object[]> rows)
{
model.appendData(rows);
activePresentation.refreshData(false, true, true);
setStatus(NLS.bind(CoreMessages.controls_resultset_viewer_status_rows_size, model.getRowCount(), rows.size()) + getExecutionTimeMessage());
updateEditControls();
}
@Override
public int promptToSaveOnClose()
{
if (!isDirty()) {
return ISaveablePart2.YES;
}
int result = ConfirmationDialog.showConfirmDialog(
viewerPanel.getShell(),
DBeaverPreferences.CONFIRM_RS_EDIT_CLOSE,
ConfirmationDialog.QUESTION_WITH_CANCEL);
if (result == IDialogConstants.YES_ID) {
return ISaveablePart2.YES;
} else if (result == IDialogConstants.NO_ID) {
rejectChanges();
return ISaveablePart2.NO;
} else {
return ISaveablePart2.CANCEL;
}
}
@Override
public void doSave(IProgressMonitor monitor)
{
applyChanges(RuntimeUtils.makeMonitor(monitor));
}
public void doSave(DBRProgressMonitor monitor)
{
applyChanges(monitor);
}
@Override
public void doSaveAs()
{
}
@Override
public boolean isDirty()
{
return model.isDirty();
}
@Override
public boolean isSaveAsAllowed()
{
return false;
}
@Override
public boolean isSaveOnCloseNeeded()
{
return true;
}
@Override
public boolean hasData()
{
return model.hasData();
}
@Override
public boolean isHasMoreData() {
return getExecutionContext() != null && dataReceiver.isHasMoreData();
}
@Override
public boolean isReadOnly()
{
if (model.isUpdateInProgress() || !(activePresentation instanceof IResultSetEditor)) {
return true;
}
DBCExecutionContext executionContext = getExecutionContext();
return
executionContext == null ||
!executionContext.isConnected() ||
executionContext.getDataSource().getContainer().isConnectionReadOnly() ||
executionContext.getDataSource().getInfo().isReadOnlyData();
}
/**
* Checks that current state of result set allows to insert new rows
* @return true if new rows insert is allowed
*/
boolean isInsertable()
{
return
!isReadOnly() &&
model.isSingleSource() &&
model.getVisibleAttributeCount() > 0;
}
public boolean isRefreshInProgress() {
return dataPumpJob != null;
}
///////////////////////////////////////////////////////
// Context menu & filters
@NotNull
static IResultSetFilterManager getFilterManager() {
return filterManager;
}
public static void registerFilterManager(@Nullable IResultSetFilterManager filterManager) {
if (filterManager == null) {
filterManager = new SimpleFilterManager();
}
ResultSetViewer.filterManager = filterManager;
}
void showFiltersMenu() {
DBDAttributeBinding curAttribute = getActivePresentation().getCurrentAttribute();
if (curAttribute == null) {
return;
}
Control control = getActivePresentation().getControl();
Point cursorLocation = getActivePresentation().getCursorLocation();
if (cursorLocation == null) {
return;
}
Point location = control.getDisplay().map(control, null, cursorLocation);
MenuManager menuManager = new MenuManager();
fillFiltersMenu(curAttribute, menuManager);
final Menu contextMenu = menuManager.createContextMenu(control);
contextMenu.setLocation(location);
contextMenu.setVisible(true);
}
@Override
public void fillContextMenu(@NotNull IMenuManager manager, @Nullable final DBDAttributeBinding attr, @Nullable final ResultSetRow row)
{
final DBPDataSource dataSource = getDataSource();
// Custom oldValue items
final ResultSetValueController valueController;
final Object value;
if (attr != null && row != null) {
valueController = new ResultSetValueController(
this,
attr,
row,
IValueController.EditType.NONE,
null);
value = valueController.getValue();
} else {
valueController = null;
value = null;
}
{
{
// Standard items
manager.add(ActionUtils.makeCommandContribution(site, IWorkbenchCommandConstants.EDIT_CUT));
manager.add(ActionUtils.makeCommandContribution(site, IWorkbenchCommandConstants.EDIT_COPY));
MenuManager extCopyMenu = new MenuManager(ActionUtils.findCommandName(ResultSetCopySpecialHandler.CMD_COPY_SPECIAL));
extCopyMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCopySpecialHandler.CMD_COPY_SPECIAL));
extCopyMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_COPY_COLUMN_NAMES));
if (row != null) {
extCopyMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_COPY_ROW_NAMES));
}
manager.add(extCopyMenu);
if (valueController != null) {
manager.add(ActionUtils.makeCommandContribution(site, IWorkbenchCommandConstants.EDIT_PASTE));
manager.add(ActionUtils.makeCommandContribution(site, CoreCommands.CMD_PASTE_SPECIAL));
manager.add(ActionUtils.makeCommandContribution(site, IWorkbenchCommandConstants.EDIT_DELETE));
// Edit items
manager.add(new Separator());
manager.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_EDIT));
manager.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_EDIT_INLINE));
if (!valueController.isReadOnly() && !DBUtils.isNullValue(value)/* && !attr.isRequired()*/) {
manager.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_CELL_SET_NULL));
}
}
manager.add(new GroupMarker(MENU_GROUP_EDIT));
}
if (valueController != null) {
// Menus from value handler
try {
manager.add(new Separator());
valueController.getValueManager().contributeActions(manager, valueController, null);
} catch (Exception e) {
log.error(e);
}
if (row.getState() == ResultSetRow.STATE_REMOVED || (row.changes != null && row.changes.containsKey(attr))) {
manager.insertAfter(IResultSetController.MENU_GROUP_EDIT, ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_CELL_RESET));
}
}
}
if (dataSource != null && attr != null && model.getVisibleAttributeCount() > 0 && !model.isUpdateInProgress()) {
// Filters and View
manager.add(new Separator());
{
String filtersShortcut = ActionUtils.findCommandDescription(ResultSetCommandHandler.CMD_FILTER_MENU, getSite(), true);
String menuName = CoreMessages.controls_resultset_viewer_action_order_filter;
if (!CommonUtils.isEmpty(filtersShortcut)) {
menuName += " (" + filtersShortcut + ")";
}
MenuManager filtersMenu = new MenuManager(
menuName,
DBeaverIcons.getImageDescriptor(UIIcon.FILTER),
"filters"); //$NON-NLS-1$
filtersMenu.setRemoveAllWhenShown(true);
filtersMenu.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
fillFiltersMenu(attr, manager);
}
});
manager.add(filtersMenu);
}
{
MenuManager viewMenu = new MenuManager(
"View/Format",
null,
"view"); //$NON-NLS-1$
List<? extends DBDAttributeTransformerDescriptor> transformers =
dataSource.getContainer().getPlatform().getValueHandlerRegistry().findTransformers(
dataSource, attr, null);
if (!CommonUtils.isEmpty(transformers)) {
MenuManager transformersMenu = new MenuManager("View as");
transformersMenu.setRemoveAllWhenShown(true);
transformersMenu.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
fillAttributeTransformersMenu(manager, attr);
}
});
viewMenu.add(transformersMenu);
} else {
final Action customizeAction = new Action("View as") {};
customizeAction.setEnabled(false);
viewMenu.add(customizeAction);
}
if (getModel().isSingleSource()) {
if (valueController != null) {
viewMenu.add(new SetRowColorAction(attr, valueController.getValue()));
if (getModel().hasColorMapping(attr)) {
viewMenu.add(new ResetRowColorAction(attr, valueController.getValue()));
}
}
viewMenu.add(new CustomizeColorsAction(attr, row));
viewMenu.add(new Separator());
}
viewMenu.add(new Action("Data formats ...") {
@Override
public void run() {
UIUtils.showPreferencesFor(
getControl().getShell(),
null,
PrefPageDataFormat.PAGE_ID);
}
});
manager.add(viewMenu);
}
{
// Navigate
MenuManager navigateMenu = new MenuManager(
"Navigate",
null,
"navigate"); //$NON-NLS-1$
if (ActionUtils.isCommandEnabled(ResultSetCommandHandler.CMD_NAVIGATE_LINK, site)) {
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_NAVIGATE_LINK));
navigateMenu.add(new Separator());
}
navigateMenu.add(new Separator());
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_FOCUS_FILTER));
navigateMenu.add(ActionUtils.makeCommandContribution(site, ITextEditorActionDefinitionIds.LINE_GOTO));
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_FIRST));
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_NEXT));
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_PREVIOUS));
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_ROW_LAST));
navigateMenu.add(new Separator());
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_FETCH_PAGE));
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_FETCH_ALL));
if (isHasMoreData() && getDataContainer() != null && (getDataContainer().getSupportedFeatures() & DBSDataContainer.DATA_COUNT) != 0) {
navigateMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_COUNT));
}
manager.add(navigateMenu);
}
{
// Layout
MenuManager layoutMenu = new MenuManager(
"Layout",
null,
"layout"); //$NON-NLS-1$
layoutMenu.add(new ToggleModeAction());
layoutMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_TOGGLE_PANELS));
layoutMenu.add(ActionUtils.makeCommandContribution(site, ResultSetCommandHandler.CMD_SWITCH_PRESENTATION));
{
layoutMenu.add(new Separator());
for (IContributionItem item : fillPanelsMenu()) {
layoutMenu.add(item);
}
}
manager.add(layoutMenu);
}
manager.add(new Separator());
}
// Fill general menu
final DBSDataContainer dataContainer = getDataContainer();
if (dataContainer != null && model.hasData()) {
manager.add(new Action(CoreMessages.controls_resultset_viewer_action_export, DBeaverIcons.getImageDescriptor(UIIcon.EXPORT)) {
@Override
public void run() {
ActiveWizardDialog dialog = new ActiveWizardDialog(
site.getWorkbenchWindow(),
new DataTransferWizard(
new IDataTransferProducer[]{
new DatabaseTransferProducer(dataContainer, model.getDataFilter())},
null
),
getSelection()
);
dialog.open();
}
});
}
manager.add(new GroupMarker(CoreCommands.GROUP_TOOLS));
if (dataContainer != null && model.hasData()) {
manager.add(new Separator());
manager.add(ActionUtils.makeCommandContribution(site, IWorkbenchCommandConstants.FILE_REFRESH));
}
manager.add(new Separator());
manager.add(new GroupMarker(IWorkbenchActionConstants.MB_ADDITIONS));
}
@Nullable
private DBPDataSource getDataSource() {
return getDataContainer() == null ? null : getDataContainer().getDataSource();
}
private class TransformerAction extends Action {
private final DBDAttributeBinding attribute;
TransformerAction(DBDAttributeBinding attr, String text, int style, boolean checked) {
super(text, style);
this.attribute = attr;
setChecked(checked);
}
@NotNull
DBVTransformSettings getTransformSettings() {
final DBVTransformSettings settings = DBVUtils.getTransformSettings(attribute, true);
if (settings == null) {
throw new IllegalStateException("Can't get/create transformer settings for '" + attribute.getFullyQualifiedName(DBPEvaluationContext.UI) + "'");
}
return settings;
}
void saveTransformerSettings() {
attribute.getDataSource().getContainer().persistConfiguration();
refreshData(null);
}
}
private void fillAttributeTransformersMenu(IMenuManager manager, final DBDAttributeBinding attr) {
final DBSDataContainer dataContainer = getDataContainer();
if (dataContainer == null) {
return;
}
final DBPDataSource dataSource = dataContainer.getDataSource();
final DBDRegistry registry = dataSource.getContainer().getPlatform().getValueHandlerRegistry();
final DBVTransformSettings transformSettings = DBVUtils.getTransformSettings(attr, false);
DBDAttributeTransformerDescriptor customTransformer = null;
if (transformSettings != null && transformSettings.getCustomTransformer() != null) {
customTransformer = registry.getTransformer(transformSettings.getCustomTransformer());
}
List<? extends DBDAttributeTransformerDescriptor> customTransformers =
registry.findTransformers(dataSource, attr, true);
if (customTransformers != null && !customTransformers.isEmpty()) {
manager.add(new TransformerAction(
attr,
"Default",
IAction.AS_RADIO_BUTTON,
transformSettings == null || CommonUtils.isEmpty(transformSettings.getCustomTransformer()))
{
@Override
public void run() {
if (isChecked()) {
getTransformSettings().setCustomTransformer(null);
saveTransformerSettings();
}
}
});
for (final DBDAttributeTransformerDescriptor descriptor : customTransformers) {
final TransformerAction action = new TransformerAction(
attr,
descriptor.getName(),
IAction.AS_RADIO_BUTTON,
transformSettings != null && descriptor.getId().equals(transformSettings.getCustomTransformer()))
{
@Override
public void run() {
if (isChecked()) {
final DBVTransformSettings settings = getTransformSettings();
final String oldCustomTransformer = settings.getCustomTransformer();
settings.setCustomTransformer(descriptor.getId());
TransformerSettingsDialog settingsDialog = new TransformerSettingsDialog(
ResultSetViewer.this, attr, settings);
if (settingsDialog.open() == IDialogConstants.OK_ID) {
saveTransformerSettings();
} else {
settings.setCustomTransformer(oldCustomTransformer);
}
}
}
};
manager.add(action);
}
}
if (customTransformer != null && !CommonUtils.isEmpty(customTransformer.getProperties())) {
manager.add(new TransformerAction(attr, "Settings ...", IAction.AS_UNSPECIFIED, false) {
@Override
public void run() {
TransformerSettingsDialog settingsDialog = new TransformerSettingsDialog(
ResultSetViewer.this, attr, transformSettings);
if (settingsDialog.open() == IDialogConstants.OK_ID) {
saveTransformerSettings();
}
}
});
}
List<? extends DBDAttributeTransformerDescriptor> applicableTransformers =
registry.findTransformers(dataSource, attr, false);
if (applicableTransformers != null) {
manager.add(new Separator());
for (final DBDAttributeTransformerDescriptor descriptor : applicableTransformers) {
boolean checked;
if (transformSettings != null) {
if (descriptor.isApplicableByDefault()) {
checked = !transformSettings.isExcluded(descriptor.getId());
} else {
checked = transformSettings.isIncluded(descriptor.getId());
}
} else {
checked = descriptor.isApplicableByDefault();
}
manager.add(new TransformerAction(attr, descriptor.getName(), IAction.AS_CHECK_BOX, checked) {
@Override
public void run() {
getTransformSettings().enableTransformer(descriptor, !isChecked());
saveTransformerSettings();
}
});
}
}
}
private void fillFiltersMenu(@NotNull DBDAttributeBinding attribute, @NotNull IMenuManager filtersMenu)
{
if (supportsDataFilter()) {
//filtersMenu.add(new FilterByListAction(operator, type, attribute));
DBCLogicalOperator[] operators = attribute.getValueHandler().getSupportedOperators(attribute);
// Operators with multiple inputs
for (DBCLogicalOperator operator : operators) {
if (operator.getArgumentCount() < 0) {
filtersMenu.add(new FilterByAttributeAction(operator, FilterByAttributeType.INPUT, attribute));
}
}
filtersMenu.add(new Separator());
// Operators with no inputs
for (DBCLogicalOperator operator : operators) {
if (operator.getArgumentCount() == 0) {
filtersMenu.add(new FilterByAttributeAction(operator, FilterByAttributeType.NONE, attribute));
}
}
for (FilterByAttributeType type : FilterByAttributeType.values()) {
if (type == FilterByAttributeType.NONE) {
// Value filters are available only if certain cell is selected
continue;
}
filtersMenu.add(new Separator());
if (type.getValue(this, attribute, DBCLogicalOperator.EQUALS, true) == null) {
// Null cell value - no operators can be applied
continue;
}
for (DBCLogicalOperator operator : operators) {
if (operator.getArgumentCount() > 0) {
filtersMenu.add(new FilterByAttributeAction(operator, type, attribute));
}
}
}
filtersMenu.add(new Separator());
DBDAttributeConstraint constraint = model.getDataFilter().getConstraint(attribute);
if (constraint != null && constraint.hasCondition()) {
filtersMenu.add(new FilterResetAttributeAction(attribute));
}
}
filtersMenu.add(new Separator());
filtersMenu.add(new ToggleServerSideOrderingAction());
filtersMenu.add(new ShowFiltersAction(true));
}
@Override
public void navigateAssociation(@NotNull DBRProgressMonitor monitor, @NotNull DBDAttributeBinding attr, @NotNull ResultSetRow row, boolean newWindow)
throws DBException
{
if (!new UIConfirmation() { @Override public Boolean runTask() { return checkForChanges(); } }
.confirm())
{
return;
}
if (getExecutionContext() == null) {
throw new DBException("Not connected");
}
DBSEntityAssociation association = null;
List<DBSEntityReferrer> referrers = attr.getReferrers();
if (referrers != null) {
for (final DBSEntityReferrer referrer : referrers) {
if (referrer instanceof DBSEntityAssociation) {
association = (DBSEntityAssociation) referrer;
break;
}
}
}
if (association == null) {
throw new DBException("Association not found in attribute [" + attr.getName() + "]");
}
DBSEntityConstraint refConstraint = association.getReferencedConstraint();
if (refConstraint == null) {
throw new DBException("Broken association (referenced constraint missing)");
}
if (!(refConstraint instanceof DBSEntityReferrer)) {
throw new DBException("Referenced constraint [" + refConstraint + "] is not a referrer");
}
DBSEntity targetEntity = refConstraint.getParentObject();
if (targetEntity == null) {
throw new DBException("Null constraint parent");
}
if (!(targetEntity instanceof DBSDataContainer)) {
throw new DBException("Entity [" + DBUtils.getObjectFullName(targetEntity, DBPEvaluationContext.UI) + "] is not a data container");
}
// make constraints
List<DBDAttributeConstraint> constraints = new ArrayList<>();
int visualPosition = 0;
// Set conditions
List<? extends DBSEntityAttributeRef> ownAttrs = CommonUtils.safeList(((DBSEntityReferrer) association).getAttributeReferences(monitor));
List<? extends DBSEntityAttributeRef> refAttrs = CommonUtils.safeList(((DBSEntityReferrer) refConstraint).getAttributeReferences(monitor));
if (ownAttrs.size() != refAttrs.size()) {
throw new DBException(
"Entity [" + DBUtils.getObjectFullName(targetEntity, DBPEvaluationContext.UI) + "] association [" + association.getName() +
"] columns differs from referenced constraint [" + refConstraint.getName() + "] (" + ownAttrs.size() + "<>" + refAttrs.size() + ")");
}
// Add association constraints
for (int i = 0; i < ownAttrs.size(); i++) {
DBSEntityAttributeRef ownAttr = ownAttrs.get(i);
DBSEntityAttributeRef refAttr = refAttrs.get(i);
DBDAttributeBinding ownBinding = model.getAttributeBinding(ownAttr.getAttribute());
assert ownBinding != null;
DBDAttributeConstraint constraint = new DBDAttributeConstraint(refAttr.getAttribute(), visualPosition++);
constraint.setVisible(true);
constraints.add(constraint);
Object keyValue = model.getCellValue(ownBinding, row);
constraint.setOperator(DBCLogicalOperator.EQUALS);
constraint.setValue(keyValue);
}
DBDDataFilter newFilter = new DBDDataFilter(constraints);
if (newWindow) {
openResultsInNewWindow(monitor, targetEntity, newFilter);
} else {
// Workaround for script results
// In script mode history state isn't updated so we check for it here
if (curState == null) {
setNewState(getDataContainer(), model.getDataFilter());
}
runDataPump((DBSDataContainer) targetEntity, newFilter, 0, getSegmentMaxRows(), -1, true, false, null);
}
}
private void openResultsInNewWindow(DBRProgressMonitor monitor, DBSEntity targetEntity, final DBDDataFilter newFilter) {
final DBCExecutionContext executionContext = getExecutionContext();
if (executionContext == null) {
return;
}
final DBNDatabaseNode targetNode = executionContext.getDataSource().getContainer().getPlatform().getNavigatorModel().getNodeByObject(monitor, targetEntity, false);
if (targetNode == null) {
UIUtils.showMessageBox(null, "Open link", "Can't navigate to '" + DBUtils.getObjectFullName(targetEntity, DBPEvaluationContext.UI) + "' - navigator node not found", SWT.ICON_ERROR);
return;
}
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
openNewDataEditor(targetNode, newFilter);
}
});
}
@Override
public int getHistoryPosition() {
return historyPosition;
}
@Override
public int getHistorySize() {
return stateHistory.size();
}
@Override
public void navigateHistory(int position) {
if (position < 0 || position >= stateHistory.size()) {
// out of range
log.debug("Wrong history position: " + position);
return;
}
HistoryStateItem state = stateHistory.get(position);
int segmentSize = getSegmentMaxRows();
if (state.rowNumber >= 0 && state.rowNumber >= segmentSize && segmentSize > 0) {
segmentSize = (state.rowNumber / segmentSize + 1) * segmentSize;
}
runDataPump(state.dataContainer, state.filter, 0, segmentSize, state.rowNumber, true, false, null);
}
@Override
public void updatePanelsContent(boolean forceRefresh) {
updateEditControls();
for (IResultSetPanel panel : getActivePanels()) {
panel.refresh(forceRefresh);
}
}
@Override
public void updatePanelActions() {
IResultSetPanel visiblePanel = getVisiblePanel();
panelToolBar.removeAll();
if (visiblePanel != null) {
visiblePanel.contributeActions(panelToolBar);
}
addDefaultPanelActions();
panelToolBar.update(true);
ToolBar toolBar = panelToolBar.getControl();
Point toolBarSize = toolBar.computeSize(SWT.DEFAULT, SWT.DEFAULT);
this.panelFolder.setTabHeight(toolBarSize.y);
}
@Override
public Composite getControl()
{
return this.viewerPanel;
}
@NotNull
@Override
public IWorkbenchPartSite getSite()
{
return site;
}
@Override
@NotNull
public ResultSetModel getModel()
{
return model;
}
@Override
public ResultSetModel getInput()
{
return model;
}
@Override
public void setInput(Object input)
{
throw new IllegalArgumentException("ResultSet model can't be changed");
}
@Override
@NotNull
public IResultSetSelection getSelection()
{
if (activePresentation instanceof ISelectionProvider) {
ISelection selection = ((ISelectionProvider) activePresentation).getSelection();
if (selection.isEmpty()) {
return new EmptySelection();
} else if (selection instanceof IResultSetSelection) {
return (IResultSetSelection) selection;
} else {
log.debug("Bad selection type (" + selection + ") in presentation " + activePresentation);
}
}
return new EmptySelection();
}
@Override
public void setSelection(ISelection selection, boolean reveal)
{
if (activePresentation instanceof ISelectionProvider) {
((ISelectionProvider) activePresentation).setSelection(selection);
}
}
@NotNull
@Override
public ResultSetDataReceiver getDataReceiver() {
return dataReceiver;
}
@Nullable
@Override
public DBCExecutionContext getExecutionContext() {
return container.getExecutionContext();
}
private boolean checkForChanges() {
// Check if we are dirty
if (isDirty()) {
switch (promptToSaveOnClose()) {
case ISaveablePart2.CANCEL:
return false;
case ISaveablePart2.YES:
// Apply changes
applyChanges(null, new ResultSetPersister.DataUpdateListener() {
@Override
public void onUpdate(boolean success) {
if (success) {
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
refreshData(null);
}
});
}
}
});
return false;
default:
// Just ignore previous RS values
return true;
}
}
return true;
}
@Override
public void refresh()
{
if (!checkForChanges()) {
return;
}
// Pump data
DBSDataContainer dataContainer = getDataContainer();
if (container.isReadyToRun() && dataContainer != null && dataPumpJob == null) {
int segmentSize = getSegmentMaxRows();
runDataPump(dataContainer, null, 0, segmentSize, -1, true, false, new Runnable() {
@Override
public void run()
{
if (activePresentation.getControl() != null && !activePresentation.getControl().isDisposed()) {
activePresentation.formatData(true);
}
}
});
} else {
UIUtils.showErrorDialog(
null,
"Error executing query",
dataContainer == null ?
"Viewer detached from data source" :
dataPumpJob == null ?
"Can't refresh after reconnect. Re-execute query." :
"Previous query is still running");
}
}
public void refreshWithFilter(DBDDataFilter filter) {
if (!checkForChanges()) {
return;
}
DBSDataContainer dataContainer = getDataContainer();
if (dataContainer != null) {
runDataPump(
dataContainer,
filter,
0,
getSegmentMaxRows(),
curRow == null ? -1 : curRow.getRowNumber(),
true,
false,
null);
}
}
@Override
public boolean refreshData(@Nullable Runnable onSuccess) {
if (!checkForChanges()) {
return false;
}
DBSDataContainer dataContainer = getDataContainer();
if (container.isReadyToRun() && dataContainer != null && dataPumpJob == null) {
int segmentSize = getSegmentMaxRows();
if (curRow != null && curRow.getVisualNumber() >= segmentSize && segmentSize > 0) {
segmentSize = (curRow.getVisualNumber() / segmentSize + 1) * segmentSize;
}
return runDataPump(dataContainer, null, 0, segmentSize, curRow == null ? 0 : curRow.getRowNumber(), false, false, onSuccess);
} else {
return false;
}
}
public synchronized void readNextSegment()
{
if (!dataReceiver.isHasMoreData()) {
return;
}
DBSDataContainer dataContainer = getDataContainer();
if (dataContainer != null && !model.isUpdateInProgress() && dataPumpJob == null) {
dataReceiver.setHasMoreData(false);
dataReceiver.setNextSegmentRead(true);
runDataPump(
dataContainer,
model.getDataFilter(),
model.getRowCount(),
getSegmentMaxRows(),
-1,//curRow == null ? -1 : curRow.getRowNumber(), // Do not reposition cursor after next segment read!
false,
true,
null);
}
}
@Override
public void readAllData() {
if (!dataReceiver.isHasMoreData()) {
return;
}
if (ConfirmationDialog.showConfirmDialogEx(
viewerPanel.getShell(),
DBeaverPreferences.CONFIRM_RS_FETCH_ALL,
ConfirmationDialog.QUESTION,
ConfirmationDialog.WARNING) != IDialogConstants.YES_ID)
{
return;
}
DBSDataContainer dataContainer = getDataContainer();
if (dataContainer != null && !model.isUpdateInProgress() && dataPumpJob == null) {
dataReceiver.setHasMoreData(false);
dataReceiver.setNextSegmentRead(true);
runDataPump(
dataContainer,
model.getDataFilter(),
model.getRowCount(),
-1,
curRow == null ? -1 : curRow.getRowNumber(),
false,
true,
null);
}
}
void updateRowCount() {
rowCountLabel.executeAction();
}
/**
* Reads row count and sets value in status label
*/
private long readRowCount(DBRProgressMonitor monitor) throws DBException {
final DBCExecutionContext executionContext = getExecutionContext();
DBSDataContainer dataContainer = getDataContainer();
if (executionContext == null || dataContainer == null) {
throw new DBException("Not connected");
}
try (DBCSession session = executionContext.openSession(
monitor,
DBCExecutionPurpose.USER,
"Read total row count"))
{
long rowCount = dataContainer.countData(
new AbstractExecutionSource(dataContainer, executionContext, this),
session,
model.getDataFilter());
model.setTotalRowCount(rowCount);
return rowCount;
}
}
private int getSegmentMaxRows()
{
if (getDataContainer() == null) {
return 0;
}
return getPreferenceStore().getInt(DBeaverPreferences.RESULT_SET_MAX_ROWS);
}
private synchronized boolean runDataPump(
@NotNull final DBSDataContainer dataContainer,
@Nullable final DBDDataFilter dataFilter,
final int offset,
final int maxRows,
final int focusRow,
final boolean saveHistory,
final boolean scroll,
@Nullable final Runnable finalizer)
{
if (dataPumpJob != null) {
UIUtils.showMessageBox(viewerPanel.getShell(), "Data read", "Data read is in progress - can't run another", SWT.ICON_WARNING);
return false;
}
// Read data
final DBDDataFilter useDataFilter = dataFilter != null ? dataFilter :
(dataContainer == getDataContainer() ? model.getDataFilter() : null);
Composite progressControl = viewerPanel;
if (activePresentation.getControl() instanceof Composite) {
progressControl = (Composite) activePresentation.getControl();
}
final Object presentationState = savePresentationState();
dataPumpJob = new ResultSetJobDataRead(
dataContainer,
useDataFilter,
this,
getExecutionContext(),
progressControl);
dataPumpJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void aboutToRun(IJobChangeEvent event) {
model.setUpdateInProgress(true);
model.setStatistics(null);
DBeaverUI.syncExec(new Runnable() {
@Override
public void run() {
filtersPanel.enableFilters(false);
}
});
}
@Override
public void done(IJobChangeEvent event) {
final ResultSetJobDataRead job = (ResultSetJobDataRead)event.getJob();
final Throwable error = job.getError();
if (job.getStatistics() != null) {
model.setStatistics(job.getStatistics());
}
final Control control = getControl();
if (control.isDisposed()) {
return;
}
DBeaverUI.syncExec(new Runnable() {
@Override
public void run() {
try {
final Control control = getControl();
if (control.isDisposed()) {
return;
}
final Shell shell = control.getShell();
final boolean metadataChanged = model.isMetadataChanged();
if (error != null) {
setStatus(error.getMessage(), DBPMessageType.ERROR);
UIUtils.showErrorDialog(
shell,
"Error executing query",
"Query execution failed",
error);
} else {
if (!metadataChanged && focusRow >= 0 && focusRow < model.getRowCount() && model.getVisibleAttributeCount() > 0) {
// Seems to be refresh
// Restore original position
curRow = model.getRow(focusRow);
restorePresentationState(presentationState);
}
}
activePresentation.updateValueView();
updatePanelsContent(false);
if (!scroll) {
// Add new history item
if (saveHistory && error == null) {
setNewState(dataContainer, dataFilter);
}
if (dataFilter != null) {
model.updateDataFilter(dataFilter);
// New data filter may have different columns visibility
redrawData(true, false);
}
}
model.setUpdateInProgress(false);
if (job.getStatistics() == null || !job.getStatistics().isEmpty()) {
if (error == null) {
// Update status (update execution statistics)
updateStatusMessage();
}
updateFiltersText(error == null);
updateToolbar();
fireResultSetLoad();
}
} finally {
if (finalizer != null) {
try {
finalizer.run();
} catch (Throwable e) {
log.error(e);
}
}
dataPumpJob = null;
}
}
});
}
});
dataPumpJob.setOffset(offset);
dataPumpJob.setMaxRows(maxRows);
dataPumpJob.schedule();
return true;
}
private void clearData()
{
this.model.clearData();
this.curRow = null;
this.activePresentation.clearMetaData();
}
@Override
public boolean applyChanges(@Nullable DBRProgressMonitor monitor)
{
return applyChanges(monitor, null);
}
/**
* Saves changes to database
* @param monitor monitor. If null then save will be executed in async job
* @param listener finish listener (may be null)
*/
public boolean applyChanges(@Nullable final DBRProgressMonitor monitor, @Nullable final ResultSetPersister.DataUpdateListener listener)
{
try {
final ResultSetPersister persister = createDataPersister(false);
final ResultSetPersister.DataUpdateListener applyListener = new ResultSetPersister.DataUpdateListener() {
@Override
public void onUpdate(boolean success) {
if (listener != null) {
listener.onUpdate(success);
}
if (success && getPreferenceStore().getBoolean(DBeaverPreferences.RS_EDIT_REFRESH_AFTER_UPDATE)) {
// Refresh updated rows
try {
persister.refreshInsertedRows();
} catch (Throwable e) {
log.error("Error refreshing rows after update", e);
}
}
}
};
return persister.applyChanges(monitor, false, applyListener);
} catch (DBException e) {
UIUtils.showErrorDialog(null, "Apply changes error", "Error saving changes in database", e);
return false;
}
}
@Override
public void rejectChanges()
{
if (!isDirty()) {
return;
}
try {
createDataPersister(true).rejectChanges();
} catch (DBException e) {
log.debug(e);
}
}
@Override
public List<DBEPersistAction> generateChangesScript(@NotNull DBRProgressMonitor monitor)
{
try {
ResultSetPersister persister = createDataPersister(false);
persister.applyChanges(monitor, true, null);
return persister.getScript();
} catch (DBException e) {
UIUtils.showErrorDialog(null, "SQL script generate error", "Error saving changes in database", e);
return Collections.emptyList();
}
}
@NotNull
private ResultSetPersister createDataPersister(boolean skipKeySearch)
throws DBException
{
if (!skipKeySearch && !model.isSingleSource()) {
throw new DBException("Can't save data for result set from multiple sources");
}
boolean needPK = false;
if (!skipKeySearch) {
for (ResultSetRow row : model.getAllRows()) {
if (row.getState() == ResultSetRow.STATE_REMOVED || (row.getState() == ResultSetRow.STATE_NORMAL && row.isChanged())) {
needPK = true;
break;
}
}
}
if (needPK) {
// If we have deleted or updated rows then check for unique identifier
if (!checkEntityIdentifier()) {
throw new DBException("No unique identifier defined");
}
}
return new ResultSetPersister(this);
}
@NotNull
public ResultSetRow addNewRow(final boolean copyCurrent, boolean afterCurrent)
{
List<ResultSetRow> selectedRows = new ArrayList<>(getSelection().getSelectedRows());
int rowNum = curRow == null ? 0 : curRow.getVisualNumber();
if (rowNum >= model.getRowCount()) {
rowNum = model.getRowCount() - 1;
}
if (rowNum < 0) {
rowNum = 0;
}
final DBCExecutionContext executionContext = getExecutionContext();
if (executionContext == null) {
throw new IllegalStateException("Can't add/copy rows in disconnected results");
}
// Add new row
// Copy cell values in new context
try (DBCSession session = executionContext.openSession(new VoidProgressMonitor(), DBCExecutionPurpose.UTIL, CoreMessages.controls_resultset_viewer_add_new_row_context_name)) {
final DBDAttributeBinding docAttribute = model.getDocumentAttribute();
final DBDAttributeBinding[] attributes = model.getAttributes();
int rowsToCopy[];
if (selectedRows.size() > 1) {
rowsToCopy = new int[selectedRows.size()];
for (int i = 0; i < selectedRows.size(); i++) {
rowsToCopy[i] = selectedRows.get(i).getVisualNumber();
}
rowNum = rowsToCopy[0];
} else {
rowsToCopy = new int[]{rowNum};
}
int newRowIndex = afterCurrent ? rowNum + rowsToCopy.length : rowNum;
for (int rowIndex = rowsToCopy.length - 1, rowCount = 0; rowIndex >= 0; rowIndex--, rowCount++) {
int currentRowNumber = rowsToCopy[rowIndex];
if (!afterCurrent) {
currentRowNumber += rowCount;
}
final Object[] cells;
if (docAttribute != null) {
cells = new Object[1];
if (copyCurrent && currentRowNumber >= 0 && currentRowNumber < model.getRowCount()) {
Object[] origRow = model.getRowData(currentRowNumber);
try {
cells[0] = docAttribute.getValueHandler().getValueFromObject(session, docAttribute, origRow[0], true);
} catch (DBCException e) {
log.warn(e);
}
}
if (cells[0] == null) {
try {
cells[0] = DBUtils.makeNullValue(session, docAttribute.getValueHandler(), docAttribute.getAttribute());
} catch (DBCException e) {
log.warn(e);
}
}
} else {
cells = new Object[attributes.length];
if (copyCurrent && currentRowNumber >= 0 && currentRowNumber < model.getRowCount()) {
Object[] origRow = model.getRowData(currentRowNumber);
for (int i = 0; i < attributes.length; i++) {
DBDAttributeBinding metaAttr = attributes[i];
if (metaAttr.isPseudoAttribute() || metaAttr.isAutoGenerated()) {
// set pseudo and autoincrement attributes to null
cells[i] = null;
} else {
DBSAttributeBase attribute = metaAttr.getAttribute();
try {
cells[i] = metaAttr.getValueHandler().getValueFromObject(session, attribute, origRow[i], true);
} catch (DBCException e) {
log.warn(e);
try {
cells[i] = DBUtils.makeNullValue(session, metaAttr.getValueHandler(), attribute);
} catch (DBCException e1) {
log.warn(e1);
}
}
}
}
} else {
// Initialize new values
for (int i = 0; i < attributes.length; i++) {
DBDAttributeBinding metaAttr = attributes[i];
try {
cells[i] = DBUtils.makeNullValue(session, metaAttr.getValueHandler(), metaAttr.getAttribute());
} catch (DBCException e) {
log.warn(e);
}
}
}
}
curRow = model.addNewRow(newRowIndex, cells);
}
}
redrawData(false, true);
updateEditControls();
fireResultSetChange();
return curRow;
}
void deleteSelectedRows()
{
Set<ResultSetRow> rowsToDelete = new LinkedHashSet<>();
if (recordMode) {
rowsToDelete.add(curRow);
} else {
IResultSetSelection selection = getSelection();
if (!selection.isEmpty()) {
rowsToDelete.addAll(selection.getSelectedRows());
}
}
if (rowsToDelete.isEmpty()) {
return;
}
int rowsRemoved = 0;
int lastRowNum = -1;
for (ResultSetRow row : rowsToDelete) {
if (model.deleteRow(row)) {
rowsRemoved++;
}
lastRowNum = row.getVisualNumber();
}
redrawData(false, rowsRemoved > 0);
// Move one row down (if we are in grid mode)
if (!recordMode && lastRowNum < model.getRowCount() - 1 && rowsRemoved == 0) {
activePresentation.scrollToRow(IResultSetPresentation.RowPosition.NEXT);
} else {
activePresentation.scrollToRow(IResultSetPresentation.RowPosition.CURRENT);
}
updateEditControls();
fireResultSetChange();
}
//////////////////////////////////
// Virtual identifier management
@Nullable
DBDRowIdentifier getVirtualEntityIdentifier()
{
if (!model.isSingleSource() || model.getVisibleAttributeCount() == 0) {
return null;
}
DBDRowIdentifier rowIdentifier = model.getVisibleAttribute(0).getRowIdentifier();
DBSEntityReferrer identifier = rowIdentifier == null ? null : rowIdentifier.getUniqueKey();
if (identifier != null && identifier instanceof DBVEntityConstraint) {
return rowIdentifier;
} else {
return null;
}
}
private boolean checkEntityIdentifier() throws DBException
{
DBSEntity entity = model.getSingleSource();
if (entity == null) {
UIUtils.showErrorDialog(
null,
"Unrecognized entity",
"Can't detect source entity");
return false;
}
final DBCExecutionContext executionContext = getExecutionContext();
if (executionContext == null) {
return false;
}
// Check for value locators
// Probably we have only virtual one with empty attribute set
final DBDRowIdentifier identifier = getVirtualEntityIdentifier();
if (identifier != null) {
if (CommonUtils.isEmpty(identifier.getAttributes())) {
// Empty identifier. We have to define it
return new UIConfirmation() {
@Override
public Boolean runTask() {
return ValidateUniqueKeyUsageDialog.validateUniqueKey(ResultSetViewer.this, executionContext);
}
}.confirm();
}
}
{
// Check attributes of non-virtual identifier
DBDRowIdentifier rowIdentifier = model.getVisibleAttribute(0).getRowIdentifier();
if (rowIdentifier == null) {
// We shouldn't be here ever!
// Virtual id should be created if we missing natural one
UIUtils.showErrorDialog(
null,
"No entity identifier",
"Entity " + entity.getName() + " has no unique key");
return false;
} else if (CommonUtils.isEmpty(rowIdentifier.getAttributes())) {
UIUtils.showErrorDialog(
null,
"No entity identifier",
"Attributes of '" + DBUtils.getObjectFullName(rowIdentifier.getUniqueKey(), DBPEvaluationContext.UI) + "' are missing in result set");
return false;
}
}
return true;
}
boolean editEntityIdentifier(DBRProgressMonitor monitor) throws DBException
{
DBDRowIdentifier virtualEntityIdentifier = getVirtualEntityIdentifier();
if (virtualEntityIdentifier == null) {
log.warn("No virtual identifier");
return false;
}
DBVEntityConstraint constraint = (DBVEntityConstraint) virtualEntityIdentifier.getUniqueKey();
EditConstraintPage page = new EditConstraintPage(
"Define virtual unique identifier",
constraint);
if (!page.edit()) {
return false;
}
Collection<DBSEntityAttribute> uniqueAttrs = page.getSelectedAttributes();
constraint.setAttributes(uniqueAttrs);
virtualEntityIdentifier = getVirtualEntityIdentifier();
if (virtualEntityIdentifier == null) {
log.warn("No virtual identifier defined");
return false;
}
virtualEntityIdentifier.reloadAttributes(monitor, model.getAttributes());
persistConfig();
return true;
}
private void clearEntityIdentifier(DBRProgressMonitor monitor) throws DBException
{
DBDAttributeBinding firstAttribute = model.getVisibleAttribute(0);
DBDRowIdentifier rowIdentifier = firstAttribute.getRowIdentifier();
if (rowIdentifier != null) {
DBVEntityConstraint virtualKey = (DBVEntityConstraint) rowIdentifier.getUniqueKey();
virtualKey.setAttributes(Collections.<DBSEntityAttribute>emptyList());
rowIdentifier.reloadAttributes(monitor, model.getAttributes());
virtualKey.getParentObject().setProperty(DBVConstants.PROPERTY_USE_VIRTUAL_KEY_QUIET, null);
}
persistConfig();
}
void fireResultSetChange() {
synchronized (listeners) {
if (!listeners.isEmpty()) {
for (IResultSetListener listener : listeners) {
listener.handleResultSetChange();
}
}
}
}
private void fireResultSetLoad() {
synchronized (listeners) {
if (!listeners.isEmpty()) {
for (IResultSetListener listener : listeners) {
listener.handleResultSetLoad();
}
}
}
}
private static class SimpleFilterManager implements IResultSetFilterManager {
private final Map<String, List<String>> filterHistory = new HashMap<>();
@NotNull
@Override
public List<String> getQueryFilterHistory(@NotNull String query) throws DBException {
final List<String> filters = filterHistory.get(query);
if (filters != null) {
return filters;
}
return Collections.emptyList();
}
@Override
public void saveQueryFilterValue(@NotNull String query, @NotNull String filterValue) throws DBException {
List<String> filters = filterHistory.get(query);
if (filters == null) {
filters = new ArrayList<>();
filterHistory.put(query, filters);
}
filters.add(filterValue);
}
@Override
public void deleteQueryFilterValue(@NotNull String query, String filterValue) throws DBException {
List<String> filters = filterHistory.get(query);
if (filters != null) {
filters.add(filterValue);
}
}
}
private class EmptySelection extends StructuredSelection implements IResultSetSelection {
@NotNull
@Override
public IResultSetController getController() {
return ResultSetViewer.this;
}
@NotNull
@Override
public Collection<DBDAttributeBinding> getSelectedAttributes() {
return Collections.emptyList();
}
@NotNull
@Override
public Collection<ResultSetRow> getSelectedRows() {
return Collections.emptyList();
}
@Override
public DBDAttributeBinding getElementAttribute(Object element) {
return null;
}
@Override
public ResultSetRow getElementRow(Object element) {
return null;
}
}
public static class PanelsMenuContributor extends CompoundContributionItem
{
@Override
protected IContributionItem[] getContributionItems() {
final ResultSetViewer rsv = (ResultSetViewer) ResultSetCommandHandler.getActiveResultSet(
DBeaverUI.getActiveWorkbenchWindow().getActivePage().getActivePart());
if (rsv == null) {
return new IContributionItem[0];
}
List<IContributionItem> items = rsv.fillPanelsMenu();
return items.toArray(new IContributionItem[items.size()]);
}
}
private class ConfigAction extends Action implements IMenuCreator {
ConfigAction()
{
super(CoreMessages.controls_resultset_viewer_action_options, IAction.AS_DROP_DOWN_MENU);
setImageDescriptor(DBeaverIcons.getImageDescriptor(UIIcon.CONFIGURATION));
}
@Override
public IMenuCreator getMenuCreator()
{
return this;
}
@Override
public void runWithEvent(Event event)
{
Menu menu = getMenu(activePresentation.getControl());
if (menu != null && event.widget instanceof ToolItem) {
Rectangle bounds = ((ToolItem) event.widget).getBounds();
Point point = ((ToolItem) event.widget).getParent().toDisplay(bounds.x, bounds.y + bounds.height);
menu.setLocation(point.x, point.y);
menu.setVisible(true);
}
}
@Override
public void dispose()
{
}
@Override
public Menu getMenu(Control parent)
{
MenuManager menuManager = new MenuManager();
menuManager.add(new ShowFiltersAction(false));
menuManager.add(new CustomizeColorsAction());
menuManager.add(new Separator());
menuManager.add(new VirtualKeyEditAction(true));
menuManager.add(new VirtualKeyEditAction(false));
menuManager.add(new DictionaryEditAction());
menuManager.add(new Separator());
menuManager.add(new ToggleModeAction());
activePresentation.fillMenu(menuManager);
if (!CommonUtils.isEmpty(availablePresentations) && availablePresentations.size() > 1) {
menuManager.add(new Separator());
for (final ResultSetPresentationDescriptor pd : availablePresentations) {
Action action = new Action(pd.getLabel(), IAction.AS_RADIO_BUTTON) {
@Override
public boolean isEnabled() {
return !isRefreshInProgress();
}
@Override
public boolean isChecked() {
return pd == activePresentationDescriptor;
}
@Override
public void run() {
switchPresentation(pd);
}
};
if (pd.getIcon() != null) {
//action.setImageDescriptor(ImageDescriptor.createFromImage(pd.getIcon()));
}
menuManager.add(action);
}
}
menuManager.add(new Separator());
menuManager.add(new Action("Preferences") {
@Override
public void run()
{
UIUtils.showPreferencesFor(
getControl().getShell(),
ResultSetViewer.this,
PrefPageDatabaseGeneral.PAGE_ID);
}
});
return menuManager.createContextMenu(parent);
}
@Nullable
@Override
public Menu getMenu(Menu parent)
{
return null;
}
}
private class ShowFiltersAction extends Action {
ShowFiltersAction(boolean context)
{
super(context ? "Customize ..." : "Order/Filter ...", DBeaverIcons.getImageDescriptor(UIIcon.FILTER));
}
@Override
public void run()
{
new FilterSettingsDialog(ResultSetViewer.this).open();
}
}
private class ToggleServerSideOrderingAction extends Action {
ToggleServerSideOrderingAction()
{
super(CoreMessages.pref_page_database_resultsets_label_server_side_order);
}
@Override
public int getStyle()
{
return AS_CHECK_BOX;
}
@Override
public boolean isChecked()
{
return getPreferenceStore().getBoolean(DBeaverPreferences.RESULT_SET_ORDER_SERVER_SIDE);
}
@Override
public void run()
{
DBPPreferenceStore preferenceStore = getPreferenceStore();
preferenceStore.setValue(
DBeaverPreferences.RESULT_SET_ORDER_SERVER_SIDE,
!preferenceStore.getBoolean(DBeaverPreferences.RESULT_SET_ORDER_SERVER_SIDE));
}
}
private enum FilterByAttributeType {
VALUE(UIIcon.FILTER_VALUE) {
@Override
Object getValue(@NotNull ResultSetViewer viewer, @NotNull DBDAttributeBinding attribute, @NotNull DBCLogicalOperator operator, boolean useDefault)
{
final ResultSetRow row = viewer.getCurrentRow();
if (attribute == null || row == null) {
return null;
}
Object cellValue = viewer.model.getCellValue(attribute, row);
if (operator == DBCLogicalOperator.LIKE && cellValue != null) {
cellValue = "%" + cellValue + "%";
}
return cellValue;
}
},
INPUT(UIIcon.FILTER_INPUT) {
@Override
Object getValue(@NotNull ResultSetViewer viewer, @NotNull DBDAttributeBinding attribute, @NotNull DBCLogicalOperator operator, boolean useDefault)
{
if (useDefault) {
return "..";
} else {
ResultSetRow[] rows = null;
if (operator.getArgumentCount() < 0) {
Collection<ResultSetRow> selectedRows = viewer.getSelection().getSelectedRows();
rows = selectedRows.toArray(new ResultSetRow[selectedRows.size()]);
} else {
ResultSetRow focusRow = viewer.getCurrentRow();
if (focusRow != null) {
rows = new ResultSetRow[] { focusRow };
}
}
if (rows == null || rows.length == 0) {
return null;
}
FilterValueEditDialog dialog = new FilterValueEditDialog(viewer, attribute, rows, operator);
if (dialog.open() == IDialogConstants.OK_ID) {
return dialog.getValue();
} else {
return null;
}
}
}
},
CLIPBOARD(UIIcon.FILTER_CLIPBOARD) {
@Override
Object getValue(@NotNull ResultSetViewer viewer, @NotNull DBDAttributeBinding attribute, @NotNull DBCLogicalOperator operator, boolean useDefault)
{
try {
return ResultSetUtils.getAttributeValueFromClipboard(attribute);
} catch (DBCException e) {
log.debug("Error copying from clipboard", e);
return null;
}
}
},
NONE(UIIcon.FILTER_VALUE) {
@Override
Object getValue(@NotNull ResultSetViewer viewer, @NotNull DBDAttributeBinding attribute, @NotNull DBCLogicalOperator operator, boolean useDefault)
{
return null;
}
};
final ImageDescriptor icon;
FilterByAttributeType(DBPImage icon)
{
this.icon = DBeaverIcons.getImageDescriptor(icon);
}
@Nullable
abstract Object getValue(@NotNull ResultSetViewer viewer, @NotNull DBDAttributeBinding attribute, @NotNull DBCLogicalOperator operator, boolean useDefault);
}
private String translateFilterPattern(DBCLogicalOperator operator, FilterByAttributeType type, DBDAttributeBinding attribute)
{
Object value = type.getValue(this, attribute, operator, true);
DBCExecutionContext executionContext = getExecutionContext();
String strValue = executionContext == null ? String.valueOf(value) : attribute.getValueHandler().getValueDisplayString(attribute, value, DBDDisplayFormat.UI);
if (operator.getArgumentCount() == 0) {
return operator.getStringValue();
} else {
return operator.getStringValue() + " " + CommonUtils.truncateString(strValue, 64);
}
}
private class FilterByAttributeAction extends Action {
private final DBCLogicalOperator operator;
private final FilterByAttributeType type;
private final DBDAttributeBinding attribute;
FilterByAttributeAction(DBCLogicalOperator operator, FilterByAttributeType type, DBDAttributeBinding attribute)
{
super(attribute.getName() + " " + translateFilterPattern(operator, type, attribute), type.icon);
this.operator = operator;
this.type = type;
this.attribute = attribute;
}
@Override
public void run()
{
Object value = type.getValue(ResultSetViewer.this, attribute, operator, false);
if (operator.getArgumentCount() != 0 && value == null) {
return;
}
DBDDataFilter filter = new DBDDataFilter(model.getDataFilter());
DBDAttributeConstraint constraint = filter.getConstraint(attribute);
if (constraint != null) {
constraint.setOperator(operator);
constraint.setValue(value);
setDataFilter(filter, true);
}
}
}
private class FilterResetAttributeAction extends Action {
private final DBDAttributeBinding attribute;
FilterResetAttributeAction(DBDAttributeBinding attribute)
{
super("Remove filter for '" + attribute.getName() + "'", DBeaverIcons.getImageDescriptor(UIIcon.REVERT));
this.attribute = attribute;
}
@Override
public void run()
{
DBDDataFilter dataFilter = new DBDDataFilter(model.getDataFilter());
DBDAttributeConstraint constraint = dataFilter.getConstraint(attribute);
if (constraint != null) {
constraint.setCriteria(null);
setDataFilter(dataFilter, true);
}
}
}
private abstract class ColorAction extends Action {
ColorAction(String name) {
super(name);
}
@NotNull
DBVEntity getVirtualEntity(DBDAttributeBinding binding)
throws IllegalStateException
{
final DBSEntity entity = getModel().getSingleSource();
if (entity == null) {
throw new IllegalStateException("No virtual entity for multi-source query");
}
final DBVEntity vEntity = DBVUtils.findVirtualEntity(entity, true);
assert vEntity != null;
return vEntity;
}
void updateColors(DBVEntity entity) {
model.updateColorMapping();
redrawData(false, false);
entity.getDataSource().getContainer().persistConfiguration();
}
}
private class SetRowColorAction extends ColorAction {
private final DBDAttributeBinding attribute;
private final Object value;
SetRowColorAction(DBDAttributeBinding attr, Object value) {
super("Color by " + attr.getName());
this.attribute = attr;
this.value = value;
}
@Override
public void run() {
RGB color;
final Shell shell = UIUtils.createCenteredShell(getControl().getShell());
try {
ColorDialog cd = new ColorDialog(shell);
color = cd.open();
if (color == null) {
return;
}
} finally {
shell.dispose();
}
try {
final DBVEntity vEntity = getVirtualEntity(attribute);
vEntity.setColorOverride(attribute, value, null, StringConverter.asString(color));
updateColors(vEntity);
} catch (IllegalStateException e) {
UIUtils.showErrorDialog(
viewerPanel.getShell(),
"Row color",
"Can't set row color",
e);
}
}
}
private class ResetRowColorAction extends ColorAction {
private final DBDAttributeBinding attribute;
ResetRowColorAction(DBDAttributeBinding attr, Object value) {
super("Reset color by " + attr.getName());
this.attribute = attr;
}
@Override
public void run() {
final DBVEntity vEntity = getVirtualEntity(attribute);
vEntity.removeColorOverride(attribute);
updateColors(vEntity);
}
}
private class CustomizeColorsAction extends ColorAction {
private final DBDAttributeBinding curAttribute;
private final ResultSetRow row;
CustomizeColorsAction() {
this(null, null);
}
CustomizeColorsAction(DBDAttributeBinding curAttribute, ResultSetRow row) {
super("Row colors ...");
this.curAttribute = curAttribute;
this.row = row;
}
@Override
public void run() {
ColorSettingsDialog dialog = new ColorSettingsDialog(ResultSetViewer.this, curAttribute, row);
if (dialog.open() != IDialogConstants.OK_ID) {
return;
}
final DBVEntity vEntity = getVirtualEntity(curAttribute);
//vEntity.removeColorOverride(attribute);
updateColors(vEntity);
}
@Override
public boolean isEnabled() {
return false;
}
}
private class VirtualKeyEditAction extends Action {
private boolean define;
VirtualKeyEditAction(boolean define)
{
super(define ? "Define virtual unique key" : "Clear virtual unique key");
this.define = define;
}
@Override
public boolean isEnabled()
{
DBDRowIdentifier identifier = getVirtualEntityIdentifier();
return identifier != null && (define || !CommonUtils.isEmpty(identifier.getAttributes()));
}
@Override
public void run()
{
DBeaverUI.runUIJob("Edit virtual key", new DBRRunnableWithProgress() {
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
if (define) {
editEntityIdentifier(monitor);
} else {
clearEntityIdentifier(monitor);
}
} catch (DBException e) {
throw new InvocationTargetException(e);
}
}
});
}
}
private class DictionaryEditAction extends Action {
DictionaryEditAction()
{
super("Define dictionary");
}
@Override
public void run()
{
EditDictionaryPage page = new EditDictionaryPage(
"Edit dictionary",
model.getSingleSource());
page.edit();
}
@Override
public boolean isEnabled()
{
final DBSEntity singleSource = model.getSingleSource();
return singleSource != null;
}
}
private class ToggleModeAction extends Action {
{
setActionDefinitionId(ResultSetCommandHandler.CMD_TOGGLE_MODE);
setImageDescriptor(DBeaverIcons.getImageDescriptor(UIIcon.RS_DETAILS));
}
ToggleModeAction() {
super("Record", Action.AS_CHECK_BOX);
}
@Override
public boolean isChecked() {
return isRecordMode();
}
@Override
public void run() {
toggleMode();
}
}
class HistoryStateItem {
DBSDataContainer dataContainer;
DBDDataFilter filter;
int rowNumber;
HistoryStateItem(DBSDataContainer dataContainer, @Nullable DBDDataFilter filter, int rowNumber) {
this.dataContainer = dataContainer;
this.filter = filter;
this.rowNumber = rowNumber;
}
String describeState() {
DBCExecutionContext context = getExecutionContext();
String desc = dataContainer.getName();
if (context != null && filter != null && filter.hasConditions()) {
StringBuilder condBuffer = new StringBuilder();
SQLUtils.appendConditionString(filter, context.getDataSource(), null, condBuffer, true);
desc += " [" + condBuffer + "]";
}
return desc;
}
}
static class PresentationSettings {
final Set<String> enabledPanelIds = new LinkedHashSet<>();
String activePanelId;
int panelRatio;
boolean panelsVisible;
}
public static void openNewDataEditor(DBNDatabaseNode targetNode, DBDDataFilter newFilter) {
IEditorPart entityEditor = NavigatorHandlerObjectOpen.openEntityEditor(
targetNode,
DatabaseDataEditor.class.getName(),
Collections.<String, Object>singletonMap(DatabaseDataEditor.ATTR_DATA_FILTER, newFilter),
DBeaverUI.getActiveWorkbenchWindow()
);
if (entityEditor instanceof MultiPageEditorPart) {
Object selectedPage = ((MultiPageEditorPart) entityEditor).getSelectedPage();
if (selectedPage instanceof IResultSetContainer) {
ResultSetViewer rsv = (ResultSetViewer) ((IResultSetContainer) selectedPage).getResultSetController();
if (rsv != null && !rsv.isRefreshInProgress() && !newFilter.equals(rsv.getModel().getDataFilter())) {
// Set filter directly
rsv.refreshWithFilter(newFilter);
}
}
}
}
}