It is possible to set or change aliases only in last spreadsheet.
My knowledge of python very low and I dont know how to resolve this problem.
That's a known limitation of the macro. You can only have one spreadsheet open at a time or else the macro can get confused and apply things to the wrong sheet. It has been a while since I worked on the macro. I would need to study the code to refresh my memory. As I recall, the sheet object is being accessed from Qt while the FreeCAD document object is accessed from the FreeCAD Gui Selection API. It was difficult to figure out which Qt object belonged to the selected document object in the combo view, so the workaround was to check if multiple sheets were open and if so then just give the message you saw and exit the macro. You just need to close the other sheet window while you apply the aliases to one of the sheets.
This is one of the many things I fixed in my improved version of the macro, see my post here:TheMarkster wrote: ↑Mon Oct 10, 2022 5:28 pm That's a known limitation of the macro. You can only have one spreadsheet open at a time or else the macro can get confused and apply things to the wrong sheet.
I also wanted to fix some things in the script and I got a version that automatically selects the spreadsheet when there's only one and also works on multiple columns (and larger than Z). However, your code is betterrosta wrote: ↑Thu Oct 20, 2022 5:08 pmThis is one of the many things I fixed in my improved version of the macro, see my post here:TheMarkster wrote: ↑Mon Oct 10, 2022 5:28 pm That's a known limitation of the macro. You can only have one spreadsheet open at a time or else the macro can get confused and apply things to the wrong sheet.
https://forum.freecadweb.org/viewtopic. ... 15#p627015
Maybe you want to try out my version?
Code: Select all
# -*- coding: utf-8 -*-
import FreeCAD
from PySide import QtGui
"""
EasyAlias.FCMacro.py
This macro can be used to easily create aliases based on the content of selected spreadsheet
cells in the previous column. As an example, suppose you wish to have the following:
A1: content = 'radius', B1: content = '5', alias = 'radius'
A2: content = 'height', B1: content = '15', alias = 'height'
The traditional way to set this up would be:
Select A1
Enter radius
Select B1
Enter 5
Right-click B1
Select properties
Select Alias
Enter radius
click OK
Select A2
Enter height
Select B2
Enter 15
Right-click B2
Select Properties
Select Alias
Enter height
Click OK
Using this macro, the work flow becomes:
Select A1
Enter radius
Select B1
Enter 5
Select A2
Enter height
Select B2
Enter 15
Select A1 through A2
Run the EasyAlias macro
Done
"""
__title__ = "EasyAlias"
__author__ = "TheMarkster"
__url__ = "https://wiki.freecadweb.org/Macro_EasyAlias"
__Wiki__ = "https://wiki.freecadweb.org/Macro_EasyAlias"
__date__ = "2022.07.31" #year.month.date
__version__ = __date__
def getSelectedIndexes():
""" Returns a QModelIndex object or None if none are selected
use [0] to get at first cell in the selection
use [0].row() to get first cell's row
use [0].column() to get first cell's column
use [-1] to get last cell in the selection
"""
mw=FreeCADGui.getMainWindow()
mdiarea=mw.findChild(QtGui.QMdiArea)
subw=mdiarea.subWindowList()
widgets = []
for i in subw:
if i.widget().metaObject().className() == "SpreadsheetGui::SheetView":
widgets.append(i.widget())
if len(widgets) > 1:
FreeCAD.Console.PrintError("Having more than one spreadsheet view open at a time can confuse the macro. Close the other sheet views and try again\n")
return None
elif len(widgets) == 1:
return widgets[0].findChild(QtGui.QTableView).selectedIndexes()
return None
def getSelectedCells():
""" Returns selected cell addresses in the form of a list of tuples (selectedAddress, nextCellAddress)
or an empty list if none selected. Works if multiple columns are selected.
"""
sel = getSelectedIndexes()
if not sel:
return []
cellAddresses = [] #will be list of tuples in form of (selectedAddress, nextCellAddress)
for c in sel:
addr = cellIndexToAddress(c.row(), c.column())
addr_next = cellIndexToAddress(c.row(), c.column()+1)
cellAddresses.append((addr, addr_next))
return cellAddresses
def getSpreadsheet():
""" Return first selected spreadsheet object in document or None if none selected.
"""
# If there is a single spreadsheet in the active document just return it even if not selected
cnt = 0
ss = None
for o in FreeCADGui.ActiveDocument.Document.Objects:
if 'Spreadsheet::Sheet' in o.TypeId:
ss = o
cnt += 1
if cnt == 1:
return ss
# Throw an exception if there are no spreadsheets in the document
if cnt == 0:
raise Exception('No spreadsheet in this document!')
# If multiple exist, check which one is selected
selObj = FreeCADGui.Selection.getSelectionEx()
if not selObj:
return None
for obj in selObj:
if 'Spreadsheet::Sheet' in obj.Object.TypeId:
return obj.Object
elif "App::Link" in obj.Object.TypeId:
if 'Spreadsheet::Sheet' in obj.Object.LinkedObject.TypeId:
return obj.Object.LinkedObject
def cellIndexToAddress(r, c):
""" Get the spreadsheet cell address (e.g. A5 or AB10) from a combination
of row and column (with starting index 0).
"""
# Check if the column is larger than 26 ("tens" in base 26 is larger than 0)
ct = c // 26
address = '' if ct==0 else chr(64+ct) # ASCII for 'A' is 65
# Add the rest of the column name ("units" in base 26)
cu = c % 26
address += chr(65+cu)
# Add the row
address += str(r+1)
return address
#thanks to Ouriço for this modification to allow parentheses to define the alias
#within the substring
def getAlias(sheet, cellAddr):
""" Get the alias from the cell contents. If there are parentheses will use
the text between the parentheses
"""
val = sheet.getContents(cellAddr)
alias = val.replace(' ','_').replace('.','_')
# extract any text between () and use that as the alias.
# If brackets not found then use the original alias.
firstidx = alias.find('(')
secondidx = alias.find(')')
if 0 <= firstidx < secondidx:
alias = alias[firstidx + 1 : secondidx]
return alias
FreeCAD.Console.PrintMessage('*** Start EasyAlias ***\n')
s = getSpreadsheet()
if not s:
raise Exception('No spreadsheet selected. Please select a spreadsheet in the tree view.')
cellAddresses = getSelectedCells()
if len(cellAddresses) == 0:
FreeCAD.Console.PrintWarning("Unable to get selected cells. Are any cells selected?\n")
s.Document.openTransaction("EasyAlias")
for ca in cellAddresses:
addr, addr_nextcol = ca
# credit to red6rick for this bit of code to allow for skipped rows
alias = getAlias(s, addr)
if alias:
try:
#FreeCAD.Console.PrintMessage(f"Setting alias: {s.Label}[{addr_nextcol}] ---> {alias}\n")
s.setAlias(addr_nextcol, alias) #use e.g. content of A5 as alias for B5
except Exception as e:
FreeCAD.Console.PrintError(f"*** Unable to set alias '{alias}' for '{s.Label}[{addr_nextcol}]'\n")
FreeCAD.Console.PrintError(f"Error: {e}\n")
FreeCAD.Console.PrintError("Remember, aliases cannot begin with a numeral or an underscore or contain any invalid characters.\n")
else:
FreeCAD.Console.PrintWarning(f"Skip empty cell {addr}\n")
s.Document.commitTransaction()
App.ActiveDocument.recompute()
Thank you for the compliment!
I'll take a look at your code this afternoon if I can or maybe tomorrow.
That's rather old, and fixes will most probably not be made to/for this ancient version. Can you upgrade to 0.20 or even 0.21?