Custom Dialog Class, Batch Job Class, & Remembering Parameters - arp6333/xplusplus GitHub Wiki
Regular dialog classes should extend RunBase.
public class CustomDialog extends RunBase
{
...
}
Batch job classes should extend RunBaseBatch and can also implement BatchRetryable. Users do not have to run in batch but this adds the option to run as batch.
class CustomBatch extends RunBaseBatch implements BatchRetryable
{
...
}
The top of the class will contain the packed variables and dialog fields. For this example, I have one yes/no box 'download locally' that I want to display on the form for the user to select.
Then, the Macro which tells the pack/unpack methods the version and list of variables to pack/unpack (pack/unpack will get into next). When adding variables to the list, it is best to increment the CurrentVersion by 1. Any variables you want on the dialog should go into the CurrentList.
// Packed variables
int dummy;
NoYes downloadLocally;
// Dialog fields
DialogField dlgLocalDownload;
#define.CurrentVersion(2)
#localmacro.CurrentList
dummy,
downloadLocally
#endmacro
Pack and unpack are used to store and retrieve the dialog fields when the user has a successful run. This is how the dialog will remember values the user has entered on previous runs. This code should never change from class to class (unless rare circumstance).
/// <summary>
/// Returns the container of packed CurrentVersion and CurrentList.
/// </summary>
/// <returns>Packed container.</returns>
public container pack()
{
return [#CurrentVersion, #CurrentList];
}
/// <summary>
/// Unpack the container of packed CurrentVersion and CurrentList.
/// </summary>
/// <param name = "packedClass">Packed container.</param>
/// <returns>True if successful; otherwise false.</returns>
public boolean unpack(container packedClass)
{
Version version = runbase::getVersion(packedClass);
switch (version)
{
case #CurrentVersion:
[version, #CurrentList] = packedClass;
break;
default:
return false;
}
return true;
}
Next, we will instantiate the dialog method which will create the dialog and all fields on it. Since we have pack/unpack, we can restore any values to variables that users have entered on previous successful runs here.
After that, we also want the getFromDialog method. This will retrieve any parameters from the dialog and assign them to our variables.
/// <summary>
/// Adds fields to the dialog box.
/// </summary>
/// <returns>The dialog box box.</returns>
public Object dialog()
{
DialogRunbase dialog;
// Setup the dialog
dialog = super();
// Dialog caption is the text at the top of the dialog
dialog.caption("@AccountsReceivable:description");
// Add our field(s) to the dialog
// extendedTypeStr should contain the appropriate EDT type for displaying your variable on the dialog
// You can add table references to an EDT to allow the user to select from a field pulled from a table, and even add filters to it
dlgLocalDownload = dialog.addField(extendedTypeStr(NoYesId), "@AccountsReceivable:localDownload");
// If downloadLocally was entered on a previous successful run, we can set it here
if (downloadLocally)
{
dlgLocalDownload.value(downloadLocally);
}
return dialog;
}
/// <summary>
/// Retrieves the user entered values from dialog form.
/// </summary>
/// <returns>True if the values are retrieved successfully; otherwise false.</returns>
public boolean getFromDialog()
{
boolean ret = super();
downloadLocally = dlgLocalDownload.value();
return ret;
}
Following this is the run method: where all processing after the user clicks 'OK' is done. This is where you will put the meat and potatoes of what you want the actual process to do.
/// <summary>
/// Runs the main process.
/// </summary>
public void run()
{
...
}
The last of the larger methods are the main and constructor methods. Constructor method is as an constructor, and the main method will construct the class object, prompt the dialog, and call the run method when the user clicks 'OK'
/// <summary>
/// Main method.
/// </summary>
/// <param name = "args">Class arguments.</param>
public static void main(Args args)
{
CustomBatch customBatch = new CustomBatch();
customBatch.parmInBatch(false);
if (customBatch.prompt())
customBatch.runOperation();
}
/// <summary>
/// Construct a new object of this class.
/// </summary>
/// <returns>Class object.</returns>
public static CustomBatch construct()
{
return new CustomBatch();
}
Other misc. dialog functions to include, some mandatory some not:
/// <summary>
/// Prompts the dialog box.
/// </summary>
/// <returns>True if successful, otherwise false.</returns>
boolean prompt()
{
return super();
}
/// <summary>
/// Sets the class description.
/// This text will also be saved as the default 'job description' in the Batch Jobs form (users can still modify it).
/// </summary>
/// <returns>Class description.</returns>
public static ClassDescription description()
{
return "@AccountsReceivable:description";
}
/// <summary>
/// Describes whether the class is designed for execution in a new session.
/// </summary>
/// <returns>If true is returned, the batch can run in a new session; otherwise it can not.</returns>
protected boolean canRunInNewSession()
{
return false;
}
/// <summary>
/// Specifies if the batch task is retryable for transient exceptions or not.
/// </summary>
/// <returns>If true is returned, the batch task is retryable; otherwise it is not.</returns>
[Hookable(false)]
final boolean isRetryable()
{
return true;
}
Finished dialog:
Full (pseudo-)code:
/// <summary>
/// The <c>CustomBatch</c> class handles a custom process with the ability to run in batch.
/// </summary>
class CustomBatch extends RunBaseBatch implements BatchRetryable
{
// Packed variables
int dummy;
NoYes downloadLocally;
// Dialog fields
DialogField dlgLocalDownload;
#define.CurrentVersion(2)
#localmacro.CurrentList
dummy,
downloadLocally
#endmacro
/// <summary>
/// Returns the container of packed CurrentVersion and CurrentList.
/// </summary>
/// <returns>Packed container.</returns>
public container pack()
{
return [#CurrentVersion, #CurrentList];
}
/// <summary>
/// Unpack the container of packed CurrentVersion and CurrentList.
/// </summary>
/// <param name = "packedClass">Packed container.</param>
/// <returns>True if successful; otherwise false.</returns>
public boolean unpack(container packedClass)
{
Version version = runbase::getVersion(packedClass);
switch (version)
{
case #CurrentVersion:
[version, #CurrentList] = packedClass;
break;
default:
return false;
}
return true;
}
/// <summary>
/// Adds fields to the dialog box.
/// </summary>
/// <returns>The dialog box box.</returns>
public Object dialog()
{
DialogRunbase dialog;
// Setup the dialog
dialog = super();
// Dialog caption is the text at the top of the dialog
dialog.caption("@AccountsReceivable:description");
// Add our field(s) to the dialog
// extendedTypeStr should contain the appropriate EDT type for displaying your variable on the dialog
// You can add table references to an EDT to allow the user to select from a field pulled from a table, and even add filters to it
dlgLocalDownload = dialog.addField(extendedTypeStr(NoYesId), "@AccountsReceivable:localDownload");
// If downloadLocally was entered on a previous successful run, we can set it here
if (downloadLocally)
{
dlgLocalDownload.value(downloadLocally);
}
return dialog;
}
/// <summary>
/// Retrieves the user entered values from dialog form.
/// </summary>
/// <returns>True if the values are retrieved successfully; otherwise false.</returns>
public boolean getFromDialog()
{
boolean ret = super();
downloadLocally = dlgLocalDownload.value();
return ret;
}
/// <summary>
/// Runs the main process.
/// </summary>
public void run()
{
...
}
/// <summary>
/// Main method.
/// </summary>
/// <param name = "args">Class arguments.</param>
public static void main(Args args)
{
CustomBatch customBatch = new CustomBatch();
customBatch.parmInBatch(false);
if (customBatch.prompt())
customBatch.runOperation();
}
/// <summary>
/// Construct a new object of this class.
/// </summary>
/// <returns>Class object.</returns>
public static CustomBatch construct()
{
return new CustomBatch();
}
/// <summary>
/// Prompts the dialog box.
/// </summary>
/// <returns>True if successful, otherwise false.</returns>
boolean prompt()
{
return super();
}
/// <summary>
/// Sets the class description.
/// This text will also be saved as the default 'job description' in the Batch Jobs form (users can still modify it).
/// </summary>
/// <returns>Class description.</returns>
public static ClassDescription description()
{
return "@AccountsReceivable:description";
}
/// <summary>
/// Describes whether the class is designed for execution in a new session.
/// </summary>
/// <returns>If true is returned, the batch can run in a new session; otherwise it can not.</returns>
protected boolean canRunInNewSession()
{
return false;
}
/// <summary>
/// Specifies if the batch task is retryable for transient exceptions or not.
/// </summary>
/// <returns>If true is returned, the batch task is retryable; otherwise it is not.</returns>
[Hookable(false)]
final boolean isRetryable()
{
return true;
}
}