Renaissance-0.9.0/0000775000076400007640000000000010770264755013276 5ustar nicolanicolaRenaissance-0.9.0/Source/0000775000076400007640000000000010770264743014533 5ustar nicolanicolaRenaissance-0.9.0/Source/Renaissance.h0000664000076400007640000000345107711176630017140 0ustar nicolanicola/* -*-objc-*- Renaissance.h - main public header for GNUstep Renaissance Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: November 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNUstep_H_Renaissance #define _GNUstep_H_Renaissance /* End-user applications typically need access to only a few * Renaissance headers. This header file includes them. * * If you need access to Renaissance advanced stuff (markup tags and * objects - typically to create new tags, patch existing ones, or * implement a visual builder for Renaissance), you need to include * Renaissance/Markup.h. */ /* GNUstep compatibility macros */ #ifndef GNUSTEP # include "GNUstep.h" #endif /* AutoLayout */ #include "GSAutoLayoutDefaults.h" #include "NSViewSize.h" /* Markup end-user functions */ #include "GSMarkupBundleAdditions.h" #include "GSMarkupApplicationMain.h" /* TagLibrary end-user classes */ #include "GSMarkupDocument.h" #include "GSMarkupWindowController.h" #endif /* _GNUstep_H_Renaissance */ Renaissance-0.9.0/Source/Markup.h0000664000076400007640000000507007602477757016160 0ustar nicolanicola/* -*-objc-*- Markup.h - header for GNUstep Renaissance giving access to the Markup internals Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: November 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNUstep_H_Renaissance_Markup #define _GNUstep_H_Renaissance_Markup /* Include all end-application Renaissance headers. */ #include "Renaissance.h" /* Now the Markup specific headers; those are only needed if you are adding custom tags, or manipulating the markup objects directly (such as in a .gsmarkup visual editor). */ /* Markup */ #include "GSMarkupCoder.h" #include "GSMarkupCoding.h" #include "GSMarkupConnector.h" #include "GSMarkupDecoder.h" #include "GSMarkupDecoderBackend.h" #include "GSMarkupLocalizer.h" #include "GSMarkupTagInstance.h" #include "GSMarkupTagObject.h" /* TagLibrary */ #include "GSMarkupTagBox.h" #include "GSMarkupTagBoxSeparator.h" #include "GSMarkupTagButton.h" #include "GSMarkupTagColorWell.h" #include "GSMarkupTagControl.h" #include "GSMarkupTagForm.h" #include "GSMarkupTagFormItem.h" #include "GSMarkupTagHbox.h" #include "GSMarkupTagHspace.h" #include "GSMarkupTagLabel.h" #include "GSMarkupTagMatrix.h" #include "GSMarkupTagMatrixCell.h" #include "GSMarkupTagMatrixRow.h" #include "GSMarkupTagMenu.h" #include "GSMarkupTagMenuItem.h" #include "GSMarkupTagMenuSeparator.h" #include "GSMarkupTagObjectAdditions.h" #include "GSMarkupTagPanel.h" #include "GSMarkupTagPopUpButton.h" #include "GSMarkupTagPopUpButtonItem.h" #include "GSMarkupTagScrollView.h" #include "GSMarkupTagSeparator.h" #include "GSMarkupTagTextField.h" #include "GSMarkupTagTextView.h" #include "GSMarkupTagVbox.h" #include "GSMarkupTagView.h" #include "GSMarkupTagVspace.h" #include "GSMarkupTagWindow.h" #endif /* _GNUstep_H_Renaissance_Markup */ Renaissance-0.9.0/Source/.cvsignore0000664000076400007640000000004607602507720016526 0ustar nicolanicola*obj derived_src Renaissance.frameworkRenaissance-0.9.0/Source/GNUstep.h0000664000076400007640000000502307602477757016244 0ustar nicolanicola/* GNUstep.h - macros to make easier to port gnustep apps to macos-x Copyright (C) 2001 Free Software Foundation, Inc. Written by: Nicola Pero Date: March, October 2001 This file is part of GNUstep. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file is automatically included when you do a #include * "Renaissance/Renaissance.h" which is the recommended way to go. */ #ifndef __GNUSTEP_GNUSTEP_H_INCLUDED_ #define __GNUSTEP_GNUSTEP_H_INCLUDED_ #ifndef GNUSTEP #define AUTORELEASE(object) [object autorelease] #define TEST_AUTORELEASE(object) ({ if (object) [object autorelease]; }) #define RELEASE(object) [object release] #define TEST_RELEASE(object) ({ if (object) [object release]; }) #define RETAIN(object) [object retain] #define TEST_RETAIN(object) ({ if (object) [object retain]; }) #define ASSIGN(object,value) ({\ id __value = (id)(value); \ id __object = (id)(object); \ if (__value != __object) \ { \ if (__value != nil) \ { \ [__value retain]; \ } \ object = __value; \ if (__object != nil) \ { \ [__object release]; \ } \ } \ }) #define ASSIGNCOPY(object,value) ASSIGN(object, [[value copy] autorelease]); #define DESTROY(object) ({ \ if (object) \ { \ id __o = object; \ object = nil; \ [__o release]; \ } \ }) #define CREATE_AUTORELEASE_POOL(X) \ NSAutoreleasePool *(X) = [NSAutoreleasePool new] #define NSLocalizedString(key, comment) \ [[NSBundle mainBundle] localizedStringForKey:(key) value:@"" table:nil] #define _(X) NSLocalizedString (X, nil) #define __(X) X #define NSLocalizedStaticString(X, Y) X #endif /* GNUSTEP */ #endif /* __GNUSTEP_GNUSTEP_H_INCLUDED_ */ Renaissance-0.9.0/Source/Markup/0000775000076400007640000000000010770264727015774 5ustar nicolanicolaRenaissance-0.9.0/Source/Markup/GSMarkupDecoderBackend.h0000664000076400007640000001065610770007223022366 0ustar nicolanicola/* -*-objc-*- GSMarkupDecoderBackend.h Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002, November 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNUstep_H_GSMarkupDecoderBackend #define _GNUstep_H_GSMarkupDecoderBackend /* This class specifically mediates between the GSMarkupDecoder and * the backend SAX parser. At the moment we have support for four * separate backends: a NSXML (new FoundationKit API) backend, a GSXML * (gnustep-base's XML package) backend, a CFXML (CoreFoundation's XML * services) backend, and a pure libxml2 (GNOME XML library) backed. * To implement a backend you basically need to implement is basically * a new subclass of GSMarkupDecoderBackend: no need to touch the more * high level classes. This class basically builds and manages the * backend SAX parser, and creates a backend-specific SAX handler * which receives the calls from the backend SAX parser, in the way * specific to this backend parser. The backend SAX handler * interprets the calls, and reissues them to the GSMarkupDecoder in * the normalized form expected by it. */ /* In the future, we will use the NSXML decoder backend on all * platforms. At the moment, we temporarily use the GSXML on GNUstep * (so that it works with old gnustep-base releases as well as new * ones) and the NSXML one on Apple. If you want and have a recent * gnustep-base, you can use the NSXML one on GNUstep as well; it * should work fine. */ #ifndef GNUSTEP # include # include "GNUstep.h" /* On Apple Mac OSX, use NSXML backend. */ # define GSMARKUP_NSXML_BACKEND /* We used to use the CoreFoundation XML backend there. */ /* # define GSMARKUP_CFXML_BACKEND */ #else # include /* On GNUstep, use gnustep-base's GSXML backend. */ # define GSMARKUP_GSXML_BACKEND /* # define GSMARKUP_NSXML_BACKEND */ #endif /* The libxml2 backend will be used on OpenStep 4.x; if you want to * use it on GNUstep or Apple Mac OS X, uncomment the following lines * (you might then need to add manually the proper include/library * flags if you installed libxml2 in a custom location, which is why * it's simpler to use CFXML or GSXML). */ /* #undef GSMARKUP_CFXML_BACKEND #undef GSMARKUP_NSXML_BACKEND #undef GSMARKUP_GSXML_BACKEND #define GSMARKUP_LIBXML_BACKEND */ /* The backend object is created by calling the function * GSMarkupDecoderBackendForReadingFromData, which each backend * implementation implements to return an object of its own * GSMarkupDecoderBackend subclass. The return object should be ready * to start parsing when its 'parse' method is called. During * parsing, the platform-specific SAX parser will likely call private * callbacks in the backend class implementation, which should be * normalized/filtered by the backend class implementation, and handed * over to GSMarkupDecoder, by calling the few methods described in * GSMarkupDecoder.h for this purpose. */ @class NSObject; @class NSData; @class GSMarkupDecoder; @interface GSMarkupDecoderBackend : NSObject /* The following method will do the parsing; the actual implementation * is in the private subclass. */ - (void) parse; @end /* The following creates a GSMarkupDecoderBackend object (or more * likely an object of a private subclass), ready to parse `data' and * to send normalized SAX calls to `decoder'. Each concrete backend * implementation will implement it differently, to return an object * of a different subclass of GSMarkupDecoderBackend. */ GSMarkupDecoderBackend * GSMarkupDecoderBackendForReadingFromData (NSData *data, GSMarkupDecoder *decoder); #endif /* _GNUstep_H_GSMarkupDecoderBackend */ Renaissance-0.9.0/Source/Markup/GSMarkupTagInstance.h0000664000076400007640000000256107620074426021756 0ustar nicolanicola/* -*-objc-*- GSMarkupInstance.h Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNUstep_H_GSMarkupTagInstance #define _GNUstep_H_GSMarkupTagInstance #ifndef GNUSTEP # include #else # include #endif #include "GSMarkupTagObject.h" /* A tag representing an instance of a custom class to allocate. * Typically used for controller objects. */ @interface GSMarkupTagInstance : GSMarkupTagObject @end #endif /* _GNUstep_H_GSMarkupTagInstance */ Renaissance-0.9.0/Source/Markup/GSMarkupCoder.h0000664000076400007640000000711007620074426020605 0ustar nicolanicola/* -*-objc-*- GSMarkupCoder.h Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNUstep_H_GSMarkupCoder #define _GNUstep_H_GSMarkupCoder #ifndef GNUSTEP # include #else # include #endif #include "GSMarkupCoding.h" @class NSArray; @class NSData; @class NSMutableArray; @class NSMutableString; @class GSMarkupConnector; @class NSMutableDictionary; @interface GSMarkupCoder : NSObject { /* The objects to encode. */ NSArray *_objects; /* The connectors still to encode. While encoding objects, * we encode some connectors inside the objects. All these * connectors are removed from here, which is why this is * a mutable array. */ NSMutableArray *_connectors; /* The name table. Used only to encode connectors inside * objects. */ NSDictionary *_nameTable; /* The XML output. We assume little files so we do not optimize * for that - we just dump the whole file into _output, then write * _output to disk. */ NSMutableString *_output; /* The current indentation level in the XML output file. Opening a * tag adds 2 to indentation; closing one removes 2. */ int _indentation; /* Instance specific mapping from classes to tag names ; * normally empty, can be modified by calling * setTagName:forObjectClass: */ NSMutableDictionary *_objectClassToTagName; /* Instance specific mapping from classes to tag names inside * ; normally empty, can be modified by calling * setTagName:forConnectorClass: */ NSMutableDictionary *_connectorClassToTagName; } + (void) encodeObjects: (NSArray *)objects connectors: (NSArray *)connectors nameTable: (NSDictionary *)nameTable toFile: (NSString *)file; + (NSData *) encodeObjects: (NSArray *)objects connectors: (NSArray *)connectors nameTable: (NSDictionary *)nameTable; - (id) initWithObjects: (NSArray *)objects connectors: (NSArray *)connectors nameTable: (NSDictionary *)nameTable; - (NSData*) encode; - (BOOL) encodeToFile: (NSString *)file; /* Output an _indentation number of spaces (called before outputting * a tag definition. */ - (void) indent; - (void) encodeObject: (id )object; - (void) encodeConnector: (GSMarkupConnector *)connector; /* First looks in the instance hardcoded tables, then tries to extract * the tagName from the class by calling [class tagName]. */ - (NSString *) tagNameForObjectClass: (Class)c; - (NSString *) tagNameForConnectorClass: (Class)c; - (void) setTagName: (NSString *)tagName forObjectClass: (NSString *)className; - (void) setTagName: (NSString *)tagName forConnectorClass: (NSString *)className; @end #endif /* _GNUstep_H_GSMarkupCoder */ Renaissance-0.9.0/Source/Markup/GSMarkupLocalizer.h0000664000076400007640000000306107602477757021514 0ustar nicolanicola/* -*-objc-*- GSMarkupLocalizer.h Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _GNUstep_H_GSMarkupLocalizer #define _GNUstep_H_GSMarkupLocalizer #ifndef GNUSTEP # include #else # include #endif @class NSBundle; @class NSString; /* An object of this class is able to localize strings. */ @interface GSMarkupLocalizer : NSObject { /* Normally, the localizer just looks up strings in a table of a * bundle. */ NSBundle *_bundle; NSString *_table; } - (id) initWithTable: (NSString *)table bundle: (NSBundle *)bundle; - (NSString *) localizeString: (NSString *)string; @end #endif /* _GNUstep_H_GSMarkupLocalizer */ Renaissance-0.9.0/Source/Markup/GSMarkupDecoderBackend.m0000664000076400007640000000341210767273112022373 0ustar nicolanicola/* -*-objc-*- GSMarkupDecoderBackend.m Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002, November 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GSMarkupDecoderBackend.h" #include "GSMarkupDecoder.h" /* * This file includes different implementations for the different * platforms. Only one of them is actually used. The backend to use * is chosen in GSMarkupDecoderBackend.h. */ @implementation GSMarkupDecoderBackend - (void) parse { /* Implemented in the subclass. */ return; } @end #ifdef GSMARKUP_NSXML_BACKEND # include "DecoderBackend/GSMarkupDecoderBackendNSXML.m" #else # ifdef GSMARKUP_GSXML_BACKEND # include "DecoderBackend/GSMarkupDecoderBackendGSXML.m" # else # ifdef GSMARKUP_CFXML_BACKEND # include "DecoderBackend/GSMarkupDecoderBackendCFXML.m" # else # ifdef GSMARKUP_LIBXML_BACKEND # include "DecoderBackend/GSMarkupDecoderBackendLibXML.m" # endif # endif # endif #endif Renaissance-0.9.0/Source/Markup/GNUmakefile.standalone0000664000076400007640000000403510760645407022174 0ustar nicolanicola# # Copyright (C) 2002 Free Software Foundation, Inc. # # Author: Nicola Pero # # This file is part of GNUstep Renaissance. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Library General Public # License as published by the Free Software Foundation; either # version 2 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Library General Public License for more details. # # You should have received a copy of the GNU Library General Public # License along with this library; see the file COPYING.LIB. # If not, write to the Free Software Foundation, # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # This file is only for advanced/perverse users. # You can use this file to compile Markup as a standalone library. # Type 'make -f GNUmakefile.standalone' and a libgnustep-markup.so # will be built; headers will be installed into Markup/. This is # useful if you have your own tag library not related to gnustep-gui # or AppKit, and that you want to use in a project that does not link # against gnustep-gui or AppKit. If you use libgnustep-markup, make # sure you do not link libRenaissance as well - that wouldn't work. # You normally want Markup to compiled as part of Renaissance; the # standard GNUmakefile is used in that case - if that's what you are # trying to do, please ignore this makefile! MAKEFILE_NAME = GNUmakefile.standalone include $(GNUSTEP_MAKEFILES)/common.make LIBRARY_NAME = libgnustep-markup include GNUmakefile.files # Install the headers standalone libgnustep-markup_HEADER_FILES_INSTALL_DIR = Markup # Only for GNUstep.h on OSX ADDITIONAL_INCLUDE_DIRS += -I../ ADDITIONAL_OBJCFLAGS = -Wall # When compiled standalone, libgnustep-markup does not need # gnustep-gui. NEEDS_GUI = NO include $(GNUSTEP_MAKEFILES)/library.make Renaissance-0.9.0/Source/Markup/.cvsignore0000664000076400007640000000000407602500741017753 0ustar nicolanicola*objRenaissance-0.9.0/Source/Markup/GSMarkupBundleAdditions.h0000664000076400007640000001031707612630060022615 0ustar nicolanicola/* -*-objc-*- GSMarkupBundleAdditions.h Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ #ifndef _GNUstep_H_GSMarkupBundleAdditions #define _GNUstep_H_GSMarkupBundleAdditions #ifndef GNUSTEP # include #else # include # include #endif @class NSString; @class NSDictionary; @class NSMutableDictionary; @class NSNotification; @interface NSObject (GSMarkupAwaking) /* * This method is called, after the objects have been created and the * connections fully established. It is called for all objects * created from a gsmarkup which implement it, and for the file owner * if it implements it. */ - (void) awakeFromGSMarkup; @end /* The following notification is posted after the gsmarkup file has been * loaded. The notification object is the file owner (or nil if no file * owner was set); the userInfo is a dictionary, where the object for * the key 'NSTopLevelObjects' is the array of top-level objects which * have been loaded from the gsmarkup file. * * If the file owner responds to the -bundleDidLoadGSMarkup: method * below, it is automatically invoked passing the notification as * argument, so that you don't need to manually register the * file owner with the notification center. * * This stuff is useful if you need to keep track of the top-level * objects, so that you can easily destroy them when you no longer * need them. */ extern NSString *GSMarkupBundleDidLoadGSMarkupNotification; @interface NSObject (GSMarkupTopLevelObjects) /* If the file owner implements this method, NSBundle calls it * automatically, passing the GSMarkupBundleDidLoadGSMarkup * notification as argument. */ - (void) bundleDidLoadGSMarkup: (NSNotification *)aNotification; @end @interface NSBundle (GSMarkupBundleAdditions) + (BOOL) loadGSMarkupData: (NSData *)data withName: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table inBundle: (NSBundle *)bundle tagMapping: (NSDictionary *)mapping; + (BOOL) loadGSMarkupData: (NSData *)data withName: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table inBundle: (NSBundle *)bundle; + (BOOL) loadGSMarkupFile: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table inBundle: (NSBundle *)localizableStringsTableBundle; + (BOOL) loadGSMarkupFile: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone; + (BOOL) loadGSMarkupNamed: (NSString *)fileName owner: (id)owner; - (BOOL) loadGSMarkupFile: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table; - (BOOL) loadGSMarkupFile: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone; /* Return the array of localizable strings in the GSMarkup file. Raise an * exception if the file can't be parsed. */ + (NSArray *) localizableStringsInGSMarkupFile: (NSString *)fileName; /* fileName must include extension. */ - (NSString *) pathForLocalizedResource: (NSString *)fileName; @end #endif /* _GNUstep_H_GSMarkupBundleAdditions */ Renaissance-0.9.0/Source/Markup/GSMarkupBundleAdditions.m0000664000076400007640000004036110760645161022632 0ustar nicolanicola/* GSMarkupBundleAdditions GSMarkup Bundle Additions to load GSMarkup files Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: 2002 Resource searching code partially derived from gnustep-gui NSBundleAdditions.h by Richard Frith-Macdonald and Simon Frankau This file is part of GNUstep Renaissance. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GSMarkupBundleAdditions.h" #include "GSMarkupDecoder.h" #include "GSMarkupTagObject.h" #include "GSMarkupConnector.h" #include "GSMarkupAwaker.h" #include "GSMarkupLocalizer.h" NSString *GSMarkupBundleDidLoadGSMarkupNotification = @"GSMarkupBundleDidLoadGSMarkupNotification"; /* * In gnustep-gui applications, we want NSApp to be always available * from gsmarkup as '#NSApp'. More generally, it is possible to * register static objects so that they are available to all * gsmarkup loaded with a certain id. */ /* The private dictionary holding the static objects. */ static NSMutableDictionary *staticNameTable = nil; @interface NSBundle (GSMarkupBundleStaticObjects) /* The method to call to register a static object. The object * will be retained, and whenever a gsmarkup file is loaded, it will * be available with id 'itsId'. This method should/will probably * be public. */ + (void) registerStaticObject: (id)object withName: (NSString *)itsId; @end @implementation NSBundle (GSMarkupBundleStaticObjects) + (void) registerStaticObject: (id)object withName: (NSString *)itsId { if (staticNameTable == nil) { staticNameTable = [NSMutableDictionary new]; } [staticNameTable setObject: object forKey: itsId]; } @end /* * initStandardStaticNameTable() is a private function; it registers * NSApp as a static object (for gui applications only) the first time * that it is called; it does nothing when called again. We could * register other objects in the main table, maybe the MainBundle, or * NSProcessInfo. Or maybe it's better not to add more names as they * could conflict with ones defined in .gsmarkup files. */ static void initStandardStaticNameTable (void) { static BOOL didInit = NO; if (didInit) { return; } didInit = YES; { Class app = NSClassFromString (@"NSApplication"); if (app != Nil) { SEL selector = NSSelectorFromString (@"sharedApplication"); if (selector != NULL) { id sharedApp = [app performSelector: selector]; if (sharedApp != nil) { [NSBundle registerStaticObject: sharedApp withName: @"NSApp"]; } } } } } @implementation NSBundle (GSMarkupBundleAdditions) + (BOOL) loadGSMarkupFile: (NSString*)fileName externalNameTable: (NSDictionary*)context withZone: (NSZone*)zone { return [self loadGSMarkupFile: fileName externalNameTable: context withZone: zone localizableStringsTable: nil inBundle: nil]; } + (BOOL) loadGSMarkupFile: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table inBundle: (NSBundle *)bundle { NSData *data; if (fileName == nil) { return NO; } /* Add .gsmarkup if missing. */ if (![[fileName pathExtension] isEqual: @"gsmarkup"]) { fileName = [fileName stringByAppendingPathExtension: @"gsmarkup"]; } data = [NSData dataWithContentsOfFile: fileName]; return [self loadGSMarkupData: data withName: fileName externalNameTable: context withZone: zone localizableStringsTable: table inBundle: bundle]; } + (BOOL) loadGSMarkupData: (NSData *)data withName: (NSString*)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table inBundle: (NSBundle *)bundle { return [self loadGSMarkupData: data withName: fileName externalNameTable: context withZone: zone localizableStringsTable: table inBundle: bundle tagMapping: nil]; } + (BOOL) loadGSMarkupData: (NSData *)data withName: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table inBundle: (NSBundle *)bundle tagMapping: (NSDictionary *)mapping; { BOOL success = NO; if (data == nil) { return NO; } if (fileName == nil) { return NO; } /* If the table is not specified, translate stuff from a table with * the same name as the .gsmarkup file we are loading. */ if (table == nil) { table = [fileName stringByDeletingPathExtension]; table = [table lastPathComponent]; } /* If bundle is specified, use it; otherwise, use mainBundle. */ if (bundle == nil) { bundle = [NSBundle mainBundle]; } initStandardStaticNameTable (); /* Read the data. */ NS_DURING { NSArray *objects; NSMutableDictionary *nameTable; NSMutableDictionary *outputTable; NSArray *connectors; NSMutableArray *platformObjects; int i, count; NSEnumerator *e; NSString *key; NSMutableArray *topLevelObjects = nil; GSMarkupAwaker *awaker = [GSMarkupAwaker new]; AUTORELEASE (awaker); /* Parse the XML file. */ { GSMarkupDecoder *decoder; decoder = [[GSMarkupDecoder alloc] initWithData: data]; AUTORELEASE(decoder); if (mapping != nil) { e = [mapping keyEnumerator]; while ((key = [e nextObject]) != nil) { NSString *value = [mapping objectForKey: key]; [decoder setObjectClass: value forTagName: key]; } } [decoder parse]; objects = [decoder objects]; nameTable = [[decoder nameTable] mutableCopy]; AUTORELEASE (nameTable); connectors = [decoder connectors]; } /* Generate the platform objects from the decoded objects. */ platformObjects = [NSMutableArray arrayWithCapacity: [objects count]]; { GSMarkupLocalizer *localizer; localizer = [[GSMarkupLocalizer alloc] initWithTable: table bundle: bundle]; count = [objects count]; for (i = 0; i < count; i++) { GSMarkupTagObject *o; id platformObject; o = [objects objectAtIndex: i]; [o setLocalizer: localizer]; [o setAwaker: awaker]; /* platformObject is autoreleased. */ platformObject = [o platformObject]; if (platformObject != nil) { /* we need to RETAIN it (to balance this autorelease), * as per spec. */ RETAIN (platformObject); [platformObjects addObject: platformObject]; } } RELEASE (localizer); } /* Now update the nameTable replacing each decoded object with * its platformObject in the nameTable. */ /* Note that we can not use [nameTable keyEnumerator] because we * will be modifying the nameTable dictionary. So we first get * an array with all the keys, then we enumerate that one. */ e = [[nameTable allKeys] objectEnumerator]; while ((key = [e nextObject]) != nil) { id object = [nameTable objectForKey: key]; id platformObject = [object platformObject]; if (platformObject != nil) { [nameTable setObject: platformObject forKey: key]; } else { [nameTable removeObjectForKey: key]; } } /* Now extend the nameTable by adding the externalNameTable * (which contains references to object outside the GSMarkup * file). */ e = [context keyEnumerator]; while ((key = [e nextObject]) != nil) { id object = [context objectForKey: key]; /* NSTopLevelObjects is special ... if it exists, it is a * key to a mutable array where we store the top-level * objects so that the caller can access them. Inspired by * an undocumented feature of nib loading on other * platforms. */ if ([key isEqualToString: @"NSTopLevelObjects"] && [object isKindOfClass: [NSMutableArray class]]) { topLevelObjects = object; } else { [nameTable setObject: object forKey: key]; } } /* Now extend the nameTable adding the static objects (for example, * NSApp if it's a gui application). */ if (staticNameTable != nil) { [nameTable addEntriesFromDictionary: staticNameTable]; } /* Now establish the connectors. Our connectors can manage * the nameTable automatically. */ count = [connectors count]; for (i = 0; i < count; i++) { GSMarkupConnector *connector = [connectors objectAtIndex: i]; [connector establishConnectionUsingNameTable: nameTable]; } /* Register the NSOwner, if any, in the list of objects to * awake. */ { id fileOwner = [nameTable objectForKey: @"NSOwner"]; if (fileOwner != nil) { [awaker registerObject: fileOwner]; } } /* Now awake the objects. */ [awaker awakeObjects]; /* Done - finally send the notification that we loaded the * file. */ { id fileOwner = [nameTable objectForKey: @"NSOwner"]; NSMutableArray *objects = [NSMutableArray array]; NSNotification *n; /* Build the array of top-level objects for the * notification. */ count = [platformObjects count]; for (i = 0; i < count; i++) { id object = [platformObjects objectAtIndex: i]; [objects addObject: object]; } /* Create the notification. */ n = [NSNotification notificationWithName: GSMarkupBundleDidLoadGSMarkupNotification object: fileOwner userInfo: [NSDictionary dictionaryWithObject: objects forKey: @"NSTopLevelObjects"]]; /* Send the notification to the file owner manually. */ if (fileOwner != nil) { if ([fileOwner respondsToSelector: @selector (bundleDidLoadGSMarkup:)]) { [fileOwner bundleDidLoadGSMarkup: n]; } } /* Send the notification. */ [[NSNotificationCenter defaultCenter] postNotification: n]; } /* Save the objects in the user-provided NSTopLevelObjects * mutable array if there is one. */ if (topLevelObjects != nil) { count = [platformObjects count]; for (i = 0; i < count; i++) { id object = [platformObjects objectAtIndex: i]; [topLevelObjects addObject: object]; } } /* * Finally, pass back name table contents in the context if possible. */ outputTable = [context objectForKey: @"GSMarkupNameTable"]; if (outputTable != nil && [outputTable isKindOfClass: [NSMutableDictionary class]] == YES) { NSString *k; [outputTable removeAllObjects]; e = [nameTable keyEnumerator]; while ((k = [e nextObject]) != nil) { if ([context objectForKey: k] == nil) { [outputTable setObject: [nameTable objectForKey: k] forKey: k]; } } } success = YES; } NS_HANDLER { NSLog (@"Exception while reading %@: %@", fileName, localException); } NS_ENDHANDLER if (!success) { NSLog (@"Failed to load %@", fileName); } return success; } + (BOOL) loadGSMarkupNamed: (NSString *)fileName owner: (id)owner { NSDictionary *table; NSBundle *bundle; if (owner == nil || fileName == nil) { return NO; } table = [NSDictionary dictionaryWithObject: owner forKey: @"NSOwner"]; bundle = [self bundleForClass: [owner class]]; if (bundle == nil) { bundle = [self mainBundle]; } return [bundle loadGSMarkupFile: fileName externalNameTable: table withZone: NSDefaultMallocZone()]; } /* We really want a localized resource! This is not really relevant, * since .gsmarkup are not normally localized, but anyway might be useful * elsewhere and we want to add the facility from the * beginning. fileName must include extension. */ - (NSString *) pathForLocalizedResource: (NSString *)fileName { NSFileManager *mgr = [NSFileManager defaultManager]; NSMutableArray *array = [NSMutableArray arrayWithCapacity: 8]; NSArray *languages; NSString *rootPath = [self bundlePath]; NSString *primary; NSString *language; NSEnumerator *enumerator; #ifdef GNUSTEP languages = [NSUserDefaults userLanguages]; #else /* FIXME!! */ languages = [NSMutableArray arrayWithObject: @"English"]; #endif /* * Build an array of resource paths that differs from the normal order - * we want a localized file in preference to a generic one. */ #ifdef GNUSTEP primary = [rootPath stringByAppendingPathComponent: @"Resources"]; #else primary = [rootPath stringByAppendingPathComponent: @"Contents/Resources"]; #endif enumerator = [languages objectEnumerator]; while ((language = [enumerator nextObject])) { NSString *langDir; langDir = [NSString stringWithFormat: @"%@.lproj", language]; [array addObject: [primary stringByAppendingPathComponent: langDir]]; } [array addObject: primary]; primary = rootPath; enumerator = [languages objectEnumerator]; while ((language = [enumerator nextObject])) { NSString *langDir; langDir = [NSString stringWithFormat: @"%@.lproj", language]; [array addObject: [primary stringByAppendingPathComponent: langDir]]; } [array addObject: primary]; enumerator = [array objectEnumerator]; while ((rootPath = [enumerator nextObject]) != nil) { NSString *path; path = [rootPath stringByAppendingPathComponent: fileName]; if ([mgr isReadableFileAtPath: path]) { return path; } } return nil; } - (BOOL) loadGSMarkupFile: (NSString *)fileName externalNameTable: (NSDictionary *)context withZone: (NSZone *)zone localizableStringsTable: (NSString *)table; { NSString *path; if (![[fileName pathExtension] isEqual: @"gsmarkup"]) { fileName = [fileName stringByAppendingPathExtension: @"gsmarkup"]; } path = [self pathForLocalizedResource: fileName]; if (path != nil) { return [NSBundle loadGSMarkupFile: path externalNameTable: context withZone: zone localizableStringsTable: table inBundle: self]; } else { /* TODO/FIXME: Turn this into a debug log. */ NSLog (@"NSBundle(GSMarkupAdditions): File %@ not found - skipping loading", fileName); return NO; } } - (BOOL) loadGSMarkupFile: (NSString*)fileName externalNameTable: (NSDictionary*)context withZone: (NSZone*)zone { return [self loadGSMarkupFile: fileName externalNameTable: context withZone: zone localizableStringsTable: nil]; } + (NSArray *) localizableStringsInGSMarkupFile: (NSString *)fileName { NSMutableArray *strings = [NSMutableArray array]; if (fileName == nil) { return strings; } /* Add .gsmarkup if missing. */ if (![[fileName pathExtension] isEqual: @"gsmarkup"]) { fileName = [fileName stringByAppendingPathExtension: @"gsmarkup"]; } /* Read the file. */ { NSArray *objects; /* Parse the XML file and extract the objects. */ { GSMarkupDecoder *decoder; decoder = [GSMarkupDecoder decoderWithContentsOfFile: fileName]; [decoder parse]; objects = [decoder objects]; } /* Prepare the array of localizable strings. */ { int i, count; count = [objects count]; for (i = 0; i < count; i++) { GSMarkupTagObject *o = (GSMarkupTagObject *)[objects objectAtIndex: i]; NSArray *a = [o localizableStrings]; if (a != nil) { [strings addObjectsFromArray: a]; } } } /* FIXME/TODO: Need to purge duplicates in the array. */ } return strings; } @end Renaissance-0.9.0/Source/Markup/GSMarkupLocalizer.m0000664000076400007640000000465010554554756021521 0ustar nicolanicola/* -*-objc-*- GSMarkupLocalizer.m Copyright (C) 2002 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GSMarkupLocalizer.h" @implementation GSMarkupLocalizer - (id) initWithTable: (NSString *)table bundle: (NSBundle *)bundle; { ASSIGN (_bundle, bundle); ASSIGN (_table, table); return self; } - (void) dealloc { RELEASE (_bundle); RELEASE (_table); [super dealloc]; } - (NSString *) localizeString: (NSString *)string; { NSString *localized; /* Here we need to look for the string in a few tables, in order * of preference. Unfortunately, the normal API does not really * allow us to do it. There is no way to tell the libraries to * return nil or raise an exception when the string is not found, * so that we can be informed about it. */ localized = [_bundle localizedStringForKey: string value: nil table: _table]; /* To work around this, we compare the result against the original * string - which is just a hack, since the string might have been * found in the table, and mapped to itself: in that case, we should * really search no longer, but we can't tell this case from the case * that the string has not been found, so we go on looking in the next * table. */ if ([localized isEqualToString: @""] || [localized isEqualToString: string]) { /* Not found in the specified table ... try in * Localizable.strings. */ localized = [_bundle localizedStringForKey: string value: string table: nil]; } return localized; } @end Renaissance-0.9.0/Source/Markup/GSMarkupCoder.m0000664000076400007640000002651210554554756020632 0ustar nicolanicola/* -*-objc-*- GSMarkupCoder.m Copyright (C) 2002, 2003 Free Software Foundation, Inc. Author: Nicola Pero Date: March 2002, July 2003 This file is part of GNUstep Renaissance This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include "GSMarkupCoder.h" #include "GSMarkupConnector.h" /* * Return the same string after replacing special chars with their * entities - in practice, after replacing: * & with & * ' with ' * " with " * < with < * > with > */ static void _GSMarkupAppendXMLEscapedString (NSMutableString *mutable, NSString *original) { static NSCharacterSet *specials = nil; NSRange r; if (specials == nil) { specials = [NSCharacterSet characterSetWithCharactersInString: @"<>&'\""]; RETAIN(specials); } r = [original rangeOfCharacterFromSet: specials]; if (r.length > 0) { unsigned length = [original length]; unsigned lastSpecialChar = -1; while (r.length > 0) { unsigned i = r.location; if (lastSpecialChar + 1 < i) { r = NSMakeRange(lastSpecialChar+1, i-(lastSpecialChar+1)); [mutable appendString: [original substringWithRange: r]]; } switch ([original characterAtIndex: i]) { case '\'': [mutable appendString: @"'"]; break; case '\"': [mutable appendString: @"""]; break; case '<': [mutable appendString: @"<"]; break; case '>': [mutable appendString: @">"]; break; case '&': [mutable appendString: @"&"]; break; } lastSpecialChar = i++; r = [original rangeOfCharacterFromSet: specials options: NSLiteralSearch range: NSMakeRange(i, length - i)]; } if (lastSpecialChar + 1 < length) { r = NSMakeRange (lastSpecialChar+1, length - (lastSpecialChar+1)); [mutable appendString: [original substringWithRange: r]]; } } else { [mutable appendString: original]; } } @implementation GSMarkupCoder + (void) encodeObjects: (NSArray *)objects connectors: (NSArray *)connectors nameTable: (NSDictionary *)nameTable toFile: (NSString *)file { GSMarkupCoder *coder; coder = [[self alloc] initWithObjects: objects connectors: connectors nameTable: nameTable]; [coder encodeToFile: file]; RELEASE (coder); } + (NSData *) encodeObjects: (NSArray *)objects connectors: (NSArray *)connectors nameTable: (NSDictionary *)nameTable { GSMarkupCoder *coder; NSData *result; coder = [[self alloc] initWithObjects: objects connectors: connectors nameTable: nameTable]; result = [coder encode]; RETAIN (result); RELEASE (coder); AUTORELEASE (result); return result; } - (id) initWithObjects: (NSArray *)objects connectors: (NSArray *)connectors nameTable: (NSDictionary *)nameTable { NSMutableArray *connectorsCopy; ASSIGN (_objects, objects); /* Copy the connectors array since we need to modify it. */ connectorsCopy = [connectors mutableCopy]; ASSIGN (_connectors, connectorsCopy); RELEASE (connectorsCopy); ASSIGN (_nameTable, nameTable); ASSIGN (_objectClassToTagName, [NSMutableDictionary dictionary]); ASSIGN (_connectorClassToTagName, [NSMutableDictionary dictionary]); return self; } - (void) dealloc { RELEASE (_objects); RELEASE (_connectors); RELEASE (_nameTable); RELEASE (_objectClassToTagName); RELEASE (_connectorClassToTagName); [super dealloc]; } - (NSData*) encode { int i; int count; NSData *data; ASSIGN (_output, [NSMutableString string]); /* XML preamble. */ [_output appendString: @"\n\n\n\n"]; /* section. */ [_output appendString: @"\n"]; count = [_objects count]; for (i = 0; i < count; i++) { [self encodeObject: [_objects objectAtIndex: i]]; } [_output appendString: @"\n\n"]; /* section. */ [_output appendString: @"\n"]; count = [_connectors count]; for (i = 0; i < count; i++) { [self encodeConnector: [_connectors objectAtIndex: i]]; } [_output appendString: @"\n\n"]; /* XML postamble. */ [_output appendString: @"\n"]; data = [_output dataUsingEncoding: NSUTF8StringEncoding]; DESTROY (_output); return data; } - (BOOL) encodeToFile: (NSString *)file { NSData *d = [self encode]; return [d writeToFile: file atomically: YES]; } - (void) indent { int i; for (i = 0; i < _indentation; i++) { [_output appendString: @" "]; } } - (void) encodeObject: (id )object { NSMutableDictionary *attributes; NSString *tagName; NSArray *content; tagName = [self tagNameForObjectClass: [object class]]; if ([object attributes] != nil) { NSEnumerator *enumerator; NSString *key; attributes = [[object attributes] mutableCopy]; /* * If there are existing attributes with a leading '#', * we must escape them so they are not decoded as references. */ enumerator = [attributes keyEnumerator]; while ((key = [enumerator nextObject]) != nil) { NSString *value = [attributes objectForKey: key]; if ([value hasPrefix: @"#"]) { [attributes setObject: [@"#" stringByAppendingString: value] forKey: key]; } } } else { attributes = [NSMutableDictionary new]; } { NSArray *keys; keys = [_nameTable allKeysForObject: object]; if (keys != nil && [keys count] > 0) { int i; NSString *idName = [keys objectAtIndex: 0]; [attributes setObject: idName forKey: @"id"]; /* Now search the connectors for outlet connectors having this * object as the source. */ for (i = [_connectors count] - 1; i > -1; i--) { /* We cast it to GSMarkupOneToOneConnector. Next we'll * manually check that the cast was justified. */ GSMarkupOneToOneConnector *connector = [_connectors objectAtIndex: i]; if ([connector isKindOfClass: [GSMarkupOutletConnector class]]) { NSString *source = [connector source]; if ([source isEqualToString: idName]) { /* Found! Encode this into the object itself! */ [attributes setObject: [NSString stringWithFormat: @"#%@", [connector target]] forKey: [connector label]]; /* No longer need to encode this separately. */ [_connectors removeObjectAtIndex: i]; } } else if ([connector isKindOfClass: [GSMarkupControlConnector class]]) { NSString *source = [connector source]; if ([source isEqualToString: idName]) { /* Found! Encode this into the object itself! */ [attributes setObject: [NSString stringWithFormat: @"#%@", [connector target]] forKey: @"target"]; [attributes setObject: [connector label] forKey: @"action"]; /* No longer need to encode this separately. */ [_connectors removeObjectAtIndex: i]; } } } } } /* Now build the start tag. */ _indentation += 2; [self indent]; [_output appendString: @"<"]; [_output appendString: tagName]; { NSEnumerator *e = [attributes keyEnumerator]; NSString *key; while ((key = [e nextObject]) != nil) { NSString *value = [attributes objectForKey: key]; [_output appendString: @" "]; _GSMarkupAppendXMLEscapedString (_output, key); [_output appendString: @"=\""]; _GSMarkupAppendXMLEscapedString (_output, value); [_output appendString: @"\""]; } /* Do not close the start tag yet ... if there is no content, we * want to produce a start/close tag, such as