1 /* 2 * Copyright (C) Azureus Software, Inc, All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details ( see the LICENSE file ). 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 */ 18 19 package com.aelitis.azureus.ui.swt.subscriptions; 20 21 import java.util.Arrays; 22 import java.util.Comparator; 23 24 import org.eclipse.swt.SWT; 25 import org.eclipse.swt.custom.StackLayout; 26 import org.eclipse.swt.layout.FillLayout; 27 import org.eclipse.swt.layout.FormAttachment; 28 import org.eclipse.swt.layout.FormData; 29 import org.eclipse.swt.layout.FormLayout; 30 import org.eclipse.swt.widgets.Button; 31 import org.eclipse.swt.widgets.Composite; 32 import org.eclipse.swt.widgets.Display; 33 import org.eclipse.swt.widgets.Event; 34 import org.eclipse.swt.widgets.Label; 35 import org.eclipse.swt.widgets.Listener; 36 import org.eclipse.swt.widgets.ProgressBar; 37 import org.eclipse.swt.widgets.Shell; 38 import org.eclipse.swt.widgets.Table; 39 import org.eclipse.swt.widgets.TableColumn; 40 import org.eclipse.swt.widgets.TableItem; 41 import org.gudy.azureus2.core3.config.COConfigurationManager; 42 import org.gudy.azureus2.core3.internat.MessageText; 43 import org.gudy.azureus2.core3.util.AEThread2; 44 import org.gudy.azureus2.ui.swt.Utils; 45 import org.gudy.azureus2.ui.swt.components.shell.ShellFactory; 46 47 import com.aelitis.azureus.core.subs.Subscription; 48 import com.aelitis.azureus.core.subs.SubscriptionAssociationLookup; 49 import com.aelitis.azureus.core.subs.SubscriptionException; 50 import com.aelitis.azureus.core.subs.SubscriptionLookupListener; 51 import com.aelitis.azureus.core.subs.SubscriptionManager; 52 import com.aelitis.azureus.core.subs.SubscriptionManagerFactory; 53 import com.aelitis.azureus.core.subs.SubscriptionPopularityListener; 54 import com.aelitis.azureus.ui.swt.widgets.AnimatedImage; 55 56 public class SubscriptionListWindow implements SubscriptionLookupListener { 57 58 final private byte[] torrent_hash; 59 final private String[] networks; 60 final private boolean useCachedSubs; 61 62 private Display display; 63 private Shell shell; 64 65 AnimatedImage animatedImage; 66 67 Button action; 68 Label loadingText; 69 ProgressBar loadingProgress; 70 boolean loadingDone = false; 71 72 SubscriptionAssociationLookup lookup = null; 73 74 Composite mainComposite; 75 Composite loadingPanel; 76 Composite listPanel; 77 Table subscriptionsList; 78 StackLayout mainLayout; 79 80 private class SubscriptionItemModel { 81 String name; 82 long popularity; 83 String popularityDisplay; 84 Subscription subscription; 85 boolean selected; 86 } 87 88 SubscriptionItemModel subscriptionItems[]; 89 90 91 92 public SubscriptionListWindow( Shell parent, String display_name, byte[] torrent_hash, String[] networks, boolean useCachedSubs )93 SubscriptionListWindow( 94 Shell parent, 95 String display_name, 96 byte[] torrent_hash, 97 String[] networks, 98 boolean useCachedSubs ) 99 { 100 this.torrent_hash = torrent_hash; 101 this.networks = networks; 102 this.useCachedSubs = useCachedSubs; 103 104 shell = ShellFactory.createShell( parent, SWT.DIALOG_TRIM | SWT.RESIZE ); 105 Utils.setShellIcon(shell); 106 shell.setSize(400,300); 107 Utils.centerWindowRelativeTo( shell, parent ); 108 109 String networks_str = ""; 110 111 for ( String net: networks ){ 112 113 networks_str += 114 (networks_str.length()==0?"":", ") + 115 MessageText.getString( "ConfigView.section.connection.networks." + net ); 116 } 117 118 if ( networks_str.length() == 0 ){ 119 120 networks_str = MessageText.getString( "PeersView.uniquepiece.none" ); 121 } 122 123 display = shell.getDisplay(); 124 shell.setText(MessageText.getString("subscriptions.listwindow.title") + " [" + networks_str + "]" ); 125 126 shell.setLayout(new FormLayout()); 127 128 mainComposite = new Composite(shell,SWT.NONE); 129 Label separator = new Label(shell,SWT.SEPARATOR | SWT.HORIZONTAL); 130 Button cancel = new Button(shell,SWT.PUSH); 131 action = new Button(shell,SWT.PUSH); 132 cancel.setText(MessageText.getString("Button.cancel")); 133 134 FormData data; 135 136 data = new FormData(); 137 data.left = new FormAttachment(0,0); 138 data.right = new FormAttachment(100,0); 139 data.top = new FormAttachment(0,0); 140 data.bottom = new FormAttachment(separator,0); 141 Utils.setLayoutData(mainComposite, data); 142 143 data = new FormData(); 144 data.left = new FormAttachment(0,0); 145 data.right = new FormAttachment(100,0); 146 data.bottom = new FormAttachment(cancel,-2); 147 Utils.setLayoutData(separator, data); 148 149 data = new FormData(); 150 data.right = new FormAttachment(action); 151 data.width = 100; 152 data.bottom = new FormAttachment(100,-5); 153 Utils.setLayoutData(cancel, data); 154 155 data = new FormData(); 156 data.right = new FormAttachment(100,-5); 157 data.width = 100; 158 data.bottom = new FormAttachment(100,-5); 159 Utils.setLayoutData(action, data); 160 161 cancel.addListener(SWT.Selection, new Listener() { 162 public void handleEvent(Event arg0) { 163 if(lookup != null) { 164 lookup.cancel(); 165 } 166 if(!shell.isDisposed()) { 167 shell.dispose(); 168 } 169 } 170 }); 171 172 mainLayout = new StackLayout(); 173 mainComposite.setLayout(mainLayout); 174 175 loadingPanel = new Composite(mainComposite,SWT.NONE); 176 loadingPanel.setLayout(new FormLayout()); 177 178 listPanel = new Composite(mainComposite,SWT.NONE); 179 listPanel.setLayout(new FillLayout()); 180 181 subscriptionsList = new Table(listPanel,SWT.V_SCROLL | SWT.SINGLE | SWT.FULL_SELECTION | SWT.VIRTUAL); 182 subscriptionsList.setHeaderVisible(true); 183 184 TableColumn name = new TableColumn(subscriptionsList,SWT.NONE); 185 name.setText(MessageText.getString("subscriptions.listwindow.name")); 186 name.setWidth(Utils.adjustPXForDPI(310)); 187 name.setResizable(false); 188 189 TableColumn popularity = new TableColumn(subscriptionsList,SWT.NONE); 190 popularity.setText(MessageText.getString("subscriptions.listwindow.popularity")); 191 popularity.setWidth(Utils.adjustPXForDPI(70)); 192 popularity.setResizable(false); 193 194 subscriptionsList.addListener(SWT.SetData, new Listener() { 195 public void handleEvent(Event e) { 196 TableItem item = (TableItem) e.item; 197 int index = subscriptionsList.indexOf(item); 198 if(index >= 0 && index < subscriptionItems.length) { 199 SubscriptionItemModel subscriptionItem = subscriptionItems[index]; 200 item.setText(0,subscriptionItem.name); 201 item.setText(1,subscriptionItem.popularityDisplay); 202 } 203 } 204 }); 205 206 subscriptionsList.setSortColumn(popularity); 207 subscriptionsList.setSortDirection(SWT.DOWN); 208 209 subscriptionsList.addListener(SWT.Selection, new Listener() { 210 public void handleEvent(Event arg0) { 211 action.setEnabled(subscriptionsList.getSelectionIndex() != -1); 212 } 213 }); 214 215 Listener sortListener = new Listener() { 216 public void handleEvent(Event e) { 217 // determine new sort column and direction 218 TableColumn sortColumn = subscriptionsList.getSortColumn(); 219 TableColumn currentColumn = (TableColumn) e.widget; 220 int dir = subscriptionsList.getSortDirection(); 221 if (sortColumn == currentColumn) { 222 dir = dir == SWT.UP ? SWT.DOWN : SWT.UP; 223 } else { 224 subscriptionsList.setSortColumn(currentColumn); 225 dir = SWT.DOWN; 226 } 227 subscriptionsList.setSortDirection(dir); 228 sortAndRefresh(); 229 } 230 }; 231 name.addListener(SWT.Selection, sortListener); 232 popularity.addListener(SWT.Selection, sortListener); 233 234 animatedImage = new AnimatedImage(loadingPanel); 235 loadingText = new Label(loadingPanel,SWT.WRAP | SWT.CENTER); 236 loadingProgress = new ProgressBar(loadingPanel,SWT.HORIZONTAL); 237 238 animatedImage.setImageFromName("spinner_big"); 239 240 loadingText.setText(MessageText.getString("subscriptions.listwindow.loadingtext", new String[] { display_name })); 241 242 loadingProgress.setMinimum(0); 243 loadingProgress.setMaximum(300); 244 loadingProgress.setSelection(0); 245 246 data = new FormData(); 247 data.left = new FormAttachment(1,2,-16); 248 data.top = new FormAttachment(1,2,-32); 249 data.width = 32; 250 data.height = 32; 251 animatedImage.setLayoutData(data); 252 253 data = new FormData(); 254 data.left = new FormAttachment(0,5); 255 data.right = new FormAttachment(100,-5); 256 data.top = new FormAttachment(animatedImage.getControl(),10); 257 data.height = 50; 258 Utils.setLayoutData(loadingText, data); 259 260 data = new FormData(); 261 data.left = new FormAttachment(0,5); 262 data.right = new FormAttachment(100,-5); 263 data.top = new FormAttachment(loadingText,5); 264 Utils.setLayoutData(loadingProgress, data); 265 266 boolean autoCheck = COConfigurationManager.getBooleanParameter("subscriptions.autocheck"); 267 268 if(autoCheck) { 269 startChecking(); 270 } else { 271 action.setText(MessageText.getString("Button.yes")); 272 Composite acceptPanel = new Composite(mainComposite,SWT.NONE); 273 acceptPanel.setLayout(new FormLayout()); 274 275 Label acceptLabel = new Label(acceptPanel,SWT.WRAP | SWT.CENTER); 276 277 acceptLabel.setText(MessageText.getString("subscriptions.listwindow.autochecktext")); 278 279 data = new FormData(); 280 data.left = new FormAttachment(0,5); 281 data.right = new FormAttachment(100,-5); 282 data.top = new FormAttachment(1,3,0); 283 Utils.setLayoutData(acceptLabel, data); 284 285 action.addListener(SWT.Selection, new Listener() { 286 public void handleEvent(Event event) { 287 action.removeListener(SWT.Selection,this); 288 COConfigurationManager.setParameter("subscriptions.autocheck",true); 289 startChecking(); 290 mainComposite.layout(); 291 } 292 }); 293 mainLayout.topControl = acceptPanel; 294 } 295 296 297 //shell.setSize(400,300); 298 shell.open(); 299 300 } 301 startChecking()302 private void startChecking() { 303 action.setText(MessageText.getString("subscriptions.listwindow.subscribe")); 304 action.setEnabled(false); 305 try { 306 307 308 SubscriptionManager subs_man = SubscriptionManagerFactory.getSingleton(); 309 if ( useCachedSubs ){ 310 Subscription[] subs = subs_man.getKnownSubscriptions( torrent_hash ); 311 complete(torrent_hash,subs); 312 }else{ 313 lookup = subs_man.lookupAssociations( torrent_hash, networks, this); 314 315 lookup.setTimeout( 1*60*1000 ); 316 } 317 318 319 loadingDone = false; 320 AEThread2 progressMover = new AEThread2("progressMover",true) { 321 public void run() { 322 final int[] waitTime = new int[1]; 323 waitTime[0]= 100; 324 while(!loadingDone) { 325 if(display != null && ! display.isDisposed()) { 326 display.asyncExec(new Runnable() { 327 public void run() { 328 if(loadingProgress != null && !loadingProgress.isDisposed()) { 329 int currentSelection = loadingProgress.getSelection() +1; 330 loadingProgress.setSelection(currentSelection); 331 if(currentSelection > (loadingProgress.getMaximum()) * 80 / 100) { 332 waitTime[0] = 300; 333 } 334 if (currentSelection > (loadingProgress.getMaximum()) * 90 / 100) { 335 waitTime[0] = 1000; 336 } 337 } else { 338 loadingDone = true; 339 } 340 } 341 }); 342 } 343 try { 344 Thread.sleep(waitTime[0]); 345 //Thread.sleep(100); 346 } catch (Exception e) { 347 loadingDone = true; 348 } 349 } 350 } 351 }; 352 progressMover.start(); 353 354 } catch(Exception e) { 355 failed(null,null); 356 } 357 animatedImage.start(); 358 mainLayout.topControl = loadingPanel; 359 } 360 361 /*private void populateSubscription(final Subscription subscription) { 362 final TableItem item = new TableItem(subscriptionsList,SWT.NONE); 363 item.setData("subscription",subscription); 364 item.setText(0,subscription.getName()); 365 try { 366 item.setText(1,MessageText.getString("subscriptions.listwindow.popularity.reading")); 367 368 369 370 371 372 action.setEnabled(true); 373 }*/ 374 found(byte[] hash, Subscription subscription)375 public void found(byte[] hash, Subscription subscription) { 376 // TODO Auto-generated method stub 377 378 } 379 complete(final byte[] hash,final Subscription[] subscriptions)380 public void complete(final byte[] hash,final Subscription[] subscriptions) { 381 if( ! (subscriptions.length > 0) ) { 382 failed(hash, null); 383 } else { 384 385 if(display != null && !display.isDisposed()) { 386 display.asyncExec(new Runnable() { 387 public void run() { 388 subscriptionItems = new SubscriptionItemModel[subscriptions.length]; 389 for(int i = 0 ; i < subscriptions.length ; i++) { 390 final SubscriptionItemModel subscriptionItem = new SubscriptionItemModel(); 391 subscriptionItems[i] = subscriptionItem; 392 subscriptionItem.name = subscriptions[i].getName(); 393 subscriptionItem.popularity = -1; 394 subscriptionItem.popularityDisplay = MessageText.getString("subscriptions.listwindow.popularity.reading"); 395 subscriptionItem.subscription = subscriptions[i]; 396 397 try { 398 subscriptions[i].getPopularity( 399 new SubscriptionPopularityListener() 400 { 401 public void 402 gotPopularity( 403 long popularity ) 404 { 405 update(subscriptionItem,popularity, popularity + "" ); 406 } 407 408 public void 409 failed( 410 SubscriptionException error ) 411 { 412 update(subscriptionItem,-2,MessageText.getString("subscriptions.listwindow.popularity.unknown")); 413 } 414 415 416 }); 417 } catch(SubscriptionException e) { 418 419 update(subscriptionItem,-2,MessageText.getString("subscriptions.listwindow.popularity.unknown")); 420 421 } 422 423 } 424 425 animatedImage.stop(); 426 427 mainLayout.topControl = listPanel; 428 mainComposite.layout(); 429 430 sortAndRefresh(); 431 subscriptionsList.setSelection(0); 432 433 action.addListener(SWT.Selection, new Listener() { 434 public void handleEvent(Event arg0) { 435 if(subscriptionsList != null && !subscriptionsList.isDisposed()) { 436 int selectedIndex = subscriptionsList.getSelectionIndex(); 437 if(selectedIndex >= 0 && selectedIndex < subscriptionItems.length) { 438 Subscription subscription = (Subscription) subscriptionItems[selectedIndex].subscription; 439 if(subscription != null) { 440 subscription.setSubscribed(true); 441 subscription.requestAttention(); 442 } 443 } 444 } 445 } 446 }); 447 } 448 449 }); 450 } 451 } 452 } 453 454 protected void update( final SubscriptionItemModel subscriptionItem, final long popularity, final String text )455 update( 456 final SubscriptionItemModel subscriptionItem, 457 final long popularity, 458 final String text ) 459 { 460 display.asyncExec( 461 new Runnable() 462 { 463 public void 464 run() 465 { 466 subscriptionItem.popularity = popularity; 467 subscriptionItem.popularityDisplay = text; 468 469 sortAndRefresh(); 470 } 471 }); 472 } 473 sortAndRefresh()474 private void sortAndRefresh() { 475 476 if ( subscriptionsList.isDisposed()){ 477 478 return; 479 } 480 481 for(int i = 0 ; i < subscriptionItems.length ; i++) { 482 subscriptionItems[i].selected = false; 483 } 484 485 int currentSelection = subscriptionsList.getSelectionIndex(); 486 if(currentSelection >= 0 && currentSelection < subscriptionItems.length) { 487 subscriptionItems[currentSelection].selected = true; 488 } 489 490 final int dir = subscriptionsList.getSortDirection() == SWT.DOWN ? 1 : -1; 491 final boolean nameSort = subscriptionsList.getColumn(0) == subscriptionsList.getSortColumn(); 492 Arrays.sort(subscriptionItems,new Comparator() { 493 public int compare(Object arg0, Object arg1) { 494 SubscriptionItemModel item0 = (SubscriptionItemModel) arg0; 495 SubscriptionItemModel item1 = (SubscriptionItemModel) arg1; 496 if(nameSort) { 497 return dir * item0.name.compareTo(item1.name); 498 } else { 499 return dir * (int) (item1.popularity - item0.popularity); 500 } 501 } 502 }); 503 subscriptionsList.setItemCount(subscriptionItems.length); 504 subscriptionsList.clearAll(); 505 if(currentSelection >= 0 && currentSelection < subscriptionItems.length) { 506 for(int i = 0 ; i < subscriptionItems.length ; i++) { 507 if(subscriptionItems[i].selected) { 508 subscriptionsList.setSelection(i); 509 } 510 } 511 } 512 } 513 failed(byte[] hash,SubscriptionException error)514 public void failed(byte[] hash,SubscriptionException error) { 515 if(display != null && !display.isDisposed()) { 516 display.asyncExec(new Runnable() { 517 public void run() { 518 animatedImage.stop(); 519 animatedImage.dispose(); 520 loadingProgress.dispose(); 521 if ( !loadingText.isDisposed()){ 522 loadingText.setText(MessageText.getString("subscriptions.listwindow.failed")); 523 } 524 } 525 }); 526 } 527 } 528 } 529