TweetFollow Us on Twitter

May 93 - Three MacApp 3.0.1 Shortcuts

Three MacApp 3.0.1 Shortcuts

Ken Victor

The following three shortcuts have made my life much simpler while developing a new MacApp 3.0.1 application using C++.

Try and Catch Macros

In a past issue of "Develop" magazine, the C macros for Try and Catch were defined for MacApp 2. I got used to using these when I was developing a MacApp 2 product using C++, and although the MacApp 3 approach to exception handling is easier to use with C++, I wanted to continue to use Try and Catch. I find this more meaningful to read than if fi.Try(). So here is my version for MacApp 3:
#define try                    \
    FailInfo fi;            \
    if (fi.Try()) {
#define catch               \
    fi.Success();           \
    }                       \
    else
#define try2                \
    if (fi.Try()) {
#define success     fi.Success()
#define resignal    fi.ReSignal()

Thus you can write code that looks like the following:

try {
    …
    }
catch {
    …
    resignal;
    }

    or:

try …
catch ;

    or:

try {
    …
    success;
    return;
    …
    }
catch ;

These macros nest properly so that you can write the following:

try {
    …
    try {
        …
        }
    catch {
        …
        resignal;
        }
    …
    }
catch {
    …
    resignal;
    }

The Try2 macro is used if you want a second, or third, Try clause at the same level as a previous one. E.g.:

try {
    …
    }
catch {
    …
    resignal;
    }
…
try2 {
    …
    }
catch {
    …
    resignal;
    }

The Catch macro could easily be modified to automatically resignal, but I felt it best not to hide this, and to save the few bytes in the situation where I didn't need to resignal.

TMyDocument Shortcut

When developing a new application, each time you add, change, or delete a class variable from your TMyDocument class, there are up to 8 different methods that you may have to change:
Initialize
IMyDocument
DoInitialState
Free
FreeData
DoNeedDiskSpace
DoRead
DoWrite

And it is important that DoRead and DoWrite perform operations in the same order. I got tired of trying to remember to update each of these methods, and of having to go back and forth between DoRead and DoWrite to make sure I was doing things in the right order. I therefore decided to localize all these functions into one common method. The price I pay for this is a slight performance hit due to the extra switches in my common routine, a slight violation of clean segmentation, and a violation of the tenant of a single routine performing a single function. I felt that these were a small price to pay for the increased convenience. When my app is complete, I can always do away with this common routine, and place the appropriate code in each of the specific methods.

My common routine is defined as follows:

enum tDocIterType {
    forReading,
    forWriting,
    forSizing,
    forInitialize,
    forIDoc,
    forDoInitial,
    forFreeData,
    forFree
    };
void    DoSRWIIDF(  tDocIterType iterType,
                    TFile* aFile,
                    long& dataForkBytes,
                    long& rsrcForkBytes,
                    Boolean modifier = false);

Each of my standard methods is now quite simple and implemented similarly to the following:

pascal void TMyDocument::DoNeedDiskSpace(
                        TFile* itsFile,
                        long& dataForkBytes,
                        long& rsrcForkBytes) {
    // count us
    DoSRWIIDF(  forSizing,
                itsFile, 
                dataForkBytes, 
                rsrcForkBytes);
    }   //  end of TMyDocument :: DoNeedDiskSpace 

My common routine locks the document, so I can read and write to it comfortably, allocates any needed Streams, and for each member variable in the document performs a switch to perform the required action. The core of the code follows:

#pragma segment DocReadWriteEtc
void TMyDocument::DoSRWIIDF(    tDocIterType iterType,
                    TFile* aFile,
                    long& dataForkBytes,
                    long& rsrcForkBytes,
                    Boolean modifier) {
TStream*        aStream = NULL;
VOLATILE( aStream);

// lock us just in case
    SignedByte myState = LockHandleHigh( (Handle) this);

    try {
    // get stream for i/o
        switch (iterType) {
            case forSizing:
                aStream = new TCountingStream;
                ((TCountingStream*) aStream)->ICountingStream();
                aStream->SetPosition( 0);
                inherited::DoNeedDiskSpace( aFile,
                                        dataForkBytes,
                                        rsrcForkBytes);
                break;
            case forReading:
            case forWriting:
                aStream = new TFileStream;
                ((TFileStream*) aStream)->IFileStream( aFile);
                aStream->SetPosition( 0);
                if (iterType == forReading)
                    inherited::DoRead( aFile, modifier);
                else inherited::DoWrite( aFile, modifier);
                break;
            }
    //  field 1
        switch (iterType) {
            case forSizing:     // fall thru
            case forWriting:
                aStream->WriteBytes( &field1, sizeof( field1));
                break;
            case forReading:    
                aStream->ReadBytes( &field1, sizeof( field1));
                break;
            case forInitialize:
                …
                break;
            case forIDoc:
                …
                break;
            case forDoInitial:
                …
                break;
            case forFreeData:
                …
                break;
            case forFree:
                …
                break;
            }
    //  field 2
        …
    // free stream
        if (iterType == forSizing)
            dataForkBytes += aStream->GetSize();
        FreeIfObject( aStream);
    // unlock us
        HSetState( (Handle) this, myState);
    }
catch {
    // free stream
        FreeIfObject( aStream);
    // unlock us
        HSetState( (Handle) this, myState);
    resignal;
    }
}   //  end of TMyDocument :: DoSRWIIDF

Now whenever I add, change, or delete a field, it is a simple matter of modifying the one "block" of code.

Floating TEditTexts

In several of my dialogs, I had fields in which I wanted to restrict what characters the user could enter. I wanted to beep if the user typed an illegal character. In looking at the MacApp3Tech$ archives, the suggestions for accomplishing this basically involved subclassing TEditText and a few other classes so that you could create you own floating TEView with its appropriate behavior. Nick Nallick, in his article "Text Filtering with Behaviors" in the July 1992 FrameWorks describes such an approach. I decided to try the different approach of attaching a Behavior to the dialog floating TEView, and much to my relief this worked out even better than I thought it would, and is in fact a very general approach. You can even attach multiple instances of this behavior to the floating view, and each instance can act on different characters and/or be applied to different TEditTexts in the dialog.

The Behavior basically looks at each character the user types into a TEditText and beeps if this is an illegal character, or if it is a legal character simply passes it along the behavior chain for normal operation. The behavior will also examine each character in a pasted string and beep if the string contains any illegal characters or pass the string along. Using the behavior is quite simple and relies on the fact that there is only one floating TEView per dialog window and that this view is usually the window's target after the window has been created. First create your window and establish it as a dialog so that the floating TEView will exist. Then create the behavior:

TBhvrInputFilter* aCharBeeper = new TBhvrInputFilter;

Then call the '"I" method, passing the window:

aCharBeeper->IBhvrInputFilter( aWindow);

This will initialize the Behavior and attach it to the floating TEView. It finds the floating TEView by first looking at the window's target to see if is a member of TDialogTEView; if not, it searches the window's sub views until it finds a TDialogTEView to attach to.

Next tell the Behavior which TEditText views you wish to check by passing the identifier(s) of these views:

aCharBeeper->AddView( aEditText->GetIdentifier());
aCharBeeper->AddView( anotherEditText->GetIdentifier());

And lastly, tell the behavior which characters are allowed. The default is to not allow any characters. However there are several methods for specifying the legal characters.

aCharBeeper->AllowNumbers();
aCharBeeper->AllowControlChars();
aCharBeeper->AllowChar( '/');

The above sequence will allow numbers and the slash character, the common characters for a date input view, but will beep on all other characters. It will also allow all control characters so that normal editing can take place.

Advantages

This approach relies on the fact that a common single floating TEView is passed around, rather than each TEditText having its own floating TEView. This leads to both the advantages and disadvantages of this approach, as opposed to subclassing TEditText to install your own floating TEView. This approach is simpler to use and requires less code since there is no need to subclass. The disadvantage is that since this behavior is attached to the only floating TEView, each TEditText that you use uses this behavior, even if you don't want to filter that TEditText. The list of views to filter is maintained as a TLongintList and I haven't noticed any unacceptable performance (but I have not made any measurements). This approach is especially useful if you have several TEditTexts that require the same filtering. And, as mentioned above, if you have different filtering requirements, you can simply install multiple instances of this behavior, each with their own set of views to check, and their own set of legal characters.

Post processing

While further developing my app, I had a need to process TEditText after each character's editing action had taken place, but before any other processing could occur. (What I wanted was to perform name lookup and recognition based on the user's [partial] input string.) Since my use of behaviors for filtering input worked so well, I decided to capitalize on what I already had. I broke up TBhvrInputFilter into two classes: TBhvrFTEVFilter and TBhvrInputFilter. TBhvrFTEVFilter is an abstract class with methods for attaching itself to the floating TEView, and for adding, removing, and checking which sub views to work with. TBhvrInputFilter is now a subclass of TBhvrFTEVFilter and contains the specific methods having to do with filtering characters.

I then subclassed TBhvrFTEVFilter again to create a class that would do post processing of the user's input. This turned out to be a little more difficult than I thought it would be at first, but still simpler than any other way I could think of. The difficulty lay in the fact that when I call inherited::DoKeyEvent or inherited::DoMenuCommand, the TDialogTEView actually created command objects, rather than acting immediately. This was solved by my examining the event queue after calling the inherited method, looking for a TTECommand. If I find one, I remove it from the queue, call its DoIt, Commit, and Free methods. I can then easily get the resulting edited text and act as I wish.

In hindsight, I realized that I may have been able to use MacApp's dependency and notification techniques to accomplish this post processing. However, I now had something that worked, and I believe I might have had problems with characters after the first typed character, and "if it ain't broke..."

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Adium 1.5.10.3 - Popular instant messagi...
Adium is a fast and free instant messaging client which supports AIM, ICQ, Jabber, MSN, Yahoo!, Google Talk, Yahoo! Japan, Bonjour, Gadu-Gadu, Novell Groupwise, SIP/SIMPLE (Text), and Lotus Sametime... Read more
CleanMyMac 3.8.1 - $39.95
CleanMyMac makes space for the things you love. Sporting a range of ingenious new features, CleanMyMac lets you safely and intelligently scan and clean your entire system, delete large, unused files... Read more
BusyCal 3.1.7 - Powerful calendar app wi...
BusyCal is an award-winning desktop calendar that combines personal productivity features for individuals with powerful calendar sharing capabilities for families and workgroups. Its unique features... Read more
Lyn 1.8.9 - Lightweight image browser an...
Lyn is a fast, lightweight image browser and viewer designed for photographers, graphic artists, and Web designers. Featuring an extremely versatile and aesthetically pleasing interface, it delivers... Read more
Tweetbot 2.5 - Popular Twitter client.
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
Monolingual 1.7.8 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. If you use your computer in only one (human) language, you... Read more
Dash 4.0.3 - Instant search and offline...
Dash is an API documentation browser and code snippet manager. Dash helps you store snippets of code, as well as instantly search and browse documentation for almost any API you might use (for a full... Read more
Posterino 3.3.6 - Create posters, collag...
Posterino offers enhanced customization and flexibility including a variety of new, stylish templates featuring grids of identical or odd-sized image boxes. You can customize the size and shape of... Read more
Apple Numbers 4.1.1 - Apple's sprea...
With Apple Numbers, sophisticated spreadsheets are just the start. The whole sheet is your canvas. Just add dramatic interactive charts, tables, and images that paint a revealing picture of your data... Read more
Apple Pages 6.1.1 - Apple's word pr...
Apple Pages is a powerful word processor that gives you everything you need to create documents that look beautiful. And read beautifully. It lets you work seamlessly between Mac and iOS devices, and... Read more

Latest Forum Discussions

See All

Get up to speed with everything you need...
In case you haven’t heard, MU Origin just got a colossal new update with new all-server events, battle modes, and systems making their way to the land of MU. Here’s a handy guide to everything you need to know about the latest content. [Read... | Read more »
Minimalist puzzle game, Cuts, free on iO...
If you're looking for a gorgeous puzzle experience on iOS devices, developer Gamebra.in's aesthetically interesting puzzler, Cuts, is discounted to free on the iOS App Store right now. [Read more] | Read more »
Anime tactical RPG, War of Crown, comes...
If you're looking for another tactical RPG fix to go alongside your Fire Emblem Heroes campaigns check out Gamevil's newest, anime-inspired tactics RPG, War of Crown, which comes out tomorrow. [Read more] | Read more »
Fantasy MMORPG MU Origin adds new modes,...
MU Origin, Webzen’s highly popular fantasy MMORPG is getting ready to shake things up for the second time this year, as a new update makes its way to the Google Play and App Store from today. Introducing new systems, modes, and events, the land of... | Read more »
Blizzard is looking to hire a mobile dev...
A new thread on the popular video game rumor forum, NeoGAF, uncovered an interesting job listing over at Blizzard Entertainment. It appears the studio behindStarCraft, World of WarCraft, Hearthstone,andOverwatch is looking to bring on a new hire... | Read more »
Legend of Zelda meets Cooking Mama in ne...
Dungeon Chef is what happens when you mix the RPG elements (and style) of a Legend of Zelda game, with cooking elements. Although, now that The Legend of Zelda: Breath of the Wild also has cookingelements, so maybe the gameplay is not so novel.... | Read more »
ChordFlow (Music)
ChordFlow 1.0.0 Device: iOS Universal Category: Music Price: $6.99, Version: 1.0.0 (iTunes) Description: ChordFlow is a chord sequencer with a unique 4-track polyphonic arpeggiator, extensive chord library, MIDI out and Ableton Link... | Read more »
The Walking Dead: A New Frontier is out...
The newest season of Telltale Games'The Walking Dead is well underway. After the release of the third episode, "Above the Law" about a month ago, episode four, "Thicker Than Water" is hot and ready for more zombies and gut-wrenching emotional... | Read more »
Best games we played this week
Another week, another new wave of mobile games do dive into. We've dug through the list of apps that came out this week to tell you which apps are worth your sweet time. And while there weren't too many games this week, there were some big ones.... | Read more »
Vignettes (Games)
Vignettes 1.0.1 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.1 (iTunes) Description: Vignettes is a casual but unique exploration game without text or characters, where objects shapeshift as you spin them around... | Read more »

Price Scanner via MacPrices.net

Digital Paper Tablet Offers Distraction Free...
I typically spend 8-10 hours a day gazing at the screens in my laptops and iPad, as tools of my livelihood, I don’t as a rule use electronic devices for pleasure reading. I subscribe to a daily... Read more
“Today at Apple” Bringing New Educational Ses...
Apple has announced plans to launch dozens of new educational sessions next month in all 495 Apple Stores ranging in topics from photo and video to music, coding, art and design, and more. The hands-... Read more
Smart Finance Free Comprehensive Personal Fin...
Moscow-based indie developer, Alexander Survillo has announced the release and immediate availability of Smart Finance: Personal Finance, Budget & Money 1.1.4, an update to his comprehensive... Read more
12-inch 1.1GHz Retina MacBooks on sale for $1...
B&H has 12″ 1.1GHz Retina MacBooks on sale for $100 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1199.99 $100 off MSRP - 12... Read more
13-inch 2.7GHz Retina MacBook Pro on sale for...
B&H Photo has the 13″ 2.7GHz Retina MacBook Pro on sale for $130 off MSRP. Shipping is free, and B&H charges NY & NJ tax only: - 13″ 2.7GHz/128GB Retina MacBook Pro (MF839LL/A): $1169 $... Read more
15-inch 2.2GHz Retina MacBook Pros available...
B&H Photo has the 15″ 2.2GHz Retina MacBook Pro available for $200 off MSRP including free shipping plus NY & NJ sales tax only: - 15″ 2.2GHz Retina MacBook Pro (MJLQ2LL/A): $1799.99 $200 off... Read more
13-inch Touch Bar MacBook Pros on sale for up...
B&H Photo has the 2016 Apple 13″ Touch Bar MacBook Pros in stock today for up to $150 off MSRP. Shipping is free, and B&H charges NY & NJ sales tax only: - 13″ 2.9GHz/512GB Touch Bar... Read more
Apple refurbished Apple TVs available for up...
Apple has Certified Refurbished 32GB and 64GB Apple TVs available for up to $30 off the cost of new models. Apple’s standard one-year warranty is included with each model, and shipping is free: -... Read more
12-inch 1.2GHz Retina MacBooks on sale for up...
B&H has 12″ 1.2GHz Retina MacBooks on sale for up to $160 off MSRP. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.2GHz Space Gray Retina MacBook: $1439.99 $160 off MSRP - 12″ 1... Read more
HyperX Ships Pulsefire FPS Gaming Mouse, Winn...
Your reporter is a longtime fan of gaming mice for general purpose coomnputing use, finding them typically superior in comfort and performance. HyperX, a division of Kingston Technology Company, Inc... Read more

Jobs Board

Product Manager, *Apple* Platforms - Viacom...
…Product Manager to drive the execution of its iOS and AppleTV experiences. The Apple Platform Product Manager will be a leader in our Agile/Scrum environment and Read more
Geek Squad *Apple* Master Consultation Agen...
**500662BR** **Job Title:** Geek Squad Apple Master Consultation Agent **Location Number:** 000286-Canton-Store **Job Description:** **What does a Geek Squad Read more
*Apple* Mobile Master - Best Buy (United Sta...
**500710BR** **Job Title:** Apple Mobile Master **Location Number:** 000279-North Olmsted-Store **Job Description:** **What does a Best Buy Apple Mobile Master Read more
*Apple* Engineering Specialist - CSRA (Unite...
Apple Engineering Specialist All times are in Eastern Daylight Time Requisition ID Job Locations US DC Washington DC Posted Date Category Engineering Sciences Read more
*Apple* Mac Computer Technician - GeekHampto...
…complex computer issues over the phone and in person? GeekHampton, Long Island's Apple Premium Service Provider, is looking for you! Come work with our crew Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.