ColorMePrivileged
What
A Windows Presentation Foundation (WPF) ClickOnce application that shades the eDoc viewer within Summation in accordance with values stored in the Privlege/Privilege field of the current database.
How
Uses the Summation API, via the swsom .Net wrapper, to monitor the location of the floating eDoc window and update the color (Red/Green/Gray) of a transparent
overlay by reading data from the currently selected record.
Technical Details are below.
Why
Because.
Where
Check for prerequisites and install from here: Download ColorMePrivileged.
Usage
As long as it is running, the app checks the contents of the Privilege/Privilege field in the currently active Summation database and places a colored transparent overlay
upon the eDoc view.
Value in Privilege | Window color |
Yes | Red |
No | Green |
(all other values) | Gray |
Move to a different record and color will update as appropriate:
If the overlay does not initially match the edoc window dimensions, moving to a different record should correct - see note re DPI below
for further information. If the eDoc window is manually resized, moving to a different record should re-sync.
Exit the application by right-clicking anywhere on the overlay.
ColorMe is not smart enough to know when Summation has focus and will always be the topmost screen while it is running. For example, Summation could be minimized
and there will still be a colored transparency on the screen. Then switch to Microsoft Word and the colored overlay will still be visible, appearing on top of the currently
open Word document.
In order to select text from the eDoc viewer, first shrink the transparency by left-clicking anywhere on the coloring. This will reduce the overlay to cover only the
label in the upper left-hand cornder. Once finished, left-click the remaining mini-window in order to restore overlay to full-size.
Technical Details
Initial Setup
ColorMePrivileged checks to see if either Summation iBlaze or Enterprise is running by iterating through the currently running process and displays pretty message box if neither is available.
If Summation is indeed running, (swsom.)Application.Script is called in order to run the .vs script that has been deployed to the application directory of the ClickOnce app.
The script will a) check to make sure a column named either 'Privilege' (Enterprise default) or Privlege (iBlaze default) is present in the current case/database and b) load
an OnImageRequested function into (Summation's) memory. The main ColorMe app then uses swsom to add this function to the ImageRequested event of the DB object - doing it
this way, instead of within the .vs script, means that the new OnImageRequested function can be unsubscribed from the ImageRequested event when user exits the application
(or it needs to close due to some error). Note that there are a number of actions, like opening a different case or, in the case of iBlaze, using utilities like Check/Pack/Blaze,
that will break the ImageRequested link. ColorMe would then need to be restarted. The next programmatic step is to create a 'watch' subfolder in the current user's Summation
profile directory, at the application level. This folder is monitored by a FileSystemWatcher in order to provide coordination between the current record and the WPF app.
I initally had trouble getting the FileSystemWatcher to actually register any changes, due to the WPF Threading Model.
My first concern was getting it to work and only afterwards trying to understand the why (mission marginally accomplished). Either way, a delegate needed to be created and
queued to the main UI thread via Dispatcher.Invoke. The delegate
calls the handler method that actually responds to the file watcher events, in this case for new files only. All things considered, performance in terms of record-change ->
WPF window update is ... adequate.
|
Assuming everything has gone OK so far, the initial sync with Summation is performed. If the eDoc view is not already in Float mode (as opposed to Tabbed, Docked and/or
Hidden) it is forced to Float. This is done in because the only solid coordinates for a window that are supplied by the Summation API are when a given View is 'Floated'.
I spent some time using Spy++ and P/Invoke (FindWindow, GetWindowRect etc.) in order to get the eDoc window coordinates when in other modes but never really got anywhere
useful with that approach. Now the app gets the four screen coordinates for the floated eDoc window via (swsom)Views.FloatPos and Views.FloatSize, accounts for DPI as necessary,
and applies some offset in order to leave clear the title bar (allow eDoc window to be moved) and window handles (allow for manually resizing). Those final coordinates are
used to populate a Rect that represents the area to be shaded.
My initial testing on a hardware VM hosted on my laptop looked fine in terms of the WPF rectangle display matching the Summation eDoc window but once I installed ColorMe
as a ClickOnce application on the host laptop, things went a little wonky. The WPF window that was supposed to be overlaid directly on top of the eDoc window was both offset
in location and, larger overall, though not at a constant number of pixels. I tried mapping the eDoc window coordinates against the WPF as-displayed coordinates with the help
of AutoHotKey's Window Spy and recorded a series of differences like
edoc: wpf: offset:
X 667 840 +173
Y 348 460 +112
W 347 405 +58
H 339 393 +54
Followed that by changing the resolution on my laptop, to no visible effect. Luckily a Google search for 'WPF window distortion' pointed to Is WPF Really Resolution Independent?
More information than I could have wanted but that page did lead to the answer, where the DPI setting on my VM was 96/normal vs. 120/Large size (125% normal size) on the
laptop. The solution was to, after accounting for the desired pixel offset, divide the Views.FloatPos and Views.FloatSize values by the mystical M11 and M22 values of the
current system in order to constitute an accurate Rect, whatever the DPI setting:
C#
Matrix m = PresentationSource.FromVisual(Application.Current.MainWindow).CompositionTarget.TransformToDevice;
_dpiX = m.M11;
_dpiY = m.M22;
...
double innerX = (floatX + 6) / _dpiX;
double innerY = (floatY + 23) / _dpiY;
double innerWidth = (floatWidth - 27) / _dpiX;
double innerHeight = (floatHeight - 28) / _dpiY;
Rect edocRect = new Rect(innerX, innerY, innerWidth, innerHeight);
|
Since the M11/M22 values cannot be retrieved until the WPF window has been created, the initial overlay will be distorted if DPI is not 96. Once a different db record
has been selected the overlay will resize correctly.
|
All of the code execution is happening within the WPF Window instance, so once it has been constructted the Rect can be passed to a method that updates the window location:
C#
|
this.Left = position.Left;
this.Top = position.Top;
this.Width = position.Width;
this.Height = position.Height;
|
The Topmost property on the window was initialized at True, with an Opacity setting of 0.25.
Keeping in sync
On the script side, whenever a different record is selected within Summation the ImageRequested event fires and the custom in-memory OnImageRequested function is called.
The function checks the value of the Privelege/Privlege field and determines which three files will be created in the folder being monitored by the FileSystemWatcher:
VBScript
priv = lcase(db.fields(fieldName).value)
If (priv = "yes") Then
fileName = "red"
ElseIf (priv = "no") Then
fileName = "green"
Else
fileName = "none"
End If
|
The function then uses FileSystemObject via VBScript to create a file of the designated name (and immediately delete it), which triggers the FileSystemWatcher.Created event.
That in turn leads to a .Net method that examines the name of the file and sets the color of the overlay window, to either red or green or gray. The 'gray' color is for
for records in which Privlege/Privlege does not equal either 'yes' or 'no'.
To help with pixel coordination I also put in a debug mode, where the action of creating a file named 'debug' (copying in existing file is easiest) in the
Watch folder will add pixel coordinate information to the overlay window.
|