]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-before/ui/org/eclipse/jdt/internal/ui/text/java/hover/SourceViewerInformationControl.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-before / ui / org / eclipse / jdt / internal / ui / text / java / hover / SourceViewerInformationControl.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2012 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.ui.text.java.hover;
12
13 import org.eclipse.swt.SWT;
14 import org.eclipse.swt.custom.StyledText;
15 import org.eclipse.swt.events.DisposeEvent;
16 import org.eclipse.swt.events.DisposeListener;
17 import org.eclipse.swt.events.FocusListener;
18 import org.eclipse.swt.events.KeyEvent;
19 import org.eclipse.swt.events.KeyListener;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.Font;
22 import org.eclipse.swt.graphics.FontData;
23 import org.eclipse.swt.graphics.GC;
24 import org.eclipse.swt.graphics.Point;
25 import org.eclipse.swt.graphics.RGB;
26 import org.eclipse.swt.graphics.Rectangle;
27 import org.eclipse.swt.layout.GridData;
28 import org.eclipse.swt.layout.GridLayout;
29 import org.eclipse.swt.widgets.Composite;
30 import org.eclipse.swt.widgets.Control;
31 import org.eclipse.swt.widgets.Display;
32 import org.eclipse.swt.widgets.Label;
33 import org.eclipse.swt.widgets.Shell;
34
35 import org.eclipse.core.runtime.Assert;
36
37 import org.eclipse.jface.preference.IPreferenceStore;
38 import org.eclipse.jface.preference.PreferenceConverter;
39 import org.eclipse.jface.resource.JFaceResources;
40
41 import org.eclipse.jface.text.Document;
42 import org.eclipse.jface.text.IDocument;
43 import org.eclipse.jface.text.IInformationControl;
44 import org.eclipse.jface.text.IInformationControlCreator;
45 import org.eclipse.jface.text.IInformationControlExtension;
46 import org.eclipse.jface.text.IInformationControlExtension3;
47 import org.eclipse.jface.text.IInformationControlExtension5;
48 import org.eclipse.jface.text.source.ISourceViewer;
49 import org.eclipse.jface.text.source.SourceViewer;
50
51 import org.eclipse.ui.texteditor.AbstractTextEditor;
52
53 import org.eclipse.jdt.ui.JavaUI;
54 import org.eclipse.jdt.ui.PreferenceConstants;
55 import org.eclipse.jdt.ui.text.IJavaColorConstants;
56 import org.eclipse.jdt.ui.text.IJavaPartitions;
57
58 import org.eclipse.jdt.internal.ui.JavaPlugin;
59 import org.eclipse.jdt.internal.ui.javaeditor.JavaSourceViewer;
60 import org.eclipse.jdt.internal.ui.text.SimpleJavaSourceViewerConfiguration;
61
62 /**
63  * Source viewer based implementation of <code>IInformationControl</code>.
64  * Displays information in a source viewer.
65  *
66  * @since 3.0
67  */
68 public class SourceViewerInformationControl implements IInformationControl, IInformationControlExtension, IInformationControlExtension3, IInformationControlExtension5, DisposeListener {
69
70         /** The control's shell */
71         private Shell fShell;
72         /** The control's text widget */
73         private StyledText fText;
74         /** The text font (do not dispose!) */
75         private Font fTextFont;
76         /** The control's source viewer */
77         private SourceViewer fViewer;
78         /**
79          * The optional status field.
80          *
81          * @since 3.0
82          */
83         private Label fStatusField;
84         /**
85          * The separator for the optional status field.
86          *
87          * @since 3.0
88          */
89         private Label fSeparator;
90         /**
91          * The font of the optional status text label.
92          *
93          * @since 3.0
94          */
95         private Font fStatusTextFont;
96         /**
97          * The color of the optional status text label or <code>null</code> if none.
98          * 
99          * @since 3.6
100          */
101         private Color fStatusTextForegroundColor;
102         /**
103          * The width size constraint.
104          * @since 3.2
105          */
106         private int fMaxWidth= SWT.DEFAULT;
107         /**
108          * The height size constraint.
109          * @since 3.2
110          */
111         private int fMaxHeight= SWT.DEFAULT;
112         /**
113          * The orientation of the shell
114          * @since 3.4
115          */
116         private final int fOrientation;
117
118         private Color fBackgroundColor;
119         private boolean fIsSystemBackgroundColor= true;
120
121
122         /**
123          * Creates a source viewer information control with the given shell as parent. The given
124          * styles are applied to the created styled text widget. The status field will
125          * contain the given text or be hidden.
126          *
127          * @param parent the parent shell
128          * @param isResizable <code>true</code> if resizable
129          * @param orientation the orientation
130          * @param statusFieldText the text to be used in the optional status field
131          *            or <code>null</code> if the status field should be hidden
132          */
133         public SourceViewerInformationControl(Shell parent, boolean isResizable, int orientation, String statusFieldText) {
134                 Assert.isLegal(orientation == SWT.RIGHT_TO_LEFT || orientation == SWT.LEFT_TO_RIGHT || orientation == SWT.NONE);
135                 fOrientation= orientation;
136
137                 GridLayout layout;
138                 GridData gd;
139
140                 int shellStyle= SWT.TOOL | SWT.ON_TOP | orientation | (isResizable ? SWT.RESIZE : 0);
141                 int textStyle= isResizable ? SWT.V_SCROLL | SWT.H_SCROLL : SWT.NONE;
142
143                 fShell= new Shell(parent, SWT.NO_FOCUS | SWT.ON_TOP | shellStyle);
144                 Display display= fShell.getDisplay();
145
146                 initializeColors();
147
148                 Composite composite= fShell;
149                 layout= new GridLayout(1, false);
150                 layout.marginHeight= 0;
151                 layout.marginWidth= 0;
152                 composite.setLayout(layout);
153                 gd= new GridData(GridData.FILL_HORIZONTAL);
154                 composite.setLayoutData(gd);
155
156                 if (statusFieldText != null) {
157                         composite= new Composite(composite, SWT.NONE);
158                         layout= new GridLayout(1, false);
159                         layout.marginHeight= 0;
160                         layout.marginWidth= 0;
161                         layout.verticalSpacing= 1;
162                         composite.setLayout(layout);
163                         gd= new GridData(GridData.FILL_BOTH);
164                         composite.setLayoutData(gd);
165                         composite.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
166                         composite.setBackground(fBackgroundColor);
167                 }
168
169                 // Source viewer
170                 IPreferenceStore store= JavaPlugin.getDefault().getCombinedPreferenceStore();
171                 fViewer= new JavaSourceViewer(composite, null, null, false, textStyle, store);
172                 fViewer.configure(new SimpleJavaSourceViewerConfiguration(JavaPlugin.getDefault().getJavaTextTools().getColorManager(), store, null, IJavaPartitions.JAVA_PARTITIONING, false));
173                 fViewer.setEditable(false);
174
175                 fText= fViewer.getTextWidget();
176                 gd= new GridData(GridData.BEGINNING | GridData.FILL_BOTH);
177                 fText.setLayoutData(gd);
178                 fText.setForeground(display.getSystemColor(SWT.COLOR_INFO_FOREGROUND));
179                 fText.setBackground(fBackgroundColor);
180
181                 initializeFont();
182
183                 fText.addKeyListener(new KeyListener() {
184
185                         public void keyPressed(KeyEvent e)  {
186                                 if (e.character == 0x1B) // ESC
187                                         fShell.dispose();
188                         }
189
190                         public void keyReleased(KeyEvent e) {}
191                 });
192
193                 // Status field
194                 if (statusFieldText != null) {
195
196                         // Horizontal separator line
197                         fSeparator= new Label(composite, SWT.SEPARATOR | SWT.HORIZONTAL | SWT.LINE_DOT);
198                         fSeparator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
199
200                         // Status field label
201                         fStatusField= new Label(composite, SWT.RIGHT);
202                         fStatusField.setText(statusFieldText);
203                         Font font= fStatusField.getFont();
204                         FontData[] fontDatas= font.getFontData();
205                         for (int i= 0; i < fontDatas.length; i++)
206                                 fontDatas[i].setHeight(fontDatas[i].getHeight() * 9 / 10);
207                         fStatusTextFont= new Font(fStatusField.getDisplay(), fontDatas);
208                         fStatusField.setFont(fStatusTextFont);
209                         GridData gd2= new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_BEGINNING);
210                         fStatusField.setLayoutData(gd2);
211                         
212                         RGB javaDefaultColor= JavaUI.getColorManager().getColor(IJavaColorConstants.JAVA_DEFAULT).getRGB();
213                         fStatusTextForegroundColor= new Color(fStatusField.getDisplay(), blend(fBackgroundColor.getRGB(), javaDefaultColor, 0.56f));
214                         fStatusField.setForeground(fStatusTextForegroundColor);
215                         fStatusField.setBackground(fBackgroundColor);
216                 }
217
218                 addDisposeListener(this);
219         }
220
221         /**
222          * Returns an RGB that lies between the given foreground and background
223          * colors using the given mixing factor. A <code>factor</code> of 1.0 will produce a
224          * color equal to <code>fg</code>, while a <code>factor</code> of 0.0 will produce one
225          * equal to <code>bg</code>.
226          * @param bg the background color
227          * @param fg the foreground color
228          * @param factor the mixing factor, must be in [0,&nbsp;1]
229          *
230          * @return the interpolated color
231          * @since 3.6
232          */
233         private static RGB blend(RGB bg, RGB fg, float factor) {
234                 // copy of org.eclipse.jface.internal.text.revisions.Colors#blend(..)
235                 Assert.isLegal(bg != null);
236                 Assert.isLegal(fg != null);
237                 Assert.isLegal(factor >= 0f && factor <= 1f);
238                 
239                 float complement= 1f - factor;
240                 return new RGB(
241                                 (int) (complement * bg.red + factor * fg.red),
242                                 (int) (complement * bg.green + factor * fg.green),
243                                 (int) (complement * bg.blue + factor * fg.blue)
244                 );
245         }
246         
247         private void initializeColors() {
248                 IPreferenceStore store= JavaPlugin.getDefault().getPreferenceStore();
249                 RGB bgRGB;
250                 if (store.getBoolean(PreferenceConstants.EDITOR_SOURCE_HOVER_BACKGROUND_COLOR_SYSTEM_DEFAULT)) {
251                         bgRGB= getVisibleBackgroundColor(fShell.getDisplay());
252                 } else {
253                         bgRGB= PreferenceConverter.getColor(store, PreferenceConstants.EDITOR_SOURCE_HOVER_BACKGROUND_COLOR);
254                 }
255                 if (bgRGB != null) {
256                         fBackgroundColor= new Color(fShell.getDisplay(), bgRGB);
257                         fIsSystemBackgroundColor= false;
258                 } else {
259                         fBackgroundColor= fShell.getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND);
260                         fIsSystemBackgroundColor= true;
261                 }
262         }
263
264         /**
265          * Returns <code>null</code> if {@link SWT#COLOR_INFO_BACKGROUND} is visibly distinct from the
266          * default Java source text color. Otherwise, returns the editor background color.
267          * 
268          * @param display the display
269          * @return an RGB or <code>null</code>
270          * @since 3.6.1
271          */
272         public static RGB getVisibleBackgroundColor(Display display) {
273                 float[] infoBgHSB= display.getSystemColor(SWT.COLOR_INFO_BACKGROUND).getRGB().getHSB();
274                 
275                 Color javaDefaultColor= JavaUI.getColorManager().getColor(IJavaColorConstants.JAVA_DEFAULT);
276                 RGB javaDefaultRGB= javaDefaultColor != null ? javaDefaultColor.getRGB() : new RGB(255, 255, 255);
277                 float[] javaDefaultHSB= javaDefaultRGB.getHSB();
278                 
279                 if (Math.abs(infoBgHSB[2] - javaDefaultHSB[2]) < 0.5f) {
280                         // workaround for dark tooltip background color, see https://bugs.eclipse.org/309334
281                         IPreferenceStore preferenceStore= JavaPlugin.getDefault().getCombinedPreferenceStore();
282                         boolean useDefault= preferenceStore.getBoolean(AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND_SYSTEM_DEFAULT);
283                         if (useDefault)
284                                 return display.getSystemColor(SWT.COLOR_LIST_BACKGROUND).getRGB();
285                         return PreferenceConverter.getColor(preferenceStore, AbstractTextEditor.PREFERENCE_COLOR_BACKGROUND);
286                 }
287                 return null;
288         }
289
290         /**
291          * Initialize the font to the Java editor font.
292          *
293          * @since 3.2
294          */
295         private void initializeFont() {
296                 fTextFont= JFaceResources.getFont(PreferenceConstants.EDITOR_TEXT_FONT);
297                 StyledText styledText= getViewer().getTextWidget();
298                 styledText.setFont(fTextFont);
299         }
300
301         /*
302          * @see org.eclipse.jface.text.IInformationControlExtension2#setInput(java.lang.Object)
303          */
304         public void setInput(Object input) {
305                 if (input instanceof String)
306                         setInformation((String)input);
307                 else
308                         setInformation(null);
309         }
310
311         /*
312          * @see IInformationControl#setInformation(String)
313          */
314         public void setInformation(String content) {
315                 if (content == null) {
316                         fViewer.setInput(null);
317                         return;
318                 }
319
320                 IDocument doc= new Document(content);
321                 JavaPlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(doc, IJavaPartitions.JAVA_PARTITIONING);
322                 fViewer.setInput(doc);
323         }
324
325         /*
326          * @see IInformationControl#setVisible(boolean)
327          */
328         public void setVisible(boolean visible) {
329                         fShell.setVisible(visible);
330         }
331
332         /**
333          * {@inheritDoc}
334          * @since 3.0
335          */
336         public void widgetDisposed(DisposeEvent event) {
337                 if (fStatusTextFont != null && !fStatusTextFont.isDisposed())
338                         fStatusTextFont.dispose();
339                 fStatusTextFont= null;
340
341                 if (fStatusTextForegroundColor != null && !fStatusTextForegroundColor.isDisposed())
342                         fStatusTextForegroundColor.dispose();
343                 fStatusTextForegroundColor= null;
344
345                 fTextFont= null;
346                 fShell= null;
347                 fText= null;
348         }
349
350         /**
351          * {@inheritDoc}
352          */
353         public final void dispose() {
354                 if (!fIsSystemBackgroundColor)
355                         fBackgroundColor.dispose();
356                 if (fShell != null && !fShell.isDisposed())
357                         fShell.dispose();
358                 else
359                         widgetDisposed(null);
360         }
361
362         /*
363          * @see IInformationControl#setSize(int, int)
364          */
365         public void setSize(int width, int height) {
366                 fShell.setSize(width, height);
367         }
368
369         /*
370          * @see IInformationControl#setLocation(Point)
371          */
372         public void setLocation(Point location) {
373                 fShell.setLocation(location);
374         }
375
376         /*
377          * @see IInformationControl#setSizeConstraints(int, int)
378          */
379         public void setSizeConstraints(int maxWidth, int maxHeight) {
380                 fMaxWidth= maxWidth;
381                 fMaxHeight= maxHeight;
382         }
383
384         /*
385          * @see IInformationControl#computeSizeHint()
386          */
387         public Point computeSizeHint() {
388                 // compute the preferred size
389                 int x= SWT.DEFAULT;
390                 int y= SWT.DEFAULT;
391                 Point size= fShell.computeSize(x, y);
392                 if (size.x > fMaxWidth)
393                         x= fMaxWidth;
394                 if (size.y > fMaxHeight)
395                         y= fMaxHeight;
396
397                 // recompute using the constraints if the preferred size is larger than the constraints
398                 if (x != SWT.DEFAULT || y != SWT.DEFAULT)
399                         size= fShell.computeSize(x, y, false);
400
401                 return size;
402         }
403
404         /*
405          * @see IInformationControl#addDisposeListener(DisposeListener)
406          */
407         public void addDisposeListener(DisposeListener listener) {
408                 fShell.addDisposeListener(listener);
409         }
410
411         /*
412          * @see IInformationControl#removeDisposeListener(DisposeListener)
413          */
414         public void removeDisposeListener(DisposeListener listener) {
415                 fShell.removeDisposeListener(listener);
416         }
417
418         /*
419          * @see IInformationControl#setForegroundColor(Color)
420          */
421         public void setForegroundColor(Color foreground) {
422                 fText.setForeground(foreground);
423         }
424
425         /*
426          * @see IInformationControl#setBackgroundColor(Color)
427          */
428         public void setBackgroundColor(Color background) {
429                 fText.setBackground(background);
430         }
431
432         /*
433          * @see IInformationControl#isFocusControl()
434          */
435         public boolean isFocusControl() {
436                 return fShell.getDisplay().getActiveShell() == fShell;
437         }
438
439         /*
440          * @see IInformationControl#setFocus()
441          */
442         public void setFocus() {
443                 fShell.forceFocus();
444                 fText.setFocus();
445         }
446
447         /*
448          * @see IInformationControl#addFocusListener(FocusListener)
449          */
450         public void addFocusListener(FocusListener listener) {
451                 fText.addFocusListener(listener);
452         }
453
454         /*
455          * @see IInformationControl#removeFocusListener(FocusListener)
456          */
457         public void removeFocusListener(FocusListener listener) {
458                 fText.removeFocusListener(listener);
459         }
460
461         /*
462          * @see IInformationControlExtension#hasContents()
463          */
464         public boolean hasContents() {
465                 return fText.getCharCount() > 0;
466         }
467
468         protected ISourceViewer getViewer()  {
469                 return fViewer;
470         }
471
472         /*
473          * @see org.eclipse.jface.text.IInformationControlExtension3#computeTrim()
474          * @since 3.4
475          */
476         public Rectangle computeTrim() {
477                 Rectangle trim= fShell.computeTrim(0, 0, 0, 0);
478                 addInternalTrim(trim);
479                 return trim;
480         }
481
482         /**
483          * Adds the internal trimmings to the given trim of the shell.
484          *
485          * @param trim the shell's trim, will be updated
486          * @since 3.4
487          */
488         private void addInternalTrim(Rectangle trim) {
489                 Rectangle textTrim= fText.computeTrim(0, 0, 0, 0);
490                 trim.x+= textTrim.x;
491                 trim.y+= textTrim.y;
492                 trim.width+= textTrim.width;
493                 trim.height+= textTrim.height;
494
495                 if (fStatusField != null) {
496                         trim.height+= fSeparator.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
497                         trim.height+= fStatusField.computeSize(SWT.DEFAULT, SWT.DEFAULT).y;
498                         trim.height+= 1; // verticalSpacing
499                 }
500         }
501
502         /*
503          * @see org.eclipse.jface.text.IInformationControlExtension3#getBounds()
504          * @since 3.4
505          */
506         public Rectangle getBounds() {
507                 return fShell.getBounds();
508         }
509
510         /*
511          * @see org.eclipse.jface.text.IInformationControlExtension3#restoresLocation()
512          * @since 3.4
513          */
514         public boolean restoresLocation() {
515                 return false;
516         }
517
518         /*
519          * @see org.eclipse.jface.text.IInformationControlExtension3#restoresSize()
520          * @since 3.4
521          */
522         public boolean restoresSize() {
523                 return false;
524         }
525
526         /*
527          * @see org.eclipse.jface.text.IInformationControlExtension5#getInformationPresenterControlCreator()
528          * @since 3.4
529          */
530         public IInformationControlCreator getInformationPresenterControlCreator() {
531                 return new IInformationControlCreator() {
532                         public IInformationControl createInformationControl(Shell parent) {
533                                 return new SourceViewerInformationControl(parent, true, fOrientation, null);
534                         }
535                 };
536         }
537
538         /*
539          * @see org.eclipse.jface.text.IInformationControlExtension5#containsControl(org.eclipse.swt.widgets.Control)
540          * @since 3.4
541          */
542         public boolean containsControl(Control control) {
543                 do {
544                         if (control == fShell)
545                                 return true;
546                         if (control instanceof Shell)
547                                 return false;
548                         control= control.getParent();
549                 } while (control != null);
550                 return false;
551         }
552
553         /*
554          * @see org.eclipse.jface.text.IInformationControlExtension5#isVisible()
555          * @since 3.4
556          */
557         public boolean isVisible() {
558                 return fShell != null && !fShell.isDisposed() && fShell.isVisible();
559         }
560
561         /*
562          * @see org.eclipse.jface.text.IInformationControlExtension5#computeSizeConstraints(int, int)
563          */
564         public Point computeSizeConstraints(int widthInChars, int heightInChars) {
565                 GC gc= new GC(fText);
566                 gc.setFont(fTextFont);
567                 int width= gc.getFontMetrics().getAverageCharWidth();
568                 int height= fText.getLineHeight(); //https://bugs.eclipse.org/bugs/show_bug.cgi?id=377109
569                 gc.dispose();
570
571                 return new Point(widthInChars * width, heightInChars * height);
572         }
573 }