DumontEXE 0.0.1
cmcDocNotes.h
00001 
00002 /*!
00003 ** \page FAQ Frequently Asked Questions
00004 **
00005 ** This list of frequently asked questions was compiled from the most incredible
00006 **  commence newsgroup found at the http://news.freedomcomputing.com website.  These
00007 **  notes are compiled from my own experiences and from the various messages posted
00008 **  on that newsgroup.
00009 **
00010 ** \subpage handyFunctions "Is there a library of handy functions?"
00011 **
00012 ** \subpage faqFilterOnNone
00013 **
00014 ** \subpage viewFilter "How do I write a filter in vbScript properly?"
00015 **
00016 ** \subpage hidingTabs "How do I hide a Tab on a Detail Form?"
00017 **
00018 ** \subpage thids "What is a THID and why do I need it?"
00019 **
00020 ** \subpage dcf "How can I create a dynamic Pick-list on my Detail form?"
00021 **
00022 ** \subpage subReports "How can I make a sub-report in a report?"
00023 **
00024 ** \subpage isolatingBadData "I think my database is corrupt.  How do I verify that and how do I fix it?"
00025 **
00026 ** \subpage multiViewBigFonts "Why are my multi-view fonts so big?"
00027 **
00028 ** \subpage outlookIssues "Outlook Issues"
00029 **
00030 ** \subpage lostToolBars "My Tool Bars are missing!  How do I get them back?"
00031 **
00032 ** \subpage serverOnlySharedAgents "How do I run an Agent on one or more machines"
00033 **
00034 ** \subpage wordMergeError "Word Merge is giving me errors.  How do I fix?"
00035 **
00036 ** \subpage commenceCrashing "Commence Keeps Crashing.  What do I do?"
00037 */
00038 
00039 /*!
00040 ** \page commenceCrashing Addressing Unexplained Crashes
00041 **
00042 ** This is a big problem.  For the most part, Commence is pretty darned reliable.
00043 **  But, as some have noted, there are times when Commence doesn't seem to want
00044 **  to run at all on a client setup, or it may run but only for a little while,
00045 **  and then it seemingly crashes for no explainable reason.  There are several
00046 **  things to look at that may improve your situation.
00047 **
00048 ** \par Virus scanning
00049 ** Turn off <b>ALL</b> virus scanning as it pertains to Commence.  Usually in
00050 **  most advanced virus scanners, there is an option to have it /c NOT scan
00051 **  particular directories.  You should set up these exclusions on your virus
00052 **  scanner, and you should include your entire database directory (mine is 
00053 **  usually \c c:/Commence and you should also include the Commence program
00054 **  directory.
00055 **
00056 ** \par Form Caching
00057 ** There is an option in the \c data.ini file that you can add that will turn
00058 **  off form caching.  This may or may not help.  Here are the instructions:
00059 **
00060 ** \par 
00061 ** Form caching configuration information is stored in \c [OtherOptions] section 
00062 **  of \c data.ini file and is used to cache recently opened detail forms.  The
00063 **  caching policy control is called \c FormCachePolicy and its values are
00064 **  as follows:\n\n
00065 **    \li 0 - No Cache
00066 **    \li 1 - Cache for current session only. i.e. do not pre-load forms nor
00067 **            write FormCache in data.ini file.
00068 **    \li 2 - Auto Cache across sessions. i.e. Read FormCacheSize and FormCache
00069 **            from data.ini file and pre-load forms. Also, write FormCache while 
00070 **            leaving database. (2 is used as a default policy)
00071 **
00072 */
00073 
00074 /*!
00075 ** \page wordMergeError Solving Word Merge Errors
00076 **
00077 ** The following post comes from the Freedom Computing newsgroup
00078 **  server, found at http://freedomcomputing.newsgrouphosting.com
00079 **  The information contained herein may help you resolve some issues
00080 **  regarding launching a word merge.
00081 **
00082 ** ~ ~ ~ begin paste ~ ~ ~
00083 **
00084 ** After installing the 3.0b patch  I received a run time error 430 when
00085 **  attempting to open or create a word document in Commence.  This error
00086 **  may occur when software attempts to access a database file by
00087 **  referencing libraries that are a different version than those installed 
00088 **  on the computer.  After reinstall the Commence program or applying a 
00089 **  patch, it is possible to receive this error message.
00090 **
00091 ** \par Here is the permanent fix:
00092 **
00093 ** Use the following steps to manually register the letters.dll:
00094 **
00095 ** \li Use Explorer to locate a file called regsvr32.exe,
00096 **
00097 ** \li Create a shortcut to the file & place it on the desktop.
00098 **
00099 ** \li Locate the Commence program directory.
00100 **
00101 ** \li Drag the letters.dll file from the program directory to the
00102 **     regsrv32.exe shortcut on the desktop.
00103 **
00104 ** You should receive a message stating the file has been successfully
00105 **  registered. Now attempt to create your mail merge again.
00106 **
00107 ** ====ADVANCED INFORMATION=====
00108 **
00109 ** \par If the error continues:
00110 ** 
00111 ** \li Using Windows Explorer, locate the CMCMERGE.DOT file in the Word
00112 **      Startup directory. Right-click and select open.
00113 **
00114 ** \li Open the VBA Editor using the ALT+F11 shortcut or the Tools -
00115 **      Macros - Visual Basic Editior command.
00116 **
00117 ** \li Select Tools-References and locate the reference for Letters.dll.
00118 **      De-select or remove the checkbox. Select OK to close the dialog 
00119 **      box.
00120 **
00121 ** \li Select the Debug - Compile Project command. This will error out.
00122 **      Click OK to the message box.
00123 **
00124 ** \li Use the Tools-References command and locate the reference for
00125 **      Letters.dll. If there are multiple listings, verify the path to
00126 **      LETTERS.DLL
00127 **      is the proper one for your current Commence program directory. 
00128 **      Select Letters.dll so that a checkbox appears.
00129 **
00130 ** \li Click OK to close the dialog box and select the Debug-Compile
00131 **      Project command. No error should occur.
00132 **
00133 ** \li Select File-Save in the VBA editor. Select File - Close and 
00134 **      Return to Word.
00135 **
00136 ** \li Select File-Save in Word to save the CMCMERGE.DOT file.
00137 **
00138 ** If more than one PC is receiving this error, the modified cmcmerge.dot
00139 **  file may be copied to the remaining workstations.
00140 **
00141 ** ~ ~ ~ end paste ~ ~ ~
00142 */
00143 
00144 /*!
00145 ** \page DumontQueue Dumont Queue Category Definition
00146 **
00147 ** The Dumont Queue Category is a special category that is used by Dumont
00148 **  to Queue up various events within the Commence database so that it can
00149 **  process them sequentially.  By using a Queue category, is is possible 
00150 **  to have agents within Commence respond to various events, and cause
00151 **  actions to be taken on those events in a step by step manner.
00152 **
00153 ** One of the things that Commence agents do not offer is any sort of 
00154 **  control over what agents get fired and in what order.  Nor does it offer
00155 **  any sort of notification of when an agent actually completes so that
00156 **  the completion of one agent can signal the start of another agent.
00157 **
00158 ** This DumontQueue handler is designed to improve this situation.  This
00159 **  queue handler watches for items that appear in the queue category 
00160 **  asychronously, and processes them out of the queue one at a time.  This
00161 **  object monitors the DumontQueue category for new items and when 
00162 **  one appears it is pulled from the queue and processed.  Each \ref cmcQueue
00163 **  object that gets instantiated in the system begins monitoring the
00164 **  DumontQueue category immediately.  As soon as an item in the Queue
00165 **  is recognized by the "Queue Name" value it is processed.
00166 **
00167 ** Processing an item in the queue is as simple as running a program and
00168 **  passing to it the listed arguments.  The \ref cmcQueue object waits until
00169 **  the called program completes before processing the next item in the
00170 **  Queue.  If the called program opens a dialog window, or even a text
00171 **  editor, the processing of remaining queue items will be suspended
00172 **  until the dialog is closed, or the text editor is shut down.
00173 **
00174 ** The DumontQueue category is designed to be a category that can be easily
00175 **  loaded by an agent, knowing that the agents have somewhat limited 
00176 **  functionality and limited access to information.  By this I mean that 
00177 **  Commence agents have limited access to fields from other categories, 
00178 **  and they cannot generate their own dynamic values such as THID numbers, 
00179 **  GUID numbers, sequence numbers, and various other values that would be 
00180 **  very handy in in agent manipulation.  Therefore, the DumontQueue is a 
00181 **  category that allows duplicate items, allowing agents to load items 
00182 **  into the queue without much concern over the naming of the item.  All 
00183 **  that the DumontQueue category items care about (for the most part) is 
00184 **  the name of the program to run, and the arguments to pass to that program.
00185 **
00186 ** The DumontQueue category is defined as follows:
00187 **
00188 ** \par The DumontQueue Category Definition
00189 ** \code
00190 ** DumontQueue Category Definition
00191 ** --------------------------
00192 ** Name:          DumontQueue
00193 ** Clarify Field: none
00194 ** Separator:     " ~ "
00195 ** Index 1:       none
00196 ** Index 2:       none
00197 ** Duplicates:    Yes
00198 **
00199 **  type        name             description
00200 ** +----------+----------------+--------------------------------------------------------
00201 **  Name      ' Item Name      ' required:  Name Field
00202 **  Memo      ' Arguments      ' required:  Program Argument List
00203 **  Number    ' Priority       ' required:  Program Prioritization
00204 **  Text(80)  ' Program        ' required:  Name of the program to run
00205 **  Text(40)  ' Queue Name     ' required:  Name of the Queue
00206 **  Memo      ' Result         ' blank:     Answer-back from the program
00207 **  Sequence  ' Sequence       ' automatic: Sequence which item was added to the queue
00208 **  Connect   ' pRWD->Employee ' required:  Assigned to which staff person (client)
00209 ** \endcode
00210 **
00211 ** Here is a Detailed description of those fields:
00212 **
00213 ** \par  Item Name
00214 ** \code
00215 **  Type        Name             Kind
00216 ** +----------+----------------+----------
00217 **  Name      ' Item Name      ' REQUIRED
00218 ** \endcode
00219 **   This field is the category 'Name' field.  The value of this field is somewhat
00220 **    inconsequential since it does not get used for any function.  An agent can
00221 **    assign a 'documentation' string such as: 
00222 **    <b>VNC-SC1&nbsp;to&nbsp;(%Initials%)&nbsp;(-Date-)&nbsp;(-Time-)</b>  The 
00223 **    actual value of this string doesn't really matter, but can be used to 
00224 **    document the queue item.  Since the DumontQueue category allows duplicates,
00225 **    then the value of this field is allowed to repeat.  Put whatever value in
00226 **    in here that you want.  \n
00227 **
00228 ** \par Arguments
00229 ** \code
00230 **  Type        Name             Kind
00231 ** +----------+----------------+----------
00232 **  Memo      ' Arguments      ' REQUIRED
00233 ** \endcode
00234 **   These are the arguments that will get sent to the Program.  Each argument
00235 **    is to appear on a separate line from the previous.  The argument list
00236 **    depends entirely on the requirements of the program being run.  Here
00237 **    is an example of an argument list: 
00238 **
00239 ** \par Queue Argument List Example
00240 ** \code
00241 ** C:\Commence\Scripts\OnChangeCalendar.vbs
00242 ** (%calendarGuid%)
00243 ** (%Date Start%)
00244 ** (%calendarKey%)
00245 ** \endcode
00246 ** 
00247 ** \par
00248 ** In the example shown above the first argument is the name of the program
00249 **  to run, the second argument gets passed to that program, and so on.  In
00250 **  this example, the name of the program that is receiving these arguments
00251 **  is going to be 'wscript' (which we'll discuss later).  So the first
00252 **  argument that gets passed to wscript is the name of the .vbs script 
00253 **  that you want to run.  The rest of the arguments shown are whatever 
00254 **  arguments you want passed to the .vbs program.  It's quite simple.
00255 **
00256 ** \par Priority
00257 ** \code
00258 **  Type        Name             Kind
00259 ** +----------+----------------+----------
00260 **  Memo      ' Priority       ' REQUIRED
00261 ** \endcode
00262 **   This controls the priority of this queue item.  Since a single queue can
00263 **    contain multiple items, it is possible to have a queue filled with
00264 **    hundreds of items to be processed.  By setting a queue item priority
00265 **    it is therefore possible to insert an item for immediate processing
00266 **    above any other item merely by setting a smaller Priority number. \n
00267 **
00268 ** \par Program
00269 ** \code
00270 **  Type        Name             Kind
00271 ** +----------+----------------+----------
00272 **  Text(80)  ' Program        ' REQUIRED
00273 ** \endcode
00274 **   This is the program to execute.  In the case of .vbs script programs
00275 **    the name of the program should be 'wscript'.  In the case of any
00276 **    other program you should make sure you specify the full path to
00277 **    the program that you want to run, if it is not in the path already.
00278 **    This means that for most regular programs, such as notepad and
00279 **    paint, no path needs to be specified.
00280 **
00281 **
00282 ** \par Queue Name
00283 ** \code
00284 **  Type        Name             Kind
00285 ** +----------+----------------+----------
00286 **  Text(40)  ' Queue Name     ' REQUIRED
00287 ** \endcode
00288 **   This is the name of the Queue.  There is only one DumontQueue category,
00289 **    but there can be multiple Queue's in it.  Each queue gets processed
00290 **    by its own \ref cmcQueue object.
00291 **
00292 **
00293 ** \par Result
00294 ** \code
00295 **  Type        Name             Kind
00296 ** +----------+----------------+----------
00297 **  Memo      ' Result         ' BLANK
00298 ** \endcode
00299 **   It is possible to have a queue item get answered by the program that
00300 **    was run.  For the time being this field is not used and should be
00301 **    left blank.
00302 **
00303 **
00304 ** \par Sequence
00305 ** \code
00306 **  Type        Name             Kind
00307 ** +----------+----------------+----------
00308 **  Sequence  ' Sequence       ' Auto
00309 ** \endcode
00310 **   This is a sequence number for the item.  Each item gets its own
00311 **    automatic sequence number.  This allows for sequential processing
00312 **    of queue items as they are placed into the queue.
00313 **
00314 **
00315 ** \par pRWD->Employee
00316 ** \code
00317 **  Type        Name             Kind
00318 ** +----------+----------------+----------
00319 **  Connect   ' pRWD->Employee ' Required
00320 ** \endcode
00321 **   This is a connection to the Employee (-Me-) item.  This connection
00322 **    is required.  Even though when items get added to the queue, they
00323 **    generally get added to the queue as 'local' items, it is important
00324 **    to connect them to the (-Me-).  The cmcQueue object pulls items
00325 **    from the queue, and it pulls them based upon the name of the queue,
00326 **    the sequence number, and the connection to the (-Me-) item.
00327 **
00328 ** \par
00329 **   The reason for this is simple.  Using the DumontQueue category, and
00330 **    by attaching the item to an employee throught the pRWD connection,
00331 **    it becomes possible to author a Queue item on one machine and
00332 **    publish it to another simply by making this connection.  This is
00333 **    usually done on the server ~ the server authors an item and 
00334 **    assigns it to a particular user, and when that user syncs-in that
00335 **    item it is processed immediately.  This makes it possible to 
00336 **    remotely launch programs on select clients from the Commence server.
00337 **
00338 **
00339 ** \par Adding Items to the Queue
00340 **   Items can be added to the DumontQueue either through an agent, or
00341 **    directly by scripting.
00342 **
00343 ** \image html DumontQueueAgent.png
00344 **
00345 */
00346 
00347 /*!
00348 ** \page serverOnlySharedAgents Running Agents on one or more machines
00349 **
00350 ** The Commence agent sub-system is a beautiful and wonderous thing.  Agents
00351 **  allow you to have your database respond quickly and easily to all sorts
00352 **  of activity.
00353 **
00354 ** However, as your implementation grows, you will find there are a couple
00355 **  of problems with agents.  Specifically, you will find you may have the
00356 **  need to run an agent on one or more clients only, or you may want to 
00357 **  run the agent on just the server.  One way to run an agent on the
00358 **  server only is to write the agent on the server, and then 'not share'
00359 **  the agent.  Simple!  Until... your server hard-drive crashes, and
00360 **  you're forced to redeploy the server on a new machine from a backup
00361 **  copy of the database... or, worse yet, a copy of one of the client
00362 **  databases.  Either way you'll find that you'll be forced to author
00363 **  those same agents again, and make sure they're not shared again, and
00364 **  so on.  This is a difficult proposition considering that the agents
00365 **  in question may have been authored more that a year ago, and remembering
00366 **  which ones were set up in exactly which way can be problemmatic in
00367 **  the least ~ especially if someone else is having to figure out something
00368 **  YOU did... without any documentation, no less!
00369 **
00370 ** It would be better if you could simply control on which clients each 
00371 **  agent was allowed to run.  You would benefit from being able to share
00372 **  all the agents to the entire workgroup providing for not only multiple 
00373 **  backups of your work, but a much simpler redeployment in the event 
00374 **  of a crash.  In other words, when restoring a database setup, or 
00375 **  redeploying a new setup, you will have to do little more than normal
00376 **  database deployment duties - the agents will take care of themselves.
00377 **
00378 ** <center><b>(: Enter Conditional Agents :)</b></center>
00379 **
00380 **  A Conditional Agent is an agent that runs
00381 **  because a set of conditions is true - in this case, the current user.
00382 **  The current user can be any client-user within your workgroup, and
00383 **  it can be the server as well.  Here is what the setup looks like:
00384 **
00385 ** \image html cmcServerOnlySharedAgents.png
00386 **
00387 ** In this example, an agent has a conditional applied to it to check for
00388 **  the 'Employee' category which happens to be the category that the
00389 **  users 'personal info' is assigned to.  The first element of the filter
00390 **  checks for the '(-Me-)' value of the key field.  The second element
00391 **  of the filter checks for any other value in that category that
00392 **  matches the client-item of the client you want the agent to run on.
00393 **  This second condition can be any number of fields for the comparison.
00394 **
00395 ** In the example shown above, this agent will be allowed to run on three
00396 **  machines; The server (SVR), Mark (MWP), or Claudia (CWG).
00397 **
00398 ** This example shows a simple server-only filter.  The filter looks for
00399 **  the (-Me-) item matching also the name "Server", which is the name
00400 **  of the item in the 'Employee' category as it relates to the server:
00401 **
00402 ** \image html cmcServerOnlySharedAgentsSimpleServer.png
00403 **
00404 ** Here is an example of a filter that will run on any user assigned to
00405 **  a particular group, making running agents on one or more machines
00406 **  a trivial task:
00407 **
00408 ** \image html cmcServerOnlySharedAgentsByGroup.png
00409 **
00410 ** In this case, the (-Me-) item is still part of the filter criteria,
00411 **  .and. included in the criteria, as Filter-2, is a connection to the
00412 **  Group called "DBA"... meaning "Database Administrators".  So, this
00413 **  agent will fire on any client (or server) that has a connection 
00414 **  to the "DBA" group item.
00415 **
00416 ** Cool, huh?  Now you can author agents and cause them to run on any
00417 **  number of specific machines easily.  Keep in mind, however, that in order 
00418 **  for these filters to work on the server you must have an item in
00419 **  your 'Employee' category called "Server" or "Mr. Server" or 
00420 **  "Master Server" or some such item, so that it can be filtered against
00421 **  just like any client would be.
00422 **
00423 ** Also, obviously, you must insure that you set up your new workgroup
00424 **  properly, and properly assign Users to items in your Employee category:
00425 **
00426 ** \image html cmcServerOnlySharedAgentsAssignUsers.png
00427 **
00428 ** Once set up properly, you should never have to fool with your 
00429 **  client-specific agents again, even on a total workgroup redeployment!
00430 **
00431 */
00432 
00433 /*!
00434 ** \page handyFunctions Handy Functions
00435 **
00436 ** Here are some functions that come in handy under various circumstances.
00437 **  I use these functions in almost all of my scripts so usually I'll 
00438 **  just copy them from this page and paste them directly into my
00439 **  script files.  At the bottom of this page are some scripts that I use
00440 **  on occasion, or have retired for newer functions, but after spending
00441 **  a good deal of time researching them I don't want to loose the codes.
00442 **
00443 ** I try to stick as much common code as possible into library files, and
00444 **  I try to duplicate code fragments as little as possible.  This method
00445 **  of providing function wrappers for 'dexe' and 'dapp' has provided
00446 **  a happy medium between pasting code over and over, and dealing with
00447 **  issues like not being able to get to Dumont or the correct application
00448 **  object.  With these two core functions, 'dexe' and 'dapp', I can stick
00449 **  the remainder of my reused code fragments into items such as 'common.inc'
00450 **  and other places so that the application can quickly and easily 
00451 **  reference them, include them, and not have to duplicate them over and 
00452 **  over.
00453 **
00454 ** \par vbScript Code ~ At the top of every program
00455 ** \code
00456 Option Explicit
00457 '
00458 ' Name my application can be referred by
00459 '
00460 const APP_NAME = "KES.sv1"
00461 
00462 '
00463 ' Replace 'commonScript.inc' with your included file.  Don't forget
00464 '  that included files can include other files as well, so you
00465 '  can chain multiple includes together into one ginormous 
00466 '  include.
00467 '
00468 ExecuteGlobal dapp.cv.getField( "Dumont", "commonScript.inc",  "Value" )
00469 ** \endcode
00470 **
00471 ** \par vbScript Code ~ for WScript (or .vbs) files
00472 ** This code is pasted in to all .vbs files.  These are the only
00473 **  functions that are unique to .vbs programs - which is different 
00474 **  from detail forms.
00475 ** \code
00476 ' ~ ~ ~ ~ ~ ~ ~ BEGIN PASTE: WSCRIPT.COMMON ~ ~ ~ ~ ~ ~ ~ ~ ~
00477 '
00478 ' This will quit a .vbs script with a log message
00479 '
00480 Sub Quit( ByVal outMessage )
00481   if( IsObject(dlog) ) then _
00482     if( outMessage <> "" ) then _
00483       dlog.print outMessage
00484   WScript.Quit
00485 End Sub
00486 
00487 '
00488 ' This will hook dumont
00489 '
00490 dim m_dexe
00491 function dexe()
00492   if( not IsObject(m_dexe) ) then
00493     set m_dexe = createObject("Dumont.EXE")
00494     if( m_dexe is nothing ) then 
00495       msgBox "unable to get to Dumont.EXE"
00496       WScript.Quit(0)
00497     end if
00498   end if
00499   set dexe = m_dexe
00500 end function
00501 
00502 '
00503 ' This hooks the primary application object.  This
00504 '  will fetch the only registered application, or
00505 '  if there are two registered applications, then
00506 '  it will fetch the application by name.
00507 '
00508 dim m_dapp
00509 function dapp()
00510   if( not IsObject(m_dapp) ) then
00511     set m_dapp = dexe.application(AppName)
00512     if( m_dapp is nothing ) then _
00513     set m_dapp = dexe.application(0)
00514     if( m_dapp is nothing ) then 
00515       Quit "application not registered"
00516     end if
00517   end if
00518   set dapp = m_dapp
00519 end function
00520 
00521 '
00522 ' This returns the script name of a .vbs file
00523 '
00524 function ScriptName()
00525   ScriptName = WScript.ScriptName
00526 end function
00527 
00528 '
00529 ' This returns the name of the target application.
00530 '  this value can vary depending how this script
00531 '  is called.  When calling from an agent, the
00532 '  first argument on the command line should be 
00533 '  the name of the target database.  This is
00534 '  accomplished by including a "(-DatabaseName-)"
00535 '  as the first argument to this script.
00536 '
00537 function AppName()
00538   if( dexe.applications.count > 1 ) then
00539     if( wscript.arguments.count > 0 ) then
00540       AppName = wscript.arguments.item(0)
00541       exit function
00542     end if
00543   end if
00544   AppName = 0
00545 end function
00546 '
00547 ' ~ ~ ~ ~ ~ ~ ~ END PASTE: WSCRIPT.COMMON ~ ~ ~ ~ ~ ~ ~ ~ ~
00548 ** \endcode
00549 ** 
00550 ** \par vbScript Code ~ for Detail Forms
00551 ** This code is pasted in to all detail forms.  These are the only
00552 **  functions that are unique to detail forms - which is different 
00553 **  from .vbs programs.
00554 ** \code
00555 ' ~ ~ ~ ~ ~ ~ ~ BEGIN PASTE: DETAILFORM.COMMON ~ ~ ~ ~ ~ ~
00556 '
00557 ' This will quit a .vbs script with a log message
00558 '
00559 Sub Quit( ByVal outMessage )
00560   if( IsObject(dlog) ) then _
00561     if( outMessage <> "" ) then _
00562       dlog.print outMessage
00563   dfrm.Abort
00564 End Sub
00565 
00566 '
00567 ' This will hook dumont
00568 '
00569 dim m_dexe
00570 function dexe()
00571   if( not IsObject(m_dexe) ) then
00572     set m_dexe = createObject("Dumont.EXE")
00573     if( m_dexe is nothing ) then 
00574       msgBox "unable to get to Dumont.EXE"
00575       WScript.Quit(0)
00576     end if
00577   end if
00578   set dexe = m_dexe
00579 end function
00580 
00581 '
00582 ' This hooks the primary application object.  This
00583 '  will fetch the only registered application, or
00584 '  if there are two registered applications, then
00585 '  it will fetch the application by name.
00586 '
00587 dim m_dapp
00588 function dapp()
00589   if( not IsObject(m_dapp) ) then
00590     if( dexe.applications.count = 1 ) then
00591       set m_dapp = dexe.application(0)
00592     else
00593       set m_dapp = dexe.application(AppName)
00594     end if
00595     if( m_dapp is nothing ) then 
00596       Quit "application not registered"
00597     end if
00598   end if
00599   set dapp = m_dapp
00600 end function
00601 
00602 '
00603 ' This returns the script name of a Detail Form
00604 '
00605 function ScriptName()
00606   ScriptName = dfrm.categoryName & "(" & dfrm.name & ")"
00607 end function
00608 
00609 '
00610 ' This returns the name of the target application.
00611 '
00612 function AppName()
00613   AppName = Application.databaseName
00614 end function
00615 '
00616 ' ~ ~ ~ ~ ~ ~ ~ END PASTE: DETAILFORM.COMMON ~ ~ ~ ~ ~ ~
00617 ** \endcode
00618 **
00619 ** \par vbScript Code ~ for the commonScript.inc file
00620 ** This code can be stuck in to a common include file and included
00621 **  in to either a .vbs program or a detail form.  The routines
00622 **  are generic enough to not require environmental adaptation
00623 **  (such as distinguishing between .vbs programs or detail form
00624 **  scripts.
00625 ** \code
00626 '
00627 ' This hooks the log object for a detail form or
00628 '  .vbs script.
00629 '
00630 dim m_dlog
00631 function dlog()
00632   if( not IsObject(m_dlog) ) then
00633     set m_dlog = dexe.logWindow(ScriptName,true)
00634     if( m_dlog is nothing ) then 
00635       Quit "unable to create log"
00636     end if
00637   end if
00638   set dlog = m_dlog
00639 end function
00640 
00641 '
00642 ' This wraps a detail form
00643 '
00644 dim m_dfrm
00645 function dfrm()
00646   if( not IsObject(m_dfrm) ) then
00647     set m_dfrm = dexe.form(form)
00648     if( m_dfrm is nothing ) then 
00649       Quit "unable to wrap form"
00650     end if
00651   end if
00652   set dfrm = m_dfrm
00653 end function
00654 
00655 '
00656 ' This gives the operator the option to opt out
00657 '
00658 function OptOut( ByVal message )
00659   OptOut = False
00660   dim a: a = MsgBox( message, vbYesNo, ScriptName & " Opt Out" )
00661   if( a = vbNo ) then OptOut = True
00662 end function
00663 
00664 '
00665 ' This hooks the Dumont dq function, which is
00666 '  a very thorough version of most vb implementations
00667 '  of dq.  In other words, and to quote the documentation
00668 '  of the dq function itself, if the dq'ed string already
00669 '  contains double-quotes, those are double-double
00670 '  quoted so as to preserve any original quotational
00671 '  marks.
00672 '
00673 ' \see cmcObject::dq
00674 '
00675 function dq( ByVal v )
00676   dq = dapp.dq(v)
00677 end function
00678 ** \endcode
00679 **
00680 **
00681 ** Here is a simple chunk of code that can color an outlook
00682 **  2003 label.  Since the release of Outlook 2007, this code is
00683 **  is more-or-less useless, but we keep it for historical 
00684 **  purposes (and in case someone wants to color an outlook 
00685 **  2003 calendar item).
00686 **
00687 ** \par vbScript Example ~ Outlook 2003 Label Colors
00688 ** \code
00689 Sub SetApptColorLabel( ByRef objAppt, ByVal intColor )
00690     ' requires reference to CDO 1.21 Library
00691     ' adapted from sample code by Randy Byrne
00692     ' intColor corresponds to the ordinal value of the color label
00693         '1=Important, 2=Business, etc.
00694     const cdoPropSetID1 = "0220060000000000C000000000000046"
00695     const cdoAppt_Colors = "0x8214"
00696     dim objCDO ' As Object
00697     dim objMsg ' As Object
00698     dim colFields ' As Object
00699     dim objField ' As Object
00700     dim strMsg ' As String
00701     dim intAns ' As Integer
00702     on error resume next
00703 
00704     Set objCDO = createObject("MAPI.Session")
00705     objCDO.Logon "", "", False, False
00706     
00707     if( not objAppt.EntryID = "" ) then
00708     
00709         set objMsg = objCDO.GetMessage( objAppt.EntryID, objAppt.Parent.StoreID )
00710         Set colFields = objMsg.Fields
00711         Set objField = colFields.Item( cdoAppt_Colors, cdoPropSetID1 )
00712         if( objField is nothing ) then
00713             err.clear
00714             set objField = colFields.Add(cdoAppt_Colors, vbLong, intColor, cdoPropSetID1)
00715         else
00716             objField.Value = intColor
00717         end if
00718 
00719         objMsg.Update True, True
00720 
00721     else
00722         strMsg = "You must save the appointment before you add a color label. " & _
00723                  "Do you want to save the appointment now?"
00724         intAns = MsgBox(strMsg, vbYesNo + vbDefaultButton1, "Set Appointment Color Label")
00725 
00726         if( intAns = vbYes ) then
00727             call SetApptColorLabel(objAppt, intColor)
00728         else
00729             exit sub
00730         end if
00731 
00732     end if
00733 
00734     set objMsg    = nothing
00735     set colFields = nothing
00736     set objField  = nothing
00737     objCDO.Logoff
00738     set objCDO    = nothing
00739 
00740 End Sub
00741 ** \endcode
00742 **
00743 **
00744 */
00745 
00746 
00747 /*!
00748 ** \page FormAnimation Form Animation
00749 **
00750 **
00751 */
00752 
00753 /*!
00754 ** \page ChangeLogEngine Change Log Engine
00755 **
00756 **
00757 */
00758 
00759 /*!
00760 ** \page lostToolBars How to recover missing tool bars
00761 **
00762 ** This is something that happens occasionally, usually when fiddling with the 
00763 **  screen while Commence is busy doing something else.  All of a sudden, *pop*
00764 **  and your toolbars are missing!  Often, usually, the Button Bar goes with
00765 **  them.  The button bar, or desktop navigator, is the thing that sits along
00766 **  the left-hand side of the application main window.
00767 **
00768 ** \image html LostToolBars.png
00769 **
00770 ** The easiest way I know to correct the problem is to go in to the system
00771 **  registry and delete all the Commence related keys. The first thing to 
00772 **  do is close the Commence program. Then, from the start menu, run the 
00773 **  program regedit as follows:
00774 **
00775 ** \image html RunRegistryEditor.png
00776 **
00777 ** Find the registry item at: \b "My Computer\HKEY_CURRENT_USER\Software\Commence"
00778 **
00779 ** \image html LostToolBarsRegistry.png
00780 **
00781 **  and just delete the entire key *at* Commence.  This will delete all the 
00782 **  sub-keys, and the offending tool-bar settings that have your toolbars 
00783 **  missing.  The result will mean that you will have to re-adjust your 
00784 **  desktop settings to accomodate the new toolbar locations, but at least
00785 **  they'll be visible again.  (Make sure you close Commence first before
00786 **  editing the registry!)
00787 **
00788 ** \image html LostToolBarsRestored.png
00789 **
00790 ** After deleting that key, and all it's sub-keys, launching Commence should
00791 **  give you regular tool-bar buttons and desktop navigator.
00792 **
00793 ** \note Here is a reference to a Commence Knowledge Base article that
00794 **        provides a little bit more detail
00795 **
00796 ** http://sales.commence.com/CommenceKB/Article.aspx?id=11123
00797 */
00798 
00799 /*!
00800 ** \page outlookIssues Issues with Outlook
00801 **
00802 ** I came across this menu option in Outlook that may or may not make a difference
00803 **  in the functionality of outlook as it relates to Commence.  It appears to be
00804 **  a function that deals with applications and components that have been disabled
00805 **  due to interference with Outlook.  See attached image:
00806 **
00807 ** \image html OutlookDisabledItems.png
00808 **
00809 ** This menu will contain "disabled" dll's associated with Outlook.  If you are having
00810 **  trouble with some functionality in Outlook or Commence, you might check this menu
00811 **  and see if something is turned off.
00812 **
00813 */
00814 
00815 /*!
00816 ** \page multiViewBigFonts How to fix the font sizes on multi-views
00817 **
00818 ** I just completed a re-installation of my entire operating system, and, of course,
00819 **  Commence, and now my multi-views that used to look fine have big-fonts on the
00820 **  tabs.
00821 **
00822 ** \image html MultiViewBigFonts.png
00823 **
00824 ** I don't know how to fix this
00825 **
00826 ** \todo fix multi-view font sizes
00827 */
00828 
00829 /*!
00830 ** \page faqFilterOnNone How Do I Filter on a Blank Connection Field?
00831 **
00832 ** I think there are several ways to get there.  This is the only one I have 
00833 **  committed to memory:
00834 ** 
00835 ** \par
00836 ** \code
00837 ** Category        Connection          Category
00838 ** ------------    -------------       -----------------
00839 ** Matter          Billing Attorney    Employee
00840 **  Matter No                           employeeKey
00841 **  Matter Name                         employeeCfy
00842 **  Label                               Initials
00843 **                                      Extension
00844 ** \endcode
00845 ** 
00846 ** \par Explanation:
00847 ** Filter on connection name, to a specific field, namely the name 
00848 **  field. The Field-value you are searching for is \a "(none)".  If 
00849 **  you set the criteria to \a "Does Not Contain" \a "(none)" then you 
00850 **  will have a filtered list of all items that ARE connected to something.  
00851 **  You can then hit the \a "except" option to get all those that aren't 
00852 **  connected to something.
00853 ** 
00854 ** \par vbScript Example ~ Filtering for blank connection field
00855 ** \code
00856 ** cursor.setFilter "[ViewFilter(1,CTCF,Not,Billing Attorney,Employee,employeeKey,Does Not Contain,""(none)"")]"
00857 ** \endcode
00858 ** 
00859 ** \note When applying this filter in code, you *must* enclose the (none) keyword
00860 **        in double-quotes, otherwise the filter will not be applied properly.  It
00861 **        is probably a good idear to enclose your other fields and category names
00862 **        in quotes as well, just in case there's unacceptable characters imbedded
00863 **        in these names.
00864 ** 
00865 ** \par See Attached: 
00866 ** 
00867 ** \image html FilterExample-ConnectedItemNone.png
00868 **
00869 ** \par See Also:
00870 ** \ref viewFilter
00871 */
00872 
00873 /*!
00874 ** \page resources Additional Resources
00875 **
00876 ** This page contains a list of other projects that are either related directly
00877 **  to the Dumont projects, or are ancillary but helpful to the Dumont projects.
00878 **  If you find any of these hyper-links to be broken please email me so I can
00879 **  fix them.  If you have any support websites that you would like to have
00880 **  referenced, please email me so I can include them.
00881 **
00882 ** \par Other Dumont Projects
00883 **
00884 ** \par
00885 ** http://dumont.showoff-db.org/dll/doc/html/index.html\n
00886 ** The DumontDLL project is the predecessor to the DumontEXE project. It has
00887 **  the same basic functionality as the DumontEXE project but is missing
00888 **  things like the Running Object Table and Application Subclassing
00889 **  technologies.  It is considered by many, well... some, me, actually, to be
00890 **  a first-generation Dumont project.  The DumontEXE is a second-generation
00891 **  project so it is a substantial improvement in the Dumont environment
00892 **  implementation.
00893 **
00894 **
00895 **
00896 ** \par Commence Support and Consulting Groups
00897 **
00898 ** \par
00899 ** http://www.freedomcomputing.com/ (Canada/Ontario)\n
00900 ** Freedom computing is a Canadian company that specializes in the delivery and 
00901 **  support of Workgroup Automation solutions.  They use Commence to deliver 
00902 **  complete solutions including development, installation, training, and 
00903 **  on-going support.  They are considered by many to be the definative source
00904 **  for all Commence support, are are hosts of the best newsgroup resource
00905 **  for the Commence database.
00906 **
00907 ** \par
00908 ** http://www.warnertech.com/ (United States/Ohio)\n
00909 ** WarnerTech provides affordable cost-effective technology solutions that fit 
00910 **  the way their customers do business.  The fast-paced world of information technology, 
00911 **  coupled with the ever-changing needs of their diverse client base demand that 
00912 **  they maintain a progressive and adaptive corporate attitude. Whether their customers are a 
00913 **  travel agency seeking methods to simplify their customer interaction operations, 
00914 **  or an investment management firm requiring on-call technical support for hardware 
00915 **  and software issues, Warner Tech can provide them with customized computing support options 
00916 **  to help streamline their business.
00917 **
00918 **
00919 **
00920 **
00921 ** \par Application Scripting and other Support Tools
00922 **
00923 ** \par
00924 ** http://www.autoitscript.com/autoit3/ (free)\n
00925 ** AutoIt is a freeware BASIC-like scripting language designed for automating the 
00926 **  Windows GUI and general scripting. It uses a combination of simulated keystrokes, 
00927 **  mouse movement and window/control manipulation in order to automate tasks in a 
00928 **  way not possible or reliable with other languages (e.g. VBScript and SendKeys). 
00929 **  AutoIt is also very small, self-contained and will run on all versions of Windows 
00930 **  out-of-the-box with no annoying "runtimes" required! 
00931 **
00932 ** \par
00933 ** http://www.scriptlogic.com/products/filesystemauditor/ (purchased)\n
00934 **  The File System Auditor allows administrators to audit file access, generate 
00935 **  easy-to-understand compliance reports, and create alerts tied to file system 
00936 **  events all from a centralized management console. File System Auditor protects 
00937 **  sensitive information by reporting attempts to access and modify files and folders, 
00938 **  with who did it and when.
00939 **
00940 ** \par
00941 ** http://setacl.sourceforge.net/ (free)\n
00942 ** SetACL is a set of routines for managing Windows permissions (ACLs) from the command 
00943 **  line, from scripts and from programs. These routines can be used from various 
00944 **  container or interface programs. Currently there exist a command line version to be 
00945 **  used in batch files or scripts and an ActiveX control (SetACL.ocx) which can be used 
00946 **  from any COM-enabled language (VB, WSH scripts, ...).
00947 **
00948 **
00949 ** \par Scripting Language References
00950 **
00951 ** \par
00952 ** http://www.activexperts.com/activmonitor/windowsmanagement/scripts/\n
00953 ** ActiveXperts is a software development company for Windows networking- and communication 
00954 **  tools. They are an excellent resource for vbScripting snippets.
00955 **
00956 ** \par
00957 ** http://www.developerfusion.co.uk/ \n
00958 ** Developer Fusion started back in 1999, then known as "VB Web", and was the 
00959 **  product of too much spare time at the hands of James Crowley. Over time, the 
00960 **  design and features of the site evolved, and regular visitors to the site started asking 
00961 **  about how they could contribute. This enabled us to gradually amass the thousands of 
00962 **  pages of content the site has today.
00963 **
00964 **
00965 ** \par Documentation Tools
00966 **
00967 ** \par 
00968 ** http://www.stack.nl/~dimitri/doxygen/commands.html\n
00969 ** Doxygen is a documentation tool that is used heavily in the Dumont projects.  It 
00970 **  automatically documents source code.  Doxygen is what is responsible for generating
00971 **  the document you're reading now!  With the addition of a few special
00972 **  tags in the source code, a comprehensive documentation library can be quickly
00973 **  assembled.  With any luck, it will be used to create nice documentation packages
00974 **  for any Commence database when used in conjunction with Dumont.
00975 **
00976 ** \par
00977 ** http://www.graphviz.org/Documentation.php\n
00978 ** Graphviz is a graphical drawing tool that is used in conjunction with doxygen to
00979 **  automatically generate graphical charts and diagrams using basic input text files.
00980 **  Here is a good graphical reference document: 
00981 **  http://www.graphviz.org/doc/info/shapes.html
00982 **
00983 ** \par
00984 ** http://cmcdoc.highiq.nl/\n
00985 ** CmcDoc is a tool to document Commence database structures.  CmcDoc analyses the structure 
00986 **  of a Commence database. It will collect general database information and detailed 
00987 **  information about categories, fields, connections, and so on. You can generate 
00988 **  reports in either HTML or XML format.
00989 **
00990 **
00991 **
00992 **
00993 ** \par Other References
00994 **
00995 ** \par
00996 ** http://doc.trolltech.com/ Qt manual.\n
00997 ** This is a reference to the Qt documentation.
00998 **
00999 ** \par
01000 ** http://www.outlookcode.com/default.aspx \n
01001 ** OutlookCode.com is a meeting place for people who want to make Outlook "work harder" 
01002 **  for themselves and their organizations by learning how to program applications for their 
01003 **  own use and to share with others. No matter whether you are a beginner or an expert, 
01004 **  you are welcome to browse the articles, samples and other resources, share your own 
01005 **  code, and discuss Outlook programming issues here.
01006 **
01007 ** \par
01008 ** http://www.dimastr.com/redemption/ \n
01009 ** Outlook Redemption works around limitations imposed by the Outlook Security Patch and 
01010 **  Service Pack 2 of MS Office 98/2000 and Office 2002/2003/2007 (which include Security 
01011 **  Patch) plus provides a number of objects and functions to work with properties and 
01012 **  functionality not exposed through the Outlook object model.
01013 **
01014 ** \par
01015 ** http://www.dimastr.com/outspy/ \n
01016 ** OutlookSpy is the ultimate Outlook developer tool. Integrated directly into Outlook, it 
01017 **  provides fast and convenient access to all  Outlook Object Model objects, lets you examine 
01018 **  values of the properties, call functions, browse object hierarchy and monitor Outlook 
01019 **  events.  CDO is supported too!
01020 **
01021 ** \par
01022 ** http://www.dependencywalker.com/ \n
01023 ** Dependency Walker is a free utility that scans any 32-bit or 64-bit Windows module 
01024 **  (exe, dll, ocx, sys, etc.) and builds a hierarchical tree diagram of all dependent 
01025 **  modules. For each module found, it lists all the functions that are exported by that 
01026 **  module, and which of those functions are actually being called by other modules. Another 
01027 **  view displays the minimum set of required files, along with detailed information about 
01028 **  each file including a full path to the file, base address, version numbers, machine 
01029 **  type, debug information, and more.
01030 **
01031 ** \par
01032 ** http://notepad-plus.sourceforge.net/uk/site.htm
01033 ** Notepad++ is a free (as in "free speech" and also as in "free beer") source code 
01034 **  editor and Notepad replacement that supports several languages. It runs in the 
01035 **  MS Windows environment.
01036 **
01037 ** \par
01038 ** http://sourceforge.net/projects/gup-w32/?abmode=1
01039 ** GUP for w32 is a Generic Updater running under MS Windows. The aim of GUP is to provide 
01040 **  a ready to use and configurable updater which downloads and installs an update 
01041 **  package. Being LGPLed, it can be integrated in both commercial and open source 
01042 **  project.
01043 **
01044 ** \par 
01045 ** http://technet.microsoft.com/en-us/sysinternals/default.aspx
01046 ** The Sysinternals web site was created in 1996 by Mark Russinovich 
01047 **  and Bryce Cogswell to host their advanced system utilities and 
01048 **  technical information. 
01049 **
01050 */
01051 
01052 /*!
01053 ** \page ROT R.O.T.
01054 **
01055 ** <center><h1>Running Object Table</h1></center>
01056 **
01057 ** <b>A Running Object Table</b> is a special object within Dumont that is used
01058 **  to maintain a list of dynamic active-objects in the system.  The R.O.T. acts
01059 **  as a parallel object collection where references (or handles) to objects can
01060 **  be retrieved.  When those objects are deleted by some other process, then
01061 **  they are automatically deleted from the R.O.T.
01062 **
01063 ** There is a video available that demonstrates the use of the running object
01064 **  tables:
01065 **
01066 ** You can find that video here: http://dumont.showoff-db.org/exe/doc/  There are 
01067 **  links for both a high-resolution version of the video (aka; long download) and
01068 **  a low-resolution youtube video of the same thing.
01069 **
01070 */
01071 
01072 /*!
01073 ** \page xml Dom references
01074 **
01075 ** The following code demonstrates that the Dom system within Qt acts as a common
01076 **  memory pool for xml elements.  When an xml reference is pulled from a 
01077 **  document, that reference refers to a common memory pool that is referenced
01078 **  from any other part of the system that also pulls the same reference.
01079 **
01080 ** \code
01081 ** #include <QDomDocument>
01082 ** #include <QApplication>
01083 ** 
01084 ** void func1( QDomDocument & doc )
01085 ** {
01086 **   qDebug( "func1 %s", qPrintable(doc.firstChild().toElement().attribute("xyzzy","func1")) );
01087 ** 
01088 **   doc.firstChild().toElement().setAttribute("xyzzy","abc");
01089 ** 
01090 ** }
01091 ** 
01092 ** void func2( QDomDocument & doc )
01093 ** {
01094 **   qDebug( "func2 %s", qPrintable(doc.firstChild().toElement().attribute("xyzzy","func2")) );
01095 ** }
01096 ** 
01097 ** int main(int argc, char **argv)
01098 ** {
01099 **   QDomDocument doc;
01100 ** 
01101 **   QDomElement element = doc.createElement( "test" );
01102 ** 
01103 **   doc.appendChild( element );
01104 ** 
01105 **   element.setAttribute( "xyzzy", "123" );
01106 ** 
01107 **   QDomElement ref2 = doc.firstChild().toElement();
01108 ** 
01109 **   func1(doc);
01110 **   func2(doc);
01111 ** 
01112 **   qDebug( "ref2 %s", qPrintable(ref2.attribute("xyzzy")) );
01113 ** 
01114 **   element.setAttribute( "xyzzy", "456" );
01115 ** 
01116 **   func1(doc);
01117 **   func2(doc);
01118 ** 
01119 **   QApplication app(argc,argv);
01120 ** 
01121 **   qDebug( "test" );
01122 ** 
01123 **   return( 0 );
01124 ** 
01125 ** }
01126 ** 
01127 ** output:
01128 ** // func1 123
01129 ** // func2 abc
01130 ** // ref2 abc
01131 ** // func1 456
01132 ** // func2 abc
01133 ** // test
01134 ** \endcode
01135 **
01136 */
01137 
01138 /*!
01139 ** \page objectExtensions Object Extensions
01140 **
01141 ** Objects Extensions... This is what the Dumont project is all about - extending the
01142 **  object capabilities of regular Commence objects.  Normally a vbScript application,
01143 **  or external program, connects to Commence directly through the Commence API.  The
01144 **  Commence API offers object interfaces such as \c Application, \c Database, \c Form
01145 **  and so on.  These objects offer a very limited interface.
01146 **
01147 ** The Dumont program extends the regular API of Commence by reproducing the Commence
01148 **  API in its entirety.  All of the objects that are normally available from Commence
01149 **  are also available from Dumont.  Those Dumont objects are also available using the
01150 **  same code as its Commence counterpart.  The functions that are available from each
01151 **  Commence object are also available from each Dumont object.  This means that using
01152 **  the Dumont objects in place of the regular Commence objects is a trivial task.
01153 **  Existing code written for the Commence API can be easily and quickly upgraded to
01154 **  use the Dumont API - very few changes are required to existing code to use Dumont.
01155 **
01156 ** \par vbScript Example to Access a Form Field Object
01157 ** \code
01158 ** Form.Field("Customer Name").value = "Joe Smith"
01159 ** \endcode
01160 **
01161 ** \par vbScript Example to Access a Dumont Form Field Object
01162 ** \code
01163 ** dfrm.Field("Customer Name").value = "Joe Smith"
01164 ** \endcode
01165 **
01166 ** As you can see the two code samples are nearly identical.  The only difference in 
01167 **  the two is the Dumont version uses a \c dfrm object rather than a \c Form object.
01168 **  How does one get a \c dfrm object?  It's simple, just wrap the regular \c Form
01169 **  object with a Dumont \c Form object using the following code:
01170 **
01171 ** \par Wrapping a Commence Form Field object with Dumont
01172 ** \code 
01173 ** dim ddll: set ddll = createObject("DumontDLL")  ' hook into dumont
01174 ** dim dfrm: set dfrm = ddll.form(Form)            ' wrap a regular commence form
01175 ** dfrm.field("Customer Name").value = "Joe Smith" ' simple!
01176 ** dfrm.field("Customer Name").previousValue       ' handy!!
01177 ** dfrm.field("Customer Name").changeLog           ' incredible!!!
01178 ** \endcode
01179 ** \sa cmcDatabaseApi::cmcField
01180 **
01181 ** The Dumont \c Form object is identical in function to the regular commence \c Form
01182 **  object in the sense that it implements all of the regular Commence Form object
01183 **  functions.
01184 ** 
01185 ** \dot
01186 ** digraph cmcCdaObjectWrapper
01187 ** {
01188 **   rankdir=LR;
01189 **   
01190 **   subgraph cluster_0
01191 **   {
01192 **     node [style=filled];
01193 **     application;
01194 **     database;
01195 **     form;
01196 **     field;
01197 **     connection;
01198 **     cdeCategory
01199 **     label = "commence.exe API";
01200 **   }
01201 **
01202 **   subgraph cluster_1
01203 **   {
01204 **     node [style=filled];
01205 **
01206 **     cmcApplication [ URL="\ref cmcDatabaseApi::cmcApplication" ];
01207 **     cmcDatabase    [ URL="\ref cmcDatabaseApi::cmcDatabase"    ];
01208 **     cmcForm        [ URL="\ref cmcDatabaseApi::cmcForm"        ];
01209 **     cmcField       [ URL="\ref cmcDatabaseApi::cmcField"       ];
01210 **     cmcConnection  [ URL="\ref cmcDatabaseApi::cmcConnection"  ];
01211 **
01212 **     cmcApplication -> application;
01213 **     cmcDatabase -> database;
01214 **     cmcForm -> form;
01215 **     cmcField -> field;
01216 **     cmcConnection -> connection;
01217 **     objectExtensions -> cdeCategory;
01218 **     label = "dumont.exe API";
01219 **     color=blue
01220 **   }
01221 **   vbScript -> cmcApplication;
01222 **
01223 **   label = "click on bubbles to see details";
01224 ** }
01225 ** \enddot
01226 **
01227 **
01228 ** However, that is where the similarity ends.  Once the programmer has a handle on
01229 **  a Dumont object, in place of a Commence object, a whole new set of functions and
01230 **  features are available.  These features include things like undo and previousValue 
01231 **  functions on fields and connections and forms, object alias names, comments, 
01232 **  descriptions, documentation, user definable properties and so on...
01233 **
01234 ** \dot
01235 ** digraph cmcCdaFieldWrapper
01236 ** {
01237 **   rankdir=LR;
01238 **   
01239 **   subgraph cluster_0
01240 **   {
01241 **     node [style=filled];
01242 **     field [ shape=record, label="<b0> name|<b1> label|<b2> value" ];
01243 **     label = "commence Field";
01244 **   }
01245 **
01246 **   subgraph cluster_1
01247 **   {
01248 **     node [style=filled];
01249 **     cmcField
01250 **     [ 
01251 **       shape=record, 
01252 **       URL="\ref cmcDatabaseApi::cmcField", 
01253 **       label="<a0>name|<a1>label|<a2>value|previousValue|undo|app|db|cv|categoryName|<a3>aliasName|<a4>comment|<a5>description|<a6>documentation|<a7>property|temp" 
01254 **     ];
01255 **     label = "dumont Field";
01256 **   }
01257 **
01258 **   subgraph cluster_2
01259 **   {
01260 **     node [style=filled];
01261 **     cdaDocument
01262 **     [ 
01263 **       shape=record, 
01264 **       URL="\ref cdaReady", 
01265 **       label="<c3>aliasName|<c4>comment|<c5>description|<c6>documentation|<c7>property" 
01266 **     ];
01267 **     label = "cda xml document\nField Component";
01268 **   }
01269 **
01270 **   cmcField:a0 -> field:b0;
01271 **   cmcField:a1 -> field:b1;
01272 **   cmcField:a2 -> field:b2;
01273 **
01274 **   cmcField:a3 -> cdaDocument:c3;
01275 **   cmcField:a4 -> cdaDocument:c4;
01276 **   cmcField:a5 -> cdaDocument:c5;
01277 **   cmcField:a6 -> cdaDocument:c6;
01278 **   cmcField:a7 -> cdaDocument:c7;
01279 **
01280 **   vbScript -> cmcField;
01281 ** }
01282 ** \enddot
01283 **
01284 ** A Running Object Table is available for any running Commence application.  
01285 **  There's even an Open Form Table available at any time - allowing the
01286 **  programmer to automate one form from another, or one database from another.
01287 **  Dumont also improves the base Commence API by offering shortcuts to regularly used
01288 **  objects and functions.  These shortcuts include access to the cmcApplication 
01289 **  object from any other object.  Additional improvements include a complete DDE 
01290 **  Conversation API that takes care of properly formatting queries into the DDE 
01291 **  system - no more worrying about how to properly double-quote a dde request string!
01292 **
01293 ** Dumont provides for a whole set of object-documentation functions.  These 
01294 **  documentation functions provide storage for complete documentation-related
01295 **  notes for every object in the system.  This includes comments and full field
01296 **  descriptions on Forms and Connections and Fields, even Agents and Views!
01297 **  While not available at the time of this writing, the Dumont system will have
01298 **  the ability of producing a full set of application documentation files using
01299 **  the doxygen documentation system (mentioned here in the \ref resources section).
01300 **
01301 ** ~ ~ ~ ~
01302 **
01303 ** In order for the cmcDatabaseApi to manage additional properties and custom
01304 **  settings of the objects within the system it must have a place to store the data.
01305 **  This type of data is referred to as meta-data, or database design data.  This 
01306 **  meta data is stored in a single xml file and stored in a specially designed
01307 **  category.
01308 */
01309 
01310 /*!
01311 ** \page tipsTricks Tips and Tricks
01312 **
01313 ** Over the years, Commence developers have developed a library of tips and tricks
01314 **  for getting around various limitations within the Commence database product, and
01315 **  have developed creative implementation procedures for some of the functions
01316 **  within Commence.  Some of those methods are documented here.
01317 **
01318 ** \subpage dcf
01319 **
01320 ** \subpage field100
01321 **
01322 ** \subpage subReports
01323 ** by Mike Warner
01324 **
01325 ** \subpage multiViews
01326 **
01327 ** \subpage dosAndDonts
01328 **
01329 ** \subpage isolatingBadData
01330 **
01331 ** \subpage thids
01332 **
01333 ** \subpage nameClarify
01334 **
01335 ** \subpage columnLabels
01336 **
01337 ** \subpage hidingTabs
01338 **  by Donald Bustell
01339 */
01340 
01341 /*!
01342 ** \page hidingTabs Hiding Tabs on Detail Forms
01343 **
01344 ** It is possible to hide tabs on detail forms, which can be a handy
01345 **  thing if you want to restrict users from certain sections of
01346 **  detail forms without the burden of creating multiple forms.  The
01347 **  procedure is not without its pitfalls, however, so you are advised
01348 **  to read this section with caution.
01349 **
01350 ** The following is a reprint (with permission) from Donald Bustell 
01351 **  regarding code for hiding tabs on detail forms.  
01352 **
01353 ** ~ ~ ~ begin quote ~ ~ ~
01354 **
01355 ** The following will hide the third tab of the tab control named "TabCtl2".
01356 ** 
01357 ** \par vbScript Example ~ Hiding Tabs with vbScript
01358 ** \code
01359 ** ' - - - Start Code - - -
01360 ** Set oFRT = Form.RunTime
01361 ** Set oCtl = oFRT.GetControl("TabCtl2")
01362 **     oCtl.Tab = 3
01363 **     oCtl.Tabstate = 1
01364 ** ' - - - End Code - - -
01365 ** 
01366 ** You can also disable and hide things like this:
01367 ** 
01368 ** ' - - - Start Code - - -
01369 ** ' Disable button
01370 ** Set oCtl = oFRT.GetControl("TextBox7")
01371 **     oCtl.Enabled = 0
01372 ** ' Hide button
01373 ** Set oCtl = oFRT.GetControl("CommandButton1")
01374 **     oCtl.Visible = 0
01375 ** ' - - - End Code - - -
01376 ** \endcode
01377 ** 
01378 ** I have had this code in production for nearly five years and have had no 
01379 ** reason to believe that the few problems I have had with Commence were ever 
01380 ** related to it.
01381 ** 
01382 ** I would definitely give careful consideration to arno's comments.They really 
01383 ** shocked me because I know I acquired the above information from this 
01384 ** newsgroup but have absolutely no recollection of any warnings. I know I 
01385 ** would have avoided the technique rather than court trouble.
01386 ** 
01387 ** FWIW,
01388 **
01389 ** Donald
01390 **
01391 ** ~ ~ ~ end quote ~ ~ ~
01392 **
01393 ** Thanks Donald!
01394 **
01395 ** And, here is a small subroutine I've written to simplify the task of hiding
01396 **  tabs:
01397 **
01398 ** \par vbScript Example ~ Tab Hiding Subroutine
01399 ** \code
01400 ** '
01401 ** ' Subroutine to hide a tab by name
01402 ** '
01403 ** sub hideTab( byVal ctlName, byVal tabName )
01404 **   dim ct: set ct = form.runtime.getControl(CStr(ctlName))
01405 **   if( not ct is nothing ) then
01406 **     for i = 0 to ct.tabCount - 1
01407 **       ct.tab = i
01408 **       if( ct.tabCaption = tabName ) then
01409 **         ct.tabstate = 1
01410 **         exit sub
01411 **       end if
01412 **     next
01413 **   end if
01414 ** end sub
01415 **
01416 ** '
01417 ** ' Call with the following (typical)
01418 ** '
01419 ** HideTab "TabCtl2", "Personal"
01420 ** 
01421 ** \endcode
01422 */
01423 
01424 
01425 /*!
01426 ** \page thids THID's and GUID's and why we need them
01427 **
01428 ** \par What is a THID?
01429 ** A THID is an invention of Commence.  As of the time of this writing nobody is
01430 **  sure what THID stands for.  Some guesses include "Thick ID" (that's mine), 
01431 **  "This ID", "Thessolonian ID" (not sure who came up with that... probably me).
01432 **  This just in: <i>At one of the Commence conferences either Todd or Flo had 
01433 **  said a thid was a "thing" id.</i>
01434 **
01435 ** \par
01436 ** In the real world, a THID is a unique 
01437 **  identifier that is associated with each item in each category.  The THID 
01438 **  values are unique, and allow each item in the entire database to be 
01439 **  uniquely identified.  No two items, in any category, in a single database, 
01440 **  will ever have the same THID value.  That's the guaranty.
01441 **
01442 ** \par Why do I need a THID?
01443 ** If you are running a simple, stand-alone database, you probably don't need a
01444 **  THID, and probably will not even know that they exist.  Even if you are running
01445 **  a large workgroup database you are likely to never be aware of THID's.  They 
01446 **  are internal and managed by Commence.  Regular users, and even casual 
01447 **  programmers, don't even see them.  In fact, if you want to make use of them 
01448 **  you have to go through quite a few steps to get at them, and even then their 
01449 **  uses are somewhat limited.
01450 **
01451 ** \par Yes, but, when DO I need them?
01452 ** It is not until you start attempting to synchronize your database with another
01453 **  external database that you will find uses for the THID.  What the THID does, in
01454 **  these instances, is allow you to bind your Commence database with any number of
01455 **  external databases, using some form of unique identification between them.  This 
01456 **  is important because without a guaranteed method of uniquely identifying an item, 
01457 **  you are not likely to be able to reliably synchronize your Commence database 
01458 **  with another database.  The process of database synchronization is quite 
01459 **  complicated, and next to impossible if you cannot uniquely identify items in 
01460 **  the two databases you are trying to synchronize.
01461 **
01462 ** \par
01463 ** Having said that, it doesn't mean that it is impossible to synchronize your
01464 **  database with an external database without the use of unique identifiers, it's 
01465 **  just that using THID's, or some form of unique identification in the 
01466 **  identification and manipulation of items within your database is rather
01467 **  essential.
01468 **
01469 ** \par What do you mean, "Some form..." of unique identification?
01470 ** The statement "some form" depends on you. If you have a category filled with
01471 **  thousands of items, and each item has a "Name" value that is guaranteed to be
01472 **  unique, then you don't need a THID to get to any one particular item, you just
01473 **  use the regular "Name" value.  This is, by far, the easiest method of item
01474 **  identification and manipulation - far easier than THID's.  But, if you don't 
01475 **  have a unique "Name" field value, but you can uniquely identify items by a 
01476 **  combination of field values, then this too is acceptable for purposes
01477 **  of database synchronization.  As long as when making a request for any item 
01478 **  within the database you can be assured that you will always get one item, the 
01479 **  same item, every time, on every request.
01480 **
01481 ** \par
01482 ** In an attempt to avoid unnecessary details, let me mention that Commence *does* 
01483 **  offer a mechanism called a "Clarified" item.  A "Clarified" item is an item that 
01484 **  has a "Name" field value that allows duplicates, and a "Clarify" field value that
01485 **  also allows duplicates.  This means that the category in question allows duplicates
01486 **  but that, hopefully, the combination of a "Name/Clarify" value in a query will 
01487 **  yeild a single item result.  This "mechanism" of uniqueness is not enforced by
01488 **  the Commence internal DB but is instead left up to the integrator who bulds
01489 **  the database.  To say the least, the "Name/Clarify" mechanism of item identification
01490 **  is weak at best, and should probably be avoided as a tool for database synchronization.
01491 **  (For more information see the \ref nameClarify section)
01492 **
01493 ** \par
01494 ** In any case, having a single value as a unique item identification value is very valuable.  
01495 **  It simplifies the process of database synchronization.
01496 **
01497 ** \par What does a THID look like?
01498 ** A THID is a string of characters and numbers.  Here is an example of a THID value:
01499 ** \code
01500 ** 0C:80006901:94BD3402
01501 ** \endcode
01502 **
01503 ** \par Wow!  That looks weird.  What does all that mean?
01504 ** Excellent question.  We don't really know.  Mostly, what we are doing is giving our
01505 **  best guesses of what we think all those numbers and punctuation marks mean.  And,
01506 **  note that the following information is only useful when your database is deployed
01507 **  as a workgroup database.  These numbers don't show up like this at all when you
01508 **  are running on a stand-alone database.  Here is what we have been able to compile 
01509 **  so far:
01510 ** \code
01511 **  +----------------------: 0C   categoryID
01512 **  |    +-----------------: 8000 unknown
01513 **  |    | +---------------: 69   clientID
01514 **  |    | | +-------------: 01   databaseID
01515 **  |    | | |    +--------: 94BD dateCode
01516 **  |    | | |    |   +----: 3402 seqNumber
01517 **  |   _| | |   _|  _|
01518 ** /|  / |/|/|  / | / |
01519 ** 0C:80006901:94BD3402
01520 ** \endcode
01521 **
01522 ** \li \c categoryID \n Every Category is numbered, internally.  This number is encoded in 
01523 **                    the first two characters of the THID value.  This essentially means
01524 **                    that if you know what this number is, you can, simply by reading
01525 **                    the THID value, know which category has to be opened to get to the
01526 **                    actual item.  Actually, now that I look at it, the Commence help file
01527 **                    indicates that up to 800 categories are allowed.  I've never had
01528 **                    a database that had anywhere near 800 categories, but if I did, it
01529 **                    would clearly overwhelm this prefix value which appears to allow 
01530 **                    for only 256 categories.  So, I'm not sure about the value or 
01531 **                    meaning of this number.
01532 **
01533 ** \li \c unknown    \n The meaning of this value is unknown.
01534 **
01535 ** \li \c clientID   \n Every registered client within a workgroup is numbered.  You can find
01536 **                    the assigned numbers for each registered client in the \c data.ini file on
01537 **                    the server.  When a client creates an item in a category, the THID
01538 **                    value for that item includes the clientID value.  This means that
01539 **                    knowing the clientID values (simply by scanning the server data.ini 
01540 **                    file) you will be able to correlate an item to its creator. \n\n Note that 
01541 **                    the clientID value of an item will always be that of the
01542 **                    client that created the item; in other words, if a database is 
01543 **                    re-enrolled, the database will have a new clientID, but the items 
01544 **                    created with the previous clientID will not be updated.
01545 **
01546 ** \li \c databaseID \n I think this is the database ID, but I'm not sure.
01547 **
01548 ** \li \c dateCode   \n This is a date code for the item.  Any item added to the database on a
01549 **                    particular day will have the same date code.  Using this knowledge it
01550 **                    is possible to determine when an item was created by cross-referencing
01551 **                    these date codes to actual calendar dates.
01552 **
01553 ** \li \c seqNumber  \n The final number in the THID value - the sequence number.  This is 
01554 **                    basically a serial number.
01555 **
01556 ** \par So, how do I make use of these here THID numbers?
01557 ** To make use of the THID's you have to read them out of the database.  The only way to do
01558 **  this is through the database cursor object.  Normally, when constructing a cursor, you
01559 **  employ the following codes:
01560 ** \code
01561 ** ' get a no-frills cursor object
01562 ** dim cursor
01563 ** set cursor = cmDB.getCursor( 0, "Calendar", 0 )
01564 ** \endcode
01565 **
01566 ** \par
01567 ** This code gives you a basic, no frills, cursor.  Note that the last parameter, the
01568 **  flags parameter, is set to zero.  This is typical and common since Commence does not
01569 **  really document the methods for working with THID's, and most programmers don't even
01570 **  know about them.
01571 **
01572 ** \par
01573 ** In order to open a cursor that provides THID capability you have to specify a 
01574 **  different value for the flags parameter.  Once you've done this then there is a
01575 **  function available through the cursor API that allows you to read out the THID
01576 **  values:
01577 ** \code
01578 ** ' get a THID based cursor
01579 ** const useTHIDS = 256
01580 ** dim cursor: set cursor = dapp.db.getCursor( 0, "Calendar", useTHIDS )
01581 ** dim qryrow: set qryrow = cursor.getQueryRowSet( cursor.rowCount, 0 )
01582 ** dim i: for i = qryrow.firstRow to qryrow.lastRow
01583 **   dim itemName: itemName = qryrow.getRowValue( i, 0, 0 )
01584 **   dim itemTHID: itemTHID = qryrow.getRowID( i, 0 )
01585 **   msgBox "Your item: " & itemName & " has a THID of: " & itemTHID
01586 ** next
01587 ** \endcode
01588 ** What you now have is access to that one unique identifier for each item in your
01589 **  database.  What you do with it after that is entirely up to you.
01590 **
01591 ** \par That's it?  That's all I can do?
01592 ** For the most part, yes.  You can read THID values out of your database.  You can
01593 **  also use those values when assigning connections between items, which we'll discuss
01594 **  shortly.  But, yes, that's about it.  You can also fetch a particular item by THID
01595 **  for query, edit or delete using the API.  But, you cannot filter a view based 
01596 **  upon a THID value.  This means that the THID value is just about useless outside 
01597 **  of the API.  You cannot gain access to THID values from inside detail form scripts
01598 **  without opening a cursor object.  If you are on a detail form for an item inside
01599 **  a category that allows duplicates there is no real safe way of acquiring the THID
01600 **  for that item without opening a cursor and, hopefully, applying a filter that will
01601 **  yeild that one same item.  This really can lead to problems if you are on a detail
01602 **  form and you want to interface to an external db or program, and you'd like to make
01603 **  reference to your item, in a category that allows duplicates, and you don't have
01604 **  access to the THID... it's more work than it needs to be.  All CCorp had to do
01605 **  was provide access to this value through the form script interface... but I digress.
01606 **
01607 ** \par
01608 ** Here is some code that demonstrates how to fetch an item directly by its THID value.
01609 ** \code
01610 ** ' get a THID based cursor
01611 ** const knownTHID = "0C:80006901:94BD3402"
01612 ** const useTHIDS = 256
01613 ** dim cursor: set cursor = cmDB.getCursor( 0, "Calendar", useTHIDS )
01614 ** dim qryrow: set qryrow = cursor.getQueryRowSetByID( knownTHID, 0 )
01615 ** dim i: for i = 0 to qryrow.rowCount - 1
01616 **   dim itemName: itemName = qryrow.getRowValue( i, 0, 0 )
01617 **   dim itemTHID: itemTHID = qryrow.getRowID( i, 0 )
01618 **   msgBox "Your item: " & itemName & " has a THID of: " & itemTHID
01619 ** next
01620 ** \endcode
01621 ** The result here should be a single row equivalent to the item that matches the THID
01622 **  value you requested (you'll have to provide your own 'good' THID value there).
01623 **
01624 ** \par Read-Only via API with no filters? That makes no sense!
01625 ** Well... welcome to Commence?
01626 **
01627 ** \par 
01628 ** Actually, it's not the end of the world.  If you are really attached to using
01629 **  the THID values in your application then you can do so with any number of methods.
01630 **  If you are synchronizing with a 3rd party database, then you can simply read all the
01631 **  items out of your category, along with the THID values, and store all that information
01632 **  including the THID values in your 3rd party synchronization database.  When you 
01633 **  perform synchronization, then, all you have to do is read all your items out again
01634 **  along with the THID value, and use that THID value to locate-again your item in
01635 **  the synchronization database, and perform whatever synchronization needs to be
01636 **  performed.
01637 **
01638 ** \par I can't filter a view based on the THID.  What else can I not do?
01639 ** Well, you can't get the THID value before an item is written to the database.  You see,
01640 **  the THID value is only available through the API cursor, and the API cursor only
01641 **  provides access to items that are actually saved to the database.  This may seem to
01642 **  be a rediculous thing to be mentioning, but consider this...
01643 **
01644 ** \par
01645 ** If you decide you need some sort of unique identifier on your items so that you can
01646 **  filter them and search for them by this unique identifier, then the THID would really
01647 **  be a handy thing, since it's already unique, internal, provided by the database, so
01648 **  on and so on.  But, to be able to search for an item by its THID, you are forced to
01649 **  store the THID value directly on to a field that can be filtered against.  However,
01650 **  when you are busy on your detail form, storing your values, the THID for that item
01651 **  that you are about to save is not available yet, because the item hasn't been written
01652 **  yet.  Therefore, you cannot provide the THID value for the field for the item that
01653 **  you are about to save.  This means you are forced to execute some sort of post-save
01654 **  process to read the THID value and store it back on to that item.
01655 **
01656 ** \par
01657 ** Frankly, it's a mess.  And it's all brought about by the fact that CCorp does not
01658 **  provide any access to these THID values except through the API cursor object.  They
01659 **  could do better.
01660 **
01661 ** \par What else?
01662 ** Well, THID's are a strange thing.  You cannot get to them directly from a form script,
01663 **  but you can use them when assigning connections between two items.  Another way to
01664 **  say this is like this; You cannot read a THID without opening a cursor, but you can
01665 **  assign a connection with a THID... assuming you know what it is.  The question is,
01666 **  if you can only read them from the cursor API, what's the point in being able to use
01667 **  them in connection assignments?  That is... yet another good question.  As indicated
01668 **  earlier, their usefulness is somewhat limited, not because they are not useful in and
01669 **  of themselves, but because they are so difficult to get to, and largely because THID
01670 **  values cannot be used in a regular filter expression.
01671 **
01672 ** \par
01673 ** <b>Also,</b> if you are going to use THID values for things like database 
01674 **  synchronization, you are most likely going to be building an intermediate database
01675 **  that maps a Commence THID value with a foreign database ID value.  If you get in
01676 **  a situation where you have to re-deploy your Commence database, for any number of
01677 **  reasons, all of the THID numbers that you are relying on, through the API, will 
01678 **  change in the new Commence workgroup database.  Depending on how you implement your
01679 **  synchronization module you may be in for a disaster.
01680 **
01681 ** \anchor thidBugs
01682 ** \par THID Bugs
01683 ** There are a few known bugs when working with THID values.  For one, you read THID
01684 **  values by opening a cursor in USE_THIDS mode.  However, notice that there are different
01685 **  Modes a cursor can be opened in:
01686 **
01687 ** \par vbScript Example ~ different types of cursors
01688 ** \code
01689 ** const CMC_CURSOR_CATEGORY  = 0
01690 ** const CMC_CURSOR_VIEW      = 1
01691 ** const CMC_CURSOR_PILOTAB   = 2
01692 ** const CMC_CURSOR_PILOTMEMO = 3
01693 ** const CMC_CURSOR_PILOTTODO = 5
01694 ** const CMC_CURSOR_PILOTAPPT = 6
01695 ** const USE_THIDS = 256
01696 ** 
01697 ** ' Category Based Cursor
01698 ** dim cursor1: set cursor1 = dapp.db.getCursor( CMC_CURSOR_CATEGORY, "Person", USE_THIDS )
01699 ** 
01700 ** ' View Based Cursor
01701 ** dim cursor2: set cursor2 = dapp.db.getCursor( CMC_CURSOR_VIEW, "Active People", USE_THIDS )
01702 **
01703 ** ' Book Based Cursor
01704 ** dim cursor3: set cursor3 = dapp.db.getCursor( CMC_CURSOR_VIEW, "Phonebook", USE_THIDS )
01705 ** \endcode
01706 **
01707 ** \par
01708 ** <b>In the example above,</b> three cursors are opened on the same category.  One 
01709 **  cursor is opened directly on the category, another cursor is opened on the category 
01710 **  through the view "Active People".  And a third cursor is opened on the same category, 
01711 **  through the view, but the View selected is of the "Phonebook" type.  Note also that 
01712 **  all three cursors are opened with the USE_THIDS flag set.
01713 **
01714 ** \par
01715 ** <b>Here is the problem.</b>  In the first cursor, reading a connection column will return
01716 **  a THID value.  In the second cursor, reading a connection column will return the 
01717 **  'Name' values for that column.  And, in the third cursor, reading that same column
01718 **  again will, like the first cursor, return the THID value for that column.  Even
01719 **  though in all three cases you may be reading the same column.
01720 **
01721 ** \par
01722 ** This is a bug.  Not widely known, but a bug all the same.
01723 **
01724 **                             <center><b>~ ~ ~ ~ ~</b></center>
01725 **
01726 ** \par What is the best way to work with THID values, then?
01727 ** Good question.  Opinions on this topic vary.  I will tell you what I have done, and
01728 **  if someone else wants to chime in with their solutions, I'll include those here
01729 **  as well.
01730 **
01731 ** \par
01732 ** <b>My first complaint</b> with THID values is they cannot be used in filter expressions.
01733 **  This is really a show stopper for me because if I am going to be manipulating my
01734 **  data through scripting, and if my categories allow duplicate items, then I am
01735 **  going to need some method of finding a particular item.  The quickest interface
01736 **  for this task is either with DDE calls or API calls - both of which employ the
01737 **  very complicated "Filter" string.
01738 **
01739 ** \par
01740 ** <b>My second complaint</b> is that the THID values are different for different databases
01741 **  within the workgroup.  You can look at one machine and find a THID value for a particular
01742 **  item and look at another machine and find a completely different THID value for that
01743 **  very same item.  This makes THID values nearly useless for tracking items between
01744 **  different databases.  And, watch your arse if you ever have to redeploy a client db
01745 **  where the scripting code relies on hard-coded THID values.  Any disruption in that
01746 **  deployment is going to cause a breakage in your code.
01747 **
01748 ** \par
01749 ** <b>When you consider</b> that on one hand, you're dealing with cursors and rowsets, 
01750 **  and they deliver THID values in their own particular way, then when you switch to
01751 **  a detail form, you don't have access to the same information.  If you're looking at
01752 **  a connection field on a detail form, you can get just about any field from a 
01753 **  connected item, but you cannot get to the THID values of those connected items.
01754 **  If the connected item category allows duplicates, and you need to know the THID
01755 **  value of one of those items, how do you fetch it when your only interface to 
01756 **  the THID value is through the cursor?  This is a silly limitation that leads to
01757 **  some seriously complicated workarounds.
01758 **
01759 ** \par
01760 ** <b>One quick improvement</b> to the inaccessability of THID values is to read the
01761 **  THID value out from the rowset and store it on the item itself, in a specially 
01762 **  tailored field.  This simple exercise opens an incredible number of possible 
01763 **  methods for interacting with THID values.  The major disadvantage with this
01764 **  "solution" (and I use that term lightly) is that it consumes one of the precious
01765 **  100 fields/connections from the category.  I have aleviated the 'pain' of such
01766 **  a workaround by providing a memo field for the THID value, and in that memo field
01767 **  I am able to store a host of other values as well, but, all in all, it's still
01768 **  a bit of an ugly workaround.
01769 **
01770 ** \par
01771 ** <b>Even still,</b> if I do store the THID value in this manner, what good is it
01772 **  if I redeploy my workgroup database?  All of those stored THID values would need
01773 **  to be updated in order to use them in conjunction with the API, and this becomes
01774 **  a THID synchronization issue between an actual THID on an item and a stored THID
01775 **  on that same item.  Furthermore, the same old problem still exists if the workgroup
01776 **  database is redeployed, and there's an old synchronization database that is 
01777 **  relying on those THID values.
01778 **
01779 ** \par Well, I need a THID, or something like it.  What now?
01780 ** What Commence needs is a THID-like value that is unique per item, available
01781 **  through any field/connection interface, and will not change if the workgroup 
01782 **  database is redeployed.  Oh, and this THID-like value should be available whether
01783 **  the database is stand-alone or deployed in a workgroup.  In short, every item in
01784 **  every category should come with an automatic unique identifier that is filterable
01785 **  and easily accessible.
01786 **
01787 **        <center><b>~ ~ ~ ~ ~ Enter Dumont and the GUID ~ ~ ~ ~ ~</b></center>
01788 **
01789 ** \par
01790 ** Dumont has built-in to it a set of functions for manipulating something called a
01791 **  GUID value.  This value is quickly and easily added to any Commence item, is static
01792 **  regardless if the database is stand-alone, workgroup, redeployed, bent, folded
01793 **  spindled or mutilated.  It is filterable.  It is searchable.  It is known BEFORE
01794 **  the item is written to the database through a \c cursor.commit or \c form.save event.
01795 **
01796 ** \par
01797 ** My thought on it is this; If in order to make practical use of the THID values
01798 **  I have to go through extra steps to store THID values on each item, and if there
01799 **  are extra problems that come with using THID values (such as database redeployment
01800 **  or whatever), then why not just go through the extra steps of providing storage
01801 **  for THID values, and then instead of storing them, store my own value there, one
01802 **  that I have full control over?  It will provide all the "unique item" functionality
01803 **  that I am looking for in the database, plus I can make sure that the value is
01804 **  available even before I have written my item to disk.
01805 **
01806 ** \par
01807 ** How handy is that?
01808 **
01809 ** \par Sounds great!  What's a GUID?
01810 ** Ah, an easy one.  Try googling it.  Here's a link: http://www.webopedia.com/TERM/G/GUID.html
01811 **  In short, a GUID is a "Globally Unique IDentifier", or a number that is guaranteed
01812 **  to be unique anywhere in the world.  A GUID generator is a software component that
01813 **  is available on most operating systems, and the rule is, that no matter how many
01814 **  numbers you generate, you will never get a duplicate number, anywhere, anytime.
01815 **  That's the promise.  If you want to test this theory yourself, go download my utility called
01816 **  http://dumont.showoff-db.org/guidgen/doc/html/ on the web.  Run it and see if you can get 
01817 **  it to generate any duplicates.  You won't!
01818 **
01819 ** \par Impressive! What does an GUID look like?
01820 ** Another easy one.  I like these!  A GUID is just a specially formatted string of
01821 **  characters, much like the THID.  Here's one:
01822 **
01823 ** \par
01824 ** \code
01825 ** {4D614E67-0210-4837-9390-924BBDDCCFFD}
01826 ** \endcode
01827 **
01828 ** \par
01829 ** <b>GUIDGEN</b> spat that out for me with just a quick click of the mouse.  What's nice
01830 **  about the GUID values is lots of programs are using them.  Not all programs.
01831 **  Not Commence, no sir!  But, a lot of other programs.  And the reason that is such
01832 **  a great thing is these are numbers that are pretty quickly and easily understood,
01833 **  there is a good deal of software already available to support them, and, if YOU
01834 **  are writing a program that is using them, then you stand a pretty good chance of
01835 **  being able to already communicate more clearly with others.
01836 **
01837 ** \par Tell me more!  What does Dumont do with these numbers?
01838 ** Dumont is providing wrappers for all the existing Commence objects.  These objects
01839 **  include cursors, rowsets, forms, fields, connections and so on.  What Dumont has
01840 **  built in to its wrappers is THID/GUID management.  What this basically means is,
01841 **  if you, the database developer, provides just a few things in your category 
01842 **  definitions, things that Dumont is trained to look for, then Dumont will 
01843 **  automatically provide for you all kinds of THID/GUID related functionality.
01844 **  The best part is it's all completely transparent.  Well, not completely, but
01845 **  mostly transparent.
01846 **
01847 ** \par What kinds of things do I have to provide?
01848 ** Well, I mentioned this earlier.  If you provide just one field, in your categories
01849 **  just for Dumont, then Dumont will make use of that field for storing all kinds
01850 **  of internal things about your items, such as when the item was created and by
01851 **  whom, when the item was changed and by whom, the THID and/or GUID for the item
01852 **  and so forth and so on.
01853 **
01854 ** \par
01855 ** <b>Also,</b> if this field is available, and Dumont can recognize it, Dumont will
01856 **  also help you break that 100 field limit barrier that has been a part of Commence
01857 **  development since the dawn of time! For the price of just one field that's quite 
01858 **  a lot in return.  You get improved THID / GUID functionality, time/user stamping 
01859 **  on items, easily extensible fields beyond the 100 field limit, and more!
01860 **
01861 ** \par I'm convinced!  Where do I begin?
01862 ** I'm working on that!  Don't rush me!  Stay tuned here.  This version of Dumont is
01863 **  almost ready for it's debut.  Once I've got it all up and running I'll have a
01864 **  nice 'making my database ready for Dumont' page where you can read all about how
01865 **  to apply Dumont to your projects.
01866 **
01867 ** \par
01868 ** It'll be fun!  Just you wait and see...
01869 **
01870 */
01871 
01872 /*!
01873 ** \page nameClarify Item Name/Clarify mechanism
01874 **
01875 **
01876 */
01877 
01878 /*!
01879 ** \page regexp Regular Expressions
01880 ** 
01881 ** http://www.regular-expressions.info/
01882 **
01883 **
01884 **
01885 ** \code
01886 ** Function FixPhone(str)
01887 **
01888 **  'Create a regular expression object
01889 **  Dim re
01890 **  Set re = New RegExp
01891 **
01892 **  'specify the pattern
01893 **  re.Pattern = "(\d{3}) (\d{3}) (\d{4})"
01894 **
01895 **  'use the test method to verify the pattern
01896 **  If re.Test(str) Then
01897 **     'use the replace method to format
01898 **     FixPhone = re.Replace(str, "($1) $2-$3")
01899 **  Else
01900 **     MsgBox "No match was found"
01901 **  End if
01902 **
01903 ** End Function
01904 ** \endcode
01905 **
01906 */
01907 
01908 /*!
01909 ** \page dcf Dynamic Connection Filters
01910 **
01911 ** Dynamic Connection Filters refers to a recent improvement in the Commence API, which
01912 **  allows the programmer to create dynamic pick-lists inside of Connection fields.
01913 **  These pick-lists can be of the sort:
01914 **
01915 ** \code
01916 ** Order Line Item
01917 **   Product Category
01918 **     Product Function
01919 **       Product ID
01920 ** \endcode
01921 **
01922 ** When entering a order line item, for instance, the user would enter one line at a time.
01923 **  Then they would choose a product category, followed by a product function, and finally
01924 **  a Product ID.  Each choice, Category, Function causes a narrowing of search for the
01925 **  actual product ID that is being searched.
01926 **
01927 ** Another example:
01928 **
01929 ** \code
01930 ** Customer Order Form
01931 **   Country
01932 **     Region
01933 **       State
01934 **         City
01935 **           Customer ID
01936 ** \endcode
01937 **
01938 ** In this example, we have a customer order we are trying to enter.  Rather than being
01939 **  forced to choose from all the billions and billions of customers we have on file, 
01940 **  we would prefer to first select the country code, followed by a region code, state
01941 **  code, city code, and then finally the Customer ID code.  \ref dcf makes this a rather 
01942 **  trivial task.
01943 **
01944 ** \b To \b begin, let's setup a demo database that shows the kinds of dynamic filtering
01945 **  we can perform (keep in mind, this is not practical - but instead just a demonstration
01946 **  for the purposes of training and support):
01947 ** 
01948 ** \image html DynoFilterLayout.png
01949 **
01950 */
01951 
01952 
01953 /*!
01954 ** \page field100 Exceeding the 100 Field Limit
01955 **
01956 **
01957 */
01958 
01959 /*!
01960 ** \page subReports How to make Nested Sub Reports
01961 **
01962 ** The following is a reprint from Mike Warner who did some good
01963 **  sub-reporting using the Commence Report Writer.  It has been
01964 **  reprinted here with his permission:
01965 **
01966 ** ~ ~ ~ begin quote ~ ~ ~
01967 **
01968 ** While I don't know if others have tried this and I am just cluing into the 
01969 ** concept but I was pretty amazed at the ability to use the Report Writer and 
01970 ** nest subreports in Commence.  I will go into great detail below how and why 
01971 ** I created the nesting of reports so if you have not done it already, you 
01972 ** will have a good idea of how to set it all up.  If you have done it already, 
01973 ** I would be interested in knowing if you have found any limitations or 
01974 ** pitfalls.
01975 ** 
01976 ** Let me explain what I did in hopes that others may benefit:
01977 ** 
01978 ** The client is a law firm and they track case related information in their 
01979 ** Commence databases.  The database is design to help manage litigation for a 
01980 ** client in which their employees and vendors may have been exposed to harmful 
01981 ** products in their facilities.  As you can imagine, the design of the 
01982 ** database starts with a Case category.  Several cases are entered for each 
01983 ** lawsuit against the company.  In each case, you will have a Claimant.  The 
01984 ** Case may have one to hundreds of Claimants involve in that particular Case. 
01985 ** Connected to each Claimant will be Claimant Notes, related Medical History 
01986 ** and Work History.  Connected to the Work History would be the Facility and 
01987 ** connected to the Facility would be additional Facility Notes.  Also 
01988 ** connected to the Facility would be Products used at the facility and each 
01989 ** Product would have Product Notes that detailed the hazards of the Product.
01990 ** 
01991 ** \par Here is a layout of the database structure:
01992 ** \code
01993 ** Case
01994 **     Claimant(s)
01995 **         Claimant Notes
01996 **         Medical History
01997 **         Work History
01998 **             Facility
01999 **                 Facility Notes
02000 **                 Products
02001 **                     Product Notes
02002 ** \endcode
02003 ** 
02004 ** Basically, the client requested a report that summarized a Case.  The result 
02005 ** was a Report Writer that, when highlighting a Case in the database, the user 
02006 ** would push a toolbar agent and the Report Writer would open and read the 
02007 ** information into the report.  Here is how the subreports were designed and 
02008 ** nested.
02009 ** 
02010 ** The first step was to develop a Report Writer view for the Case category. 
02011 ** The view was filtered to "Use highlighted item in open view".  The design of 
02012 ** the view included information directly entered in the Case category like 
02013 ** Case Name, Case Number, State and Jurisdiction.  In addition, the summary 
02014 ** section of the report provided a list of the names of the connected 
02015 ** Claimants.  Nothing fancy here, just your basic Report Writer fields and 
02016 ** labels.  The key to this part of the report was that the data from the Case 
02017 ** category was placed in the Group Header section of the Report Writer view. 
02018 ** In the Details section of the Report Writer view was a place for the 
02019 ** subreport designed for the Claimant category.  A title and company logo was 
02020 ** placed in the Page Header section and Page numbers and Date Report Generated 
02021 ** fields were placed in the Page Footer of the report with no other coding or 
02022 ** scripting involved.
02023 ** 
02024 ** Next, I designed the Claimant Report Writer view.  Like the Case category, 
02025 ** the Claimant view was filtered by the connection to a Case in which "Use 
02026 ** highlighted item in open view" was used.  The Claimant report contained no 
02027 ** Page Header but did contain a Group Header.  In the Group Header contained 
02028 ** information directly pulled from the Claimant category like Firstname, 
02029 ** Lastname, Date of Birth, Marital Status and Date of Death.  In the Details 
02030 ** section of the view, was a place for three subreports for the Claimant 
02031 ** Notes, Medical History and Work History subreports to be placed.  The only 
02032 ** scripting placed in the view was the required scripting in the Object - 
02033 ** ActiveReports Document under the Event - OnReportStart as previously 
02034 ** documented in other entries in this newsgroup.  I replicate it here for 
02035 ** convenience:
02036 ** 
02037 ** \code
02038 ** Sub OnReportStart
02039 ** End Sub
02040 ** 
02041 ** Sub OnDataInitialize
02042 **     if CmcSubReport.bSubReport = True then
02043 **         CmcSubReport.DataInitialize
02044 **     end if
02045 ** End Sub
02046 ** 
02047 ** Sub OnFetchData(eof)
02048 **     if CmcSubReport.bSubReport = True then
02049 **         CmcSubReport.FetchData eof
02050 **     end if
02051 ** End Sub
02052 ** \endcode
02053 ** 
02054 ** Next I designed the Claimant Notes and Medical History Report Writer views 
02055 ** with the filter set for each report to filter on the connected Claimant 
02056 ** using the "Use highlighted item in open view" option of the filter and 
02057 ** sorted by the date field in the respective category.  These Views did 
02058 ** contain a Report Header with simply the respective title of the information 
02059 ** like "Claimant Notes:" or "Medical History:" in the header.  In the Details 
02060 ** section, I placed the fields the client was interested in reporting on from 
02061 ** each category their respective views like Date, Medical Diagnosis and the 
02062 ** connected Doctor for the Medical History category.  No footer was used so I 
02063 ** collapsed the Report Footer area to save space.  Again, as with the Claimant 
02064 ** view, the only scripting that I added was the required subreport scripting 
02065 ** listed above.
02066 ** 
02067 ** The Work History Report Writer view is where it gets even more interesting. 
02068 ** Like the Claimant Notes and Medical History, I created the view with a 
02069 ** filter on the connected Claimant.  I also used the Report Header section to 
02070 ** title the section "Work History:".  In the Detail section, I placed the 
02071 ** fields related to the Work History category like Begin Date, End Date, 
02072 ** Employer and Notes.  At the bottom of the Detail section, was a place for 
02073 ** the subreport for the connected Facility.  No Report Footer again, so I 
02074 ** collapse the area.  Again, as with the Claimant view, the only scripting 
02075 ** that I added was the required subreport scripting listed above.
02076 ** 
02077 ** The Facility Report Writer view contained a filter to the connected Work 
02078 ** History again using the "Use highlighted item in open view".  The report in 
02079 ** this case contained no Page Header or Footer and no Report Header or Footer. 
02080 ** In the Detail section of the report were fields direction from the Facility 
02081 ** category like Name, Address and State.  At the bottom of the Details 
02082 ** section, was a place for the subreports for Facility Notes and Products. 
02083 ** Again, as with the previous views, the only scripting that I added was the 
02084 ** required subreport scripting listed above.
02085 ** 
02086 ** The Facility Notes and the Products were similar to the Facility view with 
02087 ** the exception that these reports were filtered on the connected Facility 
02088 ** using the "Use highlighted item in open view" option.  The reports contained 
02089 ** fields directly taken from their respective categories using only the detail 
02090 ** section.  The Products view contained an additional space for the Product 
02091 ** Notes subreports to be placed.  Again, as with the previous views, the only 
02092 ** scripting that I added was the required subreport scripting listed above.
02093 ** 
02094 ** The last report to be designed was the Product Notes view.  This view was 
02095 ** filtered by the connected Product using the "Use highlighted item in open 
02096 ** view" option.  The Detail section was the only area used on the report with 
02097 ** the fields directly related to the Product Notes category.  Again, as with 
02098 ** the previous views, the only scripting that I added was the required 
02099 ** subreport scripting listed above.
02100 ** 
02101 ** Now that I had all the reports created, I needed to reassemble them by 
02102 ** nesting one into the other.  While had I known this process would have 
02103 ** worked, I would have started with the Product Notes and built my reports 
02104 ** going forward but I was not that prepared to know that it would work so I 
02105 ** worked backwards.  I followed the following steps to nest one report into 
02106 ** the other.
02107 ** 
02108 ** Open the Product view and insert the subreport from the Product Notes into 
02109 ** the Detail section and saved the Product view.
02110 ** 
02111 ** Open the Facility view and inserted the subreports for Product and Facility 
02112 ** Notes into the Detail section and then saved the Facility view.
02113 ** 
02114 ** Open the Work History view and inserted the subreport for the Facility into 
02115 ** the Detail section and then saved the Work History view.
02116 ** 
02117 ** Open the Claimant view and inserted the subreports for the Claimant Notes, 
02118 ** Medical History and Work History into the Detail section and then saved the 
02119 ** Claimant view.
02120 ** 
02121 ** Open the Case view and inserted the subreport for the Claimant into the 
02122 ** Details section and then saved the Case view.
02123 ** 
02124 ** In each situation in which a subreport was placed into another report, I 
02125 ** only allowed one line to each subreport.  In this manner if there was no 
02126 ** data to report on for that particular subreport, only the Report Header 
02127 ** information from Claimant Notes, Medical History and Work History would 
02128 ** appear.  Since the CanGrow property was left by default as True, each 
02129 ** subreport could expand as needed to accommodate for those Cases in which 
02130 ** there were multiple Claimants with multiple Claimant Notes, Medical History, 
02131 ** Work History, Facilities, Facility Notes, Products and Product Notes.  Like 
02132 ** an accordian, the report would dynamically expand to report on each 
02133 ** subreport as needed.
02134 ** 
02135 ** The most amazing part to me was that each subreport, based on the filter set 
02136 ** to the respective connected category, produced the required information only 
02137 ** for that record.  For example, if I were party to a case titled "Warner 
02138 ** Technology, Inc. vs. Commence Corporation" (totally fictional lawsuit) the 
02139 ** report may contain the following informtion:
02140 ** 
02141 ** \code
02142 ** Case Name: Warner Technology, Inc. vs. Commence Corporation
02143 ** Case Number: 1234
02144 ** State: Ohio
02145 ** Jurisdiction: Supreme Court of the United States
02146 **     Claimant Name: Michael D. Warner
02147 **     Address: 1234 Main Street, Medina, OH
02148 **         Claimant Notes: Consultant - CPA in past life, enjoys golf and 
02149 ** travelling
02150 **         Medical History: Non-smoker good vitals bad knees - should not play 
02151 ** basketball anymore
02152 **         Medical History: Thyroid condition - Prescribed Synthroid to 
02153 ** stablize due to being over worked!!!
02154 **         Work History: Cohen & Company
02155 **             Date Started: 6/1/1985    Date Ended: 3/31/1993
02156 **             Facility: 1234 East Ninth Street, Cleveland, OH
02157 **                 Facility Notes: Accounting Firm specializing in tax planning
02158 **                 Products: IBM Current
02159 **                     Product Notes: Program first developed in conjuction 
02160 ** with IBM and Jensen-Jones to provided data from the mainframe to the end 
02161 ** user
02162 **                 Products: Commence 1.0
02163 **                     Product Notes: Commence 1.0 was reborn from IBM Current 
02164 ** when Jensen-Jones purchased the rights back from IBM
02165 **         Work History: INSYTE Consulting Group, Inc.
02166 **             Date Started: 4/1/1993    Date Ended: 8/31/1997
02167 **                 Facility: 4321 Prospect Ave, Cleveland, OH
02168 **                     Facility Notes: Right across the street from Jacobs 
02169 ** Field where the Cleveland Indians play.
02170 **                     Products: Commence 2.0
02171 **                         Product Notes: Second generation of the program with 
02172 ** great new features
02173 **                     Products: Commence 3.0
02174 **                         Product Notes: Third generation of the program with 
02175 ** features including scripting
02176 **         Work History: Warner Technology, Inc.
02177 **             Date Started: 9/1/1997    Date Ended:
02178 **                 Facility: 315 West Liberty Street, Medina, OH
02179 **                     Products: Commence RM 2.0
02180 **                         Program Notes: RM stands for Relationship Management
02181 **                 Facility: 588 West Sturbridge Drive, Medina, OH
02182 **                     Products: Commence RM 3.5
02183 **                         Program Notes: Added functionality to nest 
02184 ** subreports in the Report Writer feature
02185 **     Claimant Name: Robert M. Giebel
02186 **     Address: 4321 South Street, Mentor, OH
02187 **         Etc., etc., etc.
02188 ** \endcode
02189 ** 
02190 ** Of course, we would have a report header with logos and page numbers and 
02191 ** date information around the data but as you can imagine, any one report can 
02192 ** be from 2 pages to 75 pages within seconds depending on the number of 
02193 ** claimants and history provided.  Amazingly, the reports are also very quick 
02194 ** to run and display in Commence.  I have had a 16 page report display in less 
02195 ** than 15 seconds.  Of course, a lot is dependent on the system it is run on 
02196 ** but impressive none the less.
02197 ** 
02198 ** Feel free to let me know if you need any further details on how to pull this 
02199 ** altogether.  Thanks for listening.
02200 ** 
02201 ** Mike Warner \n
02202 ** Warner Technology, Inc. \n
02203 ** http://www.warnertech.com/ \n
02204 ** 330-725-5425
02205 **
02206 ** ~ ~ ~ end quote ~ ~ ~
02207 **
02208 ** Thanks, Mike!
02209 **
02210 */
02211 
02212 /*!
02213 ** \page multiViews Multi-view Features and Techniques
02214 **
02215 ** Here is an interesting little tid-bit on the multi-view building and filtering
02216 **  features and techniques. The multi-view is a tool for organizing multiple
02217 **  views into a single managed view.  The multi-view supports a bit of dynamic
02218 **  filtering which can provide a rather intuitive control over managing your
02219 **  data experience.  It's a great tool to use for creating a good user interface
02220 **  experience for your clients.
02221 **
02222 ** \image html MultiViewExample.jpg
02223 **
02224 ** First lets talk about some good techniques for building and managing multi-views.
02225 **
02226 ** One difficulty in dealing with Multi-views is keeping track of all the views
02227 **  that are being assembled into a single multi-view.  Since individual views
02228 **  are built and managed in one place, and the multi-view is built and managed
02229 **  in another, it is easy to loose track of what views you may have wanted to
02230 **  include in the multi-view.  Therefore, a simple solution to keeping track
02231 **  of views related to a multi-view implementation is to use a common view
02232 **  naming convention:
02233 **
02234 ** \image html MultiViewNamingConventions.jpg
02235 **
02236 ** In the image shown above, the multi-views are preceeded, first, with a tilde
02237 **  "~" character.  The next two characters indicate that this view is part of
02238 **  a multi-view.  Therefore, multi-views can be quickly located in the sea
02239 **  of defined views by looking for "~mv".  The next character is used to indicate
02240 **  the primary category used in the multi-view.  When constructing a multi-view,
02241 **  a primary category has to be chosen.  This primary category is used
02242 **
02243 ** I'm sure you have noticed that when constructing a multi-view, there is
02244 **  an option button
02245 **
02246 */
02247 
02248 
02249 /*!
02250 ** \page dosAndDonts Do's and Don'ts
02251 **
02252 ** \par Don't Reuse Workgroup Sync Directories
02253 ** In the process of deploying workgroups, you might be tempted to strip your
02254 **  server back down to a stand-alone, and then redeploy it again as a new
02255 **  workgroup server, DO NOT reuse the same sync directory.  Here is why:
02256 **
02257 ** \par
02258 ** If you have been running a workgroup for any length of time, you probably
02259 **  have multiple registered users connected to your workgroup.  Each one of
02260 **  these users receives their own workgroup ID.  If you shut that workgroup
02261 **  down and redeploy it, you will have to re-register all of your workgroup
02262 **  members.  It is entirely possible that one of your workgroup members is
02263 **  absent during the redeployment, maybe their machine needs repair, or
02264 **  they have decided to be out of the workgroup for a while.  So you redeploy
02265 **  with all your available and interested users leaving that one untended
02266 **  user out of the new workgroup.  If that untended user decides on his own
02267 **  to start using Commence again, and starts up his (old) copy, he will be 
02268 **  attempting to sync to the same workgroup directory that you are using in 
02269 **  your new workgroup deployment.  This is bad because Commence will not be 
02270 **  able to recognize that he is effectively a bad user with an old copy of
02271 **  an old workgroup ID who is actually using either his old/new workgroup ID
02272 **  or someone elses workgroup ID.  Commence will sync with this user anyway, 
02273 **  and it will likely completely ruin your entire workgroup database.  You 
02274 **  will notice this by the sudden appearance of duplicate categories and 
02275 **  duplicate items in those categories and likely other strange symptoms, 
02276 **  especially if his old workgroup ID clashes with someone elses new workgroup
02277 **  ID - you will then find these two users, certainly, are not functioning
02278 **  properly at all.
02279 **
02280 **
02281 **
02282 */
02283 
02284 /*!
02285 ** \page isolatingBadData Isolating Bad Data
02286 **
02287 ** A time is going to come when you will be concerned about the integrity of
02288 **  your database.  You may not necessarily notice anything specific about the
02289 **  database, but things won't seem right.  You might end up with duplicate items
02290 **  in a category that doesn't allow them, and these items might appear like
02291 **  "Johnson, Jim" and "Johnson, Jim1" which is the tell-tale tag of a duplicate
02292 **  item that the server has caught and renumbered (You'll have to sort these
02293 **  out carefully).  Or you might see duplicate categories like, "Matters" and
02294 **  "Matters1".  Where did a duplicate category suddenly come from?  See 
02295 **  \ref dosAndDonts \c "Don't Reuse Workgroup Sync Directories" for a discussion 
02296 **  on possible explanations for that.
02297 **
02298 ** The simple fact is, "databases get corrupt".  Commence is no exception.  You
02299 **  are well advised to put your Commence server on a good running machine with
02300 **  no other critical or intensive applications running, a good UPS and an 
02301 **  exptectation to pamper it well.  And, after all of that, you can count on that
02302 **  your "database will get corrupt".
02303 **
02304 ** The first trick is determining if your database is actually corrupt.  There is
02305 **  a fairly reliable and easy way to do this; execute a "Transfer Out" procedure.
02306 **  When selecting the options on the Transfer Out, you make sure that you select
02307 **  all categories and all agents and items as well, just as shown in the following
02308 **  figure:
02309 **
02310 ** \image html TransferOutDialog.jpg
02311 ** 
02312 ** Using this function, you should end up with an .tfr file on disk which represents
02313 **  a complete transfer out of your entire database.  If you attempt to run this
02314 **  procedure and it does not succeed then you know your database is corrupt.
02315 **  In my experience, when this procedure does not succeed I have ended up staring
02316 **  at a "Application Error..." dialog, and Commence closes.  I have, in fact, 
02317 **  had Commence crash in this manner simply when trying to enroll a new client.
02318 **  Somewhere in the process of enrolling a new client Commence will do the 
02319 **  effective of a Transfer Out since it is transferring the entire database to the
02320 **  new client.
02321 **
02322 ** If you do receive an error in Transfer Out, the trick is to try to catch the
02323 **  offending category or categories.  By watching the following dialog, you can
02324 **  watch as each category is processed:
02325 **
02326 ** \image html TransferOutProgress.jpg
02327 **
02328 ** If the transfer crashes during the process of a category, the last category shown
02329 **  in that dialog progress window will be the category that has the offending data.
02330 **  The trick now is to try to find it.  This is not as difficult as it might sound.
02331 **  You can't count on that you'll be able to "see" the bad data in a report view
02332 **  or even on the detail forms.  If you are able to spot it this way, it will still
02333 **  likely be extremely difficult to find. Even if the category has thousands of 
02334 **  records, it is possible to filter down the data to a much more managable size
02335 **  and then perform the transfer based on a view rather than a category.  Using
02336 **  a thing called "successive approximation" you can continuously filter a view
02337 **  for items, narrowing the search into smaller slices until you have the problem
02338 **  identified as a single item or multiple items.  It's a laborious process since
02339 **  you have to repeatedly filter and transfer and restart, but it's all good in
02340 **  the end.  
02341 **
02342 ** The following figure depicts a series of filters looking for any offending data.
02343 **  As you can see, a successive approximation of values is continuously applied to
02344 **  the view, dividing the number of letters in the alphabet in half each time, and
02345 **  each time coming closer to the target offending item:
02346 **
02347 ** \image html TransferOutFilter.jpg
02348 **
02349 ** Once the filter is applied to the view, the view must be saved so that Commence
02350 **  itself knows about the filter, and then a new Transfer Out must be executed 
02351 **  against that specific, filtered view.  Each time the new, filtered, Transfer Out
02352 **  fails, the data item is somewhere within that range.  Each time the Transfer Out
02353 **  succeeds then the offending data is NOT within that range.  Either way, if you
02354 **  continue the search long enough you will eventually find the bad item or items
02355 **  and be able to deal with them.
02356 **
02357 ** \image html TransferOutByView.jpg
02358 **
02359 ** Once the offending item has been identified, you will probably have to simply 
02360 **  delete it to clear the problem.  This means that you will have to manually 
02361 **  reenter the data associated with it to keep the item.  You will not likely
02362 **  be successful making a copy of the item and deleting the offender.  Somehow,
02363 **  when there is bad data on an item, making a copy of it also copies the bad
02364 **  data, and the problem remains.
02365 **
02366 */
02367 
02368 /*!
02369 ** \page categoryName Category Name
02370 **
02371 ** The Category Name represents the name of the category as defined in the Commence
02372 **  database.  This value is Read/Only as it pertains to the CDA and is determined
02373 **  by the actual name of the category in the Commence database.
02374 **
02375 ** When creating category names in the system, it is recommended that the names given
02376 **  to the categories be something reasonable, understandable, generally human readable,
02377 **  and as compatible with other foreign databases as possible.
02378 **
02379 **
02380 */
02381 
02382 /*!
02383 ** \page itemName Item Name Field
02384 **
02385 ** The Item Name represents the value of the 'Name' field in the category list of
02386 **  items.  The 'Name' field is always only able to contain 50 text characters of
02387 **  any printable character value.  The value in this field is usually what is used
02388 **  to distinguish one item from another.
02389 **
02390 */
02391 
02392 /*!
02393 ** \page itemClarify Item Clarify Field
02394 **
02395 ** The Item Clarify value represents a value that can be potentially used to distinguish
02396 **  items within the database.  This(generally) occurs on categories that allow
02397 **  duplicate items to be stored.  In cases such as this, the clarify field value
02398 **  can sometimes be used to distinguish one item from another.
02399 **
02400 ** \sa \ref clarifiedItemNames
02401 */
02402 
02403 /*!
02404 ** \page formName Form Name
02405 **
02406 ** Forms in Commence
02407 */
02408 
02409 /*!
02410 ** \page fieldName Field Name
02411 **
02412 ** Fields in Commence
02413 **
02414 */
02415 
02416 /*!
02417 ** \page connectionName Connection Name
02418 **
02419 ** Connection Names can be declared several ways.
02420 ** 
02421 */
02422 
02423 /*!
02424 ** \page thid Commence THID's
02425 **
02426 ** Open your Connectee Category, setting the Thid option.
02427 ** Const CMC_FLAG_USETHIDS = &H100
02428 ** 
02429 ** Filter for target Item(s)
02430 ** 
02431 ** Get Rowset
02432 ** 
02433 ** Open your target category also with the same flag set.
02434 ** 
02435 ** GetEditrowset or GetAddRowset as one does!
02436 ** 
02437 ** OutRs.ModifyRow 0,Column,InRS.GetRowID(x,0),0  'Where x is the row in InRs
02438 **
02439 **
02440 */
02441 
02442 /*!
02443 ** \page guid Commence GUID's
02444 **
02445 ** GUID's are numbers that are guaranteed to be unique in the world.
02446 **
02447 ** Commence does not natively support guid values.
02448 **
02449 */
02450 
02451 /*!
02452 ** \page ErrorReportingSystem Error Reporting System
02453 **
02454 ** The base object cmcObject supports error reporting on an object-by-object basis.  This
02455 **  means that every object can indicate within itself the error status of any operation.
02456 **  The error reporting system 
02457 **
02458 */
02459 
02460 /*!
02461 ** \page clarifiedItemNames Clarified Item Names
02462 **
02463 ** What is a clarified item name?
02464 **
02465 ** A Clarified Item Name refers to a method of identifying an item in a 
02466 **  category that allows for duplicate items.  Since categories have only
02467 **  one key field, and this key field is a text field of 50 characters, it
02468 **  is most common to set the value of this field to some value that 
02469 **  represents the "key" of the item.  This is fine for Company names or
02470 **  Class codes or Invoice numbers where duplications can be controlled, 
02471 **  but what about things like peoples names, where "Smith, John" and 
02472 **  "Smith, John" are likely to occur more than once in a large database?
02473 **
02474 ** Enter the: <b>"Clarified Item Name"</b>
02475 **
02476 ** If a category allows duplicates, that category can be assigned a
02477 **  clarify field.  The clarify field is another field in that category
02478 **  that can act like a clarification of an item.  For instance, say
02479 **  your "Person" category allows duplicates, and you have "Smith, John" 
02480 **  and "Smith, John" occurring in your database.  If you set another field
02481 **  as a clarify field and call this field "Nickname" then you would be
02482 **  able to distinguish one "Smith, John" from the other by setting one
02483 **  Nickname field value to "Smitty" and another to "Johnny".  When
02484 **  searching for this item, then, you could use a "Clarified Item Name"
02485 **  as part of your search.
02486 **
02487 ** What is a <b>Clarified Item Name</b>?
02488 **
02489 ** A Clarified Item name is an assembly of the category Name field and
02490 **  Clarify field and Clarify Separator.  The Clarify field is limited
02491 **  to 40 characters.  This does not mean that you can only use a 
02492 **  clarify field that is only 40 characters, rather Commence will only
02493 **  examine the first 40 characters of your clarify field.  Let's say 
02494 **  your category is laid out as follows:
02495 **
02496 ** \code
02497 ** Category      ~ "Person"
02498 ** Name Field    ~ "Full Name"
02499 ** Clarify Field ~ "Nickname"
02500 ** Clarify Sep   ~ " - "
02501 ** \endcode
02502 **
02503 ** If you are then looking for "Smith, John" with a nickname of "Smitty"
02504 **  you would then assemble a <b>"Clarified Item Name"</b> value as follows:
02505 **
02506 ** \code
02507 ** dim pd: pd = "                                                  " ' 50 spaces (not 50 paces)
02508 ** dim fn: fn  = "Smith, John" ' first name
02509 ** dim nn: nn  = "Smitty"      ' nick name
02510 ** dim sp: sp  = " - "         ' separator
02511 **
02512 ** dim cn:  cn = Left( fn & pd, 50 ) & sp & Left( nn, 40 )
02513 ** \endcode
02514 **
02515 ** Note that in the code above you have to pad the 'Name' field to exactly
02516 **  50 characters.  This tiny little tidbit of valuable information is
02517 **  not located anywhere in the documentation that I have come across as
02518 **  of yet.  If you're just now reading this document you're probably
02519 **  asking yourself why you just spent three days troubleshooting why
02520 **  using clarified item names doesn't work for you.  Beats me, but finally
02521 **  you're here.
02522 **
02523 ** In the code above I have also trimmed the clarify field to 40 characters.
02524 **  This is probably not necessary but I do it anyway.
02525 **
02526 ** If so desired you can set your clarify field to Memo fields (really long
02527 **  fields) and Commence will still only use the first 40 characters.  A good
02528 **  practice then is when you have a category that allows for duplicate items
02529 **  then create a special clarify field and fill it with a value that you are
02530 **  sure is not going to repeat.  Then regardless of what the 'Name' field
02531 **  value is, you'll always be guaranteed to be able to find (and connect to)
02532 **  the correct item.
02533 **
02534 ** So... therefore... if you were formatting a DDE request, using the
02535 **  DDE [AssignConnection()] command, you might format a string that looks
02536 **  something like the following:
02537 **
02538 ** \code
02539 ** dim pd:  pd   = "                                                  " ' 50 spaces (not 50 paces)
02540 ** dim fn:  fn   = "Smith, John" ' first name
02541 ** dim nn1: nn1  = "Smitty"      ' 1st nick name
02542 ** dim nn2: nn2  = "Johnny"      ' 2nd nick name
02543 ** dim sp: sp    = " - "         ' separator
02544 **
02545 ** dim cn1:  cn1 = Left( fn & pd, 50 ) & sp & Left( nn1, 40 )
02546 ** dim cn2:  cn2 = Left( fn & pd, 50 ) & sp & Left( nn2, 40 )
02547 **
02548 ** '
02549 ** ' build a connection string.  Note that the 'dq' command is a sub-routine
02550 ** '  that will double-quote a string.
02551 ** '
02552 ** dim conString
02553 **     conString = "[AssignConnection(Person," & dq(cn1) & ",Friends with,Person," & dq(cn2) & "]"
02554 **
02555 ** '
02556 ** ' Using Dumont, send the dde commands to assign the connection.  Make sure
02557 ** '  ClarifyItemNames is True before sending the assignment command.  Note
02558 ** '  that this call needs to only be made once per session (each time the
02559 ** '  .exe is run) so you might place the call is some seldom used chunk
02560 ** '  of code like in an application initialization routine, or at the top
02561 ** '  of your form or .vbs program so it doesn't get called repeatedly 
02562 ** '  unnecessarily.
02563 ** '
02564 ** dapp.cv.execute "[ClarifyItemNames(True)]"
02565 ** dapp.cv.execute conString
02566 **
02567 ** \endcode
02568 **
02569 ** Note, however, that none of this works if your category is not set up to 
02570 **  use clarified items.  In order to insure that it is you can change the 
02571 **  category properties and specify the field that you indend to use as a
02572 **  clarify field, and at the same time, choose a clarify separator as well:
02573 **
02574 ** \image html clarifiedItemNames.png
02575 **
02576 ** \note Something to remember about Dumont and the DDE channel... if you are
02577 **  using either the DumontDLL or the DumontEXE environment, note that Dumont
02578 **  will open a DDE channel back to Commence and keep it open throughout the
02579 **  life of the Commence.exe program (specifically the life of the dumont.dll
02580 **  or dumont.exe program, if you will).  This is done mostly for speed, since
02581 **  opening and closing DDE channels takes time.
02582 **
02583 ** \par
02584 ** In this environment, therefore, you would only need to specify 
02585 **  <b>[ClarifyItemNames(True)]</b> one time and it will, pretty much, stay enabled
02586 **  as long as the dumont.dll or dumont.exe stays loaded.  If you are \b not
02587 **  using the Dumont extension libraries in your project, and accessing Commence
02588 **  the usual ways, through the regular Commence API, then if you are, say,
02589 **  performing DDE functions inside a detail form, you would be opening a new
02590 **  DDE channel to Commence everytime that form opened newly.  In this environment
02591 **  you would have to execute <b>[ClarifyItemNames(True)]</b> each time your detail
02592 **  form opened, and a new DDE channel was opened.
02593 **
02594 ** \par
02595 ** If you are employing clarified item names, but you are forgetting to set
02596 **  <b>[ClarifyItemNames(True)]</b>, or if you are not attempting to employ clarified
02597 **  item names, but you have also not set <b>[ClarifyItemNames(False)]</b> then
02598 **  you will be in for some confusing days.
02599 **
02600 ** \par
02601 **  Because of the strangeness of this "feature" of Commence, it would probably be
02602 **  a good idea for you to do some serious expirimenting to see what kinds of 
02603 **  results are produced under what conditions, and then write your code accordingly.
02604 **
02605 ** \par
02606 ** 'nuff said!
02607 **
02608 */
02609 
02610 /*!
02611 ** \page dateKeyword The (-Date-) Keyword
02612 **
02613 ** The (-Date-) Keyword is one of those keywords that has changed in function over
02614 **  time within Commence.  In the early days, the (-Date-) keyword would yeild a 
02615 **  value that was easily used in agents when filling out field date values 
02616 **  automatically.  It was also especially handy when making sequential backups
02617 **  and you wanted the date-stamp in the back-up file name.  However, the 
02618 **  functionality changed and some of those features have been lost.
02619 **  Here is the official word from Commence Corp:
02620 **
02621 ** \par
02622 ** \code
02623 ** Summary: 
02624 **   The (-Date-) keyword has been enhanced to retrieve the Long 
02625 **    Date format from Control Panel Regional Settings Applies to: 
02626 **    Commence RM 3.5.1
02627 **
02628 ** More Information:
02629 **  In previous versions of the software, the (-Date-) keyword used to 
02630 **   return a Long Date string constructed by Commence in Month Day Year 
02631 **   format. In order to better support international users, the latest 
02632 **   version of Commence now respects the Long Date format set using the 
02633 **   Windows Control Panel under Regional Settings.
02634 **
02635 **  The (-Date-) keyword can be used in text letter templates and various 
02636 **   other areas of the product. It returns a value equivalent to today's 
02637 **   date in long format,.e.g. Friday, January 18, 2008. Whereever the short 
02638 **   date format of the current system date is expected, the natural language 
02639 **   date "today"  must be used.
02640 **
02641 **  The change has exposed some unintended uses of the Date keyword. The
02642 **   following agent examples illustrate some valid and invalid uses. 
02643 **
02644 ** Example 1: Date fields 
02645 **            Agents which automatically set Date fields to the 
02646 **            current date cannot use the (-Date-) keyword interchangeably 
02647 **            with "today". The (-Date-) keyword is no longer recommended 
02648 **            for use in Date fields. An example of the correct use of "today" 
02649 **            in agents can be found in the Tutorial Database. See the 
02650 **            agent named S.Account.Build.Add.Modify which sets the 
02651 **            addModifyDate to today's date.
02652 **
02653 ** Example 2: Number Fields 
02654 **            The (-Date-) keyword is not supported in Number fields whose 
02655 **            values are calculated via Agent using the @ functions. One example 
02656 **            of this is a calculation that determines the number of days between 
02657 **            two dates. A valid formula would be: 
02658 **                 @Date("(%estimatedCloseDate%)") - @Date(Today)
02659 **
02660 ** Example 3: Text Fields
02661 **            The (-Date-) keyword can continue to be used in Agents that 
02662 **            insert the current date into a Text field. For example, a date-time 
02663 **            stamp in the Notes field of an activity log.
02664 **
02665 ** Recommendations:
02666 **  The Long Date format can be changed from Windows Control Panel, Regional
02667 **   settings, to one of the following supported formats:
02668 **      MMMM dd, yyyy
02669 **      dd MMMM, yyyy
02670 **
02671 ** Any agents that currently insert the (-Date-) keyword into Date fields must be 
02672 **  updated to use "today" instead. After correcting the agent, be sure to check 
02673 **  your data to ensure no items have been added in the interim with blank Date fields. 
02674 **  Refer to "Technote 3309 - How to Filter on Blank Fields" on the commence.com website.
02675 **
02676 ** Database developers should also review their code for possible usage of the date 
02677 **  keyword which may be impacted by this change. This includes DDE, Database API, and 
02678 **  VBScripting.
02679 ** \endcode
02680 **
02681 **
02682 */
02683 
02684 /*!
02685 ** \page aliasNames Object Alias Names
02686 **
02687 ** The cda object system supports a feature called alias names.  This
02688 **  feature allows a separate unique name to be assigned to an object, and
02689 **  allows that object to be referred to by that alias name.
02690 **
02691 ** This feature is provided as a matter of convenience, but is rather handy 
02692 **  when referring to Application names Field names and Connection names.  
02693 **  Using the alias name mechanism, generic code can be written to access 
02694 **  fields and connections on a form within a category and the alias names 
02695 **  can be set to match the code - just like a mini field mapping tool.  
02696 **  Care should be taken to insure that the alias names do not collide with 
02697 **  existing names within the same name-list-context.  For instance, if there 
02698 **  is a list of field names, and some of those fields have alias names assigned 
02699 **  to them, then care must be taken that the alias names do not collide with 
02700 **  any other existing alias names, or any other regular field names.
02701 **
02702 ** Just like in a category you cannot have two fields with the same name, 
02703 **  also in a category you cannot have an alias field name that duplicates 
02704 **  either another field name, or another alias field name.  The cda
02705 **  insures that this will not happen.
02706 **
02707 ** The alias name feature is especially handy when acquiring a handle to the
02708 **  database via the dumont.ROT object.  Using the alias name, a .vbs script file
02709 **  can be developed that will always access the correct instance of the database
02710 **  regardless of what the database is actually called on that client installation.
02711 **
02712 ** \par vbScript Access to an Application via its alias name
02713 ** \code
02714 ** dim dexe: set dexe = createObject("Dumont.EXE") ' hook dumont
02715 ** dim dapp: set dapp = dexe.applications( "KES" ) ' get application by aliasName
02716 ** if( dapp.objectIsValid ) then
02717 **   dexe.debug "application name:  " & dapp.name
02718 **   dexe.debug "database name:     " & dapp.databaseName
02719 **   dexe.debug "database dir:      " & dapp.databaseDirectory
02720 **   dexe.debug "application alias: " & dapp.aliasName
02721 **   dexe.debug "----"
02722 ** end if
02723 ** 
02724 ** set dapp = dexe.applications( "KES.mwp" )       ' get application by name
02725 ** if( dapp.objectIsValid ) then
02726 **   dexe.debug "application name:  " & dapp.name
02727 **   dexe.debug "database name:     " & dapp.databaseName
02728 **   dexe.debug "database dir:      " & dapp.databaseDirectory
02729 **   dexe.debug "application alias: " & dapp.aliasName
02730 **   dexe.debug "----"
02731 ** end if
02732 ** \endcode
02733 **
02734 ** The code above will produce the following output:
02735 ** \image html cmcObjectAliasName.png
02736 **
02737 ** The \ref cmcObject::aliasName "aliasName" property is available on any object
02738 **  within the system and allows those objects, applications, forms, categories,
02739 **  fields and connections to be accessed by their generic alias names.
02740 **
02741 ** This makes it possible to write a truly generic piece of code that can access
02742 **  applications and categories and fields and by using the aliasName property of
02743 **  those object, map the generic names to the actual database object names.
02744 **  Especially as it relates to the Dumont running object table, a generic .vbs
02745 **  file can be distributed to all the client computers and regardless of what
02746 **  the database was named when it was connected to the workgroup, the script
02747 **  will be able to access it through the R.O.T. by its alias name.
02748 **
02749 */
02750 
02751 /*!
02752 ** \page viewName View Name
02753 **
02754 ** A view name...
02755 **
02756 */
02757 
02758 
02759 /*!
02760 ** \page viewFilter Filters Explained
02761 **
02762 ** The View Filter syntax is one of the most complicated strings you
02763 **  will have to assemble for a Commence query.  It is a single command
02764 **  that can represent many different filter configurations, and it is
02765 **  used both in the Cursor API calls as well as various DDE commands.
02766 **
02767 ** The following document is a cut-and-paste from the Commence help file
02768 **  and enhanced with comments and notes from the http://www.freedomcomputing.com
02769 **  newsgroup.
02770 **
02771 ** \par Syntax:
02772 ** \code
02773 ** [ViewFilter(ClauseNumber, FilterType, NotFlag, FilterTypeParameters)]
02774 ** \endcode
02775 **
02776 ** \par Clause Number
02777 ** ClauseNumber defines which filter clause is being defined, where ClauseNumber is 
02778 **  between 1 and 8.
02779 **
02780 ** \par Clause Number Example
02781 ** \code
02782 ** [ViewFilter(1,...
02783 ** [ViewFilter(2,...
02784 ** [ViewFilter(3,...
02785 ** [ViewFilter(4,...
02786 ** [ViewFilter(5,...
02787 ** [ViewFilter(6,...
02788 ** [ViewFilter(7,...
02789 ** [ViewFilter(8,...
02790 ** \endcode
02791 **
02792 ** \par Filter Type Example
02793 ** FilterType sets the type of the filter to apply. Possible types are:
02794 ** \code
02795 **  F     Field
02796 **  CTI   Connection To Item
02797 **  CTCTI Connection To Category To Item
02798 **  CTCF  Connection To Category Field
02799 **
02800 ** [ViewFilter(1,F,...
02801 ** [ViewFilter(1,CTI,...
02802 ** [ViewFilter(1,CTCTI,...
02803 ** [ViewFilter(1,CTCF,...
02804 ** \endcode
02805 **
02806 ** \par Not Flag
02807 ** NotFlag determines if a logical Not is applied against the entire clause.  
02808 **  The NotFlag parameter must be specified; it may be either Not or left 
02809 **  blank (by specifying the comma placeholder for that parameter).  This 
02810 **  is equivalent to the "Except" checkbox found in the Commence filter 
02811 **  dialog boxes.
02812 **
02813 ** \par Not Flag Example
02814 ** \code
02815 ** [ViewFilter(1,F,,...
02816 ** [ViewFilter(1,F,Not,...
02817 ** \endcode
02818 **
02819 **
02820 ** \par FilterTypeParameters
02821 ** The FilterTypeParameters specified with this REQUEST and the ViewConjunction 
02822 **  REQUEST are similar to those available from the Commence main menu.  This
02823 **  is probably the most complicated (and most often improperly expressed) 
02824 **  component of the filter request.  It is best explained by example.
02825 ** 
02826 ** \par
02827 ** The FilterType determines what additional parameters must follow the NotFlag 
02828 **  field.  The parameters are summarized in the following table:
02829 **
02830 ** \par
02831 ** \code 
02832 ** FilterType  Filter Type Parameters
02833 ** F           FieldName, Qualifier, Value, CSFlag
02834 ** CTI         ConnectionName, ConnectedCategory, ItemName
02835 ** CTITI       ConnectionName1, ConnectedCategory1, ConnectionName2, ConnectedCategory2, ItemName
02836 ** CTCF        ConnectionName, ConnectedCategory, FieldName, Qualifier, Value, CSFlag
02837 ** \endcode
02838 **
02839 ** \par Filtering by a Field
02840 ** FieldName defines the field to be filtered. The Qualifier depends on the field type.
02841 **  Value specifies the value to compare the field against. CSFlag determines if 
02842 **  the comparison is case-sensitive or not. CSFlag is only necessary for textual 
02843 **  comparisons.  Values of \c "1", \c "yes", or \c "true" will force a case-sensitive 
02844 **  comparison, while \c "0", \c "no", or \c "false" will force a case-insensitive comparison.
02845 **
02846 ** \note The Value and CSFlag fields are not relevant for certain field qualifications.  
02847 **        For "Is Blank" filtering and for Check Box fields, the Value and CSFlag 
02848 **        fields can be left blank or omitted.  When filtering for a range of 
02849 **        values, the Value and CSFlag fields are replaced by Min Value and Max 
02850 **        Value.  Range filtering always does an inclusive comparison with the 
02851 **        specified minimum and maximum values.
02852 **
02853 ** \par Clearing a Filter
02854 ** The ViewFilter REQUEST can clear a filter.  To do so, specify the filter to be 
02855 **  cleared (1, 2, 3, 4, 5, 6, 7, 8) and include the word CLEAR.  For example, issuing 
02856 ** \c "[ViewFilter(1,Clear)]" will clear filter 1.
02857 **
02858 ** \par Filtering by Shared vs. Local status
02859 ** The ViewFilter REQUEST can filter for shared or local items.  To do so, see Filtering 
02860 **  by a Field above.  Specify either "Shared" or "Local" for the Qualifier.  Leave 
02861 **  the FieldName, Value, and CSFlag parameters empty).  For example,
02862 **
02863 ** \par
02864 ** \code
02865 ** [ViewFilter(1, F, , , Shared, , )]
02866 ** [ViewFilter(2, CTCF, , Is Employed by, Company, , Local)]
02867 ** \endcode
02868 **
02869 ** \par Filtering by a Connection
02870 ** The ConnectionName, ConnectedCategory parameter pair defines the connection from 
02871 **  the previously selected (base) category to a different Commence category. ItemName 
02872 **  is the name of the item in the connected category.
02873 **
02874 ** \par Filter Examples
02875 ** \code
02876 ** [ViewFilter(1,F,,Last Name, Equal to, "Frost")]
02877 **
02878 ** [ViewFilter(1,F,,Address,Contains,NJ,yes)]
02879 ** 
02880 ** [ViewFilter(2,CTI,,Is Employed by,Company,"Great Homes Inc.")]
02881 ** 
02882 ** [ViewFilter(3,CTCTI,,Is Employed by,Company,"Associated with","Project","Storage Wizard")]
02883 ** 
02884 ** [ViewFilter(4,CTCF, ,Is Employed by,Company,"City","Contains","Seattle","yes")]
02885 ** 
02886 ** [ViewFilter(1,CTCF,Not,Billing Attorney,Employee,employeeKey,Does Not Contain,""(none)"")]
02887 ** Note that (none) must be enclosed in quotes
02888 ** 
02889 ** Request: [ViewFilter(1, F,, Title, Doesn't Contain, ?,)]
02890 ** Filter for all items with a blank Title field.
02891 ** 
02892 ** Request: [ViewFilter(1, F, Not, Title, Contains, ?,)]
02893 ** Equivalent to previous example.
02894 ** 
02895 ** Request: [ViewFilter(1, F,, Title, Blank)]
02896 ** Equivalent to previous example.
02897 ** 
02898 ** Request: [ViewFilter(1, CTI,, Is Employed by, Company, "Appliance Distributors Inc")]
02899 ** Filter for all people employed by Appliance Distributors Inc.
02900 ** 
02901 ** Request: [ViewFilter(1, CTCF,, Is Employed by, Company, State, Contains, NJ, yes)]
02902 ** Filter for all people employed by Companies in the state of New Jersey 
02903 **  (State contains the case-sensitive text "NJ")
02904 ** 
02905 ** Request: [ViewFilter(1, CTCTI,, Attends, Appointment, Relates to, Project, Space Layouts)]
02906 ** Filter for all people attending any appointment concerning the Space Layouts project.
02907 ** 
02908 ** Request: [ViewFilter(1, CTCF,, Attends, Appointment, Date, Between, 1/1/95, today)]
02909 ** Filter for all people attending appointments from January 1, 1995 to today.
02910 **
02911 ** Request: [ViewFilter(2,Clear)]
02912 ** Remove a previous filter request.
02913 ** \endcode
02914 **
02915 ** \par See Also:
02916 ** \ref faqFilterOnNone
02917 */
02918 
02919 /*!
02920 ** \page cdaReady CDA Readyness
02921 **
02922 ** The status of 'cdaReady' represents a status of a database that has been properly
02923 **  set up for Dumont/CDA extensions.  This means that this is an application that
02924 **  contains a category entitled, exactly, "~cda".  This tilde is set in front of
02925 **  the category name to distinguish it from other category names - to distinguish
02926 **  it as a special system category.  The three letters "cda" mean, obviously, 
02927 **  cmcDatabaseApi.  
02928 **
02929 ** When this category exists, there must be, secondly, a detail form called, exactly
02930 **  "~cda".  What this form is for is storage of the Dumont/CDA extensions.
02931 **
02932 ** The Dumont/CDA extensions are exported to an xml file on save.  The xml file is 
02933 **  then compressed into an Ascii MIME format.  Using the 
02934 **  \ref cmcConversation::checkInFormScript "Check-in Form Script" procedure, this
02935 **  extended definition compressed encoded xml file is checked-in to the special
02936 **  ~cda detail form.  The detail form script region is, therefore, used as the
02937 **  transport for this definition file.  As clients start up around the workgroup
02938 **  they receive this updated detail form, extract the xml content from form and use
02939 **  it within their copy of the application.
02940 **
02941 */
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties




~ ~ ~ ~ ~ ~
Source Code without Comments is like a Cranberry Garland
without the berries. Comment your Code!
 
Commence Database User Support Group Forum
http://newsgroup.showoff-db.org/
~ ~ ~ ~ ~ ~
Author: Mark Petryk
Lorimark Solutions, LLC
mark@lorimarksolutions.com