Cards and forms

Created a new class, CardsScene, that displays a card, but not necessarily a stack. This new class sits between Scene and StackScene in the class hierarchy. Moved the following operations from StackScene to CardScene: InstallCurrentCard(), RemoveCurrentCard() CurrentCard(), DefaultTool(), PlaceName(), Finalize(), MakeAddressesContentList(), ToggleEnvelope(), ForwardCard(), and ReplyToCard().

Calling CardScene_CurrentCard will return the first subview of the scene that is a card.

Eliminated Card_MatchText which provided support for the old searching framework. The new searching framework doesn't use this call.

Added support for full page faxing by overriding StandardPaperSizeVersion. Added iStandardPaperSizeNoteCard, iStandardPaperSizeNoteCard and iStandardPaperSizeTelecard as prototype full page objects.

The CardText() and MainText() operations now get text out of the card extra data even if the form is installed in the card, as long as the text field is empty and the suppressCardData flag is set.

Removed the autoGrow flag. This flag has been obsolete since before Magic Cap 1.0.

Changed WasSeen() into an attribute instead of two operations.

Added Card_ExtendBottom that extends the bottom of a card by a fixed amount. Viewable_ExtendBottom has been renamed Viewable_ExtendBottomBy since it takes a delta parameter.

A lot of obsolete code has been removed from class Card. Removed OpenCard() and CloseCard(), since they had empty implementations and no overriders. Packages that used these routines should override AboutToShow() and AboutToHide() instead. Removed the obsolete CanAutoGrow(). This had long ago been replaced by CanExtendBottom() but was left in the interface. Removed RevealTop() and RevealBottom(). Use ScrollToTop() and ScrollToBottom() instead. Removed GoToNext() and GoToPrevious(). These calls were just delegating to iCurrentScene. Removed Card overrides of Label(), RecipientName(), SenderName(), and Subject() since they were all doing the same thing as the inherited methods. Eliminated the KindOfCard() attribute which was used to define phrases like "card", "page" and "tracking report". The new ClassDescription framework should be used instead. Removed Card_SetDefaultTool and Scene_SetDefaultTool.

Forms work with the new sharing model. Forms need to be shared so multiple cards can have strong references, but they ned to be modified to be used in the view hierarchy. Typically, shared objects are not modifiable. The solution is to use a modifiable copy in the view hierarchy, leaving the form in the form field shared and unmodified. This simplifies the form API tremendously. The operations SummonForm(), DismissForm(), BorrowCopyOfForm() and ReturnCopyOfForm() are no longer necessary and have been removed. BorrowForm() and ReturnForm() have been renamed BeginUsingForm() and EndUsingForm(), and are used in all situations now. The operations ExtractCardDataToForm() and StoreCardDataFromForm() have also been removed, since they were used only from BorrowCopyOfForm() and ReturnCopyOfForm().

The read only attribute Card_InstalledForm returns the form that is a subview of the card, if any. The boolean attribute Card_FormModified is used to preserve high level changes made to the local copy of the form. SetFormModified() stores (or removes) the local copy of the form in a list. FormModified() searches this list for the specified form. This list is maintained in the indexical iModifiedFormsList.

EndUsingForm() checks whether the form was modified, and if so, changes the form field to contain a shared version of the locally modified copy. This means that changes to objects in a form, such as text style and color, are preserved and affect only that one card. The formOwner parameter of EndUsingForm() has been removed. Now, the form is removed from the card and is destroyed, after updating the form field if the form has been modified while it was on the card.

The new operation Card_PromoteModifiedForm is called when the user wants to the changes they made to the local copy of a form to be applied to all cards that use this form. This works only for cards that refer to their form through an indexical, which is most if not all cards.

BeginUsingForm() returns a boolean value. This return value will be true if a copy of the form was made, and false if the card already had a form installed in the view hierarchy. Callers need to remember this value; EndUsingForm() should not be called unless unless BeginUsingForm() returns true; EndUsingForm() would otherwise destroy the pre-existing form.

Dropping a coupon on a form now changes that form immediately, then puts up a confirmation asking whether the user would like to also affect all other cards sharing that form.

Renamed Card_Form to Card_PrototypeForm to clarify the distinction between the installed form and the one it is a copy of. The form field of Card has also been renamed prototypeForm.

Added the read-only attribute CurrentForm() that returns the installed form, if any, and the prototype form otherwise.

Added a form parameter to ExtractCardData(). This parameter specifies the form that the card data is extracted into. This replaces the ExtractDataToForm() operation.

Similarly, added a form parameter to AttachToCard() and DetachFromCard().

Magic Cap 1.x limited the length of the form data for any individual form element to 64K. This limitation has been removed in Rosemary. Form data can be of arbitrary length. This is done with a new long format. The existing format is still used for smaller amounts of data.

Added a method, Card_RevealBox which scrolls the specified box on screen. This is used to implement the auto-scrolling text fields feature.

The cardFlags field has been split into individual boolean attributes.

The CanDelete() operation in Magic Cap specifies whether or not an object is deletable. Rosemary adds another level of deletability that specifies that an object should only be deleted with the user's knowledge. This is implemented by the new attribute Object_CanDeleteAtWill. By default, CanDeleteAtWill() returns CanDelete(). If CanDelete() returns true, but CanDeleteAtWill() returns false, that means that the user should be told that the object is being deleted. The case of returning false for CanDelete() but true for CanDeleteAtWill() never arises. Class card returns false for CanDeleteAtWill() so that user data will not be lost.

Fixed a bug where calling ItemChanged() on a SortedStackOfCards object could result in the stack being unsorted. Added SortedStackOfCards_ItemChanged, which resorts the stack.

Added MiniCard_CalcContentBox so that NoteCard can compute the image size without calling Image(). This increases the performance of hopping a notecard to the trash can.

Card_CardIcon now returns a generic minicard image instead of complaining that you passed in the standard card image as a parameter. This new image is referenced by iGenericMiniCardImage.

Card_CardText now returns an ephemeral text object.

Classes affected by these changes

CanBeSearched new
CardScene new
DefaultFontStationery new
Form
IndexCard
ListCard
MiniCard
ModalCard
Scrollable obsolete
SortedStackOfCards new
StackScene

Contact information

One of the goals of Rosemary is to increase the amount of contact information that Magic Cap can store. In Magic Cap 1.x, a unit of contact information (an address or phone number) was stored in instances of AddressLabel subclasses. All the contact information for an entity was kept in AddressCard objects. Name cards were used to display the contact information kept in address cards. Rosemary increases information storage capacity in many ways. First, contact information is stored in a more compact form instead of in an object hierarchy. This is represented by instances of class AddressInfo. Second, contact information about an entity is further compacted by using a more efficient storage format, represented by instances of FullContact. Finally, Magic Cap 1.x maintained a one name card for every address card in the name cards file. In Rosemary, the name cards file contains only name card, which is updated to display contact information for any entity. AddressInfo and FullContact replace their corresponding 1.x classes, AddressLabel and AddressCard.

Class FullContact provides support for being able to display and sort names in a localizable way. This is done through describing various name parts. Magic Cap defines sixteen name parts that are accessible with attributes.

CompleteName()
returns a newline delimited text object where each line corresponds to a name part.
DisplayName()
returns a full name, possibly with a disambiguating integer.
DisplayNameForSortedList()
display name that is format adjusted for a sorted list
FormalName()
the formal name
GivenName()
the first name in the U.S. and Western Europe, but may be the last name in other parts of the world.
IdentifyingName()
format used when identifying a person, as in "Andy's phone", or "Seto-san no denwa"
InformalName()
the informal name
Name()
returns a person's full name
(read only)
Nickname()
returns a nickname if it's available, otherwise the given name is returned.
RomanGivenName()
RomanName()
RomanSurname()
Romanized version of a person's given name, name and surname. These are different only if these names contain non-Roman characters.
SortName()
format of a name used for sorting, which may not look like Name() at all.
(read only)
SortNameGivenName()
SortNameSurname()
attributes for editing the sort name
Surname()
the last name in the U.S. and parts of Europe, but may be the first name in other parts of the world.

Rosemary implements a new framework for entering and editing international postal addresses. There are now two ways to edit a postal address. The fancier way shows up if the user holds the option key when tapping on the address or chooses the "other" address stamp. Code can also get to the fancier method explicitly. The simple way does not let you change the description of the address, and uses the appropriate steps for the country that the address already specifies or the last one used when making a new address. (The last country used is stored in iLastCountryEntered.) The fancier way to edit a postal address allows you to change the description of the address, and prompts for a choice of country before the street address, city, state, zip, or equivalent information. After choosing a country, the edit steps for editing the address are determined based on the country. If there are no specific edit steps for this country, iDefaultPostalEditSteps is used. This is a single step with a big empty multi-line text field in it.

The new dialing code in Rosemary uses global phone numbers, which are stored in Text objects. You should use global phone numbers to represent phone numbers instead of Telenumber objects. The Telenumber class is considered obsolescent, and support for telenumbers is being removed from the software. Many methods that still used telenumbers now use global phone numbers. Removed Dialing_CleanUpTelenumber because telenumbers are being obsoleted. ContactsMasterList_FindOrCreateContact now uses a global phone number instead of a telenumber. Removed the Telenumber() attribute from the TelephoneAddressInfo class.

Consolidated the interface for dealing with country codes into the new mixin class HasCountryCode. This mixin defines the attribute CountryCode() and the operation DisplayCountryCode(). The classes that used to define this attribute or operation now inherit from HasCountryCode: DialingCountry, HasPhoneNumber, ProviderSetups, Telenumber and TelephoneAddressInfo.

The HasPhoneNumber now takes care of the details of remembering the default area code. You can call DialingCountry_CheckPhoneNumberAndRememberDefaulls if you are saving a phone number to set the default country and area code information. This information is used to fill out initial values in attribute steps.

DialingCountry objects store emergency numbers, so that different emergency numbers can be used for different countries. DialingCountry_IsSpecialNumber now returns true for both special numbers and emergeny numbers. It will not be possible to dial one country's emergency number from another country. Dialing_CreateDialableNumber will return nilObject if the phone number is one of these special numbers and the phone call is international.

PhonePanel_StartPhoneCall now makes the user confirm that he really wants to dial an emergency number.

The salutation on telecards would appear as "Dear ," if the contact associated with the telecard had an e-mail address but no name. To fix this problem, a new operation, Contact_SalutationName has been defined. This operation is defined as noMethod in the Contact class; FullContact provides an implementation that uses the first address in the contact if there is no name, so that the salutation might read "Dear foo@bar.com" instead of leaving a blank space. SimpleContact implements SalutationName() as well; this calls the implementation in FullContact, or Name(self) if there is no full contact associated with this simple contact.

Different countries use different parts of a name in a salutation; in the United States, the first (given) name is used. In Japan and France, the surname is used. To allow the ability to localize this behavior, a new text mapping, /salutation name/ has been added to iStandardTextMapping. In many cases, it is now desirable to use this mapping instead of /first name/ or /last name/, as this mapping will automatically do the right thing in different locales without the need for explicit localization of text.

The new class DomainInfo provides a framework that allows contact addresses to know about custom images and edit steps for specific domains by associating an image and a set of steps with a domain name.

The text of a postal address can be retrieved with the new attribute AddressExceptCountry(). The setter aspect of this attribute sets the street address and empties the postal region, postal code and city.

The Rosemary Magic Cap API tries to avoid having multiple operations have the same name but different interfaces. Since Magic Cap doesn't do polymorphism, this is just plain confusing. Many operations have been removed or renamed to avoid this problem. All occurences of Entity() in Magic Cap are now attributes. Some classes had defined two operations, Entity() and SetEntity().

The class SimpleContact is a minimal form of FullContact, much like MinimalAddressCard was a reduced form of AddressCard. Both SimpleContact and FullContact inherit from the Contact abstract class. Contacts can store up to 255 characters of information.

Here is a complete list of the classes, intrinsics, operations, and indexicals that have been renamed as part of this change:

Old class New class
MinimalAddressCard SimpleContact
AddressCard FullContact
Old intrinsic New intrinsic
AddressCardFromContactNear ContactFromContactNear
AddressCardFromLabel ContactFromLabel
AddressCardFromPseudoAddressCard ContactFromPseudoContact
AsAddressCard AsContact
AuthorityFromAddressCardOrLabel AuthorityFromContactOrLabel
DeleteOneAddressCard DeleteOneContact
FindContactAddressesByName FindFullContactByName
MakeContactAddressesFromContactNear MakeFullContactFromSimplyContactNear
MakeIncomingContactNear MakeIncomingSimpleContactNear
PersonToAddressCard PersonToContact
PseudoAddressCardFromLabel PseudoContactFromLabel
RestoreAddressCardsInList RestoreContactsInList
Old operations New operations
AddToContactAddresses AddToFullContact
AddressCard Contact
AddressCardChanged ContactChanged
AddressCardListIndex ContactListIndex
AddressCardListTitle ContactListTitle
AddressCardNumber ContactNumber
AssimilateNewAddressCard AssimilateNewContact
BeginAddressCardNameChange BeginContactNameChange
ChooseAddressCardsToCollect ChooseContactsToCollect
ContactAddresses FullContact
ContactAddressesIfAny FullContactIfAny
CreateNewAddressCard CreateNewContact
DisplayedAddressCard DisplayedContact
EndAddressCardNameChange EndContactNameChange
FindAddressCardFromInfo FindContactFromInfo
FindMatchingAddressCard FindMatchingContact
FindOrCreateAddressCard FindOrCreateContact
GenerateAddressCardsOfferCard GenerateContactsOfferCard
GoToAddressCard GoToContact
HandleNewAddressCard HandleNewContact
IsUnnamedContactAddresses IsUnnamedFullContact
KeepAddressCards KeepContacts
MakeAddressCardFromLabel MakeContactFromLabel
MakeContactNear MakeSimpleContactNear
MakeContactAddressesNear MakeFullContactNear
MergeAddressCards MergeContacts
NascentAddressCard NascentContact
RemoveDisplayedAddressCard RemoveDisplayedContact
RemoveDisplayedAddressCardWithConfirmation RemoveDisplayedContactWithConfirmation
ServiceAddressCard ServiceContact
UpdateAddressCard UpdateContact
UpdateAddressCardFields UpdateContactFields
UpdateAddressCardWithCallback UpdateContactWithCallback
Old indexicals New indexicals
iAddAddressCardImage iAddContactImage
iAddressCardsToCollect iContactsToCollect
iChangedAddressCardStationery iChangedContactStationery
iNewAddressCardList iNewContactList
iNewAddressCardStationery iNewContactStationery
iUnnamedAddressCardsQueue iUnnamedContactsQueue
iVendorProviderAddressCard iVendorProviderCard

Classes affected by these changes

AddressCard obsolete
AddressInfo new
AddressLabel obsolete
AddressLabelStamp new
AlphaPagerLabel obsolete
AOLLabel obsolete
ATTMailLabel obsolete
ATTSkyTelPagerLabel obsolete
CanBeFiled new
CompanyPostalLabel obsolete
CompuServeLabel obsolete
Contact new
ContactMergerClient
ContactSearchResult new
ContactsContentProxy new
ContactsMasterList new
Dialing new
DialingCountr
DirectConnectLabel obsolete
DirectoryLookup obsolete
DirectoryLookupScene
DLAddressCard obsolete
DomainInfo new
ElectronicMailLabel obsolete
ElectronicMailLabelStamp
FaxLabel obsolete
FaxWindow
FullContact new
GroupAddressCard obsolete
HasAddressCardSortOrder
HasContactSortOrder new
HasCountryCode new
HasPhoneLabel
HasPhoneNumber new
IndexCard
InternetMailLabel obsolete
MCIMailLabel obsolete
NameCard
NameCardsScene
NameCardsStack obsolete
NewContactHandler new
NewContacts new
PagerLabel obsolete
PeopleAddressPicker
PeoplePhonePicker
PhoneLabel obsolete
PhonePanel
PostalAddressInfo new
PostalCountry new
PostalCountryChoiceBox new
PostalLabel obsolete
PostalLabelStamp
ProdigyLabel obsolete
ProviderAddressCard obsolete
ProviderLabel obsolete
ProviderSetups
RadioTelescriptLabel obsolete
RMLabel obsolete
PSTNTelescriptLabel obsolete
SimpleContact new
TaskProxy
Telenumber
TelephoneAddressInfo new
TelescriptLabel obsolete
UnsharedAddressCard obsolete
Utilities
X400Label obsolete

Content proxies

NewContentProxy() can now be used by subclasses of Scene to return subclasses of ContentProxy. Class Scene implements the new operation PrototypeContentProxy() which returns iPrototypeContentProxy. NewContentProxy() now calls this new operation instead of copying iPrototypeContentProxy directly. Subclasses of Scene can override PrototypeContentProxy() to return a ContentProxy subclass instead of reimplementing NewContentProxy().

The conveyFlags field of class ContentProxy has been split into individual boolean attributes.

Classes affected by these changes

AppointmentScene
ContentProxy
DatebookScene
MailWindow
NameCardsScene
PrintWindow
Scene
Task

Control bar

The control bar has more flexibility in Rosemary. It is now easier to change the number of gadgets that appear in the control bar, and the control bar itself can be placed in different positions and orientations. The control bar can even be replaced by another user interface element.

Created the class AbstractControlBar which is the base class for ControlBar and SimpleControlBar. SimpleControlBar is a new class that specifies an invisible holding place for control bar gadgets.

The class ControlBarGadget is a subclass of Gadget that knows to install itself into the control bar. The current control bar gadgets are now subclasses of ControlBarGadget. Control bar gadgets can specify a preference for which slot in the control bar they should install into.

Classes affected by these changes

AbstractControlBar new
CommandGadget
ControlBar
ControlBarGadget new
KeyboardGadget
SimpleControlBar new
ToolGadget
TrashGadget

Controls

Made Control_TargetAttributeAsLevel distinguish between signed and unsigned shorts. The type is specified by the new constants, kAttributeTypeSignedShort and kAttributeTypeUnsignedShort. These constants replace kAttributeTypeShort.

In Magic Cap 1.x, you could create a choice box which had a last choice which was editable. This behavior only worked if the choices were specified by a multi-line text object. Rosemary makes this behavior available to choices listed with an object list as well. This feature is enabled when the choiceObjects and lastOneEditable flags are set in the choice box flags. If these flags are set, the operation CreateOtherChoiceObject() is called to create an object that represents the "other choice" when the choice box is about to appear on the screen. Override this method to create the appropriate object type. If the choice box appears in an attribute window, the operation ConfirmOtherChoiceObject() is called when the data in the attribute window is confirmed. By default, this operation will destroy the edited choice if it wasn't the selected choice, or the choice has a name that already exists in the choices list. Otherwise, the choice is inserted into the proper place in the list, making it a permanent choice. If a choice box with this behavior enabled appears outside of an attribute window, the created choice will remain at the end of the choice list until Confirm() is called on the choice box. As long as the object created by CreateOtherChoiceObject() exists, the new boolean field ChoiceBox_hasOtherChoiceObject will be set to true.

Classes affected by these changes

ChoiceBox
Control
PostalCountryChoiceBox new