View | Details | Raw Unified | Return to bug 195691 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/mylyn/internal/tasks/ui/wizards/ScreenshotAttachmentPage.java (-76 / +251 lines)
Lines 32-46 Link Here
32
import org.eclipse.swt.events.PaintListener;
32
import org.eclipse.swt.events.PaintListener;
33
import org.eclipse.swt.events.SelectionAdapter;
33
import org.eclipse.swt.events.SelectionAdapter;
34
import org.eclipse.swt.events.SelectionEvent;
34
import org.eclipse.swt.events.SelectionEvent;
35
import org.eclipse.swt.graphics.Color;
35
import org.eclipse.swt.graphics.Cursor;
36
import org.eclipse.swt.graphics.Cursor;
36
import org.eclipse.swt.graphics.GC;
37
import org.eclipse.swt.graphics.GC;
37
import org.eclipse.swt.graphics.Image;
38
import org.eclipse.swt.graphics.Image;
38
import org.eclipse.swt.graphics.Point;
39
import org.eclipse.swt.graphics.Point;
40
import org.eclipse.swt.graphics.RGB;
39
import org.eclipse.swt.graphics.Rectangle;
41
import org.eclipse.swt.graphics.Rectangle;
40
import org.eclipse.swt.graphics.Region;
42
import org.eclipse.swt.graphics.Region;
41
import org.eclipse.swt.layout.GridLayout;
43
import org.eclipse.swt.layout.GridLayout;
42
import org.eclipse.swt.widgets.Button;
44
import org.eclipse.swt.widgets.Button;
43
import org.eclipse.swt.widgets.Canvas;
45
import org.eclipse.swt.widgets.Canvas;
46
import org.eclipse.swt.widgets.ColorDialog;
44
import org.eclipse.swt.widgets.Composite;
47
import org.eclipse.swt.widgets.Composite;
45
import org.eclipse.swt.widgets.Display;
48
import org.eclipse.swt.widgets.Display;
46
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.swt.widgets.Shell;
Lines 69-75 Link Here
69
72
70
	private Button fitButton;
73
	private Button fitButton;
71
74
72
	private Image screenshotImage;
75
	private Button cropButton;
76
77
	private Button markButton;
78
79
	private Button colorButton;
80
81
	private Image colorIcon;
82
83
	private Color markColor;
84
85
	private Button resetButton;
86
87
	/**
88
	 * Original screenshot image; used for backup purposes
89
	 */
90
	private Image originalImage;
91
92
	/**
93
	 * Copy of {@link #originalImage original} image; all drawing operations are done here; base for the result image
94
	 */
95
	private Image workImage;
96
97
	/**
98
	 * Used to draw into {@link #workImage}
99
	 */
100
	private GC workImageGC;
73
101
74
	private Canvas canvas;
102
	private Canvas canvas;
75
103
Lines 87-94 Link Here
87
	private Rectangle originalSelection;
115
	private Rectangle originalSelection;
88
116
89
	/**
117
	/**
90
	 * Temporary storage for selection start point or selection resizing initial reference point; this value is
118
	 * Temporary storage for selection start point, selection resizing initial reference point or previous mark point
91
	 * normalized to real image coordinates, no matter the zoom level (see {@link #scaleFactor})
119
	 * (it depends on current tool); this value is normalized to real image coordinates, no matter the zoom level (see
120
	 * {@link #scaleFactor})
92
	 */
121
	 */
93
	private Point startPoint;
122
	private Point startPoint;
94
123
Lines 112-118 Link Here
112
	 */
141
	 */
113
	private static enum Action {
142
	private static enum Action {
114
143
115
		IDLE, SELECTING, RESIZING_SELECTION, MOVING_SELECTION;
144
		IDLE, SELECTING, RESIZING_SELECTION, MOVING_SELECTION, MARKING;
116
145
117
	};
146
	};
118
147
Lines 131-137 Link Here
131
	}
160
	}
132
161
133
	public void createControl(Composite parent) {
162
	public void createControl(Composite parent) {
134
135
		Composite composite = new Composite(parent, SWT.NONE);
163
		Composite composite = new Composite(parent, SWT.NONE);
136
		composite.setLayout(new GridLayout());
164
		composite.setLayout(new GridLayout());
137
		setControl(composite);
165
		setControl(composite);
Lines 139-154 Link Here
139
		allocateCursors();
167
		allocateCursors();
140
168
141
		Composite buttonsComposite = new Composite(composite, SWT.NONE);
169
		Composite buttonsComposite = new Composite(composite, SWT.NONE);
142
		buttonsComposite.setLayout(new GridLayout(3, false));
170
		buttonsComposite.setLayout(new GridLayout(6, false));
143
		captureButton = new Button(buttonsComposite, SWT.PUSH);
171
		captureButton = new Button(buttonsComposite, SWT.PUSH);
144
		captureButton.setText("Capture Desktop");
172
		captureButton.setText("&Capture Desktop");
145
		captureButton.setImage(TasksUiImages.getImage(TasksUiImages.IMAGE_CAPTURE));
173
		captureButton.setImage(TasksUiImages.getImage(TasksUiImages.IMAGE_CAPTURE));
146
		captureButton.addSelectionListener(new SelectionAdapter() {
174
		captureButton.addSelectionListener(new SelectionAdapter() {
147
175
176
			private boolean isFirstCapture = true;
177
148
			public void widgetSelected(SelectionEvent e) {
178
			public void widgetSelected(SelectionEvent e) {
149
				captureScreenshotContent();
179
				captureScreenshotContent();
150
				page.setErrorMessage(null);
180
				page.setErrorMessage(null);
151
				fitButton.setEnabled(true);
181
				if (isFirstCapture) {
182
					isFirstCapture = false;
183
					fitButton.setEnabled(true);
184
					cropButton.setEnabled(true);
185
					cropButton.setSelection(true);
186
					markButton.setEnabled(true);
187
					resetButton.setEnabled(true);
188
				}
152
			}
189
			}
153
190
154
		});
191
		});
Lines 187-193 Link Here
187
//		});
224
//		});
188
225
189
		fitButton = new Button(buttonsComposite, SWT.TOGGLE);
226
		fitButton = new Button(buttonsComposite, SWT.TOGGLE);
190
		fitButton.setText("Fit Image");
227
		fitButton.setText("&Fit Image");
191
		fitButton.setImage(TasksUiImages.getImage(TasksUiImages.IMAGE_FIT));
228
		fitButton.setImage(TasksUiImages.getImage(TasksUiImages.IMAGE_FIT));
192
		fitButton.addSelectionListener(new SelectionAdapter() {
229
		fitButton.addSelectionListener(new SelectionAdapter() {
193
230
Lines 199-204 Link Here
199
		fitButton.setSelection(true);
236
		fitButton.setSelection(true);
200
		fitButton.setEnabled(false);
237
		fitButton.setEnabled(false);
201
238
239
		cropButton = new Button(buttonsComposite, SWT.TOGGLE);
240
		cropButton.setText("Cro&p");
241
		cropButton.addSelectionListener(new SelectionAdapter() {
242
243
			@Override
244
			public void widgetSelected(SelectionEvent e) {
245
				currentAction = Action.IDLE;
246
				cropButton.setSelection(true);
247
				markButton.setSelection(false);
248
				colorButton.setEnabled(false);
249
				canvas.redraw();
250
			}
251
252
		});
253
		cropButton.setEnabled(false);
254
255
		markButton = new Button(buttonsComposite, SWT.TOGGLE);
256
		markButton.setText("&Mark");
257
		markButton.addSelectionListener(new SelectionAdapter() {
258
259
			@Override
260
			public void widgetSelected(SelectionEvent e) {
261
				currentAction = Action.MARKING;
262
				cropButton.setSelection(false);
263
				markButton.setSelection(true);
264
				colorButton.setEnabled(true);
265
				canvas.redraw();
266
			}
267
268
		});
269
		markButton.setEnabled(false);
270
271
		colorButton = new Button(buttonsComposite, SWT.PUSH);
272
		colorButton.setText("Change Co&lor...");
273
		colorIcon = new Image(Display.getCurrent(), 16, 16);
274
		setMarkColor(new RGB(255, 0, 0));
275
		colorButton.setEnabled(false);
276
		colorButton.addSelectionListener(new SelectionAdapter() {
277
278
			@Override
279
			public void widgetSelected(SelectionEvent e) {
280
				ColorDialog dialog = new ColorDialog(getControl().getShell());
281
				RGB color = dialog.open();
282
				if (color != null) {
283
					setMarkColor(color);
284
				}
285
			}
286
287
		});
288
289
		resetButton = new Button(buttonsComposite, SWT.PUSH);
290
		resetButton.setText("&Reset Image");
291
		resetButton.addSelectionListener(new SelectionAdapter() {
292
293
			@Override
294
			public void widgetSelected(SelectionEvent e) {
295
				workImageGC.drawImage(originalImage, 0, 0);
296
				canvas.redraw();
297
			}
298
299
		});
300
		resetButton.setEnabled(false);
301
202
		scrolledComposite = new ScrolledComposite(composite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
302
		scrolledComposite = new ScrolledComposite(composite, SWT.V_SCROLL | SWT.H_SCROLL | SWT.BORDER);
203
		scrolledComposite.setLayoutData(GridDataFactory.fillDefaults()
303
		scrolledComposite.setLayoutData(GridDataFactory.fillDefaults()
204
				.align(SWT.FILL, SWT.FILL)
304
				.align(SWT.FILL, SWT.FILL)
Lines 210-224 Link Here
210
		canvas.addPaintListener(new PaintListener() {
310
		canvas.addPaintListener(new PaintListener() {
211
311
212
			public void paintControl(PaintEvent e) {
312
			public void paintControl(PaintEvent e) {
213
				if (screenshotImage != null) {
313
				if (workImage != null) {
214
					Rectangle imageBounds = screenshotImage.getBounds();
314
					Rectangle imageBounds = workImage.getBounds();
215
					Rectangle canvasBounds = canvas.getClientArea();
315
					Rectangle canvasBounds = canvas.getClientArea();
216
316
217
					if (fitButton.getSelection()) {
317
					if (fitButton.getSelection()) {
218
						e.gc.drawImage(screenshotImage, 0, 0, imageBounds.width, imageBounds.height, 0, 0,
318
						e.gc.drawImage(workImage, 0, 0, imageBounds.width, imageBounds.height, 0, 0,
219
								canvasBounds.width, canvasBounds.height);
319
								canvasBounds.width, canvasBounds.height);
220
					} else {
320
					} else {
221
						e.gc.drawImage(screenshotImage, 0, 0);
321
						e.gc.drawImage(workImage, 0, 0);
222
					}
322
					}
223
323
224
					if (currentAction == Action.IDLE) {
324
					if (currentAction == Action.IDLE) {
Lines 226-232 Link Here
226
							drawSelection(e.gc);
326
							drawSelection(e.gc);
227
						}
327
						}
228
					} else if (currentAction == Action.SELECTING || currentAction == Action.RESIZING_SELECTION
328
					} else if (currentAction == Action.SELECTING || currentAction == Action.RESIZING_SELECTION
229
							|| currentAction == Action.MOVING_SELECTION) {
329
							|| currentAction == Action.MOVING_SELECTION || currentAction == Action.MARKING) {
230
						if (currentSelection != null) {
330
						if (currentSelection != null) {
231
							drawSelectionPreview(e.gc);
331
							drawSelectionPreview(e.gc);
232
						}
332
						}
Lines 250-257 Link Here
250
		registerMouseListeners();
350
		registerMouseListeners();
251
	}
351
	}
252
352
353
	private void setMarkColor(RGB color) {
354
		if (markColor != null) {
355
			markColor.dispose();
356
		}
357
		markColor = new Color(Display.getCurrent(), color);
358
		if (workImageGC != null) {
359
			workImageGC.setForeground(markColor);
360
		}
361
362
		GC colorGC = new GC(colorIcon);
363
		colorGC.setBackground(markColor);
364
		colorGC.fillRectangle(0, 0, 15, 15);
365
		colorGC.drawRectangle(0, 0, 15, 15);
366
		colorGC.dispose();
367
368
		colorButton.setImage(colorIcon);
369
	}
370
253
	@Override
371
	@Override
254
	public void dispose() {
372
	public void dispose() {
373
		disposeImageResources();
374
		if (markColor != null) {
375
			markColor.dispose();
376
		}
377
		if (colorIcon != null) {
378
			colorIcon.dispose();
379
		}
380
255
		canvas.setCursor(null);
381
		canvas.setCursor(null);
256
		for (Cursor cursor : cursors.values()) {
382
		for (Cursor cursor : cursors.values()) {
257
			cursor.dispose();
383
			cursor.dispose();
Lines 259-264 Link Here
259
		super.dispose();
385
		super.dispose();
260
	}
386
	}
261
387
388
	private void disposeImageResources() {
389
		if (originalImage != null) {
390
			originalImage.dispose();
391
		}
392
		if (workImageGC != null) {
393
			workImageGC.dispose();
394
		}
395
		if (workImage != null) {
396
			workImage.dispose();
397
		}
398
	}
399
400
	private static final int CURSOR_MARK_TOOL = -1;
401
262
	private void allocateCursors() {
402
	private void allocateCursors() {
263
		Display display = Display.getCurrent();
403
		Display display = Display.getCurrent();
264
		cursors.put(SWT.CURSOR_ARROW, new Cursor(display, SWT.CURSOR_ARROW));
404
		cursors.put(SWT.CURSOR_ARROW, new Cursor(display, SWT.CURSOR_ARROW));
Lines 268-273 Link Here
268
		cursors.put(SWT.CURSOR_SIZENS, new Cursor(display, SWT.CURSOR_SIZENS));
408
		cursors.put(SWT.CURSOR_SIZENS, new Cursor(display, SWT.CURSOR_SIZENS));
269
		cursors.put(SWT.CURSOR_SIZEWE, new Cursor(display, SWT.CURSOR_SIZEWE));
409
		cursors.put(SWT.CURSOR_SIZEWE, new Cursor(display, SWT.CURSOR_SIZEWE));
270
		cursors.put(SWT.CURSOR_CROSS, new Cursor(display, SWT.CURSOR_CROSS));
410
		cursors.put(SWT.CURSOR_CROSS, new Cursor(display, SWT.CURSOR_CROSS));
411
412
		// TODO: allocate custom cursor for "mark" tool
413
		cursors.put(CURSOR_MARK_TOOL, new Cursor(display, SWT.CURSOR_HAND));
271
	}
414
	}
272
415
273
	private Rectangle getScaledSelection() {
416
	private Rectangle getScaledSelection() {
Lines 278-293 Link Here
278
		int y = (int) Math.round(currentSelection.y * scaleFactor);
421
		int y = (int) Math.round(currentSelection.y * scaleFactor);
279
		int right = (int) Math.round((currentSelection.x + currentSelection.width) * scaleFactor);
422
		int right = (int) Math.round((currentSelection.x + currentSelection.width) * scaleFactor);
280
		int bottom = (int) Math.round((currentSelection.y + currentSelection.height) * scaleFactor);
423
		int bottom = (int) Math.round((currentSelection.y + currentSelection.height) * scaleFactor);
281
		int width = Math.min(right, (int) Math.round((screenshotImage.getBounds().width - 1) * scaleFactor)) - x;
424
		int width = Math.min(right, (int) Math.round((workImage.getBounds().width - 1) * scaleFactor)) - x;
282
		int height = Math.min(bottom, (int) Math.round((screenshotImage.getBounds().height - 1) * scaleFactor)) - y;
425
		int height = Math.min(bottom, (int) Math.round((workImage.getBounds().height - 1) * scaleFactor)) - y;
283
		return new Rectangle(x, y, width, height);
426
		return new Rectangle(x, y, width, height);
284
	}
427
	}
285
428
286
	@Override
429
	@Override
287
	public boolean isPageComplete() {
430
	public boolean isPageComplete() {
288
		if (screenshotImage == null)
431
		return workImage != null;
289
			return false;
290
		return true;
291
	}
432
	}
292
433
293
	@Override
434
	@Override
Lines 296-302 Link Here
296
		attachment.setContentType("image/jpeg");
437
		attachment.setContentType("image/jpeg");
297
		page.setFilePath(InputAttachmentSourcePage.SCREENSHOT_LABEL);
438
		page.setFilePath(InputAttachmentSourcePage.SCREENSHOT_LABEL);
298
		page.setContentType();
439
		page.setContentType();
299
		getCropScreenshot();
300
		return page;
440
		return page;
301
	}
441
	}
302
442
Lines 306-314 Link Here
306
	}
446
	}
307
447
308
	private void captureScreenshotContent() {
448
	private void captureScreenshotContent() {
309
449
		Display display = Display.getDefault();
310
		final Display display = Display.getDefault();
450
		Shell wizardShell = getWizard().getContainer().getShell();
311
		final Shell wizardShell = getWizard().getContainer().getShell();
312
		wizardShell.setVisible(false);
451
		wizardShell.setVisible(false);
313
452
314
		// NOTE: need a wait since the shell can take time to disappear (e.g. fade on Vista)
453
		// NOTE: need a wait since the shell can take time to disappear (e.g. fade on Vista)
Lines 318-341 Link Here
318
			// ignore
457
			// ignore
319
		}
458
		}
320
459
321
		display.asyncExec(new Runnable() {
460
		disposeImageResources();
322
			public void run() {
461
		Rectangle displayBounds = display.getBounds();
323
				Rectangle displayBounds = display.getBounds();
462
		originalImage = new Image(display, displayBounds);
324
				screenshotImage = new Image(display, displayBounds);
463
		workImage = new Image(display, displayBounds);
325
464
326
				GC gc = new GC(display);
465
		GC gc = new GC(display);
327
				gc.copyArea(screenshotImage, 0, 0);
466
		gc.copyArea(originalImage, 0, 0);
328
				gc.dispose();
467
		gc.copyArea(workImage, 0, 0);
468
		gc.dispose();
329
469
330
				clearSelection();
470
		workImageGC = new GC(workImage);
331
				refreshCanvasSize();
471
		workImageGC.setForeground(markColor);
472
		workImageGC.setLineWidth(4);
473
		workImageGC.setLineCap(SWT.CAP_ROUND);
332
474
333
				wizardShell.setVisible(true);
475
		clearSelection();
334
				if (screenshotImage != null) {
476
		refreshCanvasSize();
335
					setPageComplete(true);
477
336
				}
478
		wizardShell.setVisible(true);
337
			}
479
		setPageComplete(true);
338
		});
339
	}
480
	}
340
481
341
	/**
482
	/**
Lines 352-358 Link Here
352
		currentSelection = new Rectangle(startX, startY, width, height);
493
		currentSelection = new Rectangle(startX, startY, width, height);
353
494
354
		// Decreases 1 pixel size from original image because Rectangle.intersect() consider them as right-bottom limit
495
		// Decreases 1 pixel size from original image because Rectangle.intersect() consider them as right-bottom limit
355
		Rectangle imageBounds = screenshotImage.getBounds();
496
		Rectangle imageBounds = workImage.getBounds();
356
		imageBounds.width--;
497
		imageBounds.width--;
357
		imageBounds.height--;
498
		imageBounds.height--;
358
		currentSelection.intersect(imageBounds);
499
		currentSelection.intersect(imageBounds);
Lines 367-373 Link Here
367
			return;
508
			return;
368
		}
509
		}
369
510
370
		canvas.setCursor(null);
371
		grabPoints.clear();
511
		grabPoints.clear();
372
		Rectangle scaledSelection = getScaledSelection();
512
		Rectangle scaledSelection = getScaledSelection();
373
		grabPoints.add(GrabPoint.createGrabPoint(scaledSelection.x, scaledSelection.y, SWT.CURSOR_SIZENWSE, EnumSet.of(
513
		grabPoints.add(GrabPoint.createGrabPoint(scaledSelection.x, scaledSelection.y, SWT.CURSOR_SIZENWSE, EnumSet.of(
Lines 393-399 Link Here
393
				originalSelection.height);
533
				originalSelection.height);
394
		int deltaX = x - startPoint.x;
534
		int deltaX = x - startPoint.x;
395
		int deltaY = y - startPoint.y;
535
		int deltaY = y - startPoint.y;
396
		Rectangle imageBounds = screenshotImage.getBounds();
536
		Rectangle imageBounds = workImage.getBounds();
397
537
398
		// Check current selection limits
538
		// Check current selection limits
399
		if (resizableSides.contains(SelectionSide.LEFT)) {
539
		if (resizableSides.contains(SelectionSide.LEFT)) {
Lines 447-453 Link Here
447
		if (newY < 0) {
587
		if (newY < 0) {
448
			newY = 0;
588
			newY = 0;
449
		}
589
		}
450
		Rectangle imageBounds = screenshotImage.getBounds();
590
		Rectangle imageBounds = workImage.getBounds();
451
		if (newX + originalSelection.width - 1 > imageBounds.width) {
591
		if (newX + originalSelection.width - 1 > imageBounds.width) {
452
			newX = imageBounds.width - originalSelection.width;
592
			newX = imageBounds.width - originalSelection.width;
453
		}
593
		}
Lines 464-478 Link Here
464
			 * If a selection is in course, moving the mouse around refreshes the selection rectangle
604
			 * If a selection is in course, moving the mouse around refreshes the selection rectangle
465
			 */
605
			 */
466
			public void mouseMove(MouseEvent e) {
606
			public void mouseMove(MouseEvent e) {
607
				int scaledX = (int) Math.round(e.x / scaleFactor);
608
				int scaledY = (int) Math.round(e.y / scaleFactor);
609
467
				if (currentAction == Action.SELECTING) {
610
				if (currentAction == Action.SELECTING) {
468
					// Selection in course
611
					refreshCurrentSelection(scaledX, scaledY);
469
					refreshCurrentSelection((int) Math.round(e.x / scaleFactor), (int) Math.round(e.y / scaleFactor));
470
					canvas.redraw();
612
					canvas.redraw();
471
				} else if (currentAction == Action.RESIZING_SELECTION) {
613
				} else if (currentAction == Action.RESIZING_SELECTION) {
472
					refreshSelectionResize((int) Math.round(e.x / scaleFactor), (int) Math.round(e.y / scaleFactor));
614
					refreshSelectionResize(scaledX, scaledY);
473
					canvas.redraw();
615
					canvas.redraw();
474
				} else if (currentAction == Action.MOVING_SELECTION) {
616
				} else if (currentAction == Action.MOVING_SELECTION) {
475
					refreshSelectionPosition((int) Math.round(e.x / scaleFactor), (int) Math.round(e.y / scaleFactor));
617
					refreshSelectionPosition(scaledX, scaledY);
476
					canvas.redraw();
618
					canvas.redraw();
477
				} else if (currentAction == Action.IDLE && currentSelection != null) {
619
				} else if (currentAction == Action.IDLE && currentSelection != null) {
478
					boolean cursorSet = false;
620
					boolean cursorSet = false;
Lines 491-498 Link Here
491
						canvas.setCursor(cursors.get(SWT.CURSOR_SIZEALL));
633
						canvas.setCursor(cursors.get(SWT.CURSOR_SIZEALL));
492
						cursorSet = true;
634
						cursorSet = true;
493
					}
635
					}
494
					if (!cursorSet && canvas.getCursor() != null) {
636
495
						canvas.setCursor(null);
637
					// If I'm out, the default cursor for cropping mode is cross
638
					Cursor crossCursor = cursors.get(SWT.CURSOR_CROSS);
639
					if (!cursorSet && canvas.getCursor() != crossCursor) {
640
						canvas.setCursor(crossCursor);
641
					}
642
				} else if (currentAction == Action.MARKING) {
643
					drawMarkLine(scaledX, scaledY);
644
645
					Cursor markCursor = cursors.get(CURSOR_MARK_TOOL);
646
					if (canvas.getCursor() != markCursor) {
647
						canvas.setCursor(markCursor);
496
					}
648
					}
497
				}
649
				}
498
			}
650
			}
Lines 508-515 Link Here
508
			public void mouseUp(MouseEvent e) {
660
			public void mouseUp(MouseEvent e) {
509
				if (currentAction == Action.SELECTING || currentAction == Action.RESIZING_SELECTION
661
				if (currentAction == Action.SELECTING || currentAction == Action.RESIZING_SELECTION
510
						|| currentAction == Action.MOVING_SELECTION) {
662
						|| currentAction == Action.MOVING_SELECTION) {
511
					canvas.setCursor(cursors.get(SWT.CURSOR_ARROW));
512
513
					int scaledX = (int) Math.round(e.x / scaleFactor);
663
					int scaledX = (int) Math.round(e.x / scaleFactor);
514
					int scaledY = (int) Math.round(e.y / scaleFactor);
664
					int scaledY = (int) Math.round(e.y / scaleFactor);
515
					if (currentAction == Action.SELECTING) {
665
					if (currentAction == Action.SELECTING) {
Lines 527-532 Link Here
527
					currentAction = Action.IDLE;
677
					currentAction = Action.IDLE;
528
678
529
					canvas.redraw();
679
					canvas.redraw();
680
				} else if (currentAction == Action.MARKING) {
681
					startPoint = null;
530
				}
682
				}
531
			}
683
			}
532
684
Lines 534-540 Link Here
534
			 * Pressing mouse button starts a selection; normalizes and marks the start point
686
			 * Pressing mouse button starts a selection; normalizes and marks the start point
535
			 */
687
			 */
536
			public void mouseDown(MouseEvent e) {
688
			public void mouseDown(MouseEvent e) {
537
				if (currentAction != Action.IDLE) {
689
				int scaledX = (int) (e.x / scaleFactor);
690
				int scaledY = (int) (e.y / scaleFactor);
691
692
				if (currentAction == Action.MARKING) {
693
					startPoint = new Point(scaledX, scaledY);
694
					drawMarkLine(scaledX, scaledY);
695
					canvas.setCursor(cursors.get(CURSOR_MARK_TOOL));
696
					return;
697
				} else if (currentAction != Action.IDLE) {
538
					return;
698
					return;
539
				}
699
				}
540
700
Lines 545-551 Link Here
545
							originalSelection = currentSelection;
705
							originalSelection = currentSelection;
546
							currentAction = Action.RESIZING_SELECTION;
706
							currentAction = Action.RESIZING_SELECTION;
547
							resizableSides = point.resizableSides;
707
							resizableSides = point.resizableSides;
548
							startPoint = new Point((int) (e.x / scaleFactor), (int) (e.y / scaleFactor));
708
							startPoint = new Point(scaledX, scaledY);
549
							canvas.redraw();
709
							canvas.redraw();
550
							return;
710
							return;
551
						}
711
						}
Lines 553-563 Link Here
553
				}
713
				}
554
714
555
				// Check if I could move the selection
715
				// Check if I could move the selection
556
				if (currentSelection != null
716
				if (currentSelection != null && currentSelection.contains(scaledX, scaledY)) {
557
						&& currentSelection.contains((int) (e.x / scaleFactor), (int) (e.y / scaleFactor))) {
558
					originalSelection = currentSelection;
717
					originalSelection = currentSelection;
559
					currentAction = Action.MOVING_SELECTION;
718
					currentAction = Action.MOVING_SELECTION;
560
					startPoint = new Point((int) (e.x / scaleFactor), (int) (e.y / scaleFactor));
719
					startPoint = new Point(scaledX, scaledY);
561
					canvas.redraw();
720
					canvas.redraw();
562
					return;
721
					return;
563
				}
722
				}
Lines 566-572 Link Here
566
				canvas.setCursor(cursors.get(SWT.CURSOR_CROSS));
725
				canvas.setCursor(cursors.get(SWT.CURSOR_CROSS));
567
				currentAction = Action.SELECTING;
726
				currentAction = Action.SELECTING;
568
				currentSelection = null;
727
				currentSelection = null;
569
				startPoint = new Point((int) (e.x / scaleFactor), (int) (e.y / scaleFactor));
728
				startPoint = new Point(scaledX, scaledY);
570
				canvas.redraw();
729
				canvas.redraw();
571
			}
730
			}
572
731
Lines 582-589 Link Here
582
	/**
741
	/**
583
	 * Recalculates image canvas size based on "fit on canvas" setting, set up the grab points, and redraws
742
	 * Recalculates image canvas size based on "fit on canvas" setting, set up the grab points, and redraws
584
	 * <p>
743
	 * <p>
585
	 * This method should be called whenever the {@link #screenshotImage image} <strong>visible</strong> size is
744
	 * This method should be called whenever the {@link #workImage image} <strong>visible</strong> size is changed,
586
	 * changed, which can happen when:
745
	 * which can happen when:
587
	 * <p>
746
	 * <p>
588
	 * <ul>
747
	 * <ul>
589
	 * <li>The "Fit Image" setting is changed, so the image zoom level changes
748
	 * <li>The "Fit Image" setting is changed, so the image zoom level changes
Lines 602-609 Link Here
602
			scrolledComposite.getVerticalBar().setVisible(false);
761
			scrolledComposite.getVerticalBar().setVisible(false);
603
762
604
			Rectangle bounds = scrolledComposite.getClientArea();
763
			Rectangle bounds = scrolledComposite.getClientArea();
605
			if (screenshotImage != null) {
764
			if (workImage != null) {
606
				Rectangle imageBounds = screenshotImage.getBounds();
765
				Rectangle imageBounds = workImage.getBounds();
607
				if (imageBounds.width > bounds.width || imageBounds.height > bounds.height) {
766
				if (imageBounds.width > bounds.width || imageBounds.height > bounds.height) {
608
					double xRatio = (double) bounds.width / imageBounds.width;
767
					double xRatio = (double) bounds.width / imageBounds.width;
609
					double yRatio = (double) bounds.height / imageBounds.height;
768
					double yRatio = (double) bounds.height / imageBounds.height;
Lines 616-623 Link Here
616
		} else {
775
		} else {
617
			scaleFactor = 1.0;
776
			scaleFactor = 1.0;
618
			Rectangle bounds = scrolledComposite.getClientArea();
777
			Rectangle bounds = scrolledComposite.getClientArea();
619
			if (screenshotImage != null) {
778
			if (workImage != null) {
620
				Rectangle imageBounds = screenshotImage.getBounds();
779
				Rectangle imageBounds = workImage.getBounds();
621
				bounds.width = imageBounds.width;
780
				bounds.width = imageBounds.width;
622
				bounds.height = imageBounds.height;
781
				bounds.height = imageBounds.height;
623
			}
782
			}
Lines 678-683 Link Here
678
		}
837
		}
679
	}
838
	}
680
839
840
	/**
841
	 * Connects the previous mark point to the new reference point, by drawing a new line
842
	 */
843
	private void drawMarkLine(int x, int y) {
844
		if (startPoint != null) {
845
			workImageGC.drawLine(startPoint.x, startPoint.y, x, y);
846
			startPoint.x = x;
847
			startPoint.y = y;
848
			canvas.redraw();
849
		}
850
	}
851
681
	private static enum SelectionSide {
852
	private static enum SelectionSide {
682
853
683
		LEFT, RIGHT, TOP, BOTTOM;
854
		LEFT, RIGHT, TOP, BOTTOM;
Lines 706-727 Link Here
706
877
707
	private List<GrabPoint> grabPoints = new ArrayList<GrabPoint>(8);
878
	private List<GrabPoint> grabPoints = new ArrayList<GrabPoint>(8);
708
879
709
	private Image getCropScreenshot() {
880
	/**
710
		if (currentSelection == null) {
881
	 * Creates the final screenshot
711
			return screenshotImage;
882
	 * 
883
	 * @return The final screenshot, with all markings, and cropped according to user settings; <strong>The caller is
884
	 *         responsible for disposing the returned image</strong>
885
	 */
886
	public Image createScreenshotImage() {
887
		Image screenshot = new Image(Display.getDefault(), currentSelection != null ? currentSelection
888
				: workImage.getBounds());
889
890
		GC gc = new GC(screenshot);
891
		if (currentSelection != null) {
892
			gc.drawImage(workImage, currentSelection.x, currentSelection.y, currentSelection.width,
893
					currentSelection.height, 0, 0, currentSelection.width, currentSelection.height);
894
		} else {
895
			gc.drawImage(workImage, 0, 0);
712
		}
896
		}
713
714
		Image image = new Image(Display.getDefault(), currentSelection);
715
		GC gc = new GC(image);
716
		gc.drawImage(screenshotImage, currentSelection.x, currentSelection.y, currentSelection.width,
717
				currentSelection.height, 0, 0, currentSelection.width, currentSelection.height);
718
		gc.dispose();
897
		gc.dispose();
719
898
720
		return image;
899
		return screenshot;
721
	}
722
723
	public Image getScreenshotImage() {
724
		return getCropScreenshot();
725
	}
900
	}
726
901
727
}
902
}
(-)src/org/eclipse/mylyn/internal/tasks/ui/wizards/NewAttachmentWizard.java (-7 / +8 lines)
Lines 78-84 Link Here
78
	private AbstractTask task;
78
	private AbstractTask task;
79
79
80
	private boolean screenshotMode;
80
	private boolean screenshotMode;
81
	
81
82
	public NewAttachmentWizard(TaskRepository repository, AbstractTask task, boolean screenshotMode) {
82
	public NewAttachmentWizard(TaskRepository repository, AbstractTask task, boolean screenshotMode) {
83
		super();
83
		super();
84
		this.task = task;
84
		this.task = task;
Lines 92-98 Link Here
92
			setWindowTitle("Add Attachment");
92
			setWindowTitle("Add Attachment");
93
			setDefaultPageImageDescriptor(TasksUiImages.BANNER_REPOSITORY);
93
			setDefaultPageImageDescriptor(TasksUiImages.BANNER_REPOSITORY);
94
		}
94
		}
95
		
95
96
		inputPage = new InputAttachmentSourcePage(this);
96
		inputPage = new InputAttachmentSourcePage(this);
97
		attachment = new LocalAttachment();
97
		attachment = new LocalAttachment();
98
		attachment.setFilePath("");
98
		attachment.setFilePath("");
Lines 110-116 Link Here
110
	public NewAttachmentWizard(TaskRepository repository, AbstractTask task) {
110
	public NewAttachmentWizard(TaskRepository repository, AbstractTask task) {
111
		this(repository, task, false);
111
		this(repository, task, false);
112
	}
112
	}
113
	
113
114
	public NewAttachmentWizard(TaskRepository repository, AbstractTask task, File attachFile) {
114
	public NewAttachmentWizard(TaskRepository repository, AbstractTask task, File attachFile) {
115
		this(repository, task, false);
115
		this(repository, task, false);
116
		attachment.setFilePath(attachFile.getAbsolutePath());
116
		attachment.setFilePath(attachFile.getAbsolutePath());
Lines 158-176 Link Here
158
					task.setSynchronizationState(RepositoryTaskSyncState.OUTGOING);
158
					task.setSynchronizationState(RepositoryTaskSyncState.OUTGOING);
159
159
160
					if (screenshotMode || InputAttachmentSourcePage.SCREENSHOT_LABEL.equals(path)) {
160
					if (screenshotMode || InputAttachmentSourcePage.SCREENSHOT_LABEL.equals(path)) {
161
						Image image = shotPage.getScreenshotImage();
161
						Image screenshot = shotPage.createScreenshotImage();
162
						if (image == null) {
162
						if (screenshot == null) {
163
							throw new InvocationTargetException(new CoreException(new RepositoryStatus(IStatus.ERROR,
163
							throw new InvocationTargetException(new CoreException(new RepositoryStatus(IStatus.ERROR,
164
									TasksUiPlugin.ID_PLUGIN, RepositoryStatus.ERROR_INTERNAL, "Screenshot is empty",
164
									TasksUiPlugin.ID_PLUGIN, RepositoryStatus.ERROR_INTERNAL, "Screenshot is empty",
165
									null)));
165
									null)));
166
						}
166
						}
167
						String path = TasksUiPlugin.getDefault().getDefaultDataDirectory();
167
						String path = TasksUiPlugin.getDefault().getDefaultDataDirectory();
168
						ImageLoader loader = new ImageLoader();
168
						ImageLoader loader = new ImageLoader();
169
						loader.data = new ImageData[] { image.getImageData() };
169
						loader.data = new ImageData[] { screenshot.getImageData() };
170
						String fileName = path + "/" + SCREENSHOT_FILENAME;
170
						String fileName = path + "/" + SCREENSHOT_FILENAME;
171
						loader.save(fileName, SWT.IMAGE_JPEG);
171
						loader.save(fileName, SWT.IMAGE_JPEG);
172
						attachment.setFile(new File(fileName));
172
						attachment.setFile(new File(fileName));
173
						attachment.setFilename(SCREENSHOT_FILENAME);
173
						attachment.setFilename(SCREENSHOT_FILENAME);
174
						screenshot.dispose();
174
					} else if (InputAttachmentSourcePage.CLIPBOARD_LABEL.equals(path)) {
175
					} else if (InputAttachmentSourcePage.CLIPBOARD_LABEL.equals(path)) {
175
						String contents = inputPage.getClipboardContents();
176
						String contents = inputPage.getClipboardContents();
176
						if (contents == null) {
177
						if (contents == null) {
Lines 293-299 Link Here
293
	@Override
294
	@Override
294
	public boolean canFinish() {
295
	public boolean canFinish() {
295
		if (screenshotMode) {
296
		if (screenshotMode) {
296
			return shotPage.isPageComplete();
297
			return shotPage.isPageComplete() && attachPage.isPageComplete();
297
		} else {
298
		} else {
298
			return attachPage.isPageComplete();
299
			return attachPage.isPageComplete();
299
		}
300
		}

Return to bug 195691