How to create a labeled incremental reference in MS Word? - vba

I want to do cross-references manually in microsoft word 2010 (similarly to latex \label - \ref or \cite - \bibliography). I found that the Field function does almost excactly what I want (the syntax is a bit weird). If I type the following to the document (wave brackets are field marks produced by ctrl+f9):
{set dischargeRate {seq Figure}}Figure {ref dischargeRate}: Discharge
rate vs. hole diameter. Figure is from Reference [{ref authorA}].
The results are shown in Figure {ref dischargeRate} and published
previously in [{ref authorB}] and [{ref authorA}].
References:
{set authorA {seq cites}}[{ref authorA}] author, title, journal, year
{set authorB {seq cites}}[{ref authorB}] author, title, journal, year
the above produces:
Figure 1: Discharge
rate vs. hole diameter. Figure is from Reference [1].
The results are shown in Figure 1 and published
previously in [2] and [1].
References:
[1] author, title, journal, year
[2] author, title, journal, year
Is there a way to define increment and reference with one command instead of those three commands: set, seq and ref? Or how do I create a macro that does this for me. I am looking something like {setOrRef sequencename labelname} that shows a number i+1 that can be later referenced by {setOrRef sequencename labelname}.
Also there should be a check that labels are not redefined. For example: If the label does not exist, the sequence (Figure or cites) is incremented by one and that number is assigned to the label. If the label exists the existing number for the label is used.
I consider this as a programming question as it so close to macros and automating Ms Word.

If you want to use field codes and nothing else, I don't think there is a practical way to avoid using SEQ, SET and REF.
There are a number of difficulties detecting the existence/non-existence of bookmarks. I think you can sidestep them using the following set of nested fields, but I cannot say I have tried this "for real". Personally, I would try to avoid this kind of complexity in field coding.
All you need to do is insert the bookmark name you want once in the QUOTE field, i.e. by substituting the "bookmark" name you want instead of "bm". Here, I use "s" as the name that provides sequential reference numbers. It isn't actually a bookmark name, by the way, but a SEQ name.
As usual, all the {} have to be the special field code braces that you can insert using ctrl-F9 on Windows Word. You will still need to be careful about your naming of references, e.g. don't use "AuthorA" and "AuthorA1". You will need to avoid using any other SEQ names such as AuthorA2, and avoid using SEQ names s and s1 elsewhere.
{QUOTE {SET b bm}{SEQ "{b}{SEQ {b}}" \r{SEQ "s{={SEQ {b}}-3 \#"1'';''"}}" \h}{SEQ "{b}1" \c}}
Since it's not obvious how this works, I'll step through. Suppose you name your reference "AuthorA". Then you would insert
{QUOTE {SET b AuthorA}{SEQ "{b}{SEQ {b}}" \r{SEQ "s{={SEQ {b}}-3 \#"1'';''"}} \h}{SEQ "{b}1" \c}}
Bookmark "b" is set to "AuthorA"
{SEQ "{b}{SEQ {b}}"}
expands to
{SEQ "AuthorA{SEQ AuthorA}"}
In the first such set of fields for AuthorA , this expands to
{SEQ "AuthorA1" }
In subsequent sets, it expands to
{SEQ "AuthorA2" }
and so on.
The final field (the one actually inserted by the QUOTE)
{SEQ "{b}1" \c}
expands to
{SEQ "AuthorA1" \c}
i.e. it is always the value returned by the first set of fields in the document for AuthorA.
The value for AuthorA1 is set by
\r{SEQ "s{={SEQ {b}}-3 \#"1'';''"}}
{SEQ {b}}
expands to
{SEQ AuthorA}
which will actually be 2 in the very first set of fields for AuthorA (this is one of Word's SEQ field evaluation quirks). So
{={SEQ AuthorA}-3}
will be -1 and the numeric switch
\#"1'';''"
will return ''. So AuthorA1 is set to
\r{SEQ "s"}
i.e. the next value of the sequence s.
Subsequently,
{={SEQ AuthorA}-3}
is greater than 0, the numeric switch returns '1' and so AuthorA2 will be set to
\r{SEQ "s1"}
But we don't care what AuthorA2 is set to. The purpose of this bit of numeric formatting is to ensure that { SEQ s } only increments the first time time we insert one of these sets of fields for a particular "reference name".
For inserting such stuff, you could create an autotext/building block that would insert the block. All you would need to do is change "bm". A piece of VBA to prompt for a bookmark name and insert the same block would not be hard, but I leave you to look around for that.
As always, even using the general technique suggested, there may be a way to simplify the fields. Personally, I think I would go for a design that let me insert some kind of placeholder and required me to run some "pre-publishing VBA" to set them up correctly.

Related

Livecode: How do I program a button to create unique variables?

I apologize if this has been asked before (I couldn't find anything).
I'm an extreme noob in Livecode, and I want to know if there is a way of programming a button to create many new, unique variables and assign a value to them. I apologize if this is a dumb question.
Usually you use an array for that. An array is basically a list of things, where each thing is associated with an "index". An index can be any word, so you can use an array like a dictionary, where you'd e.g. have French words as the index, and English words as the value, like:
put "cow" into myDictionary["vache"]
But you can also just use numbers as the keys and make them a numbered list:
put "cow" into allMyAnimals[1]
put "duck" into allMyAnimals[2]
In end effect, you create one variable and put several things in it. For example if you had a loop that calculated something (in this example a number +100) and you wanted to have variables containing all those numbers, but named with 100 less, you'd do something like:
repeat with x = 1 to 250
put x +100 into twoHundredFiftyNumbersFrom101[x]
end repeat
And to read the first one:
answer "the first number is" && twoHundredFiftyNumbersFrom101[1]
Or all of them:
repeat with x = 1 to 250
answer twoHundredFiftyNumbersFrom101[x]
end repeat
Or whatever. You could also use 'do' to build the lines of code as a string, but then you have to make sure your variable names are generated in a fashion that makes them valid identifiers (e.g. have no spaces in them, no special characters). An array key can be any valid string, and the compiler can optimize them, and you can treat them as a whole and pass them between handlers.
Or you can do this "in the clear" with a "do" construction:
on mouseUp
repeat with y = 1 to 10
get random(100)
do "put it into onTheFlyVariable" & y
end repeat
end mouseUp
Step through this handler and watch the variables assemble themselves.

BACnet deserialization: How do I know if a new list elements starts

I'm implementing a generic BACnet decoder and came across the following question, of which I can't seem to find the answer within the BACnet standard. The chapter "20.2.1.3.2 Constructed Data" does not answer my question, or I might not fully understand it.
Let's assume I have a List (SEQUENCE OF) with elements of type Record (SEQUENCE).
Said record has 4 fields, identified by context tag, where field 0 and 1 are optional.
I further assume that the order, in which those fields are serialized, can be arbitrary (because they're identified by their context tags).
The data could look like that (number indicates field / column):
[{ "3", "0", 2" }, {"1", "2", "3"}]
Over the wire, the only "structure information" I assume I get are the open / close tags for the list.
That means:
Open Tag List
ctxTagColumn3, valueColumn3,
ctxTagColumn0, valueColumn0,
ctxTagColumn2, valueColumn2,
ctxTagColumn1, valueColumn1,
ctxTagColumn2, valueColumn2,
ctxTagColumn3, valueColumn3
Close Tag List
How do I know, after I've read the last column data ("2") of my first list item, that I must begin decoding the second item, starting with a value for column "1"?
Which of my assumptions is wrong?
Thank you and kind regards
Pascal
The order of elements of a SEQUENCE is always known and shall not be arbitrarily by definition. Further, not all conceivable combinations are possible to encode. Regarding BACnet, all type definitions shall be decodable universally.
Assuming I understand you correctly; the "order" cannot be "arbitrary"; i.e.:
SEQUENCE = *ordered* collection of variables of **different** types
SEQUENCE OF = *ordered* collection of variables of **same** type
The tag-number for the item (SD) context-tag will be different (/possibly an incremented value/maybe +1) from the containing (PD) context-tag; so you could check for that, or better still if the tag-number value is <= 5 (/'length' value) then it's a SD context-tag for one of your items, rather than a (/the closing) PD context tag (/'type' value) delimiting the end of your items.

Ampl syntax: return value at a specific position in set. AKA: use a set as an INDEX on another set

My question is this:
How can I use SUBSET (a discontinuous set) to refer to an index location in another set as opposed to an actual value? I see that ord() can be used to return the position of a value in a set, but I want the reverse of this...
my reason for needing this:
I have a model in which some of the set and data statements are roughly:
set ALL_TIME := {0..20000};
param DATA {ALL_TIME}; #read from file in later data statement;
set myTIME := {0...1000};
I am looping over the myTIME set and each time solving the model and then incrementing the start and end by 1: {1..1001}, {2..1002}, {3..1003}, etc.
I have another discontinuous set being read in from a file that looks something like this (yes below is bad syntax, the "...." is just there to mean that the pattern continues until it hits 1000 so I don't have to type it all) :
set SUBSET := {6,7,8,9,10, 16,17,18,19,20, 26,27.....}
Once myTIME increments such that it no longer contains "6", I get a subscript undefined error from a constraint which I understand to be because myTIME in this case is {7..1007} and thus in the following, tSUB=6 causes ALPHA[6] and is undefined:
subject to CONSTRAINT {tSUB in SUBSET}:
ALPHA [tSUB] = ALPHA[last(tSUB)];
What I want is to be able to use SUBSET to always refer to the same index location of ALPHA, DATA, etc.
So:
SUBSET[0] (which equals 6) should always be the 6th value of for example DATA:
{tSUB in SUBSET}: DATA[tSUB]. when tSUB is 0, I want the 6th value of DATA.
(I am new to Ampl and have a hard time wrapping my head around how indexing and sets work - if anything didn't make sense, please ask and I'll try to clarify. If you think it would be more helpful to see my actual code I'll try to sanitize the company data out and post it). Also, some of the code bits above have abysmal syntax. They are not copied from my code, just approximated to try to explain my problem. :)
You can get i-th member of set S with member(i, S), where i is a 1-based index and S is an ordered set. This is described in section 5.6 Ordered sets of the AMPL book.

Get Text Symbol Programmatically With ID

Is there any way of programmatically getting the value of a Text Symbol at runtime?
The scenario is that I have a simple report that calls a function module. I receive an exported parameter in variable LV_MSG of type CHAR1. This indicates a certain status message created in the program, for instance F (Fail), X (Match) or E (Error). I currently use a CASE statement to switch on LV_MSG and fill another variable with a short description of the message. These descriptions are maintained as text symbols that I retrieve at compile time with text-MS# where # is the same as the possible returns of LV_MSG, for instance text-MSX has the value "Exact Match Found".
Now it seems to me that the entire CASE statement is unnecessary as I could just assign to my description variable the value of the text symbol with ID 'MS' + LV_MSG (pseudocode, would use CONCATENATE). Now my issue is how I can find a text symbol based on the String representation of its ID at runtime. Is this even possible?
If it is, my code would look cleaner and I wouldn't have to update my actual code when new messages are added in the function module, as I would simply have to add a new text symbol. But would this approach be any faster or would it in fact degrade the report's performance?
Personally, I would probably define a domain and use the fixed values of the domain to represent the values. This way, you would even get around the string concatenation. You can use the function module DD_DOMVALUE_TEXT_GET to easily access the language-dependent text of a domain value.
To access the text elements of a program, use a function module like READ_TEXT_ELEMENTS.
Be aware that generic programming like this will definitely slow down your program. Whether it would make your code look cleaner is in the eye of the beholder - if the values change rarely, I don't see why a simple CASE statement should be inferior to some generic text access.
Hope I understand you correctly but here goes. This is possible with a little trickery, all the text symbols in a report are defined as variables in the program (with the name text-abc where abc is the text ID). So you can use the following:
data: lt_all_text type standard table of textpool with default key,
lsr_text type ref to textpool.
"Load texts - you will only want to do this once
read textpool sy-repid into lt_all_text language sy-langu.
sort lt_all_Text by entry.
"Find a text, the field KEY is the text ID without TEXT-
read table lt_all_text with key entry = i_wanted_text
reference into lsr_text binary search.
If you want the address you can add:
field-symbols: <l_text> type any.
data l_name type string.
data lr_address type ref to data.
concatenate 'TEXT-' lsr_text->key into l_name.
assign (l_name) to <l_text>.
if sy-subrc = 0.
get reference of <l_text> into lr_address.
endif.
As vwegert pointed out this is probably not the best solution, for error handling rather use message classes or exception objects. This is useful in other cases though so now you know how.

Putting the cursor in a specific place in a live template

I just wanted to know how you put a cursor in a specific place in a live template for IntelliJ
For example:
# $var$ is an insance of the $objectType$ class
assert isinstance($var$, $objectType$)$END$
What happens here is that your cursor gets dragged to $var$ in the comment string first and then to your other values inside assert. What I wanted to know is how you chose where the cursor goes first.
I've read the documentation, but this is not mentioned, although a lot of other things are.
You can arrange the order that your variables are visited in. You find the information under bullet number five in this IntelliJ help document: http://www.jetbrains.com/idea/webhelp/creating-and-editing-template-variables.html
To arrange variables in the order you want IntelliJ IDEA to switch between associated input fields, use the Move Up and Move Down buttons.
Edit
You have to update the macro definition to similar to this:
# $varComment$ is an insance of the $objectTypeComment$ class
assert isinstance($var$, $objectType$)$END$
And then you define the order and expression to something like this (I didn't have any good expression for the var and orderType for you):
Since you fill in the Skip if defined for the two comment variable they will just take the values from the var and orderType and fill it in. This will do exactly what you are looking for :-)