multilevel list without indentation in word vba - vba

I have a macro that search [#] in document and make it list number, with multilevel. Each hashtag represent level number. i.e
[#] level 1 - - result - -> 1.
[##] level 2 -- result --> 1.1.
[###] level 3 -- result --> 1.1.1.
So it's working just fine. But I don't want my text to get indented instead remain in their indent level. as my text is in table so its get crazy when indented.
working code is here:
Sub Nummerierung_Numeric()
'Makro Written by M.B.A
Dim Level As Integer
With ActiveDocument.Range.Find 'or Selection.Range.Find
.Text = "\[#*\]"
.MatchWildcards = True
Do While .Execute
If .Parent.Information(wdWithInTable) Then
Level = Len(.Parent.Text) - 2
.Parent.Style = ActiveDocument.Styles("1 / 1.1 / 1.1.1")
.Parent.ListFormat.ListLevelNumber = Level
.Parent.Delete
End If
Loop
.MatchWildcards = False
End With
End Sub

You can modify the 1 / 1.1 / 1.1.1 style setting such that any paragraph using this style will not have indent but note that this might affect paragraphs that you might want the indentation (in this case you will need to define a new style for this purpose):
Const newNumPos As Long = 0
Const newTextPos As Long = 18 'Change as required, this is the Text Indent (in Points)
With ActiveDocument.Styles("1 / 1.1 / 1.1.1").ListTemplate
.ListLevels(1).TextPosition = newTextPos
.ListLevels(1).NumberPosition = newNumPos
.ListLevels(2).TextPosition = newTextPos
.ListLevels(2).NumberPosition = newNumPos
.ListLevels(3).TextPosition = newTextPos
.ListLevels(3).NumberPosition = newNumPos
End With

Related

VBA WORD looping trought sentences and lines of senteces

Is that even possible?
EDIT: explain my self, and thinking in another aproach
I can loop trough letters, words and paragraphs, but not thought what I suppose should be sentences, and neither I can find any reference for lines.
As an image worth like a thousand words, I attach a picture to explain myself:
squared on black an example of text
squared on green what I success with the code bellow
squared in red, what I can figure out how to do
example of sentences coloured as mention, image as link as it is my first post
My purpose, is to highlight/mark/colour out those lines that do not fit in a single page width, as example squared in yellow. But not sure how should do event I can not achieve the easy ones.
Any help?
(been searching here and other places for like couple of hours without success)
If False Then ' Cool, letter by letter
With ActiveDocument
For i = 1 To .Characters.Count
.Characters(i).Font.Color = Int(Rnd * 1048576)
Next
End With
End If
If False Then ' Cool, word by word
With ActiveDocument
For i = 1 To .Words.Count
.Words(i).Font.Color = Int(Rnd * 1048576)
Next
End With
End If
If False Then ' :-( same as paragraph
With ActiveDocument
For i = 1 To .Sentences.Count
.Sentences(i).Font.Color = Int(Rnd * 1048576)
Next
End With
End If
If True Then ' Cool, paragraph by paragraph
With ActiveDocument
For i = 1 To .Paragraphs.Count
.Paragraphs(i).Range.Sentences(1).Font.Color = Int(Rnd * 1048576)
Next
End With
End If
NOTE + ADDs : explain my self, and thinking in another aproach
As some staid bellow, I explain myself, the overall purpose ids to identify “text lines that do not fit in one printing line”. It has something to do with writing poetry, if interested.
I guess I could also try to “locate each character” on the printing line, identify the “line-brake” character (that Word do not take into account to brake sentences), and color manually word by word / letter by letter.
But I neither have found on the character object, a property referring to the position in the printing view.
May be possible to optimize, but this works !!,, (thanks John Korchok)
For Each p In ActiveDocument.Paragraphs
first_word_of_paragraph = True
For Each w In p.Range.Words
If first_word_of_paragraph = True Then
first_word_of_paragraph = False
actual_line_vertical_start = w.Information(wdVerticalPositionRelativeToPage)
End If
If first_word_of_sentence = True Then
first_word_of_sentence = False
actual_line_vertical_start = w.Information(wdVerticalPositionRelativeToPage)
End If
If w.Text = "" Then
first_word_of_sentence = True
End If
If actual_line_vertical_start <> w.Information(wdVerticalPositionRelativeToPage) Then
w.HighlightColorIndex = wdRed
End If

Can't get recursive Range.Find in Word VBA to work

I've been flailing at this for a while and can't seem to come up with a solution. I have to search through a document from start to finish with a wildcard search for custom mark-up. For the sake of the question, we'll say {something} When I find a specific match, it gets replaced with the contents of another string which can also contain mark-up. The mark-up has to be replaced in the order it will appear in the final document AND I have to know the recursion level that each replacement was made at.
This is basically what I came up with. Note that the ProcessReplacement function is contrived for the example - the text gets replaced by an external program:
Option Explicit
Private replaced As Integer
Public Sub Demo()
Dim pos As Range
Set pos = ActiveDocument.Content
replaced = 0
pos.Text = "{fizz}{fizz}{more}{buzz}{buzz}"
Expand pos
End Sub
Private Sub Expand(incoming As Range, Optional depth = 1)
Dim sub_range As Range
Dim end_pos As Long
end_pos = incoming.End
With incoming.Find
.ClearFormatting
.MatchWildcards = True
.Forward = True
.Wrap = wdFindStop
End With
Do While incoming.Find.Execute("\{*\}")
If incoming.Start < incoming.End Then
Debug.Print "Replaced " & incoming.Text & " at " & depth
end_pos = end_pos + ProcessReplacement(incoming)
Set sub_range = incoming.Duplicate
Expand sub_range, depth + 1
incoming.End = end_pos
incoming.Start = sub_range.End - 1
End If
Loop
End Sub
Private Function ProcessReplacement(replacing As Range) As Long
Dim len_cache As Long
len_cache = Len(replacing.Text)
If replacing.Text = "{more}" Then
replacing.Text = "{foo}{evenmore}{bar}"
ElseIf replacing.Text = "{evenmore}" Then
'This kind of works.
replacing.Text = "{fizzbuzz} "
'This doesn't work at all.
' replacing.Text = "{fizzbuzz}"
Else
replaced = replaced + 1
replacing.Text = "<" & replaced & ">"
End If
ProcessReplacement = Len(replacing.Text) - len_cache
End Function
The first issue is that I can't figure how to keep the .Find.Execute confined to the correct Range. This is what the document and output look like (with the space after {fizzbuzz}- more on that later):
Document text: <1><2><3><4> <5><6><7>
Output:
Replaced {fizz} at 1
Replaced {fizz} at 1
Replaced {more} at 1
Replaced {foo} at 2
Replaced {evenmore} at 2
Replaced {fizzbuzz} at 3
Replaced {bar} at 2
Replaced {buzz} at 2 <---This was outside of the range at that depth.
Replaced {buzz} at 1
If I take the space out after {fizzbuzz}, it doesn't even get matched, even though I confirmed in the watch window that it is basically the contents of the range when the function recurses after its replacement. Output without the space:
Document text: <1><2><3>{fizzbuzz}<4><5><6>
Output:
Replaced {fizz} at 1
Replaced {fizz} at 1
Replaced {more} at 1
Replaced {foo} at 2
Replaced {evenmore} at 2
Replaced {bar} at 3 <---No clue how this happens - wdFindStop is ignored.
Replaced {buzz} at 3
Replaced {buzz} at 3
Expected output (with or without spaces):
Document text: <1><2><3><4><5><6><7>
Output:
Replaced {fizz} at 1
Replaced {fizz} at 1
Replaced {more} at 1
Replaced {foo} at 2
Replaced {evenmore} at 2
Replaced {fizzbuzz} at 3
Replaced {bar} at 2
Replaced {buzz} at 1
Replaced {buzz} at 1
Anybody see anything that I'm missing?
Word's Find behavior is very odd.
Among other peculiarities, if your search text is an exact match for the Range's text, then the Wrap option is ignored, and the search range is redefined as per this article:
When the Find object .Execute method determines that the thing to find exactly matches the search range, the search range is dynamically redefined. The new search range starts at the end of the old search range and ends at the end of the document (or targeted storyRange). Processing continues in the redefined range.
That's why the {fizzbuzz} (with the trailing space) works - it's not an exact match.
You'll need to adapt your code to handle:
Range.Text is an exact match for the wildcard search, and/or:
After calling Execute, check that the Range's start is before the expected end.
You can see the Range changes in action by adding a Range.Select statement before and after every Execute call and before and after every Text assignment

Using Word VBA, Apply Various Heading Styles Based on Number Patterns

I am fairly new to VBA. I tag text with heading styles in large documents from a variety of authors. Is it possible identify a number pattern on a line of bolded text, and apply the appropriate style to that entire line (there is usually a hard return at the end of the line).
For example, often our documents are numbered as shown below, and we tag the text accordingly.
1.0 text here (apply Heading 1)
1.2 text here (apply Heading 2)
1.2.1 text here (apply Heading 3)
1.2.1.1 text here (apply Heading 4)
2.0 text here (apply Heading 1)
2.2 text here (apply Heading 2)
….and so on
I have done a lot of research, but I am not sure if this is possible. We do not use any type of auto numbering.
Yes, it's possible. Try this code:
Sub ApplyHeadings()
Dim rg1 As Range
Dim rg2 As Range
Dim pos As Long
Dim i As Long
Dim dots As Long
Set rg1 = ActiveDocument.Range
With rg1.Find
.MatchWildcards = True
.Text = "[0-9.]{2,}[!^13]#[^13]"
.Wrap = wdFindStop
While .Execute
Set rg2 = rg1.Duplicate
dots = 0
' isolate the numbering
pos = InStr(rg2.Text, " ")
If pos > 0 Then rg2.End = rg2.Start + pos - 1
For i = 1 To Len(rg2.Text)
' count the dots in the number
If Mid(rg2.Text, i, 1) = "." Then dots = dots + 1
Next i
' apply correct heading level
Select Case dots
Case 1
If Mid(rg2.Text, 3, 1) = "0" Then
rg1.Style = ActiveDocument.Styles("Heading 1")
Else
rg1.Style = ActiveDocument.Styles("Heading 2")
End If
Case 2, 3 ' maybe more...
rg1.Style = ActiveDocument.Styles("Heading " & CStr(dots + 1))
Case Else
' do nothing
End Select
' prepare for next find
rg1.Collapse wdCollapseEnd
Wend
End With
End Sub

Define letter as number, include as part of string for loop

If SecretWordLength = 5 Then
Label3.Visible = True
Label4.Visible = True
Label5.Visible = True
Label6.Visible = True
Label7.Visible = True
End If
This is the current code for making the dash underneath a letter visible for my hangman game based on the length of the secret word. How can I change this into a FOR loop so that I don't have to repeat this code for every label individually?
I was thinking of using a FOR loop in this way:
For i = 3 To 7
Labeli.Visible = True
Next
But it does not work as it recognizes the i as the letter itself, not the number I want it to represent. Help please?

PowerPoint Programming: Indentation with Ruler margin levels not working?

Recently we upgraded one our PowerPoint addin to support 2007 and 2010. most of the items we were able to port without problem. one problem we have is that indentations doesn't work when create tables or shapes using the addin.
for eg: same table gets dropped with proper indentation in 2003 but same thing doesn't get indentation when added to using 2007.
below is the code snippet that allows indenting:
With PropertyValues.ObjShape.Table.Cell(row, col).Shape.TextFrame.Ruler
For rulerCount = 0 To 5
.Levels(rulerCount).FirstMargin = rulerFirstMargin(rulerCount) '.LeftMargin = rulerLeftMargin
.Levels(rulerCount).LeftMargin = rulerLeftMargin(rulerCount) 'Left indent marker
Next rulerCount
End With
any idea why this is not working ?
I read the following thread too but didn't help much http://answers.microsoft.com/en-us/office/forum/office_2007-customize/why-shapetextframerulerlevelsi-cant-set-the-bullet/9eac3e46-b13b-433e-b588-216ead1d9c1a?tab=AllReplies#tabs
Updated Code:
PropertyValues.ObjShape.Table.Cell(row, col).Shape.TextFrame.TextRange.Text = "N/A"
With PropertyValues.ObjShape.Table.Cell(row, col).Shape.TextFrame
'Dim rulerCount As Short
For rulerCount = 1 To 5
.Ruler.Levels(rulerCount).FirstMargin = 10 * rulerCount 'rulerFirstMargin(rulerCount) '.LeftMargin = rulerLeftMargin
.Ruler.Levels(rulerCount).LeftMargin = 20 * rulerCount 'rulerLeftMargin(rulerCount) 'Left indent marker
Next rulerCount
End With
PropertyValues.ObjShape.Table.Cell(row, col).Shape.TextFrame.TextRange.Text = text
FWIW, in 2007 and up, you can now have up to 9 ruler levels instead of 5 as in earler versions. But your code should work as is. Here's a simplified version that does work on an arbitrary cell (2,2) of a table:
Dim oSh As Shape
Dim x As Long
Set oSh = ActiveWindow.Selection.ShapeRange(1)
With oSh.Table.Cell(2, 2).Shape.TextFrame
For x = 1 To 9
.Ruler.Levels(x).LeftMargin = x * 10
.Ruler.Levels(x).FirstMargin = x * 20
Next
End With
The other thing you might be running into is that you can apply certain types of formatting (including ruler settings) all you like; if there's no text at the level you're applying it to, PPT won't bark. It'll ignore you. Your settings will have no effect. Sometimes you need to check for text, supply some if there's none there (something highly improbable in the real world) then delete all instances of your improbable text afterwards.
Ugly. Yes.
Here we add text and set indent levels before trying to FORMAT each indent level:
Sub test()
Dim oSh As Shape
Set oSh = ActiveWindow.Selection.ShapeRange(1)
Dim RulerCount As Long
Dim sTemp As String
sTemp = "##$%" ' dummy text
With oSh.Table.Cell(2, 3).Shape.TextFrame
For RulerCount = 1 To 5
.TextRange.Paragraphs(RulerCount).Text = sTemp & vbCrLf
.TextRange.Paragraphs(RulerCount).IndentLevel = RulerCount
Next
For RulerCount = 1 To 5
.Ruler.Levels(RulerCount).FirstMargin = 10 * RulerCount 'rulerFirstMargin(rulerCount) '.LeftMargin = rulerLeftMargin
.Ruler.Levels(RulerCount).LeftMargin = 20 * RulerCount 'rulerLeftMargin(rulerCount) 'Left indent marker
Next RulerCount
End With
End Sub