Sep 20
2012Macro Tutorial
Macros are built using the Macro Editor which can be launched from New Macro or Edit Macros buttons on the ribbon. See this post for more details. Macro Editor looks like below:
2012

Here you can set the name, category and description of the macro and below that you can see the set of commands at your disposal on the left and the macro you are building on the right. You can use the Add and Remove buttons to build your macro. Before diving into all the details here, let's take a look at a simple macro and see how macros are built and how they work. Then we can slowly move into more aspects of macros.
Finding and modifying objects
This macro increases font size of all text on the current page by 1pt. The macro looks like this:
As simple as that. The macro finds text in the current page and modifies its "fontSize" property by adding 1 to it. The blue underlined parts are pieces you can click and change to edit the macro. For instance you can click on "Text" and pick a different object type:

Similarly you can pick the property you want to modify and how you want to modify.
Using conditions to filter objects
When querying for objects on the page, you can make use of conditions which are in the form of:
For example if you want to find paragraphs that are edited by "John" and are inside a table which is partially selected, you can do so by:

You can combine the "Is under" and "That has" to build more complex conditions. You can add as many of them as you need to specify the objects you are interested in.
Using variables for temporary storage
You can make use of variables, for temporarily storing and manipulating information. For instance if you want to read the text in a table cell and fill the rest of the table with that text, you can temporarily store the text of the first cell in a variable:
This macro stores the "text" property of the first table cell in to a variable named "TextOfFirstCell" and then reuses that to set the text for all the table cells. To add more variables or use existing variables, simply click on the blue underlined part in the Modify line and choose one of the options:

As you can see, you can choose either a property or a variable (existing or new) to modify here.
Using conditions to selectively apply modifications
You may want to apply modifications based on different conditions. The "That has" and "Is under" filters somewhat give you that but once that filter applied and you have the set of objects you can't make further decisions using them. To provide this, you can use If/Else clauses. Let's say you want to highlight text based on author:
You can build very complex conditional statements using these and selectively apply any modifications. "If" can also evaluate conditions on variables and can use one or more of the following conditional operators, based on the values compared:

Using indices to store set of values in variables
Macros support storing a set of values in variables as
Here we check the "rowIndex" property of each cell. The first row is where rowIndex is 0, and the second row is where rowIndex is 1. We store text from each cell in the first row in the variable named "Text", indexed by the column index (colIndex property). This way we can store the text from the first row as

This will add the index and you can then choose what to use as an index.
Using constant literal values
You can use constant literal values in the right hand side of That/Modify/If clauses. In fact we already did in most of the above examples. When you click to change the right-hand-side, you will see the list of properties and variables and an option to "Enter literal value". Also if the left-hand-side is a property with known set of values, you will see them there:
Here selection property can be one of "none", "partial" or "all", so you get to choose from one of them. Alternatively you can enter the value manually.
Asking user for input
You can ask user for input during macro execution to modify behavior of the macro. To do so, add a Modify clause and choose a variable for the left-hand-side. For the right hand side choose "Prompt user for value". This will open a dialog to enter details of the user input. For instance if you are building a macro that will search for some text (e.g. Search and replace) you may ask the user for the search term:

Here you can:
- Add a message for the user (or choose a variable that contains the message),
- Choose input type which can be one of
- text
- dropdown
- checkbox
- Message
- Set an initial value for the input (for text and dropdown)
- Set possible values (for dropdown only)
- Specify whether user is allowed to leave the input empty (for text only)
This will prompt the user for input while executing your macro. The above options will result in the following dialog:

See how the message and initial value is placed. If you have multiple consecutive user prompts, Onetastic will merge them into a single user dialog. For instance see the following dialog for the Search & Replace macro:


As you can see 4 Modify clauses are turned into a dialog box with 4 inputs. This also shows different input types: text for "Find what" and "Replace with", dropdown for "Scope", and checkbox for "Match case". You can also see the underlined shortcut keys (like F in Find what), which comes from the & characters right before the corresponding letter. This is standard Windows way of specifying accelerators for labels. Hitting Alt+F will move the cursor to the "Find what" box. Finally, for the first input it is specified that user cannot leave it empty, therefore the OK button is not enabled until user types into it.
Macro Logging
When you run your macro, if it doesn't seem to be doing what you expect it to be doing, there is a way to generate logs from the execution to investigate the cause. To do so, go to the Settings and check Enable Macro Logging in the ribbon and re-run your macro. This will generate a macrolog.txt file under %appdata%Onetastic. You can see what operations took place and what the values of variables and properties were in the log file.Conclusion
Hopefully this gives you some idea about how to build macros with Onetastic. You can also look at existing macros in the Macro Editor by going to Edit Macros dropdown. You can inspect the macro and try to understand how it works.Update: A new tutorial about inserting text using a macro is available here.





I must be missing the obvious, but if I download a macro (from Macroland or from anywhere else), where the heck do I have to save it to? I tried and simply saved it in my usual Download-folder but of course that alone doesn't make it show up in Onetastic's list of available macros. So, I suppose there is a "well-known" directory somewhere where one has to save such macros to so that Onetastic can locate them at startup time and loads them. But the documentation doesn't describe where this "well-known" folder is...
M.
I'd like to bind them to keyboard shortcuts and this is the best way I can find would be a macro. But apply styles as a whole rather than having to choose each property would be useful, setting up the macros is too much hassle to do them all.
<For each="Text">
instead of
<For first="Text">
Does that fix the problem?
In my notes, I had to frequently repeat the task of changing the selected text to Courier New with font size 10. To make it working automatically, I wrote the following macro but I found it only works well with the first line and part of my second line of the selection. For example:
A = num2str([1:5;1:5])
B = mat2str([1:5;1:5])
C = str2num('44')
<Macro name="Codes" category="Content" description="">
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<ModifyProp name="fontName" op="set" value="Courier New" />
<ModifyProp name="fontSize" op="set" value="10" />
</For>
</Macro>
I really do not where the problem comes from? Any suggestion?
Alex
I was looking at creating a TOC macro that would add a TOC at the top of a page, where the TOC entries were the Titles/Names of any subpages.
I was looking for "For each Subpage in CurrentPage", or the name of the parent page in properties, i.e "That has ParentPage equal to CurrentPage"
Is there anyway to accomplish this?
Also your macro replaces the "text" property. If you want to append to the end of it try "Add ... to it" from the operation list instead of Set. It will look like:
<ModifyProp name="text" op="add" var="date" />
Thanks for very nice program. I tried to create a macro which is here:
<Macro name="Date" category="Content" description="">
<For each="Paragraph">
<That hasProp="selection" op="eq" value="partial" />
<ModifyVar name="date" op="set" prop="creationTime" />
<ModifyProp name="text" op="set" var="date" />
</For>
</Macro>
I tried to write the creation date of piece of text on the page after the text. It did not work quite right. I think that the macro for some reason changed the creation in the XML of the page. Did I do something very wrong or is this a feature in the OneNote? Would it be possible to have the date shown in a standard format?
Kari
<one:Table
with
<one: Table bordersVisible="true"
Then paste the XML back into the dialog you got it from and click OK. This should update all the tables on the page.
Is it possible to provide inserting Date via OneCalendar?
For instance, if the user right-clicks the date in OneCalendar (or, perhaps, simply click the area on the left-hand of the date, which is currently not occupied by any item), a popup menu appears providing 2 menu items, such as:
"Insert Date (Long Format)", and
"Insert Date (Short Format)" .
It will insert Date only (without Time) on the position of pointer of the currently opened page and the format is based on system default.
I think it will be useful for planning something in the future such as next meeting, etc.
Thank you.
[..you won't be able to create three paragraphs...]
Thanks for the confirmation. I will see the macro you mentioned.
Thank you.
For translating Onetastic, check the Translate Onetastic link at the bottom of the website. You will need to contact me by email to get the process started.
I am trying to find out which file to handle if someone want to translate Onetastic into a certain local language. However, I can not see where to download the file.
Is it not available here?
Thank you.
The date/time value is inserted as a current-date/time stamp.
thanks
1.
I want to insert the following automatically: (without "-----")
-----
Date: Monday, 23 January 2013
Time: 20:45
Topic:
-----
The time format (short) is identical to the system default, but the date format is not, which is :
(short) yyyy-MM-dd
(long) dddd, MMMM dd, yyyy
And I do not want to change the system default.
Can I use Onetastic macro for that purpose? Which part of the macro I should learn ? (sorry. I am rather slow about this programming things)
2.
Do you provide manual of Onetastic (including macro manual) in pdf format ?
Thank you.
.
I have an issue with the macro function. How can I apply one of the predefined styles to a paragraph, i.e. appling Heading1 ("h1") to a paragraph that has the style Heading2 ("h2")?
Using the macro editor, I don't find a parameter 'style' when using the 'Modify' Command.
I would expect the macro to look like
<Macro name="mod H2" category="helts" description="reformat">
<For each="Paragraph">
<IfProp name="style" op="eq" value="h1">
<ModifyProp name="style" op="set" value="h2" />
</IfProp>
</For>
</Macro>
Doesn't work though, even if I modify the xml file directly. Any ideas?
Thanks, w.
<Macro name="H1-Date" category="helts" description="Adds the current date to the current position for a new diary entry">
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<IfProp name="value" op="eq" value="">
<ModifyProp name="value" op="set" value="insertAndKill" />
</IfProp>
</For>
<For first="Page">
<That hasProp="isCurrentlyViewed" op="eq" value="true" />
<ModifyVar name="currentDate" op="set" prop="lastModifiedTime" />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="insertAndKill" />
<ModifyProp name="value" op="set" var="currentDate" />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value=".000Z" />
<ModifyProp name="value" op="set" value="" />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="T" />
<ModifyProp name="value" op="set" value=" -- " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-01-" />
<ModifyProp name="value" op="set" value=" January, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-02-" />
<ModifyProp name="value" op="set" value=" February, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-03-" />
<ModifyProp name="value" op="set" value=" March, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-04-" />
<ModifyProp name="value" op="set" value=" April, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-05-" />
<ModifyProp name="value" op="set" value=" May, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-06-" />
<ModifyProp name="value" op="set" value=" June, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-07-" />
<ModifyProp name="value" op="set" value=" July, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-08-" />
<ModifyProp name="value" op="set" value=" August, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-09-" />
<ModifyProp name="value" op="set" value=" September, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-10-" />
<ModifyProp name="value" op="set" value=" October, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-11-" />
<ModifyProp name="value" op="set" value=" November, " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="-12-" />
<ModifyProp name="value" op="set" value=" December, " />
</For>
</Macro>
The date will be printed as "yyyy mmmmm, dd -- hh:mm:ss"
And now there are even more wishes but i think each of them will take quite a lot of time to implement as it would more or less implementing a turing machine :)
- possibility to call macros from within other macros (like "getMonthName(date :string)"
- possibilty to call some onenote functions directly ("API" =D )
btw. macros that can simulate key strokes would be cool, too :)
THANK YOU for the plain and simple import export possibility. It simply rocks :) When it comes to repetitive stuff, i like the simplicity of a text editor :)
<Macro name="add Date as H1" category="helts" description="Add a date">
<For first="Page">
<That hasProp="isCurrentlyViewed" op="eq" value="true" />
<ModifyVar name="currentDate" op="set" prop="lastModifiedTime" />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<IfProp name="value" op="eq" value="">
<ModifyProp name="value" op="add" var="currentDate" />
<ModifyProp name="fontSize" op="add" value="12" />
</IfProp>
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value="T" />
<ModifyProp name="value" op="set" value=" " />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<That hasProp="value" op="eq" value=".000Z" />
<ModifyProp name="value" op="set" value="" />
</For>
</Macro>
This is basically finding the text that has "T" and ".000Z" and replace them with space and empty string to clean it up. You can find more of similar tricks in the "Inserting Text" tutorial I posted.
If all you want to do is to add a heading 1 date, you may want to use the built-in shortcuts:
Alt+Shift+F will add the current date time
Ctrl+Alt+1 will switch to the Heading 1 style
I keep kind of a diary (permanently docked) which is a loooong page with lots of loose notes. these are separated by Headings that contains just Date + Time.
So i have some follow up questions. Is there a possibility to add the current date to the content? Im using Page.lastModifiedDate but this is not really correct. The format of lastModifiedDate is rather ugly.
Is there a possibility to reformat it (directly or by maybe regexp)?
Instead of making text bold and large, id like to apply "Heading 1" to it.
<Macro name="add Date as H1" category="helts" description="Add a date">
<For first="Page">
<That hasProp="isCurrentlyViewed" op="eq" value="true" />
<ModifyVar name="currentDate" op="set" prop="lastModifiedTime" />
</For>
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<IfProp name="value" op="eq" value="">
<ModifyProp name="value" op="add" var="currentDate" />
<ModifyProp name="fontSize" op="add" value="12" />
</IfProp>
</For>
</Macro>
I really appreciate your macro editor. Its just what onenote needs to satisfy power users ;)
I know about the object model on codeplex, but it was dead more than a year ago already and never got past the notebook hierarchy to the page content. I've come further than that and can now do statements like "currentPage.LastParagraph.Alignment = "right"". My current problem is that I can't get tags to work when updating pages.
Can you point me to a forum or any other place where I can go with OneNote programming questions and problems?
Thanks!
Jan Roelof
<Macro name="set_tagdate" category="" description="">
<For each="Paragraph">
<That hasProp="tagName" op="contains" value="To Do" />
<ModifyProp name="tagCreationDate" op="set" value="2001-01-01T00:00:00.000Z" />
</For>
</Macro>
Will do more testing in the days ahead (on my real work stuff -- at home at the moment), and let you know if anything relevant arises. I'm absolutely STOKED Omer. You nailed it. And in general, the importance of your Add-In is not to be underestimated by the OneNote team. The ability to extend functionality like this is key (IMHO) to OneNote's utility, (and therefore it's acceptance).
Well done!
>>but it will claim schema error if it encounters a paragraph that
>>doesn't have tags instead of skipping those.
...bummer -- Is there way to get Onetastic to overcome this, so that Onetastic correctly finds all the to-do tagged items in a selected section, and changes their tag creation date? (Or must I, impatient soul, wait for your new release =]). The motivation for my request is actually a workaround for a silly issue within Onenote that has really hamstrung the way I work: Namely (and I corresponded with John Guinn on this -- helpful) in OneNote 2010, the tag-summary is *unable to list tagged items in their original order* as they occurred in their note or section. And since I intentionally arrange my to-do items into specific groups, and in a specific order that I need, this is a real bummer. After my careful arrangement of to-do items, the tag-summary insists on re-sorting my to-do items by alphabet, date, etc, etc.
So where does Onetastic fit in? I found something I'm trying exploit as a workaround. Namely, that if one chooses to sort their tag summary *by date*, then the tags are indeed left in their original order of occurrence *if they all occur within a single day*. Therefore, if I can wholesale change all of my to-do tag-dates to the same day before running a tag summary, then use the sort-by-date option in the my tag-summary, oala', the summary will extract and list all of my to-do items in the order that I arranged within the original note.
Make sense? Obviously, the *real* solution would be to allow the tag-summary to sort by "original order" -- but I suspect that will be a longer time in coming. I share all this in hopes that 1) it made sense, and 2) perhaps it will jog an idea of another Onetastic workaround to my desired end, and 3) it will elicit such deep sympathy, that you will crank out a fixed tag-filter as quickly as possible =]. (but seriously, my use of onenote at work has been in a holding pattern because of this specific issue)
What say?
--Will
<Macro name="Set Tag Creation Date" category="Tags" description="Sets the creation date of the tag on the selected paragraph">
<For each="Paragraph">
<That hasProp="selection" op="not" value="none" />
<ModifyProp name="tagCreationDate" op="set" value="2001-01-01T00:00:00.000Z" />
</For>
</Macro>
Hopefuly in a future update I will get filtering by tags working and I also want to add a date/time picker so that you don't have to type the date like this. One more thing to improve here is to give a better error message when macro execution fails. In this case it should say: "tag property not found on Paragraph object".
Thanks again and let me know if you need more help.
Here's what the macro looks like:
------------------------------------
For each Paragraph in Current Page
That has property(tag) contains (case insensitive) "To Do"
Modify property(tagCreationDate) --> Set it to "1/1/2001"
------------------------------------
Thanks in advance!
--Will
<Macro name="Add Text" category="Content" description="Adds text at the end of selected paragraph">
<For first="Paragraph">
<That hasProp="selection" op="not" value="none" />
<ModifyProp name="text" op="add" value="Some text to add" />
</For>
</Macro>
This will add to the end of the paragraph. If you want to add text to the cursor position, you can do something like:
<Macro name="Add Text at Cursor" category="Content" description="Adds text at the cursor position">
<For first="Text">
<That hasProp="selected" op="eq" value="true" />
<ModifyProp name="value" op="add" value="Some text to add" />
</For>
</Macro>
I should write up about this as a new tutorial.
One question: is it possible to create a macro that applies only to e.g. the current paragraph rather than first, last or each?
And Neil: thanks for your macro! I do a lot of document scanning and until today resizing a multi-page document was a hand job!
<Macro name="SetImageWidthToFirst" category="Image" description="Sets every image's width to match the first item while maintaining aspect ratio">
<For first="Image">
<ModifyVar name="FirstImageWidth" op="set" prop="width" />
</For>
<For each="Image">
<ModifyVar name="NewHeight" op="set" prop="height" />
<ModifyVar name="ScaleFactor" op="set" var="FirstImageWidth" />
<ModifyVar name="ScaleFactor" op="div" prop="width" />
<ModifyVar name="NewHeight" op="mul" var="ScaleFactor" />
<ModifyProp name="height" op="set" var="NewHeight" />
<ModifyProp name="width" op="set" var="FirstImageWidth" />
</For>
</Macro>