APF Refactoring Tool

Start the APF Refactoring Tool and press the Analyze button. The tool will then read the source code, analyze and modify it.

The changes resulted by refactoring will be written into a new location, <AnalyzeDir>.modified, keeping the original files untouched. This is done in to get the possibility of being able to compare the original and altered files with each other.

Once the result is verified, press the Merge button. That will...

  1. Copy all original files from <AnalyzeDir> into another new location named <AnalyzeDir>.merged.
  2. Copy all altered files from <AnalyzeDir>.modified into the new location <AnalyzeDir>.merged, overwriting the original files.

After compiling the contents in <AnalyzeDir>.merged and verifying that the business logic works as expected, press the Replace button, which will result in

  1. Delete the original <AnalyzeDir> folder
  2. Rename the <AnalyzeDir>.merged into <AnalyzeDir>.

If you are using versioning control like e.g. SVN, the result will be in a folder (<AnalyzeDir>) that contains both original & altered files ready to be checked in.

There will be some objects that will not be modified but be listed to bring in to attention. Those that have not been modified and require attention and those that have been actually modified will be shown in a tabular form.

The APF Refactoring tool do several types of refactoring.

  1. Navigation
  2. Dialog Access
  3. Access Modifiers
  4. Clean Up
  5. Redesign

Navigation

This option replaces the source code that might have anything to do with navigation logic, that navigates to a window or uses the window name for comparing purposes in some way.

Prerequisites

Result

The result will be having source code using a known window name to be enriched appending the method Pal.GetActiveInstanceName.
It's purpose is to create a "Dispatch" logic that navigates to either original windows or customized windows, all depending on the environment the code is compiled in.

In most cases, having windows that are not customized, the returned value will be the same window name that is passed as argument:
    Pal.GetActiveInstanceName("frmBasePartCharacteristic") -> frmBasePartCharacteristic

But for customized windows, the returned value will be the name of the customized window (or simple the name of the window that "replaces" the original window).
    Pal.GetActiveInstanceName("frmBasePartCharacteristic") -> frmBasePartCharacteristic_Cust
 

SessionNavigate("frmBasePartCharacteristic");

Example: Before the change

 

SessionNavigate(Pal.GetActiveInstanceName("frmBasePartCharacteristic"));

Example: After the change

Comments

All framework methods that somehow navigates to or opens a window have the Pal.GetActiveInstanceName logic "built-in" meaning that if Pal.GetActiveInstanceName would be missed somewhere, the customized window will still be opened and the "Dispatching" would work just as expected.

The example above, using SessionNavigate which is a framework method, would still work even if the Pal.GetActiveInstanceName would be excluded since the SessionNavigate method itself have the Pal.GetActiveInstanceName method "built-in".

Places where the method is not "build-in" can be e.g. when variables are compared with static window names like here:

    if (sName == "frmBasePartCharacteristic")

The above example will return the wrong result if frmBasePartCharacteristic is customized and sName expects to contain frmBasePartCharacteristic_Cust, hence the correct way of solving this is:

    if (sName == Pal.GetActiveInstanceName("frmBasePartCharacteristic"))


As result of the different scenarios and not being forced to keep track knowing when to use Pal.GetActiveInstanceName and when not, the recommendation is to enrich all possible "navigation" candidates, even if most of them will work without being enriched. Therefore, the source code might become unnecessary enriched with Pal.GetActiveInstanceName, but will on the other have be well defined explicitly indicating when the "Dispatching" might occur.

Dialog Access

This option changes the source code that instantiates/opens modal dialogs, typically by changing the implementation of the static method ModalDialog that is part of the dialog template.

Result

The static method ModalDialog will have its implementation altered and use the framework method DialogFactory.CreateInstance, which purpose is to instantiates the proper dialog (original or customized one).

The constructor will have its arguments removed, becoming a default constructor (one without arguments). The parameters to the dialog will instead be set inside the ModalDialog method.

The constructor will become protected, only to be used for sub classing.

 

public dlgCopyLibrary(SalWindowHandle hWndSource, SalString sSource, SalString sSourcePrompt, SalString sPrompts)
{
   // Assign global reference.
   App.dlgCopyLibrary = this;
   // Window Parameters initialization.
   this.hWndSource = hWndSource;
   this.sSource = sSource;
   this.sSourcePrompt = sSourcePrompt;
   this.sPrompts = sPrompts;
   // This call is required by the Windows Form Designer.
   InitializeComponent();
}

public static SalNumber ModalDialog(Control owner, SalWindowHandle hWndSource, SalString sSource, SalString sSourcePrompt, SalString sPrompts)
{
   dlgCopyLibrary dlg = new dlgCopyLibrary(hWndSource, sSource, sSourcePrompt, sPrompts);
   SalNumber ret = dlg.ShowDialog(owner);
   return ret;
}

Example: Constructor and ModalDialog implementation before the change

 

protected dlgCopyLibrary()
{
   // Assign global reference.
   App.dlgCopyLibrary = this;
   // This call is required by the Windows Form Designer.
   InitializeComponent();
}

public static SalNumber ModalDialog(Control owner, SalWindowHandle hWndSource, SalString sSource, SalString sSourcePrompt, SalString sPrompts)
{
   dlgCopyLibrary dlg = DialogFactory.CreateInstance<dlgCopyLibrary>();
   dlg.hWndSource = hWndSource;
   dlg.sSource = sSource;
   dlg.sSourcePrompt = sSourcePrompt;
   dlg.sPrompts = sPrompts;
   SalNumber ret = dlg.ShowDialog(owner);
   return ret;
}

Example: Constructor and ModalDialog implementation after the change

Scan Warnings

There might be code constructions the tool can't automatically resolve and that might be in need of manual changes.
Following list shows a list of error messages and how to best proceed with these.

Error or the Information message Resolution
Static method 'ModalDialog' could not be found A modal dialog needs a static ModalDialog method in order to be properly opened.
Add the method ModalDialog.
Static method 'ModalDialog' found (overload) The tool can only refactor standard dialogs, which contains only one static method  ModalDialog.
Change all the static methods ModalDialog .
The contents of the static method 'ModalDialog' could not recognized The static method ModalDialog was found but uses a unknown pattern.
Change the static method ModalDialog.
A constructor could not be found  There is no constructor.
Add the default constructor.
x constructors found (overload)  There are several constructors.
Ensure there is only a default constructor by removing the ones having arguments, keeping the one without any arguments.
The access modifier for the constructor could not be resolved A critical error in the tool not being able to resolve the access modifier for the constructor.
Change the access modifier
Unsupported dialog access, using '<Dialog>.CreateWindow', making the dialog 'Modeless' This method opens the dialog in a modeless state, not supported inside IEE.
Rewrite the code using <Dialog>.ModalDialog instead.
Unsupported way of dynamically opening modal dialogs using 'Sal.CompaileAndEvaluate' Sal.CompileAndEvaluate is unsupported and not to be used.
Rewrite the code using a strongly typed call (<Dialog>.ModalDialog) or using a dynamic call (DialogFactory.DynamicModalDialog) for opening the dialog
Unsupported dialog, being 'Modeless' Unsupported window decoration FndWindowRegistrationFlags.ModelessDialog

Rewrite the dialog being a modal dialog

Comments

All opening of modal dialogs must be done via the static mehod(s) ModalDialog, since these method(s) implements the framework "Dispatching" using the DialogFactory.CreateInstance method.

If a component do not have a reference to the assembly which owns the dialog but still needs to open it (probably due to being dynamically installed), the proper way of opening these dialogs is to use the dynamic method SessionModalDialog (details).

Note: Older constructions using Sal.CompileAndEvaluate and Ifs.Fnd.ApplicationForms.Var.g_DlgReturnValues are no longer supported and must be refactored. See details.

Access Modifiers

This option changes the source code and makes object accessible in sub classed windows by changing their access modifiers and letting methods become virtual, possible to override.

Prerequisites

Result

Items/Methods being private till becomes protected. Normal methods becomes virtual methods.

Comments

The change of methods, making them virtual, is not done for all methods. System methods like InitializeComponent & Dispose etc are typically excluded. Late bound methods are excluded also since they already have a public virtual wrapper method, vrt<Method>, that is supposed to be used when overriding these.

Clean Up

This option is cleaning up unnecessary source code like obsolete methods that are not used anywhere. Known source constructions can also be refactored by this option, becoming shorter, easier to read or simply using an alternative API. The step is optional and will not have any logical impact on the business logic if or not run.

Clean Up Action Comment
Static method 'CreateWindow' removed The method is not to be used, due to not working together with the IEE design and concepts. Windows should typically be opened using e.g. SessionNavigate, dialogs using e.g. SessionModalDialog.
Window decoration 'FndWindowRegistration' made shorter FndWindowRegistration decorations are often unnecessary long, using default parameters that can be removed by using one of its overloaded decorations.
Window decoration 'FndWindowRegistration' removed FndWindowRegistration decoration being empty can be removed.
Window decoration 'FndWindowRegistration' duplicate FndWindowRegistration decoration being a duplicate can be removed.
Window decoration 'DynamicTabPage' made shorter DynamicTabPage decorations are often unnecessary long, using default parameters that can be removed by using one of its overloaded decorations.
Window decoration 'DynamicTabPage' duplicate DynamicTabPage decoration being a duplicate can be removed.
Ctor of App reference removed "ThreadStatic" references in App.cs files are no longer used. The Constructor needs to have its reference assignment removed.
Dispose of App reference removed "ThreadStatic" references in App.cs files are no longer used. The Dispose method needs to have its reference unassignment removed.
Reference to 'App.cs' removed "ThreadStatic" references in App.cs files are no longer used. The *.csproj file can exclude its reference.
Attribute 'NodeSetup' removed cTreeListBox attribute NodeSetup is unused and can be removed. When used with the .NET 4.5.2 Designers, the old binary serialization causes errors.

Redesign

This option highlights areas that need to be redesigned in the application where the current design does not support extending.

Redesign Action Comment
Use of TableLayoutPanel control Shows where TableLayoutPanel control is used. TableLayoutPanel control should not be used in a form that is expected to be customized since it does not support visual inheritance.