Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: use the same cell reference constructor in order to ensure consistency #4634

Draft
wants to merge 18 commits into
base: main
Choose a base branch
from

Conversation

ugur-vaadin
Copy link
Contributor

@ugur-vaadin ugur-vaadin commented Feb 2, 2023

Description

In Apache POI, CellReference has multiple constructors. In the version that Vaadin V8 used, the constructor CellReference(Cell cell) did not use the sheet name from the Cell object. However, while having the same signature, this constructor started using the sheet name in the new versions. This creates inconsistencies when checking equality for CellReferences since we use different constructors in various locations.

Several options were discussed, including:

  • Adding cell references with and without the sheet names to the event. This fixes Set.contains usages, however the set will have duplicates and any size comparison would be broken.
  • Using the cell references that only use the sheet names. This will have the correct size without duplicates, however will require the Set.contains checks to be updated to include the sheet names. This might also be somewhat inconvenient. Using the constructors without sheet names (e.g "B2", "C3") is easier and the sheet name might be expected to determined from the context.
  • Using the cell references that only use the sheet names internally, but introducing a new class CellSet that handles contains behaviour inside. This will be a breaking change for users that use the set directly or use other Set API.

This PR goes with this option. For the API:

  • size() is present
  • contains(...) is present
  • getCells() is used to get the actual set of cells and perform any other operations

Note that currently, CellSet only supports cells from the same sheet. If necessary, another internal set can be initialized with all the combinations to provide accurate and fast response to contains(...) calls.

Fixes #4588

Type of change

  • Bugfix
  • Feature

Checklist

  • I have read the contribution guide: https://vaadin.com/docs/latest/contributing/overview
  • I have added a description following the guideline.
  • The issue is created in the corresponding repository and I have referenced it.
  • I have added tests to ensure my change is effective and works as intended.
  • New and existing tests are passing locally with my change.
  • I have performed self-review and corrected misspellings.

@@ -399,8 +401,10 @@ public void onSelectionDecreasePainted(int r, int c) {
if (!SpreadsheetUtil.isCellInRange(selectedCellReference,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

18% of developers fix this issue

NULL_DEREFERENCE: object selectedCellReference last assigned on line 398 could be null and is dereferenced by call to isCellInRange(...) at line 401.


ℹ️ Learn about @sonatype-lift commands

You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.

Command Usage
@sonatype-lift ignore Leave out the above finding from this PR
@sonatype-lift ignoreall Leave out all the existing findings from this PR
@sonatype-lift exclude <file|issue|path|tool> Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file

Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.


Was this a good recommendation?
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]

@@ -148,7 +148,8 @@ public void captureCellRangeValues(CellRangeAddress... cellRanges) {

@Override
public CellReference getSelectedCellReference() {
return new CellReference(selectedCellRow, selectedcellCol);
return new CellReference(spreadsheet.getActiveSheet().getSheetName(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For commands, it seems safer to use SpreadsheetCommand.getSheet(). Currently that always delegates to Spreadsheet.getActivesheet(), but there's a chance that the implementation might change at some point.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest version

@@ -334,7 +334,9 @@ private void fireCellValueChangeEvent(CellRangeAddress region) {
for (int x = region.getFirstColumn(); x <= region
.getLastColumn(); x++) {
for (int y = region.getFirstRow(); y <= region.getLastRow(); y++) {
cells.add(new CellReference(y, x));
cells.add(new CellReference(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main issue with the overall change to include spreadsheet names into the cell references is that if a developer is already using cell references without the sheet name, the comparison will now fail. And that's quite easy to achieve, as new CellReference("A2") is a lot easier to use than the other alternatives that include the sheet name. It's very likely a breaking change.

We could consider adding both types of references (with and without sheet name) to the events. For example, for cell value change events we could modify the logic here:

private void fireCellValueChangeEvent(Set<CellReference> changedCells) {
spreadsheet
.fireEvent(new CellValueChangeEvent(spreadsheet, changedCells));
}

To something like:

    private void fireCellValueChangeEvent(Set<CellReference> changedCells) {
        List<CellReference> cellRefsWithSheetName = changedCells
                .stream()
                .filter(ref -> ref.getSheetName() != null)
                .toList();
        cellRefsWithSheetName.forEach(ref -> {
            CellReference refWithoutSheetName = new CellReference(ref.getRow(), ref.getCol());
            changedCells.add(refWithoutSheetName);
        });
        spreadsheet
                .fireEvent(new CellValueChangeEvent(spreadsheet, changedCells));
    }

The downside would be that a change to a single cell will report two changes in the event. Though that might be the lesser evil than relying on which CellReference constructor someone is using.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the latest version

@sonarcloud
Copy link

sonarcloud bot commented Feb 27, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@ugur-vaadin ugur-vaadin marked this pull request as ready for review February 28, 2023 06:51
@ugur-vaadin ugur-vaadin requested review from vursen and removed request for tomivirkki February 28, 2023 06:52
…uechangelistener-for-anything-else-than-text-input
@ugur-vaadin ugur-vaadin marked this pull request as draft June 30, 2023 09:20
@ugur-vaadin ugur-vaadin changed the title fix: use the same cell reference constructor in order to ensure consistency fix!: use the same cell reference constructor in order to ensure consistency Jul 3, 2023
@sonarcloud
Copy link

sonarcloud bot commented Jul 18, 2023

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 5 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@rolfsmeds
Copy link
Contributor

As we are not aware of any users having problems due to this issue, perhaps it would be better to wait until the next major as it will introduce some breaking changes?

@vursen vursen added the requires new major This would be a breaking change label Feb 28, 2024
@yuriy-fix
Copy link
Contributor

Added to the v25 breaking changes list to be revisited before v25.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
requires new major This would be a breaking change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Spreadsheet does not trigger addCellValueChangeListener for anything else than text input
5 participants