Skip to content

Commit e32bf95

Browse files
fix: determine whether a cell is locked on the fly (#7847) (#7858)
* fix: determine whether a cell is locked on the fly * fix: add missing cell locked checks * chore: merge if blocks * test: add its for navigating to custom editors * fix: determine whether a cell is locked on the fly * fix: add missing cell locked checks * chore: merge if blocks * test: add its for navigating to custom editors * test: add horizontal its and cleanup test page Co-authored-by: Ugur Saglam <106508695+ugur-vaadin@users.noreply.github.com>
1 parent 8d2867b commit e32bf95

File tree

5 files changed

+188
-18
lines changed

5 files changed

+188
-18
lines changed

vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow-client/src/main/java/com/vaadin/addon/spreadsheet/client/SelectionHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,6 @@ public void selectCell(String name, int col, int row, String value,
129129
spreadsheet.customCellEditorDisplayed = false;
130130
sheetWidget.removeCustomCellEditor();
131131
}
132-
spreadsheet.cellLocked = locked;
133132
sheetWidget.setSelectedCell(col, row);
134133
newSelectedCellSet();
135134

@@ -182,7 +181,8 @@ public void newSelectedCellSet(boolean focusEditor) {
182181
sheetWidget.removeCustomCellEditor();
183182
}
184183

185-
if (!sheetWidget.isSelectedCellCustomized() && !spreadsheet.cellLocked
184+
if (!sheetWidget.isSelectedCellCustomized()
185+
&& !spreadsheet.isCurrentCellLocked()
186186
&& spreadsheet.customEditorFactory != null
187187
&& spreadsheet.customEditorFactory
188188
.hasCustomEditor(sheetWidget.getSelectedCellKey())) {

vaadin-spreadsheet-flow-parent/vaadin-spreadsheet-flow-client/src/main/java/com/vaadin/addon/spreadsheet/client/SpreadsheetWidget.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ public void columnHeaderContextMenu(NativeEvent nativeEvent,
124124
private boolean inlineEditing;
125125
private boolean cancelDeferredCommit;
126126
private boolean selectedCellIsFormulaType;
127-
boolean cellLocked;
128127
boolean customCellEditorDisplayed;
129128
private boolean sheetProtected;
130129
private boolean cancelNextSheetRelayout;
@@ -501,7 +500,7 @@ public void removeCellCustomEditors(HashMap<String, Slot> customEditors) {
501500
* the currently selected cell.
502501
*/
503502
public void loadSelectedCellEditor() {
504-
if (!sheetWidget.isSelectedCellCustomized() && !cellLocked
503+
if (!sheetWidget.isSelectedCellCustomized() && !isCurrentCellLocked()
505504
&& customEditorFactory != null && customEditorFactory
506505
.hasCustomEditor(sheetWidget.getSelectedCellKey())) {
507506
Widget customEditor = customEditorFactory
@@ -514,6 +513,15 @@ public void loadSelectedCellEditor() {
514513
}
515514
}
516515

516+
boolean isCellLocked(int col, int row) {
517+
return sheetWidget.isCellLocked(col, row);
518+
}
519+
520+
boolean isCurrentCellLocked() {
521+
return isCellLocked(sheetWidget.getSelectedCellColumn(),
522+
sheetWidget.getSelectedCellRow());
523+
}
524+
517525
public void addVisibleCellComment(String key) {
518526
sheetWidget.setCellCommentVisible(true, key);
519527
}
@@ -778,9 +786,8 @@ public void updateSelectedCellValues(int column, int row, String name) {
778786
sheetWidget.getOriginalCellValue(column, row));
779787
}
780788
}
781-
cellLocked = sheetWidget.isCellLocked(column, row);
782789
if (!customCellEditorDisplayed) {
783-
formulaBarWidget.setFormulaFieldEnabled(!cellLocked);
790+
formulaBarWidget.setFormulaFieldEnabled(!isCellLocked(column, row));
784791
} else {
785792
sheetWidget.displayCustomCellEditor(customEditorFactory
786793
.getCustomEditor(sheetWidget.getSelectedCellKey()), false);
@@ -1072,13 +1079,12 @@ public void onCellDoubleClick(int column, int row, String value) {
10721079
}
10731080
formulaBarEditing = false;
10741081
checkEditableAndNotify();
1075-
if (!cellLocked) {
1076-
if (!inlineEditing && !customCellEditorDisplayed) {
1077-
inlineEditing = true;
1078-
sheetWidget.startEditingCell(true, true, value);
1079-
formulaBarWidget.setInFullFocus(true);
1080-
formulaBarWidget.startInlineEdit(true);
1081-
}
1082+
if (!isCellLocked(column, row) && !inlineEditing
1083+
&& !customCellEditorDisplayed) {
1084+
inlineEditing = true;
1085+
sheetWidget.startEditingCell(true, true, value);
1086+
formulaBarWidget.setInFullFocus(true);
1087+
formulaBarWidget.startInlineEdit(true);
10821088
}
10831089
}
10841090

@@ -1160,7 +1166,7 @@ public void onSheetKeyPress(NativeEvent event, String enteredCharacter) {
11601166
case KeyCodes.KEY_BACKSPACE:
11611167
case KeyCodes.KEY_DELETE:
11621168
checkEditableAndNotify();
1163-
if (!cellLocked) {
1169+
if (!isCurrentCellLocked()) {
11641170
spreadsheetHandler.deleteSelectedCells();
11651171
formulaBarWidget.setCellPlainValue("");
11661172
}
@@ -1232,7 +1238,8 @@ public void onSheetKeyPress(NativeEvent event, String enteredCharacter) {
12321238
}
12331239
checkEditableAndNotify();
12341240
if (!sheetWidget.isSelectedCellCustomized() && !inlineEditing
1235-
&& !cellLocked && !customCellEditorDisplayed) {
1241+
&& !isCurrentCellLocked()
1242+
&& !customCellEditorDisplayed) {
12361243
cachedCellValue = sheetWidget.getSelectedCellLatestValue();
12371244
formulaBarWidget.cacheFormulaFieldValue();
12381245
formulaBarEditing = false;
@@ -1251,7 +1258,8 @@ public void onSheetKeyPress(NativeEvent event, String enteredCharacter) {
12511258
checkEditableAndNotify();
12521259

12531260
if (!sheetWidget.isSelectedCellCustomized() && !inlineEditing
1254-
&& !cellLocked && !customCellEditorDisplayed) {
1261+
&& !isCurrentCellLocked()
1262+
&& !customCellEditorDisplayed) {
12551263
// cache value and start editing cell as empty
12561264
inlineEditing = true;
12571265
cachedCellValue = sheetWidget.getSelectedCellLatestValue();
@@ -1323,7 +1331,7 @@ private boolean isSelectedCellHidden() {
13231331
* Checks if selected cell is locked, and sends an RPC to server if it is.
13241332
*/
13251333
private void checkEditableAndNotify() {
1326-
if (cellLocked) {
1334+
if (isCurrentCellLocked()) {
13271335

13281336
if (!okToSendCellProtectRpc) {
13291337
// don't send just yet
@@ -1760,7 +1768,6 @@ public void setSheetProtected(boolean sheetProtected) {
17601768
sheetWidget.removeCustomCellEditor();
17611769
}
17621770
} else { // might need to load the custom editor
1763-
cellLocked = false;
17641771
selectionHandler.newSelectedCellSet();
17651772
if (customCellEditorDisplayed) {
17661773
// need to update the editor value on client side
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* Copyright 2000-2025 Vaadin Ltd.
3+
*
4+
* This program is available under Vaadin Commercial License and Service Terms.
5+
*
6+
* See {@literal <https://vaadin.com/commercial-license-and-service-terms>} for the full
7+
* license.
8+
*/
9+
package com.vaadin.flow.component.spreadsheet.tests;
10+
11+
import java.io.File;
12+
import java.io.IOException;
13+
import java.net.URISyntaxException;
14+
15+
import org.apache.poi.ss.usermodel.Sheet;
16+
import org.slf4j.Logger;
17+
import org.slf4j.LoggerFactory;
18+
19+
import com.vaadin.flow.component.Component;
20+
import com.vaadin.flow.component.html.Div;
21+
import com.vaadin.flow.component.spreadsheet.Spreadsheet;
22+
import com.vaadin.flow.component.spreadsheet.SpreadsheetComponentFactory;
23+
import com.vaadin.flow.component.textfield.TextField;
24+
import com.vaadin.flow.router.Route;
25+
26+
@Route("vaadin-spreadsheet/locked-cell-with-custom-editor")
27+
public class LockedCellsWithCustomEditorPage extends Div {
28+
29+
private static final Logger LOGGER = LoggerFactory
30+
.getLogger(LockedCellsWithCustomEditorPage.class);
31+
32+
private TextField customEditor;
33+
34+
public LockedCellsWithCustomEditorPage() {
35+
setSizeFull();
36+
try {
37+
var file = loadFile();
38+
var spreadsheet = loadSpreadSheet(file);
39+
add(spreadsheet);
40+
} catch (Exception e) {
41+
LOGGER.warn("Could not load spreadsheet", e);
42+
}
43+
}
44+
45+
private Spreadsheet loadSpreadSheet(File file) throws IOException {
46+
var spreadsheet = new Spreadsheet(file);
47+
spreadsheet.setSizeFull();
48+
spreadsheet.setSpreadsheetComponentFactory(
49+
new SpreadsheetComponentFactory() {
50+
51+
@Override
52+
public Component getCustomComponentForCell(
53+
org.apache.poi.ss.usermodel.Cell cell, int rowIndex,
54+
int columnIndex, Spreadsheet spreadsheet,
55+
Sheet sheet) {
56+
return null;
57+
}
58+
59+
@Override
60+
public Component getCustomEditorForCell(
61+
org.apache.poi.ss.usermodel.Cell cell, int rowIndex,
62+
int columnIndex, Spreadsheet spreadsheet,
63+
Sheet sheet) {
64+
var shouldHaveCustomEditor = spreadsheet
65+
.getActiveSheetIndex() == 0
66+
&& (rowIndex == 2 && columnIndex == 2
67+
|| rowIndex == 3 && columnIndex == 3);
68+
if (!shouldHaveCustomEditor) {
69+
return null;
70+
}
71+
if (customEditor == null) {
72+
customEditor = new TextField();
73+
}
74+
return customEditor;
75+
}
76+
77+
@Override
78+
public void onCustomEditorDisplayed(
79+
org.apache.poi.ss.usermodel.Cell cell, int rowIndex,
80+
int columnIndex, Spreadsheet spreadsheet,
81+
Sheet sheet, Component customEditor) {
82+
// NO-OP
83+
}
84+
});
85+
spreadsheet.setShowCustomEditorOnFocus(true);
86+
return spreadsheet;
87+
}
88+
89+
private static File loadFile() throws URISyntaxException {
90+
var classLoader = LockedCellsWithCustomEditorPage.class
91+
.getClassLoader();
92+
var resource = classLoader.getResource("test_sheets" + File.separator
93+
+ "locked_cell_next_to_custom_editor.xlsx");
94+
assert resource != null;
95+
return new File(resource.toURI());
96+
}
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/**
2+
* Copyright 2000-2025 Vaadin Ltd.
3+
*
4+
* This program is available under Vaadin Commercial License and Service Terms.
5+
*
6+
* See {@literal <https://vaadin.com/commercial-license-and-service-terms>} for the full
7+
* license.
8+
*/
9+
package com.vaadin.flow.component.spreadsheet.test;
10+
11+
import org.junit.Assert;
12+
import org.junit.Before;
13+
import org.junit.Test;
14+
import org.openqa.selenium.By;
15+
import org.openqa.selenium.Keys;
16+
17+
import com.vaadin.flow.component.spreadsheet.testbench.SpreadsheetElement;
18+
import com.vaadin.flow.testutil.TestPath;
19+
20+
@TestPath("vaadin-spreadsheet/locked-cell-with-custom-editor")
21+
public class LockedCellsWithCustomEditorIT extends AbstractSpreadsheetIT {
22+
23+
@Before
24+
public void init() {
25+
open();
26+
setSpreadsheet($(SpreadsheetElement.class).first());
27+
}
28+
29+
@Test
30+
public void clickRegularCell_navigateVerticallyToCellWithCustomEditor_customEditorDisplayed() {
31+
clickCell("C4");
32+
getSpreadsheet().sendKeys(Keys.UP);
33+
getSpreadsheet().sendKeys(Keys.ENTER);
34+
assertCustomEditorDisplayed();
35+
}
36+
37+
@Test
38+
public void clickRegularCell_navigateHorizontallyToCellWithCustomEditor_customEditorDisplayed() {
39+
clickCell("C4");
40+
getSpreadsheet().sendKeys(Keys.RIGHT);
41+
getSpreadsheet().sendKeys(Keys.ENTER);
42+
assertCustomEditorDisplayed();
43+
}
44+
45+
@Test
46+
public void clickLockedCell_navigateVerticallyToCellWithCustomEditor_customEditorDisplayed() {
47+
clickCell("C2");
48+
getSpreadsheet().sendKeys(Keys.DOWN);
49+
getSpreadsheet().sendKeys(Keys.ENTER);
50+
assertCustomEditorDisplayed();
51+
}
52+
53+
@Test
54+
public void clickLockedCell_navigateHorizontallyToCellWithCustomEditor_customEditorDisplayed() {
55+
clickCell("B3");
56+
getSpreadsheet().sendKeys(Keys.RIGHT);
57+
getSpreadsheet().sendKeys(Keys.ENTER);
58+
assertCustomEditorDisplayed();
59+
}
60+
61+
private void assertCustomEditorDisplayed() {
62+
var editor = getDriver().switchTo().activeElement()
63+
.findElement(By.xpath(".."));
64+
Assert.assertEquals("vaadin-text-field", editor.getTagName());
65+
}
66+
}

0 commit comments

Comments
 (0)