« Looking forward to LS12! Has anybody seen presentation downloads yet? | Main| Classic Notes Development; How to launch a database in Designer with Command Line Parameters »

Classic Notes Development - Access Search Bar from LotusScript

Tags: LotusScript
0

Have you ever wanted to access the Search Bar from LotusScript?

image

Being able to do so would perhaps remove the need for various homecooked solutions on how to do full text searches and display the results to the user. Even though we do have programmatic access to full text, I have allways felt that something is missing. Why not just use the standard search bar in the Notes client? This post describes how to do exactly that with a couple LotusScript classes, using Windows API functions. You can set and get the text of the Search Bar, and even click the "Search" button programmatically.


Before diving into the details, please let me advertise for the shareware application Windows Detective. It is what Spy+ and WInspector was on Windows XP and older Invaluable tool when trying to understand window-hierarchies. Below you see how Windows Detective has enumerated the whole hierarchy down to the search bar;
~b411424
As always, you can place code many places. In the samples below I have created a LotusScript Script Library named "class:CEnumerateWindowHandles", and thus all code reference that library by

Use "class:CEnumerateWindowHandles"

Then I create a search bar manager object, and use it like this;

Dim searchBarMgr As New CSearchBarManager()
Dim
hWndSearchBar As Long


hWndSearchBar = searchBarMgr.FindSearchBar()


If
hWndSearchBar > 0 Then
  Call
searchBarMgr.SetSearchBarText("Hey there!")
  Call
searchBarMgr.ClickSearchButton()
Else

  MessageBox
|Click View -> "Search This View" to show the search bar first|
End
If


The code above first create a searchBarMgr-object. Then it calls the FindSearchBar() method. This is the enumeration of all Windows handles from the current active window (....the Notes client). If FindSearchBar() returns a non-zero value, it found the search bar. If the return value is 0, the search bar wasn't visible (note the user can at will turn the search bar on or off. BTW, you can turn it on or off by using the @formula ViewShowSearchBar @Command.


Then the code simply set the text of the search bar by using SetSearchBarText(). Finally it clicks the "Search" button by using ClickSearchButton(). Pretty simple!


I have by the way tested the code on Windows XP with a Notes 7 client, Windows 7 32 bit with Notes 8.5.2 and finally Windows 7 64-bit with the latest and greatest 8.5.3. FP1.


Now for the internals.


When you look at the code, you will see that I have prefixed all defines with CEW (CEnumeratedWindows ...). Why? Because the script library will live better together with other code which may have the same defines!

The base class is named CEnumerateWindows which basically do the same as EnumChildWindows. Since EnumChildWindows uses a so-called callback function, it is no-go in LotusScript since we don't have the AddressOf-like function in LotusScript. However, we can easily create similar logic with the function GetWindow() since it allows us to enumerate siblings and child windows with ease. When CEnumerateWindows is finished I have a LotusScript list of handles. The code also shows you how to use a LotusScript list with a custom LotusScript class - which again contains a list. In effect you end up with a list of lists The core logic inside the class is to dive into the windows handle hierarchy, and for each level, it enumerates all siblings (ie handles on the same level). If any handle has children handles, the EnumerateSiblings() method recursivly enumerate the next level and so forth. Using a LotusScript class is also a nice construct for keeping all variables encapsulated.

The derived class CSearchBarManager puts CEnumerateWindows to work. The method FindSearchBar()  will loop through the list of handles and look for the window handles with class name equal to IRIS.tedit. As soon as that is encountered I check it's parent handle to see whether that has class name NotesSubprog. And if that is the case too, I check that the last recorded windows title exists in the windows title of the Notes client itself. If so, I know that the search bar is visble in the current view I am calling the code from. Note that you can have the search bar visible in many views, it is just that you don't seem them all due to window overlapping. Finally I use the Windows API GetClipBox() to reveal whether I got a visible search bar or not.

As I enumerate through the window handles, I also look out for windows with class name IRIS.bmpbutton. By a similar check as for IRIS.tedit, I determine whether I've got the "Search"-button or not. A careful note about how I detect which IRIS.bmpbutton is the correct. The method IsSearchButtonCaption() determine whether the windows title of the handle is equal to "Search" in a lot of languages. As you see from the constructor method New  of CSearchBarManager, I fill a list with the captions for "Search" in a lot of languages. This is not necessary correct in your language, so if this class doesn't work for you, try to see that I have defined "Search" correctly for your language.
SNAGHTML18d01cc
I would of course have loved to determine the language of the Notes client  programatically, but I didn't find any way to do that at the time of writing.
I think the classes perform pretty well. Thanks to the automatic memory handling of LotusScript lists, and their performace when using IsElement(), the classes are pretty easy to follow.
What am I most satisfied with in these classes? The fact that I found a reliable way of coding EnumChildWindows without using callback functions. This opens up a bunch of possibilities regarding menus and other fun stuff, also for a classic Notes developer not diving too much into Eclipse plug-ins etc.
The downside; Windows-only ....
Hope you like it.

Download it from here.

Comments

Gravatar Image1 - Robert that is way cool. Wondering what else the technique might be useful for. Attachment handling comes to mind.

Great job!

Gravatar Image2 - @LanguagePreference([REGION]) or @LanguagePreference([CONTENT])
would give you the languages specified in the Regional settings part of the preferences...

Gravatar Image3 - Lars; Unfortunately LanguagePreference will return language related to your *settings*, not your *notes client* language. For example, I have an English Notes/Admin/Dev client, but my Regional Settings is all set to Norwegian. LanguagePreferences Region will return "no" for me. The LanguagePreferences CONTENT will return the preferred language for *database content*, and again, not the client language itself.

Gravatar Image4 - How does one set the "preferred language for *database content*"? I see how to return it, but not how to set it. Google hasn't helped.

Gravatar Image5 - I just wanted to post; great article and script lib! Helped me!

Post A Comment

:-D:-o:-p:-x:-(:-):-\:angry::cool::cry::emb::grin::huh::laugh::lips::rolleyes:;-)