Good News – Going to Connect/Lotusphere after all!

Thanks to some good luck, I will be able to afford to pay my way and attend Connect in just over a week. I found a decent air fare (they have been going up every date for the last couple of days), and I will be arriving at MCO on Saturday at 2.10pm. That should make me show up at BALD around 3.30pm or so, just in time for a late lunch and a after-travel beer. I am heading back home Friday at 7.40pm, giving me time to do a little bit of shopping at the LEGO store at Downtown Disney after the conference... I have had several people offer me to share/split their rooms, and I want to thank everyone that been trying to help me out. This is what the Lotus community is all about, helping each other. I hope I will be able to repay this in some way in the future. I am looking forward to seeing all my old friends, and to hopefully make some new ones. See you in Orlando in 8 days!  

0 Comments

No Connect/Lotusphere for me this year…

I just got word from my boss that I will not be able to go to Connect 2013 in Orlando. This is due to financial reasons, the company is trying to save money anywhere they can. Even as the conference would only cost them $3,200 (I found a really good airfare and got offers to share a room), it was not approved (not even after I offered to pay part of the cost myself). This will be the first time since I started going in 1998 that I won't be in Orlando to learn new things, network and meet all my friends in the Yellowverse. This would actually have been my 17th Lotusphere (I also attended Lotusphere Europe in 1996). I am of course very disappointed, but it happens. I hope to be able to go next year, and possibly attend IamLUG or some other conference later this year. I will be following the event through twitter and Facebook, and hopefully there will be some videos uploaded during/after the conference. Have a beer for me, and enjoy the conference. And keep the blog posts and twitter messages coming!

0 Comments

Code: Expanded Class for File Functions

Yesterday I blogged about a simple class to parse file names, and that inspired me to improve it and add some functionality, which will actually come in handy for a project at work shortly. The class is pretty self-explanatory, there is really nothing complicated in the code. When the class is initialized, if a path to a directory (i.e. ending with \) is passed to the constructor the directory is created if it does not exist. If the directory exist, there are functions to copy or move both single files or all files in the directory. Directories can also be deleted using the RemoveDir method. In addition, there are properties to get the path, file name, extension and file size (in bytes) of the file (if the class was initialized with a file name). Here is an agent with some examples of how to call the class: Option Public Option Declare Use "Class.FileFunctions" Sub Initialize Dim file As FileObject Dim cnt As Integer Dim success As Boolean '*** Create new file object Set file = New FileObject("D:\Downloads\Downloads\MERP\Assassins of Dol Amroth.pdf") '*** Copy the file to another (new) directory Call file.CopyTo("D:\Downloads\MERP1\", file.FileName) '*** Move the file to a new location and replace space with + in file name Call file.MoveTo("D:\Downloads\MERP2\", Replace(file.FileName," ","+")) '*** Create a new directory if it does not exist Set file = New FileObject("D:\Downloads\MERP3\Test\") '*** Copy all files in specified directory to another directory Set file = New FileObject("D:\Downloads\Downloads\MERP\") cnt = file.CopyAllTo("D:\Downloads\MERP\Backup\") MsgBox "Copied " & cnt & " files." '*** Move all files in the previously specified directory to another location cnt = file.MoveAllTo("D:\Downloads\Middle-Earth Role Playing Game\") MsgBox "Moved " & cnt & " files." '*** Remove D:\Downloads\Downloads\MERP\ Call file.RemoveDir("") '*** Remove D:\Downloads\MERP3\ and Test directory that we created earlier success = file.RemoveDir("D:\Downloads\MERP3\Test\") If success = True Then success = file.RemoveDir("D:\Downloads\MERP3\") If success = False Then MsgBox "Failed to delete D:\Downloads\MERP3\" End If Else MsgBox "Failed to delete D:\Downloads\MERP3\Test\" End If End Sub   Below is the class itself, I put it in a script library called Class.FileFunctions. %REM Copyright (c) Karl-Henry Martinsson 2012. Some code copyright Andre Guirard (see below). You are free to use and modify my code, as long as you keep all copyright info intact. If you improve the code, please consider sharing it back to the community. %END REM Option Public Option Declare Type FileDetails path As String filename As String extension As String filesize As Long End Type Class FileObject Private file As FileDetails Public silent As Boolean Public Sub New(filepathname As String) silent = False FullPathName = filepathname If file.FileName = "" Then If file.Path "" Then On Error 76 GoTo parentDoesNotExist 'No filename but path, then we create that directory (if missing) If Dir$(file.Path,16)="" Then createDirectory: Call MakeDir(file.Path) End If End If file.FileSize = 0 Else file.FileSize = FileLen(filepathname) End If Exit Sub parentDoesNotExist: Resume createDirectory End Sub Public Property Set FileName As String file.FileName = FileName file.Extension = StrRightBack(FileName,".") End Property Public Property Get FileName As String FileName…

0 Comments

IBM Notes & Domino 9.0 Social Edition – Public beta now available!

Today, one day before the day previously mentioned, IBM have made the public beta of IBM Notes and Domino 9.0 Social Edition available for download. This is perhaps because of the fact that tomorrow is the opening day here in the US for The Hobbit, and IBM figured that all us geeks will go watch that instead of playing with the latest version of Notes. This is what IBM says about the new version: IBM Notes and Domino 9.0 Social Edition Public Beta isa preview of the next release of Notes, iNotes, Domino Designer, Domino and Notes Traveler. IBM Notes and Domino software puts you on a solid path to becoming a social business. IBM Notes and Domino 9.0 Social Edition Public Beta provides significant new social capabilities including : Activity streams: allow you to view and take action quickly on content and events Embedded Experiences: allow you to access business critical actions from other applications without leaving your email. This brings collaboration in-context and results in tighter integration across iNotes, Connections, Notes, app dev (XPages), and 3rd-party products and services Contemporary user interface, simpler navigation, easier to locate information both in Notes and iNotes IBM Notes Browser Plug-in: allows rapid delivery of IBM Notes Social Edition applications to the web Incorporation of a social application container, based on the OpenSocial standard, which provides for development of a reusable set of “gadgets” from both IBM and third parties Inclusion of the XPages Extension Library which greatly improves developer productivity when building collaborative workflow driven applications for web, mobile web and Notes Domino Designer provides a new home page, editor enhancements and a server-side JavaScript debugger for use with XPages Enhancements to Domino REST services and new Calendaring and Scheduling APIs Domino integration: SAML, OAuth Notes Traveler: Windows Phone 7.5/8; BlackBerry 10 BES support; IBM i Server There are already some screenshots available online, and I plan to look closer at the product over the weekend and next week. I am currently downloading the 2GB of files I need...

0 Comments

Show and Tell – Dynamic Web Calendar

In this post in the developerWorks forum, Andy Herlihy is asking about how to create a small calendar that can be embedded into an existing intranet website. As Carl Tyler points out, Andy could simply use Dojo. However, this is a good example to show some jQuery combined with the power of IBM Lotus Domino.  Lets' break it down into a few smaller steps. The first one is to create a Domino web agent that will take the current date and build a calendar for that month. There will be no links or javascript code in the HTML generated, just plain HTML code, with some id attributes to make it easy to address different cells later. The next step is to create a very simple webpage, with some Javascript to load jQuery and set up the calendar to detect clicks. The clicks will cause another call to the Domino server, this time to a view using RestrictToCategories to only get the entries for the specified date. The entries are returned as HTML and through jQuery they are displayed in a div on the webpage. We also want to add a little bit of CSS to make the calendar pretty. The CSS also lives on the HTML page. Finally we create the view, it's associated view template form and a form to create some entries that we can use for testing.   Let's look at the code. First the Domino web agent. It should be pretty self explanatory: %REM Agent WebCalendar Created Nov 26, 2012 by Karl-Henry Martinsson/Deep-South Description: Returns HTML for a calendar for current month %END REM Option Public Option Declare Sub Initialize '*** Used to get URL params Dim session As New NotesSession Dim webform As NotesDocument Dim urlstring As String Dim urlarr As Variant Dim urlvaluename As Variant Dim urldata List As String Dim webservername As String '*** Agent specific Dim startDate As NotesDateTime Dim endDate As NotesDateTime Dim i As Integer Dim j As Integer Dim startweekday As Integer Dim thisMonth As Integer Dim currDate As Double Dim cellclass As String Set webform = session.DocumentContext '*** Calculate path for this database, for image/icon file references later webservername = webform.GetItemValue("Server_Name")(0) '*** Remove leading "OpenAgent" urlstring = StrRight(webform.Query_String_Decoded(0),"&") If urlstring <> "" Then '*** Get all params passed to agent urlarr = Split(urlstring,"&") For i = LBound(urlarr) To UBound(urlarr) urlvaluename = Split(urlarr(i),"=") urldata(urlvaluename(0)) = urlvaluename(1) Next If IsElement(urldata("date")) = False Then urldata("date") = Format$(Now(),"mm/dd/yyyy") End If Else urldata("date") = Format$(Now(),"mm/dd/yyyy") End If '*** Get first and last date of current month Set startDate = New NotesDateTime(Format$(urldata("date"),"mm/01/yyyy")) Set endDate = New NotesDateTime(startdate.DateOnly) Call endDate.AdjustMonth(1) Call endDate.AdjustDay(-1) currDate = CDbl(CDat(startDate.DateOnly)) startweekday = Weekday(Cdat(startDate.Dateonly)) '*** HTML header Print "Content-type: text/html" ' & CRLF Print |<table class="calendar">| '*** Create calendar header with weekdays Print |<tr><td colspan=7 class="labelMonthYear">| + Format$(CDat(startDate.DateOnly),"mmmm yyyy") + |</td></tr>| Print |<tr class="calendarHeader">| Print |<td>S</td><td>M</td><td>T</td><td>W</td><td>T</td><td>F</td><td>S</td>| Print |</tr>| '*** Build rows for the weeks For i = 1 To 6 Print |<!-- Start row | & i & | -->| Print |<tr class="calendarRow" id="calendarRow| & i…

1 Comment

How to detect changes in fields on a form

A question I have seen a few times in the developerWorks forums is how to detect what values (often names) have been added in a multi-value field. This is not very difficult to do in Lotusscript, and there are a few different ways to do it. I prefer to use lists, but you can of course use arrays as well. The basic idea is to declare a global variable to hold the initial value of the field, populate it when the document is either opened or put into edit mode, and then checked when the document is saved. Globals: Dim oldValue List As String PostModeChange: Dim oldarray as Variant '*** Create array, assume ; as item separator in field oldarray = Split(uidoc.FieldGetText("myMultiValueField"),";") '*** Build a list of values ForAll o in oldarray oldValue(o) = o End ForAll QuerySave: Dim newarray as Variant Dim newValue List As String '*** Create array, assume ; as item separator in field newarray = Split(uidoc.FieldGetText("myMultiValueField"),";") '*** Compare with values in list ForAll n in newarray '*** Check if value is not in global list, then it is new If IsElement(oldValue(n)) = False Then newValue(n) = n ' Add new value to list End If End ForAll '*** Loop through all new values and print them ForAll nv in newValue Print nv + " is new." End Forall The same technique can be used to detect what fields have changed since the document was opened. Just store the values of all fields (except any starting with $) in a list, then check the values in the fields against that list when saving the document. Globals: Dim oldValue List As String QueryOpen: '*** Build a list of values with field name as listtag ForAll i in doc.Items If Left$(i.Name,1)"$") Then oldValue(i.Name)=i.Text End If End ForAll QuerySave: Dim modified List As String Dim tmpValue As String '*** Compare current fields with values in list ForAll o in oldValue '*** Check if value is the same or not tmpValue = uidoc.FieldGetText(Listtag(o)) ' Get current field value If tmpValue o Then modified(ListTag(o))=tmpValue ' Add new value to list of modified fields End If End ForAll '*** Loop through all modified fields and display new value ForAll m in modified Print Listtag(m) + " was changed from " + oldValue(Listtag(m)) + " to " + m End Forall All very easy when you know how to do it. And again, it shows the power of lists.

3 Comments

Export from Notes to Excel – 3 different ways

While reading the developerWorks forums, I have noted that some tasks seem to be common, and users often have issues with it. One very common is to export data from Notes/Domino to Excel. My guess is that some manager/executive want to get the data to manipulate and analyze it in Excel, which they know better, and where reporting can be done easier. First of all, for anyone that want to do real integration with Excel (or Word, or any other office program), I would suggest to look at the presentations given by John Head at Lotusphere and other conferences in the past: Lotusphere 2011 - JMP208 IamLUG 2009 - Integration and Coexistance Lotusphere 2006 - BP309 Lotusphere 2005 - JMP108 But if you just need to export raw data to Excel, there are a couple easy ways to do that. You don't need to automate Excel, something the programmers posting in the forums seem to frequently do. That just makes things more complicated, and if you run the code in a server agent, Microsoft Office have to be installed on the server itself. Different versions of Excel also cause different issues. The different methods I use to export Notes data to Excel are as follows: Create a CSV file, which can be opened in Excel Create a HTML table in a file with .xls extension, which can be opened in Excel Create a HTML table and return it through a browser, with a content type set to open in Excel. Depending on what the requirement is, I usually choose one of those method.   Method 1 - CSV file (local) The easiest way to get data from Notes to Excel (or any other spreadsheet program) is to simply save the data as  comma-separated values (CSV). Use regular Lotusscript file operations and write the values to the file, encased in double quotes and separated by a comma. You need to build a string containing a complete line, as the Print statement adds a line break to the end automatically. A CSV file could look like this: FirstName,LastName,Department,StartYear "Karl-Henry","Martinsson","IT","2002" "John","Smith","Accounting","2009"   The first row is the header, with the field names listed. This helps on the receiving side, but is optional. Dates and numbers don't need quotes around them, as long as they don't contain commas. So make a habit to format any numbers without commas.   Method 2 - HTML file (local) This method is very similar to the CSV method. The difference is that you create a table in HTML, matching the cells in Excel you want to create/populate. But instead of creating a file with the extension .htm or .html, you give it the extension .xls. Excel is intelligent enough to identify it as HTML and map the content correctly. The biggest advantages of using a HTML file instead of CSV is that you get more control over the formatting. By using colspan and rowspan, you can merge cells together, for example in a header. You can also use markup to make cells bold or italic, or even set the…

14 Comments

IBM Notes and Domino 9.0 Social Edition

This morning, IBM presented the latest version of Notes and Domino. The new product name is IBM Notes 9.0 Social Edition. As you notice, the Lotus name is now gone, and the look is changed to look more like other IBM applications, with a more modern design. There are also changes and updates to the user interface inside the different parts of the client.   One thing, totally new for Notes, is that tutorials and training videos are available in the client.  The tutorials are not just for new functions, but also older tips and tricks that will make the users more productive. During the presentation, new functions in mail and calendar were demonstrated. One function that will surely be popular with users is to group mail by date: Other new features shown were the ability to color code different categories of meetings using custom colors and improved monthly view, as well as a weekly planner taken from Organizer. The activity stream is using the OpenSocial standard, and Domino is now supporting OAuth and SAML for authentication. Customers can however deploy Notes 9.0 without the Social Edition functions, and add them later. Not only has the traditional Notes client been updated, iNotes is also updated to look even more like the rich client. One of the biggest news in this version is the Notes browser plugin, that allow user to run traditional Notes applications directly in the browser, in full fidelity with no Notes client installed. The new version of iNotes also contains the new activity stream, as shown in the image below.   The new version of Traveler will (in addition to iPhone and Android) also support the Blackberry 10 platform and Windows Phone 7.5/8, and now also be available for IBM iSeries. A public beta version of Notes 9.0 Social Edition will be available December 14. For previous versions of Notes, since (if I remeber correctly Notes 5), IBM have been doing managed beta testing and not released public beta version. The final version is planned for Q1 2013. IBM also outlined the future roadmap for the next couple of years, which included a new major realease in 2015:

4 Comments

Using jQuery to emulate Notes hide-when

We have all built applications in Lotus Notes where we use the value of a checkbox, radio button or dropdown box to show or hide additional fields, like you can see in this clip. But the hide-when formula will not work this way on the web. The Domino HTTP stack will simply render the page before sending it to the browser, and even if you make a selection in the browser, the hidden section will not display or vice versa. So what can you do? One easy way is to use jQuery (or Dojo, if you rather fancy that). You can then detect if a checkbox/radio button is clicked on or if a dropdown box is changed. Then you read the value of the button/box and hide/show the content you like.   In this example, you can also see that that one of the dropdown boxes actually switch which dropdown box to display next to it, you can see that the available choices are different, in addition to performing the more visible hiding of the last row when recommendations is not set to "n/a". So how do you actually do this? It is fairly easy. First you add a reference to the jQuery library to the HTML Head Content section of the form. Remember that you need to prefix any quote marks with a \ when you put it in as a string. Here I am calling the Google-hosted jQuery library: <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script> Next, remove any hide-when formulas from the form you are going to expose on the web. That is important, since the Domino server will otherwise not render all the HTML you need. Then give each element you want to hide a unique id. You are probably using tables to create the layout you want, then you can use the table cell id to address the element.   In this case, I give the cell containing the label the id "ReasonNALabel" and the cell containing the dropdown box the id "ReasonNA". The field 'Recommendation', which is the one where we are detecting the click and if it has the value "n/a" should display the two cells below it, has an id of "Recommendations". One more thing, we want to detect the value as soon as the page is loaded, and display/hide the section accordingly. I will break out the code that perform the check of the value and does the hide/show, so I can call one function insted of duplicating the code. $(document).ready( function () { // Check value and do initial show/hide after page is finished loading refreshRecommendations(); // Set trigger for click on radio button to call function $("input[name='Recommendations']").click( function() { refreshRecommendations(); }); }); function refreshRecommendations() { var checked = $('input[name=Recommendations]:checked').val(); if (checked == "n/a") { $("#ReasonNA").show(); $("#ReasonNALabel").show(); } else { $("#ReasonNA").hide(); $("#ReasonNALabel").hide(); } }   If you want to check the value if a checkbox, use  $("#checkboxID").is(":checked") and to check the value of a dropdown box, use $("#dropdownboxID").val(). For the dropdown box, use .change() instead of .click(), otherwise the code is identical.   That…

1 Comment

Replace images on web page using jQuery

Last week I encountered a situation where I wanted to replace images on a Domino generated webpage. I am sure you all know what doc links look like by default when rendered by the Domino HTTP task:   By adding a few lines of jQuery to the form, you can manipulate the image source, as well as the CSS class and other attributes. This allows you to modify a page served by the Domino HTTP task almost as much as you like. Below is the code I used to modify what you see above into something that I found a little bit nicer.     $("img").each( function() {         var t = $(this);         imgicon = t.attr("src");         if (imgicon == "/icons/doclink.gif") {            t.attr('src', '/applications/losscontrol.nsf/icon_picture.gif');            t.addClass('photoicon');         }         if (imgicon.indexOf("Attachments") > 1 ) {            t.attr('src', '/applications/losscontrol.nsf/icon_attach.gif');            t.addClass('attachmenticon');            t.attr('height','16');            t.attr('width','16');         }     });     $("a").each( function() {         var t = $(this);         url = t.attr("href");         if (url.indexOf("$FILE")>0) {            t.removeAttr("style");            t.addClass('attachmentLink');            t.outerHTML = t.outerHTML + "<br>";         }     });     var plink = $('#photolinks').html();     plink = plink.replace(/<br>/i,'');     plink = plink.replace(/<\/a><font\b[^>]*>/gim,'<span class="photoLink">');     plink = plink.replace(/<\/font>/gim,'</span></a>');     $("#photolinks").html(plink);     var alink = $('#attachmentlinks').html();     alink = alink.replace(/<\/a>/ig,'</a><br>');     $("#attachmentlinks").html(alink);   What I am doing is to loop through all img tags on the page, and identify the ones that are doc links (using the file name for the icon). I replace the src attribute of those links with a different icon I added as an image resource to the database. I then set the class name for the link, so I can manipulate the look using CSS. I also look for any src attribute containing the field name "Attachments", which is where the attachments (if present) are located. I change the icon from the one generated by Domino to another image resource in the database. The next section of the code will loop through all anchor tags and check if the link includes "$FILE", indicating it is an attachment. If that is the case, I remove the Domino generated style attribute, set a class name and append a line break to the end of each link. I then perform some string replacements to remove the font tags that Domino generate automatically when rendering rich text fields. I replace the font tags with a span (containing a class name) so I can style the look of the link later, and also move the </a> tag to after the link text. The last thing I do is to add a line break after each attachment link. Here is the result:   Hope this can help anyone. And if you wonder, I am using the fieldset tag to create the box around each set of icons.

3 Comments

Free Tool: Analyze ACL in Notes Application/Database

Yesterday my network admin asked me if I could write a simple tool that could provide him with with a spreadsheet of what users had access to a certain database, and through what groups and roles. A couple of hours later I had created an agent that analyze the ACL and identify the users who can access it. The result is presented as a CSV file. I am sharing the code below. It is pretty straight forward. As you can see, I am using lists to hold the data for easy export later to CSV. Run the code with the Lotusscript debugger turned on, and put a breakpoint before the CSV export starts, and you can see how the data is stored in the lists. The function ExpandGroups() is called recursively to drill down, if the group contains additional groups. This function also use a lookup into a custom view, (LookupPeople), that we have in our corporate NAB, I am sure you can modify this code with something that works for you. Enjoy! As always, use the code on your own risk, no warranties, etc. %REM Agent Export ACL Info to CSV Created Nov 14, 2011 by Karl-Henry Martinsson/Deep-South Description: Read ACl for specified database and create a CSV file with info about each user's access (roles, groups, delete access, access level). %END REM Option Public Option Declare Dim nab As NotesDatabase Type RowData role As String group As String username As String deletedoc As String level As String levelno As Integer End Type Class GroupData Public roles List As String Public Sub New() End Sub End Class Class PersonData Public accesslevel As Integer Public roles List As String Public deletedoc As boolean Public accessthrough List As String Public Sub New() me.deletedoc = False End Sub Public Sub SetAccessLevel(level As Integer) If me.Accesslevel<level Then me.AccessLevel = level End If End Sub Public Function GetAccessLevelText() Select Case me.AccessLevel Case 0 : GetAccessLevelText = "No Access" Case 1 : GetAccessLevelText = "Depositor" Case 2 : GetAccessLevelText = "Reader" Case 3 : GetAccessLevelText = "Author" Case 4 : GetAccessLevelText = "Editor" Case 5 : GetAccessLevelText = "Designer" Case 6 : GetAccessLevelText = "Manager" End Select End Function End Class Class RoleData Public groups List As String Public Sub New() End Sub End Class Sub Initialize Dim ws As New NotesUIWorkspace Dim session As New NotesSession Dim db As NotesDatabase Dim pview As NotesView Dim pdoc As NotesDocument Dim acl As NotesACL Dim entry As NotesACLEntry Dim person List As PersonData Dim group List As GroupData Dim role List As RoleData Dim users As Variant Dim row List As RowData Dim cnt As Long Dim groupname As String Dim filename As String Dim rowstr As String Dim dbname As String Dim servername As String servername = InputBox$("Enter server for database:","Select Server") If servername = "" Then Exit Sub End If dbname = InputBox$("Enter full path of database:","Select Database") If dbname = "" Then Exit Sub End If set nab = New NotesDatabase(servername,"names.nsf") Set db…

3 Comments

Dynamic tables in classic Notes

Using Xpages, you can do many neat things in Notes. But I am still doing all my development in classic Notes, despite being on Notes/Domino 8.5.2. The reason is simple. Memory. There is just not enough memory to run the standard client in our Citrix environment, so all users are using the basic client. And Xpages is not working in the basic client. So how do I solve issues like multiple documents tied to a main document, being displayed inline in the main document? Well, I solved this a long time ago by using a rich text field and building the document list on the fly. I am sure many other Notes developers use this technique. I know it was discussed in a session at Lotusphere several years ago, perhaps as long ago as 7-8 years ago. So this is of course not anything I came up with myself. In this post I just want to share how I am using this, and perhaps this can help someone. The database (download it here) is very simple. It contains three (3) forms and two (2) views. In addition I have some icon as image resources, but that is just to make things pretty.   Forms The 'MainDoc' form is the main document, being displayed in the view 'By Last Change'. It contains a few fields: 'Title' - a text field where the user can enter a title/description 'Data' - a rich text field where the rendered table rows will be displayed 'ParentUNID' - a hidden computed-when-composed field where the UniversalID of the document is stored 'EntryCount' - a hidden text field used to count the number of entries (to display in the views) 'LastEntry' and 'LastEntryDate' - Hidden text fields to keep track of the last person who edded an entry The form also contains some regular action buttons ('Save', 'Edit', 'Close'), as well as 'Add entry...', an action button with two lines of Formula language: @Command([FileSave]); @Command([Compose];"Entry") The QueryOpen event, which executes before the form is opened in the front-end and displayed to the user, contains some Lotusscript code. This event let us modify the document in the backend, which is where rich text fields can be updated. The code - which I will post at the end of this article - is very simple, it is just over 50 lines of code.   The 'Entry' form is where the entries are created. It is set to let fields inherit values from the document it is created from, and contains a couple of fields, some action buttons and some Lotusscript code as follows: 'ParentUNID' - editable, default value is "ParentUNID", to inherit the value from MainDoc 'Created' and 'Creator' - computed-when-composed to store date/time and user name of creator 'ItemDate', 'Issue' and 'Action' - user data fields. The 'Entry' form contains the following Lotusscript code: (Declarations) Dim callinguidoc As NotesUIDocument Dim callingdoc As NotesDocument Sub Initialize Dim ws As New NotesUIWorkspace Set callinguidoc = ws.CurrentDocument If Not callinguidoc Is Nothing Then Set callingdoc = callinguidoc.Document End If End Sub Sub Terminate Dim ws As New NotesUIWorkspace…

7 Comments

Free Application Template/Framework for Notes

Many of my Notes application have a similar/the same look, based on a generic application template I created a while back. The standard look makes the users feel at home when I deploy a new application, and the template makes life easier for me. If I create a new application based on that template, I already have the frameset, navigator and a few design element done before I even start the development. Below is a screenshot of what it looks like in the Notes 8.5.2 client:   I want to share the template with the Lotus community, as a small way of giving back. I may add more things to it later, I will post any modifications here as well. Click here to download the file. Update: Download link fixed now.Thanks Hynek for pointing it out!  

2 Comments

Agent Logging – Budget Style

At my work, we had several issues/needs related to agents in different Domino databases. I tried to come up with a quick and lean solution, that gave us the functionality we needed, nothing more and nothing less. Yes, I am aware of Julian Robichaux's excellent OpenLog. But we had some needs that I did not feel were addressed in that project. What I wanted was a database where the agents could be documented, and also where the log data was stored. So I created a Agent Log database where one document is stored per agent. The form let me document the actions of the agent, as well as what server it is running on, in what database, when it is triggered, etc. When the document is opened, I also read the last time the agent was run and if the agent is enabled or not. This is a sample document for an agent. It is scheduled to run at 11am every day:   This is what the actual database looks like. I plan to release the database on OpenNTF.org when I get the time.   Nothing complicated this far. The next step was to create a small script library, doing the actual logging. I created a script library called Class.AgentLog with the following code: Public Const THREAD_TICKS=6 Public Const THREAD_TICKS_PER_SEC=7 Class AgentLog Private session As NotesSession Private logdb As NotesDatabase Private agentdoc As NotesDocument ' Main doc in Agent Log db Private logdoc As NotesDocument Private running As Integer Private tstart As Long ' Ticks at start Private tend As Long ' Ticks at end Private tps As Long ' Ticks per second (system dependant) Public Sub New( agentname As String ) Dim view As NotesView Dim key As String running = True tstart = GetThreadInfo( THREAD_TICKS ) tps = GetThreadInfo( THREAD_TICKS_PER_SEC ) Set session = New NotesSession Set logdb = New NotesDatabase( session.CurrentDatabase.Server, "IT/AgentLog.nsf" ) Set view = logdb.GetView( "(LookupAgent)" ) If agentname = "" Then agentname = session.CurrentAgent.Name End If key = session.CurrentDatabase.FilePath & "~" & agentname Set agentdoc = view.GetDocumentByKey( key ) If agentdoc Is Nothing Then Print "AgentLog: Failed to locate agent document for " & agentname & "." Exit Sub End If Set logdoc = New NotesDocument( logdb ) logdoc.Form = "LogItem" Call logdoc.MakeResponse( agentdoc ) Call logdoc.ReplaceItemValue("AgentName", agentname ) Call logdoc.ReplaceItemValue("StartTime", Now() ) If session.IsOnServer = True Then Call logdoc.ReplaceItemValue("RunBy", session.CurrentDatabase.Server ) Else Call logdoc.ReplaceItemValue("RunBy", session.CommonUserName ) End If End Sub Public Sub Finish() running = False End Sub Public Sub Terminate() Dim seconds As Integer If logdoc Is Nothing Then Exit Sub End If tend = GetThreadInfo( THREAD_TICKS ) seconds = (tend - tstart) / tps Call logdoc.ReplaceItemValue("EndTime", Now() ) Call logdoc.ReplaceItemValue("Seconds", seconds ) If running = True Then ' Check if not terminated gracefully Call logdoc.ReplaceItemValue("Terminated", "Yes" ) End If Call logdoc.Save(True,True) End Sub End Class All code goes in the (Declarations) section of the script library. There are a few things to notice. I actually make each log item a child…

0 Comments

My Favorite Tools

Kathy Brown today asked "What's Your Favorite Tool", so I thought I wanted to share the tools I use. My favorite tool is probably NoteMan from MartinScott. If I have to pick one tool from the suite, it would be either NoteMan.Editor or NoteMan.DocDelta. It is very hard to decide between the two of them. Editor is great for editing documents, see the contents of different fields and even change data types. I use it to get the UniversalID of documents and much more. DocDelta help me solve replication conflicts quickly and easy. I can higly recommend the NoteMan suite of tools to any Notes/Docmino developer, and for the price ($395 for the whole suite), you get a lot of functionality. I also use several tools from TeamStudio and Ytria. Yes, I am lucky enough to have a boss who believe in getting me the tools I need. From TeamStudio I use Undo (previously called Snapper) to make snapshots of the design while developing for easy roll-back, Profiler to find performance issues in my code and Configurator for search-and-replace through-out a database (design and/or documents). Those tools run around $500 each, if I recall correctly. I also use their free class browser, a tool I highly recommend to everyone doing object oriented Lotusscript development. From Ytria I use a number of tools.The two I use the most are scanEZ and actionBarEZ. The latter is great when I want to apply a specific design of action bars to many forms and/or views. I design the action bar in one view, with colors, fonts, backgrounds, etc. When I am satisfied I can update all views and forms the the database with the new design. I don't use scanEZ as much, but still on a regular basis. It also have functions to identify replication conflicts, like NoteMan.DocDelta, but the two tools complement each other. Using scanEZ, I can locate and delete documents of a particular type, including profile documents, and much more. I also sometimes use designPropEZ to check the design of a database and make sure it does not inherit element from the wrong templates/databases. Here is a screenshot of my currect toolbar with all my development tools:   In addition I use Photoshop CS2 for graphics editing, TechSmith Jing to create screencam demos for managers/users, and Notepad++ for some HTML/Javascript/jQuery editing.

2 Comments

End of content

No more pages to load