Main Views

June 28, 2010

Since SLX 6.2, the Account, Contact, and Opportunity entities have been implemented as Main Views.

If you want to create your own custom Main View (e.g., for hospital Cases, or company Projects) entity, these are the steps:

  1. In the Picklist Manager, on the Plugin Families tab, add a “MyEntity” value to the Active Form Types, Active Script Types, Main View Types, Menu Types, Report Families, and Toolbar Types picklists
  2. Create a new table (e.g., MyEntity), not associated with any other tables
  3. Create a new MyEntity Detail Main View, bound to the MyEntity table; set the EntityNamePlural and EntityNameSingular properties; and save it under the MyEntity plugin family
  4. Create an Insert New MyEntity Data Form, bound to the MyEntity table
  5. Create a MyEntity Details form, and assign it to the ViewName property of the DetailsView control, on the MyEntity Main View
  6. Create a new lookup (Manage -> Lookups) against the MyEntity table, to be used as the QuickFindLookup on the MyEntity Main View. (For lookups, the Search field is the field searched on, e.g., the field which the “Starting With” value is applied to; the LookupID is what it returns [e.g., to the LookupID field of a LookupEdit control], as an SLX Standard ID; and the Name field is “the value that would be displayed in a LookupEdit when the lookup returns [like a contact name, address info, etc.”])
  7. Create tabs for the Main View (tabs are just Data Forms, bound to the MyEntity table, with the default panel and buttons removed)
  8. Add those tabs to the DefaultTabs list property of the Main View TabsPane control
  9. On the Standard Menus plugin, add a new item to launch the Insert New MyEntity form
  10. In the Standard Menus plugin, create a new MyEntity NavMenu entry. (The OTB right-click popup items for the Sales Toolbar [!] can be found in the same Standard Menus plugin, below the main menu items; e.g., Contacts NavMenu)
  11. On the Sales Toolbar, add an item to jump to the MyEntity Main View (i.e., an Action value of Function, with an Argument of MyEntity:MyEntity Detail). Set its Popup menu property to the MyEntity NavMenu
  12. On the Standard Toolbar, add a new item (with icon) to Insert New MyEntity, which launches the MyEntity:Insert New MyEntity form
  13. Add an item to the Lookup main menu (in the Standard Menu plugin) to launch your MyEntity lookup via a script, using the LookupItemWithConditionByID function (example)

You can’t change the bound-table for a Data Form after it’s created, so if you want to reproduce the normal Attachments or Contacts tabs for the MyEntity entity, you can’t just save them under the new Family. What you’ll have to do instead is create a new Data Form, bound to the MyEntity table, and then copy-and-paste the code and the controls from the existing OTB tab, onto your new one.

In 7.5, the Activities tab (and also the Summary tab) are still part of the compiled functionality of SLX; so if you want to have an Activities tab for the MyEntity entity, you’ll have to build it from scratch.

Of course, if you’re associating Activities with MyEntity records, you’ll also need to modify the Activity Detail View form, and add a MyEntityID field to the Activity table, data-bound from the Activity Detail View. You can do a similar thing for the MyEntity Notes/History tab, adding the MyEntityID field to the History table.

If your MyEntity Main View is displaying “%n of %n records” at the top, or if the All MyEntities group in the (F8) groups view contains no records, check to make sure that your lookup has been assigned to the QuickFindLookup property of the Main View, that it exists on the database in question (i.e., if you’re in QA or production, it should have been bundled and applied), and doesn’t include fields which don’t exist in the MyEntity table.

Also, for the menu/toolbar additions above, it’s much preferable to do those in new plugins, which simply add/remove options from the OTB Standard Menu, Standard Toolbar, and Sales Toolbar. That way, when it comes time to upgrade to the next version, you don’t have to search through the OTB menus/toolbars to try and figure out what you’ve added or deleted from them.



June 23, 2010

As of SLX 7.5 LAN, you can now set the default comparison operator in lookups to be something other than “Starting With”.

Lookups which exist as controls on forms are the easiest to adapt, as they already have a DefaultLookupOption property exposed on their property page, so you can just change that in Architect.

For button lookups such as the “Account” button on the Account Detail view, that calls a FunctionLookupClick function, which is already using code to launch the lookup, via the Application.BasicFunctions.DoInvoke method. That would need to be rewritten to use the LookupItemWithConditionByID function instead.

For launches which are being done from menu/toolbar/navmenu items, instead of launching the lookup directly those would now need to run a new script, which in turn launches the lookup. For example, to launch the Account lookup with conditions from a menu item, and then have the Account record selected by the user in the lookup be loaded into SLX, you’d have the menu-item’s Action execute a VB Script (ActiveScript) containing the following code:

Sub Main

     Dim objLookup

     ' Ignore the blog-formatting line breaks here:
     Set objLookup = Application.BASICFunctions.LookupItem
        WithConditionByID("Account:Account", False, "", "",
        "", "", 2)

     If TypeName(objLookup) = "Link" then
          ' If type <> "Link" then the user Cancelled
          Application.BasicFunctions.DoInvoke "MainView", _
               "System:Account Details"
          Application.MainViews.ActiveView.CurrentID = objLookup.ID
          Set objLookup = Nothing
     End if

End Sub

You could save several steps by using ShowMainViewFromLookupWithConditionByID instead.

From the LAN Developer’s Guide .chm (not the PDF, where they aren’t given!), the enumerated constants which can be used for the last parameter of the LookupItemWithConditionByID function are:

loDefault = 0 (means Starting With for string fields and Equals for all other fields)
loStartingWith = 1
loLike = 2
loEquals = 3
loNotEquals = 4
loLTE = 5
loGTE = 6
loLT = 7
loGT = 8

LookupEdit controls with multiple restrictions

June 9, 2010

Further under the heading of things which are too easy to forget (or be unable to find when you need them) is this, from Ryan Farley:

A question that surfaces fairly often deals with LookupEdit controls and how to do more with the LookupRestriction properties, such as add multiple conditions to the restriction. Although it is undocumented, you can do that with the existing LookupEdit—you just have to put things in the wrong place. Let’s say you want to add a restriction to a LookupEdit for all contacts with an areacode of “623” AND that have a title of “Developer.”

LookupRestrictField = "WORKPHONE"

LookupRestrictOp = " LIKE '623%' AND " _
    & "TITLE = 'Developer' AND "1" = "

LookupRestrictValue = "1"

Or you could do it like this:

LookupRestrictField = "CONTACTID"

LookupRestrictOp = " IN (SELECT CONTACTID " _
    & "AND TITLE = 'Developer') AND "1" = "

LookupRestrictValue = "1"

A few things to point out, make sure you notice the extra space at the start of the operator (ie: before “IN” or “LIKE” etc). This is needed because when the final query is constructed it just appends the three values together without spaces (so you’d get something like “CONTACTIDIN…” without the space). Also, the reason why you have to put all that in the RestrictOp property is because when the final query is constructed the RestrictValue gets enclosed in single-quotes. That is also the reason for the AND “1” = at the end.

And this, from RJ Samp:

Take a close look at the LookupEdit control……

If it’s LookupMode USER (or Owner, or…..) then it doesn’t use the ‘normal’
properties of a Lookup… ignores the TABLE for the lookup (it’s most
often CONTACT even if you are looking up Userinfo.USERNAME for example)….
And it used It’s OWN lookup view (DIALOG control).

Also it display’s data based on the databound TEXT field ….but displays
the UserName in the Text field as well (Format Type property = ftUSER)…..
So strUSERID = lueUSER.TEXT…..unless they just popped up the form…then
you can use strUSERID = lueUSER.LOOKUPID….

So Lookup Restrict stuff DOESN’T WORK.

You have to reconstruct the LookupEdit control as a USERINFO table
lookup…..base it on a USERINFO Table Lookup……

Return the USERNAME in the TEXT property……USERID in the LOOKUPID
property….and Lookup by LAST NAME or whatever…..

No need for a custom form……although you can go that route.

Most developers aren’t highly aware of this ‘feature’ functionality of the
LookupEdit Control……and be aware of the difference between Lookup Mode
OWNER and a lookup of the SECCODE table……

Tips and Tricks – II

May 5, 2010

More Tips and Tricks….

  • To execute a method of a control on another form:
Set oForm = Application.Forms("Ticket:Support Ticket Widgets")
  • You can turn off “Open project at startup” via the Tools > Options menu in Architect
  • To delete an old version of a plugin, right-click on it in Plugin Manager, select Properties…, and remove the checkmark from the Read Only checkbox. Click OK. Then press the Delete key. You will be prompted for whether you are sure that you want to delete the plugin. Click Yes
  • If you set the ShowGroupPanel property of a DataGrid to True, it will create a blank (dark gray) area above the grid’s table. You can then drag any column header from the grid into that area, allowing the user to group by that field
  • The SysInternals Suite from Microsoft contains, among many other goodies, a DebugView utility. If you put lines like
Application.Debug.WriteLine Err.Number
Application.Debug.WriteLine "Creating Recordset"
    into your SLX scripting, and then run the dbgView.exe, you can read the WriteLine’s there

  • The SLX Mail Merge engine calls the System:SLX Mail Merge OnCustomFieldName script whenever it encounters a custom field in a (Word template) document. “This allows us to insert whatever data we need to in the document at merge time” (Stephen Redmond)
  • The recommended way of creating new recordsets in SLX is to use this function:
  • Using DoEvents in SLX VBScripting works fine, but there’s also Application.DoEvents
  • To programmatically create a new activity, use the Application.Activities class:
Set Act = Application.Activities.Add(atPhoneCall)
Act.AccountID = strAccountID
Act.StartTime = DateAdd("d", 7, Now)
  • The “Insert:ContactAccount” function, for inserting new Accounts/Contacts, calls the System:ChooseContactAccount plugin
  • When closing a form via Application.BasicFunctions.CloseCurrentView blnValue, passing True causes the form to be closed as if the user clicked the Cancel button; passing False closes the form as if the OK button had been pressed (i.e., also running any validation code before it closes)
  • Use Application.BasicFunctions.GetGroupList(Family, Type) to retrieve a list of either all of the groups available to the current user (Type = 0 returns string names, Type = 1 returns the actual plugin IDs). Use GetGroupSQL to retrieve a particular group’s SQL (by its ID). Use GetGroupIDs to get a handle to the comma-separated list of IDs in a group, and then use GetGroupCount and GetGroupValue (0-based) with that handle to iterate through the list, to parse it out into its individual ID values
  • For parsing general CSV strings, use CSVCount and CSVField (to get the value in the 1-based position, from 1 to CSVCount)
  • Use GetLineCount and GetNthLine to parse strings where there is a carriage return and line feed separating the values (e.g., from ParseName)
  • GetOwnerName returns the name for a given SecCodeID value
  • To get an OTB path where you can create your own temporary files, use GetPersonalDataPath (SLX already stores copies of reports that are run, or checked out of Architect, in that folder)
  • To attach a new file to an ACO record, use InsertFileAttachment. If you already know the path to the file you want to attach, use InsertFileAttachmentEx instead
  • To transform a string in ISO format (yyyymmdd hh:mm:ss) into a date variable, use ISOToDate
  • In custom code (as opposed to the OTB SLX functionality) and on DataGrids, deleting an Account doesn’t automatically delete its Contact, Opportunities, Activites, or History records, etc. To cause that cascade-deletion to happen, you’ll need to call CascadeDelete strEntity, strEntityID for the parent entity. That will cascade through all of the Joined tables where CascadeDelete is set to “Delete”