Sunday, December 25, 2016

Write It Using Word, Post It to Blogger: A quick way to get your Word document posted to Blogger

Genesis

I had a Word document that I spent some time preparing and suddenly decided that it would make a good blog post. Problem: How to get the document into Blogger without actually re-keying it or spending lots of time fixing formatting errors after using some form of cut and paste.

Here's how I finally resolved my problem. 

Prepare and Import the Word Document

  1. Prepare your Word document in the normal way. I usually save the Word document as a .docx file so it can be easily reedited.
  2. I also typically prepare a .pdf of the final document to make sharing the document easier and also to make it difficult to change or plagiarize it.
  3. To use the document for a Blogger post, save the document as a .odt file (Open Document Text). This seems to be the only format that Google Docs and Blogger will handle easily.
  4. Open Google Docs and import your .odt document into Google Docs. Open it.
  5. Use Ctrl-A to select all of your document text. (If you have headers and footers, it will not include them.)
  6. Use Ctrl-C to copy the selected text.
  7. Switch to Blogger and create a new, empty blog.
  8. Paste the copied text into the empty blog. It will likely be formatted quite well and require no further manipulation.

Caution

If you feel the need to start tweaking various items of your blog, you'll probably end up with a mess. I'm not sure why, but this technique results in HTML that is not easily controlled by the Blogger editor functions.

Go ahead and fiddle with things if you must, but don't say I didn't warn you.

When Your Blog Passes Muster

Publish it!

Salesforce Macros: A Quick Guide to Enablement and Implementation

Salesforce Macros
A Quick Guide to Enablement and Implementation
  1. Preamble

I normally blog about Delphi, however this is an exception. I was recently asked to examine Salesforce macros and discovered a world of difficulty in getting my arms around the conceptual framework and obscure documentation. In order to preserve and share that hard-won experience, I decided to prepare this blog. Any errors are mine and please feel free to share corrections and improvements in the comments.
  1. Overview

As with any macro, Salesforce macros encapsulate a series of operations so that when the macro is invoked, the operations specified take place more or less automatically, thus resulting in fewer errors and greater efficiency. Salesforce is notorious for some of the worst documentation on the planet; it is generally 100% accurate and in many cases, nearly 100% useless for learning and solving problems. Macros are no exception, and the Salesforce documentation may actually be 110% useless. This guide will attempt to anticipate those deficiencies and offer the reader a quick way to navigate the false starts and poorly documented settings needed to actually get Salesforce macros to work.
This guide was developed used a Salesforce Developer Sandbox in December, 2016. The Sandbox was created sometime in November, 2016. Salesforce is a moving target, constantly rearranging, redefining and often making seemingly arbitrary changes to nomenclature and the interface. If you’re reading this a year or so after I post it, don’t be afraid to “reinterpret” my approaches and explanations to fit the current Salesforce paradigms, interfaces and idiosyncrasies.
  1. Development Technique

Your workflow when developing macros is likely to alternate frequently between a Setup page and your running console app. Don’t hesitate to switch back and forth a lot. Work on something in the Setup and then immediately try it in your app. To minimize the keystrokes it takes to switch back and forth, note the following:
  • If you are displaying a console, click the gear in the upper right corner of the window to switch immediately to the Setup display.
  • From a non-console view, click the Setup item next to your name.
  • Use the Quick Find / Search box at the top of the Setup menu tree. It makes finding some setup items much faster than trying to open the reveal triangles to navigate.
  • When you are displaying a non-console page, a quick navigation is provided at the top of the page, on the left side of the window. This will typically say something like “Back to xyz-app.” You’re one click away from your app using this navigation aid.
  1. Prerequisites

It is assumed that the reader knows how to find the Setup button and further that the reader has full administrative authority. You may want to work in a sandbox or developer edition but for even a beginning administrator, you probably won’t be able to do much harm to your organization if you are the least bit careful. Hence you can dive right in on your organization’s production system with some degree of confidence. Even if your macros are a dismal failure, you won’t preclude the organization’s functioning.
  • Macros are only available in: Professional, Enterprise, Performance, Unlimited, and Developer editions.
Click SetupAdminister to display the edition at the top of the page. Click SetupCompany ProfileCompany Information to display lots of useful stuff about your organization. Of particular interest are the licenses assigned to the particular instance of Salesforce you are using.
  • Macros are supported only on the Accounts, Cases, Contacts, and Leads objects. (Salesforce objects are nothing more than a relational entity to use standard E/R jargon.)
  • Macros are only available on console applications. The documentation says only on “Service Console” but that is misleading. At one time, there may have been a Service Console, but now you can designate any app to be a console app. This simply means that the user will have access to multiple records in tabs rather than the nearly unusable standard presentation Salesforce uses.
  • Feed Tracking must be enabled for objects (remember, only four are supported—see above) you intend to target a macro to.
Go to SetupFeed Tracking. Click on the object needed (remember, only four are supported for macros) and then click the Enable Feed Tracking check box at the top of the display. Remember to click Save to save the setting.
  • Use a feed-based page layout for objects that are targets for your macros. (Remember, only four objects are supported for macros.) This one is tougher. You must either use a feed-based layout or if none exists, create one.
Click SetupCustomizethe desired object, i.e. CASESPage Layouts. This will display all page layouts for that object. At the far right is a check-box that says "Feed-based Layout." You cannot change this setting, it is read-only. If you need to create a feed-based layout, click the New button. You will be given a chance to clone an existing layout under a new name. Be sure to check the “Feed-Based Layout” check box for your new layout! Cloning is probably the easiest way to get a feed-based layout but if you’re really ambitious, you can create your own from scratch.
After you clone or create your page layout, press the Save button to save it. You will be redirected back to the list of Page Layouts for the object you’re working on.
Click Page Layout Assignment. Click Edit Assignment. Make sure your new page is assigned to the user profiles for users who will be using macros. At the very least, if you have an Administrator profile, make sure you assign the Page Layout to System Administrator.
  • Now create your console application. You must do this because macros are only available on console applications, so you must either create a new console application or modify an existing one to use macros.
Go to SetupApps. You can either edit an existing console app or create a new one. You cannot change a non-console app to a console app or vice versa. If you create a new app be sure to check the “Console” radio button on the first step. After the Label, Name and Description on the second step, the app logo on the third step, you arrive at the fourth step, selecting the tabs to appear. Choose the tabs you want your app to display. Remember that only Accounts, Cases, Contacts and Leads support macros so you’ll want to include at least one of those. Move on to step 5 and organize your app’s tabs. Remember that this screen controls the way records are displayed when selected outside of primary tabs or subtabs. Move to step six and choose the profiles for which your app will be visible. If you’re the Administrator, don’t forget to check “System Administrator.” Click Finish and your app is created, but it still won’t display macros. You’ll be on the App list screen. Click the Edit action for your new app. You can now make lots of changes to your console app, but the important ones are Choose List Placement: Pinned to Left is popular with about a 30% width. But choose whatever arrangement you think is best. Choose Console Components is critical. Move “Macro Browser” to the Selected Items list box to enable the Macro Browser for the app. Be sure to click Save to save all of your changes.
  1. Writing Macros

This is the exciting part where you actually get to write and run Salesforce Macros.
  • Now run your app. The Macros widget should appear in the extreme lower right corner of the browser window. If it doesn’t you probably have forgotten to add the Macro Browser to the app. Go back and fix that. From the list dropdown (on the left if you followed the previous app configuration suggestion) choose Cases. Then click on a Case from the list. (This assumes you have some.)  The primary and subtabs (on the right if you followed the previous app configuration suggestion) will populate with the appropriate records for the selected Case. Click on a subtab to display that record. To change views between Detail and Feed, use the icons on the right near the top of the record’s display. Now you can write a macro.
Click on the Macro Browser widget in the far lower right corner of the Salesforce browser window. The widget opens. Click on + Create Macro at the very bottom left of the widget. A new primary tab opens to edit your new macro. Fill in the name and description, then click + Add Instruction. The currently available instruction selector appears. The very first thing you’ll want to do is select the appropriate record tab. If your macro updates a Case, you’ll want to choose Select Active Case Tab, etc. Click Done to move to the next instruction. Next, choose the action you’d like to perform, for example, Update Case Action. Click Done once more. Continue in the manner until you have entered all of your instructions.
To run your macro first select the tab or subtab of a record type the macro targets. I.e, if your macro targets a Case record, select a Case record tab. Now click the Macros widget and then click on the name of the macro you’d like to run. Finally, click the run triangle that appears in the macro text box. You’ll get either a success message or error messages that will help you debug your macro.
  1. More Prerequisites

Unfortunately, you may finally get around to writing a macro only to discover that you still lack some of the required resources. The two common deficiencies are Publisher Resources and Email. An explanation of these items follows.
  • Next come publisher actions. These are even more obtuse and the source of much confusion. The documentation says that publisher actions that you want to use in macros must be available on the page layout, a pretty ambiguous statement. If you are attempting to write a macro and a needed publisher action is not available in the macro editor instruction dropdown, you should check the page layout. When you are writing or editing a macro, available actions are displayed in the instruction editor dropdown list, so there is no ambiguity about an action; you either have it available or you don’t.
Go back and click Edit for the page-layout you’re using for your object. Click Quick Actions in the source pallet. This will provide a list of quick actions available to include in the section of the layout entitled “Quick Actions in the Salesforce Classic Publisher.” You may be able to simply drag the desired quick action down to the Quick Actions section and that will add the action to the macro’s dropdown list. An example of this is the “Log a Call” quick action. However, there are two instances of this quick action in the source pallet. If you hover each, you’ll discover that only one has the attribute “Create Feed Item: Yes.” This is the one to choose. The other will not appear in the macro editor.
If there are no Quick Actions available to solve your problem, you need to define your own action. After you define a new Quick Action, it will appear in the Page Layout pallet and you can drag it to the Quick Actions section of the layout. See the next bullet point for a discussion on creating quick action items.
Send an Email can be especially gnarly. This is handled in the second bullet point following. Be sure to read it if you intend to use macros to send email.
If you edit your page layout, but sure to click Save before leaving the page.
  • Define your own Quick Actions, if you need them. Then go back and include the new Quick Action in your Page Layout. Notice the almost labyrinthian path we are now following:
    1. Switch to the Button, Links and Actions items for the object you are working on;
    2. Define a quick action for the object;
    3. Switch to edit the page layout you are using for the object and its macros;
    4. Drag the new quick action object from the quick action pallet to the Quick Actions in the Salesforce Classic Publisher section of the layout and be sure to save the layout;
    5. Switch to the console view that will contain the desired macro;
    6. Edit or create the macro. The desired action should now appear in the macro instruction dropdown list.
Go to SetupCustomizethe desired object, i.e. CASESButtons, Links and Actions. Click New Action. For this example, choose Update a Record as the Action Type. Choose Change Status for the Standard Label Type. Enter Case_Status_Close for the Name. (Note the use of the snake-case underscore. This is an API name.) Enter “Close the target Case.” In the Description. Finally, enter “Case successfully modified.” In the Success Message. Finally click Save and again on the layout for the Quick Action that appears.
You will now be presented with the Action Detail page. At the top you will see the information entered when you created the Action. The next section is Predefined Field Values. Click New. On the next screen in the Field Name dropdown, choose Status. This will display a second dropdown with allowable specific values. Chose “Closed.” Click Save.
You have now created an Action that Close a case. Remember, that closing a case involves simply changing its status to “Closed,” which is what this Action does.
Go to the Page Layout you are using for the object. Click Quick Actions in the Pallet. Drag the Change Status item from the pallet to the Quick Actions section of the layout. If you have more than one Change Status item, hover over the items and choose the item that displays “Name: Case.Case_Status_Close.” This matches the name you gave the Action Item when you defined it. Click Save.
Now switch to your console app and click Macros and create a new macro. Your new action will appear in the instruction dropdown list (after first selecting the target record.) Create a macro that has the following: 1) Select Active Case Tab; 2) Select Change Status Action (this matches the name of the action); 3) Submit Action. Name and save the macro.
Test your macro on an appropriate record. This macro will change the status of a Case to Closed. (Note that this is a trivial example, as there is a Close button on the Case listing in the console. However, in complex macros, you may want to update several fields in the Case record. This can be accomplished by adding additional predefined field values in the Action item. You might also want to send email to the contact for the Case. You can include more than one action in a macro.
  • We arrive, finally, at sending email. This involves even more mystifying settings, especially if you’re working in a fresh Sandbox. Here’s how to make Email (actually “Select Email Action”) appear in the macro instruction dropdown list.
Go to SetupEmail AdministrationDeliverability and make sure that “Access level” is set to “All email.” In a fresh sandbox, this may not be the value. Click Save.
Go to SetupCustomizeCasesEmail to Case and make sure that “Enable Email-to-Case is checked. Click Save.
Go to SetupCustomizeCasesPage Layouts. Check to be sure Send Email appears in the Quick Actions section of the page layout you are using. If it is not, drag it in from the Quick Actions section of the pallet.
The item “Select Email Action” should now appear in your macro instruction dropdown. After you include the Email Quick Action item the next level of instructions will permit you to modify one or more message attributes, such as template, addressees, subject and so forth. Finish up with Submit Action to send your email.
You may now include other quick actions in your macro, such as closing the case. Macro design can be as simple or complex as you choose and limited only by your needs, resources and imagination.
  1. Conclusion

Using Salesforce macros is unfortunately excessively complex and frustrating. I recommend using an iterative approach, first establishing all of the known prerequisites and then, when you have a console app running, trying to actually write a macro. When you discover a deficiency, back up and resolve the deficiency by adjusting the Page Layout, creating an Action Item, Enabling Email or some combination of all three. Try your macro again and repeat the process until you have all deficiencies resolved and your macro functions as desired.
I have obviously left out some significant parts of the administrative burden associated with macros. For example, I haven’t dwelled at all on user permissions, but take note that there are three:
  • Create Macros
  • Run Macros
  • Run Irreversible Macros
I leave these and other details to you, assuming you are a competent administrator and capable of addressing these issues.

Thursday, August 18, 2016

VKScrollDemo: A Working Example of Vertical Scroll Box Management


This is the forth post of a four-post series on Delphi's FireMonkey support for mobile device virtual keyboards. For the first in the series, see Using Delphi's FireMonkey Vertical Scroll Box With a Virtual Keyboard.

There is source code that accompanies these blogs. The project group FMXVertScrollBoxEtude can be downloaded from GitHub:

https://github.com/Pasquina/FMXVertScrollBoxEtude/releases

Source code was developed using RAD Studio 10.1 Berlin (No updates.)

The GUI


Execute the VKScrollDemo project with an Android device as target. The screen is identical to previously presented screens.

VKScrollDemo Initial Screen

Although the screen appears identical to previously presented screens there is a significant difference in the program source. Refer to the Structure window in the IDE to see how components are arranged.
  • A vertical scroll box has been added with an alignment of client so that it takes up nearly all of the form's area.
  • The GridPanelLayout, Memo and Button are all children of the Vertical Scroll Box. Thus, when the viewport on the scroll box is changed, all children are repositioned in accordance with the new position of the scroll box.
  • The labels at the top of the form are not children of the Vertical Scroll Box, and thus will not participate in the repositioning of the viewport.
  • The VyDVSBFMXScroll component has been dropped onto the form. The VScrollBox property has been set to the form's only vertical scroll box. This is the scroll box that the component will manage. The optional MemoBox property has been set to point to the Memo on the form as this is a demonstration program and seeing the event handler properties may be useful. 

Program Behavior


Select the input field component with a text hint of "Default." This will cause the virtual keyboard to appear and the scroll box viewport to be adjusted so that the input field is just above the virtual keyboard. Choose the Next key twice on the virtual keyboard and move the focus to the input field with a text hint of Email Addr. The viewport will adjust appropriately and the display should be as follows:

VKScrollDemo Advancing Through Input Components

Chose Next two more times and the screen should appear as follows:

VKScrollDemo With Troublesome Number Pad Virtual Keyboard


Ideally, the device display should appear as shown. As we have noted earlier, the height of the virtual keyboard is not always reliably reported, and on occasion the vertical scroll box and its contents will not be positioned correctly.

Viewport Misposition Workaround


If the viewport is not positioned correctly, this is probably because of an erroneous reporting of virtual keyboard parameters in the VirtualKeyboardShown event. It is easy to recover from this by the following method:
  • With the virtual keyboard showing, select the hardware back key on the device. This will cause the virtual keyboard to be hidden and the viewport will be returned to its default position.
  • Reselect the input field that was originally desired. You can select any input field at any time; you don't have to start with the first field in the tab list. This will probably correctly position the vertical scroll box and input may proceed normally.
  • If this recovery procedure does not correct the display, select a field prior to the field desired and use the Return key (that may be displaying Next or some other value if selected in the field properties) to Tab through the fields until you reach the desired field.

Conclusion


If you have worked with the prior demonstration programs to gain an understanding of scroll boxes, field navigation and some of the quirks involved with FireMonkey and Android, you should be able to track down most ordinary bugs you may encounter. The demonstration programs also display the parameter values of the event handlers that will assist in problem determination.

This is the last post in the four-post series about FireMonkey scroll boxes. 

Happy scrolling and thanks for reading this.

Comments are welcome.





FireMonkey VyDVSBHelper: A Component to Manage a Vertical Scroll Box to Reveal Input Fields Obscured by a Virtual Keyboard


This is the third post of a four-post series on Delphi's FireMonkey support for mobile device virtual keyboards. For the first in the series, see Using Delphi's FireMonkey Vertical Scroll Box With a Virtual Keyboard.

There is source code that accompanies these blogs. The project group FMXVertScrollBoxEtude can be downloaded from GitHub:

https://github.com/Pasquina/FMXVertScrollBoxEtude/releases

Source code was developed using RAD Studio 10.1 Berlin (No updates.)

Overview


VyDVSBHelper is designed to manage a Vertical Scroll Box in response to change in the presence or absence of a virtual keyboard and the current input field focus. The concept is straightforward:
  • For each change in either input field focus or virtual keyboard show or hide, calculate the screen difference between the bottom of the focused field and the top of the virtual keyboard.
  • If the difference is positive (the top of the virtual keyboard is above the bottom of the focused field and therefore is obscuring the field) then reposition the vertical scroll box viewport so that the focused field is just above the virtual field and no longer obscured.

There are three major event handlers required to achieve this functionality, all events of TForm:
  • FormFocusChanged—fired when the focus changes to a different child on the form.
  • VirtualKeyboardShown—fired when the virtual keyboard is shown in response an input field receiving the focus.
  • virtualKeyboardHidden—fired when no control requiring input has the focus.

In addition, there is one event handler that is used to effect viewport repositioning:
  • CalcContentBounds—fired when the RealignContents method is invoked. Here is is used to ensure sufficient vertical content to allow the viewport to be shifted the required amount.

Internally used routines are:
  • Create—performs initialization including setting the TForm event handlers needed by the component.
  • LogFocused—Optionally logs the FormFocusChanged event. (Debugging tool.)
  • LogVK—Optionally logs the VirtualKeyboardHidden and VirtualKeyboardShown events. (Debugging tool.)
  • ResetViewport—resets the scroll box viewport if needed to reveal obscured input objects.
  • SetFocusedABSY—besides being a property setter determines if a viewport shift is required.
  • SetVKAbsY—besides being a property setter determines if a viewport shift is required.
  • SetupContentBounds—ensures that the vertical bounds of the scroll box are sufficient to effect the viewport shift.
  • ShiftViewport—Determines the shift amount required and either resets the viewport to the default position or invokes SetupContentBounds and then repositions the viewport to reveal the obscured object.

Using the VyDVSBFMXScroll Component


Component Installation


Install the 32-bit version of the component. This will cause it to appear in the Tool Pallet in the VSB Helper category. Note that this will only appear if the project framework is FireMonkey. The component is intended to work for mobile devices that can only be developed using FireMonkey. See the Register procedure for details on how this is accomplished.

The component code must be available for use in your Android deployments. One way to do this is to build the Android version of the component.

It is assumed that the user is familiar with how components are installed and used in projects. You may have to make changes to the component project to ensure that the proper libraries contain the necessary files.

Application Project 


The application project must contain a vertical scroll box. This is the layout that will be repositioned to reveal obscured input objects. All objects requiring repositioning must be children of the vertical scroll box, so that they are repositioned along with the scroll box when needed. (This can be seen in the VKScrollDemo project.)

Drop the VyDVSBHelper onto the project. There is one property to set: VScrollBox should be set to the vertical scroll box it is desired to manage. Normally, there will be only one. Optionally, you can specify a value for the MemoBox property if it is desired to log the event handler traces. This property is optional and if omitted, no logging will take place.

Be sure that the tab order is set as you intend navigation to take place. Also, you must include the following event handler (OnFormKeyDown) in your own code:



Besides any application code you require, no other programming should be necessary to manage the vertical scroll box.

Some Caveats


The create procedure of the VKScrollDemo component modifies the TForm component that calls it. Specifically, it puts its own event handler addresses in the OnVirtualKeyboardShown, OnVirtualKeyboardHidden and OnFocusChanged events. It will overlay any specification you may have made at design time. Do not modify these values as proper functioning of the component depends on the required event handlers.

Similar remarks apply to the OnCalcContentBounds event handler of the Vertical Scroll Box. It is not done in the Create procedure because the address of the Vertical Scroll Box is not yet available to make the modification. See the SetupContentBounds procedure in the source code for more information.

It is important that the two setters, SetVKAbsY and SetFocusedAbsY be used rather than referencing the base fields, FVKAbsY and FFocusedAbsY. This is because the setters make a logical decision and invoke the ShiftViewportRoutine when required. Setting the field values directly would bypass this small but important piece of logic.

It is not always possible to determine the height of a virtual keyboard accurately. When the reported height is 25, you can be certain this is erroneous. See the event handler VirtualKeyboardShown to see the simple hack used to try to guess an appropriate value.

Conclusion


I have attempted to make VyDVSBHelper a simple and straightforward component to use. Certain anomalies in either FireMonkey or Android conspire to make this a bit dodgy, especially when parameters from events are not reported accurately and consistently.

In the fourth and final posting in this series, we examine a working example of an application that uses the VyDVSBHelper component. Since there are occasional random failings when virtual keyboard heights are misreported, we examine circumventions that the user may employ to recover.


Comments are welcomed. Thanks for reading this far.

FireMonkey TForms: Events for Virtual Keyboard  Navigation and Scroll Box Control


This is the second post of a four-post series on Delphi's FireMonkey support for mobile device virtual keyboards. For the first in the series, see Using Delphi's FireMonkey Vertical Scroll Box With a Virtual Keyboard.

There is source code that accompanies these blogs. The project group FMXVertScrollBoxEtude can be downloaded from GitHub:

https://github.com/Pasquina/FMXVertScrollBoxEtude/releases

Source code was developed using RAD Studio 10.1 Berlin (No updates.)


Objectives


  • Understand the FireMonkey TForm events that are useful for virtual keyboard support, the order that they are fired, and the values of the parameters that are passed to the event handlers. Addtionally, some anomalies will be discussed that will become apparent when the handler log is examined.
  • Develop a simple technique to permit input field navigation by using the Return key on the virtual keyboard. Additonally, an anomaly in the implementation of this feature will be discussed.

Note that the objective of implementing a Vertical Scroll Box to reveal otherwise hidden input fields is not implemented by this program. When you run the program on a mobile device, the input fields will be hidden by the virtual keyboard. Implementing the Vertical Scroll Box is deferred to the next blog post.

The VKLogger.exe Program


While the program will run as a Windows application, it is most effective when run on a mobile device. The illustrations that follow are from a Samsung Galaxy Tab 3 running Android 4.4.2. 

The GUI

VKLogger.exe GUI

Always Show Checkbox: This is useful when running the program on a windows PC or any device that has a hardware keyboard. Devices with hardware keyboards do not normally show the virtual keyboard. Checking this box modifies that behavior so that the virtual keyboard is shown even in cases where a hardware keyboard is present.

Input Field Array: The eight input fields are arranged in two columns using a TGridPanelLayout. Each of the input fields specifies a different type of virtual keyboard required for input. The TextPrompt property is used to indicate the type of keyboard specified for the field. Additionally, each input field specifies a ReturnKeyType of Next with the exception of the last field (URL) that specifies a ReturnKeyType of Done.

Some Button: is an arbitrary control that is outside of the TGridPanelLayout that contains the input fields. It does nothing.

Navigation


The desired behavior is as follows: The user selects the first input field (Default) and complete data entry. The Next key on the virtual keyboard causes the cursor to navigate to the next input field, which selects the desired virtual keyboard type. The process is repeated for all input fields except the last, that displays Done rather than Next. Selecting Done results in navigation to the Some Button button.

Within the TGridPanelLayout this is accomplished by setting an appropriate tab order. In the IDE, right click on the TGridPanelLayout and choose Tab Order... This displays the Tab Order editor.



Tab Order Editor for TGridPanelLayout

The individual controls within the TGridPanelLayout will be navigated in the order specified from top to bottom. You can make any changes you deem necessary by moving controls up and down in the list.

Similarly, right click on the TForm component and choose Tab Order... The tab order editor will present a similar screen but this time itemizing the controls that are children of the TForm component.

Tab Order Editor for TForm

Note that the TButton control follows the TGridPanelLayout control. Navigation from the last control in the TGridPanelLayout will be to the TButton control, the next control after the TGridPanelLayout.


Navigation using Tab Order is accomplished by the keyboard tab key. However, the virtual keyboard does not have a tab key. Instead, the Return Key is employed by intercepting the Return and changing it to a Tab. This is accomplished in the Form Key Down event handler using the following code:




Statement 10 is required to cause the modified key code to be reprocessed by the TForm to effect navigation.

Setting the tab order and implementing the FormKeyDown event handler as illustrated is all that is needed to effect a simple and straightforward navigation scheme.

It should be noted that despite indicating the ReturnKeyType on each input field, this value is not reliably observed by FireMonkey. Frequently, Done is not displayed at all and sometimes the ordinary return key symbol is displayed rather than the designated type. This is a cosmetic failing, however. The key is always a return key as you can see by the FormKeyDown processing; the only difference is the label on the return key.

Event Tracing


VKLogger traces three events:
  • FormFocusChanged
  • FormVirtualKeyboardHidden
  • FormVirtualKeyboardShown

Each time one of these event handlers is entered, a line is added to the memo box at the top of the form. Parameters passed to the handler are displayed on the same line. The following is a typical display after all eight input fields have been navigated by using the Next key (Return.) The display is from  a Samsung Tab Galaxy Tab 3) (Model SM-T310) running Android 4.4.2.

VKLogger Trace Sample 1

Notice several things:
  • The first Focused event (FormFocusChanged) is followed by two identical Shown (FormVirtualKeyboardShown) events. This is not unusual and is not reliably reproduced. All that can be said is that it sometimes happens. Further, the duplication is not always precisely the same; occasionally the second or subsequent occurrence has one or more parameters that differ from its predecessor. Usually, the difference is in the height parameter (H). 
  • The Shown event following the Focused event for Edit five is simply wrong. No virtual keyboard has a height of 5; it's much to small. This anomaly is not reliably reproduced but seems to occur when the KeyboardType is specified as NumberPad. The NumberPad virtual keyboard is different (on this device and Android version) in that it has a grab handle enabling the user to move it about the form. Other virtual keyboards remain fixed at the bottom of the screen.
  • The final Focused moves from the last input field to the Some Button. Some Button does not require a virtual keyboad and so the FormVirtualKeyboardHidden event is fired resulting in the last entry in the memo box. However, aside from the Visible parameter (V) correctly having a value of False, the rest of the parameters are incorrect. A hidden virtual keyboard has no height or width nor does it have a meaningful position.
  • When switching virtual keyboards, the Hidden event does not fire. In other words, the old virtual keyboard is not hidden followed by showing the new virtual keyboard. The switch is indicated by a single Shown event that implies that a prior virtual keyboard has been dismissed.

Here is a similar execution of VKLogger on a different Samsung Galaxy Tab 3 Model SM-T217S) also running Android 4.4.2.

VKLogger Trace Sample 2

Despite being the same environment (so far as I can tell) there are some differences between this and the first sample:
  • The Shown event following TEdit1 is not repeated.
  • The Shown height following TEdit5 is not incorrectly reported as 25. Instead, the more reasonable 327 is reported.
  • However, the Shown height following TEdit6 is now an very unreasonable 489.

I can't explain these differences. I can only observe that they exist.

Conclusion


Navigation and event tracing of significant TForm events is fairly straightforward and largely predictable. Problem areas include the misreported parameters for some virtual keyboards, the occasional and unpredictable duplication of Shown events (that sometimes do not have identical parameters) and the cosmetic irritation of the virtual keyboard return key not displaying the specified value.

Armed with this knowledge and the knowledge gained from ScrollDemo about scroll boxes, we are now ready to build a component that will handle repositioning a viewport to reveal input fields when a virtual keyboard is shown. That is the subject of the next blog post:

See the next post in this series at FireMonkey VyDVSBHelper: A Component to Manage a Vertical Scroll Box to Reveal Input Fields Obscured by a Virtual Keyboard

Comments are welcomed. Thanks for reading this far.

Tuesday, August 16, 2016

Using Delphi's FireMonkey Vertical Scroll Box With a Virtual Keyboard


Background


Input fields on a FireMonkey form become problematic when the application is ported to a mobile device. Mobile devices frequently do not have hardware keyboards; in place of the hardware keyboard Android provides a virtual keyboard, e.g. a visual keyboard on-screen with a layout similar to a hardware keyboard that can be used for input. The problem arises when the virtual keyboard covers a part of the original form, often obscuring the input field and depriving the user of the visual cues used to verify input.

The solution to this is to use a vertical scroll box component for the input fields so that they may be positioned above the virtual keyboard thus allowing the user to visually observe the input process. In vernacular terms, everything "slides up" to reveal the current input field.

It turns out that this involves programming a number of events that respond to changes in the field focus, the appearance and disappearance of the virtual keyboard and the positioning of the vertical scroll box viewport. Embarcadero provides a sample project to demonstrate this that frankly is typically deficient in that it doesn't work correctly much of the time, has code that is completely uncommented and undocumented and that assumes some pretty extensive knowledge of FireMonkey internals. In short, the sample is of little value as a learning or teaching tool.

My purpose here is to try to provide some needed information about FireMonkey components and how they may be used to solve this problem; to provide running applications that illustrate some of the FireMonkey behaviors that I encountered; to provide a simple Delphi component that encapsulates the techniques I developed to solve this problem; and to provide a working example of my solution that may be used as a model for further development. I have attempted to do this with heavily documented code and meaningful naming conventions that will assist the reader in understanding what I have discovered. Additionally, this posting and three subsequent postings offer more detailed discussion of the applications.

There is source code that accompanies these blogs. The project group FMXVertScrollBoxEtude can be downloaded from GitHub:

https://github.com/Pasquina/FMXVertScrollBoxEtude/releases

Source code was developed using RAD Studio 10.1 Berlin (No updates.)

Approach


ScrollBoxEtude Project Group (ScrollBoxEtude)


The ScrollBoxEtude project group was established to aggregate the four projects used to explore this problem. Each of the four projects within the ScrollBoxEtude project group has a specific objective. The code is written to illustrate that objective. All projects can be compiled for Windows 32 and 64 bit or Android executables.

Understanding Scroll Boxes (ScrollDemo.exe)


Understanding Scroll Boxes (ScrollDemo.exe) is provided to allow the manipulation of a scroll box interactively and to display the various parametric results of the user-entered manipulations. Examining the source code comments will add further insights into the way Scroll Boxes work.

Understanding Events and Event Parameters (VKLogger.exe)


There are a number of events that must be handled to implement a scroll box solution to the virtual keyboard obfuscation of input fields. VKLogger.exe interactively logs the firing of a number of important events along with the values of their parameters. 

Building a Scrolling Component (VyDVSBFMXScroll.bpl)


The TVyDVSBHelper component combines all of the necessary code and event handling needed to implement a vertical scroll box solution to the virtual keyboard input field obfuscation problem. After installing the component, it is dropped on a form containing a vertical scroll box that contains the input fields. A single property connects TVyDVSBHelper to the scroll box. This is the only code needed to implement the solution.

Scrolling Demo Program (VKScrollDemo.exe)


VKScrollDemo.exe illustrates the use of the TVyDVSBHelper with a vertical scroll box populated with input fields. Additionally, it illustrates a suggested approach to field navigation (not handled by the component) and summarizes a couple of minor anomalies in the way FireMonkey or Android handles events and displays the various virtual keyboards.

Understanding Scroll Boxes


Run ScrollDemo.exe. The following screen is displayed. The bottom portion of the window consists of a scroll box populated with a number of random controls. The top band consists of a number of controls that enable the manipulation and display of scroll box contents and properties.


Scroll Box Etude: Scroll Demo

Show Width/Height Button: Pressing this button will show the width and height properties of the scroll box. These values don't change unless the size of the scroll box on the form changes. Since the scroll box is aligned to client you can resize the form and that will cause the scroll box to resize. Pressing the button again will show the new height and width.

Beep: If you resized the form and pressed the Show Width/Height button, you probably noticed a beep. This is an audible signal programmed in the CalcContentBounds event handler. It's to let you know that the Content Bounds have been recalculated by the scroll box. This beep also sounds when the application starts, since the scroll box calculates the Content Bounds on startup as well.

Show Bounds: Pressing this button displays the Content Bounds of the scroll box. Content Bounds is the rectangle that exactly includes all child controls. The content bounds extend from 0, 0 to the farthest point horizontally and vertically used by child controls. Note that this does not have anything to do with the Width and Height of the scroll box. Initially, the demo program Content Bounds is smaller in both directions than the width and height. This is because the child controls do not extend to the edges of the scroll box. In fact, if a control extends beyond the the width or height of the scroll box, the bounds will be adjusted by the scroll box to include the control. This adjustment sometimes occurs automatically, as when the height and width of the scroll box itself are changed (try resizing the window to see this) or it can be caused programmatically by invoking the RealignContent method of the scroll box.

Add Label: A label can be added at any arbitrary position by first specifying the X and Y coordinates of the upper left hand corner of the label rectangle and then clicking the Add Label button. For example, enter 200, 200 for the X and Y coordinates and click the Add Label button. (Beep as bounds are recalculated. The bounds are recalculated by the routine that adds the label. This is not automatic. The label add routine invokes the RealignContent method after the label has been added.) The label appears at the specified location. Click Show Bounds and notice that the content bounds values have not changed. this is because the label added lies completely within the existing content bounds. Now try adding a label at 1000, 1000. (Beep!) Now click Show Bounds and discover that the bounds are now much larger than previously. They are even larger than the 1000, 1000 specified for the label's position. This is because the label position is the top left of the label, and the bounds have been expanded to include the length and height of the label that extend to the right and down from the position. But there's more: scroll bars have appeared on the scroll box. You can now scroll down and to the right to view the newly added label. (You must have the ShowScrollBars property of the scroll box set to True for the scroll bars to appear.)

Apply Viewport: You can position the contents of a scroll box to a specified position in the visible control window by changing the viewport position. For example, you can specify a viewport of 100, 100, and point 100, 100 within the content bounds will be placed at point 0, 0 in the visible control window. This is analogous to moving the window contents by using the scroll bars. It is not always possible to position the viewport to something other than 0, 0. If the content bounds of the control do not extend beyond the width and height of the control window, then no repositioning is possible. Another way of thinking of this is by observing the scroll bars on the window. If no scroll bars are visible, then no repositioning is possible, either programmatically or by using the scroll bars. The maximum amount of the repositioning is determined by the content bounds. You cannot reposition the viewport if it would result in moving the right or bottom content bound to a value less than the width or height respectively of the scroll box window.

Force Bounds: Without any special handling, when the scroll box bounds are recalculated, they include everything from 0, 0 to the right and down sufficient to exactly include all child controls but no more. It is possible to override this calculation by using the CalcContentBounds event. This event is fired when the RealignContent method is invoked. It is the only way the content bounds can be set programmatically without changing the child content of the scroll box. The ContentBounds property of the scroll box is read-only. This property can only be changed by the CalcContentBounds event handler. This is an important technique to master. To change the content bounds to arbitrary values, the CalcContentBounds event handler must return the new content bounds values to the invoker. If the content bounds are not changed by the event handler, then the default calculated values will be retained. The Force Bounds check box exploits this behavior. First, click Show Bounds to display the current values. Then enter new bounds values in the entry fields beneath the Force Bounds checkbox. Finally, check the Force Bounds checkbox and click Show Bounds again to display the new values. Notice that the content bounds have changed to the specified values but no new controls have been added to or removed from the scroll box. Only the bounds have been changed. Uncheck the Force Bounds checkbox to cause the default content bounds values to be restored. The CalcContentBounds event handler examines the state of the checkbox to determine whether or not to override the default bounds calculation. Remember, to change the content bounds programmatically, you must write a CalContentBounds event handler and then invoke RealignContent to cause the event to fire. This behavior is an important part of repositioning the viewport to avoid hiding input controls when the virtual keyboard is displayed. This is discussed further in a later blog.

VK Auto Show Mode Enabled: This is a minor feature of this demo that forces the display of the virtual keyboard even when it is not required. Input fields have a KeyboardType property that allows the designation of the type of keyboard to be displayed when the field has the focus. When the target device has a hardware keyboard, the default behavior is to not display the virtual keyboard, instead allowing the user to perform data entry using the hardware keyboard. This checkbox overrides that behavior and forces the system to always display the virtual keyboard, even when it is running on a device with a hardware keyboard. Virtual keyboards have greater variety when the program is run on a mobile device. While the virtual keyboard will appear on Windows, it is completely different in appearance from the mobile version. To observe the program's behavior, check the VK Auto Show Mode Enabled. When an input field receives the focus, the virtual keyboard is automatically displayed. Moving to another input field preserves the virtual keyboard display. However, if the focus is moved to a field that does not require input, the virtual keyboard is hidden.

Conclusion


This completes the discussion of the ScrollDemo.exe project. You are encouraged to download the project group and experiment with the program to gain a feel for scroll boxes and how they can be manipulated programmatically. Additionally the source code for the program is dense with comments that help explain the various features, the reasons for the methods and their operation.

In the next blog, we'll take a look at the VKLogger.exe project that examines events and their parameters as they relate to solving the virtual keyboard obfuscation issue. In addition, we'll take a look at navigation during data input.

See the next post in this series at FireMonkey TForms: Events for Virtual Keyboard Navigation and Scroll Box Control

Comments are welcomed. Thanks for reading this far.