Tuesday, September 12, 2006

SNTT - Letting a user reorder documents from a listbox

I've been working on a project tracker to help me get organized. It's got a lot of nifty bells and whistles, but one thing that was critical was giving my boss the ability to easily reprioritize projects. Getting this implemented proved to be a bit of a challenge so I thought I would share the technique.

The idea I came up with was to provide a dialog that shows all the projects with a priority assigned. The user can select a project, then click an up button to increase the project's priority, or a down arrow to decrease the priority. There are a few caveats to getting this to work:
  1. Setting the default value on a listbox requires computing the default value from a field.
  2. Since you are changing the information you want to put on the underlying documents you have to be careful that you give yourself some way to relate the new information to the existing documents
Here is the dialog the user sees:

The numbers are the project priorities and the text is the project title. The up and down arrows are used to move things around. Here's what the design looks like:

[Sidebar: Lotus Notes cannot produce a graphical button. The up and down arrow buttons were created in VB5 then copied out of a print screen and pasted in. The code referenced below is in the default hotspot on each picture.]

  • Projects - Text, multivalue, computed, Default Value is @ThisValue
  • ProjectUNIDS - Text, multivalue, computed, Default Value is @ThisValue
  • SelectedProject - Text, computed, Default Value is @ThisValue
  • lstProjects - Listbox, editable, use formula for choices, formula is Projects. Default Value is SelectedProject.
The Projects field contains all the project priorities and their titles. The ProjectUNIDs field contains all the UNIDs for the Project documents, which is how I address the second caveat above. To put this together I create the Project Priority document in LotusScript, populate the Projects, ProjectUNIDs and SelectedProject fields in code, then display the document using the NotesUIWorkspace.DialogBox method. Here is the code I use to display the dialog:
Sub Click(Source As Button)
Dim nUIWS As NotesUIWorkspace
Dim nSession As NotesSession
Dim nDB As NotesDatabase
Dim nVW As NotesView
Dim nDC As NotesDocumentCollection
Dim nDoc As NotesDocument

Dim sProjects As String
Dim sUNIDs As String

Set nSession = New NotesSession
Set nDB = nSession.CurrentDatabase
Set nVW = nDB.GetView("(Projects)")

Set nDoc = nVW.GetFirstDocument
Do Until nDoc Is Nothing
sProjects = sProjects & "~" & nDoc.ColumnValues(0) & " - " & nDoc.ColumnValues(1)
sUNIDs = sUNIDs & "~" & nDoc.ColumnValues(2)
Set nDoc = nVW.GetNextDocument(nDoc)
sProjects = Mid$(sProjects, 2)
sUNIDs = Mid$(sUNIDs, 2)

Set nDoc = nDB.CreateDocument
Call nDoc.ReplaceItemValue("Form", "(Prioritize Projects)")
Call nDoc.ReplaceItemValue("Projects", Split(sProjects, "~"))
Call nDoc.ReplaceItemValue("ProjectUNIDs", Split(sUNIDs, "~"))
Call nDoc.ReplaceItemValue("SelectedProject", nDoc.Projects(0))

Set nUIWS = New NotesUIWorkspace
If nUIWS.DialogBox("(Prioritize Projects)", True, True, False, False, False, False, "Prioritize Projects", nDoc, True, False, True) Then
The remainder of the code deals with reordering the priorities and may be discussed later if readers want to see it. It is beyond the scope of this posting, but I don't mind sharing so ask if you would like to see that, too.

To Move an item up or down we have to do a few things:
  1. Get the currently selected element and extract its priority
  2. Get the next or previous element and extract its priority
  3. Swap the two priorities
  4. Swap the UNID's so you can apply the priorities to the correct documents
  5. Re-select the item with the new priority
Here is the code for the Up button:

selproject := lstProjects;
@If(selproject = "";@Return("");"");

index := @Member(selproject;Projects);
@If(index = 1;@Return("");"");

selpriority := @TextToNumber(@Left(selproject; "-"));
prevproject := Projects[index - 1];

FIELD Projects := @Replace(Projects;selproject; @Text(selpriority - 1) + " - " + @Trim(@Right(selproject;"-")));
FIELD Projects := @Replace(Projects;prevproject; @Text(selpriority) + " - " + @Trim(@Right(prevproject;"-")));
FIELD Projects := @Sort(Projects);

selunid := ProjectUNIDs[index];
prevunid := ProjectUNIDs[index - 1];
FIELD ProjectUNIDs := @Replace(ProjectUNIDs;prevunid; "¥" + selunid);
FIELD ProjectUNIDs := @Replace(ProjectUNIDs;selunid; prevunid);
FIELD ProjectUNIDs := @Replace(ProjectUNIDs; "¥" + selunid; selunid);


FIELD SelectedProject := @Text(selpriority - 1) + " - " + @Trim(@Right(selproject;"-"));
FIELD lstProjects := SelectedProject;

And for the down button:

selproject := lstProjects;
@If(selproject = "";@Return("");"");

index := @Member(selproject;Projects);
@If(index = @Count(Projects);@Return("");"");

selpriority := @TextToNumber(@Left(selproject; "-"));

FIELD Projects := @Replace(Projects;selproject; @Text(selpriority + 1) + " - " + @Trim(@Right(selproject;"-")));
FIELD Projects := @Replace(Projects;Projects[index + 1]; @Text(selpriority) + " - " + @Trim(@Right(Projects[index + 1];"-")));
FIELD Projects := @Sort(Projects);

selunid := ProjectUNIDs[index];
nextunid := ProjectUNIDs[index + 1];
FIELD ProjectUNIDs := @Replace(ProjectUNIDs;nextunid; "¥" + selunid);
FIELD ProjectUNIDs := @Replace(ProjectUNIDs;selunid; nextunid);
FIELD ProjectUNIDs := @Replace(ProjectUNIDs; "¥" + selunid; selunid);


FIELD SelectedProject := @Text(selpriority +1) + " - " + @Trim(@Right(selproject;"-"));
FIELD lstProjects := SelectedProject;

And that's really all there is to it. Once you click OK control returns to the LotusScript action button, which then steps through the UNID's and applyies the new priorities to the documents. Hopefully you can see how simple it is to reorder items in a listbox and how this can be applied to allow documents to be reordered.

All code was converted to HTML using the ls2html routine,
provided by Julian Robichaux at nsftools.com.


No comments:

Post a Comment