Work Place Shell Programming - Part 4

Written by Chris Palchak

Overview
In this, the fourth article in this series, the ChartFolder class will be created. This class inherits from WPFolder and is used to hold ChartFile objects.

The SOM IDL for ChartFolder
The contents of ChFoldr.idl are listed below. For a description of the WPS functions that are overridden by ChartFolder, refer to the first article in this series. The only function that ChartFolder overrides that ChartFile doesn't override is wpclsQueryIconN. This function is the same as wpclsQueryIcon except that it returns the handle of the animated icon. (This is the icon that is displayed when the folder is open.)

The main difference between this class and the ChartFile class is that users of this class want to process the ChartFile objects contained by this ChartFolder object and not the ChartFolder object itself. This means that the user must be able to determine the drive and path of this folder and process its contents. The user must also be able to determine the types of the objects in a ChartFolder.

Note also that data member, pCommandProcessor, in the listing for ChFoldr.idl is declared as an unsigned long. This variable holds a pointer returned by "new CommandProcessor". Pointers to any type of object can be stored in unsigned long variables and typecast as needed.

In order to keep the length of this article reasonably short, only functions that are notably different from ChFile functions will be discussed.

ChFoldr.idl listing
#ifndef CHFOLDR_IDL #define CHFOLDR_IDL #include  interface M_ChartFolder; interface ChartFolder : WPFolder {     #ifdef __SOMIDL__ // Access methods for ChartFolder's data members float getLowPriceCutoff; float getLowPriceChangePct; float getRegPriceChangePct; short getStartDD; short getStartMM; short getStartYYYY; short getEndDD; short getEndMM; short getEndYYYY; string getErrorFolder; void  setLowPriceCutoff(in float LowPrice); void  setLowPriceChangePct(in float LowPricePct); void  setRegPriceChangePct(in float RegPricePct); void  setStartDD(in short dd); void  setStartMM(in short mm); void  setStartYYYY(in short yyyy); void  setEndDD(in short dd); void  setEndMM(in short mm); void  setEndYYYY(in short yyyy); void  setErrorFolder(in string ErrorFolder); //--     // This method that reallocates memory for ChartFile's      // strings is necessary because string is defined as      // "char *" in \ibmcpp\include\som\somcorba.h.      //-- string reallocateString(in string oldString,                                in string newValue); implementation {            externalstem = ChFolder; local; externalprefix = ChFolderX_; majorversion = 1; minorversion = 1; filestem = ChFoldr; metaclass = M_ChartFolder; //-      // Class method (function) overrides //-         // add my settings pages wpAddSettingsPages: override; // restore state when object is awaken wpRestoreState:    override; // save state during shut down or idle times wpSaveState:       override; // called when object is opened wpOpen:            override; // allocate memory for this object wpInitData:        override; // free allocated memory wpUnInitData:      override; // add my items to the pop-up menu wpModifyPopupMenu: override; // process user selection of my menu items wpMenuItemSelected: override; //-      // Instance data (Exists separately for each       // ChartFolder object). These are NOT declared with the // SOM IDL "attribute" statement so that the get // and set functions can be named manually. //-        // price changes that indicate an error or split float lowPriceCutoff; float lowPriceChangePct; float regPriceChangePct; // first date to check short startDD; short startMM; short startYYYY; // last date to check short endDD; short endMM; short endYYYY; // for future use string errorFolder; //-      // Passthru Statements: // These statements are passed without change to the // generated "chfoldr.xih" and "chfoldr.xh" files. //-      // These statements get written to ChFoldr.xih. // ChFoldr.xih is included in ChFoldr.cpp. passthru C_xih_before = "" " /* PM and OS2 include directives */" "  #define INCL_WINWORKPLACE" "  #define INCL_WIN" "  #define INCL_DOS" "  #include " ""         " /* WPS include directives */" "  #define INCL_WPCLASS" "  #define INCL_WPFOLDER" "  #include " ""         " /* C include directives */" "  #include "; // These statements get written to ChFoldr.xh. // ChFoldr.xh is included in C++ programs that // reference ChartFolder objects. passthru C_xh_before = "" " /* PM and OS2 include directives */" "  #define INCL_WINWORKPLACE" "  #define INCL_WIN" "  #define INCL_DOS" "  #include " ""         " /* WPS include directives */" "  #define INCL_WPCLASS" "  #define INCL_WPFOLDER" "  #include " ""         " /* C include directives */" "  #include "; };     #endif };  //-   // Metaclass section: // --  // Describe the metaclass of ChartFolder. The Meta Class // defines data that is common (global) to all ChartFolder // objects. It also defines functions that operate on Meta // Class Data. //-  interface M_ChartFolder // Comment for parent WPFolder: {    //     // New class methods //        unsigned long queryCommandProcessor; //    // implementation //  #ifdef __SOMIDL__ implementation {      // Class Modifiers externalstem = ChFolder; local; externalprefix = ChFolderX_; functionprefix = ChFolderC_; majorversion = 1; minorversion = 1; filestem = ChFoldr; // non-instance (global) data unsigned long hChartFolderIcon; unsigned long hChartFolderOpenIcon; unsigned long pCmdProc; // Class method overrides wpclsInitData:        override; wpclsUnInitData:      override; wpclsQueryIcon:       override; wpclsQueryIconN:      override; };  #endif /* __SOMIDL__ */ };  #endif   /* CHFOLDR_IDL */

Compiling ChFolder.idl
This file can be compiled with the following command: sc.exe -s"xc;xh;xih;def" -S128000 chfoldr.idl. The output from this command will be the C++ stub file, ChFoldr.cpp.

Completing ChFoldr.cpp
//--- Completing wpclsInitData - //  // In this function a new CommandProcessor object is   // created. This is a custom class that processes commands // (via DosStartSession) and captures the command's output. // Any C++ object could be created here with "new." This // object is created in a MetaClass function because only // one CommandProcessor object is needed, regardless of how // many ChartFolder objects exist. The same is true for the // icon handles. //--  SOM_Scope void  SOMLINK ChFolderX_wpclsInitData(M_ChartFolder *somSelf) {      M_ChartFolderData *somThis = M_ChartFolderGetData(somSelf); M_ChartFolderMethodDebug("M_ChartFolder",                               "ChFolderX_wpclsInitData"); IDynamicLinkLibrary dll("chfoldr"); // load regular icon handle somThis->hChartFolderIcon = dll.loadIcon(WPICONID_CHFOLDR, false); // load the animated icon handle somThis->hChartFolderOpenIcon = dll.loadIcon(WPICONID_CHFOLDR_OPEN, false); // instantiate the command processor try { CommandProcessor *p = new CommandProcessor; somThis->pCmdProc = (unsigned long)p; }      catch(IException& e)           { IMessageBox msgBox(IWindow::desktopWindow); msgBox.setTitle(                         "ChFolderX_wpclsInitData Exception"); msgBox.show(e); }      M_ChartFolder_parent_M_WPFolder_wpclsInitData(somSelf); }  //-- Completing wpclsUnInitData //  // In this function the CommandProcessor object created in   // wpclsInitData is deleted. Recall that the pointer to the // CommandProcessor object is stored as an unsigned long. //--  SOM_Scope void  SOMLINK ChFolderX_wpclsUnInitData(M_ChartFolder *somSelf) {      M_ChartFolderData *somThis = M_ChartFolderGetData(somSelf); M_ChartFolderMethodDebug("M_ChartFolder",                               "ChFolderX_wpclsUnInitData"); // delete the command processor created in wpclsInitData CommandProcessor *p = (CommandProcessor *)somThis->pCmdProc; delete p;      M_ChartFolder_parent_M_WPFolder_wpclsUnInitData(somSelf); }

Processing the Contents of a ChartFolder
One of the items added to the pop-up menu for this class is "Update Quotes." This function FTPs a file containing a day's stock quotes (from Micro Data) and checks each ChartFile object within the ChartFolder to determine whether or not the ChartFile needs to be updated. The class that performs this function is called MicroData and is constructed from a pointer to the ChartFolder whose pop-up menu was used to begin the process.

Please Note: It is not the intent of this writer to provide full listings of working programs in this article. The purpose of this article is to show the reader how to write C++ code that references WPS objects. //-- MicroData::MicroData -- //  // Note that the class dll includes the resources for this // frame window. //--  MicroData::MicroData(ChartFolder *PChartFolder) : IFrameWindow(IResourceId(WND_MICRODATA, IDynamicLinkLibrary("chfoldr")),                          IFrameWindow::defaultStyle |                           IFrameWindow::menuBar        |                           IFrameWindow::minimizedIcon) , menuBar(IResourceId(WND_MICRODATA, IDynamicLinkLibrary("chfoldr")),this) , myTitle(this) , pChartFolder(PChartFolder) , appName("MICRODATA") , pOpenDialog(0) , pQuoteSeq(0) {   // First, get the required SOM Environment pointer pSomEnv = somGetGlobalEnvironment; // Now, get the pointer to the Meta Class, then // use the pointer to the Meta Class to get the pointer // to the global command processor object. M_ChartFolder *pMetaClass = pChartFolder->somGetClass; pCmdProc = (CommandProcessor *) (pMetaClass->queryCommandProcessor(pSomEnv)); // IString baseTitle is a member of this class //   // Use the wpQueryTitle function to get the name of the // folder being updated //   // Change the title bar to include the name of the folder baseTitle = "Update quotes in "; baseTitle += pChartFolder->wpQueryTitle; myTitle.setText(baseTitle); ... // non WPS code is excluded to shorten this article return; }  //---MicroData::processSelectedFile- //  // This function is executed after a file is downloaded, or   // the user selects a previously downloaded file. Only part // of this function will be included here to show how the // next function, updateStocksInFolder, is started. //--  void MicroData::processSelectedFile {      ...       char szFilename[CCHMAXPATH]; unsigned long ulLength = sizeof(szFilename); // Call wpQueryRealName with the third argument set to   // true to get the fully qualified name of this folder. // What we really need here is the name of the underlying // directory. pChartFolder->wpQueryRealName(szFilename,                                    &ulLength, true); IString sChartPath = szFilename; // Now, update all the ChartFile objects in this directory updateStocksInFolder(sChartPath); ...      return; }  //---MicroData::updateStocksInFolder //  // In this function, each object in the folder is checked // for type. If the object is a ChartFile, the ChartFile // is checked to see if it needs to be updated. //--  void MicroData::updateStocksInFolder(IString& ChartPath) {      IString    qSymbol, qTitle, inStr, tStr, tName, qExchange; float     qHigh, qLow, qClose; long      qVolume; Date      qDate, sDate; int       mm, dd, yyyy; QuotePtr  pQuote; IString   fileName; IString   sChartPath = ChartPath; ChartFile     *pChart      = 0; ChartFolder   *pNextFolder = 0; // Get a pointer to the WPFileSystem Meta Class. This is   // used below to get a WPS object pointer from a fully // qualified file name. M_WPFileSystem *pClass = pChartFolder->somGetClass; // FileDirectory is a custom class that uses DosFindFirst // and DosFindNext to retrieve the files in a given // directory. FileDirectory chartDirectory(sChartPath); fileName = chartDirectory.getNext; while (fileName.length > 0) {          // If a subdirectory is found, call this function // (recursively) to process the subdirectory. // Then continue processing. if (chartDirectory.foundSubdirectory) {                IString nextPath(sChartPath + "\\" + fileName); updateStocksInFolder(nextPath); }            else {             // Build a fully qualified file name and use it              // to get a generic WPS Object pointer. IString tFile(sChartPath + "\\" + fileName); WPObject *pObj = pClass->wpclsQueryObjectFromPath(tFile); // Now, see if the object is a ChartFile object. // If it is, see if it needs to be updated. // Otherwise, go on to the next file in this // directory. tName = pObj->somGetClassName; if (tName == "ChartFile") {                // This conversion is safe because we know // this is a ChartFile object. pChart = (ChartFile *)pObj; // Two files are downloaded. One with Stock // quotes and one with Index Quotes. //                // When processing a file with Index quotes, // use the ChartFile member function, // getExchange, to make sure the ChartFile // represents an Index. if (selectedIndexFile) {                        qExchange = pChart->getExchange(pSomEnv); if (qExchange == "INDEX") ;                        else {                            fileName = chartDirectory.getNext; continue; }                       }                 // All functions prefixed with pChart-> are // ChartFile member functions. Refer to the // first article in this series for more // information on these functions. qSymbol = pChart->getStockSymbol(pSomEnv); qTitle = pChart->wpQueryTitle; try { // pQuoteSeq is a pointer to a custom // class derived from IKeyedSortedSet. pQuote = pQuoteSeq->elementWithKey(qSymbol); qDate = pQuote->getQuoteDate; // Date is a custom date class // Compare the ChartFile's date to the // quote's date to see if the ChartFile // needs to be updated. Date sDate(pChart->getLastMM(pSomEnv),                                pChart->getLastDD(pSomEnv),                                 pChart->getLastYYYY(pSomEnv)); if (sDate < qDate) {                             tStr = IString("Updating: ") + qTitle; pStatusLine->setText(tStr); qHigh  = pQuote->getHigh; qLow   = pQuote->getLow; qClose = pQuote->getClose; qVolume = pQuote->getVolume; // QuoteRec and QuoteFile are also // custom classes. The previous // article in this series covers // the QuoteFile class as it relates // to the WPS. QuoteRec qr(qDate.getLong,                                         qVolume,                                          qHigh, qLow, qClose); QuoteFile qf(pChart,ios::out |                                                 ios::app |                                                  ios::binary); qf << qr; pChart->setLastDD(pSomEnv,                                               qDate.getDD); pChart->setLastMM(pSomEnv,                                               qDate.getMM); pChart->setLastYYYY(pSomEnv,                                             qDate.getYYYY); // pChart->setLastPrice; symbolsUpdated++; }                         else {                             tStr = IString("Skipping: ") + qTitle; pStatusLine->setText(tStr); }                        }                     catch (IException& e)                         { tStr = IString("Skipping: ") + qTitle; pStatusLine->setText(tStr); }                   }                 else     //  tName != "ChartFile" ;               }         //  end if file (not directory) fileName = chartDirectory.getNext; }  // end while return; }