Create a Unique ID for a Visio Shape use the Shape Sheet - visio

I'm not new to Visio nor to programming but I am new to developing in Visio.
I'm using 2007 and am creating my own custom shapes with Shape Data.
I want to create a UniqueID for all my shapes in the context of the drawing.
I have created a Shape data element called 'Shape UniqueID'. (ShapeSheet Prop.Shape_Unique_ID)
I tried to generate a unique ID (Shape.UniqueID property), using the formula syntax below, in the ShapeSheet 'Value' cell for the property :
=UniqueID(visGetOrMakeGUID) and =UniqueID(1)
But Visio does not recognize this as a valid Formula..
I also tried to use DATA1():
=Guard(Data1())
That gives me a unique value BUT it does not update if you copy the shape.
I've dowloaded the 2007 SDK and can't find a Shapesheet function to read the properties.
I have also seen that you can set the page so UniqueIDs are always on shapes used but I can't figure out how to turn it on.
My "preference" is to use a Shape Data element and set it BUT......
Any Ideas would be appreciated?
Thanks ... Scott

[Note this answer is rough duplicate of the one here ]
UniqueIDs are only accessible in code, ie, there's no ShapeSheet function that'll return a unique ID (GUID).
By default a shape starts off without a UniqueID so you have to assign it in code. Some shapes such as the off page connector shape store the unique IDs in the ShapeSheet so that they can track which shape is connected to which, but this is managed by an addon.
You can store a GUID in a ShapeSheet cell (usually a User cell), but generally if you have a reference to a shape to read a cell then you also have the means to read the .UniqueID property as well. If you're looking for other ways to identify a shape then shp.ID (or the ID() ShapeSheet function) will return an ID that's unique to the page, so that may be something to consider as well
Here's some sample code that demonstrates how to use UniqueIDs:
Sub UniqueIDsDemo()
Dim vPag As Page
Set vPag = ActivePage
Dim vShp As Shape
Set vShp = vPag.DrawRectangle(1, 1, 1, 1)
Debug.Print vShp.NameID & " UniqueID = '" & vShp.UniqueID(visGetGUID) & "'"
Dim sGUID As String
sGUID = vShp.UniqueID(visGetOrMakeGUID)
Debug.Print vShp.NameID & " UniqueID = '" & vShp.UniqueID(visGetGUID) & "'"
vShp.AddSection visSectionUser
Dim rowIdx As Integer
Dim cellName As String
cellName = "UniqueID"
rowIdx = vShp.AddNamedRow(visSectionUser, cellName, visTagDefault)
vShp.CellsSRC(visSectionUser, rowIdx, visUserValue).FormulaU = sGUID
Debug.Print vShp.NameID & "!User." & cellName & " = '" & vShp.CellsU("User." & cellName).ResultStrU("") & "'"
End Sub

Related

insert and delete text after an Range-position in Word

I have a SET-field in Word 2007. After the set-field there could be everything (text,bookmark, SET field,...). I want to add a text (e.g. "exampletext") in between.
After this I want to delete this inserted text (but I don't want to search through the whole document).
Is there a method?
Trial 1 (it inserts it in the field - and not after the field):
' xStartReturn is a field
Dim myExampletext As WordApp.Range = objDoc.Range(xStartReturn.Code.End, xStartReturn.Code.End )
myExampletext.Text = "exampletext"
Trial 2 (leads to the problem that I don't get the Range-field to delete the exampletext afterwards):
xEndeReturn.insertAfter("exampletext")
Trial 3:
'xStartReturn.Code.End + 1 doesn't work.. but I found out that the "}"-Sign in the setField is +20 after xStartReturn.Code.End. Theoretical this should work - but there could be e.g. also paragraph afterwards.
'-> I can automatically check that there is a paragraph - but why is the exampletext added **after** the paragraph?
Dim example As WordApp.Range = objDoc.Range(xStartReturn.Code.End + 20, xStartReturn.Code.End + 20)
example.Text = "exampletext"
Dim later As WordApp.Range = objBasisvorlage_.Range(objXStartReturn.Code.End + 20, objXStartReturn.Code.End + 20 + "SDFSD".Length) 'this is wrong?!
later.Delete()
The following works for me. Since you didn't give us a minimum code with which to reproduce the problem I don't know how relevant the framework is that I used. But you should be able to follow the steps.
Watch what I do with r_f_Code (field code range). You can ignore/remove r_f_Result as I had that in for reference and debugging purposes.
Collapsing the field code range to its end-point leaves the range just within the field braces. Moving the starting point one character to the right puts it just outside the braces, but before anything else. (Note: I tested with two immediately adjacent SET fields.)
My code then enters some text and bookmarks it. That's the only way you do what you ask if what follows the SET field can be "anything". Although I suppose you could insert a Content Control - that would be uniquely identifiable if you go about it correctly...
Sub PositionAfterFieldCode()
Dim f As word.Field
Dim r_f_Code As word.Range, r_f_Result As word.Range
For Each f In ActiveDocument.Fields
If f.Type = wdFieldSet Then
Set r_f_Code = f.code
Set r_f_Result = f.result
'Debug.Print Len(r_f_Code), r_f_Code.Text, Len(r_f_Result), r_f_Result.Text
r_f_Code.Collapse wdCollapseEnd
r_f_Code.MoveStart wdCharacter, 1
'r_f_Code.Select
r_f_Code.Text = "abc"
r_f_Code.Bookmarks.Add "AfterSet", r_f_Code
Exit For
End If
Next
End Sub

Using powershell to change an image in MS office publisher

I am creating a powershell script that will auto generate publisher files for wristbands. On the Wristband is a QR code and a few other details to personally identify the wearer. I currently have a template file set up, a script that copies this, renames it, and edits some of the text on the page.
What I need it the script to change the placeholder image in the template to a QR code image, the data in the QR is only every going to be from a set amount of images (one of 1800), all have been generated and named to match up with the names used in Powershell.
Has anyone changed an image in MS Publisher using powershell before? Below is the code I currently have.
$CurrentMember = "M001S001"
$CurrectDocumet = "C:\Users\Rob\Documents\DistrictCamp2017\GeneratedFiles\" + $CurrentMember + ".pub"
copy-item "C:\Users\Rob\Documents\DistrictCamp2017\TemplateWristband.pub" "C:\Users\Rob\Documents\DistrictCamp2017\GeneratedFiles"
Rename-Item "C:\Users\Rob\Documents\DistrictCamp2017\GeneratedFiles\TemplateWristband.pub" "$CurrentMember.pub"
Add-Type -AssemblyName Microsoft.Office.Interop.Publisher
$Publisher = New-Object Microsoft.Office.Interop.Publisher.ApplicationClass
$OpenDoc = $Publisher.Open("C:\Users\Rob\Documents\DistrictCamp2017\GeneratedFiles\M001S001.pub")
###Replace Barcode and text
$pbReplaceScopeAll = 2
$OpenDoc.Find.Clear()
$OpenDoc.Find.FindText = "DEFAULT"
$OpenDoc.Find.ReplaceWithText = $CurrentMember
$OpenDoc.Find.ReplaceScope = "2" #$pbReplaceScopeAll
$OpenDoc.Find.Execute()
$OpenDoc.Save()
$OpenDoc.Close()
$Publisher.quit()
The image in the template document is currently a blank 145*145 pixel square, to be replaced by the appropriate QR code image, dependant on the value of $CurrentMember. I haven't yet written anything to try and change the image as I cannot find anything online, anything I search for seems to return results about Azure publisher server images.
Many thanks,
Rob
The easiest way is probably to get the shape by index, then add a new picture in its place, then remove the original shape:
Sub ReplaceFirstShapeWithImage()
Dim oPage As Page
Dim oShape As Shape
Dim newImage As Shape
Set oPage = Application.ActiveDocument.ActiveView.ActivePage
Set oShape = oPage.Shapes(1)
''https://msdn.microsoft.com/en-us/library/office/ff940072.aspx
Set newImage = oPage.Shapes.AddPicture("C:\Users\johanb\Pictures\X.png", msoFalse, msoTrue, oShape.Left, oShape.Top, oShape.Width, oShape.Height)
oShape.Delete
End Sub
This should help you find the right index
Sub GetIndexOfSelectedShape()
If Application.Selection.ShapeRange.Count = 0 Then
MsgBox "Please select a shape first"
Exit Sub
End If
Dim oShape As Shape
Dim oLoopShape As Shape
Dim i As Long
Set oShape = Application.Selection.ShapeRange(1)
For i = 1 To oShape.Parent.Shapes.Count
Set oLoopShape = oShape.Parent.Shapes(i)
If oLoopShape Is oShape Then
MsgBox oShape.Name & " has index " & i
End If
Next i
End Sub
Unfortunately I can't use PowerShell right now, but this VBA code should help you with the object model

LibreOffice Draw -add hyperlinks based on query table

I am using draw to mark up a pdf format index map. So in grid 99, the text hyperlinks to map99.pdf
There are 1000's of grid cells - is there a way for a (macro) to scan for text in a sheet that is like
Text in File | Link to add
99|file:///c:/maps/map99.pdf
100|file:///c:/maps/map100.pdf
and add links to the relevant file whenever the text is found (99,100 etc).
I don't use libre much but happy to implement any programatic solution.
Ok, after using xray to drill through enumerated content, I finally have the answer. The code needs to create a text field using a cursor. Here is a complete working solution:
Sub AddLinks
Dim oDocument As Object
Dim vDescriptor, vFound
Dim numText As String, tryNumText As Integer
Dim oDrawPages, oDrawPage
Dim oField, oCurs
Dim numChanged As Integer
oDocument = ThisComponent
oDrawPages = oDocument.getDrawPages()
oDrawPage = oDrawPages.getByIndex(0)
numChanged = 0
For tryNumText = 1 to 1000
vDescriptor = oDrawPage.createSearchDescriptor
With vDescriptor
'.SearchString = "[:digit:]+" 'Patterns work in search box but not here?
.SearchString = tryNumText
End With
vFound = oDrawPage.findFirst(vDescriptor)
If Not IsNull(vFound) Then
numText = vFound.getString()
oField = ThisComponent.createInstance("com.sun.star.text.TextField.URL")
oField.Representation = numText
oField.URL = numText & ".pdf"
vFound.setString("")
oCurs = vFound.getText().createTextCursorByRange(vFound)
oCurs.getText().insertTextContent(oCurs, oField, False)
numChanged = numChanged + 1
End If
Next tryNumText
MsgBox("Added " & numChanged & " links.")
End Sub
To save relative links, go to File -> Export as PDF -> Links and check Export URLs relative to file system.
I uploaded an example file here that works. For some reason your example file is hanging on my system -- maybe it's too large.
Replacing text with links is much easier in Writer than in Draw. However Writer does not open PDF files.
There is some related code at https://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=1401.

Conditional formatting on Access form looking up a value

I've created a form within Access which uses a cross-tab query as its data source.
The column headings for the query are 1, 2, 3, 4 and 5 representing week numbers.
The values display items such as 3/3 = 100.00% or 0/13 = 0.00% or 3/14 = 21.00%.
I've added conditional formatting to the text boxes on the form.
Expression Is Right([2],7)="100.00%" works and displays the figure in bold red when the percentage is 100.
Expression is Val(Right([2],7))=100 also works - converting the text value to a numeric value.
The problem I'm having is that I'm not always looking for 100% - it depends on the value within a table. What I'm trying to do is
Val(Right([2],7))=(SELECT ParamValue*100 FROM tbl_System WHERE Param='SampleSize') - this doesn't work.
Neither does:
Eval(Val(Right([2],7))=(SELECT ParamValue*100 FROM tbl_System WHERE Param='SampleSize'))
or
Val(Right([2],7))=EVAL(SELECT ParamValue*100 FROM tbl_System WHERE Param='SampleSize')
or
Val(Right([2],7))=DLookUp("ParamValue","tbl_System","Param= 'SampleSize'")*100
or
Val(Right([2],7))=Eval(DLookUp("ParamValue","tbl_System","Param= 'SampleSize'")*100)
The SQL for the cross-tab query is:
TRANSFORM NZ(Sum(Abs([Include])),0) & "/" & NZ(Count(*),0) & " = " &
FormatPercent(NZ(Round(Sum(Abs(Include))/Count(*),2),0),2)
SELECT tbl_TMP_PrimaryDataSelection.TeamMember
FROM tbl_TMP_PrimaryDataSelection
GROUP BY tbl_TMP_PrimaryDataSelection.TeamMember
PIVOT tbl_TMP_PrimaryDataSelection.WeekNum In (1,2,3,4,5)
I don't think you can use a function in there, be it system or user-defined.
But you can define the FormatCondition dynamically at runtime, like this:
Dim txtFld As TextBox
Dim objFrc As FormatCondition
Dim strExpr As String
Set txtFld = Me!myTextBox
' Remove existing FormatConditions
txtFld.FormatConditions.Delete
' The dynamic expression
strExpr = "Val(Right([2],7))=" & DLookUp("ParamValue","tbl_System","Param='SampleSize'")*100
' Assign a new FormatCondition to text box
Set objFrc = txtFld.FormatConditions.Add(acExpression, , strExpr)
' Set the format
objFrc.ForeColor = &HFF0000
This example simply removes and recreates all FormatConditions. If you have a fixed number of conditions, you can also use the FormatCondition.Modify method (see online help).
Edit:
The final code I have used executes on the Form_Load event and adds a format to each of the five weekly text boxes:
Private Sub Form_Load()
Dim aTxtBox(1 To 5) As TextBox
Dim x As Long
Dim oFrc As FormatCondition
Dim sExpr As String
With Me
Set aTxtBox(1) = .Wk1
Set aTxtBox(2) = .Wk2
Set aTxtBox(3) = .Wk3
Set aTxtBox(4) = .Wk4
Set aTxtBox(5) = .Wk5
For x = 1 To 5
aTxtBox(x).FormatConditions.Delete
sExpr = "Val(Right([" & x & "],7))>=" & DLookup("ParamValue", "tbl_System", "Param='SampleSize'") * 100
Set oFrc = aTxtBox(x).FormatConditions.Add(acExpression, , sExpr)
oFrc.ForeColor = RGB(255, 0, 0)
Next x
End With
End Sub
Edit 2
Yes, defining FormatConditions via VBA is especially useful when dealing with multiple controls in a loop. You can do this in Design View too and save the FormatConditions permanently, simply to avoid going through the FormatConditions dialogs one by one. Or if the customer later decides that he'd rather have a different color. :)
Note: You could use Set aTxtBox(x) = Me("Wk" & x) in the loop. But actually you don't need multiple TextBox variables, you can simply re-use it.

maskedEditColumn datagridview how to use class? is it what i need?

I am trying to mask user's input in a datagridview column and i found this ready class Masked edit column Class that adds a 'mask edit column' option in the column types list. When i select this column type a mask field is being added in the list of column properties. I tried to do my job by adding some mask elements in this 'Mask' field, but when I run the code it didnt restrict me from adding other characters. I re-opened the 'edit columns menu' and I saw that the 'Mask' field was empty.
I want the text cell to accept 20 chars maximum and only: 1.Capital Letters(English & Greek), 2.these three chars(.,-), 3.Numbers 0-9
So as a first test i used only this mask(>????????????????????) but it didnt work as it didnt convert my characters to Uppercase and accepted more than 20 chars when i end the cell edit.
i am not sure the way to go is the Masked Text Box way. i have made many projects on vb and i used to use a loop in the textChanged event of a text box to restrict characters entry. the loop is this : (but i cant use it now in the valueChanged event cause it seems that 'value' doesn't have a selectionStart property.)
Dim charactersDisallowed As String = "!##$%^&*()+=|}{][:;?/><.,~""
Dim theText As String = txtCopies.Text
Dim Letter As String
Dim SelectionIndex As Integer = txtCopies.SelectionStart
Dim Change As Integer
For x As Integer = 0 To txtCopies.Text.Length - 1
Letter = txtCopies.Text.Substring(x, 1)
If charactersDisallowed.Contains(Letter) Then
theText = theText.Replace(Letter, String.Empty)
Change = 1
End If
Next
txtCopies.Text = theText
txtCopies.Select(SelectionIndex - Change, 0)
So,
Is a masked text cell what i need? and if yes( Why is this mask box not keeping the mask i enter? And how can i use this class to do my job?)
What can i alternately do to restrict some characters in a column's cells? (I will then convert to Uppercase on cellEndEdit)
I finally did it by removing the unwanted characters on cellvaluechanged event, which seems that is being raised when I end the cell's edit by for example hitting "Enter".