Copyright © 2002 Ben Martin
Abstract
This paper details the key interactions of the ferriscp, gfcp, ferrismv, gfmv, ferrisrm, and gfrm clients with the ferris and ferrisui shared libraries. These clients accept the same command line options as the fileutils cp, rm and mv programs. Where API changes in the core library are anticipated they are mentioned in this paper so that the paper will be relevant to the newer versions of ferris as well as the current codebase. The paper aims to allow both the maintainer (given time away from the code) and other interested parties enough information to either add to existing clients or start creating new ones.
Table of Contents
Recent versions of ferris require gcc 3.0.4 or later gcc compiler versions to work. Because the ABI for C++ libraries changed at gcc 3 then all the C++ libraries that ferris requires must also be compiled with gcc 3.0.4. The author has tested that all libraries requiring this restriction compile and work with recent ferris and gcc 3.0.4. The subject of compilation and installation of ferris will likely be the matter of another paper because of the weighty requirements of modern ferris builds and the ability to compile and install modules either during ferris compilation or as an after thought. From here it is assumed that one has the sources for ferris and an installed version.
For each of the client types there is a basic_PopTableCollector subclass that presents command line options using popt. The use of basic_PopTableCollector revolves around defining custom versions of the following methods. Each basic_PopTableCollector keeps its popt data in instance variables which are to be reset to default values in void reset(). All options are placed in a custom popt table in struct ::poptOption* getTable( fh_cp _cp ) which can use the methods allocTable and setToCallbackEntry to create a suitable table and setEntry and clearEntry to populate the popt options. The instance variables that are set to command line options in getTable() are then processed in ArgProcessingDone( poptContext optCon ). Note that interaction with the poptContext object is not needed in the ArgProcessingDone() method. The usual pattern is to define a constructor that takes a reference to an object and sets that object's state in ArgProcessingDone(), and this is exactly what the tools in this paper do.
The core of each of the copy/remove/move operations are performed in the libferris code
| FerrisCopy | Defines a Ferrisls_long_display subclass which has set methods for all interesting options including src and dst, and perform and copy methods to begin the copy. |
| FerrisMove | Moving is an anomaly, it is either a plain rename of an object or a copy followed be a delete. The FerrisMv class thus only inherits from Handlable. It defines set methods for all interesting options which should be a mix of copy and remove options and a move method to begin the move. |
| FerrisRemove | Defines a Ferrisls_display subclass which has set methods for all interesting options including src and dst, and a remove method to begin the deletion. |
The core for FerrisMove, FerrisCopy and FerrisRemove all perform their actions and define signals that are fired when either information could be displayed to the user (such as when a few more blocks are copied in and a progress could be shown to the user) or when interaction is sought. An example of a signal that is fired for an interactive response is for cp -i when the user should be asked if they wish to replace an existing destination object. Some of these signals are connected to protected virtual methods in the FerrisMv, FerrisCopy and FerrisRm classes. This is for convenience in subclasses mainly.
There are two differing solutions to the signals emitted in the general code in FerrisMove, FerrisCopy and FerrisRemove. One is used by FerrisCopy by defining a subclass FerrisCopy_TTY that handles console based interaction. The other method is used by Remove and Move by defining the console interaction right into the main FerrisMove and FerrisRemove classes.
Graphical clients are created by defining a subclass of GTK_TreeWalkClient. Provided by GTK_TreeWalkClient are methods for creating the main window, displaying it and waiting for the user to choose to exit. There are virtual methods for adding new elements to the body of the window and for adding new notebook pages to the window which are called at the appropriate times.
Rather than just inheriting from FerrisRm and GTK_TreeWalkClient in the GTK2 remove client a delegation system was used so that the FerrisMv GTK2 client could use the GUI handling code of both Copy and Remove for its cross volume move. The following discusses the delegation system as it applies to the FerrisRm GTK2 client.
For FerrisRemove a class FerrisRm_SignalHandler is defined in FerrisRemoveUI.hh. The FerrisRm_SignalHandler connects to both its model, a FerrisRm object, and to a GUI, a GTK_TreeWalkClient. The SignalHandler attaches to the signal emitted by the FerrisRm object and updates the GUI when signals are emitted by the FerrisRm.
There is a special window class FileCompareWindow which is used by the graphical clients to display information about one or two fh_context objects (a fh_context is a file or directory) to the user and get a response. This window is used mainly for the -i option to the clients. FerrisRm defines a custom subclass of FileCompareWindow called FerrisRm_FileCompareWindow. The main methods that are overridden in the subclass are the dialog_yes, dialog_auto_yes, dialog_auto_no and dialog_no methods. These overridden methods correspond to the buttons shown in the FileCompareWindow object as shown in Figure 1.
Note that a simple yes/no response actions or declines this particular removal whereas the auto buttons collect current EA for the checked items in the auto column from that target and will respond either yes/no for items matching these criteria in the future. For example if both the "size-human-readable" row and the "writable" option were checked and "auto yes" pressed then all items with a size of 0 and that are writable will be automatically removed without interaction.gfcp uses the same style as gfrm with its own FerrisCopy_FileCompareWindow and FerrisCopy_SignalHandler. The FerrisCopy_SignalHandler takes both a GTK_TreeWalkClient and FerrisCopy at its constructor. The FerrisCopy_FileCompareWindow presents both the source and destination fh_context so that the user can decide what action to preform when the destination file exists and gfcp was invoked with -i.
The delegation method pays off for the hybrid gfmv. The gfmv client defines a class FerrisMove_GTK which is a subclass of FerrisMv and GTK_TreeWalkClient. The FerrisMove_GTK contains lazy initialized smart pointers to FerrisCopy, FerrisCopy_SignalHandler, FerrisRemove and FerrisRm_SignalHandler. The element of each SignalHandler that takes a GTK_TreeWalkClient is passed a pointer to the FerrisMove_GTK. This means for example that the FerrisCopy_SignalHandler will monitor the FerrisCopy and update the FerrisMove_GTK and present a FerrisCopy_FileCompareWindow for interactive copy mode. Likewise the FerrisRm_SignalHandler watches its FerrisRemove and updates the same GUI.
When the gfmv client discovers that the user wants to perform a cross volume move it first uses the FerrisCopy to clone the source and if all is well it then uses the FerrisRemove to wipe out the source. Because the FerrisCopy and FerrisRemove are never in action at the same time there is no contention for the GUI (FerrisMove_GTK) so everything works as desired.
The only covert to this method is that the gfmv client must make sure that the GUI has all of the elements that both FerrisCopy_SignalHandler and and FerrisRm_SignalHandler are expecting to be present.
This section describes some of the things one would need to do to create new graphical clients for libferris.
There are two main parts to a simple graphical client for libferris, the popt and command line part and the GTK_TreeWalkClient part. The popt part will either use a custom basic_PopTableCollector or process its command line directly. After option processing the source and if applicable destination URLs are collected from the command line, destination set, and source list iterated.
The bulk of the "real work" is in overridden methods of Ferrisls_display which will effect the GUI presented with the GTK_TreeWalkClient object. The easies method to achieve this is to subclass both GTK_TreeWalkClient and Ferrisls_display in a custom class. A Ferrisls object is needed to drive the tree visiting algorithm and should be connected to the Ferrisls_display object using Ferrisls::setDisplay. Other interesting options of Ferrisls are setURL for setting the base URL for the operation, setRecursiveList to recurse that URL, usePreorderTraversal to call the displays visit before recursing into the fh_context's children and operator()() to preform the operation.
The interesting methods in Ferrisls_display to override are now presented. The void workStarting() and void workComplete() methods are called when a tree is about to be traversed and when that tree traversal is done. A "tree" is only entered once for each invocation of Ferrisls::operator()() method. The void EnteringContext(fh_context ctx) and void LeavingContext(fh_context ctx) methods are called once for each fh_context and surround the main visitation method void ShowAttributes( fh_context ctx ). The first four methods are only provided as a convenience, the main method of interest is ShowAttributes.
For an example see the source code to gfrm.cpp.
Given that each client can be executed from the command line, these clients can be integrated with enlightenment 0.17, nautilus, ego, witme2, or any other file manager. A clipboard API (ClipAPI) using a filesystem as an underlying store is already planed. This ClipAPI will allow Cut+Paste and Copy+Paste operations to invoke gfcp and gfmv to provide both file movement and multilevel persistent undo. It may also be possible to allow for this ClipAPI to share its data in a network transparent manner with other login sessions (usually controlled by the one user) so that a copy can be performed on a local machine and a paste on a web server machine to put files there. The only difficulty in providing this is to be able to record and change the machine names and change them when the paste occurs on a machine other than the one that issued the copy operation.
For discussion about this document please use the Ferris mailing list or on irc.openprojects.net/#ferris.
[FerrisWebSite] Copyright © 2001 Ben Martin.
Ferris' web site
. .
[FerrisCreatePaper] Copyright © 2001 Ben Martin.
Ferris Creation paper
. .
[FerrisXSL1Paper] Copyright © 2002 Ben Martin.
Ferris XSLT and SQL paper
. .
[Apache handler manual]
Apache Handler Docs
. .
[QT]
Trolltech QT site
. .
[GTK+]
GTK+ The GIMP Toolkit
. .
[EWL]
Enlightenment Widget Library
. .
[XML W3C]
Extensible Markup Language
. .
[XSL W3C]
Extensible Stylesheet Language
. .
[XSD W3C]
XML Schema
. .
[Berkeley DB]
Sleepycat Software
. .
[MySQL]
MySQL website
. .
[BML]
Bean Markup Language
. .
[GNU CGICC website]
GNU CGICC
. .
[CGICC src rpm from makdrake Linux]
CGICC.src.rpm
. .
[ORA XSLT]
ORA XSLT
. .