Legacy Documentclose button

Important: The information in this document is obsolete and should not be used for new development.

Previous Book Contents Book Index Next

Inside Macintosh: Cyberdog Programmer's Kit / Part 1 - Basics
Chapter 2 - Development Overview


Cyberdog Item Opening Process

This section discusses the opening process of a Cyberdog item and how various Cyberdog objects play a role in that process. It begins with a description of how Cyberdog items are manipulated and stored. Then it discusses the opening process, including a description of the roles played by the Cyberdog item, Cyberdog display part, opener part, navigator, and download part. Finally, it describes various scenarios for implementing a Cyberdog item's Open method and a Cyberdog display part's OpenCyberItem method.

Manipulating and Storing Cyberdog Items

In order to understand the opening process of a Cyberdog item, it is useful to first understand the different ways in which a Cyberdog item is represented and how those representations are manipulated and stored.

When displayed as an icon in a window, such as the log, a notebook, or a web page, a Cyberdog item is an object in memory; it is not an OpenDoc part. A user can open a Cyberdog item that is in memory by clicking on its icon. This action results in a call to the Cyberdog item's Open method.

Cyberdog items implement their opening behavior; in other words, they know how to open themselves. In the simplest cases, Open creates a Cyberdog display part and calls its OpenCyberItem method. OpenCyberItem initiates a download of the data referenced by the Cyberdog item and displays the display part. For more information on the objects involved in the opening process, see "Object Roles in the Opening Process" (page 72).

When the user drags a Cyberdog item object (from a notebook, for example), the Cyberdog item is stored in the storage unit of the OpenDoc drag-and-drop object as kind kCyberItemKind. The destination of the drop determines what happens.

Copying and pasting of Cyberdog items are handled in a similar fashion.

Object Roles in the Opening Process

"A Cyberdog Example" (page 66) shows how to open a Cyberdog item that references content stored on a Gopher server. Because that Cyberdog item references text, it creates a Cyberdog text display part. The text display part downloads the data and displays it. That example represents the simplest case of opening a Cyberdog item: the Cyberdog item knows the type of the data it references and the text display part opens itself immediately.

The primary responsibility for opening a Cyberdog item is shared between the Cyberdog item being opened (the Cyberdog item's Open method) and the display part that will display the data referenced by the Cyberdog item (the display part's OpenCyberItem method). However, opening a Cyberdog item is more complex in these situations:

The Cyberdog item and the Cyberdog display part may rely on other objects, such as an opener part, a navigator, or a download part, in these more complex opening scenarios.

Role of the Cyberdog Item

A Cyberdog item's Open method is responsible for the following:

Some Cyberdog items (Gopher items, for example) are resolved inherently; they always refer to a single, known type of data. If you are developing a Cyberdog item that is resolved inherently, your Cyberdog item's Open method can be synchronous.

Some other Cyberdog items (HTTP items, for example) cannot be resolved without communicating with the server on which the data they reference resides. If you are developing a Cyberdog item that is not resolved inherently, your Cyberdog item's Open method must be asynchronous.

Role of the Display Part

When a Cyberdog item calls a Cyberdog display part's OpenCyberItem method, the display part is responsible for the following:

Some display parts (the Cyberdog HTML display part, for example) display data as it is downloaded; they do not wait to display until all the data has been downloaded. If you want your display part to display before the data referenced by its Cyberdog item has been completely downloaded, the display part's OpenCyberItem method can be synchronous.

Some other display parts (the Cyberdog QuickTime display part, for example) do not display until all of the data they are to display has been downloaded. If you do not want your display part to display until the data referenced by its Cyberdog item has been completely downloaded, the display part's OpenCyberItem method must be asynchronous.

In addition, a Cyberdog display part decides whether it is to be embedded in a navigator. If your display part is to be embedded in a navigator, you need to modify your OpenCyberItem method to obtain a navigator and call its GoToCyberItem method.

Role of the Opener Part

The primary purpose of the opener part is to bridge the gap between a Cyberdog item stored in an OpenDoc document and the Cyberdog display part that displays the content referenced by the Cyberdog item. To bridge this gap, the opener part does the following:

A secondary purpose of the opener part is to display progress to the user during an asynchronous operation. A Cyberdog item or Cyberdog display part that initiates an asynchronous operation can attach a progress broadcaster to the opener part and use the opener part to display progress.

An initial opener part is an opener part created by OpenDoc to bind to a part of kind kCyberItemKind. In this situation, the initial opener part is passed as a parameter to the Cyberdog item's Open method. However, before the Cyberdog item can use the initial opener part, the item must first obtain it from the Cyberdog session by calling the session object's ObtainOpener method; this method returns an obtained opener part.

You should always use the opener part returned by ObtainOpener and should not assume that it is the same as the initial opener part that you passed in. Once you have obtained an opener part, you should use the opener part's methods to manipulate it. For example, you should not call an obtained opener part's Open method or place the opener part in an embedded frame.You can call ObtainOpener without worrying about whether it has already been called during the opening of a given Cyberdog item; the method can be called more than once.

Binding to Stored Cyberdog Items

When a Cyberdog item is stored in a storage unit (for example, when it is stored on the desktop as a reference) its part kind is kCyberItemKind. If the user later clicks on the Cyberdog item's reference icon on the desktop, OpenDoc attempts to create a part for the storage unit. Because the storage unit contains data of kind kCyberItemKind, OpenDoc creates an opener part.

The opener part reads the Cyberdog item from the storage unit by calling CyberSession::CreateCyberItemFromSU. The opener part waits until it is displayed in a frame and then calls the Cyberdog item's Open method, passing itself as the initial opener part.

Acting as a Placeholder for Display Parts

If either the Cyberdog item's Open method or the Cyberdog display part's OpenCyberItem method is asynchronous, the method must obtain an opener part by calling CyberSession::ObtainOpener and attach to the opener part a progress broadcaster representing the asynchronous operation. If either Open or OpenCyberItem is passed an opener part as a parameter, the method can try to obtain that opener part by passing it as a parameter to ObtainOpener. However, ObtainOpener may return a different opener part than the one passed to it.

The opener part opens in its own window or in an embedded frame and displays progress during the opening process. The opener part is responsible for ensuring that a Cyberdog display part is created in the appropriate document and displayed in the right place on the screen.

Role of the Navigator

A navigator is a special type of opener part; CyberNavigatorExtension is a subclass of CyberOpenerPartExtension. As an opener part, a navigator can be a placeholder in a document during the opening process and can display progress. Unlike other opener parts, a navigator does not replace itself in a document, putting the resulting display part in its stead. Rather, the display part is embedded in the navigator. Also, a navigator does not bind to parts of kind kCyberItemKind.

The calling Cyberdog item may pass a navigator as a parameter to a Cyberdog display part's OpenCyberItem method. However, it is up to the display part to decide whether it will be embedded in a navigator.

A display part that wants to be embedded in a navigator must obtain a navigator by calling ObtainOpener, passing kNavigatorKind as the part kind of the opener part. The display part should always use the navigator returned by ObtainOpener. If a navigator was passed into the OpenCyberItem method, the display part can try to obtain that navigator by passing it as a parameter to ObtainOpener. However, ObtainOpener may not return the same navigator that the display part passed to it. For example, if the user has disabled the Browse in Place menu item in the Navigate menu, ObtainOpener returns a new navigator.

Once the display part has obtained a navigator, the display part should call the navigator's GoToCyberItem method, which displays the display part in the navigator.

Role of the Download Part

A Cyberdog item calls CyberSession::CreateCyberPart to create an appropriate Cyberdog display part for the data type referenced by the item. If no Cyberdog display part editor is available for that data type, CreateCyberPart cannot create a Cyberdog display part. If so, the Cyberdog item can use a download part to download the data referenced by the item, save it to a file, and attempt to open the file in some other way.

To create a download part, the Cyberdog item calls CyberSession::CreatePartInCyberDocument, passing kDownloadPartKind as the part kind to be created. The Cyberdog item calls the resulting download part's OpenCyberItem method, which takes these actions:

Implementing the Opening Methods

Responsibility for opening a Cyberdog item is divided between the Open method of the Cyberdog item being opened and the OpenCyberItem method of the display part that will display the data referenced by the Cyberdog item.

Implementing a Cyberdog Item's Open Method

The Cyberdog item's Open method is responsible for determining the type of data the item references, creating an appropriate display part for that type of data, and calling the display part's OpenCyberItem method.

If you are developing your own Cyberdog item, you must subclass the CyberItem class and override your subclass's Open method to implement the item's opening behavior.

Open as a Synchronous Method

If a Cyberdog item is inherently resolved, its Open method can be asynchronous. Before returning, Open calls the Cyberdog display part's OpenCyberItem method, which displays the display part. In this case, the Open method should perform the following steps:

  1. If the parameter set contains either an initial or an obtained opener part, retrieve it. For example, the parameter set may contain an opener part if the Cyberdog item is being opened from a storage unit, as discussed in "Binding to Stored Cyberdog Items" (page 75).

   if (params)
      if (!params->GetParameter (ev, kCDInitialOpenerPartKey,
         &openerPart))
      params->GetParameter (ev, kCDObtainedOpenerPartKey, &openerPart);
  1. Call CyberSession::GetISOTypeFromMIMEType to translate the MIME type of the data referenced by the Cyberdog item to a part kind.

   ODValueType kind = cyberSession (ev)->GetISOTypeFromMIMEType (ev,
      someMIMEType);
  1. Call CyberSession::CreateCyberPart to create the part, passing the part kind and the opener part, if any. CreateCyberPart determines whether to create the new part in the session document or in another OpenDoc document by checking which document the opener part is contained in.

   ODPart* part = cyberSession->CreateCyberPart (ev, openerPart,
      kind, kODNULL);
  1. If CreateCyberPart cannot create a Cyberdog display part for the type of data referenced by the Cyberdog item and the referenced data can be downloaded, call CyberSession::CreatePartInCyberDocument to create a download part.

   if (!part && this->IsDownloadable (ev))
      part = cyberSession->CreatePartInCyberDocument (ev,
         kDownloadPartKind, kODNULL);
  1. Call the display part's (or the download part's) OpenCyberItem method.

   CyberPartExtension* CyberPartExt = part->GetExtension (ev,
      kCyberPartExtension);
   CyberPartExt->OpenCyberItem (ev, this, openerPart, params);
   CyberPartExt->Release (ev);

Open as an Asynchronous Method

If the Cyberdog item is not inherently resolved, its Open method must be asynchronous. In this case, the Cyberdog item must obtain an opener part to act as a placeholder and to display progress until an appropriate Cyberdog display part can be created. The Cyberdog item defers the call to OpenCyberItem until the display part is created. In this case, Open should perform the following steps:

  1. Determine whether the Cyberdog item has been resolved by calling its isResolved method. If the Cyberdog item is resolved, perform steps 1 to 5 described in "Open as a Synchronous Method" (page 77).
  2. If the Cyberdog item has not been resolved, retrieve an initial or obtained opener part, if any, from the parameter set. For example, the parameter set may contain an opener part if the Cyberdog item is being opened from a storage unit, as discussed in "Binding to Stored Cyberdog Items" (page 75).

   if (params)
      if (!params->GetParameter (ev, kCDInitialOpenerPartKey, 
         &openerPart))
         params->GetParameter (ev, kCDObtainedOpenerPartKey, 
            &openerPart);
  1. Call the CyberSession::ObtainOpener method to obtain an opener part, passing the opener part retrieved from the parameter set, if any. You should acquire the parameter set before passing it to ObtainOpener. If no parameter set was passed to the Open method, you should create one before calling ObtainOpener.

   openerPart = cyberSession->ObtainOpener (ev, openerPart, 
      kODNULL, this, params);
  1. Call the Cyberdog item's Resolve method, passing a pointer to a notification function that Resolve can call when the Cyberdog item is resolved.

   this->Resolve (ev, MyCyberItemResolved, params, openerPart);
Your Cyberdog item's Resolve method should initiate whatever process is necessary for its resolution, such as creating and opening a Cyberdog stream. To display progress during the resolution process, the Resolve method should attach a progress broadcaster to the opener part and call the broadcaster's accessor methods to update its progress settings. When the Resolve method has finished trying to resolve the Cyberdog item, it should call the notification function.

Note
Do not call the resolution notification function at interrupt time.
Your resolution notification function should check the error code parameter to determine whether the Cyberdog item was resolved successfully. If the Cyberdog item is resolved, the resolution notification function should perform steps 1 to 5 described in "Open as a Synchronous Method" (page 77). The resolution notification function should release the parameter set.

Implementing a Display Part's OpenCyberItem Method

The Cyberdog display part's OpenCyberItem method is responsible for downloading and displaying the data referenced by the Cyberdog item. If you are developing your own Cyberdog display part, you must subclass CyberPartExtension and override your subclass's OpenCyberItem method.

OpenCyberItem as a Synchronous Method

A Cyberdog display part's OpenCyberItem method can be synchronous if the display part can be displayed before all of the data it is to display has been downloaded. In this case, OpenCyberItem should perform the following steps:

  1. Call the Cyberdog item's CreateCyberStream method to retrieve a stream for downloading the data and call the stream's Open method to initiate the download operation.

   fMyStream = fMyItem->CreateCyberStream (ev);
   fMyStream->Open (ev);
  1. Retrieve the Cyberdog item's parent item, if any, from the parameter set, and call CyberSession::AddCyberItemToLog to add the Cyberdog item to the log.

   CyberItem* parent = kODNULL;
   if (params)
      params->GetParameter (ev, kCDParentItemKey, &parent);
   GetCyberSession (ev)->AddCyberItemToLog (ev, parent, fMyItem);
  1. Call the inherited OpenCyberItem method, which displays the display part.

   inherited::OpenCyberItem (item, openerPart, params);

OpenCyberItem as an Asynchronous Method

If a Cyberdog display part cannot be displayed until all the content referenced by its Cyberdog item has been downloaded, the display part's OpenCyberItem method must asynchronous. OpenCyberItem does not call its inherited method; calling the inherited method is deferred until the data has been downloaded.

In this case, OpenCyberItem should perform the following steps:

  1. Retrieve the Cyberdog item's parent item, if any, from the parameter set, and call CyberSession::AddCyberItemToLog to add the Cyberdog item to the log.

   CyberItem* parent = kODNULL;
   if (params)
      params->GetParameter (ev, kCDParentItemKey, &parent);
   GetCyberSession (ev)->AddCyberItemToLog (ev, parent, fMyItem);
  1. Call the CyberSession::ObtainOpener method to obtain an opener part, which will be used to display progress until the display part can be displayed. You must acquire the parameter set before passing it to ObtainOpener. If no parameter set was passed to the Open method, you should create one before calling ObtainOpener.

   openerPart = cyberSession->ObtainOpener (ev, openerPart,
      kODNULL, this, params);
  1. Call a method that initiates whatever asynchronous process is necessary for the data to be displayed, such as creating and opening a Cyberdog stream. To display progress while the data is downloaded, the method should attach a progress broadcaster to the opener part and call the broadcaster's accessor methods to update its progress settings. When the method is finished downloading the data, it should call the inherited OpenCyberItem method.

Embedding a Display Part in a Navigator

A Cyberdog display part determines whether to embed itself in a navigator. If so, the display part must call ObtainOpener to obtain a navigator. In this case, OpenCyberItem performs the following steps:

  1. Call the Cyberdog item's CreateCyberStream method to retrieve a stream for downloading the data and call the stream's Open method to initiate the download operation.

   fMyStream = fMyItem->CreateCyberStream (ev);
   fMyStream->Open (ev);
  1. Retrieve the Cyberdog item's parent item, if any, from the parameter set, and call CyberSession::AddCyberItemToLog to add the Cyberdog item to the log.

   CyberItem* parent = kODNULL;
   if (params)
      params->GetParameter (ev, kCDParentItemKey, &parent);
   GetCyberSession (ev)->AddCyberItemToLog (ev, parent, fMyItem);
  1. Call the display part's SetCyberItem method to store a reference to the Cyberdog item. This method is called by the inherited OpenCyberItem method; however, in this case, the inherited OpenCyberItem method is not called.

   SetCyberItem (item, params);
  1. Call the CyberSession::ObtainOpener method, passing kNavigatorKind as the opener part kind, to obtain a navigator. You must acquire the parameter set before passing it to ObtainOpener. If no parameter set was passed to the Open method, you should create one before calling ObtainOpener.

   ODPart* navPart = GetCyberSession()->ObtainOpener (ev, openerPart,
      kNavigatorKind, item, params);
  1. Instead of calling the display part's OpenCyberItem method, call the navigator's GoToCyberItem method, which displays the display part in the navigator.

   TempNavigatorExtension navigatorExt (navPart, 
      kCyberNavigatorExtension);
   navigatorExt->GoToCyberItem (ev, item, this->GetODPart(), params);
  1. Release the parameter set.

   params->Release (ev);
Note
The previous scenario assumes that OpenCyberItem is synchronous. However, a display part whose OpenCyberItem method is asynchronous can also be embedded in a navigator.


Previous Book Contents Book Index Next

© Apple Computer, Inc.
13 JUL 1996