
Hacking on Grr
==============

 Grr is a modular RSS Reader application. If you want to hack on it,
it's good to be familiar with NSBundles.

 When hacking on Grr, please try to stay within the bounds of your own
bundle and try to change as few as possible in the core application. If
you can't realise your task otherwise, please try to discuss your changes
with me (Guenther Noack, guenther@unix-ag.uni-kl.de) first, to ensure
maximal conformity to the application architecture.

 In short words, the patch policy is as follows:

	* I will revert changes in SVN to the Grr core that people haven't
	  asked me about first.

	* Patches going against the application architecture will not
	  be applied.


Grr components.
===============

 Grr components are NSBundle directories with a grrc (Grr components)
or grrdb (Grr Database) extension. They have a principal class which
conforms to the Component protocol defined in Components.h. Most of
them also conform to one of the extended component protocols in
Components.h.


Piping Grr components
=====================

 Many Grr components pipe output to each other. The components
involved in this piping are all components working with articles and
feeds. The piping components can have two distinctive abilities:

	* they accept input (protocol InputAcceptingComponent)
	* they provide output (protocol OutputProvidingComponent)

 Many components do both at the same time. For convenience, there's
a protocol called FilterComponent which is built from these two
protocols.

	EXAMPLES
	 A database component : Output Providing, because it's the
	component that reads the articles from the hard disk and
	hands them on to the other components to use.
	
	 A article view component : Input Accepting, because it
	just displays an article and doesn't hand it on.
 
 Many components also provide a NSView object for the application.
If such a component is a filtering component at the same time, it
typically allows the user to choose a subset of the received feeds
or articles in the view. This subset is then given as output.

	EXAMPLES
	 Filtering, view providing components: The component on the
	left of the main window, which allows to select feeds. The
	component on the top right, which allows to select an article
	which is then displayed in the component below.

 View providing components conform to the ViewProvidingComponent
protocol and can be easily created by inheriting from the class with
the same name.


The technical side of piping components
=======================================

 The piping mechanism is not very similar to the UNIX piping mechanism
for command line applications, as the piped data isn't evaluated on the
receiving side when it's still being piped. Components "piping" data from
one to another is basically just the handing around of pointers to NSSet
objects holding objects which all conform to the same protocol.

 The big idea behind the mechanism is that components are rowed up in a big
chain, where each filter component filters its input object set and outputs
a subset of it. On the left side of this chain, the database component
outputs the set of all articles known to the application. On the right side,
the article view component consumes a set of optimally just one article,
which is then displayed.

 Of course it's not that easy. :-> First of all, in reality, the row is a
tree. The component where the user selects the article to be viewed in the
article view component also pipes its output to another component, which
handles menu and toolbar items for all actions applying to articles.

 The second big disillusion is that components don't just pipe sets of
articles, but also sets of feeds and are theoretically able to pipe sets of
pretty much every object type. This is needed for special things like
the toolbar and menu for operations on feeds.

 Here's a small diagram of the Grr piping tree:

          Article Group &          Article
          Feed Selection -------> Selection -----> Article View
             Component            Component         Component
                 |                    |
                 |                    |
                 v                    v
          Feed Operations     Article Operations
          Toolbar & Menu        Toolbar & Menu

 (Note: The database component used to communicate using piping with the
Article Group & Feed Selection Component. When the database started to
support hierarchical structures and both components had to be rewritten,
this was changed to a more natural direct communication. Thus, it doesn't
appear in the piping tree any more.)

 In the following two subsections, I'll describe the technical aspects of
the two piping protocols (OutputProviding- and InputAcceptingComponent).


1. Output Providing Components
==============================

 An output providing component signals other components by sending a
ComponentDidUpdateNotification to the default notification center. It
sends itself as the notification's "object" value.

 Any InputAcceptingComponent which is registered for the notifications
of this component will now ask for the output using the output providing
component's -objectsForPipeType: method. The pipeType argument is just
a unique object identifying the type of objects contained in the piped
set. You can get a pointer to the used pipe types by using the class
methods of the PipeType class (e.g. [PipeType articleType]). 


2. Input Accepting Components
=============================

 An input accepting component is notified by a output providing component
when the output of that component changed. When this happens, a
-componentDidUpdateSet: message is sent to the input accepting component.

 Theoretically, it's possible to signal an OutputProvidingComponent's
notification via another message. It's easy to do using the notification
center, but should not be used in Grr. The convention to use exactly the
same method name again and again unifies the way components are connected.


Non-Piping Grr components
=========================

 Although most Grr components make use of piping, some of them don't.
If a component doesn't use piping, it typically provides a preference
panel. Of course, components without all that are also perfectly possible.


Writing a database component
============================

 A database component is basically just a loadable NSBundle directory,
whose principal class conforms to the Database protocol declared in
Database.h.

 A database component will specially want to implement the OutputProviding
protocol, although the connection to the component pipe tree can also be
handled in a separate class.

 The methods in the database protocol are easy to understand, very few, and
it's thus probably best just to point you to the source code of the Database
protocol here. It can be found in Database.h. If I'd explain it here instead,
it would just end up in me forgetting to update the documentation and people
complaining about it.

 What's more important about it is that you can get to playing around with
your own implementation quickly. Here's how you do it:

	* Create a new bundle project. Unlike all other types of Grr
	  components, the bundle extension has to be grrdb.
	
	* Make sure your bundle installs in Grr's installation domain
	  in the Library/Grr directory.
	
	* Set your "DatabasePluginName" user default for Grr to the name
	  of your bundle. For example, if your bundle is located in
	  "/opt/GNUstep/Local/Library/Grr/MyDatabaseBundle.grrdb", the
	  default needs to be set to "MyDatabaseBundle".

	* For testing, you will have to install everything and run Grr from
	  the place where you installed it to. If you want to run Grr with
	  your plugin from the source directory, place your bundle's source
	  in Grr's "Components" subdirectory, just like the other bundles.
	  Look into NSBundle+Extensions.m for details.

	* If you can't give out instances of articles and feeds as provided
	  by RSSKit, implement the Feed and Article protocols in your own
	  classes and hand these out. Reasons why you would want to do that
	  may be:
	  
	  	* You want to parse feeds using an other parser.
	  	* You want to parse feeds using RSSKit but store them in
	  	  a completely different format like when you're using the
	  	  Etoile CollectionKit. (Yen-Ju, that's you. :-))


