diff --git a/grid/core-impl/gen/icons/GridCoreImplIcons.java b/grid/core-impl/gen/icons/GridCoreImplIcons.java index c856fc26ff23..39364a7be47f 100644 --- a/grid/core-impl/gen/icons/GridCoreImplIcons.java +++ b/grid/core-impl/gen/icons/GridCoreImplIcons.java @@ -11,9 +11,13 @@ import javax.swing.*; */ @org.jetbrains.annotations.ApiStatus.Internal public final class GridCoreImplIcons { + private static @NotNull Icon load(@NotNull String path, int cacheKey, int flags) { + return IconManager.getInstance().loadRasterizedIcon(path, GridCoreImplIcons.class.getClassLoader(), cacheKey, flags); + } private static @NotNull Icon load(@NotNull String expUIPath, @NotNull String path, int cacheKey, int flags) { return IconManager.getInstance().loadRasterizedIcon(path, expUIPath, GridCoreImplIcons.class.getClassLoader(), cacheKey, flags); } + /** 16x16 */ public static final @NotNull Icon CellDownload = load("icons/cellDownload.svg", 18297100, 2); /** 16x16 */ public static final @NotNull Icon ColumnFilter = load("icons/expui/columnFilter.svg", "icons/columnFilter.svg", -1426207601, 0); /** 16x16 */ public static final @NotNull Icon FilterHistory = load("icons/expui/filterHistory.svg", "icons/filterHistory.svg", 686246081, 0); /** 16x16 */ public static final @NotNull Icon SingleRecordView = load("icons/expui/singleRecordView.svg", "icons/singleRecordView.svg", 502511093, 2); diff --git a/grid/core-impl/resources/icons/cellDownload.svg b/grid/core-impl/resources/icons/cellDownload.svg new file mode 100644 index 000000000000..8e433344a459 --- /dev/null +++ b/grid/core-impl/resources/icons/cellDownload.svg @@ -0,0 +1,4 @@ + + + + diff --git a/grid/core-impl/resources/icons/cellDownload_dark.svg b/grid/core-impl/resources/icons/cellDownload_dark.svg new file mode 100644 index 000000000000..8da86f75161f --- /dev/null +++ b/grid/core-impl/resources/icons/cellDownload_dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/grid/core-impl/resources/messages/DataGridBundle.properties b/grid/core-impl/resources/messages/DataGridBundle.properties index 9566e803381b..cdb9992f0fa5 100644 --- a/grid/core-impl/resources/messages/DataGridBundle.properties +++ b/grid/core-impl/resources/messages/DataGridBundle.properties @@ -389,3 +389,9 @@ grid.load.prev.nested.table.error.loading=Navigation to {0} table is not availab progress.text.loading.data=Loading data\u2026 progress.text.loading.script=Loading script\u2026 invalid.extractor.name=Invalid extractor name: ''{0}'' +action.Console.TableResult.ReloadCell.ErrorCellLoading.text=Cannot load cell value +action.Console.TableResult.SaveLobAsAction.TableChanged.text=table has been changed +action.Console.TableResult.SaveLobAsAction.AmbiguousQueryResult.text=ambiguous query result ({0} rows received) +action.Console.TableResult.ReloadCell.Confirmation.title=Warning +action.Console.TableResult.ReloadCell.Confirmation.text=One of the loaded cells contains a large amount of data, which may affect performance. Do you want to continue? + diff --git a/grid/core-impl/src/datagrid/DataGridListModel.java b/grid/core-impl/src/datagrid/DataGridListModel.java index 9a2c0589cc7e..66e1eca51ef5 100644 --- a/grid/core-impl/src/datagrid/DataGridListModel.java +++ b/grid/core-impl/src/datagrid/DataGridListModel.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.BiFunction; -public class DataGridListModel extends GridListModelBase { +public class DataGridListModel extends GridListModelBase implements GridModelWithInjections { private final BiFunction myValuesEquals; public DataGridListModel(@NotNull BiFunction valuesEquals) { @@ -45,4 +45,12 @@ public class DataGridListModel extends GridListModelBase { } return true; } + + @Override + public void injectValue(@NotNull ModelIndex rowIndex, @NotNull ModelIndex columnIndex, @NotNull Object value) { + var row = getRow(rowIndex); + if (row != null) { + row.setValue(columnIndex.value, value); + } + } } diff --git a/grid/core-impl/src/datagrid/GridModelWithInjections.java b/grid/core-impl/src/datagrid/GridModelWithInjections.java new file mode 100644 index 000000000000..353ca8d76f38 --- /dev/null +++ b/grid/core-impl/src/datagrid/GridModelWithInjections.java @@ -0,0 +1,7 @@ +package com.intellij.database.datagrid; + +import org.jetbrains.annotations.NotNull; + +public interface GridModelWithInjections extends GridModel { + void injectValue(@NotNull ModelIndex row, @NotNull ModelIndex columns, @NotNull Object what); +} diff --git a/grid/core-impl/src/extractors/DatabaseObjectFormatterConfig.java b/grid/core-impl/src/extractors/DatabaseObjectFormatterConfig.java index a22a4f74f12d..c6b0448d2a65 100644 --- a/grid/core-impl/src/extractors/DatabaseObjectFormatterConfig.java +++ b/grid/core-impl/src/extractors/DatabaseObjectFormatterConfig.java @@ -31,6 +31,11 @@ public class DatabaseObjectFormatterConfig implements ObjectFormatterConfig { return null; } + @Override + public boolean isAllowedShowBigObjects() { + return false; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -62,6 +67,8 @@ public class DatabaseObjectFormatterConfig implements ObjectFormatterConfig { private final DataGridSettings settings; + private boolean isAllowedShowBigObjects; + public DatabaseDisplayObjectFormatterConfig() { this(null, false, null, null); } @@ -73,6 +80,7 @@ public class DatabaseObjectFormatterConfig implements ObjectFormatterConfig { @Nullable DataGridSettings settings ) { super(ObjectFormatterMode.DISPLAY); + this.isAllowedShowBigObjects = false; this.displayType = displayType; this.isModeDetectedAutomatically = isModeDetectedAutomatically; this.allowedTypes = allowedTypes; @@ -97,6 +105,15 @@ public class DatabaseObjectFormatterConfig implements ObjectFormatterConfig { return settings; } + public void allowShowBigObjects() { + this.isAllowedShowBigObjects = true; + } + + @Override + public boolean isAllowedShowBigObjects() { + return this.isAllowedShowBigObjects; + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/grid/core-impl/src/extractors/ObjectFormatterConfig.java b/grid/core-impl/src/extractors/ObjectFormatterConfig.java index 269fa6e6b021..e6840b60cb6c 100644 --- a/grid/core-impl/src/extractors/ObjectFormatterConfig.java +++ b/grid/core-impl/src/extractors/ObjectFormatterConfig.java @@ -11,4 +11,6 @@ public interface ObjectFormatterConfig { @Nullable DataGridSettings getSettings(); + + boolean isAllowedShowBigObjects(); } diff --git a/grid/impl/src/datagrid/GridUtil.java b/grid/impl/src/datagrid/GridUtil.java index 78bd044db22c..1085b0a1b99d 100644 --- a/grid/impl/src/datagrid/GridUtil.java +++ b/grid/impl/src/datagrid/GridUtil.java @@ -608,6 +608,18 @@ public class GridUtil extends GridUtilCore { }; } + public static @NotNull Function getConfigProvider(@NotNull DataGrid dataGrid, boolean allowLongValues) { + return num -> { + ModelIndex idx = ModelIndex.forColumn(dataGrid, num); + if (!allowLongValues) { + return createFormatterConfig(dataGrid, idx); + } + var config = createFormatterConfig(dataGrid, idx); + config.allowShowBigObjects(); + return config; + }; + } + public static boolean canMutateColumns(@Nullable DataGrid grid) { return grid != null && GridHelper.get(grid).canMutateColumns(grid); } diff --git a/grid/impl/src/run/ui/EditorCellViewer.kt b/grid/impl/src/run/ui/EditorCellViewer.kt index 8c0b9a0f0d06..1251445ecd9d 100644 --- a/grid/impl/src/run/ui/EditorCellViewer.kt +++ b/grid/impl/src/run/ui/EditorCellViewer.kt @@ -1,5 +1,6 @@ package com.intellij.database.run.ui +import com.intellij.database.DataGridBundle import com.intellij.database.datagrid.* import com.intellij.database.extractors.DisplayType import com.intellij.database.run.ReservedCellValue diff --git a/grid/impl/src/run/ui/TabInfoProvider.kt b/grid/impl/src/run/ui/TabInfoProvider.kt index f0d70d0684b2..2387083abc91 100644 --- a/grid/impl/src/run/ui/TabInfoProvider.kt +++ b/grid/impl/src/run/ui/TabInfoProvider.kt @@ -5,11 +5,11 @@ import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionPlaces import com.intellij.openapi.actionSystem.ActionToolbar -import com.intellij.openapi.editor.impl.EditorHeaderComponent import com.intellij.openapi.util.NlsContexts import com.intellij.ui.components.JBPanelWithEmptyText +import com.intellij.ui.components.TwoSideComponent +import com.intellij.ui.components.panels.Wrapper import com.intellij.ui.tabs.TabInfo -import com.intellij.util.ui.JBUI import java.awt.BorderLayout import javax.swing.JPanel @@ -19,11 +19,9 @@ import javax.swing.JPanel abstract class TabInfoProvider(title: @NlsContexts.TabTitle String, private val actionGroup: ActionGroup?) : Disposable { private val panel = JPanel(BorderLayout()) protected val toolbar = createToolbar() - val tabInfo = TabInfo(JBPanelWithEmptyText()).setText(title).setComponent(panel).setSideComponent(toolbar?.let { - EditorHeaderComponent().also { header -> - header.add(toolbar.component, BorderLayout.EAST) - header.border = JBUI.Borders.empty() - } + val tabInfo = TabInfo(JBPanelWithEmptyText()).setText(title).setComponent(panel) + .setSideComponent(toolbar?.let { + TwoSideComponent(Wrapper(), toolbar.component) }) protected var isOnTab: Boolean = false diff --git a/grid/impl/src/run/ui/grid/GridCopyProvider.java b/grid/impl/src/run/ui/grid/GridCopyProvider.java index b560defdc366..a7b3b0228610 100644 --- a/grid/impl/src/run/ui/grid/GridCopyProvider.java +++ b/grid/impl/src/run/ui/grid/GridCopyProvider.java @@ -108,7 +108,7 @@ public class GridCopyProvider implements CopyProvider { SelectionModel selectionModel = myGrid.getSelectionModel(); if (selectionModel.getSelectedRowCount() == 1 && selectionModel.getSelectedColumnCount() == 1) { - return GridExtractorsUtilCore.getSingleValueExtractor(myGrid.getObjectFormatter(), GridUtil.getConfigProvider(myGrid)); + return GridExtractorsUtilCore.getSingleValueExtractor(myGrid.getObjectFormatter(), GridUtil.getConfigProvider(myGrid, true)); } DataExtractorFactory extractorFactory = DataExtractorFactories.getExtractorFactory(myGrid, GridUtil::suggestPlugin); diff --git a/grid/impl/src/run/ui/table/TableResultView.java b/grid/impl/src/run/ui/table/TableResultView.java index a3b5acf6e53b..c48f9c68eefc 100644 --- a/grid/impl/src/run/ui/table/TableResultView.java +++ b/grid/impl/src/run/ui/table/TableResultView.java @@ -1,9 +1,11 @@ package com.intellij.database.run.ui.table; import com.intellij.application.options.EditorFontsConstants; +import com.intellij.database.actions.ShowEditMaximizedAction; import com.intellij.database.datagrid.*; import com.intellij.database.datagrid.HierarchicalColumnsDataGridModel.HierarchicalGridColumn; import com.intellij.database.extractors.DisplayType; +import com.intellij.database.remote.jdbc.LobInfo; import com.intellij.database.run.actions.ColumnLocalFilterAction; import com.intellij.database.run.ui.*; import com.intellij.database.run.ui.grid.*; @@ -25,6 +27,7 @@ import com.intellij.ide.ui.UISettingsListener; import com.intellij.ide.ui.UISettingsUtils; import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.actionSystem.ex.ActionUtil; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.editor.colors.EditorColorsListener; import com.intellij.openapi.editor.colors.EditorColorsScheme; @@ -1295,6 +1298,10 @@ public final class TableResultView extends JBTableWithResizableCells @Override public boolean editCellAt(int row, int column, EventObject e) { ClientProperty.put(this, GridTableCellEditor.EDITING_STARTER_CLIENT_PROPERTY_KEY, e); + if (shouldDisplayValueEditor(row, column)) { + showValueEditor(e); + return false; + } try { return super.editCellAt(row, column, e); } @@ -1303,6 +1310,23 @@ public final class TableResultView extends JBTableWithResizableCells } } + private boolean shouldDisplayValueEditor(int row, int column) { + var tableModel = getModel(); + var cellValue = tableModel.getValueAt(row, column); + return cellValue instanceof LobInfo.ClobInfo clob && clob.isFullyReloaded(); + } + + private void showValueEditor(EventObject e) { + if (e instanceof MouseEvent mouseEvent && mouseEvent.getClickCount() < 2) return; + if (e instanceof KeyEvent && !UIUtil.isReallyTypedEvent((KeyEvent)e)) return; + + var action = ActionUtil.wrap("Console.TableResult.EditValueMaximized"); + var dataContext = DataManager.getInstance().getDataContext(this); + AnActionEvent event = AnActionEvent.createEvent(action, dataContext, null, ActionPlaces.UNKNOWN, ActionUiKind.NONE, null); + var view = ShowEditMaximizedAction.getView(this.myResultPanel, event); + view.open(tabInfoProvider -> tabInfoProvider instanceof ValueTabInfoProvider); + } + @Override public void createDefaultColumnsFromModel() { GridTableModel model = getModel(); diff --git a/grid/types/src/remote/jdbc/LobInfo.java b/grid/types/src/remote/jdbc/LobInfo.java index 98059612e3e6..f7d48ba99b2c 100644 --- a/grid/types/src/remote/jdbc/LobInfo.java +++ b/grid/types/src/remote/jdbc/LobInfo.java @@ -20,6 +20,8 @@ import java.util.Objects; public abstract class LobInfo> implements Comparable, Serializable { public final long length; + private boolean isFullyReloaded; + private static final ThreadLocal BUFFER = new ThreadLocal() { @Override protected byte[] initialValue() { @@ -35,6 +37,14 @@ public abstract class LobInfo> implements Comparable, Se return length != getLoadedDataLength(); } + public boolean isFullyReloaded() { + return isFullyReloaded; + } + + public void setFullyReloaded(boolean fullyReloaded) { + this.isFullyReloaded = fullyReloaded; + } + public abstract long getLoadedDataLength(); @Override diff --git a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java index 20cf02cfde27..ab6c65ee5481 100644 --- a/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java +++ b/platform/platform-impl/src/com/intellij/ui/EditorTextFieldCellRenderer.java @@ -1,4 +1,4 @@ -// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.ui; import com.intellij.ide.ui.UISettings;