/******************************************************************************* * Copyright (c) 2004, 2008 Composent, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Composent, Inc. - initial API and implementation * Jacek Pospychala <jacek.pospychala@pl.ibm.com> - bug 192762, 197329, 190851 * Abner Ballardo <modlost@modlost.net> - bug 192756, 199336, 200630 * Jakub Jurkiewicz <jakub.jurkiewicz@pl.ibm.com> - bug 197332 * Hiroyuki Inaba <Hiroyuki <hiroyuki.inaba@gmail.com> - bug 222253 ******************************************************************************/ package org.eclipse.ecf.presence.ui.chatroom; import java.net.URI; import java.net.URISyntaxException; import java.text.SimpleDateFormat; import java.util.*; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.ecf.core.IContainerListener; import org.eclipse.ecf.core.events.*; import org.eclipse.ecf.core.identity.*; import org.eclipse.ecf.core.security.ConnectContextFactory; import org.eclipse.ecf.core.user.IUser; import org.eclipse.ecf.core.util.ECFException; import org.eclipse.ecf.internal.presence.ui.*; import org.eclipse.ecf.internal.presence.ui.preferences.PreferenceConstants; import org.eclipse.ecf.internal.ui.actions.SelectProviderAction; import org.eclipse.ecf.presence.*; import org.eclipse.ecf.presence.chatroom.*; import org.eclipse.ecf.presence.im.IChatID; import org.eclipse.ecf.presence.im.IChatMessage; import org.eclipse.ecf.presence.ui.MessagesView; import org.eclipse.jface.action.*; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.text.*; import org.eclipse.jface.text.source.SourceViewer; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.*; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; import org.eclipse.ui.*; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.part.ViewPart; import org.eclipse.ui.progress.IWorkbenchSiteProgressService; public class ChatRoomManagerView extends ViewPart implements IChatRoomInvitationListener { public ChatRoomManagerView() { } private static final String ATSIGN = "@"; //$NON-NLS-1$ public static final String VIEW_ID = "org.eclipse.ecf.presence.ui.chatroom.ChatRoomManagerView"; //$NON-NLS-1$ public static final String PARTICIPANTS_MENU_ID = "org.eclipse.ecf.presence.ui.chatroom.participantsView"; //$NON-NLS-1$ private static final int RATIO_READ_WRITE_PANE = 85; private static final int RATIO_PRESENCE_PANE = 15; protected static final int DEFAULT_INPUT_HEIGHT = 25; protected static final int DEFAULT_INPUT_SEPARATOR = 5; private CTabFolder rootTabFolder = null; private ChatRoomTab rootChannelTab = null; private IChatRoomViewCloseListener rootCloseListener = null; private IChatRoomMessageSender rootMessageSender = null; /** * UI independent renderer, that is aware of displaying any special fragments * of message, like formatting, graphical attachments, emotional content, etc. */ private IMessageRenderer messageRenderer = null; Action outputClear = null; Action outputCopy = null; Action outputPaste = null; Action outputSelectAll = null; boolean rootDisposed = false; private boolean rootEnabled = false; private Hashtable chatRooms = new Hashtable(); private IChatRoomCommandListener commandListener = null; private IChatRoomContainer container = null; private String localUserName = Messages.ChatRoomManagerView_DEFAULT_USER; private String hostName = Messages.ChatRoomManagerView_DEFAULT_HOST; private CTabItem infoTab; private boolean fClearInfoTab = true; class ChatRoomTab { private SashForm fullChat; private CTabItem tabItem; private Composite rightComposite; private StyledText subjectText; private StyledText outputText; private Text inputText; private Label participantsNumberLabel; private TableViewer participantsTable; private Action tabSelectAll; private Action tabCopy; private Action tabClear; private Action tabPaste; private boolean withParticipants; ChatRoomTab(CTabFolder parent, String name) { this(true, parent, name, null); } ChatRoomTab(boolean withParticipantsList, CTabFolder parent, String name, KeyListener keyListener) { withParticipants = withParticipantsList; tabItem = new CTabItem(parent, SWT.NULL); tabItem.setText(name); if (withParticipants) { fullChat = new SashForm(parent, SWT.HORIZONTAL); fullChat.setLayout(new FillLayout()); Composite memberComp = new Composite(fullChat, SWT.NONE); GridLayout layout = new GridLayout(1, true); layout.marginWidth = 0; layout.marginHeight = 0; memberComp.setLayout(layout); participantsNumberLabel = new Label(memberComp, SWT.BORDER | SWT.READ_ONLY); participantsNumberLabel.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); participantsNumberLabel.setAlignment(SWT.CENTER); participantsTable = new TableViewer(memberComp, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI); participantsTable.setSorter(new ViewerSorter()); participantsTable.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); participantsTable.addOpenListener(new IOpenListener() { public void open(OpenEvent event) { IStructuredSelection selection = (IStructuredSelection) event.getSelection(); String user = ((ChatRoomParticipant) selection.getFirstElement()).getName(); if (!ChatRoomManagerView.this.localUserName.equals(user)) { try { MessagesView messagesView = getMessagesView(); messagesView.selectTab(container.getPrivateMessageSender(), null, createStringID(localUserName), createStringID(user), user); getSite().getPage().activate(messagesView); } catch (PartInitException e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, NLS.bind(Messages.ChatRoomManagerView_EXCEPTION_MESSAGE_VIEW_INITIALIZATION, user), e)); } } } }); rightComposite = new Composite(fullChat, SWT.NONE); layout = new GridLayout(1, true); layout.marginHeight = 0; layout.marginWidth = 0; rightComposite.setLayout(layout); subjectText = createStyledTextWidget(rightComposite, SWT.SINGLE | SWT.BORDER); subjectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); /* * The sendSubjectChange method in Smack 2.2.1 does not seem to be working correctly, so this whole block * can be temporily removed. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=223560 subjectText.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent evt) { if (evt.character == SWT.CR || evt.character == SWT.KEYPAD_CR) { ChatRoom chatroom = (ChatRoom) chatRooms.get(tabItem.getText()); if (chatroom != null) { IChatRoomAdminSender chatRoomAdminSender = chatroom.chatRoomContainer.getChatRoomAdminSender(); try { if (chatRoomAdminSender != null) { chatRoomAdminSender.sendSubjectChange(subjectText.getText()); } } catch (ECFException e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, "sendSubjectChange", e));disconnected(); //$NON-NLS-1$ } } } } }); */ subjectText.setEditable(false); subjectText.setEnabled(false); } else { rightComposite = new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(1, true); layout.marginHeight = 0; layout.marginWidth = 0; rightComposite.setLayout(layout); } outputText = createStyledTextWidget(rightComposite, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI | SWT.READ_ONLY); outputText.setEditable(false); outputText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); inputText = new Text(rightComposite, SWT.BORDER | SWT.MULTI | SWT.WRAP | SWT.V_SCROLL); GridData gd = new GridData(SWT.FILL, SWT.CENTER, true, false); GC gc = new GC(inputText); gc.setFont(inputText.getFont()); FontMetrics fontMetrics = gc.getFontMetrics(); gc.dispose(); gd.heightHint = fontMetrics.getHeight() * 2; inputText.setLayoutData(gd); if (keyListener != null) inputText.addKeyListener(keyListener); if (withParticipants) { fullChat.setWeights(new int[] {RATIO_PRESENCE_PANE, RATIO_READ_WRITE_PANE}); tabItem.setControl(fullChat); } else tabItem.setControl(rightComposite); parent.setSelection(tabItem); makeActions(); hookContextMenu(); if (withParticipants) { hookParticipantsContextMenu(); } StyledText st = getOutputText(); if (st != null) { ScrollBar vsb = st.getVerticalBar(); if (vsb != null) { vsb.addSelectionListener(scrollSelectionListener); vsb.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { StyledText ot = getOutputText(); if (ot != null) { ScrollBar sb = ot.getVerticalBar(); if (sb != null) sb.removeSelectionListener(scrollSelectionListener); } } }); } } } private SelectionListener scrollSelectionListener = new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // do nothing } public void widgetSelected(SelectionEvent e) { if (!isLastOutputInvisible(getOutputText())) { makeTabItemNormal(); } } }; protected void makeTabItemBold() { changeTabItem(true); } protected void makeTabItemNormal() { changeTabItem(false); } protected void changeTabItem(boolean bold) { CTabItem item = tabItem; Font oldFont = item.getFont(); FontData[] fd = oldFont.getFontData(); item.setFont(new Font(oldFont.getDevice(), fd[0].getName(), fd[0].getHeight(), (bold) ? SWT.BOLD : SWT.NORMAL)); } private StyledText createStyledTextWidget(Composite parent, int styles) { SourceViewer result = null; try { result = new SourceViewer(parent, null, null, true, styles); } catch (NoClassDefFoundError e) { Activator.getDefault().getLog().log(new Status(IStatus.WARNING, Activator.PLUGIN_ID, IStatus.WARNING, Messages.ChatRoomManagerView_WARNING_HYPERLINKING_NOT_AVAILABLE, e)); return new StyledText(parent, styles); } result.configure(new ChatRoomViewerConfiguration(EditorsUI.getPreferenceStore(), container, ChatRoomManagerView.this)); result.setDocument(new Document()); return result.getTextWidget(); } protected void outputClear() { if (MessageDialog.openConfirm(null, Messages.ChatRoomManagerView_CONFIRM_CLEAR_TEXT_OUTPUT_TITLE, Messages.ChatRoomManagerView_CONFIRM_CLEAR_TEXT_OUTPUT_MESSAGE)) { outputText.setText(""); //$NON-NLS-1$ } } protected void outputCopy() { String t = outputText.getSelectionText(); if (t == null || t.length() == 0) { outputText.selectAll(); } outputText.copy(); outputText.setSelection(outputText.getText().length()); } private void fillContextMenu(IMenuManager manager) { manager.add(tabCopy); manager.add(tabPaste); manager.add(tabClear); manager.add(new Separator()); manager.add(tabSelectAll); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } private void hookContextMenu() { MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fillContextMenu(manager); } }); Menu menu = menuMgr.createContextMenu(outputText); outputText.setMenu(menu); ISelectionProvider selectionProvider = new ISelectionProvider() { public void addSelectionChangedListener(ISelectionChangedListener listener) { // do nothing } public ISelection getSelection() { ISelection selection = new TextSelection(outputText.getSelectionRange().x, outputText.getSelectionRange().y); return selection; } public void removeSelectionChangedListener(ISelectionChangedListener listener) { // do nothing } public void setSelection(ISelection selection) { if (selection instanceof ITextSelection) { ITextSelection textSelection = (ITextSelection) selection; outputText.setSelection(textSelection.getOffset(), textSelection.getOffset() + textSelection.getLength()); } } }; getSite().registerContextMenu(menuMgr, selectionProvider); } private void hookParticipantsContextMenu() { MenuManager menuMgr = new MenuManager(); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } }); menuMgr.setRemoveAllWhenShown(true); Control control = participantsTable.getControl(); Menu menu = menuMgr.createContextMenu(control); control.setMenu(menu); getSite().registerContextMenu(PARTICIPANTS_MENU_ID, menuMgr, participantsTable); } private void makeActions() { tabSelectAll = new Action() { public void run() { outputText.selectAll(); } }; tabSelectAll.setText(Messages.ChatRoomManagerView_SELECT_ALL_TEXT); tabSelectAll.setToolTipText(Messages.ChatRoomManagerView_SELECT_ALL_TOOLTIP); tabSelectAll.setAccelerator(SWT.CTRL | 'A'); tabCopy = new Action() { public void run() { outputCopy(); } }; tabCopy.setText(Messages.ChatRoomManagerView_COPY_TEXT); tabCopy.setToolTipText(Messages.ChatRoomManagerView_COPY_TOOLTIP); tabCopy.setAccelerator(SWT.CTRL | 'C'); tabCopy.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_COPY)); tabClear = new Action() { public void run() { outputClear(); } }; tabClear.setText(Messages.ChatRoomManagerView_CLEAR_TEXT); tabClear.setToolTipText(Messages.ChatRoomManagerView_CLEAR_TOOLTIP); tabPaste = new Action() { public void run() { getInputText().paste(); } }; tabPaste.setText(Messages.ChatRoomManagerView_PASTE_TEXT); tabPaste.setToolTipText(Messages.ChatRoomManagerView_PASTE_TOOLTIP); tabPaste.setAccelerator(SWT.CTRL | 'V'); tabPaste.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_PASTE)); } protected Text getInputText() { return inputText; } protected void setKeyListener(KeyListener listener) { if (listener != null) inputText.addKeyListener(listener); } protected Label getParticipantsLabel() { return participantsNumberLabel; } protected TableViewer getParticipantsViewer() { return participantsTable; } /** * @return the <tt>StyledText</tt> widget that is displaying the output of the chatroom */ public StyledText getOutputText() { return outputText; } public void setSubject(String subject) { subjectText.setText(subject); } } public void createPartControl(Composite parent) { Composite rootComposite = new Composite(parent, SWT.NONE); rootComposite.setLayout(new FillLayout()); boolean useTraditionalTabFolder = PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS); rootTabFolder = new CTabFolder(rootComposite, SWT.NORMAL | SWT.CLOSE); rootTabFolder.setUnselectedCloseVisible(false); rootTabFolder.setSimple(useTraditionalTabFolder); populateInfoTab(getInfoTabControl(SWT.NONE, "Info", true)); //$NON-NLS-1$ PlatformUI.getPreferenceStore().addPropertyChangeListener(new IPropertyChangeListener() { public void propertyChange(PropertyChangeEvent event) { if (event.getProperty().equals(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS) && !rootTabFolder.isDisposed()) { rootTabFolder.setSimple(((Boolean) event.getNewValue()).booleanValue()); rootTabFolder.redraw(); } } }); rootTabFolder.addCTabFolder2Listener(new CTabFolder2Adapter() { public void close(CTabFolderEvent event) { event.doit = closeTabItem((CTabItem) event.item); } }); } /** * This enables IM providers to provide additional information about the provider by asking the creation of a separate information tab. This information is displayed in a separate info tab. * * @param style with additional information about the provider * @param title * @param clearInfoTab set to true if the tab must be cleared when population of the view begins. * @return the Composite to draw on * @since 2.2 */ public Composite getInfoTabControl(int style, String title, boolean clearInfoTab) { // dispose old tab if (infoTab != null) infoTab.dispose(); CTabItem tab = new CTabItem(rootTabFolder, style); tab.setText(title); // assign new tab this.infoTab = tab; this.fClearInfoTab = clearInfoTab; Composite parent = new Composite(rootTabFolder, SWT.NONE); parent.setLayout(new FillLayout()); tab.setControl(parent); rootTabFolder.setSelection(tab); return parent; } /** * Creates a tab with view information. This view does nothing when it is opened manually. This tab is used to provide that information. */ private void populateInfoTab(Composite parent) { Link link = new Link(parent, SWT.NONE); link.setText("\n This view is not intended to be opened as a standalone view. Please select one of the <a>IM Providers</a> to open a populated view."); //$NON-NLS-1$ link.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { SelectProviderAction action = new SelectProviderAction(); action.init(ChatRoomManagerView.this.getSite().getWorkbenchWindow()); action.run(null); } }); } private boolean closeTabItem(CTabItem tabItem) { ChatRoom chatRoom = findChatRoomForTabItem(tabItem); if (chatRoom == null) { return true; } if (MessageDialog.openQuestion(getSite().getShell(), Messages.ChatRoomManagerView_CLOSE_CHAT_ROOM_TITLE, NLS.bind(Messages.ChatRoomManagerView_CLOSE_CHAT_ROOM_MESSAGE, tabItem.getText()))) { chatRoom.chatRoomDisconnect(); return true; } return false; } public IChatRoomContainer getRootChatRoomContainer() { return container; } /** * @return a list of IChatRoomContainer for each open channel * or an empty array if there are no channels open. * @since 2.1 */ public IChatRoomContainer[] getChatRoomContainers() { List containers = new ArrayList(chatRooms.size()); for (Iterator i = chatRooms.values().iterator(); i.hasNext();) { ChatRoom cr = (ChatRoom) i.next(); if (cr.chatRoomContainer != null) { containers.add(cr.chatRoomContainer); } } return (IChatRoomContainer[]) containers.toArray(new IChatRoomContainer[containers.size()]); } /** * @return chat room container of currently selected tab or null if none found. */ public IChatRoomContainer getActiveChatRoomContainer() { CTabItem selection = rootTabFolder.getSelection(); if (selection != null) { ChatRoom chatRoom = findChatRoomForTabItem(selection); if (chatRoom != null) { return chatRoom.chatRoomContainer; } } return null; } private ChatRoom findChatRoomForTabItem(CTabItem tabItem) { for (Iterator i = chatRooms.values().iterator(); i.hasNext();) { ChatRoom cr = (ChatRoom) i.next(); if (tabItem == cr.chatRoomTab.tabItem) return cr; } return null; } private Text getRootTextInput() { if (rootChannelTab == null) return null; return rootChannelTab.getInputText(); } private StyledText getRootTextOutput() { if (rootChannelTab == null) return null; return rootChannelTab.getOutputText(); } public void initializeWithoutManager(String username, String hostname, final IChatRoomCommandListener commandListener1, final IChatRoomViewCloseListener closeListener) { initializeWithManager(username, hostname, null, commandListener1, closeListener); } public void initializeWithManager(String localUserName1, String hostName1, final IChatRoomContainer rootChatRoomContainer, final IChatRoomCommandListener commandListener1, final IChatRoomViewCloseListener closeListener) { // We get populated, remove the info tab if requested if (infoTab != null && fClearInfoTab && !(infoTab.isDisposed())) { infoTab.getControl().dispose(); infoTab.dispose(); infoTab = null; } ChatRoomManagerView.this.localUserName = (localUserName1 == null) ? Messages.ChatRoomManagerView_DEFAULT_USER : localUserName1; ChatRoomManagerView.this.hostName = (hostName1 == null) ? Messages.ChatRoomManagerView_DEFAULT_HOST : hostName1; ChatRoomManagerView.this.rootCloseListener = closeListener; ChatRoomManagerView.this.commandListener = commandListener1; String viewTitle = localUserName1 + ATSIGN + hostName1; ChatRoomManagerView.this.setPartName(NLS.bind(Messages.ChatRoomManagerView_VIEW_TITLE, viewTitle)); ChatRoomManagerView.this.setTitleToolTip(Messages.ChatRoomManagerView_VIEW_TITLE_HOST_PREFIX + ChatRoomManagerView.this.hostName); if (rootChatRoomContainer != null) { ChatRoomManagerView.this.container = rootChatRoomContainer; ChatRoomManagerView.this.rootMessageSender = rootChatRoomContainer.getChatRoomMessageSender(); rootChannelTab = new ChatRoomTab(false, rootTabFolder, ChatRoomManagerView.this.hostName, new KeyListener() { public void keyPressed(KeyEvent evt) { handleKeyPressed(evt); } public void keyReleased(KeyEvent evt) { // do nothing } }); makeActions(); hookContextMenu(); if (rootChatRoomContainer.getConnectedID() == null) { StyledText outputText = getRootTextOutput(); if (!outputText.isDisposed()) outputText.setText(new SimpleDateFormat(Messages.ChatRoomManagerView_CONNECT_DATE_TIME_FORMAT).format(new Date()) + NLS.bind(Messages.ChatRoomManagerView_CONNECT_MESSAGE, viewTitle)); } } setEnabled(false); } public void setEnabled(boolean enabled) { this.rootEnabled = enabled; Text inputText = getRootTextInput(); if (inputText != null && !inputText.isDisposed()) inputText.setEnabled(enabled); } public boolean isEnabled() { return rootEnabled; } protected void clearInput() { Text textInput = getRootTextInput(); if (textInput != null) textInput.setText(""); //$NON-NLS-1$ } public void sendMessageLine(String line) { try { if (rootMessageSender != null) rootMessageSender.sendMessage(line); } catch (ECFException e) { // And cut ourselves off removeLocalUser(); } } public void disconnected() { Display.getDefault().asyncExec(new Runnable() { public void run() { if (rootDisposed) return; setEnabled(false); setPartName(NLS.bind(Messages.ChatRoomManagerView_VIEW_DISABLED_NAME, getPartName())); } }); } protected CTabItem getTabItem(String targetName) { CTabItem[] items = rootTabFolder.getItems(); for (int i = 0; i < items.length; i++) { if (items[i].getText().equals(targetName)) { return items[i]; } } return null; } protected void doJoinRoom(final IChatRoomInfo roomInfo, final String password) { final ID targetRoomID = roomInfo.getRoomID(); final String targetRoomName = targetRoomID.getName(); // first, check to see if we already have it open. If so just activate ChatRoom room = (ChatRoom) chatRooms.get(targetRoomName); if (room != null && room.isConnected()) { room.setSelected(); return; } // Then we create a new chatRoomContainer from the roomInfo try { final IChatRoomContainer chatRoomContainer = roomInfo.createChatRoomContainer(); // Setup new user interface (new tab) final ChatRoom chatroom = new ChatRoom(chatRoomContainer, new ChatRoomTab(rootTabFolder, targetRoomName)); // setup message listener chatRoomContainer.addMessageListener(new IIMMessageListener() { public void handleMessageEvent(IIMMessageEvent messageEvent) { if (messageEvent instanceof IChatRoomMessageEvent) { IChatRoomMessage m = ((IChatRoomMessageEvent) messageEvent).getChatRoomMessage(); chatroom.handleMessage(m.getFromID(), m.getMessage()); } } }); // setup participant listener chatRoomContainer.addChatRoomParticipantListener(new IChatRoomParticipantListener() { public void handlePresenceUpdated(ID fromID, IPresence presence) { chatroom.handlePresence(fromID, presence); } public void handleArrived(IUser participant) { // do nothing } public void handleUpdated(IUser updatedParticipant) { // do nothing } public void handleDeparted(IUser participant) { // do nothing } }); chatRoomContainer.addListener(new IContainerListener() { public void handleEvent(IContainerEvent evt) { if (evt instanceof IContainerDisconnectedEvent || evt instanceof IContainerEjectedEvent) { chatroom.disconnected(); } } }); // Now connect/join Display.getDefault().asyncExec(new Runnable() { public void run() { try { chatRoomContainer.connect(targetRoomID, ConnectContextFactory.createPasswordConnectContext(password)); chatRooms.put(targetRoomName, chatroom); } catch (Exception e) { MessageDialog.openError(getSite().getShell(), "Connect Error", //$NON-NLS-1$ NLS.bind("Could not connect to {0}.\n\nError is {1}.", //$NON-NLS-1$ targetRoomName, e.getLocalizedMessage())); } } }); } catch (Exception e) { MessageDialog.openError(getSite().getShell(), "Container Create Error", //$NON-NLS-1$ NLS.bind("Could not create chatRoomContainer for {0}.\n\nError is {1}.", //$NON-NLS-1$ targetRoomName, e.getLocalizedMessage())); } } class ChatRoom implements IChatRoomInvitationListener, KeyListener { private IChatRoomContainer chatRoomContainer; private ChatRoomTab chatRoomTab; private IChatRoomMessageSender chatRoomMessageSender; private IUser localUser; private Label chatRoomParticipantsLabel; private TableViewer chatRoomParticipantViewer = null; /** * A list of available nicknames for nickname completion via the 'tab' * key. */ private ArrayList options; /** * Denotes the number of options that should be available for the user * to cycle through when pressing the 'tab' key to perform nickname * completion. The default value is set to 5. */ private int maximumCyclingOptions = 5; /** * The length of a nickname's prefix that has already been typed in by * the user. This is used to remove the beginning part of the available * nickname choices. */ private int prefixLength; /** * The index of the next nickname to select from {@link #options}. */ private int choice = 0; /** * The length of the user's nickname that remains resulting from * subtracting the nickname's length from the prefix that the user has * keyed in already. */ private int nickRemainder; /** * The caret position when the user first started * cycling through nickname completion options. */ private int caret; /** * The character to enter after the user's nickname has been * autocompleted. The default value is a colon (':'). */ private char nickCompletionSuffix = ':'; /** * Indicates whether the user is currently cycling over the list of * nicknames for nickname completion. */ private boolean isCycling = false; /** * Check to see whether the user is currently starting the line of text * with a nickname at the beginning of the message. This determines * whether {@link #nickCompletionSuffix} should be inserted when * performing autocompletion. If the user is not at the beginning of the * message, it is likely that the user is typing another user's name to * reference that person and not to direct the message to said person, * as such, the <code>nickCompletionSuffix</code> does not need to be * appended. */ private boolean isAtStart = false; private CTabItem itemSelected = null; private Text getInputText() { return chatRoomTab.getInputText(); } private StyledText getOutputText() { return chatRoomTab.getOutputText(); } ChatRoom(IChatRoomContainer container, ChatRoomTab tabItem) { Assert.isNotNull(container); Assert.isNotNull(tabItem); this.chatRoomContainer = container; this.chatRoomMessageSender = container.getChatRoomMessageSender(); this.chatRoomTab = tabItem; options = new ArrayList(); this.chatRoomTab.setKeyListener(this); this.chatRoomParticipantsLabel = tabItem.getParticipantsLabel(); this.chatRoomParticipantViewer = tabItem.getParticipantsViewer(); chatRoomContainer.addChatRoomAdminListener(new IChatRoomAdminListener() { public void handleSubjectChange(ID from, final String newSubject) { if (!chatRoomTab.getInputText().isDisposed()) { chatRoomTab.getInputText().getDisplay().asyncExec(new Runnable() { public void run() { chatRoomTab.setSubject(newSubject); } }); } } }); rootTabFolder.setUnselectedCloseVisible(true); rootTabFolder.addSelectionListener(new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // do nothing } public void widgetSelected(SelectionEvent e) { itemSelected = (CTabItem) e.item; if (itemSelected == chatRoomTab.tabItem) makeTabItemNormal(); if (rootChannelTab != null && itemSelected == rootChannelTab.tabItem) rootChannelTab.makeTabItemNormal(); } }); StyledText st = getOutputText(); if (st != null) { ScrollBar vsb = st.getVerticalBar(); if (vsb != null) { vsb.addSelectionListener(scrollSelectionListener); vsb.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { StyledText ot = getOutputText(); if (ot != null) { ScrollBar vb = ot.getVerticalBar(); if (vb != null) vb.removeSelectionListener(scrollSelectionListener); } } }); } } } private SelectionListener scrollSelectionListener = new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { // do nothing } public void widgetSelected(SelectionEvent e) { if (!isLastOutputInvisible(getOutputText())) { makeTabItemNormal(); } } }; protected void makeTabItemBold() { changeTabItem(true); } protected void makeTabItemNormal() { changeTabItem(false); } protected void changeTabItem(boolean bold) { CTabItem item = chatRoomTab.tabItem; Font oldFont = item.getFont(); FontData[] fd = oldFont.getFontData(); item.setFont(new Font(oldFont.getDevice(), fd[0].getName(), fd[0].getHeight(), (bold) ? SWT.BOLD : SWT.NORMAL)); } public void handleMessage(final ID fromID, final String messageBody) { Display.getDefault().asyncExec(new Runnable() { public void run() { if (rootDisposed) return; appendText(chatRoomTab, getOutputText(), new ChatLine(messageBody, new ChatRoomParticipant(fromID))); } }); } public void handleInvitationReceived(ID roomID, ID from, String subject, String body) { // XXX TODO show UI for invitation } public void keyPressed(KeyEvent e) { handleKeyPressed(e); } public void keyReleased(KeyEvent e) { handleKeyReleased(e); } protected void handleKeyPressed(KeyEvent evt) { Text inputText = getInputText(); if (evt.character == SWT.CR) { if (inputText.getText().trim().length() > 0) handleTextInput(inputText.getText()); clearInput(); makeTabItemNormal(); if (Activator.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.PREFERENCES_SCROLLONINPUT)) scrollToEnd(getOutputText()); evt.doit = false; isCycling = false; } else if (evt.character == SWT.TAB) { // don't propogate the event upwards and insert a tab character evt.doit = false; int pos = inputText.getCaretPosition(); // if the user is at the beginning of the line, do nothing if (pos == 0) return; String text = inputText.getText(); // check to see if the user is currently cycling through the // available nicknames if (isCycling) { // if everything's been cycled over, start over at zero if (choice == options.size()) { choice = 0; } String append = ((String) options.get(choice++)) + (isAtStart ? nickCompletionSuffix + " " : " "); //$NON-NLS-1$ //$NON-NLS-2$ // remove the previous completion proposal and insert the new one inputText.setText(text.substring(0, caret - prefixLength) + append + text.substring(caret + nickRemainder)); // subtract the prefix so we remember where we were originally nickRemainder = append.length() - prefixLength; // set the caret position to be the place where the nickname // completion ended inputText.setSelection(caret + nickRemainder); } else { // the user is not cycling, so we need to identify what the // user has typed based on the current caret position int count = pos - 1; // keep looping until the whitespace has been identified or // the beginning of the message has been reached while (count > -1 && !Character.isWhitespace(text.charAt(count))) { count--; } count++; // remove all previous options options.clear(); // get the prefix that the user typed as a lowercase string String prefix = text.substring(count, pos).toLowerCase(); isAtStart = count == 0; // if what's found was actually whitespace, do nothing if (prefix.trim().equals("")) { //$NON-NLS-1$ return; } // get all of the users in this room and store them if they // start with the prefix that the user has typed TableItem[] participants = chatRoomParticipantViewer.getTable().getItems(); for (int i = 0; i < participants.length; i++) { String name = participants[i].getText(); // do a lowercase comparison because we should display options that differ in casing if (name.toLowerCase().startsWith(prefix)) { options.add(name); } } // simply return if no matches have been found if (options.isEmpty()) return; prefixLength = prefix.length(); if (options.size() == 1) { String nickname = (String) options.get(0); // since only one nickname is available, we'll select // the prefix that has been entered and then replace it // with the nickname option inputText.setSelection(pos - prefixLength, pos); inputText.insert(nickname + (isAtStart ? nickCompletionSuffix + " " : " ")); //$NON-NLS-1$ //$NON-NLS-2$ } else if (options.size() <= maximumCyclingOptions) { // note that the user is currently cycling through // options and also store the current caret position isCycling = true; caret = pos; choice = 0; // insert the nickname after removing the prefix String nickname = options.get(choice++) + (isAtStart ? nickCompletionSuffix + " " : " "); //$NON-NLS-1$ //$NON-NLS-2$ // select the prefix of the proposal inputText.setSelection(pos - prefixLength, pos); // and then replace it with a proposal inputText.insert(nickname); // store the length of this truncated nickname so that // it can be removed when the user is cycling nickRemainder = nickname.length() - prefixLength; } else { // as there are too many choices for the user to pick // from, simply display all of the available ones on the // chat window so that the user can get a visual // indicator of what's available and narrow down the // choices by typing a few more additional characters StringBuffer choices = new StringBuffer(); synchronized (choices) { for (int i = 0; i < options.size(); i++) { choices.append(options.get(i)).append(' '); } choices.delete(choices.length() - 1, choices.length()); } appendText(chatRoomTab, getOutputText(), new ChatLine(choices.toString())); } } } else { // remove the cycling marking for any other key pressed isCycling = false; } } protected void handleKeyReleased(KeyEvent evt) { if (evt.character == SWT.TAB) { // don't move to the next widget or try to add tabs evt.doit = false; } } protected void handleTextInput(String text) { if (chatRoomMessageSender == null) { MessageDialog.openError(getViewSite().getShell(), Messages.ChatRoomManagerView_NOT_CONNECTED_TITLE, Messages.ChatRoomManagerView_NOT_CONNECTED_MESSAGE); return; } String output = processForCommand(chatRoomContainer, text); if (output != null) sendMessageLine(output); } protected void chatRoomDisconnect() { if (chatRoomContainer != null) chatRoomContainer.disconnect(); } protected void clearInput() { getInputText().setText(""); //$NON-NLS-1$ } protected void sendMessageLine(String line) { try { chatRoomMessageSender.sendMessage(line); } catch (ECFException e) { disconnected(); } } public void handlePresence(final ID fromID, final IPresence presence) { Display.getDefault().asyncExec(new Runnable() { public void run() { if (rootDisposed) return; boolean isAdd = presence.getType().equals(IPresence.Type.AVAILABLE); ChatRoomParticipant p = new ChatRoomParticipant(fromID); if (isAdd) { if (localUser == null) localUser = p; addParticipant(p); } else removeParticipant(p); } }); } public void disconnected() { Display.getDefault().asyncExec(new Runnable() { public void run() { if (rootDisposed) return; Text inputText = getInputText(); if (!inputText.isDisposed()) inputText.setEnabled(false); } }); } protected boolean isConnected() { Text inputText = getInputText(); return !inputText.isDisposed() && inputText.isEnabled(); } protected void setSelected() { rootTabFolder.setSelection(chatRoomTab.tabItem); } protected void addParticipant(IUser p) { if (p != null) { ID id = p.getID(); if (id != null) { IPreferenceStore store = Activator.getDefault().getPreferenceStore(); if (store.getBoolean(PreferenceConstants.CHATROOM_SHOW_USER_PRESENCE)) appendText(chatRoomTab, getOutputText(), new ChatLine(NLS.bind(Messages.ChatRoomManagerView_ENTERED_MESSAGE, getUsernameFromID(id)), null)); chatRoomParticipantViewer.add(p); chatRoomParticipantsLabel.setText(NLS.bind(Messages.ChatRoomManagerView_USERS_IN_CHAT_ROOM, String.valueOf(chatRoomContainer.getChatRoomParticipants().length))); } } } protected boolean isLocalUser(ID id) { if (localUser == null) return false; else if (localUser.getID().equals(id)) return true; else return false; } protected void removeLocalUser() { // It's us that's gone away... so we're outta here String title = getPartName(); setPartName(NLS.bind(Messages.ChatRoomManagerView_VIEW_DISABLED_NAME, title)); removeAllParticipants(); disconnect(); setEnabled(false); } protected void removeParticipant(IUser p) { if (p != null) { ID id = p.getID(); if (id != null) { IPreferenceStore store = Activator.getDefault().getPreferenceStore(); if (store.getBoolean(PreferenceConstants.CHATROOM_SHOW_USER_PRESENCE)) appendText(chatRoomTab, getOutputText(), new ChatLine(NLS.bind(Messages.ChatRoomManagerView_LEFT_MESSAGE, getUsernameFromID(id)), null)); chatRoomParticipantViewer.remove(p); chatRoomParticipantsLabel.setText(NLS.bind(Messages.ChatRoomManagerView_USERS_IN_CHAT_ROOM, String.valueOf(chatRoomContainer.getChatRoomParticipants().length))); } } } protected void removeAllParticipants() { Table t = chatRoomParticipantViewer.getTable(); for (int i = 0; i < t.getItemCount(); i++) { Object o = chatRoomParticipantViewer.getElementAt(i); if (o != null) chatRoomParticipantViewer.remove(o); } chatRoomParticipantsLabel.setText(NLS.bind(Messages.ChatRoomManagerView_USERS_IN_CHAT_ROOM, String.valueOf(chatRoomContainer.getChatRoomParticipants().length))); } } protected void handleTextInput(String text) { if (rootMessageSender == null) { MessageDialog.openError(getViewSite().getShell(), Messages.ChatRoomManagerView_NOT_CONNECTED_TITLE, Messages.ChatRoomManagerView_NOT_CONNECTED_MESSAGE); } else { String output = processForCommand(null, text); if (output != null) sendMessageLine(output); } } protected String processForCommand(IChatRoomContainer chatRoomContainer, String text) { IChatRoomCommandListener l = commandListener; if (l != null) return l.handleCommand(chatRoomContainer, text); return text; } protected void handleEnter() { Text inputText = getRootTextInput(); if (inputText.getText().trim().length() > 0) handleTextInput(inputText.getText()); clearInput(); scrollToEnd(getRootTextOutput()); if (rootChannelTab != null) rootChannelTab.makeTabItemNormal(); } protected void handleKeyPressed(KeyEvent evt) { if (evt.character == SWT.CR) { handleEnter(); evt.doit = false; } } public void setFocus() { Text text = getRootTextInput(); if (text != null) text.setFocus(); } public void joinRoom(final IChatRoomInfo info, final String password) { Display.getDefault().syncExec(new Runnable() { public void run() { if (rootDisposed) return; doJoinRoom(info, password); } }); } public void dispose() { disconnect(); rootDisposed = true; super.dispose(); } protected String getMessageString(ID fromID, String text) { return NLS.bind(Messages.ChatRoomManagerView_MESSAGE, fromID.getName(), text); } private ID createStringID(String str) { try { return IDFactory.getDefault().createStringID(str); } catch (IDCreateException e) { // Should not happen } return null; } private MessagesView getMessagesView() throws PartInitException { IWorkbenchPage page = getSite().getPage(); MessagesView messageView = (MessagesView) page.findView(MessagesView.VIEW_ID); if (messageView == null) { messageView = (MessagesView) page.showView(MessagesView.VIEW_ID, null, IWorkbenchPage.VIEW_CREATE); } return messageView; } /** * A delegate method to handle chat messages. * @param message the chat message that has been received * @since 1.1 */ public void handleChatMessage(final IChatMessage message) { Display.getDefault().asyncExec(new Runnable() { public void run() { try { ID targetID = createStringID(localUserName); MessagesView messageView = getMessagesView(); IWorkbenchSiteProgressService service = (IWorkbenchSiteProgressService) messageView.getSite().getAdapter(IWorkbenchSiteProgressService.class); if (container.getPrivateMessageSender() != null) { messageView.openTab(container.getPrivateMessageSender(), null, targetID, message.getFromID(), new ChatRoomParticipant(targetID).getNickname()); messageView.showMessage(message); service.warnOfContentChange(); } } catch (Exception e) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, IStatus.ERROR, Messages.ChatRoomManagerView_EXCEPTION_MESSAGE_VIEW_INITIALIZATION + message.getFromID(), e)); } } }); } public void handleMessage(final ID fromID, final String messageBody) { Display.getDefault().asyncExec(new Runnable() { public void run() { if (rootDisposed) return; if (rootChannelTab != null) { appendText(rootChannelTab, getRootTextOutput(), new ChatLine(messageBody, new ChatRoomParticipant(fromID))); rootChannelTab.makeTabItemBold(); } } }); } /** * @return String username for given <code>targetID</code> */ public static String getUsernameFromID(ID targetID) { IChatID chatID = (IChatID) targetID.getAdapter(IChatID.class); if (chatID != null) return chatID.getUsername(); try { URI uri = new URI(targetID.getName()); String user = uri.getUserInfo(); return user == null ? targetID.getName() : user; } catch (URISyntaxException e) { String userAtHost = targetID.getName(); int atIndex = userAtHost.lastIndexOf(ATSIGN); if (atIndex != -1) userAtHost = userAtHost.substring(0, atIndex); return userAtHost; } } /** * @return String hostname for given <code>targetID</code> */ public static String getHostnameFromID(ID targetID) { IChatID chatID = (IChatID) targetID.getAdapter(IChatID.class); if (chatID != null) return chatID.getHostname(); try { URI uri = new URI(targetID.getName()); String host = uri.getHost(); return host == null ? targetID.getName() : host; } catch (URISyntaxException e) { String userAtHost = targetID.getName(); int atIndex = userAtHost.lastIndexOf(ATSIGN); if (atIndex != -1) userAtHost = userAtHost.substring(atIndex + 1); return userAtHost; } } class ChatRoomParticipant implements IUser, IActionFilter { private static final long serialVersionUID = 2008114088656711572L; ID id; public ChatRoomParticipant(ID id) { this.id = id; } public ID getID() { return id; } public String getName() { return toString(); } public boolean equals(Object other) { if (!(other instanceof ChatRoomParticipant)) return false; ChatRoomParticipant o = (ChatRoomParticipant) other; if (id.equals(o.id)) return true; return false; } public int hashCode() { return id.hashCode(); } public String toString() { return getUsernameFromID(id); } public Map getProperties() { return null; } public Object getAdapter(Class adapter) { return null; } /* * (non-Javadoc) * * @see org.eclipse.ecf.core.user.IUser#getNickname() */ public String getNickname() { return getName(); } public boolean testAttribute(Object target, String name, String value) { if (name.equals("scheme")) { //$NON-NLS-1$ IChatRoomContainer c = ChatRoomManagerView.this.container; String scheme = c.getConnectedID().getNamespace().getScheme(); return scheme.equalsIgnoreCase(value); } return false; } } public void disconnect() { if (rootCloseListener != null) { rootCloseListener.chatRoomViewClosing(); } // disconnect from each chat room container for (Iterator i = chatRooms.values().iterator(); i.hasNext();) { ChatRoom chatRoom = (ChatRoom) i.next(); IChatRoomContainer c = chatRoom.chatRoomContainer; if (c != null) c.disconnect(); } rootMessageSender = null; rootCloseListener = null; chatRooms.clear(); } protected void removeLocalUser() { // It's us that's gone away... so we're outta here String title = getPartName(); setPartName(NLS.bind(Messages.ChatRoomManagerView_VIEW_DISABLED_NAME, title)); disconnect(); setEnabled(false); } public void handleInvitationReceived(ID roomID, ID from, String subject, String body) { // XXX TODO } private boolean isLastOutputInvisible(StyledText chatText) { Point locAtEnd = chatText.getLocationAtOffset(chatText.getText().length()); Rectangle bounds = chatText.getBounds(); return (locAtEnd.y > bounds.height + 5); } private void scrollToEnd(StyledText chatText) { chatText.setSelection(chatText.getText().length()); } protected void appendText(ChatRoomTab chatRoomTab, StyledText st, ChatLine text) { if (st == null || text == null) { return; } boolean isAtEndBeforeAppend = !isLastOutputInvisible(st); String originator = null; if (text.getOriginator() != null) { originator = text.getOriginator().getNickname(); } if (messageRenderer == null) messageRenderer = new MessageRenderer(); String output = messageRenderer.render(text.getText(), originator, localUserName); StyleRange[] ranges = messageRenderer.getStyleRanges(); if (output == null) { return; } int startRange = st.getText().length(); if (!text.isNoCRLF()) { output += "\n"; //$NON-NLS-1$ } st.append(output); if (ranges != null) { // set all ranges to start as message line starts for (int i = 0; i < ranges.length; i++) { ranges[i].start += startRange; } st.replaceStyleRanges(startRange, output.length(), ranges); } if (isAtEndBeforeAppend) scrollToEnd(st); if (isCurrentlyActive(chatRoomTab)) chatRoomTab.makeTabItemNormal(); else chatRoomTab.makeTabItemBold(); } protected void outputClear() { if (MessageDialog.openConfirm(null, Messages.ChatRoomManagerView_CLEAR_CONFIRM_TITLE, Messages.ChatRoomManagerView_CLEAR_CONFIRM_MESSAGE)) { getRootTextOutput().setText(""); //$NON-NLS-1$ } } protected void outputCopy() { StyledText outputText = getRootTextOutput(); String t = outputText.getSelectionText(); if (t == null || t.length() == 0) { outputText.selectAll(); } outputText.copy(); outputText.setSelection(outputText.getText().length()); } protected void outputSelectAll() { getRootTextOutput().selectAll(); } protected void makeActions() { outputSelectAll = new Action() { public void run() { outputSelectAll(); } }; outputSelectAll.setText(Messages.ChatRoomManagerView_SELECT_ALL_TEXT); outputSelectAll.setToolTipText(Messages.ChatRoomManagerView_SELECT_ALL_TOOLTIP); outputSelectAll.setAccelerator(SWT.CTRL | 'A'); outputCopy = new Action() { public void run() { outputCopy(); } }; outputCopy.setText(Messages.ChatRoomManagerView_COPY_TEXT); outputCopy.setToolTipText(Messages.ChatRoomManagerView_COPY_TOOLTIP); outputCopy.setAccelerator(SWT.CTRL | 'C'); outputCopy.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_COPY)); outputClear = new Action() { public void run() { outputClear(); } }; outputClear.setText(Messages.ChatRoomManagerView_CLEAR_TEXT); outputClear.setToolTipText(Messages.ChatRoomManagerView_CLEAR_TOOLTIP); outputPaste = new Action() { public void run() { getRootTextInput().paste(); } }; outputPaste.setText(Messages.ChatRoomManagerView_PASTE_TEXT); outputPaste.setToolTipText(Messages.ChatRoomManagerView_PASTE_TOOLTIP); outputPaste.setAccelerator(SWT.CTRL | 'V'); outputPaste.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_PASTE)); } private void fillContextMenu(IMenuManager manager) { manager.add(outputCopy); manager.add(outputPaste); manager.add(outputClear); manager.add(new Separator()); manager.add(outputSelectAll); manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); } private void hookContextMenu() { MenuManager menuMgr = new MenuManager(); menuMgr.setRemoveAllWhenShown(true); menuMgr.addMenuListener(new IMenuListener() { public void menuAboutToShow(IMenuManager manager) { fillContextMenu(manager); } }); StyledText outputText = getRootTextOutput(); Menu menu = menuMgr.createContextMenu(outputText); outputText.setMenu(menu); ISelectionProvider selectionProvider = new ISelectionProvider() { public void addSelectionChangedListener(ISelectionChangedListener listener) { // do nothing } public ISelection getSelection() { StyledText ot = getRootTextOutput(); ISelection selection = new TextSelection(ot.getSelectionRange().x, ot.getSelectionRange().y); return selection; } public void removeSelectionChangedListener(ISelectionChangedListener listener) { // do nothing } public void setSelection(ISelection selection) { if (selection instanceof ITextSelection) { ITextSelection textSelection = (ITextSelection) selection; StyledText ot = getRootTextOutput(); ot.setSelection(textSelection.getOffset(), textSelection.getOffset() + textSelection.getLength()); } } }; getSite().registerContextMenu(menuMgr, selectionProvider); } public void setMessageRenderer(IMessageRenderer defaultMessageRenderer) { this.messageRenderer = defaultMessageRenderer; } private boolean isCurrentlyActive(ChatRoomTab chatRoomTab) { int selected = rootTabFolder.getSelectionIndex(); if (selected != -1) { CTabItem item = rootTabFolder.getItem(selected); if (item == chatRoomTab.tabItem) return true; } return false; } }