MessageView
is an IDE panel called the message pane that appears only as it is needed. Because there are multiple subsystems within the IDE that use the message pane, a tabbed interface
separates the subsystems. There is one MessageView
for each Browser
instance. You can't replace a MessageView
using the OpenTools API.
The
MessageCategory
class defines a MessageView
tab. When we speak of a tab in the message pane, we are referring to the tab and the page it displays as a unit. A MessageCategory
routes Message
objects to the correct tab as messages are added to the message pane. Usually the tab is the parent of a JComponent
that displays a tree, but you can provide a custom component. In fact, the run/debug console in JBuilder is a custom component.
Each
Message
object displays using its defined text, background color, foreground color, font, icon, context Action
, and tooltip attributes. To add a message to the MessageView
, call one of the several variants of the addMessage()
method, specifying the appropriate MessageCategory
.
Despite the appearance of being a text control, the MessageView
actually
contains a JTree
allowing
you to optionally generate a hierarchical view by specifying a parent Message
.
(This also means that you should not send extremely long blocks of text with embedded
carriage control or tab characters since they will not display as they
would in a text control.)
The Message
class accepts event notifications. When the user single-clicks a message in the message pane, the selectAction()
method is called. A double-click calls the messageAction()
method, which is the trigger of the event. If the user presses F1 while a message is selected in the message pane, the helpAction()
method is called. Implementing these events is optional.
MessageView
, call the Browser
getMessageView()
method. The Browser
also provides the isMessagePaneVisible()
and setMessagePaneVisible()
methods that are called when the user selects the View|Messages menu command.
MessageView
tab is defined from a
MessageCategory
object. You can choose from several possible constructors. The simplest one requires just the initial text for the tab, such as this example:
final static MessageCategory MYMESSAGES = new MessageCategory("MyMessages");
The MessageCategory
is always passed as a parameter in either one of the many variants of the addMessage()
method or in the addCustomTab()
method. If the passed MessageCategory
describes a tab that doesn't yet exist, then a new tab is created before the message is added to it. For example, this code adds the new tab labeled "MyMessages" to the MessageView
and adds the message that displays "This is a test.":
final static MessageCategory MYMESSAGES = new MessageCategory("MyMessages"); Browser.getMessageView().addMessage(MYMESSAGES, new Message("This is a test."));If you have created a custom component to display the tab content, that component supplies all the UI inside that tab. Therefore, calling the
MessageView
addMessage()
method would result in an exception. To create a custom tab, call the MessageView
addCustomTab()
method, passing to it the MessageCategory
and the custom component. For example,
JComponent c = new MyCustomPanel(); Browser.getMessageView().addCustomTab(MYMESSAGES, c);
JTree
inside a JScrollPane
. You can create a message hierarchy with code like this:
MessageView mv = Browser.getActiveBrowser().getMessageView(); Message msg = mv.addMessage(MYMESSAGES, new Message("This is test.")); mv.addMessage(MYMESSAGES, msg, new Message("This is a child of test."));
If messages are added to the MessageView
with addMessage()
calls that don't supply a parent Message
, the tree appears flat like a text area.
MessageView
provides several
UpdateAction
and
BrowserAction
objects that are tied to the user interface.
Some apply against a particular Message
object (expand, next, prior), a
particular tab (clear, copy content, remove), and against all tabs (hide, remove
all).
ACTION_CopyContent
attempts to work against tab
content in a way that might also work with a custom component. It assumes
that within the component hierarchy there exists either a JTree
or a
JTextArea
. When it is invoked with a keystroke or a click on a context menu, it tries to identify the key component and copies the selected portion (or if none is selected, then the entire content) to the clipboard.
MessageView
calls the MessageCategory
methods
categoryActivated()
, categoryDeactivated()
, and categoryClosing()
at the appropriate times. You might find them useful when you are implementing a custom tab. You can also use a PropertyChangeListener
class for
notification if the icon, tooltip, or title of the MessageCategory
changes.
Message
object represents a single message line in the
MessageView
. Its text is displayed using any font, background color, and/or foreground color settings it defines. (Font changes are currently disabled here and elsewhere in the IDE.)
If you are using a message hierarchy, you might want to take advantage of the
setLazyFetchChildren()
and fetchChildren()
methods.
They allow you to create a parent Message
yet not supply its children
until later when the user decides to expand it. Here's an example that shows you how to do it:
public class ParentMessage extends Message { public ParentMessage() { setLazyFetchChildren(true); } public void fetchChildren(Browser browser) { MessageView mv = browser.getMessageView(); mv.addMessage(MYMESSAGES, this, new Message("This is my child.")); } }
If the user selects a Message
by using the keyboard arrow keys to
navigate through the message tree or by single-clicking the message, then either the selectAction()
method or an Action
specified by setSelectAction()
method is called. If this is the type of interface you want, you should highlight the UI element that is associated with that Message
.
If the user triggers a Message
by using the Enter key or
double-clicking, then either messageAction()
or an Action
specified by
setMessageAction()
is called. If this is the type of interface you want, you should move the focus to the UI element that is associated with that Message
.
This example assumes that when the Message
was created, it was associated with a known
TextFileNode
and a particular location in that file. (Refer to
LineMark
and
EditorPane
for more details about how this works.)
TextFileNode fileNode; int line; int column; static final LineMark MARK = new HighlightMark(); public void selectAction(Browser browser) { displayResult(browser, false); } public void messageAction(Browser browser) { displayResult(browser, true); } private void displayResult(Browser browser, boolean requestFocus) { try { if (requestFocus || browser.isOpenNode(fileNode)) { browser.setActiveNode(fileNode, requestFocus); TextNodeViewer viewer = (TextNodeViewer)browser.getViewerOfType(fileNode, TextNodeViewer.class); browser.setActiveViewer(fileNode, viewer, requestFocus); EditorPane editor = viewer.getEditor(); editor.gotoPosition(line, column, false, EditorPane.CENTER_IF_NEAR_EDGE); if (requestFocus) editor.requestFocus(); else editor.setTemporaryMark(line, MARK); } } catch (Exception ex) { ex.printStackTrace(); } public static class HighlightMark extends LineMark { static Style highlightStyle; static { StyleContext context = EditorManager.getStyleContext(); highlightStyle = context.addStyle("line_highlight", null); highlightStyle.addAttribute(MasterStyleContext.DISPLAY_NAME, "Line highlight"); StyleConstants.setBackground(highlightStyle, Color.yellow); StyleConstants.setForeground(highlightStyle, Color.black); } public HighlightMark() { super(highlightStyle); } }
If the user presses F1 when the Message
has the focus, its helpAction()
method is called if no Action
was supplied by setHelpAction()
.
Each Message
can supply an
Action
or
ActionGroup
through the getContextAction()
method so that a pop-up menu appears if the user right-clicks it.
If you want a Message
to appear as something other than a text string, specify a TreeCellRenderer
using the setCellRenderer()
method.