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 2 - Programming in Cyberdog
Chapter 3 - Adding Cyberdog Features to an OpenDoc Part


Manipulating a Cyberdog Item

To use a Cyberdog item, your part must be able to create and open one. If you want a Cyberdog item to persist between sessions, you must support reading and writing Cyberdog items. To support data interchange of Cyberdog items, your part should support drag and drop.

The button part manipulates Cyberdog items in the following ways, as described in the following sections:

Creating a Cyberdog Item From a URL

To create a Cyberdog item from a URL, you must first obtain a reference to the Cyberdog session by calling the GetCyberSession function. You then can create a Cyberdog item from the URL text by calling the Cyberdog session's CreateCyberItemFromURL method. Optionally, you can set the default name of the Cyberdog item.

Listing 3-5 shows how the button part creates a Cyberdog item when the part is first opened. The default URL text, which is stored in the part's resource fork, is used to create the item and to set the item's display name.

Listing 3-5 The button part's InitPart method

void CybTxtBtn::InitPart( Environment* ev,
                     ODStorageUnit* storageUnit,
                     ODPart* partWrapper )
{
   TRY
      fSelf = partWrapper;
      fReadOnlyStorage = kODFalse;
         
      // Call the common initialization code to initialize Cyberdog.
      this->Initialize(ev, storageUnit);
      
      // Use CUsingLibraryResources to access part's resource fork.
      {
         CUsingLibraryResources fil;
         Str255defaultURL;
         
         // Get the default string from the resource fork.
         ::GetIndString( defaultURL, kMenuStringResID,
                              kDefaultContent1ID);
         
         if (defaultURL[0] == 0)
            DebugStr("\p InitPart -- couldn't get string.");
         else
         {  
            // Make a C string out of the default URL pascal string.
            char cStr[255];
            ODBlockMove(&defaultURL[1], cStr, defaultURL[0]);
            cStr[ defaultURL[0] ] = 0;
         
            // Create a Cyberdog item from the URL.
            fCyberItem = GetCyberSession(ev)->CreateCyberItemFromURL
                                       (ev, (char*)cStr);
            
            // Make the default name equivalent to the URL.
            // Assume all URLs are smRoman font.
            if (fCyberItem)
               fCyberItem->SetDefaultName(ev, defaultURL, smRoman);
         }
      }
      // Allow the state and content info to be written to storage.
      this->SetDirty(ev);

   CATCH_ALL
      RERAISE;
   ENDTRY
}
Note
The default font for displaying URL's is smRoman. u

Reading and Writing Cyberdog Items

To read a Cyberdog item from a storage unit, you must obtain a reference to the Cyberdog session by calling the GetCyberSession function. You then can call the session's CreateCyberItemFromSU method. Optionally, you can call the Cyberdog item's GetStringProperty method to retrieve the string associated with the item's display name, as indicated by the kCDDefaultName constant.

Listing 3-6 shows the button part's InternalizeContent method, which replaces the current Cyberdog item, if one exists, with one that has just been created from the storage unit. (The InternalizeContent method is called by the InitPartFromStorage method.)

Listing 3-6 The button part's InternalizeContent method

void CybTxtBtn::InternalizeContent (Environment* ev, 
                           ODStorageUnit* storageUnit)
{
   if (ODSUExistsThenFocus(ev, storageUnit, kODPropContents,
                                          kCybTxtBtnKind))
   {              
      CyberItem* ci = kODNULL;
      
      // Retrieve the Cyberdog item from the storage unit.
      ci = GetCyberSession(ev)->CreateCyberItemFromSU(ev, storageUnit);
         
      // Replace the current Cyberdog item with the one in the 
      // storage unit.
      if (ci != kODNULL)
      {
         if (fCyberItem != kODNULL)
            fCyberItem->Release(ev);
         fCyberItem = ci;
      }
   }
}
To write a Cyberdog item to a storage unit, you can call the item's StreamToStorageUnit method. Listing 3-7 shows the button part's ExternalizeContent method, which takes this action. (The InternalizeContent method is called by the Externalize method and other methods that write to storage units.)

Listing 3-7 The button part's ExternalizeContent method

void CybTxtBtn::ExternalizeContent( Environment* ev,
                            ODStorageUnit* storageUnit,
                            ODDraftKey /*key*/,
                            ODFrame* /*scopeFrame*/ )
{
   // Focus on content property and get the current size of the data.
   ODSUForceFocus(ev, storageUnit, kODPropContents, kCybTxtBtnKind);
   ODULong oldSize = storageUnit->GetSize(ev);
   
   // Flatten an item to a buffer and then write the
   // buffer out to the specified ODStorageUnit. 
   fCyberItem->StreamToStorageUnit(ev, storageUnit);

   ODULong newSize = storageUnit->GetOffset(ev);
   if (newSize < oldSize)
      storageUnit->DeleteValue(ev, oldSize - newSize);
}
Once you write the Cyberdog item to storage in this fashion, you must call the Cyberdog session's CreateCyberItemFromSU method to recreate the item in the storage unit (see Listing 3-6).

Note
Whenever you store data in an OpenDoc storage unit, you must modify all methods that work with storage and change them to support your kind of data. In this example, the kCybTxtBtnKind constant specifies the kind of data associated with the Cyberdog item. It is defined as follows:
#define kCybTxtBtnKind kODISOPrefix "Apple:Kind:CybTxtBtn" u

Opening a Cyberdog Item

You call the Cyberdog item's Open method to open a Cyberdog item. What it means to open a Cyberdog item depends on the kind of data at the location referenced by the Cyberdog item. For example, if the Cyberdog item represents a URL for HTML-formatted data, calling the item's Open method causes the data to be downloaded and displayed in a Cyberdog display part. If the Cyberdog item represents an e-mail address, calling the item's Open method results in actions to send mail.

The Open method takes, as a parameter, a ParameterSet object that specifies various options for opening the Cyberdog item. The value can be nil, meaning that no additional options are used. For information about the ParameterSet class, see "ParameterSet" (page 391).

Listing 3-8 shows a portion of the button part's HandleMouseEvent method from which the Cyberdog item's Open method is called. The HandleMouseEvent method is called when the user clicks in the button part. (The HandleMouseEvent method is called from the HandleEvent method.)

Listing 3-8 Opening the Cyberdog item

ODBoolean CybTxtBtn::HandleMouseEvent( Environment* ev,
                              ODEventData* event,
                              ODFacet* facet,
                              ODEventInfo* eventInfo )
{
   if ( facet != kODNULL )
   {
      if ( event->what == kODEvtMouseUp )
      {
         ...
      }
      else if ( event->what == kODEvtMouseDown )
      {
         if (fCyberItem == kODNULL)
            SysBeep(1);
         else
            fCyberItem->Open(ev, nil);
      }
   }
   else
   {
      SysBeep(1);
   }
   return kODTrue;
}

Supporting Drag and Drop of Cyberdog Items

To support drag and drop, you must implement the OpenDoc drag-and-drop protocol, which is explained in OpenDoc Programmer's Guide. It involves overriding the DragEnter, DragWithin, DragLeave, and Drop methods. To support drag and drop of Cyberdog items, you must modify two methods:

In this example, the button part accepts drags of Cyberdog items and of text. Text is used to create a Cyberdog item representing a URL.

Listing 3-9 shows the DragEnter method that checks for Cyberdog items and for text. The kCyberItemKind constant, which is passed to the storage unit's Exists method, identifies a Cyberdog item.

Listing 3-9 The button part's DragEnter method

ODDragResult CybTxtBtn::DragEnter(Environment* ev, 
                         ODDragItemIterator* dragInfo, 
                         ODFacet* facet, ODPoint* where)
{
   ODUnused(facet);
   ODUnused(where);

   ODStorageUnit dragSU;
   ODValueType textType = ODGetSession(ev,fSelf)->GetTranslation(ev)->
                     GetISOTypeFromPlatformType(ev, 'TEXT',
                                       kODPlatformDataType);

   fAcceptThisDrag = kODFalse;
   fActiveFrameHilitedForDrop = kODFalse;

   // Accept the drag if it is a Cyberdog item or text
   for (dragSU = dragInfo->First(ev); 
       dragSU != kODNULL; 
       dragSU = dragInfo->Next(ev))
   {
      if (dragSU->Exists(ev, kODPropContents, kCyberItemKind, 0))
         fAcceptThisDrag = kODTrue;
      else if (dragSU->Exists(ev, kODPropContents, textType, 0))
         fAcceptThisDrag = kODTrue;
   }
   return fAcceptThisDrag;
}
The Drop method handles dropping of data allowed by the DragEnter method. Specifically, the method should create a Cyberdog item from the specified kind of data. You create a Cyberdog item from an item dropped into your part's storage unit by calling the Cyberdog session's CreateCyberItemFromSU method. In the call to CreateCyberItemFromSU, you specify the drag storage unit as a parameter. If your part supports drag and drop of text, you can create a Cyberdog item by calling the Cyberdog session's CreateCyberItemFromURL method.

Listing 3-10 shows how the button part creates a Cyberdog item when Cyberdog item data or text is dropped on the part. If a Cyberdog item already exists, it is released and a reference to the newly created Cyberdog item is saved in the fCyberItem field. The draft is marked as dirty so that its state will be saved, and the facet is invalidated so that it will be redrawn.

Listing 3-10 The button part's Drop method

ODDropResult CybTxtBtn::Drop(Environment* ev, 
                      ODDragItemIterator* dragInfo, 
                      ODFacet* facet, ODPoint* where)
{
   ODStorageUnit*dragSU;
   CyberItem*  ci = kODNULL;
   CyberSession*cyberSession = GetCyberSession(ev);
   ScriptCode  script= smRoman;
   ODValueType textType = ODGetSession(ev,fSelf)->
               GetTranslation(ev)->GetISOTypeFromPlatformType(ev, 
                                 'TEXT', kODPlatformDataType);
   
   for (dragSU = dragInfo->First(ev); 
       dragSU != kODNULL; 
       dragSU = dragInfo->Next(ev))
   {
      // A Cyberdog item is dropped.
      if (dragSU->Exists(ev, kODPropContents, kCyberItemKind, 0))
      {
         // Focus on the Cyberdog item data in the drag storage unit
         dragSU->Focus(ev, kODPropContents, kODPosUndefined,
                           kCyberItemKind, 0, kODPosUndefined);

         // Retrieve the Cyberdog item from the drag storage unit.
         ci = cyberSession->CreateCyberItemFromSU(ev, dragSU);
      }
      
      // The drop is not a Cyberdog item; deal with it as text.
      else if (dragSU->Exists(ev, kODPropContents, textType, 0))
      {
         Size textSize = 0;
         ODPtr theText = kODNULL;
         
         // Get the text from the drag storage unit.
         dragSU->Focus(ev, kODPropContents, kODPosUndefined,
                              textType, 0, kODPosUndefined);
         
         // Get the text length and enough memory for the text.
         textSize = (long) dragSU->GetSize(ev);
         theText = ODNewPtrClear(textSize + 1);
         if (theText)
         {
            // Read the text.
            StorageUnitGetValue(dragSU, ev, textSize,
                                       (ODValue)theText);
            
            // Create a Cyberdog item for the text.
            ci = cyberSession->CreateCyberItemFromURL(ev,
                                          (char*)theText);
            if (ci != kODNULL)
            {
               // Convert the text to a pascal string.
               Str255 pStr;
               Size maxSize = 255;
               textSize = (textSize > maxSize) ? maxSize : textSize;
               ODBlockMove(theText, &pStr[1], textSize);
               pStr[0] = textSize;
               
               // Set the Cyberdog item's default name.
               ci->SetDefaultName(ev, pStr, script);
            }
            ODDisposePtr(theText);
         }
      }
      // Replace the current Cyberdog item with the one from the drop.
      if (ci != kODNULL)
      {
         if (fCyberItem != kODNULL)
            fCyberItem->Release(ev);
         fCyberItem = ci;

         // Successful; save the state and invalidate the display.
         this->SetDirty(ev);
         facet->Invalidate(ev, kODNULL, kODNULL);
         return kODDropCopy;
      }
   }
   // Not successful
   return kODDropFail;
}

Previous Book Contents Book Index Next

© Apple Computer, Inc.
13 JUL 1996