Work Place Shell Programming - Part 4

From EDM2
Jump to: navigation, search
Work Place Shell Programming
Part: 1 / 2 / 3 / 4

Written by Chris Palchak

The ChartFolder Class

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 <wpfolder.idl>
 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 <os2.h>"
        ""
        " /* WPS include directives */"
        "   #define INCL_WPCLASS"
        "   #define INCL_WPFOLDER"
        "   #include <pmwp.h>"
        ""
        " /* C include directives */"
        "   #include <stdio.h>";
 
     // 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 <os2.h>"
        ""
        " /* WPS include directives */"
        "   #define INCL_WPCLASS"
        "   #define INCL_WPFOLDER"
        "   #include <pmwp.h>"
        ""
        " /* C include directives */"
        "   #include <stdio.h>";
       };
 
    #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;
 }