Bit by Bit: Opening Files
Stephen Beaulieu <hippo@be.com>

Rephrase inches towards usability. This week -- opening
files from the command line in Terminal. To make each
file open up in its own phrase window, type:

	Rephrase <space separated file names>

You can find this version of Rephrase at:

<ftp://ftp.be.com/pub/samples/tutorials/rephrase/rephrase0.1d2.zip>

Rephrase 0.1d2
New Features
Open Files from command line arguments at launch
Multiple Windows


Programming Concepts

You access files in BeOS through the classes of the
Storage Kit. Conceptually, the Storage Kit consists of
two types of objects: those representing a location in
a filesystem, and those representing the content at a
specific location.

The objects representing a location include:

* entry_ref -- a location expressed through a name, a
  directory token, and a volume token. entry_refs are
  usually the most efficient way to represent a location,
  but they must be converted to a more useful format to
  do much real work.

* BPath -- a convenience class representing a location
  as a string. It provides the means to manipulate and
  parse the path string. A path string is the appropriate
  method to persistently store a location, as an
  entry_ref's tokens can change across a reboot.

* BEntry -- a class representing a location. It provides
  information about that location, including whether a
  file exists there. It also provides facilities to
  rename, move, or remove a file at that location.

The content at a specific location is represented by
subclasses of BNode. This version of Rephrase deals
with one such class, the BFile, and only with it's
creation. The BFile is manipulated through the BTextView.

For more detailed information on the Storage Kit or on
BeOS installation see:
<http://www-classic.be.com/documentation/be_book/The%20Storage%20Kit/
index.html>

or:
<file:///boot/beos/documentation/Be%20Book/The%20Storage%20Kit/
index.html>

BApplication has a hook function ArgvReceived() that
passes in any command line arguments passed to the
application. Rephrase interprets these arguments as a
list of files to open. In ArgvReceived() Rephrase
translates each file name to a BEntry, and if there is
a file at that location, puts the appropriate entry ref
in a B_REFS_RECEIVED message, which it passes to
RefsReceived().

RefsReceived() is a BApplication hook function that
presents a BMessage with one or more entry_refs for
the app to process. In Rephrase, the appropriate
action is to open a new window for each specified
ref. In the future, the system will call RefsReceived()
when files are dropped onto the Rephrase binary. It
made sense to put the file opening code where it will
be used.


Implementation Details

1. If you accept command line arguments to open files,
   you should call RefsRecieved() directly from ArgvReceived().
   Why? The ReadyToRun() hook provides a last chance to
   prepare for user interaction. It is called after all
   launch-time messages have been handled. Posting the
   B_REFS_RECEIVED message results in ReadyToRun() being
   called before RefsReceived(). This creates the default
   phrase editing window in addition to any windows opened
   by RefsReceived(). This is not the intended behavior.
   [Rephrase.cpp:84-85]

2. Windows can call Show() in their constructor. This
   ensures that the window will be shown when created.
   Try to be consistent --  pick a place to call Show()
   and stick with it.
   [pDisplay.cpp:75]

3. An application that opens multiple windows should
   make the effort to ensure that they don't all open
   right on top of one another. The pDisplay class keeps
   track of the next position for a window. It tiles the
   windows across the screen in rows, until the screen
   is filled, then starts over.
   [pDisplay.cpp:140-167]

4. The BWindow and BView system lets you find a view by
   its name. BWindow::FindView() and BView::FindView()
   return a BView * with the given name if one exists.
   Use a safe casting mechanism to the appropriate BView
   subclass, and always make sure you actually have a
   view before acting on it. FindView() returns NULL if
   no view is found and dynamic_cast() returns NULL if
   the view is not of the specified type. When you need
   to refer to a specific view often, it's wiser to
   cache a pointer to the view when it is created.
   The BTextView will be an obvious choice as Rephrase
   develops.
   [pDisplay.cpp:123]

5. You can also search a BMenu hierarchy for BMenuItems
   with a given name. Accordingly, we don't hold onto
   a pointer to the "About Rephrase" item any longer,
   but simply look it up. Submenus added to a BMenu
   (which includes BMenuBars) have a BMenuItem created
   for them. To find a submenu, look for the BMenuItem
   with the correct name and call Submenu() to get the
   menu object.
   [pDisplay.cpp:60-66]

6. Instead of reading contents out of the file directly,
   Rephrase currently uses the version of BTextView::SetText()
   that accepts a BFile pointer as an argument. This is
   a matter of convenience in these early stages. In an
   upcoming installment we'll show how to read and write
   to the BFile.
   [pDisplay.cpp:131]

7. BMessage is a class that acts as a data container. It
   provides easy methods to add and find data and to
   query what types of data are available.
   [Rephrase.cpp:88-108]

8. I've fixed an off-by-one bug from 01.d1.  Views should not
   overlap: accordingly the BTextView should start one
   pixel below the end of the menu.
   [pDisplay.cpp:47]

Next Week: Resizing and Scroll bars



