Next: 2.7 Object tag reference Up: 2. The GNUstep Markup Previous: 2.5 The GSMarkup NSBundle

Subsections


2.6 Integrating Renaissance in your application

In this part of manual we examine practical issues involved in integrating Renaissance in your application - in practice, how to write an application which uses gsmarkup files for creating menus and windows. Our main concern here is teaching you the traps and tricks involved in switching from nib/gorm files to gsmarkup files. There is nothing essentially different: the structure and the organization of the application is the same; everything is the same except that you need to load Renaissance files instead of nib ones. A few details might confuse you the first time you try to do it - in this part of the manual we examine all the details step to step to make sure you won't get confused or upset by a small silly detail.

2.6.1 The application main nib

Traditionally, an application has a main nib file, and support for automatically loading this nib file at the application startup is built into the system libraries. Because we can't modify the system libraries, if you are using a gsmarkup file instead of the main nib file, you will have to load this gsmarkup file manually. Normally, you would have a main gsmarkup file creating the main menu, and, if needed, another one creating the main application window (if there is one). We now examine those separately in the next sections.

  
2.6.2 When to load the main menu gsmarkup

If you are creating the main menu from a gsmarkup file, you need to load the gsmarkup file as soon as possible, typically in your main function. Here is the classical example:
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#include <Renaissance/Renaissance.h>

int main (int argc, const char **argv, char** env)
{
  CREATE_AUTORELEASE_POOL (pool);
  [NSApplication sharedApplication];
  [NSApp setDelegate: [MyApplicationDelegate new]];

  /* Load the menu before calling NSApplicationMain(), because on
   * Apple Mac OS X NSApplicationMain() creates automatically a menu
   * if none is there, and when we try to replace it later, it doesn't
   * really get replaced ... (?)
   *
   * After extensive experiments, loading the menu at this stage is the best
   * way of having it work on both platforms.
   */
#ifdef GNUSTEP
  [NSBundle loadGSMarkupNamed: @"MainMenu-GNUstep"  owner: [NSApp delegate]];
#else
  [NSBundle loadGSMarkupNamed: @"MainMenu-OSX"  owner: [NSApp delegate]];
#endif

  RELEASE (pool);

  return NSApplicationMain (argc, argv);
}
Please note that in the example we have two separate gsmarkup files for the menu on the different platforms. While it can be clumsy to do so, it's certainly the way which works best at the moment - unless you know what you are doing, it's recommended that you do it this way (and that you check/use default template examples of main menu gsmarkup files). Finally, we set an instance of an hypothetic MyApplicationDelegate as the application delegate. That is only an example, but implementing an application delegate custom class can be useful for loading the main window gsmarkup if you need so, as explained in the next section.

2.6.3 When to load the main window gsmarkup

If you are creating the main window of your application from a gsmarkup file, I'd suggest to load this file after the application has been launched. That makes sure the window can immediately be displayed on screen.

In practice, you can implement your own application delegate class, and have it implement the

- (void)applicationDidFinishLaunching: (NSNotification *)aNotification;
method. This method will be called when the application has finished launching; you can load the main window gsmarkup from there. For example:
@interface MyApplicationDelegate : NSObject
{
  /* ... */
}
- (void)applicationDidFinishLaunching: (NSNotification *)aNotification;
@end

@implementation MyApplicationDelegate
- (void)applicationDidFinishLaunching: (NSNotification *)aNotification
{
  [NSBundle loadGSMarkupNamed: @"MainWindow"  owner: self];  
}
@end
Of course, in your main function, you need to set an instance of MyApplicationDelegate as the application delegate (as demonstrated in the previous section). Please note that this is just a very simple example: depending on how you are organizing the code in your application, you might be loading the MainWindow from a different object, or with a different owner - as a classical variant, in -applicationDidFinishLaunching: you could be creating a controller object, and that object might be loading the gsmarkup file during initialization.

Renaissance includes full examples of applications demonstrating how to do all this - the first example you should look at is probably the CurrencyConverter example -

/Examples/Applications/CurrencyConverter

2.6.4 When to load other gsmarkup files

You can literally load other gsmarkup files whenever you want. Typically, you simply do -
  /* ... code here ... */
  [NSBundle loadGSMarkupNamed: @"HighScores"  owner: self];  
  /* ... more code here ... */
that would load the HighScores.gsmarkup file from the main bundle, create the window(s) from the file, using self as the owner (assuming this method call is done inside a method implementation). The owner used when loading is quite important, because instance variables of the owner can be set to point to objects in the window (by using outlets in the gsmarkup file), and vice versa objects in the window can have some of their instance variables (/attributes) set to point to the file owner, so it is particularly natural to use as owner the object which will be interacting more closely and directly with the window while the program is running.

2.6.5 Renaissance and NSDocument-based applications

The AppKit contains a set of classes (NSDocumentController, NSDocument, NSWindowController) which are meant to simplify building document-based application. The default implementation uses nib/gorm files to create windows. Renaissance provides subclasses which behave exactly in the same way, but they use gsmarkup files to create windows instead of nib/gorm files. In the next sections we will examine these subclasses.

2.6.5.1 GSMarkupWindowController

Renaissance provides s0"> 2.5.2.3 GSMarkupTopLevelObjects informal protocol This section contains a single method, which the file owner can implement to receive a notification when the gsmarkup is loaded. The notification will include an array containing all top-level objects which were loaded from the gsmarkup file.
- (void) bundleDidLoadGSMarkup: (NSNotification *)aNotification;

  
2.5.3 Accessing the top-level objects

There are basically three ways of accessing the top-level objects created from a gsmarkup file:
  1. Using one of the NSBundle methods which allow you to set manually the context dictionary, and adding a NSTopLevelObjects to the context dictionary, with value a mutable array. After loading the gsmarkup, Renaissance will store in that dictionary all the top-level objects which have been created from the file. For example:
    NSDictionary *table;
    NSMutableArray *topLevelObjects = [NSMutableArray array];
    
    table = [NSDictionary dictionaryWithObjectsAndKeys: 
                                     self, @"NSOwner",
                          topLevelObjects, @"NSTopLevelObjects",
                                      nil];
    
    [NSBundle loadGSMarkupFile: @"MyFile"
             externalNameTable: table
                      withZone: [self zone]];
    
    /* Now topLevelObjects contains the top-level objects which
     * were created from the gsmarkup file.  */
    
    This method of accessing the top-level objects is similar as the method which can be used with NSBundleAdditions, where an undocumented Apple extension can be used to get the top-level objects by adding a key NSTopLevelObjects with value a mutable array to the context dictionary.

  2. Implementing a -bundleDidLoadGSMarkup: method in the file owner, and retrieving the top-level objects from the notification object. Example:
    - (void) bundleDidLoadGSMarkup: (NSNotification *)aNotification
    {
      NSArray *topLevelObjects;
      topLevelObjects = [[aNotification userInfo] objectForKey: 
                                                      @"NSTopLevelObjects"];
      /* Now topLevelObjects contains the top-level objects which
       * were created from the gsmarkup file.  */
    }
    
    There is no equivalent of this method in the traditional NIB loading API.

  3. Registering some object to receive the notification
    GSMarkupBundleDidLoadGSMarkup
    
    This is more advanced and more rarely useful; there is no equivalent of this method in the traditional NIB loading API.


Next: 2.6 Integrating Renaissance in Up: 2. The GNUstep Markup Previous: 2.4 The connectors section
Nicola 2003-05-05
./usr/share/doc/renaissance/html/manual/node2.html0000644000000000000000000000545010150375633022251 0ustar rootroot00000000000000