Issue with using ProtectContent - Spreadsheet gear - spreadsheetgear

I am trying to make a selected cells of my excel to be editable and rest to be readonly.
Following is my code, I am trying to set the Locked property for the specified rows to be "False" and trying to protect the sheet
excl.WorkSheet(0).Range[0, myColumns.Count, rowCount + 2, myColumns.Count].Locked = false; // Unlock cells to not make them read-only by ProtectContents
excl.WorkSheet(0).ProtectContents = true; //Make all the locked cells read only
Say rowCount = 5, I would like to have the entire rows between 0-6 to be editable, but the rest of the fields in the workbook to be read-only.
But, the entire sheet ends up being protected rather than the cells that are locked only.
Can anyone please help me fix this

I did this and was able to achieve what I wanted, but I am eager to know any other way to do this as well
IRange rows = excl.WorkSheet(0).Cells[rowStart, myColumns.Count].EntireRow;
rows.Locked = false;
excl.WorkSheet(0).ProtectContents = true;

Related

Google Sheets: Conditionally Shade an Individual Set of Repeating Groups of Cells Based on Value

I have a Google Sheet I use to document my quotes for customers. I've copied and pasted it down the sheet several times. Within each quote is a list validated field where the options are "Won" or "Lost." When I select "Won," I want to turn that background color of JUST that quote green. However, I also only want to shade green the fields that I am not entering text into or accomplishing the calculations on (the data fields); I want to shade the background of the "form" and the "labels." (See screenshot where I did this by hand.)
I've attempted do this myself, but I'm having two issues.
I have to create separate conditional format rules for each quote/group of cells. This is tedious. I'd like, if possible, to create one rule that is able to adapt the conditional test of ="Won" to each group/quote separately.
I have to individually select each and every cell to be highlighted because if I just do A1:G33, all of the cells change color, even the ones in black and gray. I know this is expected, but is there a way around it?
I'm confused why applying the rule to the first group and copying and pasting it doesn't work. All of the quotes change green if the first quote shows "Won." This functionality works correctly with the built-in conditions that test the value of the cell itself. However, custom formulas to test the value of another cell don't "repeat" and operate individually it seems.
EDIT: Link to spreadsheet: https://docs.google.com/spreadsheets/d/1OH16NXLiRzY3-EdZaxmUl5Vp6cQNPzY-_-LV7VIDl8U/edit#gid=983650786
in your case perhaps best would be to color the first table exactly as you wish and then select it, copy it, select the first cell of the next table and:
Use Apps Script
This way you can have a lot of flexibility and its easier to manage.
You seem to already have an onEdit trigger, so you could integrate some more logic into that to test for statues. I can't implement everything you want but this should get you well on the way.
function onEdit(e){
// Getting the information on the edited cell
let editedCell = e.range;
let sheet = editedCell.getSheet()
// If the edited cell is in column 6, in "Quotes" and is value "Won"
if (editedCell.getColumn() == 6 && sheet.getName() == "Quotes" && editedCell.getValue() == "Won") {
// Get the row to know where to change the format
let statusRow = editedCell.getRow();
// Get the range of the whole form
let formRange = sheet.getRange(statusRow, 3, 17, 6)
// Set the background color
formRange.setBackground("green")
}
}
Hopefully you can see how you might extend this to include other ranges. You would need to base everything of the position of the edited cell. I have identified it by its column, the sheet that contains it, and its value. You can extend this to include checks on the value next to it for example. Then to change the color of each black box, you would need to define a range for each, relative to the edited cell.
References
setBackgroundColor
getRange

Changing background color of a listbox's cell

Working on a desktop application and having a probably silly problem that's still managing to driving me mad.
I have a listbox that gets its rows from a dynamic source.
I'm trying to change the forecolor of specific cells in the control if the underlying data for that cell changes to specific conditions.
The control also gets drawn once before the condition starts being checked,meaning every cells starts painted with the same (white) forecolor.
Also, this listbox sits inside a Canvas, and that Canvas is in turn inside a Window control.
This code checks for the condition vs. all the rows in the listbox:
for each dict as Dictionary in WidgetsDictionary
Dim site as String = dict.Value("Site").StringValue
Dim device as String = dict.Value("Device").StringValue
Dim sensor as String = dict.Value("Sensor").StringValue
for intC as integer = 0 to actualLstBox.ListCount
Dim siteComp as String = actualLstBox.Cell(intC,4)
Dim deviceComp as String = actualLstBox.Cell(intC,0)
Dim sensorComp as String = actualLstBox.Cell(intC,1)
if actualLstBox.Cell(intC,4) = site AND
actualLstBox.Cell(intC,1) = sensor AND
actualLstBox.Cell(intC,0) = device then
actualLstBox.CellTag(intC,2) = RGB(255, 192, 203)
exit For
end
next
next
Where WidgetsDictionary contains the conditions I need to check against.
And that works,if i check the CellTags after it runs I find them set correctly where they are supposed to be.
Now,if after that code i call
actualLstBox.Refresh()
Note: I know Refresh isn't optimal but I need it to fire as soon as possible
I see the code jumping to the CellBackgroundPaint event of the ListBox
There I have this
If (row<me.ListCount ) then
If Me.CellTag(row, column ) <>nil Then
g.ForeColor = me.CellTag(row,column)
g.FillRect(0, 0, g.Width, g.Height)
End If
end
And again, I see this code executing correctly.
So, I'd expect the list to be redrawn with the correct cells in the new color.
But nothing changes, I see the CellBackgroundPaint event fire after every refresh but the end result shown is always the default (white) colored cells.
I've tried calling, in order
InvalidateCell on the specific cell
Invalidate on the whole Listbox instead of Refresh (since you never know)
Refresh on the containing Canvas
After the first block of code,to no avail.
So now I'm at a loss on what to try next.
Edit
If i replace the event handler with
If (row mod 2) = 0 Then
g.ForeColor = RGB(232,235,255)
g.FillRect 0, 0, g.Width, g.Height
End If
if column = 2 then
g.ForeColor = RGB(255,253,208)
g.FillRect 0, 0, g.Width, g.Height
end
I get alternating colors for the rows and the whole 3rd column of a different colour.
So I guess the fact that I'm trying to repaint it after the first time it's shown is where the problem lies.
You need to return true from the handler in order to tell Xojo that you already have do e the painting. Otherwise Xojo will do its own FillRect after yours.
Keep in mind that this will also override the selection coloring. Meaning that if the row is selected, your cell won't show that unless you either return false in that case or draw your own special bg color for that case.
Also, what you are talking about is the background color, not foreground color, it seems to me. You could perhaps update your question title accordingly.

How To Detect Which Cells Are Merged In Google Sheets

While trying to remove duplicate phone numbers from a relatively large list I recently combined, Google Sheets presented me with this error message:
There was a problem.
Your selection contains a merged cell. To remove duplicates, all cells must contain the same number of rows and columns.
The formula I used to test and try to expose merged cells within Google sheets was:
=if(columns(A2:F2) = 6, "True", "False")
But this always returned true Because even though the cells may be merged they are still considered individual cells.
I am wondering if there is an easy way to discover and sort out these cells in Google Sheets. Excel used to have a very simple way of doing it but has since removed the functionality.
Any ideas?
if you have such an option you can use Conditional Formatting to check for merged cells like:
=MOD(COLUMN(),2)=0
where you can immediately spot merged cells where the color pattern is interrupted
in the same manner you can use this formula for rows:
=MOD(ROW(),2)=0
or you can play with scripts to find merged cells: https://issuetracker.google.com/issues/36753230
Custom formula
function isMerge(sheetName, a1Notation) {
var range = SpreadsheetApp.getActive().getSheetByName(sheetName).getRange(a1Notation);
var merges = [];
for (var i = 0; i < range.getHeight(); i++)
{
var merge = range.offset(i, 0, 1, 1).isPartOfMerge();
merges.push(merge);
}
return merges;
}
Usage:
Paste the code above to the Editor: menu Tools > Script Editor...
Save Project
Use as usual formula: =isMerge(sheetName, a1Notation)
you can copy and paste the column somewhere, for example creating an extra column next to it.
You can then create a new column. You can run increasing numbers in both and subtract each cell from each other. If the result is not 0, then cells have been merged.
I was facing a similar issue and found a hack - ctrl+shift+down button to select all the data in the column. This automatically became a selection of two columns (the one I want to select plus the one next to it). I then worked from the bottom of the list up, using ctrl+shift+down button to select all data in that column, starting from the bottom 20 entries - with this, only data in that column was select - it didn't automatically include the next row too, which meant that the merged cell was not within these cells.
I repeated this step, going up the rows ~50 rows at a time, until the selection suddenly became two rows instead, when I was actually just selecting a single row's data. This meant that the merged cell was somewhere in the last 50 rows, and I just went down the list within that selection to check for the merged cell.

Calling refreshCells() with list of 3000+ cells makes vaading spreadsheet non responsive

I am using vaadin spreadsheet addon version 1.1.6. In my project sheets in workbook will have minimum 40 rows and 60 columns. When user navigates between sheets I need to update cellstyles of around 3000+ cells. After applying styles I need to refresh the cells to see the changes in UI. I am using Spreadsheet.refreshCells() to refresh cells. Once I make this call UI hangs and I get a message in browser that cache.js is not responding. I would like to know if anyone facing this issue and found the resolution?
Not sure if it a proper solution but I have found a workaround for this problem. I think refreshCells() API in Spreadsheet can't handle large number of cells. Instead of refreshCells() I used Spreadsheet.getSpreadsheetStyleFactory().cellStyleUpdated(). Find sample code below
for(int i=0; i< row.getPhysicalNumberOfCells();i++)
{
Cell cell = row.getCell(i);
CellStyle cellStyle = cell.getCellStyle();
/*
Apply Styles here
*/
spreadsheet.getSpreadsheetStyleFactory().cellStyleUpdated(cell, true);
}

Force conditional formatting apply

I have a google spreadseet table with conditional background formatting rules on it. I also have a function that autosort sheet when user change a cell (it's a list of tasks with priorities). Unfortunately, the autosorting can somehow set a wrong background for cells which can be fixed manually by selecting a column and then clicking "background->reset parameters" button. I need to do the same with script automatically to keep correct backgrounding of cells. How do I force google-spreadsheet to re-render cells with its conditional formatting rules?
Autosorting function:
function onEdit(event){
var sheet = event.source.getActiveSheet();
var editedCell = sheet.getActiveCell();
var columnToSortBy = 1;
var tableRange = "A2:Z1000";
if(editedCell.getColumn() == columnToSortBy){
var range = sheet.getRange(tableRange);
range.sort( { column : columnToSortBy, ascending: false } );
// code below doesn't help to solve the problem:
//var statusRange = sheet.getRange("B2:B1000");
//statusRange.clear({formatOnly: true})
//statusRange.clearFormat();
//SpreadsheetApp.flush()
}
}
What is possibly happening is that you have applied conditional formatting to a range of cells.
When your sheet is sorted by a script some/all of the cells may be affected because the range the conditional formatting applies to is being moved.
I will try to answer your question but I think you may be looking at the problem from the wrong angle. Given that your table is huge, entire page except header row? You could be applying the conditional formatting incorrectly. If it is acting on the whole page then reordering the page should not affect it. I have seen similar problems when rows are added or deleted within a formatting range. So if you want to post your formatting rules I may spot something there.
Getting back to your questions.
var range = sheet.getRange(tableRange); is correct.
I don't think you can use
statusRange.clear({formatOnly: true})
statusRange.clearFormat();
because .clear and .clearFormat are applied to the sheet.
Your table looks like it is taking up the entire sheet except for a header row? If so then try.
sheet.clearFormat();
This will clear your sheet formats so you are now left with white background colour.
Now, I do not know any way of using a script to set conditional formatting rules directly. I do have two possible solutions that I have used myself.
Abandon conditional formatting and set the format you want with a script.
You can set various cell formats directly, one of the the Background colour.
I don't know hoe you want to do this, your logic, but there are several functions to do this with CSS or RGB or to set a range to different colours.
When you have selected your cell or range you can use
range.setBackground("red");
red can be replaced with notation e.g. '#ff0000'.
Use a hidden conditional formatting template .
After your header row create another row. So adjust your table range to
var tableRange = "A3:Z1000";
Now row 2 becomes your template. Set the conditional formatting rules you want in row 2 and hide the row. Don't clear the formatting, instead copy the format form row 2 over the page.
var sheet = event.source.getActiveSheet();
var source = sheet.getRange(2,1,1,26); // Gets row 2
source.copyFormatToRange(sheet, 1, 26, 3, 1000); // will repeat down rows.

Resources