home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / macfe / utility / URobustCreateWindow.cp < prev    next >
Encoding:
Text File  |  1998-04-08  |  8.4 KB  |  266 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. /*======================================================================================
  20.     AUTHOR:            Ted Morris <tmorris@netscape.com> - 12 DEC 96
  21.  
  22.     MODIFICATIONS:
  23.  
  24.     Date            Person            Description
  25.     ----            ------            -----------
  26. ======================================================================================*/
  27.  
  28.  
  29. /*====================================================================================*/
  30.     #pragma mark INCLUDE FILES
  31. /*====================================================================================*/
  32.  
  33. #include "URobustCreateWindow.h"
  34.  
  35. #include <LWindow.h>
  36. #include <LCommander.h>
  37. #include <LControl.h>
  38. #include <LDataStream.h>
  39. #include <LString.h>
  40. #include <UMemoryMgr.h>
  41.  
  42. #include "fredmem.h"
  43.  
  44. // Necessary stuff from <UReanimator.cp>
  45.  
  46. typedef    Int32    TagID;
  47.  
  48. enum {
  49.     tag_ObjectData        = 'objd',
  50.     tag_BeginSubs        = 'begs',
  51.     tag_EndSubs            = 'ends',
  52.     tag_Include            = 'incl',
  53.     tag_UserObject        = 'user',
  54.     tag_ClassAlias        = 'dopl',
  55.     tag_Comment            = 'comm',
  56.     tag_End                = 'end.',
  57.     
  58.     object_Null            = 'null'
  59. };
  60.  
  61. #pragma options align=mac68k
  62.  
  63. typedef struct {
  64.     Int16    numberOfItems;
  65.     PaneIDT    itemID[1];
  66. } SResList, *SResListP;
  67.  
  68. #pragma options align=reset
  69.  
  70.  
  71. #pragma mark -
  72. /*====================================================================================*/
  73.     #pragma mark CLASS IMPLEMENTATIONS
  74. /*====================================================================================*/
  75.  
  76. #pragma mark -
  77. /*======================================================================================
  78.     Return a newly created Window object initialized from a PPob resource. Raise an
  79.     exception if the window cannot be created. If no exception is raised, this method
  80.     will ALWAYS return a valid LWindow object.
  81. ======================================================================================*/
  82.  
  83. LWindow *URobustCreateWindow::CreateWindow(ResIDT inWindowID, LCommander *inSuperCommander)
  84. {
  85.     ThrowIf_(Memory_MemoryIsLow());
  86.     LCommander::SetDefaultCommander(inSuperCommander);
  87.     LAttachable::SetDefaultAttachable(nil);
  88.     LWindow    *theWindow = nil;
  89.     OSErr error = noErr;
  90.  
  91.     URobustCreateWindow::ReadObjects('PPob', inWindowID, &theWindow, &error);    
  92.     ThrowIfOSErr_(error);        // theWindow not valid yet, don't bother trying to delete it.
  93.     
  94.     theWindow->FinishCreate();
  95.     if ( theWindow->HasAttribute(windAttr_ShowNew) )
  96.         theWindow->Show();
  97.  
  98.     return theWindow;
  99. }
  100.  
  101.  
  102. /*======================================================================================
  103.     Much more robust object creation. Create new objects from the data resource. 
  104.     Return a pointer to the first object created, or nil if no objects were created.
  105.     If a non-nil value is returned, check the outErr value to see if the object
  106.     is valid (i.e. no exceptions were thrown during creation); if outErr returns something
  107.     other than noErr, the object is invalid (which means don't try to delete it).
  108. ======================================================================================*/
  109.  
  110. void URobustCreateWindow::ReadObjects(OSType inResType, ResIDT inResID, void **outFirstObject, 
  111.                                       OSErr *outErr) {
  112.  
  113.     *outFirstObject = nil;
  114.     *outErr = noErr;
  115.     
  116.     Try_ {
  117.         StResource objectRes(inResType, inResID);
  118.         ::HLockHi(objectRes.mResourceH);
  119.         
  120.         LDataStream objectStream(*objectRes.mResourceH, ::GetHandleSize(objectRes.mResourceH));
  121.                                         
  122.         Int16 ppobVersion;
  123.         objectStream.ReadData(&ppobVersion, sizeof(Int16));
  124.         
  125.         ThrowIf_(ppobVersion != 2);
  126.                                         
  127.         URobustCreateWindow::ObjectsFromStream(&objectStream, outFirstObject);
  128.     }
  129.     Catch_(inErr) {
  130.         *outErr = inErr;
  131.         // No throw, catch the exception and return error
  132.     }
  133.     EndCatch_
  134. }
  135.  
  136.  
  137. /*======================================================================================
  138.     Same as the UReanimator::ObjectsFromStream(), but returns the first object, if it 
  139.     is created.
  140. ======================================================================================*/
  141.  
  142. void *URobustCreateWindow::ObjectsFromStream(LStream *inStream, void **outFirstObject) {
  143.  
  144.     void        *firstObject = nil;
  145.     ClassIDT    aliasClassID = 'null';
  146.     
  147.                                 // Save current defaults
  148.     LCommander    *defaultCommander = LCommander::GetDefaultCommander();
  149.     LView        *defaultView = LPane::GetDefaultView();
  150.     
  151.     Boolean        readingTags = true;
  152.     do {
  153.         void    *currentObject = nil;    // Object created by current tag
  154.         TagID    theTag = tag_End;
  155.         inStream->ReadData(&theTag, sizeof(TagID));
  156.         
  157.         switch (theTag) {
  158.         
  159.             case tag_ObjectData: {
  160.                     // Restore default Commander and View
  161.                 LCommander::SetDefaultCommander(defaultCommander);
  162.                 LPane::SetDefaultView(defaultView);
  163.                 
  164.                     // Object data consists of a byte length, class ID,
  165.                     // and then the data for the object. We use the
  166.                     // byte length to manually set the stream marker
  167.                     // after creating the object just in case the
  168.                     // object constructor doesn't read all the data.
  169.                     
  170.                 Int32        dataLength;
  171.                 inStream->ReadData(&dataLength, sizeof(Int32));
  172.                 Int32        dataStart = inStream->GetMarker();
  173.                 ClassIDT    classID;
  174.                 inStream->ReadData(&classID, sizeof(ClassIDT));
  175.                 
  176.                 if (aliasClassID != 'null') {
  177.                         // The previous tag specified an Alias for
  178.                         // the ID of this Class
  179.                     classID = aliasClassID;
  180.                 }
  181.                 
  182.                 currentObject = URegistrar::CreateObject(classID, inStream);
  183.                 inStream->SetMarker(dataStart + dataLength, streamFrom_Start);
  184.                 
  185.                 aliasClassID = 'null';    // Alias is no longer in effect
  186.  
  187.                 #ifdef Debug_Signal                
  188.                     if (currentObject == nil  &&  classID != 'null') {
  189.                         LStr255    msg("\pUnregistered ClassID: ");
  190.                         msg.Append(&classID, sizeof(classID));
  191.                         SignalPStr_(msg);
  192.                     }
  193.                 #endif
  194.                 break;
  195.             }
  196.                 
  197.             case tag_BeginSubs:
  198.                 currentObject = URobustCreateWindow::ObjectsFromStream(inStream, outFirstObject);
  199.                 break;
  200.                 
  201.             case tag_EndSubs:
  202.             case tag_End:
  203.                 readingTags = false;
  204.                 break;
  205.                 
  206.             case tag_UserObject: {
  207.             
  208.                     // The UserObject tag is only needed for the Constructor
  209.                     // view editing program. It tells Constructor to treat
  210.                     // the following object as if it were an object of the
  211.                     // specified superclass (which must be a PowerPlant
  212.                     // class that Constructor knows about). We don't need
  213.                     // this information here, so we just read and ignore
  214.                     // the superclass ID.
  215.                     
  216.                 ClassIDT    superClassID;
  217.                 inStream->ReadData(&superClassID, sizeof(ClassIDT));
  218.                 break;
  219.             }
  220.                 
  221.             case tag_ClassAlias:
  222.             
  223.                     // The ClassAlias tag defines the ClassID the for
  224.                     // the next object in the Stream. This allows you
  225.                     // to define an object which belongs to a subclass
  226.                     // of another class, but has the same data as that
  227.                     // other class.
  228.                     
  229.                 inStream->ReadData(&aliasClassID, sizeof(ClassIDT));
  230.                 break;
  231.                 
  232.             case tag_Comment: {
  233.             
  234.                     // The Comment tag denotes data used by PPob editors
  235.                     // that PowerPlant ignores. Format is a long word
  236.                     // byte count followed by arbitrary hex data.
  237.                 
  238.                 Int32    commentLength;
  239.                 inStream->ReadData(&commentLength, sizeof(commentLength));
  240.                 inStream->SetMarker(commentLength, streamFrom_Marker);
  241.                 break;
  242.             }
  243.                 
  244.             default:
  245.                 SignalPStr_("\pUnrecognized Tag");
  246.                 readingTags = false;
  247.                 break;
  248.         }
  249.             
  250.         if (firstObject == nil) {
  251.             firstObject = currentObject;
  252.             if ( *outFirstObject == nil ) {    // This if statement if the only modified code in 
  253.                                             // this method from the UReanimator::ObjectsFromStream() 
  254.                                             // method.
  255.                 *outFirstObject = firstObject;    // Store the first created object in case an 
  256.                                                 // exception is thrown
  257.             }
  258.         }
  259.             
  260.     } while (readingTags);
  261.     
  262.     return firstObject;
  263. }
  264.  
  265.  
  266.