/** * Created on Jan 5, 2010 * * Copyright 2008 Vuze, Inc. All rights reserved. * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 2 of the License only. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.aelitis.azureus.ui.swt.shells; import java.util.HashMap; import java.util.Map; import org.eclipse.swt.SWT; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.gudy.azureus2.core3.internat.MessageText; import org.gudy.azureus2.core3.util.*; import org.gudy.azureus2.plugins.PluginException; import org.gudy.azureus2.plugins.PluginInterface; import org.gudy.azureus2.plugins.installer.*; import org.gudy.azureus2.plugins.update.UpdateCheckInstance; import org.gudy.azureus2.ui.swt.Utils; import org.gudy.azureus2.ui.swt.mainwindow.ClipboardCopy; import org.gudy.azureus2.ui.swt.mainwindow.Colors; import org.gudy.azureus2.ui.swt.shells.CoreWaiterSWT; import org.gudy.azureus2.ui.swt.shells.GCStringPrinter; import org.gudy.azureus2.ui.swt.shells.CoreWaiterSWT.TriggerInThread; import org.gudy.azureus2.ui.swt.shells.GCStringPrinter.URLInfo; import com.aelitis.azureus.core.AzureusCore; import com.aelitis.azureus.core.AzureusCoreFactory; import com.aelitis.azureus.core.AzureusCoreRunningListener; import com.aelitis.azureus.core.pairing.*; import com.aelitis.azureus.ui.swt.skin.*; import com.aelitis.azureus.ui.swt.skin.SWTSkinButtonUtility.ButtonListenerAdapter; import com.aelitis.azureus.ui.swt.utils.ColorCache; import com.aelitis.azureus.ui.swt.utils.FontUtils; import com.aelitis.azureus.ui.swt.views.skin.SkinnedDialog; import com.aelitis.azureus.ui.swt.views.skin.SkinnedDialog.SkinnedDialogClosedListener; import com.aelitis.azureus.util.StringCompareUtils; /** * @author TuxPaper * @created Jan 5, 2010 * */ public class RemotePairingWindow implements PairingManagerListener { private static final String PLUGINID_WEBUI = "xmwebui"; private static final boolean SHOW_SPEW = false; private static final boolean DEBUG = false; static RemotePairingWindow instance = null; private SkinnedDialog skinnedDialog; private SWTSkin skin; private SWTSkinObjectButton soEnablePairing; private PairingManager pairingManager; private SWTSkinObject soCodeArea; private Font fontCode; private String accessCode; private Control control; private SWTSkinObjectText soStatusText; private SWTSkinObject soFTUX; private SWTSkinObject soCode; private SWTSkinObjectText soToClipboard; private boolean hideCode = true; private String fallBackStatusText = ""; private static testPairingClass testPairingClass; private PairingTest pairingTest; private boolean alreadyTested; private String storedToClipboardText; private String lastPairingTestError; public static void open() { if (DEBUG) { if (testPairingClass == null) { testPairingClass = new testPairingClass(); } else { testPairingClass.inc(); } } synchronized (RemotePairingWindow.class) { if (instance == null) { instance = new RemotePairingWindow(); } } CoreWaiterSWT.waitForCore(TriggerInThread.SWT_THREAD, new AzureusCoreRunningListener() { public void azureusCoreRunning(AzureusCore core) { instance._open(); } }); } private PluginInterface getWebUI() { return AzureusCoreFactory.getSingleton().getPluginManager().getPluginInterfaceByID( PLUGINID_WEBUI, true); } private void _open() { alreadyTested = false; pairingManager = PairingManagerFactory.getSingleton(); PluginInterface piWebUI = getWebUI(); boolean showFTUX = piWebUI == null || !pairingManager.isEnabled(); if (skinnedDialog == null || skinnedDialog.isDisposed()) { skinnedDialog = new SkinnedDialog("skin3_dlg_remotepairing", "shell", SWT.DIALOG_TRIM); skin = skinnedDialog.getSkin(); soCodeArea = skin.getSkinObject("code-area"); control = soCodeArea.getControl(); soEnablePairing = (SWTSkinObjectButton) skin.getSkinObject("enable-pairing"); soEnablePairing.addSelectionListener(new ButtonListenerAdapter() { // @see com.aelitis.azureus.ui.swt.skin.SWTSkinButtonUtility.ButtonListenerAdapter#pressed(com.aelitis.azureus.ui.swt.skin.SWTSkinButtonUtility, com.aelitis.azureus.ui.swt.skin.SWTSkinObject, int) public void pressed(SWTSkinButtonUtility buttonUtility, SWTSkinObject skinObject, int stateMask) { skinObject.getControl().setEnabled(false); if (!pairingManager.isEnabled()) { // enabling will automatically get access code and trigger // somethingChanged pairingManager.setEnabled(true); if (SHOW_SPEW) { System.out.println("PAIR] SetEnabled"); } } else { // fire something changed ourselves, so that accesscode gets // picked up if (SHOW_SPEW) { System.out.println("PAIR] AlreadyEnabled"); } somethingChanged(pairingManager); } if (getWebUI() == null) { installWebUI(); } else { switchToCode(); } } }); soFTUX = skin.getSkinObject("pairing-ftux"); soCode = skin.getSkinObject("pairing-code"); soStatusText = (SWTSkinObjectText) skin.getSkinObject("status-text"); soStatusText.addUrlClickedListener(new SWTSkinObjectText_UrlClickedListener() { public boolean urlClicked(URLInfo urlInfo) { if (urlInfo.url.equals("retry")) { if (DEBUG) { testPairingClass.inc(); } alreadyTested = false; testPairing(false); return true; } return false; } }); pairingManager.addListener(this); Font font = control.getFont(); GC gc = new GC(control); fontCode = FontUtils.getFontWithHeight(font, gc, Constants.isWindows ? 20 : 18, SWT.BOLD); gc.dispose(); control.setFont(fontCode); control.addPaintListener(new PaintListener() { public void paintControl(PaintEvent e) { Color oldColor = e.gc.getForeground(); Rectangle printArea = ((Composite) e.widget).getClientArea(); int fullWidth = printArea.width; int fullHeight = printArea.height; GCStringPrinter sp = new GCStringPrinter(e.gc, MessageText.getString("remote.pairing.accesscode"), printArea, false, false, SWT.NONE); sp.calculateMetrics(); Point sizeAccess = sp.getCalculatedSize(); String drawAccessCode = accessCode == null ? " " : accessCode; int numBoxes = drawAccessCode == null ? 0 : drawAccessCode.length(); int boxSize = 25; int boxSizeAndPadding = 30; int allBoxesWidth = numBoxes * boxSizeAndPadding; int textPadding = 15; printArea.x = (fullWidth - (allBoxesWidth + sizeAccess.x + textPadding)) / 2; printArea.width = sizeAccess.x; sp.printString(e.gc, printArea, 0); e.gc.setBackground(Colors.white); e.gc.setForeground(Colors.blue); int xStart = printArea.x + sizeAccess.x + textPadding; int yStart = (fullHeight - boxSize) / 2; for (int i = 0; i < numBoxes; i++) { Rectangle r = new Rectangle(xStart + (i * boxSizeAndPadding), yStart, boxSize, boxSize); e.gc.fillRectangle(r); e.gc.setForeground(Colors.blues[Colors.BLUES_DARKEST]); e.gc.drawRectangle(r); if (!hideCode) { e.gc.setForeground(oldColor); GCStringPrinter.printString(e.gc, "" + drawAccessCode.charAt(i), r, false, false, SWT.CENTER); } } } }); soToClipboard = (SWTSkinObjectText) skin.getSkinObject("pair-clipboard"); soToClipboard.addUrlClickedListener(new SWTSkinObjectText_UrlClickedListener() { public boolean urlClicked(URLInfo urlInfo) { if (urlInfo.url.equals("new")) { try { accessCode = pairingManager.getReplacementAccessCode(); } catch (PairingException e) { // ignore.. if error, lastErrorUpdates will trigger } control.redraw(); String s = soToClipboard.getText(); int i = s.indexOf("|"); if (i > 0) { soToClipboard.setText(s.substring(0, i - 1)); } } else if (urlInfo.url.equals("clip")) { ClipboardCopy.copyToClipBoard(accessCode); } return true; } }); SWTSkinButtonUtility btnToClipboard = new SWTSkinButtonUtility( soToClipboard); btnToClipboard.addSelectionListener(new ButtonListenerAdapter() { public void pressed(SWTSkinButtonUtility buttonUtility, SWTSkinObject skinObject, int stateMask) { } }); skinnedDialog.addCloseListener(new SkinnedDialogClosedListener() { public void skinDialogClosed(SkinnedDialog dialog) { skinnedDialog = null; pairingManager.removeListener(RemotePairingWindow.this); Utils.disposeSWTObjects(new Object[] { fontCode }); if (pairingTest != null) { pairingTest.cancel(); } } }); if (showFTUX) { soFTUX.getControl().moveAbove(null); } } hideCode = true; skinnedDialog.open(); hideCode = false; if (showFTUX) { switchToFTUX(); } else { switchToCode(); } } public void switchToFTUX() { SWTSkinObject soPairInstallArea = skin.getSkinObject("pair-install"); if (soPairInstallArea != null) { soPairInstallArea.getControl().moveAbove(null); } soFTUX.setVisible(true); soCode.setVisible(false); } public void switchToCode() { // use somethingChanged to trigger testPairing if needed somethingChanged(pairingManager); Utils.execSWTThread(new AERunnable() { public void runSupport() { if (skinnedDialog == null || skinnedDialog.isDisposed()) { return; } SWTSkinObjectImage soImage = (SWTSkinObjectImage) skin.getSkinObject("status-image"); if (soImage != null) { soImage.setImageByID("icon.spin", null); } SWTSkinObject soPairArea = skin.getSkinObject("reset-pair-area"); if (soPairArea != null) { soPairArea.getControl().moveAbove(null); } soFTUX.setVisible(false); soCode.setVisible(true); } }); } protected void testPairing(boolean delay) { if (SHOW_SPEW) { System.out.println("PAIR] Want testPairing; alreadyTested=" + alreadyTested + ";Delay?" + delay + ";" + Debug.getCompressedStackTrace()); } if (alreadyTested) { return; } lastPairingTestError = ""; alreadyTested = true; storedToClipboardText = soToClipboard.getText(); try { hideCode = true; Utils.execSWTThread(new AERunnable() { public void runSupport() { control.redraw(); SWTSkinObjectImage soImage = (SWTSkinObjectImage) skin.getSkinObject("status-image"); if (soImage != null) { soImage.setImageByID("icon.spin", null); } } }); soStatusText.setTextID("remote.pairing.test.running"); soStatusText.setTextColor(ColorCache.getColor(control.getDisplay(), "#000000")); soToClipboard.setText(" "); final PairingTestListener testListener = new PairingTestListener() { public void testStarted(PairingTest test) { } public void testComplete(PairingTest test) { if (skinnedDialog.isDisposed()) { return; } int outcome = test.getOutcome(); String iconID = null; String colorID = "#000000"; switch (outcome) { case PairingTest.OT_SUCCESS: fallBackStatusText = MessageText.getString("remote.pairing.test.success"); iconID = "icon.success"; colorID = "#007305"; break; case PairingTest.OT_CANCELLED: fallBackStatusText = test.getErrorMessage(); iconID = "icon.warning"; colorID = "#A97000"; break; case PairingTest.OT_SERVER_FAILED: case PairingTest.OT_SERVER_OVERLOADED: case PairingTest.OT_SERVER_UNAVAILABLE: fallBackStatusText = MessageText.getString( "remote.pairing.test.unavailable", new String[] { test.getErrorMessage() }); iconID = "icon.warning"; colorID = "#C98000"; break; default: fallBackStatusText = MessageText.getString( "remote.pairing.test.fail", new String[] { test.getErrorMessage() }); iconID = "icon.failure"; colorID = "#c90000"; break; } hideCode = false; final String fIconID = iconID; somethingChanged(pairingManager); lastPairingTestError = pairingTest.getErrorMessage(); Utils.execSWTThread(new AERunnable() { public void runSupport() { control.redraw(); SWTSkinObjectImage soImage = (SWTSkinObjectImage) skin.getSkinObject("status-image"); if (soImage != null) { soImage.setImageByID(fIconID, null); } } }); updateToolTip(); soStatusText.setText(fallBackStatusText); soStatusText.setTextColor(ColorCache.getColor(control.getDisplay(), colorID)); soToClipboard.setText(storedToClipboardText); } }; SimpleTimer.addEvent("testPairing", SystemTime.getOffsetTime(delay ? 5000 : 0), new TimerEventPerformer() { public void perform(TimerEvent event) { try { pairingTest = pairingManager.testService(PLUGINID_WEBUI, testListener); } catch (PairingException e) { finishFailedTest(); soStatusText.setText(Debug.getNestedExceptionMessage(e)); Debug.out(e); } if (pairingTest == null) { finishFailedTest(); } } }); if (DEBUG) { testListener.testComplete(testPairingClass); return; } } catch (Exception e) { finishFailedTest(); soStatusText.setText(Debug.getNestedExceptionMessage(e)); Debug.out(e); } } /** * * * @since 4.1.0.5 */ protected void updateToolTip() { SWTSkinObjectImage soImage = (SWTSkinObjectImage) skin.getSkinObject("status-image"); if (soImage != null) { String s = lastPairingTestError; if (s == null) { s = ""; } String status = pairingManager.getStatus(); if (status != null && status.length() > 0) { if (s.length() > 0) { s += "\n"; } s += "Pairing Status: " + status; } String lastPairingErr = pairingManager.getLastServerError(); if (lastPairingErr != null && lastPairingErr.length() > 0) { if (s.length() > 0) { s += "\n"; } s += "Pairing Error: " + lastPairingErr; } soImage.setTooltipID("!" + s + "!"); } } private void finishFailedTest() { hideCode = false; somethingChanged(pairingManager); Utils.execSWTThread(new AERunnable() { public void runSupport() { control.redraw(); } }); if (storedToClipboardText != null && storedToClipboardText.length() > 0) { soToClipboard.setText(storedToClipboardText); } } protected void installWebUI() { final PluginInstaller installer = AzureusCoreFactory.getSingleton().getPluginManager().getPluginInstaller(); StandardPlugin vuze_plugin = null; try { vuze_plugin = installer.getStandardPlugin(PLUGINID_WEBUI); } catch (Throwable e) { } if (vuze_plugin == null) { return; } if (vuze_plugin.isAlreadyInstalled()) { PluginInterface plugin = vuze_plugin.getAlreadyInstalledPlugin(); plugin.getPluginState().setDisabled(false); return; } try { switchToFTUX(); final SWTSkinObject soInstall = skin.getSkinObject("pairing-install"); final SWTSkinObject soLearnMore = skin.getSkinObject("learn-more"); if (soLearnMore != null) { soLearnMore.setVisible(false); } Map<Integer, Object> properties = new HashMap<Integer, Object>(); properties.put(UpdateCheckInstance.PT_UI_STYLE, UpdateCheckInstance.PT_UI_STYLE_SIMPLE); properties.put(UpdateCheckInstance.PT_UI_PARENT_SWT_COMPOSITE, soInstall.getControl()); properties.put(UpdateCheckInstance.PT_UI_DISABLE_ON_SUCCESS_SLIDEY, true); installer.install(new InstallablePlugin[] { vuze_plugin }, false, properties, new PluginInstallationListener() { public void completed() { if (soLearnMore != null) { soLearnMore.setVisible(true); } switchToCode(); } public void cancelled() { Utils.execSWTThread(new AERunnable() { public void runSupport() { if ( skinnedDialog != null && !skinnedDialog.isDisposed()){ skinnedDialog.close(); skinnedDialog = null; } } }); } public void failed(PluginException e) { Debug.out(e); //Utils.openMessageBox(Utils.findAnyShell(), SWT.OK, "Error", // e.toString()); } }); } catch (Throwable e) { Debug.printStackTrace(e); } } // @see com.aelitis.azureus.core.pairing.PairingManagerListener#somethingChanged(com.aelitis.azureus.core.pairing.PairingManager) public void somethingChanged(PairingManager pm) { if (skinnedDialog.isDisposed()) { return; } updateToolTip(); String lastAccessCode = accessCode; accessCode = pairingManager.peekAccessCode(); boolean newAccessCode = !StringCompareUtils.equals(lastAccessCode, accessCode); if (accessCode != null && getWebUI() != null && !alreadyTested && !pm.hasActionOutstanding()) { if (newAccessCode) { // pause while registering.. testPairing(true); } else { testPairing(false); } } if (newAccessCode) { Utils.execSWTThread(new AERunnable() { public void runSupport() { control.redraw(); } }); } } public static class testPairingClass implements PairingTest { int curOutcome = 0; int[] testOutcomes = { OT_SUCCESS, OT_FAILED, OT_CANCELLED, OT_SERVER_FAILED, OT_SERVER_OVERLOADED, OT_SERVER_UNAVAILABLE }; String[] testErrs = { "Success", "Could Not Connect blah blah technical stuff", "You Cancelled (unpossible!)", "Server Failed", "Server Overloaded", "Server Unavailable", }; public void inc() { curOutcome++; if (curOutcome == testOutcomes.length) { curOutcome = 0; } } public int getOutcome() { return testOutcomes[curOutcome]; } public String getErrorMessage() { return testErrs[curOutcome]; } public void cancel() { } } }