I just realized how easy it is to add Trac search to the Firefox search engine widget. Yes, it's a not even "a small step for man", but it speeds one task up every-so-litte, which is always nice. And one image should be enough to explain:

Bits & Pixels by Marc Englund
The first one is a ComboBox: immediate, new items allowed, null selection disallowed.
The following is the CSS used to hide the regular ComboBox arrow and make it look like a textfield:
ComboBox cb = new ComboBox();
cb.setImmediate(true);
cb.setNewItemsAllowed(true);
cb.setNullSelectionAllowed(false);
cb.addStyleName("search");
cb.addListener(new ComboBox.ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
// do search
}
});
.i-filterselect-search .i-filterselect-button {
background-position: right 0;
width: 5px;
}
The second one is basically the above field, but the entered "tag" is added to the layout before the ComboBox, as a Button that removes itself when clicked:
cb = new ComboBox();
cb.setImmediate(true);
cb.setNewItemsAllowed(true);
cb.setNullSelectionAllowed(false);
cb.addStyleName("search");
cb.addListener(new ComboBox.ValueChangeListener() {
public void valueChange(ValueChangeEvent event) {
Object val = event.getProperty().getValue();
if (val != null) {
Button b = new Button(val + " ⊠",
new Button.ClickListener() {
public void buttonClick(ClickEvent event) {
tokenLayout.removeComponent(event.getButton());
tokenCount--;
}
});
b.setStyleName(Button.STYLE_LINK);
tokenLayout.addComponent(b, tokenCount++);
event.getProperty().setValue(null);
}
}
});
The third example is basically the previous one, vertically oriented and using FILTERINGMODE_CONTAINS instead of the default FILTERINGMODE_STARTSWITH to match anywhere (when entering last name or domain).
[...]
cb.setFilteringMode(ComboBox.FILTERINGMODE_CONTAINS);
[...]
The forth one is a little different; it's styled as a text that turns into a suggesting ComboBox when focused; hovering shows an arrow to indicate the text can be changed.
[...]
cb.setImmediate(true);
cb.setNullSelectionAllowed(false);
cb.setNewItemsAllowed(true);
cb.addStyleName("inplace");
[...]
.i-filterselect-inplace {
background: transparent none;
}
.i-filterselect-inplace input {
font-size: 18px;
border: 1px solid none;
}
.i-filterselect-inplace:hover input {
font-style: italic;
}
.i-filterselect-inplace input:focus {
background: #fff url(../default/textfield/img/bg.png) repeat-x;
border: 1px solid #b6b6b6;
border-top-color: #9d9d9d;
border-bottom-color: #d6d6d6;
border-right-color: #d6d6d6;
font-style: inherit;
font-size: inherit;
}
.i-filterselect-inplace .i-filterselect-button {
background: transparent none;
}
* html .i-filterselect-inplace .i-filterselect-button {
/* IE6 does not support :hover on div */
background: #f0f0f0 url(../default/select/img/arrow-down.png) no-repeat center 10px;
}
.i-filterselect-inplace:hover .i-filterselect-button,
.i-filterselect-inplace input:focus + .i-filterselect-button {
background: #f0f0f0 url(../default/select/img/arrow-down.png) no-repeat center 10px;
}
.i-filterselect-inplace input:focus + .i-filterselect-button {
background-color: transparent;
}
cb = new ComboBox();
cb.setWidth("70px");
for (int i=0; i
.i-filterselect-icon {
height: auto;
}
.i-filterselect-icon,
.i-filterselect-icon .i-filterselect-button {
background: transparent none;
}
.i-filterselect-icon input {
visibility: hidden;
}
.i-filterselect-icon:hover .i-filterselect-button,
.i-filterselect-icon input:focus + .i-filterselect-button {
background: #ffffff url(../default/select/img/arrow-down.png) no-repeat center 10px;
border: 1px solid #eeeeee;
margin-top: -25px;
}
* html .i-filterselect-icon .i-filterselect-button {
/* IE6 does not support :hover on div */
background: #ffffff url(../default/select/img/arrow-down.png) no-repeat center 10px;
border: 1px solid #eeeeee;
margin-top: -25px;
}