Probably the easiest was to show the path that the Tracker (or BNodeInfo
's
GetTrackerIcon()
method) uses for selecting a document's icon is through
a flowchart...
/\ / \ / \ / \ / \ / Does the \ / document \ Yes +----------------------+ / contain \----------->| Display document's | \ an icon / | icon attribute | \ attribute? / +----------------------+ \ / \ / \ / \ / \ / \/ | | No | V /\ / \ / \ / \ / \ / \ / Is it \ No / a known \---------------------------------------+ \ mime type? / | \ / | \ / | \ / | \ / | \ / | \ / | \/ | | | | Yes | | | V | /\ /\ | / \ / \ | / \ / \ | / \ / \ | / \ / \ | / \ / Does the \ | / Is there \ No / mime type \ No | / a handler \-----+----->/ setting file \-----------+ \ for the / | \ contain a / | \ mime type? / | \ meta icon / | \ / | \attribute?/ | \ / | \ / | \ / | \ / | \ / | \ / | \ / | \ / | \/ | \/ | | | | | | Yes | | Yes | | | | | V | V | /\ | +----------------------+ | / \ | | Display mime type's | | / \ | | meta icon attribute | | / \ | +----------------------+ | / Does \ | | / handler \ | | / contain \ No | | / an attribute \-----+ | \ icon for the / | \ mime type? / | \ / | \ / | \ / | \ / | \ / | \/ | | | | Yes | | | V | +----------------------+ +----------------------+ | | Display handler's | | Display generic |<-----+ | icon attribute | | document icon | +----------------------+ +----------------------+
'Icon' in the flowchart actually refers to two icons, a mini-icon (16 x
16) and a large icon (32 x 32). Both icons are 8-bits/pixel color
(B_CMAP8
). A mini-icon has an attribute type of 'MICN' and a large icon has
a type of 'ICON'.
For documents that contain icon attributes, the attribute names are 'BEOS:M:STD ICON' for mini-icons and 'BEOS:L:STD ICON' for large icons.
Applications that have icon attributes for documents concatinate 'BEOS:M:' (or 'BEOS:L:') with the mime type of the document for the attribute's name. For example, an image-editing application that saves to a private file format with a mime type of 'image/x-vnd.acme-bits' would contain icon attributes named 'BEOS:M:image/x-vnd.acme-bits' and 'BEOS:L:image/x-vnd.acme-bits'.
To programatically retrieve the Tracker icon for a file (also known as a
node), there's a BNodeInfo
method called (surprisingly)
GetTrackerIcon
.
GetTrackerIcon
takes a preconstructed bitmap of the correct size and
color space and an enum of the icon size to retrieve (B_MINI_ICON
or B_LARGE_ICON
). Given an entry_ref, here's an example...
BNode
node
(ref
); if (node
.InitCheck()
==B_NO_ERROR
) {BBitmap
*large_icon
;BBitmap
*mini_icon
;BNodeInfo
info
(&node
);large_icon
= newBBitmap
(BRect
(0, 0,B_LARGE_ICON
- 1,B_LARGE_ICON
- 1),B_CMAP8
); if (info
.GetTrackerIcon
(large_icon
,B_LARGE_ICON
) !=B_NO_ERROR
) { // handle error }mini_icon
= newBBitmap
(BRect
(0, 0,B_MINI_ICON
- 1,B_MINI_ICON
- 1),B_CMAP8
); if (info
.GetTrackerIcon
(mini_icon
,B_MINI_ICON
) !=B_NO_ERROR
) { // handle error } }
Setting an icon for a document is just as easy, given a bitmap of the correct size and color space...
info
.SetTrackerIcon
(large_icon
,B_LARGE_ICON
);info
.SetTrackerIcon
(mini_icon
,B_MINI_ICON
);
And to remove an icon from a document...
info
.SetTrackerIcon
(NULL
,B_LARGE_ICON
);info
.SetTrackerIcon
(NULL
,B_MINI_ICON
);
Here's a handy function for converting any bitmap to the correct size and color space, optionally maintaining the aspect ratio...
BBitmap
*ConvertBitmap
(BBitmap
*src
,BRect
dst
, color_spacecolor
, boolpreserve_aspect_ratio
) { // convert a bitmap from one size/color space into a different // size color space (possibly maintaining the aspect ratio) by // using the app servers DrawBitmap // create a temporary bitmap and attach a view to it so we // can draw into itBBitmap
*tmp
= newBBitmap
(dst
,color
,true
);BBitmap
*final
= newBBitmap
(dst
,color
);BView
*view
= newBView
(dst
, "",B_FOLLOW_ALL
,B_WILL_DRAW
);tmp
->AddChild
(view
);tmp
->Lock()
;view
->SetHighColor
(B_TRANSPARENT_32_BIT
);view
->FillRect
(dst
); if (preserve_aspect_ratio
) { floatf
;BRect
bounds
(src
->Bounds()
); if (bounds
.Width()
>bounds
.Height()
) { // leave width, adjust height to maintain aspect ratiof
=bounds
.Height()
/bounds
.Width()
*dst
.Height()
;dst
.top
=dst
.top
+ ((dst
.Height()
-f
) / 2);dst
.bottom
=dst
.top
+f
; } else { // leave height, adjust width to maintain aspect ratiof
=bounds
.Width()
/bounds
.Height()
*dst
.Width()
;dst
.left
=dst
.left
+ ((dst
.Width()
-f
) / 2);dst
.right
=dst
.left
+f
; } }view
->DrawBitmap
(src
,src
->Bounds()
,dst
); // we can draw do additional drawing at this point such as // placing a frame around the image or a 'bug' in the cornerview
->Sync()
;tmp
->Unlock()
; // copy bits from temporary bitmap into final bitmapmemcpy
(final
->Bits()
,tmp
->Bits()
,tmp
->BitsLength()
); // delete the temporary bitmap (deletes the attached view as well) deletetmp
; returnfinal
; }
Follow the ftp link below to grab some sample source that uses the above to create thumbnails for images and videos.
<ftp://ftp.be.com/pub/samples/graphics/Thumbnailer.zip
One of the powerful tools Tracker provides is the API for specific add-ons that only a small number of users may need. In a nonextensible windowing system, only general purpose features are available. For example, in browser development I often need to quickly and repeatedly FTP a file to a remote server, which is too simple a task to merit a full scale FTP client and would needlessly take up space on the majority of user's hard drives.
Enter a new Tracker add-on, FtpIt. Extending Howard's FtpClient object to include more messaging for state and status, FtpIt allows context menu choosing of files and folders for quick and dirty uploading. (See "Be Engineering Insights: Duty Now for the Future" for Howard's FTP client code.) While there are many possibilities for improvement in FtpIt (including secure display and saving of passwords, mulitple servers, alternate port numbers, and storage of specific servers for files or folders), this is a simplified example which should allow for easy extension.
You can get to the FtpIt source code here: <ftp://ftp.be.com/pub/samples/add-ons/FtpIt.zip>. Let's dive in!
When Tracker receives the message to instantiate the add-on, it spawns a
thread which calls the process_refs()
function. In FtpIt, this function
creates the FIWindow
and then waits for the window to quit. It's
important that process_refs()
not return before everything has been
completed and deleted, because without that context any threads you have
running will be stranded and Tracker will probably crash.
During the construction of the window, there are four main actions:
setting the working directory, creating the list of entries to FTP,
reading the settings file, and adding the ServerView
that will contain
the UI. If passed an entry ref to a folder, FtpIt will traverse the
folder and its children, adding all the paths to mPathList
and
calculating the total size of the transfer. This can take some time for
large numbers of files, which delays the window's Show()
call. Future
versions of FtpIt could split this process out into a seperate thread
with the ServerView UI indicating what is happening, but for simplicity's
sake we do it in the constructor.
The settings file (currently ~/config/settings/FtpIt/settings
) is used to
store the FTP server information. Presently, the information stored is
the hostname, the path, the username, the password, and whether the
connection should be passive or not. As with many BeOS application, FtpIt
stores its settings in attributes on a settings file. The FIWindow
's
ReadSettings
and WriteSettings
take care of the details of finding the
file and manipulating the attributes.
Now that the file list and settings are initialized, the ServerView is
created and displayed. From that point on, FtpIt is driven by user events
such as button or window messages. I don't have enough room here to go
through all the UI code, but the widgets used are basic. One point of
interest is the BNodeInfo::GetTrackerIcon
call which is used on the first
entry_ref in mPathList
to grab an icon for the
ServerView
.
The FtpClient
object is essentially the same as Howard's previous
newsletter article, with the addition of messaging of state. For example,
when the client completes a Send call, it relays that information to the
ServerView
in the form of a BMessage
.
ServerView
catches this in its
MessageReceived
and updates the status bar. Success or failure messages
are sent in a similar manner for the connect, get, and put calls.
Welcome back to our two-part look at the Translation Kit. I'm going to hold off on Part II as planned due to...
a small bug in the sample code from my last newsletter. Interestingly, it only shows up with certain plugins. Curiously, even the ones that work actually have the wrong behavior. So let's get to the bottom of this.
The issue here is how you request a format from a given translator. The correct way is to supply the 4-byte constant to the Translate() function. The bug involves using zero and assuming a certain behavior. For the record, passing zero to a translator means "Translate to the native BeOS format for that type."
Some of our translators took zero to mean "Translate to the opposite format of the input data," which happened to work with my code. Others tried to save as TranslatorBitmaps, and then unfortunately had a bug in their copy routines which resulted in only 32 bytes being written to disk.
Now the translators in the next release behave correctly when zero is passed in, and have working copy routines when the input and ouput data are in the same format. As a general rule, don't use zero—there are sure to be third-party add-ons that have undefined bahavior, too.
As for TranslatorPanel, it now queries on a translator id to determine which constant to use. The changes to the code are minimal.
To make up for this little slip, I've added some new features to TranslatorPanel, which you can find in the same spot as last time:
<ftp://ftp.be.com/pub/samples/translation_kit/TranslatorPanel.zip>
The primary additions are a C++ plugin architecture and live drag and drop to and from the Tracker.
Let's start with the plugins. I've whipped together a simple interface to run filters on the current image, and three sample filters in the add-ons directory. There is currently no way to configure the effect—it's just a "do it" kind of add-on. For a tutorial on writing add-ons, check out the excellent description in the Be Book under Images in the Kernel Kit.
The interface is very simple—every add-on subclasses ImageFilter and
provides a C hook to instantiate the class. It then sets up its name and
id in the constructor, and implements the Run()
function to do its work.
The add-on makefile sets the BUILDING_ADDON
flag to export its symbols;
the BeIDE project and makefile for the app do not, and therefore import
the symbols in ImageFilter.h
.
The rest is pretty simple. TranslatorPanel
builds a Filters Menu when the
program is launched by looking in its add-ons directory and trying to
find the instantiate()
hook in each file there. Those that load
successfully are inserted into a linked list, and the menu items are all
given the same what
field. To distinguish between the messages, a
"filter_id" field is added using ImageFilter::GetId()
. When a filter
message is received, TestView
iterates through the linked list and tries
to find a match.
The previous version of TranslatorPanel
let you drop images into the app,
but not drag them out. It also didn't give you any feedback. In this
update, when you drag a file over the app, it scans the mime type of the
file. If the supertype is "image," a blue border is drawn in the window
to indicate that the file type is understood.
Dragging the current image out to the Tracker is now also possible. A semitransparent version of the image is built and a three-step messaging protocol is negotiated. The app writes the current image wherever the Tracker reports the drop landed. For now, the image is hardcoded in Targa format.
The real trick here is how the drag starts. I wanted to discard casual
mouse clicks in the window, and only begin the drag session if the user
holds the button down for a certain duration. Rather than sleep in
TestView::MouseDown()
and tie up the window's thread, I set a boolean to
indicate that a drag may be starting, and then used a one time
BMessageRunner
to resume the drag initialization after the period of
time. If the user releases the mouse button before the message arrives,
TestView::MouseUp()
will have already
set the boolean to false
. If not,
the bitmap is built and passed to DragMessage()
.
Every year for the past 12, I've attended an industry conference called Agenda. The venue since 1991 has been the Phoenician, in Phoenix, Arizona. This is a very nice resort, built partly with taxpayer money -- thanks to the federally subsidized bailout of failed S&L (Savings and Loans, not Synergy and Leverage) real estate investments. The S&L can take pride in its free-market independence of government handouts.
By now, the real benefits of such conferences are well established. These gatherings are a benign, nerdy version of the Bohemian Grove. We go there to meet the brotherhood, people like us, more than for the contents of the sessions. Schmoozing in the hallways counts for more than the boiler plate of prepared speeches.
Of course, there are exceptions—occasionally, we see people who are not like us. And there's even the odd bit of real content in some of the artfully spun company manifestos—some of it voluntary. Among those present who were not like us was Rupert Murdoch, the media giant. He read a long speech about the future of his and our businesses combined. At least I think that what it was about. I asked around, and my brothers and sisters were not sure either. There was a brief, precious moment during the perfunctory question and answer period that followed the speech. Eric Raymond, the well-known, well-quoted Open Source advocate, stood up and asked our guest what he thought of the Open Source movement. I hope a tape exists of the look on Murdoch's face and of his brave recovery to make a heartfelt statement of his commitment to openness.
George W. Bush was another guest who was not like us, but the point of his before-dinner speech was easier to grasp. You are the American Dream incarnate. As your President, I'll make sure that more people believe in and have access to the American Dream. He even proposed some means to that end, ranging from tax cuts, to better legislation for technology, to more choices and accountability for education. The flattery worked, assisted by George W's warm, affable demeanour.
Al Gore was scheduled to give a talk and take questions by telephone later in the conference. We'll see how his brand of flattery works and how he fared with a crowd that was less than pleased with his gauche attempt to take some credit for the Internet, a point George W. gently rubbed in, without mentioning the claimant by name or title.
But there was more than the politics of politics—there was also computer industry politicking. Unfortunately, I have no revelations to bring you from that aspect of the gathering either. Exploiting the publicity around the "End of Moore's Law" question, Intel claimed that, yes, we were approaching an inflexion point, not right this minute, but maybe in a decade or so. Meanwhile, they would inflect their strategy, moving from making the building blocks of personal computing to building the key ingredients of e-business. How they will exert the kind of control on e-business that they have on the PC business was not explained.
Microsoft, no less predictably, claimed that the PC was approaching an inflexion point, a popular term this year, concurrent with the rise of Internet appliances. Microsoft added a little twist, saying that the inflexion point for PCs meant they would grow more rapidly in the future. And that there wouldn't be a shift from PCs to appliances, but rather more of both—more PCs and more appliances, from GSM telephones to Web TVs. In prior years such prophecies—about NetPCs, Zero Administration, pick a subject—drew retorts, attacks, controversy. This year, no one bothered. I find that reassuring.