package org.gudy.azureus2.ui.swt.shells; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.swt.SWT; import org.eclipse.swt.browser.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.util.*; import org.gudy.azureus2.ui.swt.ImageRepository; import org.gudy.azureus2.ui.swt.Utils; import org.gudy.azureus2.ui.swt.components.shell.ShellFactory; import org.gudy.azureus2.ui.swt.mainwindow.TorrentOpener; import com.aelitis.azureus.ui.UIFunctionsUserPrompter; import com.aelitis.azureus.ui.common.RememberedDecisionsManager; import com.aelitis.azureus.ui.swt.UISkinnableManagerSWT; import com.aelitis.azureus.ui.swt.UISkinnableSWTListener; /** * A messagebox that allows you config the button * * @todo When key is pressed, cancel auto close timer */ public class MessageBoxShell implements UIFunctionsUserPrompter { private final static String REGEX_URLHTML = "<A HREF=\"(.+?)\">(.+?)</A>"; private final static int MIN_SIZE_X = 300; private final static int MIN_SIZE_Y = 120; private final static int MAX_SIZE_X = 500; private static final int MIN_BUTTON_SIZE = 70; private static int numOpen = 0; private static ArrayList skinnableListeners = new ArrayList(); private Shell parent; private final String title; private final String text; private final String[] buttons; private final int defaultOption; private String rememberID; private String rememberText; private boolean rememberByDefault; private int rememberOnlyIfButton = -1; private int autoCloseInMS; private String html; private String url; private boolean autoClosed = false; private Object[] relatedObjects; private Image imgLeft; public static void addSkinnableListener(UISkinnableSWTListener l) { skinnableListeners.add(l); } public static void removeSkinnableListener(UISkinnableSWTListener l) { skinnableListeners.remove(l); } public static int open(final Shell parent, final String title, final String text, final String[] buttons, final int defaultOption) { return open(parent, title, text, buttons, defaultOption, null, false, -1); } public static int open(final Shell parent, final String title, final String text, final String[] buttons, final int defaultOption, final String rememberID, final boolean bRememberByDefault, final int autoCloseInMS) { return open(parent, title, text, buttons, defaultOption, rememberID, MessageText.getString("MessageBoxWindow.rememberdecision"), bRememberByDefault, autoCloseInMS); } public static int open(final Shell parent, final String title, final String text, final String[] buttons, final int defaultOption, final String rememberID, final String rememberText, final boolean bRememberByDefault, final int autoCloseInMS) { MessageBoxShell messageBoxShell = new MessageBoxShell(parent, title, text, buttons, defaultOption, rememberID, rememberText, bRememberByDefault, autoCloseInMS); return messageBoxShell.open(); } public static boolean isOpen() { return numOpen > 0; } /** * @param parent * @param title * @param text * @param buttons * @param defaultOption * @param rememberID * @param rememberText * @param bRememberByDefault * @param autoCloseInMS */ public MessageBoxShell(final Shell parent, final String title, final String text, final String[] buttons, final int defaultOption, final String rememberID, final String rememberText, final boolean bRememberByDefault, final int autoCloseInMS) { this.parent = parent; this.title = title; this.text = text; this.buttons = buttons; this.defaultOption = defaultOption; this.rememberID = rememberID; this.rememberText = rememberText; this.rememberByDefault = bRememberByDefault; this.autoCloseInMS = autoCloseInMS; } /** * @param shellForChildren * @param string * @param string2 * @param strings */ public MessageBoxShell(final Shell parent, final String title, final String text, final String[] buttons, final int defaultOption) { this(parent, title, text, buttons, defaultOption, null, null, false, -1); } public int open() { if (rememberID != null) { int rememberedDecision = RememberedDecisionsManager.getRememberedDecision(rememberID); if (rememberedDecision >= 0) { return rememberedDecision; } } numOpen++; final int[] result = new int[1]; result[0] = -1; Utils.execSWTThread(new AERunnable() { public void runSupport() { result[0] = _open(); } }, false); numOpen--; return result[0]; } private int _open() { final int[] result = { -1 }; if (parent == null || parent.isDisposed()) { parent = Utils.findAnyShell(); if (parent == null || parent.isDisposed()) { return result[0]; } } MouseTrackAdapter mouseAdapter = null; Display display = parent.getDisplay(); final Shell shell = ShellFactory.createShell(parent, SWT.DIALOG_TRIM | SWT.RESIZE | SWT.APPLICATION_MODAL); shell.setText(title); GridLayout gridLayout = new GridLayout(); shell.setLayout(gridLayout); Utils.setShellIcon(shell); UISkinnableSWTListener[] listeners = UISkinnableManagerSWT.getInstance().getSkinnableListeners( MessageBoxShell.class.toString()); for (int i = 0; i < listeners.length; i++) { listeners[i].skinBeforeComponents(shell, this, relatedObjects); } FormData formData; GridData gridData; Composite textComposite = shell; if (imgLeft != null) { textComposite = new Composite(shell, SWT.NONE); textComposite.setLayout(new GridLayout(2, false)); textComposite.setLayoutData(new GridData(GridData.FILL_BOTH)); Label lblImage = new Label(textComposite, SWT.NONE); lblImage.setImage(imgLeft); lblImage.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING)); } Control linkControl; try { Link linkLabel = new Link(textComposite, SWT.WRAP); linkControl = linkLabel; linkLabel.setText(text.replaceAll(" &", " &&")); linkLabel.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { if (e.text.startsWith(":")) { return; } if (e.text.endsWith(".torrent")) TorrentOpener.openTorrent(e.text); else Utils.launch(e.text); } }); Matcher matcher = Pattern.compile(REGEX_URLHTML, Pattern.CASE_INSENSITIVE).matcher( text); String tooltip = null; while (matcher.find()) { if (tooltip == null) tooltip = ""; else tooltip += "\n"; String url = matcher.group(1); if (url != null && url.startsWith(":")) { url = url.substring(1); } tooltip += matcher.group(2) + ": " + url; } linkLabel.setToolTipText(tooltip); } catch (Throwable t) { // 3.0 Label linkLabel = new Label(textComposite, SWT.WRAP); linkControl = linkLabel; String urlText = Pattern.compile(REGEX_URLHTML, Pattern.CASE_INSENSITIVE).matcher( text).replaceAll("$2 ($1)"); linkLabel.setText(urlText); } if ((html != null && html.length() > 0) || (url != null && url.length() > 0)) { try { final Browser browser = new Browser(shell, SWT.NONE); if (url != null && url.length() > 0) { browser.setUrl(url); } else { browser.setText(html); } GridData gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 200; browser.setLayoutData(gd); browser.addProgressListener(new ProgressListener() { public void completed(ProgressEvent event) { browser.addLocationListener(new LocationListener() { public void changing(LocationEvent event) { event.doit = false; } public void changed(LocationEvent event) { } }); browser.addOpenWindowListener(new OpenWindowListener() { public void open(WindowEvent event) { event.required = true; } }); } public void changed(ProgressEvent event) { } }); } catch (Exception e) { Debug.out(e); if (html != null) { Text text = new Text(shell, SWT.BORDER | SWT.READ_ONLY | SWT.WRAP); text.setText(html); GridData gd = new GridData(GridData.FILL_BOTH); gd.heightHint = 200; text.setLayoutData(gd); } } gridData = new GridData(GridData.FILL_HORIZONTAL); linkControl.setLayoutData(gridData); } else { gridData = new GridData(GridData.FILL_BOTH); linkControl.setLayoutData(gridData); } Label lblPadding = new Label(shell, SWT.NONE); lblPadding.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // Closing in.. if (autoCloseInMS > 0) { final Label lblCloseIn = new Label(shell, SWT.WRAP); lblCloseIn.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); long endOn = SystemTime.getCurrentTime() + autoCloseInMS; lblCloseIn.setData("CloseOn", new Long(endOn)); SimpleTimer.addPeriodicEvent("autoclose", 500, new TimerEventPerformer() { public void perform(TimerEvent event) { if (shell.isDisposed()) { event.cancel(); return; } Utils.execSWTThread(new AERunnable() { public void runSupport() { if (!shell.isDisposed()) { boolean bDelayPaused = lblCloseIn.getData("DelayPaused") != null; if (bDelayPaused) { return; } long endOn = ((Long) lblCloseIn.getData("CloseOn")).longValue(); if (SystemTime.getCurrentTime() > endOn) { result[0] = defaultOption; autoClosed = true; shell.dispose(); } else { String sText = ""; if (lblCloseIn == null || lblCloseIn.isDisposed()) return; if (!bDelayPaused) { long delaySecs = (endOn - SystemTime.getCurrentTime()) / 1000; sText = MessageText.getString("popup.closing.in", new String[] { String.valueOf(delaySecs) }); } lblCloseIn.setText(sText); } } }; }); } }); SimpleTimer.addPeriodicEvent("OverPopup", 100, new TimerEventPerformer() { boolean wasOver = true; long lEnterOn = 0; public void perform(final TimerEvent event) { if (shell.isDisposed()) { event.cancel(); return; } Utils.execSWTThread(new AERunnable() { public void runSupport() { if (shell.isDisposed()) { event.cancel(); return; } boolean isOver = shell.getBounds().contains( shell.getDisplay().getCursorLocation()); if (isOver != wasOver) { wasOver = isOver; if (isOver) { lblCloseIn.setData("DelayPaused", ""); lEnterOn = SystemTime.getCurrentTime(); lblCloseIn.setText(""); } else { lblCloseIn.setData("DelayPaused", null); if (lEnterOn > 0) { long diff = SystemTime.getCurrentTime() - lEnterOn; long endOn = ((Long) lblCloseIn.getData("CloseOn")).longValue() + diff; lblCloseIn.setData("CloseOn", new Long(endOn)); } } } } }); } }); } // Remember Me Button checkRemember = null; if (rememberID != null) { checkRemember = new Button(shell, SWT.CHECK); checkRemember.setText(rememberText); checkRemember.setSelection(rememberByDefault); checkRemember.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { Button checkRemember = (Button) e.widget; if (rememberID != null && checkRemember != null && checkRemember.getSelection()) { RememberedDecisionsManager.setRemembered(rememberID, result[0]); } } }); } // Buttons Composite cButtons = new Composite(shell, SWT.NONE); FormLayout layout = new FormLayout(); cButtons.setLayout(layout); gridData = new GridData(GridData.HORIZONTAL_ALIGN_CENTER); cButtons.setLayoutData(gridData); Control lastButton = null; Listener buttonListener = new Listener() { public void handleEvent(Event event) { result[0] = ((Integer) event.widget.getData()).intValue(); shell.dispose(); } }; int buttonWidth = 0; Button[] swtButtons = new Button[buttons.length]; for (int i = 0; i < buttons.length; i++) { Button button = new Button(cButtons, SWT.PUSH); swtButtons[i] = button; button.setData(new Integer(i)); button.setText(buttons[i]); button.addListener(SWT.Selection, buttonListener); formData = new FormData(); if (lastButton != null) { formData.left = new FormAttachment(lastButton, 5); } button.setLayoutData(formData); Point size = button.computeSize(SWT.DEFAULT, SWT.DEFAULT); if (size.x > buttonWidth) { buttonWidth = size.x; } if (i == defaultOption) { button.setFocus(); shell.setDefaultButton(button); } lastButton = button; } if (buttonWidth > 0) { if (buttonWidth < MIN_BUTTON_SIZE) { buttonWidth = MIN_BUTTON_SIZE; } for (int i = 0; i < buttons.length; i++) { Point size = swtButtons[i].computeSize(buttonWidth, SWT.DEFAULT); swtButtons[i].setSize(size); formData = (FormData) swtButtons[i].getLayoutData(); formData.width = buttonWidth; } } shell.addTraverseListener(new TraverseListener() { public void keyTraversed(TraverseEvent event) { if (event.detail == SWT.TRAVERSE_ESCAPE) { shell.dispose(); } } }); Listener filterListener = new Listener() { public void handleEvent(Event event) { if (event.detail == SWT.TRAVERSE_ARROW_NEXT) { event.detail = SWT.TRAVERSE_TAB_NEXT; event.doit = true; } else if (event.detail == SWT.TRAVERSE_ARROW_PREVIOUS) { event.detail = SWT.TRAVERSE_TAB_PREVIOUS; event.doit = true; } } }; display.addFilter(SWT.Traverse, filterListener); if (mouseAdapter != null) { addMouseTrackListener(shell, mouseAdapter); } shell.pack(); Point size = shell.getSize(); if (size.x < MIN_SIZE_X) { size.x = MIN_SIZE_X; shell.setSize(size); } else if (size.x > MAX_SIZE_X) { size = shell.computeSize(MAX_SIZE_X, SWT.DEFAULT); shell.setSize(size); } if (size.y < MIN_SIZE_Y) { size.y = MIN_SIZE_Y; shell.setSize(size); } Utils.centerWindowRelativeTo(shell, parent); for (int i = 0; i < listeners.length; i++) { listeners[i].skinAfterComponents(shell, this, relatedObjects); } shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) { display.sleep(); } } if (display != null && !display.isDisposed()) { display.removeFilter(SWT.Traverse, filterListener); } return result[0]; } /** * Adds mousetracklistener to composite and all it's children * * @param parent Composite to start at * @param listener Listener to add */ private void addMouseTrackListener(Composite parent, MouseTrackListener listener) { if (parent == null || listener == null || parent.isDisposed()) return; parent.addMouseTrackListener(listener); Control[] children = parent.getChildren(); for (int i = 0; i < children.length; i++) { Control control = children[i]; if (control instanceof Composite) addMouseTrackListener((Composite) control, listener); else control.addMouseTrackListener(listener); } } public String getHtml() { return html; } public void setHtml(String html) { this.html = html; } public void setUrl(String url) { this.url = url; } /** * @return the rememberID */ public String getRememberID() { return rememberID; } /** * @param rememberID the rememberID to set */ public void setRememberID(String rememberID, boolean rememberByDefault) { this.rememberID = rememberID; this.rememberByDefault = rememberByDefault; } /** * @return the rememberText */ public String getRememberText() { return rememberText; } /** * @param rememberText the rememberText to set */ public void setRememberText(String rememberText) { this.rememberText = rememberText; } /** * @return the autoCloseInMS */ public int getAutoCloseInMS() { return autoCloseInMS; } /** * @param autoCloseInMS the autoCloseInMS to set */ public void setAutoCloseInMS(int autoCloseInMS) { this.autoCloseInMS = autoCloseInMS; } /** * @return the autoClosed */ public boolean isAutoClosed() { return autoClosed; } // @see com.aelitis.azureus.ui.UIFunctionsUserPrompter#setRelatedObject(java.lang.Object) public void setRelatedObject(Object relatedObject) { this.relatedObjects = new Object[] { relatedObject }; } // @see com.aelitis.azureus.ui.UIFunctionsUserPrompter#setRelatedObjects(java.lang.Object[]) public void setRelatedObjects(Object[] relatedObjects) { this.relatedObjects = relatedObjects; } public Object[] getRelatedObjects() { return relatedObjects; } public void setLeftImage(Image imgLeft) { this.imgLeft = imgLeft; } /** * Replaces Image on left with icon * * @param icon SWT.ICON_ERROR, ICON_INFORMATION, ICON_QUESTION, ICON_WARNING, ICON_WORKING * * @since 3.0.1.7 */ public void setLeftImage(final int icon) { Utils.execSWTThread( new AERunnable() { public void runSupport() { setLeftImage(Display.getDefault().getSystemImage(icon)); } }); } public void setIconResource( String resource ) { if ( resource.equals( "info" )){ setLeftImage( SWT.ICON_INFORMATION ); }else if ( resource.equals( "warning" )){ setLeftImage( SWT.ICON_WARNING ); }else if ( resource.equals( "error" )){ setLeftImage( SWT.ICON_ERROR ); }else{ setLeftImage( ImageRepository.getImage( resource )); } } public static void main(String[] args) { Display display = Display.getDefault(); Shell shell = new Shell(display, SWT.SHELL_TRIM); shell.open(); MessageBoxShell messageBoxShell = new MessageBoxShell( shell, "Title", "Test\n" + "THis is a very long line that tests whether the box gets really wide which is something we don't want.\n" + "A <A HREF=\"Link\">link</A> for <A HREF=\"http://moo.com\">you</a>", new String[] { "Okay", "Cancyyyyyy", "Maybe" }, 1, "test2", MessageText.getString("MessageBoxWindow.nomoreprompting"), false, 15000); messageBoxShell.setHtml("<b>Moo</b> goes the cow<p><hr>"); System.out.println(messageBoxShell.open()); } public int getRememberOnlyIfButton() { return rememberOnlyIfButton; } public void setRememberOnlyIfButton(int rememberOnlyIfButton) { this.rememberOnlyIfButton = rememberOnlyIfButton; } }