VBA Word : SmartArts and range - vba

I'm currently working with SmartArts in Word.
The SmartArt already exists, and I would like to find a way to access a SmartArt value from a range, Office cursor (so Selection) or something akin to it.
Here's my SmartArt.
To be exact, the SmartArtLayout is Application.SmartArtLayouts(88)
What I can do already :
Create a SmartArt on my Document, keep it as a Shape to work on it.
Looping on all the Nodes of my SmartArt, selecting the ones I want to keep, and inserting the ones I want to keep in a database, with a link to their parent.
Now I'm blocked on something.
I want to find a Way to edit/delete a particular node, both in DB and in the SmartArt.
It would be possible if I made a Userform that put every Shape Text in a drop-down list, and I then looped on all shapes to find the shape with the chosen text in it.
If noone answers, that'll probably be what I am going to do.
But I don't find this way natural or practical.
So I'm looking for a method to be able to find the Node that have the cursor on it. I would've done something like that :
'Putting my SmartArt in SAShape
For Each Node In SAShape.SmartArt.AllNodes
If (Selection.Range.InRange(Node.Range)) Then
'my code
End If
Next Node
But It'd have been too easy... The shapes don't seem to have a range.
Is there a way to get the Node with focus, or to get the node we clicked on?
Thanks in advance!
Cordially,

firt It not like Question but it is task but i will give you some hint to help you
1) to get any node in any level loop will be like this
Set oShape = ActiveSheet.Shapes(1)
For i = 1 To oShape.SmartArt.AllNodes.Count
oShape.SmartArt.AllNodes(i).TextFrame2.TextRange.Text = "Sample " & i
Next
2)To Get specific node for delete or edit you must determine an id i can not do that perfect but i assign the id to alt text when i add alt text i can find any node
2.1) when shearch
nod.TextFrame2.TextRange.Text = str
nod.Shapes(1).AlternativeText = index
2.2) when check for search
If oShape.SmartArt.AllNodes(i).Shapes(1).AlternativeText = index
and the imge will show where alt store
that i think will help you in some way for do what you need but you must understand how smart art tree change after item delete
smartart

Related

How to select current row in SAP GUI Grid View with VBA Macro?

I am trying to automate a repetitive task in the SAP GUI. I need to search for an order number, select the row that the order number is in and then click a button to complete the task. I have recorded a macro which gives me:
session.findById("wnd[0]").maximize
session.findById("wnd[0]/usr/cntlCONTAINER/shellcont/shell").pressToolbarButton "&FIND"
session.findById("wnd[1]/usr/txtGS_SEARCH-VALUE").text = "4521305207"
session.findById("wnd[1]/usr/txtGS_SEARCH-VALUE").caretPosition = 10
session.findById("wnd[1]/tbar[0]/btn[0]").press
session.findById("wnd[1]/tbar[0]/btn[12]").press
session.findById("wnd[0]/usr/cntlCONTAINER/shellcont/shell").currentCellColumn = ""
session.findById("wnd[0]/usr/cntlCONTAINER/shellcont/shell").selectedRows = "2894"
session.findById("wnd[0]/tbar[1]/btn[14]").press
session.findById("wnd[1]/usr/chk[1,6]").selected = true
The line:
session.findById("wnd[1]/usr/txtGS_SEARCH-VALUE").text = "4521305207"
Corresponds to the order I want to search, but if I change this value it still tries to process the same order that the macro was recorded on, I'm assuming because of the line:
session.findById("wnd[0]/usr/cntlCONTAINER/shellcont/shell").selectedRows = "2894"
Does anyone know how I would go about finding the number of the row which corresponds to the outcome of the SEARCH-VALUE and then using that as the .selectedRows = ""?
First of all I'd really recommend you add a reference to the native SAP library. Go to your VBA Editor, click Tools, then References, then Browse, and find this file: "C:\Program Files\SAP\FrontEnd\SAPgui\sapfewse.ocx". Add it, and now you'll have types and libraries and coding for SAP will be a lot easier, safer, and slightly faster (Variant types in VBA impose a tiny overhead that in this case is totally unnecessary). Get familiar with this new library if you are going to do any SAP scripting more than once.
Second, about this problem, what you have is a shell, of type GuiShell, which inherits from GuiGridView. GuiGridView looks like a table, a classic Excel-like set of rows and columns. In your transaction, is showing you a big list of orders, in which you go click the "Find" button, put the order you're looking for, and then close the Search Window. Back to your (Grid)Shell, this cell has been selected (Grid has properties SelectedCells, SelectedRows, SelectedColumns that get all set when you go find something), but then you go and modify the value of SelectedRows to a specific one.
So yeah, upon find, a cell has been selected, so all you need is to query its row and then assign it where you need:
Dim numrRow As Long
numrRow = session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell").CurrentCellRow
session.FindById("wnd[0]/usr/cntlGRID1/shellcont/shell").SelectedRows = numrRow
where "thisShell" is however you do to find a reference to the Shell (session.findByID("blabla") for example, but I'd advise to reduce all the findByID's, they're very slow and type-unsafe).
If you need help about this SAP libraries, feel free to maybe make some new post and ping me on the comments about it.

Working with multiple discontinuous selection

I'm trying to do something with a multiple selection. I wanna add some text before every selected paragraph but, when I select multiple discontinuous paragraphs, if I do Selection.Paragraphs.Count I always get "1".
How could I work with all paragraphs apart?
Example:
Paragraph1(Selected first)
Paragraph2
Paragraph3(Selected second)
What I got when I try to add some text at the beginning of these paragraphs:
Paragraph1
Paragraph2
TEXTParagraph3
What I really want to obtain:
TEXTParagraph1
Paragraph2
TEXTParagraph3
I'm working like this:
sub x()
dim p as paragraph
for each p in selection.paragraphs
p.range.insertbefore("TEXT")
next
End sub
Word simply cannot do what you'd like for it to do. Developers have wished for this since multiple selections were introduced in 2003 (I think it was, might have been version 2007). Word's object model simply does not support it.
If this is something you want to provide to the user to make life easier you'll need to give the tool a way to mark the paragraphs so your code can recognize them. You could provide a macro, for example, that assigns an incrementing bookmark name to each selection (the user selects, then runs your macro; repeat for each paragraph). Your code can then address each bookmark and perform the actions. To make this more user friendly you can assign the macro to a keyboard shortcut and/or a button in the Ribbon/QAT and/or the right-click menu.

How can i set the name of a textbox in publisher?

I want to set the name of the text box so it can be easily accessed by code.
e.g
I am looking for an editing field similar to this
Thanks
There's a properties Window that can be accessed for each of the controls on the UI. There you may rename the controls. (Since you do not seem to have a VBA code yet and you want to rename the control from UI)
The other alternative. Record a macro, do some changes to the textbox (e.g. resize, change text etc). Then check the programme assigned default name of the textbox from the VBA editor. As you said, you can access the control via this default name and utilizing your VBA code (as you said), rename the textbox.
If you really want to be editing a worksheet object in Publisher you will have to get the OLEobject of the Shape and interpret it as an Excel.Application.
If you are just looking for a placeholder solution for Publisher documents, you could simply create a textbox that contains a certain string, then loop through all pages, all shapes on each page where HasTextFrame = msoTrue, and compare shape.TextFrame.TextRange.Text to your placeholder string. If it's the one you're after, you can do anything you want with the shape in question.
Sorry for the vague answer, but your images don't work anymore.
Edit: you can work with Shape.Name for your comparison (you mentioned this property in a comment), but I have no idea how you'd set the value from the interface, without using VBA, in the first place, so if you're making templates the approach I outlined above might be easier for users (see https://msdn.microsoft.com/EN-US/library/office/ff939233.aspx for Shape.Name). There is also a .Name property for page objects (https://msdn.microsoft.com/EN-US/library/office/ff940382.aspx), so you should be able to do something like ActiveDocument.Pages("page_name").Shapes("shape_name").TextRange.Text = "your content" once you've figured out how to actually set the name values
Edit 2:
You can also try to use search and replace as per Replacing Text in Microsoft Publisher Using Powershell if you don't need to do anything advanced beyond placing some text
Edit 3: Given the title of your question, unless you can figure something out with Publisher's interface, you can set the .Name property of the selected text box (or other shape) with dim shape = Selection.ShapeRange.TextFrame.Parent and shape.Name = "your_name". You can set the name of the selected page with ActiveDocument.ActiveView.ActivePage.Name="your_name". (Create a VBA macro that prompts you for names and you should be good to go)

Visio VBA copy/cut/paste intercept

I have another challenge. Has anyone tried to intercept the copy/paste events? My goal is to prevent someone from cut/copy/paste a shape that is already on a sheet. If they drag it from a stencil, that is fine. I just can't have them duplicate an existing shape. To make this a bit harder, it is only the shape that I need to prevent. If the want to copy text, that is fine.
We have a order type database that contains items that need to be dropped on a Visio sheet. I cannot use the shapeID because I need to be able to update the shape from the database and I can't write the ID back to the database as it is against security policy. The way that I am tying the two together is a property named shapeKey and that value is provided by the database at the time the shape is dropped.
When a use needs to refresh the sheet from the database, I interate through the shapes, comparing the shapeKey in the shape and in the database. if there is a match, I do an update of the other properties. If there is no match, I want to delete the shape. if a user copies a shape, the shapeKey will also be duplicated and that causes problems. Lastly, they can add their own shapes from stencils and those shapes must be excluded from the delete process
I have two options:
Disable shape cut/copy/paste
Intercept the copy/cut and when they paste, change a property so that I know that it was a user pasted shape. This is preferred because it is more user friendly
I just thought if another way I that might work. Is there a way to lock the shapes to prevent the copy? If there is a lock, would that also lock the location? The user needs to be able to most the shapes around.
I thought about capturing the event but I could not find the event codes to look for. I cannot install the Visio SDK which has the Event monitor. The monitor might have shown me the code. Here is some pseudo code as to what I think would be the flow.
option 1
if select item is a shape then
msgbox "shape copying verboten. please us the stencil"
clear selected item
option 2
capture the paste event
if selected item is a shape then
vsoShape.Cells("Prop.ShapeKey").Formula = Chr(34) & "protect" & Chr(34)
Layers might work. All the database controlled shapes can be on one layers and all the user shapes on another but I haven't worked with layers before. would that work? How can I be sure that any shape pasted goes onto the user layer?
Thanks all! I did find a solution and it was really elegant. I found the idea here and changed it to what I needed:
Shape added event: https://msdn.microsoft.com/en-us/library/office/ff767288.aspx
Here is what I came up with:
Private Sub Document_ShapeAdded(ByVal vsoShape As Visio.IVShape)
If vsoShape.CellExistsU("Prop.ShapeName", 0) Then
vsoShape.CellsU("Prop.ShapeName").Formula = Chr(34) & "ShapeName" & Chr(34)
End If
End Sub
The interesting thing is that it doesn't fire if I add the shape via VBA. That is perfect for what I need but I would have thought that dropping a shape is adding a shape. I am only looking for one property because not all shapes on the stencils come from a database and for those objects, I don't need to do anything.
It was not the solution that I expected but it works really well.

How to delete the last return in a PowerPoint field?

I have created a function that allows a user to import one or more text files into a field in PowerPoint. This works really well. The user clicks in the field, clicks the button on the custom menu, selects the files from a list and in they go. The problem I have is that I have to put two returns between each imported text, which means there are two left on the end.
This is the usual result to delete a paragraph I have found:
ActiveWindow.Selection.ShapeRange.TextFrame.TextRange.Characters(Start:=27, Length:=1).Select
ActiveWindow.Selection.TextRange.Text = ""
This suggests I would have to calculate the last position int he selected field to be able to delete it.
Could anyone give me an idea of how I would go about this?
This solution is a bit easier (not tested):
dim tmpTXT as string
tmpTXT = ActiveWindow.Selection.ShapeRange.TextFrame.TextRange.Text
ActiveWindow.Selection.ShapeRange.TextFrame.TextRange.Text = Left(tmpTXT, len(tmpTXT) -1)
You could do something similar earlier, before you write text to your shape which would be better.