1 11 package org.eclipse.jface.text.contentassist; 12 13 import org.eclipse.swt.SWT; 14 import org.eclipse.swt.events.SelectionEvent; 15 import org.eclipse.swt.events.SelectionListener; 16 import org.eclipse.swt.graphics.Point; 17 import org.eclipse.swt.graphics.Rectangle; 18 import org.eclipse.swt.widgets.Control; 19 import org.eclipse.swt.widgets.Display; 20 import org.eclipse.swt.widgets.Shell; 21 import org.eclipse.swt.widgets.Table; 22 import org.eclipse.swt.widgets.TableItem; 23 24 import org.eclipse.core.runtime.Assert; 25 import org.eclipse.core.runtime.IProgressMonitor; 26 import org.eclipse.core.runtime.IStatus; 27 import org.eclipse.core.runtime.Status; 28 import org.eclipse.core.runtime.jobs.Job; 29 30 import org.eclipse.jface.text.AbstractInformationControlManager; 31 import org.eclipse.jface.text.IInformationControl; 32 import org.eclipse.jface.text.IInformationControlCreator; 33 34 35 40 class AdditionalInfoController extends AbstractInformationControlManager { 41 42 47 private static abstract class Timer { 48 private static final int DELAY_UNTIL_JOB_IS_SCHEDULED= 50; 49 50 55 private abstract class Task implements Runnable { 56 59 public abstract long delay(); 60 63 public abstract void run(); 64 67 public abstract Task nextTask(); 68 } 69 70 74 private final Task IDLE= new Task() { 75 public void run() { 76 Assert.isTrue(false); 77 } 78 79 public Task nextTask() { 80 Assert.isTrue(false); 81 return null; 82 } 83 84 public long delay() { 85 return Long.MAX_VALUE; 86 } 87 88 public String toString() { 89 return "IDLE"; } 91 }; 92 95 private final Task FIRST_WAIT= new Task() { 96 public void run() { 97 final ICompletionProposalExtension5 proposal= getCurrentProposalEx(); 98 Job job= new Job(JFaceTextMessages.getString("AdditionalInfoController.job_name")) { protected IStatus run(IProgressMonitor monitor) { 100 Object info; 101 try { 102 info= proposal.getAdditionalProposalInfo(monitor); 103 } catch (RuntimeException x) { 104 108 return new Status(IStatus.WARNING, "org.eclipse.jface.text", IStatus.OK, "", x); } 110 setInfo((ICompletionProposal) proposal, info); 111 return new Status(IStatus.OK, "org.eclipse.jface.text", IStatus.OK, "", null); } 113 }; 114 job.schedule(); 115 } 116 117 public Task nextTask() { 118 return SECOND_WAIT; 119 } 120 121 public long delay() { 122 return DELAY_UNTIL_JOB_IS_SCHEDULED; 123 } 124 125 public String toString() { 126 return "FIRST_WAIT"; } 128 }; 129 133 private final Task SECOND_WAIT= new Task() { 134 public void run() { 135 allowShowing(); 137 } 138 139 public Task nextTask() { 140 return IDLE; 141 } 142 143 public long delay() { 144 return fDelay - DELAY_UNTIL_JOB_IS_SCHEDULED; 145 } 146 147 public String toString() { 148 return "SECOND_WAIT"; } 150 }; 151 154 private final Task LEGACY_WAIT= new Task() { 155 public void run() { 156 final ICompletionProposal proposal= getCurrentProposal(); 157 if (!fDisplay.isDisposed()) { 158 fDisplay.asyncExec(new Runnable () { 159 public void run() { 160 synchronized (Timer.this) { 161 if (proposal == getCurrentProposal()) { 162 Object info= proposal.getAdditionalProposalInfo(); 163 showInformation(proposal, info); 164 } 165 } 166 } 167 }); 168 } 169 } 170 171 public Task nextTask() { 172 return IDLE; 173 } 174 175 public long delay() { 176 return fDelay; 177 } 178 179 public String toString() { 180 return "LEGACY_WAIT"; } 182 }; 183 186 private final Task EXIT= new Task() { 187 public long delay() { 188 return 1; 189 } 190 191 public Task nextTask() { 192 Assert.isTrue(false); 193 return EXIT; 194 } 195 196 public void run() { 197 Assert.isTrue(false); 198 } 199 200 public String toString() { 201 return "EXIT"; } 203 }; 204 205 206 private final Thread fThread; 207 208 209 private Task fTask; 210 211 private long fNextWakeup; 212 213 private ICompletionProposal fCurrentProposal= null; 214 private Object fCurrentInfo= null; 215 private boolean fAllowShowing= false; 216 217 private final Display fDisplay; 218 private final int fDelay; 219 220 226 public Timer(Display display, int delay) { 227 fDisplay= display; 228 fDelay= delay; 229 long current= System.currentTimeMillis(); 230 schedule(IDLE, current); 231 232 fThread= new Thread (new Runnable () { 233 public void run() { 234 try { 235 loop(); 236 } catch (InterruptedException x) { 237 } 238 } 239 }, JFaceTextMessages.getString("InfoPopup.info_delay_timer_name")); fThread.start(); 241 } 242 243 246 public synchronized final void terminate() { 247 schedule(EXIT, System.currentTimeMillis()); 248 notifyAll(); 249 } 250 251 256 public final synchronized void reset(ICompletionProposal p) { 257 if (fCurrentProposal != p) { 258 fCurrentProposal= p; 259 fCurrentInfo= null; 260 fAllowShowing= false; 261 262 long oldWakeup= fNextWakeup; 263 Task task= taskOnReset(p); 264 schedule(task, System.currentTimeMillis()); 265 if (fNextWakeup < oldWakeup) 266 notifyAll(); 267 } 268 } 269 270 private Task taskOnReset(ICompletionProposal p) { 271 if (p == null) 272 return IDLE; 273 if (isExt5(p)) 274 return FIRST_WAIT; 275 return LEGACY_WAIT; 276 } 277 278 private synchronized void loop() throws InterruptedException { 279 long current= System.currentTimeMillis(); 280 Task task= currentTask(); 281 282 while (task != EXIT) { 283 long delay= fNextWakeup - current; 284 if (delay <= 0) { 285 task.run(); 286 task= task.nextTask(); 287 schedule(task, current); 288 } else { 289 wait(delay); 290 current= System.currentTimeMillis(); 291 task= currentTask(); 292 } 293 } 294 } 295 296 private Task currentTask() { 297 return fTask; 298 } 299 300 private void schedule(Task task, long current) { 301 fTask= task; 302 long nextWakeup= current + task.delay(); 303 if (nextWakeup <= current) 304 fNextWakeup= Long.MAX_VALUE; 305 else 306 fNextWakeup= nextWakeup; 307 } 308 309 private boolean isExt5(ICompletionProposal p) { 310 return p instanceof ICompletionProposalExtension5; 311 } 312 313 ICompletionProposal getCurrentProposal() { 314 return fCurrentProposal; 315 } 316 317 ICompletionProposalExtension5 getCurrentProposalEx() { 318 Assert.isTrue(fCurrentProposal instanceof ICompletionProposalExtension5); 319 return (ICompletionProposalExtension5) fCurrentProposal; 320 } 321 322 synchronized void setInfo(ICompletionProposal proposal, Object info) { 323 if (proposal == fCurrentProposal) { 324 fCurrentInfo= info; 325 if (fAllowShowing) { 326 triggerShowing(); 327 } 328 } 329 } 330 331 private void triggerShowing() { 332 final Object info= fCurrentInfo; 333 if (!fDisplay.isDisposed()) { 334 fDisplay.asyncExec(new Runnable () { 335 public void run() { 336 synchronized (Timer.this) { 337 if (info == fCurrentInfo) { 338 showInformation(fCurrentProposal, info); 339 } 340 } 341 } 342 }); 343 } 344 } 345 346 352 protected abstract void showInformation(ICompletionProposal proposal, Object info); 353 354 void allowShowing() { 355 fAllowShowing= true; 356 triggerShowing(); 357 } 358 } 359 362 private class TableSelectionListener implements SelectionListener { 363 364 367 public void widgetSelected(SelectionEvent e) { 368 handleTableSelectionChanged(); 369 } 370 371 374 public void widgetDefaultSelected(SelectionEvent e) { 375 } 376 } 377 378 379 private Table fProposalTable; 380 381 private SelectionListener fSelectionListener= new TableSelectionListener(); 382 383 private final int fDelay; 384 388 private Timer fTimer; 389 394 private ICompletionProposal fProposal; 395 400 private Object fInformation; 401 402 408 AdditionalInfoController(IInformationControlCreator creator, int delay) { 409 super(creator); 410 fDelay= delay; 411 setAnchor(ANCHOR_RIGHT); 412 setFallbackAnchors(new Anchor[] { ANCHOR_RIGHT, ANCHOR_LEFT, ANCHOR_BOTTOM }); 413 414 419 int spacing= -1; 420 setMargins(spacing, spacing); } 422 423 426 public void install(Control control) { 427 428 if (fProposalTable == control) { 429 return; 431 } 432 433 super.install(control.getShell()); 434 435 Assert.isTrue(control instanceof Table); 436 fProposalTable= (Table) control; 437 fProposalTable.addSelectionListener(fSelectionListener); 438 fTimer= new Timer(fProposalTable.getDisplay(), fDelay) { 439 protected void showInformation(ICompletionProposal proposal, Object info) { 440 AdditionalInfoController.this.showInformation(proposal, info); 441 } 442 }; 443 } 444 445 448 public void disposeInformationControl() { 449 450 if (fTimer !=null) { 451 fTimer.terminate(); 452 fTimer= null; 453 } 454 455 fProposal= null; 456 fInformation= null; 457 458 if (fProposalTable != null && !fProposalTable.isDisposed()) { 459 fProposalTable.removeSelectionListener(fSelectionListener); 460 fProposalTable= null; 461 } 462 463 super.disposeInformationControl(); 464 } 465 466 469 public void handleTableSelectionChanged() { 470 471 if (fProposalTable != null && !fProposalTable.isDisposed() && fProposalTable.isVisible()) { 472 TableItem[] selection= fProposalTable.getSelection(); 473 if (selection != null && selection.length > 0) { 474 475 TableItem item= selection[0]; 476 477 Object d= item.getData(); 478 if (d instanceof ICompletionProposal) { 479 ICompletionProposal p= (ICompletionProposal) d; 480 fTimer.reset(p); 481 } 482 } 483 } 484 } 485 486 void showInformation(ICompletionProposal proposal, Object info) { 487 if (fProposalTable == null || fProposalTable.isDisposed()) 488 return; 489 490 if (fProposal == proposal && ((info == null && fInformation == null) || (info != null && info.equals(fInformation)))) 491 return; 492 493 fInformation= info; 494 fProposal= proposal; 495 showInformation(); 496 } 497 498 501 protected void computeInformation() { 502 if (fProposal instanceof ICompletionProposalExtension3) 503 setCustomInformationControlCreator(((ICompletionProposalExtension3) fProposal).getInformationControlCreator()); 504 else 505 setCustomInformationControlCreator(null); 506 507 Point size= computeTrueShellSize(fProposalTable.getShell()); 509 510 setInformation(fInformation, new Rectangle(0, 0, size.x, size.y)); 512 } 513 514 521 private Point computeTrueShellSize(Shell shell) { 522 Point size= shell.getSize(); 523 if ("gtk".equals(SWT.getPlatform())) { 525 Rectangle trim= shell.computeTrim(0, 0, 0, 0); 526 size.x += trim.width; 527 size.y += trim.height; 528 } 529 return size; 530 } 531 532 535 protected Point computeLocation(Rectangle subjectArea, Point controlSize, Anchor anchor) { 536 Point location= super.computeLocation(subjectArea, controlSize, anchor); 537 538 543 Rectangle trim= fProposalTable.getShell().computeTrim(0, 0, 0, 0); 544 location.x += trim.x; 545 location.y += trim.y; 546 547 return location; 548 } 549 550 553 protected Point computeSizeConstraints(Control subjectControl, IInformationControl informationControl) { 554 Point sizeConstraint= super.computeSizeConstraints(subjectControl, informationControl); 555 Point size= computeTrueShellSize(subjectControl.getShell()); 556 557 if (sizeConstraint.x < size.x) 558 sizeConstraint.x= size.x; 559 if (sizeConstraint.y < size.y) 560 sizeConstraint.y= size.y; 561 return sizeConstraint; 562 } 563 } 564 565 566 | Popular Tags |