September 19, 2006
MS Word - VBA - StoryRanges - Odd-page headers
Document.StoryRanges does not explicitly return odd-page headers/footers. Instead, they're linked from the even-page ones. One has to use Range.NextStoryRange on the even-page headers/footers to get the odd-page ones.
Because example code is always nice, here's my function to grab _all_ of the ranges in a document, updated with this knowledge:
' Builds a collection of all the ranges in this document.
' (StoryRanges, which include the headers and footers, augmented with any text box ranges)
' also include linked ranges via NextStoryRange to grab the odd page header/footers
Private Function AllRanges(Optional Doc As Document) As Collection
Dim Rng As Range
Dim Sh As Shape
Set AllRanges = New Collection
If Doc Is Nothing Then Set Doc = ActiveDocument
For Each Rng In Doc.StoryRanges
While Not Rng Is Nothing
Set Rng = Rng.NextStoryRange
' Grab all of the text boxes in the document, too.
' Use .ContainingRange to return the entire story that flows between linked text frames,
' but examine .Previous to make sure I grab it only once - from the first box in the chain.
For Each Sh In Doc.Shapes
If .HasText And .Previous Is Nothing Then AllRanges.Add .ContainingRange
September 18, 2006
Oracle Forms goodness - extending the text fields
I've gotten pretty frustrated with the Forms development environment, so I never thought I'd see the word "goodness" combined with "Oracle Forms", but recently I've made a breakthrough of sorts that has really encouraged me to pursue more elegent Forms programming.
Every Oracle Form is composed of Java objects. Text fields, buttons, frames, you name it, they are all some derivitive of Java awt or swing objects. As such, they can be extended.
Sounds simple, even too simple, doesn't it? Well, it really is!
If you're a Forms developer, there's a good chance that you know about embedding Java Beans (also called PJCs - Pluggable Java Components) into your Forms. They're really cool and can be used to accomplish all kinds of things. This takes PJCs one level further.
Let's assume that you have a text field to which you want to apply special effects. One of the most popular effects is to make the field behave like a hyperlink: blue in color, underlined, and, most importantly, having the mouse cursor change to the historical "hand".
Applying the color and underline are straightforward Forms development features, but the mouse cursor is another matter entirely. Ever since Forms became "webified", the ability to natively capture mouse-over events has disappeared because the traffic required for the server to track mouse movement is huge. However, PJCs run on the client, so we can employ them to implement mouse over effects. Oracle has provided a Hyperlink Bean in its demo package, but the drawback of the Hyperlink bean is that it takes too long to load, so having a decent number of them in a Form (say, 10 - 20) causes the Form load time to go through the roof.
However, if you write a class that extends the Forms text field, you can apply that class to select fields using the Implementation Class in the Properties Page, and the load time (so long as you don't do extravent things in the constructor) is the same as a regular text field.
Now, take that and apply it to ANY forms object. Write a class that extends the button object to implement "rollover" effects. Or how about extending text fields so that they scroll their text like a ticker tape? Or image objects that load new images every x seconds?
Anyway, here's one implementation I came up with. This text field extension underlines the text and does the following on mouseover: turns the cursor into a hand, makes the font bold, changes the font color to red, changes the background color to gray. You can easily add Property IDs to control the behavior. This concept and most of the code was taken from the Oracle demo ModCursor:
public class Hotlink
private Cursor stdCursor;
private Font stdFont;
private int stdStyle;
private Color stdForeColor;
private Color stdBackColor;
public void init(IHandler h)
stdCursor = this.getCursor();
public void mouseEntered(MouseEvent me)
if(getTextLength() > 0)
public void mouseExited(MouseEvent me)
if(getTextLength() > 0)
public void paint(Graphics g)
if (this.getTextLength() > 0)
FontMetrics metrics = getFontMetrics(getFont());
int strWidth = metrics.stringWidth(getText());
int yoffset = (int)(metrics.getHeight() * 0.95);
g.drawLine(0, yoffset, strWidth, yoffset);
public boolean setProperty(ID pid, Object value)
if(pid.getName().equals("FOREGROUND")) this.stdForeColor = (Color)value;
else if(pid.getName().equals("BACKGROUND")) this.stdBackColor = (Color)value;
else if(pid.getName().equals("FONT")) this.stdFont = (Font)value;
return super.setProperty(pid, value);