Here is a solution to write stand-alone scripts for Smart Office. Stand-alone scripts are interesting to create mini applications in Smart Office like widgets, or to create full blown applications like composite applications.
A stand-alone script runs independently of an M3 program, in its own instance, eventually with its own user interface. Whereas a regular script runs as part of an M3 program, for example inside CRS610.
I will illustrate how to write a stand-alone script by creating a Tiling Window Manager widget. It’s a continuation of my previous post on How to tile windows in Smart Office. The result will look like this:
Make sure to read my disclaimer before trying this as I’m using non-public APIs.
First, I will create an empty window with an icon in the Taskbar:
var task = new Task(new Uri('jscript://')); task.VisibleName = 'Hello World'; var runner = DashboardTaskService.Current.LaunchTask(task, null); runner.Status = RunnerStatus.Running; var host = runner.Host; host.HostTitle = 'Hello World'; host.Show();
The result will look like a regular Smart Office window, albeit empty:
Then, I will use HostType.Widget to change the appearance of the window and make it look like a small widget:
var task = new Task(new Uri('jscript://')); task.AllowAsShortcut = false; task.VisibleName = 'Tiling Window Manager'; var runner = DashboardTaskService.Current.LaunchTask(task, HostType.Widget); runner.Status = RunnerStatus.Running; var host = runner.Host; var wrapPanel = new WrapPanel(); host.HostContent = wrapPanel; host.HostTitle = 'Tiling Window Manager'; host.ResizeMode = ResizeMode.NoResize; host.Show(); host.Width = 221; host.Height = 85;
The host’s Width and Height must be set after host.Show().
The result will look like a widget:
Then, I will add three buttons to the widget:
var buttons: String[] = [' ← ', 'Tile', ' → ']; for (var i in buttons) { var btn = new Button(); btn.Content = buttons[i]; btn.Width = double.NaN; // auto width btn.Margin = new Thickness(3, 0, 3, 0); // ltrb btn.Padding = new Thickness(7, 0, 7, 0); // ltrb wrapPanel.Children.Add(btn); } wrapPanel.HorizontalAlignment = HorizontalAlignment.Center;
The result will finally look like the desired widget:
Then, I will add an event handler for the buttons:
btn.add_Click(OnClick); ... function OnClick(sender: Object, e: RoutedEventArgs) { if (sender.Content.Equals(' ← ')) { // } else if (sender.Content.Equals('Tile')) { // } else if (sender.Content.Equals(' → ')) { // } }
Then, I will add the functions for tiling and shifting the visible windows horizontally on the screen.
var shift = 0; ... /* Tiles the specified windows horizontally accross the screen. */ function tileInstances(instances: ArrayList) { this.shift = 0; for (var i = 0; i < instances.Count; i++) { tileInstance(instances[i], i, instances.Count); } } /* Shifts the specified windows horizontally, to the left or to the right. */ function shiftInstances(instances: ArrayList, increment: int) { this.shift += increment; for (var i = 0; i < instances.Count; i++) { var n: int = instances.Count; var j: int = (((i + this.shift) % n) + n) % n; // fix the JavaScript modulo bug tileInstance(instances[i], j, instances.Count); } }
Then, I will deploy the script on the server.
For Grid installations the deploy folder is somewhere like:
\\hostname\d$\Lawson\LifeCycleManager\Service\XYZ\grid\TST\applications\LSO_M3_Adapter\webapps\mne\jscript\
For non-Grid installations the deploy folder is somewhere like:
\\hostname\d$\IBM\WebSphere7\AppServer\profiles\MWPProfile\installedApps\MWPProfileCell\MWP_EAR.ear\MNE.war\jscript\
Then, I will add a shortcut to the Smart Office Canvas to launch the script with this special syntax:
mforms://_runscript?name=TilingWindowManager
My final script is:
import System; import System.Collections; import System.Windows; import System.Windows.Controls; import Mango.Services; import Mango.UI.Core; import Mango.UI.Services; import MForms; import Mango.UI; /* Thibaud Lopez Schneider Infor May 7, 2012 This script opens a widget to tile and shift the visible windows horizontally in Smart Office. */ package MForms.JScript { class TilingWindowManager { var shift = 0; public function Init(element: Object, args: Object, controller : Object, debug : Object) { try { var task = new Task(new Uri('jscript://')); task.AllowAsShortcut = false; task.VisibleName = 'Tiling Window Manager'; var runner = DashboardTaskService.Current.LaunchTask(task, HostType.Widget); runner.Status = RunnerStatus.Running; var host = runner.Host; host.HostContent = CreateWindow(); host.HostTitle = 'Tiling Window Manager'; host.ResizeMode = ResizeMode.NoResize; host.Show(); host.Width = 221; host.Height = 85; } catch(ex: Exception) { ConfirmDialog.ShowErrorDialogWithoutCancel(ex.GetType(), ex.Message + '\n' + ex.StackTrace, null); } } function CreateWindow() { var wrapPanel: WrapPanel = new WrapPanel(); var buttons: String[] = [' ← ', 'Tile', ' → ']; for (var i in buttons) { var btn = new Button(); btn.Content = buttons[i]; btn.Width = double.NaN; // auto width btn.Margin = new Thickness(3, 0, 3, 0); // ltrb btn.Padding = new Thickness(7, 0, 7, 0); // ltrb wrapPanel.Children.Add(btn); btn.add_Click(OnClick); } wrapPanel.HorizontalAlignment = HorizontalAlignment.Center; return wrapPanel; } /* Returns a list of the visible windows. */ function getVisibleInstances() { var instances = MainController.Current.GetInstances(); var visibleInstances = new ArrayList(); for (var instance in instances) { var window: EmbeddedHostWindow = instance.Host.Implementation; if (window.Visibility == Visibility.Visible) { visibleInstances.Add(instance); } } return visibleInstances; } /* Tiles the specified window at the specified index relative to the specified count of windows. */ function tileInstance(instance: InstanceController, i: int, count: int) { var window: EmbeddedHostWindow = instance.Host.Implementation; window.Width = instance.ParentWindow.Width / count; window.Height = instance.ParentWindow.Height; DashboardService.Window.SetPosition(new Point(window.Width * i, 0), window); } /* Tiles the specified windows horizontally accross the screen. */ function tileInstances(instances: ArrayList) { this.shift = 0; for (var i = 0; i < instances.Count; i++) { tileInstance(instances[i], i, instances.Count); } } /* Shifts the specified windows horizontally, to the left or to the right. */ function shiftInstances(instances: ArrayList, increment: int) { this.shift += increment; for (var i = 0; i < instances.Count; i++) { var n: int = instances.Count; var j: int = (((i + this.shift) % n) + n) % n; // fix the JavaScript modulo bug tileInstance(instances[i], j, instances.Count); } } /* Handles the click on the buttons. */ function OnClick(sender: Object, e: RoutedEventArgs) { try { var visibleInstances = getVisibleInstances(); if (visibleInstances.Count > 0) { if (sender.Content.Equals(' ← ')) { shiftInstances(visibleInstances, -1); } else if (sender.Content.Equals('Tile')) { tileInstances(visibleInstances); } else if (sender.Content.Equals(' → ')) { shiftInstances(visibleInstances, +1); } } } catch(ex: Exception) { ConfirmDialog.ShowErrorDialogWithoutCancel(ex.GetType(), ex.Message + '\n' + ex.StackTrace, null); } } } }
Voilà!
This solution showed how to create a stand-alone script in Smart Office, how to create a widget-like script, and how to tile and shift windows.
If you liked this solution, I invite you to subscribe to this blog.
Special thanks to Peter A.J. for the original help.
Great finding dude!! I take it! Thanks!
LikeLike
Thanks Juan! This solution was a 3-in-1.
LikeLike
Interesting, goods work! Do you know what version of Smart Office is required for “Stand-alone scripts”?
LikeLike
Hi Daniel, I don’t know the version numbers. I wrote the post using Smart Office 10.0.2.0.4. I think the special shortcut mforms://_runscript and the LaunchTask work since Lawson Smart Client 1.x; I started using it around three years ago. I don’t know about the special look and feel HostType.Widget; I started using it around over a year ago with Smart Office 9.x. Nevertheless, not much of the source is using public APIs of Smart Office, so it’s subject to change in the future.
LikeLike
Great stuff and worked perfectly, thanks.
Would it be possible to adapt this to add images and use the button/s to cycle through them ?
That would be awesome.
Any help would be much appreciated.
LikeLike
Hi Colm, I don’t understand your requirement about the images and the buttons; I would need more details. It’s technically possible to add images, add buttons, and listen to keyboard input with a script in an M3 program. So I guess your requirement is possible. If you need official support, I invite you to contact me with more details at my Infor email address which you can find at http://www.thibaudlopez.net/
LikeLike
Hello Thibaud! I copied your script, but the tile only covers about 2/3 of the sceeen. Can I in the code somewhere change the screen resolution? I am using 1600/800. Kind regards, Johan
LikeLike
Hi Johan, the script is independent of the screen resolution as it’s using instance.ParentWindow.Width and instance.ParentWindow.Height. I tested the script on 1024×768 and 1600×900 and it works fine on both resolutions. Maybe my script doesn’t work for your version of Smart Office, it’s plausible. What exact version number do you have?
LikeLike
Hi there! Great post! I didn’t know this blog existed. I’m linking it on my blog 🙂 /Thibaud
LikeLike
Dear Thibaud,
My new issue is related with calling scripts from Mashup. This post by CA, which is a partner of our company, has sorted out the issue completely.
Using {Variable} directly instead of {}{Variable} can eliminate the special character issue, like #, which is used to mean temporary customer address.
Best Regards,
Warren
LikeLike
Nice post (like usual!).
I used this script as a basis to create a widget that counts the number of error records in GLS037 for the current company/division; the counter is refreshed every x minutes. Is there a way to automatically launch this script defined as a shortcut (mforms://…) as soon as the user logs on ?
LikeLike
Hi Max, thank you for the feedback. I believe you can run a script on startup but I forgot how. I know you can do &task=mforms://_runcript=myscript.js where you have to properly URI-encode the parameter values in cascade. Maybe you can add _runscript on the canvas. Ask Karin or norpe, they would know. /Thibaud
LikeLike
You are right. On their blog, it is said that you can add a parameter to the link of the Smart Office URL. Something like this :
…/mango/MangoClient.application?&task=mforms://_runscript?name=MyScript.js
Use internet explorer and… it works! The widget is opened automatically as soon as you log in.
LikeLiked by 1 person
To add arguments you can use the args parameter, for example:
…/mango/MangoClient.application?&task=mforms://_runscript?name=MyScript.js&args=12345
Jonathan
LikeLike
Maxime, I just re-read your requirement. I would use Event Analytics for such counter. Have you considered it? Also, instead of using _runscript in the URL, you can create a feature with Smart Office SDK in C#.
LikeLike
Event analytics would be a great idead. As for SDK, it’s a bit complicated for a zero-skilled C# user 😉
LikeLiked by 1 person