Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 246875 | Differences between
and this patch

Collapse All | Expand All

(-)plugin.xml (-1 / +24 lines)
Lines 701-707 Link Here
701
            description="%command.installationDialog.description"
701
            description="%command.installationDialog.description"
702
            helpContextId="org.eclipse.ui.about_action_context"
702
            helpContextId="org.eclipse.ui.about_action_context"
703
            id="org.eclipse.ui.help.installationDialog"
703
            id="org.eclipse.ui.help.installationDialog"
704
            name="%command.installationDialog.name"/>            
704
            name="%command.aboutAction.name"/>            
705
      <command
705
      <command
706
            categoryId="org.eclipse.ui.category.file"
706
            categoryId="org.eclipse.ui.category.file"
707
            defaultHandler="org.eclipse.ui.internal.handlers.WizardHandler$New"
707
            defaultHandler="org.eclipse.ui.internal.handlers.WizardHandler$New"
Lines 2221-2224 Link Here
2221
            type="java.lang.Object">
2221
            type="java.lang.Object">
2222
      </propertyTester>
2222
      </propertyTester>
2223
   </extension>
2223
   </extension>
2224
   <extension
2225
         point="org.eclipse.ui.installationPages">
2226
          <page
2227
            name="%installationPage.plugins.name"
2228
            class="org.eclipse.ui.internal.about.AboutPluginsPage"
2229
            id="15.PluginPage">
2230
          </page>        
2231
          <page
2232
            name="%installationPage.system.name"
2233
            class="org.eclipse.ui.internal.about.AboutSystemPage"
2234
            id="16.SystemPage">
2235
          </page>
2236
     </extension>
2237
     <extension
2238
         point="org.eclipse.ui.menus">
2239
      <menuContribution
2240
            locationURI="toolbar:org.eclipse.ui.installationDialog.buttonbar/16.SystemPage">
2241
         <command
2242
               commandId="org.eclipse.ui.edit.copy"
2243
               style="push">
2244
         </command>
2245
      </menuContribution>    
2246
   </extension>
2224
</plugin>
2247
</plugin>
(-)plugin.properties (-1 / +5 lines)
Lines 330-333 Link Here
330
command.quickMenu.name = Open Quick Menu
330
command.quickMenu.name = Open Quick Menu
331
command.quickMenu.uri.name = Location URI
331
command.quickMenu.uri.name = Location URI
332
command.showIn.name = Show In
332
command.showIn.name = Show In
333
command.showIn.targetId.name = Show In Target Id
333
command.showIn.targetId.name = Show In Target Id
334
335
installationPage.main.name = About
336
installationPage.system.name = Configuration
337
installationPage.plugins.name = Plug-ins
(-)schema/installationPages.exsd (-23 / +55 lines)
Lines 2-20 Link Here
2
<!-- Schema file written by PDE -->
2
<!-- Schema file written by PDE -->
3
<schema targetNamespace="org.eclipse.ui" xmlns="http://www.w3.org/2001/XMLSchema">
3
<schema targetNamespace="org.eclipse.ui" xmlns="http://www.w3.org/2001/XMLSchema">
4
<annotation>
4
<annotation>
5
      <appinfo>
5
      <appInfo>
6
         <meta.schema plugin="org.eclipse.ui" id="installationPages" name="Installation Dialog Pages"/>
6
         <meta.schema plugin="org.eclipse.ui" id="installationPages" name="Installation Dialog Pages"/>
7
      </appinfo>
7
      </appInfo>
8
      <documentation>
8
      <documentation>
9
         This is an experimental extension point for an extensible about dialog.  It is not ready for production and is included at this time only for evaluation by downstream clients.  Use at your own risk.
9
         &lt;p&gt;The Eclipse UI provides an AboutDialog that can be branded and reused by client product plugins.  This dialog typically shows the product splash image and other descriptive information about the product. The about dialog includes a button that allows the user to launch a secondary dialog, the &lt;b&gt;Installation Details&lt;/b&gt; dialog.&lt;/p&gt;
10
&lt;p&gt;The purpose of this extension point is to allow plug-ins to add
11
pages to the installation details dialog.  When the installation details dialog is opened, the pages contributed in this way will be added to the dialog box.  These pages are used to supply additional detail about the product configuration.&lt;/p&gt;
12
13
&lt;p&gt;This is an experimental extension point for an extensible about dialog.  It is not ready for production and is included at this time only for evaluation by downstream clients.  Use at your own risk.&lt;/p&gt;
10
      </documentation>
14
      </documentation>
11
   </annotation>
15
   </annotation>
12
16
13
   <element name="extension">
17
   <element name="extension">
14
      <annotation>
18
      <annotation>
15
         <appinfo>
19
         <appInfo>
16
            <meta.element />
20
            <meta.element />
17
         </appinfo>
21
         </appInfo>
18
      </annotation>
22
      </annotation>
19
      <complexType>
23
      <complexType>
20
         <sequence>
24
         <sequence>
Lines 39-47 Link Here
39
               <documentation>
43
               <documentation>
40
                  
44
                  
41
               </documentation>
45
               </documentation>
42
               <appinfo>
46
               <appInfo>
43
                  <meta.attribute translatable="true"/>
47
                  <meta.attribute translatable="true"/>
44
               </appinfo>
48
               </appInfo>
45
            </annotation>
49
            </annotation>
46
         </attribute>
50
         </attribute>
47
      </complexType>
51
      </complexType>
Lines 61-69 Link Here
61
               <documentation>
65
               <documentation>
62
                  
66
                  
63
               </documentation>
67
               </documentation>
64
               <appinfo>
68
               <appInfo>
65
                  <meta.attribute kind="java" basedOn="org.eclipse.ui.branding.InstallationPage:"/>
69
                  <meta.attribute kind="java" basedOn="org.eclipse.ui.branding.InstallationPage:"/>
66
               </appinfo>
70
               </appInfo>
67
            </annotation>
71
            </annotation>
68
         </attribute>
72
         </attribute>
69
         <attribute name="name" type="string" use="required">
73
         <attribute name="name" type="string" use="required">
Lines 71-119 Link Here
71
               <documentation>
75
               <documentation>
72
                  
76
                  
73
               </documentation>
77
               </documentation>
74
               <appinfo>
78
               <appInfo>
75
                  <meta.attribute translatable="true"/>
79
                  <meta.attribute translatable="true"/>
76
               </appinfo>
80
               </appInfo>
77
            </annotation>
81
            </annotation>
78
         </attribute>
82
         </attribute>
79
      </complexType>
83
      </complexType>
80
   </element>
84
   </element>
81
85
82
   <annotation>
86
   <annotation>
83
      <appinfo>
87
      <appInfo>
84
         <meta.section type="since"/>
88
         <meta.section type="since"/>
85
      </appinfo>
89
      </appInfo>
86
      <documentation>
90
      <documentation>
87
         [Enter the first release in which this extension point appears.]
91
         3.5
88
      </documentation>
92
      </documentation>
89
   </annotation>
93
   </annotation>
90
94
91
   <annotation>
95
   <annotation>
92
      <appinfo>
96
      <appInfo>
93
         <meta.section type="examples"/>
97
         <meta.section type="examples"/>
94
      </appinfo>
98
      </appInfo>
95
      <documentation>
99
      <documentation>
96
         [Enter extension point usage example here.]
100
         The following is an example installation page: 
101
&lt;p&gt;
102
&lt;pre&gt;
103
   &lt;extension point=&quot;org.eclipse.ui.installationPages&quot;&gt; 
104
       &lt;page
105
            name=&quot;XYZ Info&quot;
106
            class=&quot;org.eclipse.ui.internal.XYZInstallInfoPage&quot;
107
            id=&quot;org.eclipse.ui.internal.xyz&gt;
108
       &lt;/page&gt;
109
    &lt;/extension&gt;
110
&lt;/pre&gt;
111
&lt;/p&gt;
97
      </documentation>
112
      </documentation>
98
   </annotation>
113
   </annotation>
99
114
100
   <annotation>
115
   <annotation>
101
      <appinfo>
116
      <appInfo>
102
         <meta.section type="apiinfo"/>
117
         <meta.section type="apiinfo"/>
103
      </appinfo>
118
      </appInfo>
104
      <documentation>
119
      <documentation>
105
         [Enter API information here.]
120
         The value of the attribute class must represent a fully qualified name of a class that is a concrete subclass of
121
&lt;samp&gt;org.eclipse.ui.about.InstallationPage&lt;/samp&gt;.
106
      </documentation>
122
      </documentation>
107
   </annotation>
123
   </annotation>
108
124
109
   <annotation>
125
   <annotation>
110
      <appinfo>
126
      <appInfo>
111
         <meta.section type="implementation"/>
127
         <meta.section type="implementation"/>
112
      </appinfo>
128
      </appInfo>
113
      <documentation>
129
      <documentation>
114
         [Enter information about supplied implementation of this extension point.]
130
         The Workbench uses this extension point to provide the following pages in the installation details dialog:
131
&lt;ul&gt;
132
&lt;li&gt;Plug-ins: A list of all of the plug-ins in the running the system, including details about each plug-in.&lt;/li&gt;
133
&lt;li&gt;Configuration: The configuration information contributed via the &lt;samp&gt;org.eclipse.ui.systemSummarySections&lt;/samp&gt; extension.&lt;/li&gt;
134
&lt;/ul&gt;
115
      </documentation>
135
      </documentation>
116
   </annotation>
136
   </annotation>
117
137
138
   <annotation>
139
      <appInfo>
140
         <meta.section type="copyright"/>
141
      </appInfo>
142
      <documentation>
143
         Copyright (c) 2008, 2009 IBM Corporation and others.&lt;br&gt;
144
All rights reserved. This program and the accompanying materials are made
145
available under the terms of the Eclipse Public License v1.0 which accompanies
146
this distribution, and is available at &lt;a 
147
href=&quot;http://www.eclipse.org/legal/epl-v10.html&quot;&gt;http://www.eclipse.org/legal/epl-v10.html&lt;/a&gt;
148
      </documentation>
149
   </annotation>
118
150
119
</schema>
151
</schema>
(-)schema/systemSummarySections.exsd (-2 / +7 lines)
Lines 1-16 Link Here
1
<?xml version='1.0' encoding='UTF-8'?>
1
<?xml version='1.0' encoding='UTF-8'?>
2
<!-- Schema file written by PDE -->
2
<!-- Schema file written by PDE -->
3
<schema targetNamespace="org.eclipse.ui">
3
<schema targetNamespace="org.eclipse.ui" xmlns="http://www.w3.org/2001/XMLSchema">
4
<annotation>
4
<annotation>
5
      <appInfo>
5
      <appInfo>
6
         <meta.schema plugin="org.eclipse.ui" id="systemSummarySections" name="System Summary Sections"/>
6
         <meta.schema plugin="org.eclipse.ui" id="systemSummarySections" name="System Summary Sections"/>
7
      </appInfo>
7
      </appInfo>
8
      <documentation>
8
      <documentation>
9
         The Eclipse UI provides an AboutDialog that can be branded and reused by client product plugins.  This dialog includes a SystemSummary dialog that contains configuration details.  By extending the org.eclipse.ui.systemSummarySections extension point clients are able to put their own information into the log.
9
         The Eclipse UI provides an AboutDialog that can be branded and reused by client product plugins.  This dialog includes SystemSummary information that contains configuration details.  By extending the org.eclipse.ui.systemSummarySections extension point clients are able to put their own information into the log.
10
      </documentation>
10
      </documentation>
11
   </annotation>
11
   </annotation>
12
12
13
   <element name="extension">
13
   <element name="extension">
14
      <annotation>
15
         <appInfo>
16
            <meta.element />
17
         </appInfo>
18
      </annotation>
14
      <complexType>
19
      <complexType>
15
         <sequence>
20
         <sequence>
16
            <element ref="section" minOccurs="1" maxOccurs="unbounded"/>
21
            <element ref="section" minOccurs="1" maxOccurs="unbounded"/>
(-)plugin.properties (+2 lines)
Lines 284-286 Link Here
284
menu.mnemonic.0 = I
284
menu.mnemonic.0 = I
285
menu.showIn.label = Show In
285
menu.showIn.label = Show In
286
menu.showIn.mnemonic = I
286
menu.showIn.mnemonic = I
287
288
installationPage.feature.name = Features
(-)plugin.xml (+8 lines)
Lines 2234-2237 Link Here
2234
            type="org.eclipse.core.resources.IMarker">
2234
            type="org.eclipse.core.resources.IMarker">
2235
      </propertyTester>
2235
      </propertyTester>
2236
   </extension>
2236
   </extension>
2237
      <extension
2238
         point="org.eclipse.ui.installationPages">
2239
          <page
2240
            name="%installationPage.feature.name"
2241
            class="org.eclipse.ui.internal.about.AboutFeaturesPage"
2242
            id="20.FeaturesPage">
2243
          </page>
2244
       </extension>
2237
</plugin>
2245
</plugin>
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/AboutFeaturesDialog.java (-503 / +17 lines)
Lines 12-110 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.ui.internal.dialogs;
13
package org.eclipse.ui.internal.dialogs;
14
14
15
import java.util.HashMap;
16
import java.util.Iterator;
17
import java.util.Map;
18
19
import org.eclipse.core.runtime.IBundleGroup;
20
import org.eclipse.jface.dialogs.IDialogConstants;
21
import org.eclipse.jface.dialogs.MessageDialog;
22
import org.eclipse.jface.internal.ConfigureColumnsDialog;
23
import org.eclipse.jface.resource.ImageDescriptor;
24
import org.eclipse.jface.window.Window;
25
import org.eclipse.osgi.util.NLS;
15
import org.eclipse.osgi.util.NLS;
26
import org.eclipse.swt.SWT;
27
import org.eclipse.swt.custom.StyledText;
28
import org.eclipse.swt.events.DisposeEvent;
29
import org.eclipse.swt.events.DisposeListener;
30
import org.eclipse.swt.events.SelectionAdapter;
31
import org.eclipse.swt.events.SelectionEvent;
32
import org.eclipse.swt.graphics.Cursor;
33
import org.eclipse.swt.graphics.Font;
34
import org.eclipse.swt.graphics.Image;
35
import org.eclipse.swt.layout.GridData;
36
import org.eclipse.swt.layout.GridLayout;
37
import org.eclipse.swt.widgets.Button;
38
import org.eclipse.swt.widgets.Composite;
39
import org.eclipse.swt.widgets.Control;
40
import org.eclipse.swt.widgets.Label;
41
import org.eclipse.swt.widgets.Shell;
16
import org.eclipse.swt.widgets.Shell;
42
import org.eclipse.swt.widgets.Table;
43
import org.eclipse.swt.widgets.TableColumn;
44
import org.eclipse.swt.widgets.TableItem;
45
import org.eclipse.ui.PlatformUI;
46
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
17
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
47
import org.eclipse.ui.internal.WorkbenchMessages;
18
import org.eclipse.ui.internal.WorkbenchMessages;
48
import org.eclipse.ui.internal.about.AboutBundleGroupData;
19
import org.eclipse.ui.internal.about.AboutBundleGroupData;
49
import org.eclipse.ui.internal.about.AboutData;
20
import org.eclipse.ui.internal.about.AboutFeaturesPage;
50
import org.osgi.framework.Bundle;
21
import org.eclipse.ui.internal.about.ProductInfoDialog;
51
22
52
/**
23
/**
53
 * Displays information about the product plugins.
24
 * Displays information about the product plugins.
54
 *
25
 * 
55
 * PRIVATE
26
 * PRIVATE This class is internal to the workbench and must not be called
56
 *	This class is internal to the workbench and must not be called outside
27
 * outside the workbench.
57
 *	the workbench.
58
 */
28
 */
59
public class AboutFeaturesDialog extends ProductInfoDialog {
29
public class AboutFeaturesDialog extends ProductInfoDialog {
60
30
	   /**
61
    /**
62
     * Table height in dialog units (value 150).
63
     */
64
    private static final int TABLE_HEIGHT = 150;
65
66
    private static final int INFO_HEIGHT = 100;
67
68
    private final static int MORE_ID = IDialogConstants.CLIENT_ID + 1;
69
70
    private final static int PLUGINS_ID = IDialogConstants.CLIENT_ID + 2;
71
72
    private final static int COLUMNS_ID = IDialogConstants.CLIENT_ID + 3;
73
74
    private Table table;
75
76
    private Label imageLabel;
77
78
    private StyledText text;
79
80
    private Composite infoArea;
81
82
    private Map cachedImages = new HashMap();
83
84
    private String columnTitles[] = {
85
            WorkbenchMessages.AboutFeaturesDialog_provider,
86
            WorkbenchMessages.AboutFeaturesDialog_featureName, 
87
            WorkbenchMessages.AboutFeaturesDialog_version, 
88
            WorkbenchMessages.AboutFeaturesDialog_featureId, 
89
    };
90
91
    private String productName;
92
93
    private AboutBundleGroupData[] bundleGroupInfos;
94
95
    private int lastColumnChosen = 0; // initially sort by provider
96
97
    private boolean reverseSort = false; // initially sort ascending
98
99
    private AboutBundleGroupData lastSelection = null;
100
101
    private Button moreButton;
102
103
    private Button pluginsButton;
104
105
    private static Map featuresMap;
106
107
    /**
108
     * Constructor for AboutFeaturesDialog.
31
     * Constructor for AboutFeaturesDialog.
109
     * 
32
     * 
110
     * @param parentShell the parent shell
33
     * @param parentShell the parent shell
Lines 112-537 Link Here
112
     * @param bundleGroupInfos the bundle info
35
     * @param bundleGroupInfos the bundle info
113
     */
36
     */
114
    public AboutFeaturesDialog(Shell parentShell, String productName,
37
    public AboutFeaturesDialog(Shell parentShell, String productName,
115
            AboutBundleGroupData[] bundleGroupInfos) {
38
            AboutBundleGroupData[] bundleGroupInfos, AboutBundleGroupData initialSelection) {
116
        super(parentShell);
39
        super(parentShell);
117
        this.productName = productName;
40
        AboutFeaturesPage page = new AboutFeaturesPage();
118
41
        page.setProductName(productName);
119
        // the order of the array may be changed due to sorting, so create a
42
        page.setBundleGroupInfos(bundleGroupInfos);
120
        // copy
43
        page.setInitialSelection(initialSelection);
121
        this.bundleGroupInfos = new AboutBundleGroupData[bundleGroupInfos.length];
44
        String title;
122
        System.arraycopy(bundleGroupInfos, 0, this.bundleGroupInfos, 0,
45
        if (productName != null) 
123
                bundleGroupInfos.length);
46
			title = NLS.bind(WorkbenchMessages.AboutFeaturesDialog_shellTitle, productName);
124
47
        else
125
        AboutData.sortByProvider(reverseSort, this.bundleGroupInfos);
48
        	title = WorkbenchMessages.AboutFeaturesDialog_SimpleTitle;
126
    }
49
        initializeDialog(page, title, IWorkbenchHelpContextIds.ABOUT_FEATURES_DIALOG);
127
128
    /**
129
     * The More Info button was pressed.  Open a browser with the license for the
130
     * selected item or an information dialog if there is no license, or the browser
131
     * cannot be opened. 
132
     */
133
    private void handleMoreInfoPressed() {
134
        TableItem[] items = table.getSelection();
135
        if (items.length <= 0) {
136
			return;
137
		}
138
139
        AboutBundleGroupData info = (AboutBundleGroupData) items[0].getData();
140
        if (info == null || !openBrowser(info.getLicenseUrl())) {
141
            MessageDialog.openInformation(getShell(), WorkbenchMessages.AboutFeaturesDialog_noInfoTitle, 
142
                    WorkbenchMessages.AboutFeaturesDialog_noInformation);
143
        }
144
    }
145
146
    /**
147
     * The Plugins button was pressed. Open an about dialog on the plugins for
148
     * the selected feature.
149
     */
150
    private void handlePluginInfoPressed() {
151
        TableItem[] items = table.getSelection();
152
        if (items.length <= 0) {
153
			return;
154
		}
155
156
        AboutBundleGroupData info = (AboutBundleGroupData) items[0].getData();
157
        IBundleGroup bundleGroup = info.getBundleGroup();
158
        Bundle[] bundles = bundleGroup == null ? new Bundle[0] : bundleGroup
159
                .getBundles();
160
161
        AboutPluginsDialog d = new AboutPluginsDialog(getShell(), productName,
162
                bundles, WorkbenchMessages.AboutFeaturesDialog_pluginInfoTitle, 
163
                NLS.bind(WorkbenchMessages.AboutFeaturesDialog_pluginInfoMessage, bundleGroup.getIdentifier()),
164
                IWorkbenchHelpContextIds.ABOUT_FEATURES_PLUGINS_DIALOG);
165
        d.open();
166
    }
167
168
    /*
169
     * (non-Javadoc) Method declared on Dialog.
170
     */
171
    protected void buttonPressed(int buttonId) {
172
        switch (buttonId) {
173
        case MORE_ID:
174
            handleMoreInfoPressed();
175
            break;
176
        case PLUGINS_ID:
177
            handlePluginInfoPressed();
178
            break;
179
        case COLUMNS_ID:
180
        	handleColumnsPressed();
181
        	break;
182
        default:
183
            super.buttonPressed(buttonId);
184
            break;
185
        }
186
    }
187
188
    /**
189
	 * 
190
	 */
191
	private void handleColumnsPressed() {
192
		ConfigureColumnsDialog d = new ConfigureColumnsDialog(this, table);
193
		d.open();
194
	}
195
196
	/*
197
     * (non-Javadoc) Method declared on Window.
198
     */
199
    protected void configureShell(Shell newShell) {
200
        super.configureShell(newShell);
201
        if (productName != null) {
202
			newShell.setText(NLS.bind(WorkbenchMessages.AboutFeaturesDialog_shellTitle, productName));
203
		}
204
205
        PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
206
				IWorkbenchHelpContextIds.ABOUT_FEATURES_DIALOG);
207
    }
208
209
    /**
210
     * Add buttons to the dialog's button bar.
211
     * 
212
     * Subclasses should override.
213
     * 
214
     * @param parent
215
     *            the button bar composite
216
     */
217
    protected void createButtonsForButtonBar(Composite parent) {
218
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
219
220
        moreButton = createButton(parent, MORE_ID, WorkbenchMessages.AboutFeaturesDialog_moreInfo, false);
221
        pluginsButton = createButton(parent, PLUGINS_ID, WorkbenchMessages.AboutFeaturesDialog_pluginsInfo, false); 
222
        createButton(parent, COLUMNS_ID, WorkbenchMessages.AboutFeaturesDialog_columns, false); 
223
        Label l = new Label(parent, SWT.NONE);
224
        l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
225
        GridLayout layout = (GridLayout) parent.getLayout();
226
        layout.numColumns++;
227
        layout.makeColumnsEqualWidth = false;
228
229
        Button b = createButton(parent, IDialogConstants.OK_ID,
230
                IDialogConstants.OK_LABEL, true);
231
        b.setFocus();
232
233
        TableItem[] items = table.getSelection();
234
        if (items.length > 0) {
235
			updateButtons((AboutBundleGroupData) items[0].getData());
236
		}
237
    }
238
239
    /**
240
     * Create the contents of the dialog (above the button bar).
241
     * 
242
     * Subclasses should overide.
243
     * 
244
     * @param parent  the parent composite to contain the dialog area
245
     * @return the dialog area control
246
     */
247
    protected Control createDialogArea(Composite parent) {
248
        setHandCursor(new Cursor(parent.getDisplay(), SWT.CURSOR_HAND));
249
        setBusyCursor(new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT));
250
        getShell().addDisposeListener(new DisposeListener() {
251
            public void widgetDisposed(DisposeEvent e) {
252
                if (getHandCursor() != null) {
253
					getHandCursor().dispose();
254
				}
255
                if (getBusyCursor() != null) {
256
					getBusyCursor().dispose();
257
				}
258
            }
259
        });
260
261
        Composite outer = (Composite) super.createDialogArea(parent);
262
263
        createTable(outer);
264
        createInfoArea(outer);
265
        
266
        return outer;
267
    }
268
269
    /** 
270
     * Create the info area containing the image and text
271
     */
272
    protected void createInfoArea(Composite parent) {
273
        Font font = parent.getFont();
274
275
        infoArea = new Composite(parent, SWT.NULL);
276
        GridData data = new GridData(GridData.FILL, GridData.FILL, true, true);
277
        // need to provide space for arbitrary feature infos, not just the
278
        // one selected by default
279
        data.heightHint = convertVerticalDLUsToPixels(INFO_HEIGHT);
280
        infoArea.setLayoutData(data);
281
282
        GridLayout layout = new GridLayout();
283
        layout.numColumns = 2;
284
        infoArea.setLayout(layout);
285
286
        imageLabel = new Label(infoArea, SWT.NONE);
287
        data = new GridData(GridData.FILL, GridData.BEGINNING, false, false);
288
        data.widthHint = 32;
289
        data.heightHint = 32;
290
        imageLabel.setLayoutData(data);
291
        imageLabel.setFont(font);
292
293
        // text on the right
294
        text = new StyledText(infoArea, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);
295
        text.setCaret(null);
296
        text.setFont(parent.getFont());
297
        data = new GridData(GridData.FILL, GridData.FILL, true, true);
298
        text.setLayoutData(data);
299
        text.setFont(font);
300
        text.setCursor(null);
301
        text.setBackground(infoArea.getBackground());
302
        addListeners(text);
303
304
        TableItem[] items = table.getSelection();
305
        if (items.length > 0) {
306
			updateInfoArea((AboutBundleGroupData) items[0].getData());
307
		}
308
    }
309
310
    /**
311
     * Create the table part of the dialog.
312
     *
313
     * @param parent  the parent composite to contain the dialog area
314
     */
315
    protected void createTable(Composite parent) {
316
        table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE
317
                | SWT.FULL_SELECTION | SWT.BORDER);
318
        
319
        GridData gridData = new GridData(GridData.FILL, GridData.FILL, true,
320
                true);
321
        gridData.heightHint = convertVerticalDLUsToPixels(TABLE_HEIGHT);
322
        table.setLayoutData(gridData);
323
        table.setHeaderVisible(true);
324
        
325
        table.setLinesVisible(true);
326
        table.setFont(parent.getFont());
327
        table.addSelectionListener(new SelectionAdapter() {
328
            public void widgetSelected(SelectionEvent e) {
329
                AboutBundleGroupData info = (AboutBundleGroupData) e.item
330
                        .getData();
331
                updateInfoArea(info);
332
                updateButtons(info);
333
            }
334
        });
335
        
336
        int[] columnWidths = { convertHorizontalDLUsToPixels(120),
337
                convertHorizontalDLUsToPixels(120),
338
                convertHorizontalDLUsToPixels(70),
339
                convertHorizontalDLUsToPixels(130) };
340
341
        for (int i = 0; i < columnTitles.length; i++) {
342
            TableColumn tableColumn = new TableColumn(table, SWT.NULL);
343
            tableColumn.setWidth(columnWidths[i]);
344
            tableColumn.setText(columnTitles[i]);
345
            final int columnIndex = i;
346
            tableColumn.addSelectionListener(new SelectionAdapter() {
347
                public void widgetSelected(SelectionEvent e) {
348
                    sort(columnIndex);
349
                }
350
            });
351
        }
352
353
        // create a table row for each bundle group
354
        String selId = lastSelection == null ? null : lastSelection.getId();
355
        int sel = 0;
356
        for (int i = 0; i < bundleGroupInfos.length; i++) {
357
            if (bundleGroupInfos[i].getId().equals(selId)) {
358
				sel = i;
359
			}
360
361
            TableItem item = new TableItem(table, SWT.NULL);
362
            item.setText(createRow(bundleGroupInfos[i]));
363
            item.setData(bundleGroupInfos[i]);
364
        }
365
366
        // if an item was specified during construction, it should be
367
        // selected when the table is created
368
        if (bundleGroupInfos.length > 0) {
369
            table.setSelection(sel);
370
            table.showSelection();
371
        }
372
    }
373
374
    /**
375
     * @see Window#close()
376
     */
377
    public boolean close() {
378
        boolean ret = super.close();
379
380
        Iterator iter = cachedImages.values().iterator();
381
        while (iter.hasNext()) {
382
            Image image = (Image) iter.next();
383
            image.dispose();
384
        }
385
386
        return ret;
387
    }
388
389
    /**
390
     * Update the button enablement
391
     */
392
    private void updateButtons(AboutBundleGroupData info) {
393
        if (info == null) {
394
            moreButton.setEnabled(false);
395
            pluginsButton.setEnabled(false);
396
            return;
397
        }
398
399
        // Creating the feature map is too much just to determine enablement, so if
400
        // it doesn't already exist, just enable the buttons.  If this was the wrong
401
        // choice, then when the button is actually pressed an dialog will be opened. 
402
        if (featuresMap == null) {
403
            moreButton.setEnabled(true);
404
            pluginsButton.setEnabled(true);
405
            return;
406
        }
407
408
        moreButton.setEnabled(info.getLicenseUrl() != null);
409
        pluginsButton.setEnabled(true);
410
    }
411
412
    /**
413
     * Update the info area
414
     */
415
    private void updateInfoArea(AboutBundleGroupData info) {
416
        if (info == null) {
417
            imageLabel.setImage(null);
418
            text.setText(""); //$NON-NLS-1$
419
            return;
420
        }
421
422
        ImageDescriptor desc = info.getFeatureImage();
423
        Image image = (Image) cachedImages.get(desc);
424
        if (image == null && desc != null) {
425
            image = desc.createImage();
426
            cachedImages.put(desc, image);
427
        }
428
        imageLabel.setImage(image);
429
430
        String aboutText = info.getAboutText();
431
        setItem(null);
432
        if (aboutText != null) {
433
			setItem(scan(aboutText));
434
		}
435
436
        if (getItem() == null) {
437
			text.setText(WorkbenchMessages.AboutFeaturesDialog_noInformation);
438
		} else {
439
            text.setText(getItem().getText());
440
            text.setCursor(null);
441
            setLinkRanges(text, getItem().getLinkRanges());
442
        }
443
    }
444
445
    /**
446
     * Select the initial selection
447
     * 
448
     * @param info the info
449
     */
450
    public void setInitialSelection(AboutBundleGroupData info) {
451
        lastSelection = info;
452
    }
453
454
    /**
455
     * Sort the rows of the table based on the selected column.
456
     * 
457
     * @param column
458
     *            index of table column selected as sort criteria
459
     */
460
    private void sort(int column) {
461
        if (lastColumnChosen == column) {
462
			reverseSort = !reverseSort;
463
		} else {
464
            reverseSort = false;
465
            lastColumnChosen = column;
466
        }
467
468
        if (table.getItemCount() <= 1) {
469
			return;
470
		}
471
472
        // Remember the last selection
473
        int sel = table.getSelectionIndex();
474
        if (sel != -1) {
475
			lastSelection = bundleGroupInfos[sel];
476
		}
477
478
        switch (column) {
479
        case 0:
480
            AboutData.sortByProvider(reverseSort, bundleGroupInfos);
481
            break;
482
        case 1:
483
            AboutData.sortByName(reverseSort, bundleGroupInfos);
484
            break;
485
        case 2:
486
            AboutData.sortByVersion(reverseSort, bundleGroupInfos);
487
            break;
488
        case 3:
489
            AboutData.sortById(reverseSort, bundleGroupInfos);
490
            break;
491
        }
492
493
        refreshTable();
494
    }
495
496
    /**
497
     * Refresh the rows of the table based on the selected column. Maintain
498
     * selection from before sort action request.
499
     */
500
    private void refreshTable() {
501
        TableItem[] items = table.getItems();
502
503
        // create new order of table items
504
        for (int i = 0; i < items.length; i++) {
505
            items[i].setText(createRow(bundleGroupInfos[i]));
506
            items[i].setData(bundleGroupInfos[i]);
507
        }
508
509
        // Maintain the original selection
510
        int sel = -1;
511
        if (lastSelection != null) {
512
            String oldId = lastSelection.getId();
513
            for (int k = 0; k < bundleGroupInfos.length; k++) {
514
				if (oldId.equalsIgnoreCase(bundleGroupInfos[k].getId())) {
515
					sel = k;
516
				}
517
			}
518
519
            table.setSelection(sel);
520
            table.showSelection();
521
        }
522
523
        updateInfoArea(lastSelection);
524
    }
525
526
    /**
527
     * Return an array of strings containing the argument's information in the
528
     * proper order for this table's columns.
529
     * 
530
     * @param info
531
     *            the source information for the new row, must not be null
532
     */
533
    private static String[] createRow(AboutBundleGroupData info) {
534
        return new String[] { info.getProviderName(), info.getName(),
535
                info.getVersion(), info.getId() };
536
    }
50
    }
537
}
51
}
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/AboutDialog.java (-56 / +24 lines)
Lines 19-24 Link Here
19
import org.eclipse.core.runtime.Platform;
19
import org.eclipse.core.runtime.Platform;
20
import org.eclipse.jface.action.MenuManager;
20
import org.eclipse.jface.action.MenuManager;
21
import org.eclipse.jface.dialogs.IDialogConstants;
21
import org.eclipse.jface.dialogs.IDialogConstants;
22
import org.eclipse.jface.dialogs.TrayDialog;
22
import org.eclipse.jface.resource.ImageDescriptor;
23
import org.eclipse.jface.resource.ImageDescriptor;
23
import org.eclipse.jface.resource.JFaceColors;
24
import org.eclipse.jface.resource.JFaceColors;
24
import org.eclipse.osgi.util.NLS;
25
import org.eclipse.osgi.util.NLS;
Lines 35-41 Link Here
35
import org.eclipse.swt.events.SelectionAdapter;
36
import org.eclipse.swt.events.SelectionAdapter;
36
import org.eclipse.swt.events.SelectionEvent;
37
import org.eclipse.swt.events.SelectionEvent;
37
import org.eclipse.swt.graphics.Color;
38
import org.eclipse.swt.graphics.Color;
38
import org.eclipse.swt.graphics.Cursor;
39
import org.eclipse.swt.graphics.GC;
39
import org.eclipse.swt.graphics.GC;
40
import org.eclipse.swt.graphics.Image;
40
import org.eclipse.swt.graphics.Image;
41
import org.eclipse.swt.graphics.Point;
41
import org.eclipse.swt.graphics.Point;
Lines 47-72 Link Here
47
import org.eclipse.swt.widgets.Control;
47
import org.eclipse.swt.widgets.Control;
48
import org.eclipse.swt.widgets.Label;
48
import org.eclipse.swt.widgets.Label;
49
import org.eclipse.swt.widgets.Shell;
49
import org.eclipse.swt.widgets.Shell;
50
import org.eclipse.ui.IWorkbenchWindow;
50
import org.eclipse.ui.PlatformUI;
51
import org.eclipse.ui.PlatformUI;
51
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
52
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
52
import org.eclipse.ui.internal.ProductProperties;
53
import org.eclipse.ui.internal.ProductProperties;
53
import org.eclipse.ui.internal.WorkbenchMessages;
54
import org.eclipse.ui.internal.WorkbenchMessages;
54
import org.eclipse.ui.internal.about.AboutBundleGroupData;
55
import org.eclipse.ui.internal.about.AboutBundleGroupData;
55
import org.eclipse.ui.internal.about.AboutFeaturesButtonManager;
56
import org.eclipse.ui.internal.about.AboutFeaturesButtonManager;
57
import org.eclipse.ui.internal.about.AboutItem;
58
import org.eclipse.ui.internal.about.AboutTextManager;
59
import org.eclipse.ui.internal.about.InstallationDialog;
56
import org.eclipse.ui.menus.CommandContributionItem;
60
import org.eclipse.ui.menus.CommandContributionItem;
57
import org.eclipse.ui.menus.CommandContributionItemParameter;
61
import org.eclipse.ui.menus.CommandContributionItemParameter;
58
62
59
/**
63
/**
60
 * Displays information about the product.
64
 * Displays information about the product.
61
 */
65
 */
62
public class AboutDialog extends ProductInfoDialog {
66
public class AboutDialog extends TrayDialog {
63
    private final static int MAX_IMAGE_WIDTH_FOR_TEXT = 250;
67
    private final static int MAX_IMAGE_WIDTH_FOR_TEXT = 250;
64
68
65
    private final static int FEATURES_ID = IDialogConstants.CLIENT_ID + 1;
69
    private final static int DETAILS_ID = IDialogConstants.CLIENT_ID + 1;
66
67
    private final static int PLUGINS_ID = IDialogConstants.CLIENT_ID + 2;
68
69
    private final static int INFO_ID = IDialogConstants.CLIENT_ID + 3;
70
70
71
    private String productName;
71
    private String productName;
72
72
Lines 78-86 Link Here
78
78
79
    private AboutFeaturesButtonManager buttonManager = new AboutFeaturesButtonManager();
79
    private AboutFeaturesButtonManager buttonManager = new AboutFeaturesButtonManager();
80
80
81
    // TODO should the styled text be disposed? if not then it likely
82
    //      doesn't need to be a member
83
    private StyledText text;
81
    private StyledText text;
82
    
83
    private AboutTextManager aboutTextManager;
84
84
85
    /**
85
    /**
86
     * Create an instance of the AboutDialog for the given window.
86
     * Create an instance of the AboutDialog for the given window.
Lines 117-141 Link Here
117
     */
117
     */
118
    protected void buttonPressed(int buttonId) {
118
    protected void buttonPressed(int buttonId) {
119
        switch (buttonId) {
119
        switch (buttonId) {
120
        case FEATURES_ID:
120
        case DETAILS_ID:
121
			BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
121
			BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
122
				public void run() {
122
				public void run() {
123
		            new AboutFeaturesDialog(getShell(), productName, bundleGroupInfos)
123
					IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
124
		                    .open();
124
					InstallationDialog dialog = new InstallationDialog(getShell(), workbenchWindow);
125
				}
125
					dialog.open();	
126
			});
127
            break;
128
        case PLUGINS_ID:
129
			BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
130
				public void run() {
131
		            new AboutPluginsDialog(getShell(), productName).open();
132
				}
133
			});
134
            break;
135
        case INFO_ID:
136
			BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
137
				public void run() {
138
		            new AboutSystemDialog(getShell()).open();
139
				}
126
				}
140
			});
127
			});
141
            break;
128
            break;
Lines 176-189 Link Here
176
    protected void createButtonsForButtonBar(Composite parent) {
163
    protected void createButtonsForButtonBar(Composite parent) {
177
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
164
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
178
165
179
        // bug 64232: the feature details button should only be created if there
166
        createButton(parent, DETAILS_ID, WorkbenchMessages.AboutDialog_DetailsButton, false); 
180
        // are features to show
181
        if (bundleGroupInfos != null && bundleGroupInfos.length > 0) {
182
			createButton(parent, FEATURES_ID, WorkbenchMessages.AboutDialog_featureInfo, false);
183
		} 
184
185
        createButton(parent, PLUGINS_ID, WorkbenchMessages.AboutDialog_pluginInfo, false);
186
        createButton(parent, INFO_ID, WorkbenchMessages.AboutDialog_systemInfo, false); 
187
167
188
        Label l = new Label(parent, SWT.NONE);
168
        Label l = new Label(parent, SWT.NONE);
189
        l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
169
        l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Lines 206-226 Link Here
206
     * @return the dialog area control
186
     * @return the dialog area control
207
     */
187
     */
208
    protected Control createDialogArea(Composite parent) {
188
    protected Control createDialogArea(Composite parent) {
209
        final Cursor hand = new Cursor(parent.getDisplay(), SWT.CURSOR_HAND);
189
         // brand the about box if there is product info
210
        final Cursor busy = new Cursor(parent.getDisplay(), SWT.CURSOR_WAIT);
211
        setHandCursor(hand);
212
        setBusyCursor(busy);
213
        getShell().addDisposeListener(new DisposeListener() {
214
            public void widgetDisposed(DisposeEvent e) {
215
                setHandCursor(null);
216
                hand.dispose();
217
                setBusyCursor(null);
218
                busy.dispose();
219
            }
220
        });
221
222
        // brand the about box if there is product info
223
        Image aboutImage = null;
190
        Image aboutImage = null;
191
        AboutItem item = null;
224
        if (product != null) {
192
        if (product != null) {
225
            ImageDescriptor imageDescriptor = ProductProperties
193
            ImageDescriptor imageDescriptor = ProductProperties
226
                    .getAboutImage(product);
194
                    .getAboutImage(product);
Lines 233-239 Link Here
233
                    || aboutImage.getBounds().width <= MAX_IMAGE_WIDTH_FOR_TEXT) {
201
                    || aboutImage.getBounds().width <= MAX_IMAGE_WIDTH_FOR_TEXT) {
234
                String aboutText = ProductProperties.getAboutText(product);
202
                String aboutText = ProductProperties.getAboutText(product);
235
                if (aboutText != null) {
203
                if (aboutText != null) {
236
					setItem(scan(aboutText));
204
					item = AboutTextManager.scan(aboutText);
237
				}
205
				}
238
            }
206
            }
239
207
Lines 276-282 Link Here
276
        topContainer.setForeground(foreground);
244
        topContainer.setForeground(foreground);
277
245
278
        layout = new GridLayout();
246
        layout = new GridLayout();
279
        layout.numColumns = (aboutImage == null || getItem() == null ? 1 : 2);
247
        layout.numColumns = (aboutImage == null || item == null ? 1 : 2);
280
        layout.marginWidth = 0;
248
        layout.marginWidth = 0;
281
        layout.marginHeight = 0;
249
        layout.marginHeight = 0;
282
        layout.verticalSpacing = 0;
250
        layout.verticalSpacing = 0;
Lines 318-324 Link Here
318
        data.heightHint = topContainerHeightHint;
286
        data.heightHint = topContainerHeightHint;
319
        topContainer.setLayoutData(data);
287
        topContainer.setLayoutData(data);
320
        
288
        
321
        if (getItem() != null) {
289
        if (item != null) {
322
        	final int minWidth = 400; // This value should really be calculated
290
        	final int minWidth = 400; // This value should really be calculated
323
        	// from the computeSize(SWT.DEFAULT,
291
        	// from the computeSize(SWT.DEFAULT,
324
        	// SWT.DEFAULT) of all the
292
        	// SWT.DEFAULT) of all the
Lines 340-351 Link Here
340
    		text = new StyledText(textComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);
308
    		text = new StyledText(textComposite, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);
341
    		text.setCaret(null);
309
    		text.setCaret(null);
342
            text.setFont(parent.getFont());
310
            text.setFont(parent.getFont());
343
            text.setText(getItem().getText());
311
            text.setText(item.getText());
344
            text.setCursor(null);
312
            text.setCursor(null);
345
            text.setBackground(background);
313
            text.setBackground(background);
346
            text.setForeground(foreground);
314
            text.setForeground(foreground);
347
            setLinkRanges(text, getItem().getLinkRanges());
315
            
348
            addListeners(text);
316
            aboutTextManager = new AboutTextManager(text);
317
            aboutTextManager.setItem(item);
349
            
318
            
350
            createTextMenu();
319
            createTextMenu();
351
            
320
            
Lines 487-494 Link Here
487
                        .getData();
456
                        .getData();
488
457
489
                AboutFeaturesDialog d = new AboutFeaturesDialog(getShell(),
458
                AboutFeaturesDialog d = new AboutFeaturesDialog(getShell(),
490
                        productName, groupInfos);
459
                        productName, groupInfos, selection);
491
                d.setInitialSelection(selection);
492
                d.open();
460
                d.open();
493
            }
461
            }
494
        });
462
        });
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/BundleSigningTray.java (-301 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007, 2008 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
12
package org.eclipse.ui.internal.dialogs;
13
14
import java.io.IOException;
15
import java.security.GeneralSecurityException;
16
import java.security.cert.Certificate;
17
import java.security.cert.X509Certificate;
18
import java.text.DateFormat;
19
import java.util.ArrayList;
20
import java.util.Date;
21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Map;
24
import java.util.Properties;
25
import java.util.StringTokenizer;
26
import java.util.Map.Entry;
27
28
import org.eclipse.core.runtime.IProgressMonitor;
29
import org.eclipse.core.runtime.IStatus;
30
import org.eclipse.core.runtime.OperationCanceledException;
31
import org.eclipse.core.runtime.Status;
32
import org.eclipse.core.runtime.jobs.Job;
33
import org.eclipse.jface.dialogs.Dialog;
34
import org.eclipse.jface.dialogs.DialogTray;
35
import org.eclipse.jface.dialogs.TrayDialog;
36
import org.eclipse.jface.resource.JFaceResources;
37
import org.eclipse.osgi.signedcontent.SignedContent;
38
import org.eclipse.osgi.signedcontent.SignedContentFactory;
39
import org.eclipse.osgi.signedcontent.SignerInfo;
40
import org.eclipse.osgi.util.NLS;
41
import org.eclipse.swt.SWT;
42
import org.eclipse.swt.custom.StyledText;
43
import org.eclipse.swt.graphics.Color;
44
import org.eclipse.swt.graphics.GC;
45
import org.eclipse.swt.graphics.Point;
46
import org.eclipse.swt.layout.GridData;
47
import org.eclipse.swt.layout.GridLayout;
48
import org.eclipse.swt.widgets.Composite;
49
import org.eclipse.swt.widgets.Control;
50
import org.eclipse.swt.widgets.Display;
51
import org.eclipse.swt.widgets.Label;
52
import org.eclipse.swt.widgets.Shell;
53
import org.eclipse.swt.widgets.Text;
54
import org.eclipse.ui.internal.WorkbenchMessages;
55
import org.eclipse.ui.internal.WorkbenchPlugin;
56
import org.eclipse.ui.internal.about.AboutBundleData;
57
import org.eclipse.ui.statushandlers.StatusManager;
58
import org.osgi.framework.BundleContext;
59
import org.osgi.framework.ServiceReference;
60
61
/**
62
 * @since 3.3
63
 *
64
 */
65
public class BundleSigningTray extends DialogTray {
66
67
68
	private Text date;
69
	private StyledText certificate;
70
	private AboutBundleData data;
71
	private TrayDialog dialog;
72
	
73
	/**
74
	 * 
75
	 */
76
	public BundleSigningTray(TrayDialog dialog) {
77
		this.dialog = dialog;
78
	}
79
	
80
	public void setData(AboutBundleData data) {
81
		this.data = data;
82
		startJobs();
83
	}
84
85
	/* (non-Javadoc)
86
	 * @see org.eclipse.jface.dialogs.DialogTray#createContents(org.eclipse.swt.widgets.Composite)
87
	 */
88
	protected Control createContents(Composite parent) {
89
		Composite content = new Composite(parent, SWT.NONE);
90
		content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
91
		GridLayout layout = new GridLayout(2, false);
92
		content.setLayout(layout);
93
		// date
94
		Color backgroundColor = parent.getDisplay().getSystemColor(
95
				SWT.COLOR_WIDGET_BACKGROUND);
96
		{
97
			Label label = new Label(content, SWT.NONE);
98
			label.setText(WorkbenchMessages.BundleSigningTray_Signing_Date); 
99
			GridData data = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
100
			date = new Text(content, SWT.READ_ONLY);
101
			GC gc = new GC(date);
102
			gc.setFont(JFaceResources.getDialogFont());
103
			Point size = gc.stringExtent(DateFormat.getDateTimeInstance().format(new Date()));
104
			data.widthHint = size.x;
105
			gc.dispose();
106
			date.setText(WorkbenchMessages.BundleSigningTray_Working); 
107
			date.setLayoutData(data);
108
			date.setBackground(backgroundColor);
109
		}
110
		// signer
111
		{
112
			Label label = new Label(content, SWT.NONE);
113
			label.setText(WorkbenchMessages.BundleSigningTray_Signing_Certificate); 
114
			GridData data = new GridData(SWT.BEGINNING, SWT.BEGINNING, true, false);
115
			data.horizontalSpan = 2;
116
			data = new GridData(SWT.FILL, SWT.FILL, true, true);
117
			data.horizontalSpan = 2;
118
			certificate = new StyledText(content, SWT.READ_ONLY | SWT.MULTI | SWT.WRAP);
119
			certificate.setText(WorkbenchMessages.BundleSigningTray_Working); 
120
			certificate.setLayoutData(data);
121
		}
122
		
123
		// problems
124
//		{
125
//			Label label = new Label(content, SWT.NONE);
126
//			label.setText("Problems:"); //$NON-NLS-1$
127
//
128
//		}
129
		Dialog.applyDialogFont(content);
130
131
		startJobs(); // start the jobs that will prime the content
132
133
		return content;
134
	}
135
	
136
	/**
137
	 * 
138
	 */
139
	private void startJobs() {
140
		if (!isOpen())
141
			return;
142
		certificate.setText(WorkbenchMessages.BundleSigningTray_Working); 
143
		date.setText(WorkbenchMessages.BundleSigningTray_Working); 
144
		final BundleContext bundleContext = WorkbenchPlugin.getDefault()
145
				.getBundleContext();
146
		final ServiceReference factoryRef = bundleContext
147
				.getServiceReference(SignedContentFactory.class.getName());
148
		if (factoryRef == null) {
149
			StatusManager.getManager().handle(
150
					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
151
							WorkbenchMessages.BundleSigningTray_Cant_Find_Service), 
152
					StatusManager.LOG);
153
			return;
154
		}
155
156
		final SignedContentFactory contentFactory = (SignedContentFactory) bundleContext
157
				.getService(factoryRef);
158
		if (contentFactory == null) {
159
			StatusManager.getManager().handle(
160
					new Status(IStatus.WARNING, WorkbenchPlugin.PI_WORKBENCH,
161
							WorkbenchMessages.BundleSigningTray_Cant_Find_Service), 
162
					StatusManager.LOG);
163
			return;
164
		}
165
166
		final AboutBundleData myData = data;
167
		final Job signerJob = new Job(NLS.bind(WorkbenchMessages.BundleSigningTray_Determine_Signer_For, myData.getId())) { 
168
169
			protected IStatus run(IProgressMonitor monitor) {
170
				try {
171
					if (myData != data)
172
						return Status.OK_STATUS;
173
					SignedContent signedContent = contentFactory.getSignedContent(myData
174
							.getBundle());
175
					if (myData != data)
176
						return Status.OK_STATUS;
177
					SignerInfo[] signers = signedContent.getSignerInfos();
178
					final String signerText, dateText;
179
					final Shell dialogShell = dialog.getShell();
180
					if (!isOpen() && BundleSigningTray.this.data == myData)
181
						return Status.OK_STATUS;
182
183
					if (signers.length == 0) {
184
						signerText = WorkbenchMessages.BundleSigningTray_Unsigned; 
185
						dateText = WorkbenchMessages.BundleSigningTray_Unsigned; 
186
					} else {
187
						Properties [] certs = parseCerts(signers[0].getCertificateChain());
188
						if (certs.length == 0)
189
							signerText = WorkbenchMessages.BundleSigningTray_Unknown; 
190
						else {
191
							StringBuffer buffer = new StringBuffer();
192
							for (Iterator i = certs[0].entrySet().iterator(); i.hasNext(); ) {
193
								Map.Entry entry = (Entry) i.next();
194
								buffer.append(entry.getKey());
195
								buffer.append('=');
196
								buffer.append(entry.getValue());
197
								if (i.hasNext())
198
									buffer.append('\n');
199
							}
200
							signerText = buffer.toString();
201
						}
202
203
						Date signDate = signedContent.getSigningTime(signers[0]);
204
						if (signDate != null)
205
							dateText = DateFormat.getDateTimeInstance().format(
206
									signDate);
207
						else
208
							dateText = WorkbenchMessages.BundleSigningTray_Unknown; 
209
					}
210
					
211
					Display display = dialogShell.getDisplay();
212
					display.asyncExec(new Runnable() {
213
214
						public void run() {
215
							// check to see if the tray is still visible and if we're still looking at the same item
216
							if (!isOpen() && BundleSigningTray.this.data != myData)
217
								return;
218
							certificate.setText(signerText);
219
							date.setText(dateText);
220
						}
221
					});
222
223
				} catch (IOException e) {
224
					return new Status(IStatus.ERROR,
225
							WorkbenchPlugin.PI_WORKBENCH, e.getMessage(), e);
226
				} catch (GeneralSecurityException e) {
227
					return new Status(IStatus.ERROR,
228
							WorkbenchPlugin.PI_WORKBENCH, e.getMessage(), e);
229
				}
230
				return Status.OK_STATUS;
231
			}
232
		};
233
		signerJob.setSystem(true);
234
		signerJob.belongsTo(signerJob);
235
		signerJob.schedule();
236
237
		Job cleanup = new Job(WorkbenchMessages.BundleSigningTray_Unget_Signing_Service) { 
238
239
			protected IStatus run(IProgressMonitor monitor) {
240
				try {
241
					getJobManager().join(signerJob, monitor);
242
				} catch (OperationCanceledException e) {
243
				} catch (InterruptedException e) {
244
				}
245
				bundleContext.ungetService(factoryRef);
246
				return Status.OK_STATUS;
247
			}
248
		};
249
		cleanup.setSystem(true);
250
		cleanup.schedule();
251
252
	}
253
254
	/**
255
	 * 
256
	 */
257
	private boolean isOpen() {
258
		return certificate != null && !certificate.isDisposed();
259
	}
260
261
	private Properties[] parseCerts(Certificate[] chain) {
262
		List certs = new ArrayList(chain.length);
263
		for (int i = 0; i < chain.length; i++) {
264
			if (!(chain[i] instanceof X509Certificate))
265
				continue;
266
			Map cert = parseCert(((X509Certificate) chain[i]).getSubjectDN().getName());
267
			if (cert != null)
268
				certs.add(cert);
269
		}
270
		return (Properties []) certs.toArray(new Properties[certs.size()]);
271
272
273
	}
274
275
	/**
276
	 * @param certString
277
	 * @return
278
	 */
279
	private Properties parseCert(String certString) {
280
		StringTokenizer toker = new StringTokenizer(certString, ","); //$NON-NLS-1$
281
		Properties cert = new Properties();
282
		while (toker.hasMoreTokens()) {
283
			String pair = toker.nextToken();
284
			int idx = pair.indexOf('=');
285
			if (idx > 0 && idx < pair.length() - 2) {
286
				String key = pair.substring(0, idx).trim();
287
				String value = pair.substring(idx + 1).trim();
288
				if (value.length() > 2) {
289
					if (value.charAt(0) == '\"')
290
						value = value.substring(1);
291
292
					if (value.charAt(value.length() - 1) == '\"')
293
						value = value.substring(0, value.length() - 1);
294
				}
295
				cert.setProperty(key, value);
296
			}
297
		}
298
		return cert;
299
	}
300
301
}
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/ProductInfoDialog.java (-478 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 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.ui.internal.dialogs;
12
13
import java.io.IOException;
14
import java.net.MalformedURLException;
15
import java.net.URL;
16
import java.util.ArrayList;
17
import java.util.StringTokenizer;
18
19
import org.eclipse.core.runtime.IStatus;
20
import org.eclipse.core.runtime.Platform;
21
import org.eclipse.jface.dialogs.TrayDialog;
22
import org.eclipse.jface.resource.JFaceColors;
23
import org.eclipse.osgi.util.NLS;
24
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.custom.StyleRange;
26
import org.eclipse.swt.custom.StyledText;
27
import org.eclipse.swt.events.KeyAdapter;
28
import org.eclipse.swt.events.KeyEvent;
29
import org.eclipse.swt.events.MouseAdapter;
30
import org.eclipse.swt.events.MouseEvent;
31
import org.eclipse.swt.events.MouseMoveListener;
32
import org.eclipse.swt.events.TraverseEvent;
33
import org.eclipse.swt.events.TraverseListener;
34
import org.eclipse.swt.graphics.Color;
35
import org.eclipse.swt.graphics.Cursor;
36
import org.eclipse.swt.graphics.Point;
37
import org.eclipse.swt.widgets.Shell;
38
import org.eclipse.ui.PartInitException;
39
import org.eclipse.ui.PlatformUI;
40
import org.eclipse.ui.browser.IWebBrowser;
41
import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
42
import org.eclipse.ui.internal.WorkbenchMessages;
43
import org.eclipse.ui.internal.WorkbenchPlugin;
44
import org.eclipse.ui.internal.about.AboutItem;
45
import org.eclipse.ui.internal.misc.StatusUtil;
46
import org.eclipse.ui.statushandlers.StatusManager;
47
48
/**
49
 * Abstract superclass of about dialogs 
50
 */
51
52
public abstract class ProductInfoDialog extends TrayDialog {
53
54
    private AboutItem item;
55
56
    private Cursor handCursor;
57
58
    private Cursor busyCursor;
59
60
    private boolean mouseDown = false;
61
62
    private boolean dragEvent = false;
63
64
    /**
65
     * Create an instance of this Dialog
66
     */
67
    public ProductInfoDialog(Shell parentShell) {
68
        super(parentShell);
69
    }
70
71
    /**
72
     * Adds listeners to the given styled text
73
     */
74
    protected void addListeners(StyledText styledText) {
75
        styledText.addMouseListener(new MouseAdapter() {
76
            public void mouseDown(MouseEvent e) {
77
                if (e.button != 1) {
78
                    return;
79
                }
80
                mouseDown = true;
81
            }
82
83
            public void mouseUp(MouseEvent e) {
84
                mouseDown = false;
85
                StyledText text = (StyledText) e.widget;
86
                int offset = text.getCaretOffset();
87
                if (dragEvent) {
88
                    // don't activate a link during a drag/mouse up operation
89
                    dragEvent = false;
90
                    if (item != null && item.isLinkAt(offset)) {
91
                        text.setCursor(handCursor);
92
                    }
93
                } else if (item != null && item.isLinkAt(offset)) {
94
                    text.setCursor(busyCursor);
95
                    openLink(item.getLinkAt(offset));
96
                    StyleRange selectionRange = getCurrentRange(text);
97
                    text.setSelectionRange(selectionRange.start,
98
                            selectionRange.length);
99
                    text.setCursor(null);
100
                }
101
            }
102
        });
103
104
        styledText.addMouseMoveListener(new MouseMoveListener() {
105
            public void mouseMove(MouseEvent e) {
106
                // Do not change cursor on drag events
107
                if (mouseDown) {
108
                    if (!dragEvent) {
109
                        StyledText text = (StyledText) e.widget;
110
                        text.setCursor(null);
111
                    }
112
                    dragEvent = true;
113
                    return;
114
                }
115
                StyledText text = (StyledText) e.widget;
116
                int offset = -1;
117
                try {
118
                    offset = text.getOffsetAtLocation(new Point(e.x, e.y));
119
                } catch (IllegalArgumentException ex) {
120
                    // leave value as -1
121
                }
122
                if (offset == -1) {
123
					text.setCursor(null);
124
				} else if (item != null && item.isLinkAt(offset)) {
125
					text.setCursor(handCursor);
126
				} else {
127
					text.setCursor(null);
128
				}
129
            }
130
        });
131
132
        styledText.addTraverseListener(new TraverseListener() {
133
            public void keyTraversed(TraverseEvent e) {
134
                StyledText text = (StyledText) e.widget;
135
                switch (e.detail) {
136
                case SWT.TRAVERSE_ESCAPE:
137
                    e.doit = true;
138
                    break;
139
                case SWT.TRAVERSE_TAB_NEXT:
140
                    //Previously traverse out in the backward direction?
141
                    Point nextSelection = text.getSelection();
142
                    int charCount = text.getCharCount();
143
                    if ((nextSelection.x == charCount)
144
                            && (nextSelection.y == charCount)) {
145
                        text.setSelection(0);
146
                    }
147
                    StyleRange nextRange = findNextRange(text);
148
                    if (nextRange == null) {
149
                        // Next time in start at beginning, also used by 
150
                        // TRAVERSE_TAB_PREVIOUS to indicate we traversed out
151
                        // in the forward direction
152
                        text.setSelection(0);
153
                        e.doit = true;
154
                    } else {
155
                        text.setSelectionRange(nextRange.start,
156
                                nextRange.length);
157
                        e.doit = true;
158
                        e.detail = SWT.TRAVERSE_NONE;
159
                    }
160
                    break;
161
                case SWT.TRAVERSE_TAB_PREVIOUS:
162
                    //Previously traverse out in the forward direction?
163
                    Point previousSelection = text.getSelection();
164
                    if ((previousSelection.x == 0)
165
                            && (previousSelection.y == 0)) {
166
						text.setSelection(text.getCharCount());
167
					}
168
                    StyleRange previousRange = findPreviousRange(text);
169
                    if (previousRange == null) {
170
                        // Next time in start at the end, also used by 
171
                        // TRAVERSE_TAB_NEXT to indicate we traversed out
172
                        // in the backward direction
173
                        text.setSelection(text.getCharCount());
174
                        e.doit = true;
175
                    } else {
176
                        text.setSelectionRange(previousRange.start,
177
                                previousRange.length);
178
                        e.doit = true;
179
                        e.detail = SWT.TRAVERSE_NONE;
180
                    }
181
                    break;
182
                default:
183
                    break;
184
                }
185
            }
186
        });
187
188
        //Listen for Tab and Space to allow keyboard navigation
189
        styledText.addKeyListener(new KeyAdapter() {
190
            public void keyPressed(KeyEvent event) {
191
                StyledText text = (StyledText) event.widget;
192
                if (event.character == ' ' || event.character == SWT.CR) {
193
                    if (item != null) {
194
                        //Be sure we are in the selection
195
                        int offset = text.getSelection().x + 1;
196
197
                        if (item.isLinkAt(offset)) {
198
                            text.setCursor(busyCursor);
199
                            openLink(item.getLinkAt(offset));
200
                            StyleRange selectionRange = getCurrentRange(text);
201
                            text.setSelectionRange(selectionRange.start,
202
                                    selectionRange.length);
203
                            text.setCursor(null);
204
                        }
205
                    }
206
                    return;
207
                }
208
            }
209
        });
210
    }
211
212
    /**
213
     * Gets the busy cursor.
214
     * @return the busy cursor
215
     */
216
    protected Cursor getBusyCursor() {
217
        return busyCursor;
218
    }
219
220
    /**
221
     * Sets the busy cursor.
222
     * @param busyCursor the busy cursor
223
     */
224
    protected void setBusyCursor(Cursor busyCursor) {
225
        this.busyCursor = busyCursor;
226
    }
227
228
    /**
229
     * Gets the hand cursor.
230
     * @return Returns a hand cursor
231
     */
232
    protected Cursor getHandCursor() {
233
        return handCursor;
234
    }
235
236
    /**
237
     * Sets the hand cursor.
238
     * @param handCursor The hand cursor to set
239
     */
240
    protected void setHandCursor(Cursor handCursor) {
241
        this.handCursor = handCursor;
242
    }
243
244
    /**
245
     * Gets the about item.
246
     * @return the about item
247
     */
248
    protected AboutItem getItem() {
249
        return item;
250
    }
251
252
    /**
253
     * Sets the about item.
254
     * @param item about item
255
     */
256
    protected void setItem(AboutItem item) {
257
        this.item = item;
258
    }
259
260
    /**
261
     * Find the range of the current selection.
262
     */
263
    protected StyleRange getCurrentRange(StyledText text) {
264
        StyleRange[] ranges = text.getStyleRanges();
265
        int currentSelectionEnd = text.getSelection().y;
266
        int currentSelectionStart = text.getSelection().x;
267
268
        for (int i = 0; i < ranges.length; i++) {
269
            if ((currentSelectionStart >= ranges[i].start)
270
                    && (currentSelectionEnd <= (ranges[i].start + ranges[i].length))) {
271
                return ranges[i];
272
            }
273
        }
274
        return null;
275
    }
276
277
    /**
278
     * Find the next range after the current 
279
     * selection.
280
     */
281
    protected StyleRange findNextRange(StyledText text) {
282
        StyleRange[] ranges = text.getStyleRanges();
283
        int currentSelectionEnd = text.getSelection().y;
284
285
        for (int i = 0; i < ranges.length; i++) {
286
            if (ranges[i].start >= currentSelectionEnd) {
287
				return ranges[i];
288
			}
289
        }
290
        return null;
291
    }
292
293
    /**
294
     * Find the previous range before the current selection.
295
     */
296
    protected StyleRange findPreviousRange(StyledText text) {
297
        StyleRange[] ranges = text.getStyleRanges();
298
        int currentSelectionStart = text.getSelection().x;
299
300
        for (int i = ranges.length - 1; i > -1; i--) {
301
            if ((ranges[i].start + ranges[i].length - 1) < currentSelectionStart) {
302
				return ranges[i];
303
			}
304
        }
305
        return null;
306
    }
307
308
    /**
309
     * display an error message
310
     */
311
    private void openWebBrowserError(final String href, final Throwable t) {
312
        String title = WorkbenchMessages.ProductInfoDialog_errorTitle;
313
		String msg = NLS.bind(
314
				WorkbenchMessages.ProductInfoDialog_unableToOpenWebBrowser,
315
				href);
316
		IStatus status = WorkbenchPlugin.getStatus(t);
317
		StatusUtil.handleStatus(status, title + ": " + msg, StatusManager.SHOW, //$NON-NLS-1$
318
				getShell());
319
    }
320
321
    /**
322
     * Open a link
323
     */
324
    protected void openLink(String href) {
325
        // format the href for an html file (file:///<filename.html>
326
        // required for Mac only.
327
        if (href.startsWith("file:")) { //$NON-NLS-1$
328
            href = href.substring(5);
329
            while (href.startsWith("/")) { //$NON-NLS-1$
330
                href = href.substring(1);
331
            }
332
            href = "file:///" + href; //$NON-NLS-1$
333
        }
334
		IWorkbenchBrowserSupport support = PlatformUI.getWorkbench().getBrowserSupport();
335
		try {
336
			IWebBrowser browser = support.getExternalBrowser();
337
			browser.openURL(new URL(urlEncodeForSpaces(href.toCharArray())));
338
		}
339
		catch (MalformedURLException e) {
340
			openWebBrowserError(href, e);
341
		}
342
		catch (PartInitException e) {
343
			openWebBrowserError(href, e);
344
		}
345
    }
346
347
    /**
348
     * This method encodes the url, removes the spaces from the url and replaces
349
     * the same with <code>"%20"</code>. This method is required to fix Bug
350
     * 77840.
351
     * 
352
     * @since 3.0.2
353
     */
354
    private String urlEncodeForSpaces(char[] input) {
355
       StringBuffer retu = new StringBuffer(input.length);
356
       for (int i = 0; i < input.length; i++) {
357
           if (input[i] == ' ') {
358
			retu.append("%20"); //$NON-NLS-1$
359
		} else {
360
			retu.append(input[i]);
361
		}
362
       }
363
       return retu.toString();
364
    }
365
366
    /**
367
     * Open a browser with the argument title on the argument url.  If the url refers to a
368
     * resource within a bundle, then a temp copy of the file will be extracted and opened.
369
     * @see <code>Platform.asLocalUrl</code>
370
     * @param url The target url to be displayed, null will be safely ignored
371
     * @return true if the url was successfully displayed and false otherwise
372
     */
373
    protected boolean openBrowser(URL url) {
374
        if (url != null) {
375
			try {
376
                url = Platform.asLocalURL(url);
377
            } catch (IOException e) {
378
                return false;
379
            }
380
		}
381
        if (url == null) {
382
			return false;
383
		}
384
        openLink(url.toString());
385
        return true;
386
    }
387
388
    /**
389
     * Sets the styled text's bold ranges
390
     */
391
    protected void setBoldRanges(StyledText styledText, int[][] boldRanges) {
392
        for (int i = 0; i < boldRanges.length; i++) {
393
            StyleRange r = new StyleRange(boldRanges[i][0], boldRanges[i][1],
394
                    null, null, SWT.BOLD);
395
            styledText.setStyleRange(r);
396
        }
397
    }
398
399
    /**
400
     * Sets the styled text's link (blue) ranges
401
     */
402
    protected void setLinkRanges(StyledText styledText, int[][] linkRanges) {
403
        Color fg = JFaceColors.getHyperlinkText(styledText.getShell()
404
                .getDisplay());
405
        for (int i = 0; i < linkRanges.length; i++) {
406
            StyleRange r = new StyleRange(linkRanges[i][0], linkRanges[i][1],
407
                    fg, null);
408
            styledText.setStyleRange(r);
409
        }
410
    }
411
412
    /**
413
     * Scan the contents of the about text
414
     */
415
    protected AboutItem scan(String s) {
416
        ArrayList linkRanges = new ArrayList();
417
        ArrayList links = new ArrayList();
418
        
419
        // slightly modified version of jface url detection
420
        // see org.eclipse.jface.text.hyperlink.URLHyperlinkDetector
421
        
422
		int urlSeparatorOffset= s.indexOf("://"); //$NON-NLS-1$
423
		while(urlSeparatorOffset >= 0) {
424
	
425
			boolean startDoubleQuote= false;
426
	
427
			// URL protocol (left to "://")
428
			int urlOffset= urlSeparatorOffset;
429
			char ch;
430
			do {
431
				urlOffset--;
432
				ch= ' ';
433
				if (urlOffset > -1)
434
					ch= s.charAt(urlOffset);
435
				startDoubleQuote= ch == '"';
436
			} while (Character.isUnicodeIdentifierStart(ch));
437
			urlOffset++;
438
			
439
	
440
			// Right to "://"
441
			StringTokenizer tokenizer= new StringTokenizer(s.substring(urlSeparatorOffset + 3), " \t\n\r\f<>", false); //$NON-NLS-1$
442
			if (!tokenizer.hasMoreTokens())
443
				return null;
444
	
445
			int urlLength= tokenizer.nextToken().length() + 3 + urlSeparatorOffset - urlOffset;
446
	
447
			if (startDoubleQuote) {
448
				int endOffset= -1;
449
				int nextDoubleQuote= s.indexOf('"', urlOffset);
450
				int nextWhitespace= s.indexOf(' ', urlOffset);
451
				if (nextDoubleQuote != -1 && nextWhitespace != -1)
452
					endOffset= Math.min(nextDoubleQuote, nextWhitespace);
453
				else if (nextDoubleQuote != -1)
454
					endOffset= nextDoubleQuote;
455
				else if (nextWhitespace != -1)
456
					endOffset= nextWhitespace;
457
				if (endOffset != -1)
458
					urlLength= endOffset - urlOffset;
459
			}
460
			
461
			linkRanges.add(new int[] { urlOffset, urlLength });
462
			links.add(s.substring(urlOffset, urlOffset+urlLength));
463
			
464
			urlSeparatorOffset= s.indexOf("://", urlOffset+urlLength+1); //$NON-NLS-1$
465
		}
466
        return new AboutItem(s, (int[][]) linkRanges.toArray(new int[linkRanges
467
                .size()][2]), (String[]) links
468
                .toArray(new String[links.size()]));
469
    }
470
    
471
    /*
472
     * (non-Javadoc)
473
     * @see org.eclipse.jface.dialogs.Dialog#isResizable()
474
     */
475
    protected boolean isResizable() {
476
    	return true;
477
    }
478
}
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/AboutPluginsDialog.java (-645 / +12 lines)
Lines 12-672 Link Here
12
 *******************************************************************************/
12
 *******************************************************************************/
13
package org.eclipse.ui.internal.dialogs;
13
package org.eclipse.ui.internal.dialogs;
14
14
15
import java.io.IOException;
16
import java.net.URL;
17
import java.util.ArrayList;
18
import java.util.HashMap;
19
import java.util.LinkedList;
20
import java.util.List;
21
import java.util.Map;
22
23
import org.eclipse.core.runtime.IPath;
24
import org.eclipse.core.runtime.IProgressMonitor;
25
import org.eclipse.core.runtime.IStatus;
26
import org.eclipse.core.runtime.Path;
27
import org.eclipse.core.runtime.Platform;
28
import org.eclipse.core.runtime.Status;
29
import org.eclipse.core.runtime.jobs.Job;
30
import org.eclipse.jface.dialogs.DialogTray;
31
import org.eclipse.jface.dialogs.IDialogConstants;
32
import org.eclipse.jface.internal.ConfigureColumnsDialog;
33
import org.eclipse.jface.viewers.ArrayContentProvider;
34
import org.eclipse.jface.viewers.IBaseLabelProvider;
35
import org.eclipse.jface.viewers.ISelectionChangedListener;
36
import org.eclipse.jface.viewers.IStructuredSelection;
37
import org.eclipse.jface.viewers.ITableLabelProvider;
38
import org.eclipse.jface.viewers.LabelProvider;
39
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
40
import org.eclipse.jface.viewers.SelectionChangedEvent;
41
import org.eclipse.jface.viewers.TableViewer;
42
import org.eclipse.jface.viewers.Viewer;
43
import org.eclipse.jface.viewers.ViewerComparator;
44
import org.eclipse.osgi.util.NLS;
15
import org.eclipse.osgi.util.NLS;
45
import org.eclipse.swt.SWT;
46
import org.eclipse.swt.events.SelectionAdapter;
47
import org.eclipse.swt.events.SelectionEvent;
48
import org.eclipse.swt.graphics.Image;
49
import org.eclipse.swt.layout.GridData;
50
import org.eclipse.swt.layout.GridLayout;
51
import org.eclipse.swt.widgets.Button;
52
import org.eclipse.swt.widgets.Composite;
53
import org.eclipse.swt.widgets.Control;
54
import org.eclipse.swt.widgets.Label;
55
import org.eclipse.swt.widgets.Shell;
16
import org.eclipse.swt.widgets.Shell;
56
import org.eclipse.swt.widgets.TableColumn;
57
import org.eclipse.ui.PlatformUI;
58
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
59
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
60
import org.eclipse.ui.internal.WorkbenchImages;
61
import org.eclipse.ui.internal.WorkbenchMessages;
17
import org.eclipse.ui.internal.WorkbenchMessages;
62
import org.eclipse.ui.internal.WorkbenchPlugin;
18
import org.eclipse.ui.internal.about.AboutPluginsPage;
63
import org.eclipse.ui.internal.about.AboutBundleData;
64
import org.eclipse.ui.internal.misc.StatusUtil;
65
import org.eclipse.ui.internal.util.BundleUtility;
66
import org.eclipse.ui.progress.WorkbenchJob;
67
import org.eclipse.ui.statushandlers.StatusManager;
68
import org.osgi.framework.Bundle;
19
import org.osgi.framework.Bundle;
20
import org.eclipse.ui.internal.about.ProductInfoDialog;
69
21
70
/**
22
/**
71
 * Displays information about the product plugins.
23
 * Displays information about the product plugins.
72
 *
24
 * 
73
 * PRIVATE
25
 * PRIVATE this class is internal to the ide
74
 *	this class is internal to the ide
75
 */
26
 */
76
public class AboutPluginsDialog extends ProductInfoDialog {
27
public class AboutPluginsDialog extends ProductInfoDialog {
77
78
	public class BundleTableLabelProvider extends LabelProvider implements ITableLabelProvider  {
79
		
80
		/**
81
		 * Queue containing bundle signing info to be resolved.
82
		 */
83
		private LinkedList resolveQueue = new LinkedList();
84
		
85
		/**
86
         * Queue containing bundle data that's been resolve and needs updating.
87
         */
88
		private List updateQueue = new ArrayList();
89
90
		/*
91
		 * this job will attempt to discover the signing state of a given bundle
92
		 * and then send it along to the update job
93
		 */
94
		private Job resolveJob= new Job(AboutPluginsDialog.class.getName()) {
95
			{
96
				setSystem(true);
97
				setPriority(Job.SHORT);
98
			}
99
			
100
			protected IStatus run(IProgressMonitor monitor) {
101
				while (true) {
102
					Shell dialogShell = getShell();
103
					// the shell has gone down since we were asked to render
104
					if (dialogShell == null || dialogShell.isDisposed())
105
						return Status.OK_STATUS;
106
					AboutBundleData data = null;
107
					synchronized (resolveQueue) {
108
						if (resolveQueue.isEmpty())
109
							return Status.OK_STATUS;
110
						data = (AboutBundleData) resolveQueue.removeFirst();
111
					}
112
					try {
113
						// following is an expensive call
114
						data.isSigned();
115
						
116
						synchronized (updateQueue) {
117
							updateQueue.add(data);
118
						}
119
						// start the update job
120
						updateJob.schedule();
121
					} catch (IllegalStateException e) {
122
						// the bundle we're testing has been unloaded.  Do nothing.
123
					}
124
				}
125
			}
126
		};
127
		
128
		/*
129
		 * this job is responsible for feeding label change events into the
130
		 * viewer as they become available from the resolve job
131
		 */
132
		private Job updateJob= new WorkbenchJob(getShell().getDisplay(), AboutPluginsDialog.class.getName()) {
133
			{
134
				setSystem(true);
135
				setPriority(Job.DECORATE);
136
			}
137
			
138
			/* (non-Javadoc)
139
			 * @see org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.runtime.IProgressMonitor)
140
			 */
141
			public IStatus runInUIThread(IProgressMonitor monitor) {
142
				while (true) {
143
					Shell dialogShell = getShell();
144
					// the shell has gone down since we were asked to render
145
					if (dialogShell == null || dialogShell.isDisposed())
146
						return Status.OK_STATUS;
147
					AboutBundleData[] data = null;
148
					synchronized (updateQueue) {
149
						if (updateQueue.isEmpty())
150
							return Status.OK_STATUS;
151
152
						data = (AboutBundleData[]) updateQueue
153
								.toArray(new AboutBundleData[updateQueue.size()]);
154
						updateQueue.clear();
155
156
					}
157
					fireLabelProviderChanged(new LabelProviderChangedEvent(
158
							BundleTableLabelProvider.this, data));
159
				}
160
			}
161
		};
162
			
163
		/* (non-Javadoc)
164
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
165
		 */
166
		public Image getColumnImage(Object element, int columnIndex) {
167
			if (columnIndex == 0) {
168
				if (element instanceof AboutBundleData) {
169
					final AboutBundleData data = (AboutBundleData) element;
170
					if (data.isSignedDetermined()) {
171
						return WorkbenchImages
172
								.getImage(data.isSigned() ? IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_YES
173
										: IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_NO);
174
					} 
175
					
176
					synchronized (resolveQueue) {
177
						resolveQueue.add(data);
178
					}
179
					resolveJob.schedule();
180
					
181
					return WorkbenchImages
182
							.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_UNKNOWN);
183
				}
184
			}
185
			return null;
186
		}
187
188
		/* (non-Javadoc)
189
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
190
		 */
191
		public String getColumnText(Object element, int columnIndex) {
192
			if (element instanceof AboutBundleData) {
193
				AboutBundleData data = (AboutBundleData) element;
194
				switch (columnIndex) {
195
				case 1:
196
					return data.getProviderName();
197
				case 2:
198
					return data.getName();
199
				case 3:
200
					return data.getVersion();
201
				case 4:
202
					return data.getId();
203
				}
204
			}
205
			return ""; //$NON-NLS-1$
206
		}		
207
	}
208
	
209
    /**
210
     * Table height in dialog units (value 200).
211
     */
212
    private static final int TABLE_HEIGHT = 200;
213
214
	private static final IPath baseNLPath = new Path("$nl$"); //$NON-NLS-1$
215
216
    private static final String PLUGININFO = "about.html"; //$NON-NLS-1$
217
218
    private final static int MORE_ID = IDialogConstants.CLIENT_ID + 1;
219
    private final static int SIGNING_ID = MORE_ID + 1;
220
    private final static int COLUMNS_ID = MORE_ID + 2;
221
    
222
    private static final int PLUGIN_NAME_COLUMN_INDEX = 2;
223
224
    private TableViewer vendorInfo;
225
226
    private Button moreInfo, signingInfo;
227
228
    private String title;
229
230
    private String message;
231
    
232
    private String helpContextId;
233
234
    private String columnTitles[] = {
235
    		WorkbenchMessages.AboutPluginsDialog_signed,
236
            WorkbenchMessages.AboutPluginsDialog_provider,
237
            WorkbenchMessages.AboutPluginsDialog_pluginName,
238
            WorkbenchMessages.AboutPluginsDialog_version, 
239
            WorkbenchMessages.AboutPluginsDialog_pluginId,
240
            
241
    };
242
243
    private String productName;
244
245
    private AboutBundleData[] bundleInfos;
246
    
247
    /**
248
     * Constructor for AboutPluginsDialog.
249
     * 
250
     * @param parentShell the parent shell
251
     * @param productName the product name
252
     */
253
    public AboutPluginsDialog(Shell parentShell, String productName) {
254
        this(parentShell, productName, WorkbenchPlugin.getDefault()
255
                .getBundles(), null, null, IWorkbenchHelpContextIds.ABOUT_PLUGINS_DIALOG);
256
        WorkbenchPlugin.class.getSigners();
257
    }
258
259
    /**
260
     * Constructor for AboutPluginsDialog.
261
     * 
262
     * @param parentShell 
263
     * 			  the parent shell
264
     * @param productName
265
     *            must not be null
266
     * @param bundles
267
     *            must not be null
268
     * @param title 
269
     *            the title
270
     * @param message 
271
     * 			  the message
272
     * @param helpContextId 
273
     *            the help context id
274
     */
275
    public AboutPluginsDialog(Shell parentShell, String productName,
28
    public AboutPluginsDialog(Shell parentShell, String productName,
276
            Bundle[] bundles, String title, String message, String helpContextId) {
29
            Bundle[] bundles, String title, String message, String helpContextId) {
277
        super(parentShell);
30
    	super(parentShell);
278
        this.title = title;
31
    	AboutPluginsPage page = new AboutPluginsPage();
279
        this.message = message;
32
    	page.setHelpContextId(helpContextId);
280
        this.helpContextId = helpContextId;
33
    	page.setBundles(bundles);
281
        this.productName = productName;
34
    	page.setMessage(message);
282
        
35
    	if (title == null && page.getProductName() != null)
283
        // create a data object for each bundle, remove duplicates, and include only resolved bundles (bug 65548)
36
            title = NLS.bind(WorkbenchMessages.AboutPluginsDialog_shellTitle, productName);
284
        Map map = new HashMap();
37
    	initializeDialog(page, title, helpContextId);
285
        for (int i = 0; i < bundles.length; ++i) {
286
            AboutBundleData data = new AboutBundleData(bundles[i]);
287
            if (BundleUtility.isReady(data.getState()) && !map.containsKey(data.getVersionedId())) {
288
				map.put(data.getVersionedId(), data);
289
			}
290
        }
291
        bundleInfos = (AboutBundleData[]) map.values().toArray(
292
                new AboutBundleData[0]);
293
    }
294
295
    /*
296
     * (non-Javadoc) Method declared on Dialog.
297
     */
298
    protected void buttonPressed(int buttonId) {
299
        switch (buttonId) {
300
        case MORE_ID:
301
            handleMoreInfoPressed();
302
            break;
303
        case SIGNING_ID:
304
        	handleSigningInfoPressed();
305
        	break;
306
        case COLUMNS_ID:
307
        	handleColumnsPressed();
308
        	break;
309
        default:
310
            super.buttonPressed(buttonId);
311
            break;
312
        }
313
    }
314
315
    /**
316
	 * 
317
	 */
318
	private void handleColumnsPressed() {
319
		ConfigureColumnsDialog d = new ConfigureColumnsDialog(this, vendorInfo.getTable());
320
		d.open();
321
	}
322
323
	/**
324
	 */
325
	private void handleSigningInfoPressed() {
326
		DialogTray existingTray = getTray();
327
		if (existingTray instanceof BundleSigningTray) {
328
			// hide
329
			getButton(SIGNING_ID).setText(WorkbenchMessages.AboutPluginsDialog_signingInfo_show); 
330
			closeTray();
331
		}
332
		else {
333
			//show
334
			getButton(SIGNING_ID).setText(WorkbenchMessages.AboutPluginsDialog_signingInfo_hide);
335
			if (existingTray != null)
336
				closeTray();
337
			AboutBundleData bundleInfo = (AboutBundleData) ((IStructuredSelection) vendorInfo
338
					.getSelection()).getFirstElement();
339
			BundleSigningTray tray = new BundleSigningTray(this);
340
			tray.setData(bundleInfo);
341
			openTray(tray);
342
		}
343
		
344
	}
345
346
	/*
347
     * (non-Javadoc) Method declared on Window.
348
     */
349
    protected void configureShell(Shell newShell) {
350
        super.configureShell(newShell);
351
        
352
        //signImage = new Image( this.getParentShell().getDisplay(), AboutPluginsDialog.class.getResourceAsStream("Signed.gif")); //$NON-NLS-1$
353
        
354
        if (title == null && productName != null) {
355
			title = NLS.bind(WorkbenchMessages.AboutPluginsDialog_shellTitle, productName);
356
		}
357
358
        if (title != null) {
359
			newShell.setText(title);
360
		}
361
362
        PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
363
				helpContextId);
364
    }
365
    
366
    /**
367
     * Add buttons to the dialog's button bar.
368
     * 
369
     * Subclasses should override.
370
     * 
371
     * @param parent
372
     *            the button bar composite
373
     */
374
    protected void createButtonsForButtonBar(Composite parent) {
375
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
376
377
        moreInfo = createButton(parent, MORE_ID, WorkbenchMessages.AboutPluginsDialog_moreInfo, false); 
378
        moreInfo.setEnabled(false);
379
        
380
        signingInfo = createButton(parent, SIGNING_ID, WorkbenchMessages.AboutPluginsDialog_signingInfo_show, false);
381
        signingInfo.setEnabled(false);
382
383
        createButton(parent, COLUMNS_ID, WorkbenchMessages.AboutPluginsDialog_columns, false);
384
385
        Label l = new Label(parent, SWT.NONE);
386
        l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
387
        GridLayout layout = (GridLayout) parent.getLayout();
388
        layout.numColumns++;
389
        layout.makeColumnsEqualWidth = false;
390
391
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL,
392
                true);
393
    }
394
395
    /**
396
     * Create the contents of the dialog (above the button bar).
397
     * 
398
     * Subclasses should overide.
399
     * 
400
     * @param parent
401
     *            the parent composite to contain the dialog area
402
     * @return the dialog area control
403
     */
404
    protected Control createDialogArea(Composite parent) {
405
        Composite outer = (Composite) super.createDialogArea(parent);
406
407
        if (message != null) {
408
            Label label = new Label(outer, SWT.NONE);
409
            label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
410
            label.setFont(parent.getFont());
411
            label.setText(message);
412
        }
413
414
        createTable(outer);
415
416
        return outer;
417
    }
418
419
    /**
420
     * Create the table part of the dialog.
421
     * 
422
     * @param parent
423
     *            the parent composite to contain the dialog area
424
     */
425
    protected void createTable(Composite parent) {
426
        vendorInfo = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE
427
                | SWT.FULL_SELECTION | SWT.BORDER);
428
        vendorInfo.setUseHashlookup(true);
429
        vendorInfo.getTable().setHeaderVisible(true);
430
        vendorInfo.getTable().setLinesVisible(true);
431
        vendorInfo.getTable().setFont(parent.getFont());
432
        vendorInfo.addSelectionChangedListener(new ISelectionChangedListener() {
433
434
			public void selectionChanged(SelectionChangedEvent event) {
435
				// enable if there is an item selected and that
436
                // item has additional info
437
				IStructuredSelection selection = (IStructuredSelection) event.getSelection();
438
				if (selection.getFirstElement() instanceof AboutBundleData) {
439
					AboutBundleData selected = (AboutBundleData) selection.getFirstElement(); 
440
					moreInfo.setEnabled(selectionHasInfo(selected));
441
					signingInfo.setEnabled(true);
442
					if (getTray() instanceof BundleSigningTray) {
443
						((BundleSigningTray)getTray()).setData(selected);
444
					}
445
				}
446
				else {
447
					moreInfo.setEnabled(false);
448
					signingInfo.setEnabled(false);
449
				}
450
			}});
451
        
452
        final TableComparator comparator = new TableComparator();
453
        vendorInfo.setComparator(comparator);
454
        int[] columnWidths = {
455
        		convertHorizontalDLUsToPixels(30), //signature
456
        		convertHorizontalDLUsToPixels(120),
457
                convertHorizontalDLUsToPixels(120),
458
                convertHorizontalDLUsToPixels(70),
459
                convertHorizontalDLUsToPixels(130),
460
                };
461
462
        
463
        // create table headers
464
        for (int i = 0; i < columnTitles.length; i++) {
465
            TableColumn column = new TableColumn(vendorInfo.getTable(), SWT.NULL);
466
            if (i == PLUGIN_NAME_COLUMN_INDEX) { // prime initial sorting
467
            	updateTableSorting(i);
468
            }	
469
            column.setWidth(columnWidths[i]);
470
            column.setText(columnTitles[i]);
471
            final int columnIndex = i;
472
            column.addSelectionListener(new SelectionAdapter() {
473
                public void widgetSelected(SelectionEvent e) {
474
                    updateTableSorting(columnIndex);
475
                }
476
            });
477
        }
478
                
479
        vendorInfo.setContentProvider(new ArrayContentProvider());        
480
        vendorInfo.setLabelProvider(new BundleTableLabelProvider());
481
       
482
        GridData gridData = new GridData(GridData.FILL, GridData.FILL, true,
483
                true);
484
        gridData.heightHint = convertVerticalDLUsToPixels(TABLE_HEIGHT);
485
        vendorInfo.getTable().setLayoutData(gridData);
486
        
487
        vendorInfo.setInput(bundleInfos);
488
    }
489
490
	/**
491
	 * Update the sort information on both the comparator and the table.
492
	 * 
493
	 * @param columnIndex
494
	 *            the index to sort by
495
	 * @since 3.4
496
	 */
497
	private void updateTableSorting(final int columnIndex) {
498
		TableComparator comparator = (TableComparator) vendorInfo
499
				.getComparator();
500
		// toggle direction if it's the same column
501
		if (columnIndex == comparator.getSortColumn()) {
502
			comparator.setAscending(!comparator.isAscending());
503
		}
504
		comparator.setSortColumn(columnIndex);
505
		vendorInfo.getTable().setSortColumn(
506
				vendorInfo.getTable().getColumn(columnIndex));
507
		vendorInfo.getTable().setSortDirection(
508
				comparator.isAscending() ? SWT.UP : SWT.DOWN);
509
		vendorInfo.refresh(false);
510
	}
511
	
512
	/**
513
     * Check if the currently selected plugin has additional information to
514
     * show.
515
     * @param bundleInfo 
516
     * 
517
     * @return true if the selected plugin has additional info available to
518
     *         display
519
     */
520
    private boolean selectionHasInfo(AboutBundleData bundleInfo) {
521
        
522
        URL infoURL = getMoreInfoURL(bundleInfo, false);
523
524
        // only report ini problems if the -debug command line argument is used
525
        if (infoURL == null && WorkbenchPlugin.DEBUG) {
526
        	WorkbenchPlugin.log("Problem reading plugin info for: " //$NON-NLS-1$
527
					+ bundleInfo.getName());
528
		}
529
530
        return infoURL != null;
531
    }
532
533
    /** 
534
     * The More Info button was pressed.  Open a browser showing the license information
535
     * for the selected bundle or an error dialog if the browser cannot be opened.
536
     */
537
    protected void handleMoreInfoPressed() {
538
        if (vendorInfo == null) {
539
			return;
540
		}
541
        
542
        if (vendorInfo.getSelection().isEmpty())
543
        	return;
544
        
545
        AboutBundleData bundleInfo = (AboutBundleData) ((IStructuredSelection) vendorInfo
546
				.getSelection()).getFirstElement();
547
        
548
        if (!openBrowser(getMoreInfoURL(bundleInfo, true))) {
549
			String message = NLS.bind(
550
					WorkbenchMessages.AboutPluginsDialog_unableToOpenFile,
551
					PLUGININFO, bundleInfo.getId());
552
			StatusUtil.handleStatus(
553
					WorkbenchMessages.AboutPluginsDialog_errorTitle
554
							+ ": " + message, StatusManager.SHOW, getShell()); //$NON-NLS-1$
555
		}
556
    }
557
558
    /**
559
     * Return an url to the plugin's about.html file (what is shown when "More info" is
560
     * pressed) or null if no such file exists.  The method does nl lookup to allow for
561
     * i18n.
562
     * 
563
     * @param bundleInfo the bundle info
564
     * @param makeLocal whether to make the about content local
565
     * @return the url or <code>null</code>
566
     */
567
    private URL getMoreInfoURL(AboutBundleData bundleInfo, boolean makeLocal) {
568
        Bundle bundle = Platform.getBundle(bundleInfo.getId());
569
        if (bundle == null) {
570
			return null;
571
		}
572
573
        URL aboutUrl = Platform.find(bundle, baseNLPath.append(PLUGININFO), null);
574
        if (!makeLocal) {
575
            return aboutUrl;
576
        }
577
		if (aboutUrl != null) {
578
		    try {
579
				URL result = Platform.asLocalURL(aboutUrl);
580
				try {
581
				    // Make local all content in the "about" directory.
582
				    // This is needed to handle jar'ed plug-ins.
583
				    // See Bug 88240 [About] About dialog needs to extract subdirs.
584
					URL about = new URL(aboutUrl, "about_files"); //$NON-NLS-1$
585
					if (about != null) {
586
						Platform.asLocalURL(about);
587
					}
588
				} catch (IOException e) {
589
					// skip the about dir if its not found or there are other problems.
590
				}
591
				return result;
592
		    } catch(IOException e) {
593
		        // do nothing
594
		    }
595
        }
596
		return null;
597
    }
598
}
599
600
601
class TableComparator extends ViewerComparator {
602
603
	private int sortColumn = 0;
604
	private boolean ascending = true;
605
	
606
	/* (non-Javadoc)
607
	 * @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
608
	 */
609
	public int compare(Viewer viewer, Object e1, Object e2) {
610
		if (sortColumn == 0 && e1 instanceof AboutBundleData && e2 instanceof AboutBundleData) {
611
			AboutBundleData d1= (AboutBundleData) e1;
612
			AboutBundleData d2= (AboutBundleData) e2;
613
			int diff= getSignedSortValue(d1) - getSignedSortValue(d2);
614
			return ascending ? diff : -diff;
615
		}
616
		if (viewer instanceof TableViewer) {
617
			TableViewer tableViewer = (TableViewer) viewer;
618
			IBaseLabelProvider baseLabel = tableViewer.getLabelProvider();
619
			if (baseLabel instanceof ITableLabelProvider) {
620
				ITableLabelProvider tableProvider = (ITableLabelProvider) baseLabel;
621
				String e1p = tableProvider.getColumnText(e1, sortColumn);
622
				String e2p = tableProvider.getColumnText(e2, sortColumn);
623
				int result = getComparator().compare(e1p, e2p);
624
				return ascending ?  result : (-1) * result;
625
			}
626
		}
627
		
628
		return super.compare(viewer, e1, e2);
629
	}
630
631
	/**
632
	 * @param data
633
	 * @return a sort value depending on the signed state
634
	 */
635
	private int getSignedSortValue(AboutBundleData data) {
636
		if (! data.isSignedDetermined()) {
637
			return 0;
638
		} else if (data.isSigned()) {
639
			return 1;
640
		} else {
641
			return -1;
642
		}
643
	}
644
	
645
	/**
646
	 * @return Returns the sortColumn.
647
	 */
648
	public int getSortColumn() {
649
		return sortColumn;
650
	}
651
652
	/**
653
	 * @param sortColumn The sortColumn to set.
654
	 */
655
	public void setSortColumn(int sortColumn) {
656
		this.sortColumn = sortColumn;
657
	}
658
659
	/**
660
	 * @return Returns the ascending.
661
	 */
662
	public boolean isAscending() {
663
		return ascending;
664
	}
665
666
	/**
667
	 * @param ascending The ascending to set.
668
	 */
669
	public void setAscending(boolean ascending) {
670
		this.ascending = ascending;
671
	}
38
	}
672
}
39
}
(-)Eclipse UI/org/eclipse/ui/internal/dialogs/AboutSystemDialog.java (-229 lines)
Removed Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2003, 2008 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.ui.internal.dialogs;
12
13
import java.io.File;
14
import java.io.FileNotFoundException;
15
import java.io.FileReader;
16
import java.io.FileWriter;
17
import java.io.IOException;
18
19
import org.eclipse.core.runtime.IPath;
20
import org.eclipse.core.runtime.Platform;
21
import org.eclipse.jface.dialogs.IDialogConstants;
22
import org.eclipse.jface.dialogs.MessageDialog;
23
import org.eclipse.jface.resource.JFaceResources;
24
import org.eclipse.osgi.util.NLS;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.dnd.Clipboard;
27
import org.eclipse.swt.dnd.TextTransfer;
28
import org.eclipse.swt.dnd.Transfer;
29
import org.eclipse.swt.layout.GridData;
30
import org.eclipse.swt.layout.GridLayout;
31
import org.eclipse.swt.widgets.Button;
32
import org.eclipse.swt.widgets.Composite;
33
import org.eclipse.swt.widgets.Control;
34
import org.eclipse.swt.widgets.Label;
35
import org.eclipse.swt.widgets.Shell;
36
import org.eclipse.swt.widgets.Text;
37
import org.eclipse.ui.PlatformUI;
38
import org.eclipse.ui.internal.ConfigurationInfo;
39
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
40
import org.eclipse.ui.internal.WorkbenchMessages;
41
import org.eclipse.ui.internal.WorkbenchPlugin;
42
43
44
/**
45
 * Displays system information about the eclipse application.  The content of
46
 * what is displayed is selectable through the
47
 * <code>org.eclipse.ui.systemSummaryExtensions</code> extension point.
48
 */
49
public final class AboutSystemDialog extends ProductInfoDialog {
50
51
    private Text text;
52
    
53
    private final static int BROWSE_ERROR_LOG_BUTTON = IDialogConstants.CLIENT_ID;
54
55
    private final static int COPY_TO_CLIPBOARD_BUTTON = IDialogConstants.CLIENT_ID + 1;
56
    
57
    private final static String ERROR_LOG_COPY_FILENAME = "log"; //$NON-NLS-1$
58
59
    /**
60
     * Create an instance of this dialog.
61
     * 
62
     * @param parentShell the parent shell
63
     */
64
    public AboutSystemDialog(Shell parentShell) {
65
        super(parentShell);
66
    }
67
68
    /* (non-Javadoc)
69
     * Method declared on Window.
70
     */
71
    protected void configureShell(Shell newShell) {
72
        super.configureShell(newShell);
73
        newShell.setText(WorkbenchMessages.SystemSummary_title);
74
        PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
75
				IWorkbenchHelpContextIds.SYSTEM_SUMMARY_DIALOG);
76
    }
77
78
    /* (non-Javadoc)
79
     * Method declared on Dialog.
80
     */
81
    protected void createButtonsForButtonBar(Composite parent) {
82
        parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
83
84
        Button button = createButton(parent, BROWSE_ERROR_LOG_BUTTON, WorkbenchMessages.AboutSystemDialog_browseErrorLogName, false);
85
        String filename = Platform.getLogFileLocation().toOSString();
86
        button.setEnabled(new File(filename).exists());
87
88
        createButton(parent, COPY_TO_CLIPBOARD_BUTTON, WorkbenchMessages.AboutSystemDialog_copyToClipboardName, false);
89
90
        new Label(parent, SWT.NONE).setLayoutData(new GridData(
91
                GridData.FILL_HORIZONTAL));
92
        GridLayout layout = (GridLayout) parent.getLayout();
93
        layout.numColumns++;
94
        layout.makeColumnsEqualWidth = false;
95
96
        createButton(parent, IDialogConstants.CLOSE_ID,
97
                IDialogConstants.CLOSE_LABEL, true);
98
    }
99
100
    /* (non-Javadoc)
101
     * Method declared on Dialog.
102
     */
103
    protected Control createDialogArea(Composite parent) {
104
        Composite outer = (Composite) super.createDialogArea(parent);
105
106
        text = new Text(outer, SWT.MULTI | SWT.BORDER | SWT.READ_ONLY
107
                | SWT.V_SCROLL | SWT.NO_FOCUS | SWT.H_SCROLL);
108
        text.setBackground(parent.getDisplay().getSystemColor(
109
                SWT.COLOR_LIST_BACKGROUND));
110
        GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
111
                | GridData.VERTICAL_ALIGN_FILL);
112
        gridData.grabExcessVerticalSpace = true;
113
        gridData.grabExcessHorizontalSpace = true;
114
        gridData.heightHint = convertVerticalDLUsToPixels(300);
115
        gridData.widthHint = convertHorizontalDLUsToPixels(400);
116
        text.setLayoutData(gridData);
117
        text.setText(ConfigurationInfo.getSystemSummary());
118
        text.setFont(JFaceResources.getTextFont());
119
        return outer;
120
    }
121
122
    /* (non-Javadoc)
123
     * @see org.eclipse.jface.dialogs.Dialog#buttonPressed(int)
124
     */
125
    protected void buttonPressed(int buttonId) {
126
        switch (buttonId) {
127
        case IDialogConstants.CLOSE_ID:
128
            close();
129
            break;
130
        case BROWSE_ERROR_LOG_BUTTON:
131
            openErrorLogBrowser();
132
            break;
133
        case COPY_TO_CLIPBOARD_BUTTON:
134
            runCopyToClipboard();
135
            break;
136
        }
137
        super.buttonPressed(buttonId);
138
    }
139
140
    private void openErrorLogBrowser() {
141
        String filename = Platform.getLogFileLocation().toOSString();
142
143
        File log = new File(filename);
144
        if (log.exists()) {
145
        	// Make a copy of the file with a temporary name.
146
        	// Working around an issue with windows file associations/browser malfunction
147
        	// whereby the browser doesn't open on ".log" and we aren't returned an error.
148
        	// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97783
149
        	File logCopy = makeDisplayCopy(log);
150
        	if (logCopy != null) {
151
        		openLink("file:///" + logCopy.getAbsolutePath()); //$NON-NLS-1$
152
        		return;
153
        	}
154
        	// Couldn't make copy, try to open the original log.
155
        	// We try the original in this case rather than putting up an error,
156
        	// because the copy could fail due to an I/O or out of space problem.
157
        	// In that case we may still be able to show the original log,
158
        	// depending on the platform.  The risk is that users with configurations
159
        	// that have bug #97783 will still get nothing (vs. an error) but we'd rather
160
        	// try again than put up an error dialog on platforms where the ability to
161
        	// view the original log works just fine.
162
        	openLink("file:///" + filename); //$NON-NLS-1$
163
        	return;
164
        }
165
        MessageDialog.openInformation(getShell(), WorkbenchMessages.AboutSystemDialog_noLogTitle, 
166
                NLS.bind(WorkbenchMessages.AboutSystemDialog_noLogMessage,  filename ));
167
    }
168
    
169
    /**
170
     * Returns a copy of the given file to be used for display in
171
     * a browser.
172
     * 
173
     * @return the file, or <code>null</code>
174
     */
175
    private File makeDisplayCopy(File file) {
176
        IPath path = WorkbenchPlugin.getDefault().getDataLocation();
177
        if(path == null) {
178
			return null;
179
		}
180
        path = path.append(ERROR_LOG_COPY_FILENAME);
181
        File copy = path.toFile();
182
        FileReader in = null;
183
        FileWriter out = null;
184
        try {
185
			in = new FileReader(file);
186
			// don't append data, overwrite what was there
187
			out = new FileWriter(copy);
188
			char buffer[] = new char[4096];
189
		    int count;
190
		    while ((count = in.read(buffer, 0, buffer.length)) > 0) {
191
		        out.write(buffer, 0, count);
192
		    }
193
		} catch (FileNotFoundException e) {
194
			return null;
195
		} catch (IOException e) {
196
			return null;
197
		} finally {
198
			try {
199
				if (in != null) {
200
					in.close();
201
				}
202
				if (out != null) {
203
					out.close();
204
				}
205
			} catch (IOException e) {
206
				return null;
207
			}
208
		}
209
		return copy;
210
211
    }
212
213
    private void runCopyToClipboard() {
214
        if (text == null) {
215
			return;
216
		}
217
218
        Clipboard clipboard = null;
219
        try {
220
            clipboard = new Clipboard(getShell().getDisplay());
221
            clipboard.setContents(new Object[] { text.getText() },
222
                    new Transfer[] { TextTransfer.getInstance() });
223
        } finally {
224
            if (clipboard != null) {
225
				clipboard.dispose();
226
			}
227
        }
228
    }
229
}
(-)Eclipse UI/org/eclipse/ui/internal/about/InstallationDialog.java (-180 / +163 lines)
Lines 14-35 Link Here
14
import org.eclipse.core.runtime.CoreException;
14
import org.eclipse.core.runtime.CoreException;
15
import org.eclipse.core.runtime.IConfigurationElement;
15
import org.eclipse.core.runtime.IConfigurationElement;
16
import org.eclipse.core.runtime.IExtensionPoint;
16
import org.eclipse.core.runtime.IExtensionPoint;
17
import org.eclipse.core.runtime.IProduct;
17
import org.eclipse.core.runtime.Platform;
18
import org.eclipse.core.runtime.Platform;
18
import org.eclipse.jface.action.ContributionManager;
19
import org.eclipse.jface.action.ContributionManager;
19
import org.eclipse.jface.action.IContributionItem;
20
import org.eclipse.jface.action.IContributionItem;
20
import org.eclipse.jface.action.ToolBarManager;
21
import org.eclipse.jface.dialogs.Dialog;
21
import org.eclipse.jface.dialogs.Dialog;
22
import org.eclipse.jface.dialogs.IDialogConstants;
22
import org.eclipse.jface.dialogs.IDialogConstants;
23
import org.eclipse.jface.resource.ColorRegistry;
23
import org.eclipse.jface.dialogs.IDialogSettings;
24
import org.eclipse.jface.resource.JFaceResources;
24
import org.eclipse.osgi.util.NLS;
25
import org.eclipse.swt.SWT;
25
import org.eclipse.swt.SWT;
26
import org.eclipse.swt.custom.CTabFolder;
27
import org.eclipse.swt.custom.CTabItem;
28
import org.eclipse.swt.events.DisposeEvent;
26
import org.eclipse.swt.events.DisposeEvent;
29
import org.eclipse.swt.events.DisposeListener;
27
import org.eclipse.swt.events.DisposeListener;
30
import org.eclipse.swt.events.SelectionAdapter;
28
import org.eclipse.swt.events.SelectionAdapter;
31
import org.eclipse.swt.events.SelectionEvent;
29
import org.eclipse.swt.events.SelectionEvent;
32
import org.eclipse.swt.graphics.Color;
33
import org.eclipse.swt.graphics.FontMetrics;
30
import org.eclipse.swt.graphics.FontMetrics;
34
import org.eclipse.swt.graphics.GC;
31
import org.eclipse.swt.graphics.GC;
35
import org.eclipse.swt.graphics.Point;
32
import org.eclipse.swt.graphics.Point;
Lines 39-50 Link Here
39
import org.eclipse.swt.widgets.Control;
36
import org.eclipse.swt.widgets.Control;
40
import org.eclipse.swt.widgets.Label;
37
import org.eclipse.swt.widgets.Label;
41
import org.eclipse.swt.widgets.Shell;
38
import org.eclipse.swt.widgets.Shell;
42
import org.eclipse.swt.widgets.ToolBar;
39
import org.eclipse.swt.widgets.TabFolder;
43
import org.eclipse.ui.IWorkbenchPreferenceConstants;
40
import org.eclipse.swt.widgets.TabItem;
44
import org.eclipse.ui.PlatformUI;
45
import org.eclipse.ui.about.IInstallationPageContainer;
41
import org.eclipse.ui.about.IInstallationPageContainer;
46
import org.eclipse.ui.about.InstallationPage;
42
import org.eclipse.ui.about.InstallationPage;
47
import org.eclipse.ui.internal.IWorkbenchThemeConstants;
43
import org.eclipse.ui.internal.ConfigurationInfo;
44
import org.eclipse.ui.internal.WorkbenchMessages;
45
import org.eclipse.ui.internal.WorkbenchPlugin;
48
import org.eclipse.ui.internal.menus.InternalMenuService;
46
import org.eclipse.ui.internal.menus.InternalMenuService;
49
import org.eclipse.ui.internal.menus.SlaveMenuService;
47
import org.eclipse.ui.internal.menus.SlaveMenuService;
50
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
48
import org.eclipse.ui.internal.registry.IWorkbenchRegistryConstants;
Lines 56-73 Link Here
56
 * 
54
 * 
57
 */
55
 */
58
public class InstallationDialog extends Dialog {
56
public class InstallationDialog extends Dialog {
59
	private static final String ID = "ID"; //$NON-NLS-1$
57
	class ButtonManager extends ContributionManager {
60
58
61
	private CTabFolder folder;
59
		private Composite composite;
60
61
		public ButtonManager(Composite composite) {
62
			this.composite = composite;
63
		}
64
65
		public Composite getParent() {
66
			return composite;
67
		}
68
69
		/*
70
		 * (non-Javadoc)
71
		 * 
72
		 * @see org.eclipse.jface.action.IContributionManager#update(boolean)
73
		 */
74
		public void update(boolean force) {
75
			if (composite == null || composite.isDisposed())
76
				return;
77
			GC metricsGC = new GC(composite);
78
			FontMetrics metrics = metricsGC.getFontMetrics();
79
			metricsGC.dispose();
80
			IContributionItem[] items = getItems();
81
			Control[] children = composite.getChildren();
82
83
			int visibleChildren = 0;
84
			for (int i = 0; i < children.length; i++) {
85
				Control control = children[i];
86
				control.dispose();
87
			}
88
89
			for (int i = 0; i < items.length; i++) {
90
				IContributionItem item = items[i];
91
				if (item.isVisible()) {
92
					item.fill(composite);
93
					children = composite.getChildren();
94
					Control itemControl = children[children.length - 1];
95
					setButtonLayoutData(metrics, itemControl);
96
					visibleChildren++;
97
				}
98
			}
99
			GridLayout compositeLayout = (GridLayout) composite.getLayout();
100
			compositeLayout.numColumns = visibleChildren;
101
			composite.layout(true);
102
		}
103
104
		protected void setButtonLayoutData(FontMetrics metrics, Control button) {
105
			GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
106
			int widthHint = Dialog.convertHorizontalDLUsToPixels(metrics,
107
					IDialogConstants.BUTTON_WIDTH);
108
			Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
109
			data.widthHint = Math.max(widthHint, minSize.x);
110
			button.setLayoutData(data);
111
		}
112
113
	}
114
115
	protected static final String ID = "ID"; //$NON-NLS-1$
116
	private static final String DIALOG_SETTINGS_SECTION = "InstallationDialogSettings"; //$NON-NLS-1$
117
118
	private TabFolder folder;
62
	private IServiceLocator serviceLocator;
119
	private IServiceLocator serviceLocator;
63
	private ToolBarManager toolbarManager;
64
	private ButtonManager buttonManager;
120
	private ButtonManager buttonManager;
65
	private IMenuService menuService = null;
121
	private IMenuService menuService = null;
66
122
67
	/**
123
	/**
68
	 * @param parentShell
124
	 * @param parentShell
125
	 * @param locator
69
	 */
126
	 */
70
	protected InstallationDialog(Shell parentShell, IServiceLocator locator) {
127
	public InstallationDialog(Shell parentShell, IServiceLocator locator) {
71
		super(parentShell);
128
		super(parentShell);
72
		this.serviceLocator = locator;
129
		this.serviceLocator = locator;
73
		menuService = new SlaveMenuService((InternalMenuService) serviceLocator
130
		menuService = new SlaveMenuService((InternalMenuService) serviceLocator
Lines 84-101 Link Here
84
	 */
141
	 */
85
	protected void configureShell(Shell newShell) {
142
	protected void configureShell(Shell newShell) {
86
		super.configureShell(newShell);
143
		super.configureShell(newShell);
87
		// TODO
144
		String productName = ""; //$NON-NLS-1$
88
		// This should use the title of the about dialog, this
145
		IProduct product = Platform.getProduct();
89
		// is a temporary hack so that p2 can launch the dialog
146
		if (product != null && product.getName() != null)
90
		// with a proper title until this is actually hooked into
147
			productName = product.getName();
91
		// the about dialog.
148
		newShell.setText(NLS.bind(
92
		newShell.setText("Installation Information"); //$NON-NLS-1$
149
				WorkbenchMessages.InstallationDialog_ShellTitle, productName));
93
		newShell.setSize(600, 768);
94
95
	}
150
	}
96
	
151
97
	/*
152
	/*
98
	 * (non-Javadoc)
153
	 * (non-Javadoc)
154
	 * 
99
	 * @see org.eclipse.jface.dialogs.Dialog#isResizable()
155
	 * @see org.eclipse.jface.dialogs.Dialog#isResizable()
100
	 */
156
	 */
101
	protected boolean isResizable() {
157
	protected boolean isResizable() {
Lines 112-214 Link Here
112
	protected Control createDialogArea(Composite parent) {
168
	protected Control createDialogArea(Composite parent) {
113
		Composite composite = (Composite) super.createDialogArea(parent);
169
		Composite composite = (Composite) super.createDialogArea(parent);
114
170
115
		createToolbar(composite);
171
		folder = new TabFolder(composite, SWT.NONE);
116
117
		folder = new CTabFolder(composite, SWT.MULTI | SWT.BORDER);
118
		configureFolder();
172
		configureFolder();
173
		createFolderItems(folder);
119
		GridData folderData = new GridData(SWT.FILL, SWT.FILL, true, true);
174
		GridData folderData = new GridData(SWT.FILL, SWT.FILL, true, true);
120
		folderData.widthHint = SWT.DEFAULT;
175
		folderData.widthHint = SWT.DEFAULT;
121
		folderData.heightHint = SWT.DEFAULT;
176
		folderData.heightHint = SWT.DEFAULT;
122
		folder.setLayoutData(folderData);
177
		folder.setLayoutData(folderData);
178
		folder.addSelectionListener(createFolderSelectionListener());
179
		folder.addDisposeListener(new DisposeListener() {
180
			public void widgetDisposed(DisposeEvent e) {
181
				releaseContributions();
182
			}
183
		});
184
		return composite;
185
	}
123
186
124
		IConfigurationElement[] elements = loadElements();
187
	protected void createFolderItems(TabFolder folder) {
188
		IConfigurationElement[] elements = ConfigurationInfo
189
				.getSortedExtensions(loadElements());
125
		for (int i = 0; i < elements.length; i++) {
190
		for (int i = 0; i < elements.length; i++) {
126
			IConfigurationElement element = elements[i];
191
			IConfigurationElement element = elements[i];
127
			CTabItem item = new CTabItem(folder, SWT.NONE);
192
			TabItem item = new TabItem(folder, SWT.NONE);
128
			item.setText(element
193
			item.setText(element
129
					.getAttribute(IWorkbenchRegistryConstants.ATT_NAME));
194
					.getAttribute(IWorkbenchRegistryConstants.ATT_NAME));
130
			item.setData(element);
195
			item.setData(element);
131
			Composite control = new Composite(folder, SWT.BORDER);
196
			Composite control = new Composite(folder, SWT.BORDER);
132
			control.setLayout(new GridLayout());
197
			control.setLayout(new GridLayout());
133
			item.setControl(control);
198
			item.setControl(control);
134
135
		}
199
		}
136
		folder.addSelectionListener(createFolderSelectionListener());
200
	}
137
		return composite;
201
	
202
	protected Control createContents(Composite parent) {
203
		Control control = super.createContents(parent);
204
		if (folder.getItemCount() > 0)
205
			tabSelected(folder.getItem(0));
206
		return control;
138
	}
207
	}
139
208
140
	private SelectionAdapter createFolderSelectionListener() {
209
	private SelectionAdapter createFolderSelectionListener() {
141
		return new SelectionAdapter() {
210
		return new SelectionAdapter() {
142
211
143
			public void widgetSelected(SelectionEvent e) {
212
			public void widgetSelected(SelectionEvent e) {
144
				final CTabItem item = (CTabItem) e.item;
213
				tabSelected((TabItem) e.item);
145
				String id = null;
146
				if (item.getData() instanceof IConfigurationElement) {
147
					final IConfigurationElement element = (IConfigurationElement) item
148
							.getData();
149
150
					id = element
151
							.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
152
					item.setData(ID, id);
153
154
					Composite pageComposite = (Composite) item.getControl();
155
					try {
156
						final InstallationPage page = (InstallationPage) element
157
								.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
158
						page.createControl(pageComposite);
159
						page.init(createDialogServiceLocator(item));
160
						item.setData(page);
161
						item.addDisposeListener(new DisposeListener() {
162
163
							public void widgetDisposed(DisposeEvent e) {
164
								page.dispose();
165
							}
166
						});
167
						pageComposite.layout(true, true);
168
169
					} catch (CoreException e1) {
170
						Label label = new Label(pageComposite, SWT.NONE);
171
						label.setText(e1.getMessage());
172
						item.setData(null);
173
					}
174
175
					
176
				} else {
177
					id = (String) item.getData(ID);
178
				}
179
				
180
				menuService.releaseContributions(toolbarManager);
181
				menuService.populateContributionManager(toolbarManager,
182
						InstallationDialog.this.getToolbarURI(id));
183
				toolbarManager.update(true);
184
185
				menuService.releaseContributions(buttonManager);
186
				menuService.populateContributionManager(buttonManager,
187
						InstallationDialog.this.getButtonBarURI(id));
188
				buttonManager.update(true);
189
				createButton(buttonManager.getParent(), IDialogConstants.OK_ID,
190
						IDialogConstants.OK_LABEL, true);
191
				// Layout the button manager again now that the OK button is there.
192
				// Must do this before we layout the button bar or else the button
193
				// manager will not know about the OK button
194
				buttonManager.getParent().layout();
195
				// Now we layout the button bar itself so it will accommodate the
196
				// button manager's buttons
197
				getButtonBar().getParent().layout();
198
			}
214
			}
199
		};
215
		};
200
	}
216
	}
201
217
202
	private void createToolbar(Composite composite) {
218
	/*
203
		toolbarManager = new ToolBarManager(SWT.NONE);
219
	 * Must be called after contributions and button manager are created.
204
		toolbarManager.createControl(composite);
220
	 */
205
		ToolBar toolbar = toolbarManager.getControl();
221
	private void tabSelected(TabItem item) {
206
		{
222
		String id = null;
207
			GridData toolbarData = new GridData(SWT.FILL, SWT.FILL, true, false);
223
		if (item.getData() instanceof IConfigurationElement) {
208
			toolbarData.widthHint = SWT.DEFAULT;
224
			final IConfigurationElement element = (IConfigurationElement) item
209
			toolbarData.heightHint = SWT.DEFAULT;
225
					.getData();
210
			toolbar.setLayoutData(toolbarData);
226
227
			id = element.getAttribute(IWorkbenchRegistryConstants.ATT_ID);
228
			item.setData(ID, id);
229
230
			Composite pageComposite = (Composite) item.getControl();
231
			try {
232
				final InstallationPage page = (InstallationPage) element
233
						.createExecutableExtension(IWorkbenchRegistryConstants.ATT_CLASS);
234
				page.createControl(pageComposite);
235
				page.init(createDialogServiceLocator(item));
236
				item.setData(page);
237
				item.addDisposeListener(new DisposeListener() {
238
239
					public void widgetDisposed(DisposeEvent e) {
240
						page.dispose();
241
					}
242
				});
243
				pageComposite.layout(true, true);
244
245
			} catch (CoreException e1) {
246
				Label label = new Label(pageComposite, SWT.NONE);
247
				label.setText(e1.getMessage());
248
				item.setData(null);
249
			}
250
251
		} else {
252
			id = (String) item.getData(ID);
211
		}
253
		}
254
		menuService.releaseContributions(buttonManager);
255
		menuService.populateContributionManager(buttonManager,
256
				InstallationDialog.this.getButtonBarURI(id));
257
		buttonManager.update(true);
258
		createButton(buttonManager.getParent(), IDialogConstants.OK_ID,
259
				IDialogConstants.OK_LABEL, true);
260
		// Layout the button manager again now that the OK button is there.
261
		// Must do this before we layout the button bar or else the button
262
		// manager will not know about the OK button
263
		buttonManager.getParent().layout();
264
		// Now we layout the button bar itself so it will accommodate the
265
		// button manager's buttons
266
		getButtonBar().getParent().layout();
212
	}
267
	}
213
268
214
	/*
269
	/*
Lines 222-261 Link Here
222
		buttonManager = new ButtonManager(parent);
277
		buttonManager = new ButtonManager(parent);
223
	}
278
	}
224
279
225
	/**
226
	 * @param folder2
227
	 */
228
	private void configureFolder() {
280
	private void configureFolder() {
229
		ColorRegistry reg = JFaceResources.getColorRegistry();
230
		Color c1 = reg.get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_START), c2 = reg
231
				.get(IWorkbenchThemeConstants.ACTIVE_TAB_BG_END);
232
		folder.setSelectionBackground(new Color[] { c1, c2 }, new int[] { 50 },
233
				true);
234
		folder.setSelectionForeground(reg
235
				.get(IWorkbenchThemeConstants.ACTIVE_TAB_TEXT_COLOR));
236
		folder.setSimple(PlatformUI.getPreferenceStore().getBoolean(
237
				IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS));
238
239
	}
281
	}
240
282
241
	/**
242
	 * @return
243
	 */
244
	private IConfigurationElement[] loadElements() {
283
	private IConfigurationElement[] loadElements() {
245
		IExtensionPoint point = Platform.getExtensionRegistry()
284
		IExtensionPoint point = Platform.getExtensionRegistry()
246
				.getExtensionPoint("org.eclipse.ui", "installationPages"); //$NON-NLS-1$ //$NON-NLS-2$
285
				.getExtensionPoint("org.eclipse.ui", "installationPages"); //$NON-NLS-1$ //$NON-NLS-2$
247
		return point.getConfigurationElements();
286
		return point.getConfigurationElements();
248
	}
287
	}
249
288
250
	private String getButtonBarURI(String id) {
289
	protected String getButtonBarURI(String id) {
251
		return "toolbar:org.eclipse.ui.installationDialog.buttonbar/" + id; //$NON-NLS-1$
290
		return "toolbar:org.eclipse.ui.installationDialog.buttonbar/" + id; //$NON-NLS-1$
252
	}
291
	}
253
292
254
	protected String getToolbarURI(String id) {
293
	protected IServiceLocator createDialogServiceLocator(final TabItem item) {
255
		return "toolbar:org.eclipse.ui.installationDialog/" + id; //$NON-NLS-1$
256
	}
257
258
	private IServiceLocator createDialogServiceLocator(final CTabItem item) {
259
		return new IServiceLocator() {
294
		return new IServiceLocator() {
260
295
261
			public Object getService(Class api) {
296
			public Object getService(Class api) {
Lines 267-282 Link Here
267
									.getButtonBarURI((String) item.getData(ID));
302
									.getButtonBarURI((String) item.getData(ID));
268
						}
303
						}
269
304
270
						public String getToolbarURI() {
271
							return InstallationDialog.this
272
									.getToolbarURI((String) item.getData(ID));
273
						}
274
275
						public void updateMessage() {
305
						public void updateMessage() {
276
							// TBD
306
							// TBD
277
307
278
						}
308
						}
279
						
309
280
						public void close() {
310
						public void close() {
281
							InstallationDialog.this.close();
311
							InstallationDialog.this.close();
282
						}
312
						}
Lines 294-359 Link Here
294
			}
324
			}
295
		};
325
		};
296
	}
326
	}
297
}
298
299
class ButtonManager extends ContributionManager {
300
301
	private Composite composite;
302
303
	/**
304
	 * 
305
	 */
306
	public ButtonManager(Composite composite) {
307
		this.composite = composite;
308
	}
309
310
	/**
311
	 * @return
312
	 */
313
	public Composite getParent() {
314
		return composite;
315
	}
316
327
317
	/*
328
	protected IDialogSettings getDialogBoundsSettings() {
318
	 * (non-Javadoc)
329
		IDialogSettings settings = WorkbenchPlugin.getDefault()
319
	 * 
330
				.getDialogSettings();
320
	 * @see org.eclipse.jface.action.IContributionManager#update(boolean)
331
		IDialogSettings section = settings.getSection(DIALOG_SETTINGS_SECTION);
321
	 */
332
		if (section == null) {
322
	public void update(boolean force) {
333
			section = settings.addNewSection(DIALOG_SETTINGS_SECTION);
323
		if (composite == null || composite.isDisposed())
324
			return;
325
		GC metricsGC = new GC(composite);
326
		FontMetrics metrics = metricsGC.getFontMetrics();
327
		metricsGC.dispose();
328
		IContributionItem[] items = getItems();
329
		Control[] children = composite.getChildren();
330
331
		int visibleChildren = 0;
332
		for (int i = 0; i < children.length; i++) {
333
			Control control = children[i];
334
			control.dispose();
335
		}
334
		}
336
335
		return section;
337
		for (int i = 0; i < items.length; i++) {
338
			IContributionItem item = items[i];
339
			if (item.isVisible()) {
340
				item.fill(composite);
341
				children = composite.getChildren();
342
				Control itemControl = children[children.length - 1];
343
				setButtonLayoutData(metrics, itemControl);
344
				visibleChildren++;
345
			}
346
		}
347
		GridLayout compositeLayout = (GridLayout) composite.getLayout();
348
		compositeLayout.numColumns = visibleChildren;
349
		composite.layout(true);
350
	}
336
	}
351
	
337
352
	protected void setButtonLayoutData(FontMetrics metrics, Control button) {
338
	protected void releaseContributions() {
353
		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
339
		menuService.releaseContributions(buttonManager);
354
		int widthHint = Dialog.convertHorizontalDLUsToPixels(metrics, IDialogConstants.BUTTON_WIDTH);
340
		buttonManager.removeAll();
355
		Point minSize = button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
356
		data.widthHint = Math.max(widthHint, minSize.x);
357
		button.setLayoutData(data);
358
	}
341
	}
359
}
342
}
(-)Eclipse UI/org/eclipse/ui/about/InstallationPage.java (-1 / +1 lines)
Lines 10-16 Link Here
10
 * page (via the provided service locator) to update the status message in the
10
 * page (via the provided service locator) to update the status message in the
11
 * hosting dialog.
11
 * hosting dialog.
12
 * 
12
 * 
13
 * <em>This API is experiemental and will change before 3.5 ships</em>
13
 * <em>This API is experimental and will change before 3.5 ships</em>
14
 * 
14
 * 
15
 * @since 3.5
15
 * @since 3.5
16
 */
16
 */
(-)Eclipse UI/org/eclipse/ui/about/IInstallationPageContainer.java (-7 lines)
Lines 30-42 Link Here
30
	public void updateMessage();
30
	public void updateMessage();
31
31
32
	/**
32
	/**
33
	 * URI to be provided to the IMenuService for additions to the toolbar.
34
	 * 
35
	 * @return the toolbar uri
36
	 */
37
	public String getToolbarURI();
38
39
	/**
40
	 * URI to be provided to the IMenuService for additions to the button bar.
33
	 * URI to be provided to the IMenuService for additions to the button bar.
41
	 * 
34
	 * 
42
	 * This may not be desirable. We've never had a "button manager" before now,
35
	 * This may not be desirable. We've never had a "button manager" before now,
(-)Eclipse UI/org/eclipse/ui/internal/messages.properties (-3 / +3 lines)
Lines 243-252 Link Here
243
DynamicHelpAction_text = &Dynamic Help
243
DynamicHelpAction_text = &Dynamic Help
244
DynamicHelpAction_toolTip = Dynamic Help
244
DynamicHelpAction_toolTip = Dynamic Help
245
AboutDialog_shellTitle = About {0}
245
AboutDialog_shellTitle = About {0}
246
AboutDialog_featureInfo = &Feature Details
247
AboutDialog_pluginInfo = &Plug-in Details
248
AboutDialog_systemInfo = &Configuration Details
249
AboutDialog_defaultProductName =
246
AboutDialog_defaultProductName =
247
AboutDialog_DetailsButton=&Installation Details
250
ProductInfoDialog_errorTitle = Problems Opening Link
248
ProductInfoDialog_errorTitle = Problems Opening Link
251
ProductInfoDialog_unableToOpenWebBrowser = Unable to open web browser on {0}
249
ProductInfoDialog_unableToOpenWebBrowser = Unable to open web browser on {0}
252
PreferencesExportDialog_ErrorDialogTitle=Error
250
PreferencesExportDialog_ErrorDialogTitle=Error
Lines 282-287 Link Here
282
AboutFeaturesDialog_pluginInfoTitle = Feature Plug-ins
280
AboutFeaturesDialog_pluginInfoTitle = Feature Plug-ins
283
AboutFeaturesDialog_pluginInfoMessage = Plug-ins contributed by feature: {0}
281
AboutFeaturesDialog_pluginInfoMessage = Plug-ins contributed by feature: {0}
284
AboutFeaturesDialog_noInfoTitle = No Further Information
282
AboutFeaturesDialog_noInfoTitle = No Further Information
283
AboutFeaturesDialog_SimpleTitle=Features
285
AboutSystemDialog_browseErrorLogName = &View Error Log
284
AboutSystemDialog_browseErrorLogName = &View Error Log
286
AboutSystemDialog_copyToClipboardName = Copy &to Clipboard
285
AboutSystemDialog_copyToClipboardName = Copy &to Clipboard
287
AboutSystemDialog_noLogTitle = Error Log Not Found
286
AboutSystemDialog_noLogTitle = Error Log Not Found
Lines 518-523 Link Here
518
# ==============================================================================
517
# ==============================================================================
519
Error = Error
518
Error = Error
520
Information = Information
519
Information = Information
520
InstallationDialog_ShellTitle={0} Installation Details
521
521
522
Workbench_NeedsClose_Title = Restart Needed
522
Workbench_NeedsClose_Title = Restart Needed
523
Workbench_NeedsClose_Message = A required plug-in is no longer available and the Workbench needs to be restarted. You will be prompted to save if there is any unsaved work.
523
Workbench_NeedsClose_Message = A required plug-in is no longer available and the Workbench needs to be restarted. You will be prompted to save if there is any unsaved work.
(-)Eclipse UI/org/eclipse/ui/internal/ConfigurationInfo.java (-6 / +5 lines)
Lines 80-86 Link Here
80
	 * extension point.
80
	 * extension point.
81
	 */
81
	 */
82
	private static void appendExtensions(PrintWriter writer) {
82
	private static void appendExtensions(PrintWriter writer) {
83
		IConfigurationElement[] configElements = getSortedExtensions();
83
		IConfigurationElement[] configElements = getSortedExtensions(Platform
84
				.getExtensionRegistry().getConfigurationElementsFor(
85
						PlatformUI.PLUGIN_ID,
86
						IWorkbenchRegistryConstants.PL_SYSTEM_SUMMARY_SECTIONS));
84
		for (int i = 0; i < configElements.length; ++i) {
87
		for (int i = 0; i < configElements.length; ++i) {
85
			IConfigurationElement element = configElements[i];
88
			IConfigurationElement element = configElements[i];
86
89
Lines 108-118 Link Here
108
		}
111
		}
109
	}
112
	}
110
113
111
	private static IConfigurationElement[] getSortedExtensions() {
114
	public static IConfigurationElement[] getSortedExtensions(IConfigurationElement[] configElements) {
112
		IConfigurationElement[] configElements = Platform
113
				.getExtensionRegistry().getConfigurationElementsFor(
114
						PlatformUI.PLUGIN_ID,
115
						IWorkbenchRegistryConstants.PL_SYSTEM_SUMMARY_SECTIONS);
116
115
117
		Arrays.sort(configElements, new Comparator() {
116
		Arrays.sort(configElements, new Comparator() {
118
			Collator collator = Collator.getInstance(Locale.getDefault());
117
			Collator collator = Collator.getInstance(Locale.getDefault());
(-)Eclipse UI/org/eclipse/ui/internal/WorkbenchMessages.java (-3 / +9 lines)
Lines 283-292 Link Here
283
	public static String DynamicHelpAction_text;
283
	public static String DynamicHelpAction_text;
284
	public static String DynamicHelpAction_toolTip;
284
	public static String DynamicHelpAction_toolTip;
285
	public static String AboutDialog_shellTitle;
285
	public static String AboutDialog_shellTitle;
286
	public static String AboutDialog_featureInfo;
287
	public static String AboutDialog_pluginInfo;
288
	public static String AboutDialog_systemInfo;
289
	public static String AboutDialog_defaultProductName;
286
	public static String AboutDialog_defaultProductName;
287
288
289
	public static String AboutDialog_DetailsButton;
290
	public static String ProductInfoDialog_errorTitle;
290
	public static String ProductInfoDialog_errorTitle;
291
	public static String ProductInfoDialog_unableToOpenWebBrowser;
291
	public static String ProductInfoDialog_unableToOpenWebBrowser;
292
	public static String PreferencesExportDialog_ErrorDialogTitle;
292
	public static String PreferencesExportDialog_ErrorDialogTitle;
Lines 322-327 Link Here
322
	public static String AboutFeaturesDialog_pluginInfoTitle;
322
	public static String AboutFeaturesDialog_pluginInfoTitle;
323
	public static String AboutFeaturesDialog_pluginInfoMessage;
323
	public static String AboutFeaturesDialog_pluginInfoMessage;
324
	public static String AboutFeaturesDialog_noInfoTitle;
324
	public static String AboutFeaturesDialog_noInfoTitle;
325
326
327
	public static String AboutFeaturesDialog_SimpleTitle;
325
	public static String AboutSystemDialog_browseErrorLogName;
328
	public static String AboutSystemDialog_browseErrorLogName;
326
	public static String AboutSystemDialog_copyToClipboardName;
329
	public static String AboutSystemDialog_copyToClipboardName;
327
	public static String AboutSystemDialog_noLogTitle;
330
	public static String AboutSystemDialog_noLogTitle;
Lines 551-556 Link Here
551
	// ==============================================================================
554
	// ==============================================================================
552
	public static String Error;
555
	public static String Error;
553
	public static String Information;
556
	public static String Information;
557
558
559
	public static String InstallationDialog_ShellTitle;
554
	
560
	
555
	public static String Workbench_NeedsClose_Title;
561
	public static String Workbench_NeedsClose_Title;
556
	public static String Workbench_NeedsClose_Message;
562
	public static String Workbench_NeedsClose_Message;
(-)Eclipse (+80 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 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.ui.internal.about;
12
13
import org.eclipse.swt.SWT;
14
import org.eclipse.swt.events.DisposeEvent;
15
import org.eclipse.swt.events.DisposeListener;
16
import org.eclipse.swt.layout.GridLayout;
17
import org.eclipse.swt.widgets.Composite;
18
import org.eclipse.swt.widgets.Shell;
19
import org.eclipse.swt.widgets.TabFolder;
20
import org.eclipse.swt.widgets.TabItem;
21
import org.eclipse.ui.PlatformUI;
22
23
/**
24
 * Abstract superclass of the individual about dialogs. 
25
 * These are installation dialogs that contain a single 
26
 * installation page.  Often the dialogs scope the
27
 * page to something more specific than it would be in 
28
 * the standard about installation page.
29
 */
30
31
public abstract class ProductInfoDialog extends InstallationDialog {
32
33
	ProductInfoPage page;
34
	String title;
35
	String helpContextId;
36
	
37
	protected ProductInfoDialog(Shell shell) {
38
		super(shell, PlatformUI.getWorkbench().getActiveWorkbenchWindow());
39
	}
40
41
	public void initializeDialog(ProductInfoPage page, 
42
			String title, String helpContextId) {
43
		this.page = page;
44
		this.title = title;
45
		this.helpContextId = helpContextId;
46
	}
47
	
48
	protected void createFolderItems(TabFolder folder) {
49
		TabItem item = new TabItem(folder, SWT.NONE);
50
		item.setText(title);
51
		Composite control = new Composite(folder, SWT.BORDER);
52
		control.setLayout(new GridLayout());
53
		item.setControl(control);
54
		page.createControl(control);
55
		// must set up the page data before creating the service locator. 
56
		// The id is used by the dialog service locator
57
		item.setData(page);
58
		item.setData(ID, page.getId());
59
		page.init(createDialogServiceLocator(item));
60
		item.addDisposeListener(new DisposeListener() {
61
62
			public void widgetDisposed(DisposeEvent e) {
63
				page.dispose();
64
			}
65
		});
66
		control.layout(true, true);
67
	}
68
69
	/*
70
	 * (non-Javadoc)
71
	 * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
72
	 */
73
	protected void configureShell(Shell newShell) {
74
		super.configureShell(newShell);
75
		newShell.setText(title);
76
		if (helpContextId != null)
77
			PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
78
					helpContextId);
79
	}
80
}
(-)Eclipse (+350 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 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.ui.internal.about;
12
13
import java.util.ArrayList;
14
import java.util.StringTokenizer;
15
16
import org.eclipse.jface.resource.JFaceColors;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.custom.StyleRange;
19
import org.eclipse.swt.custom.StyledText;
20
import org.eclipse.swt.events.DisposeEvent;
21
import org.eclipse.swt.events.DisposeListener;
22
import org.eclipse.swt.events.KeyAdapter;
23
import org.eclipse.swt.events.KeyEvent;
24
import org.eclipse.swt.events.MouseAdapter;
25
import org.eclipse.swt.events.MouseEvent;
26
import org.eclipse.swt.events.MouseMoveListener;
27
import org.eclipse.swt.events.TraverseEvent;
28
import org.eclipse.swt.events.TraverseListener;
29
import org.eclipse.swt.graphics.Color;
30
import org.eclipse.swt.graphics.Cursor;
31
import org.eclipse.swt.graphics.Point;
32
33
/**
34
 * Manages links in styled text.
35
 */
36
37
public class AboutTextManager {
38
39
    /**
40
     * Scan the contents of the about text
41
     * @param s 
42
     * @return 
43
     */
44
    public static AboutItem scan(String s) {
45
        ArrayList linkRanges = new ArrayList();
46
        ArrayList links = new ArrayList();
47
        
48
        // slightly modified version of jface url detection
49
        // see org.eclipse.jface.text.hyperlink.URLHyperlinkDetector
50
        
51
		int urlSeparatorOffset= s.indexOf("://"); //$NON-NLS-1$
52
		while(urlSeparatorOffset >= 0) {
53
	
54
			boolean startDoubleQuote= false;
55
	
56
			// URL protocol (left to "://")
57
			int urlOffset= urlSeparatorOffset;
58
			char ch;
59
			do {
60
				urlOffset--;
61
				ch= ' ';
62
				if (urlOffset > -1)
63
					ch= s.charAt(urlOffset);
64
				startDoubleQuote= ch == '"';
65
			} while (Character.isUnicodeIdentifierStart(ch));
66
			urlOffset++;
67
			
68
	
69
			// Right to "://"
70
			StringTokenizer tokenizer= new StringTokenizer(s.substring(urlSeparatorOffset + 3), " \t\n\r\f<>", false); //$NON-NLS-1$
71
			if (!tokenizer.hasMoreTokens())
72
				return null;
73
	
74
			int urlLength= tokenizer.nextToken().length() + 3 + urlSeparatorOffset - urlOffset;
75
	
76
			if (startDoubleQuote) {
77
				int endOffset= -1;
78
				int nextDoubleQuote= s.indexOf('"', urlOffset);
79
				int nextWhitespace= s.indexOf(' ', urlOffset);
80
				if (nextDoubleQuote != -1 && nextWhitespace != -1)
81
					endOffset= Math.min(nextDoubleQuote, nextWhitespace);
82
				else if (nextDoubleQuote != -1)
83
					endOffset= nextDoubleQuote;
84
				else if (nextWhitespace != -1)
85
					endOffset= nextWhitespace;
86
				if (endOffset != -1)
87
					urlLength= endOffset - urlOffset;
88
			}
89
			
90
			linkRanges.add(new int[] { urlOffset, urlLength });
91
			links.add(s.substring(urlOffset, urlOffset+urlLength));
92
			
93
			urlSeparatorOffset= s.indexOf("://", urlOffset+urlLength+1); //$NON-NLS-1$
94
		}
95
        return new AboutItem(s, (int[][]) linkRanges.toArray(new int[linkRanges
96
                .size()][2]), (String[]) links
97
                .toArray(new String[links.size()]));
98
    }
99
	private StyledText styledText;
100
	
101
    private Cursor handCursor;
102
103
    private Cursor busyCursor;
104
105
    private boolean mouseDown = false;
106
107
    private boolean dragEvent = false;
108
    
109
    private AboutItem item;
110
    
111
    public AboutTextManager(StyledText text) {
112
    	this.styledText = text;
113
    	createCursors();
114
    	addListeners();
115
    }
116
    
117
    private void createCursors() {
118
        handCursor = new Cursor(styledText.getDisplay(), SWT.CURSOR_HAND);
119
        busyCursor = new Cursor(styledText.getDisplay(), SWT.CURSOR_WAIT);
120
        styledText.addDisposeListener(new DisposeListener() {
121
            public void widgetDisposed(DisposeEvent e) {
122
                handCursor.dispose();
123
                handCursor = null;
124
                busyCursor.dispose();
125
                busyCursor = null;
126
            }
127
        });
128
    }
129
130
	
131
    /**
132
     * Adds listeners to the given styled text
133
     */
134
    protected void addListeners() {
135
        styledText.addMouseListener(new MouseAdapter() {
136
            public void mouseDown(MouseEvent e) {
137
                if (e.button != 1) {
138
                    return;
139
                }
140
                mouseDown = true;
141
            }
142
143
            public void mouseUp(MouseEvent e) {
144
                mouseDown = false;
145
                int offset = styledText.getCaretOffset();
146
                if (dragEvent) {
147
                    // don't activate a link during a drag/mouse up operation
148
                    dragEvent = false;
149
                    if (item != null && item.isLinkAt(offset)) {
150
                    	styledText.setCursor(handCursor);
151
                    }
152
                } else if (item != null && item.isLinkAt(offset)) {
153
                	styledText.setCursor(busyCursor);
154
                    AboutUtils.openLink(styledText.getShell(), item.getLinkAt(offset));
155
                    StyleRange selectionRange = getCurrentRange();
156
                    styledText.setSelectionRange(selectionRange.start,
157
                            selectionRange.length);
158
                    styledText.setCursor(null);
159
                }
160
            }
161
        });
162
163
        styledText.addMouseMoveListener(new MouseMoveListener() {
164
            public void mouseMove(MouseEvent e) {
165
                // Do not change cursor on drag events
166
                if (mouseDown) {
167
                    if (!dragEvent) {
168
                        StyledText text = (StyledText) e.widget;
169
                        text.setCursor(null);
170
                    }
171
                    dragEvent = true;
172
                    return;
173
                }
174
                StyledText text = (StyledText) e.widget;
175
                int offset = -1;
176
                try {
177
                    offset = text.getOffsetAtLocation(new Point(e.x, e.y));
178
                } catch (IllegalArgumentException ex) {
179
                    // leave value as -1
180
                }
181
                if (offset == -1) {
182
					text.setCursor(null);
183
				} else if (item != null && item.isLinkAt(offset)) {
184
					text.setCursor(handCursor);
185
				} else {
186
					text.setCursor(null);
187
				}
188
            }
189
        });
190
191
        styledText.addTraverseListener(new TraverseListener() {
192
            public void keyTraversed(TraverseEvent e) {
193
                switch (e.detail) {
194
                case SWT.TRAVERSE_ESCAPE:
195
                    e.doit = true;
196
                    break;
197
                case SWT.TRAVERSE_TAB_NEXT:
198
                    //Previously traverse out in the backward direction?
199
                    Point nextSelection = styledText.getSelection();
200
                    int charCount = styledText.getCharCount();
201
                    if ((nextSelection.x == charCount)
202
                            && (nextSelection.y == charCount)) {
203
                    	styledText.setSelection(0);
204
                    }
205
                    StyleRange nextRange = findNextRange();
206
                    if (nextRange == null) {
207
                        // Next time in start at beginning, also used by 
208
                        // TRAVERSE_TAB_PREVIOUS to indicate we traversed out
209
                        // in the forward direction
210
                    	styledText.setSelection(0);
211
                        e.doit = true;
212
                    } else {
213
                    	styledText.setSelectionRange(nextRange.start,
214
                                nextRange.length);
215
                        e.doit = true;
216
                        e.detail = SWT.TRAVERSE_NONE;
217
                    }
218
                    break;
219
                case SWT.TRAVERSE_TAB_PREVIOUS:
220
                    //Previously traverse out in the forward direction?
221
                    Point previousSelection = styledText.getSelection();
222
                    if ((previousSelection.x == 0)
223
                            && (previousSelection.y == 0)) {
224
                    	styledText.setSelection(styledText.getCharCount());
225
					}
226
                    StyleRange previousRange = findPreviousRange();
227
                    if (previousRange == null) {
228
                        // Next time in start at the end, also used by 
229
                        // TRAVERSE_TAB_NEXT to indicate we traversed out
230
                        // in the backward direction
231
                    	styledText.setSelection(styledText.getCharCount());
232
                        e.doit = true;
233
                    } else {
234
                    	styledText.setSelectionRange(previousRange.start,
235
                                previousRange.length);
236
                        e.doit = true;
237
                        e.detail = SWT.TRAVERSE_NONE;
238
                    }
239
                    break;
240
                default:
241
                    break;
242
                }
243
            }
244
        });
245
246
        //Listen for Tab and Space to allow keyboard navigation
247
        styledText.addKeyListener(new KeyAdapter() {
248
            public void keyPressed(KeyEvent event) {
249
                StyledText text = (StyledText) event.widget;
250
                if (event.character == ' ' || event.character == SWT.CR) {
251
                    if (item != null) {
252
                        //Be sure we are in the selection
253
                        int offset = text.getSelection().x + 1;
254
255
                        if (item.isLinkAt(offset)) {
256
                            text.setCursor(busyCursor);
257
                            AboutUtils.openLink(styledText.getShell(), item.getLinkAt(offset));
258
                            StyleRange selectionRange = getCurrentRange();
259
                            text.setSelectionRange(selectionRange.start,
260
                                    selectionRange.length);
261
                            text.setCursor(null);
262
                        }
263
                    }
264
                    return;
265
                }
266
            }
267
        });
268
    }
269
270
    /**
271
     * Gets the about item.
272
     * @return the about item
273
     */
274
    public AboutItem getItem() {
275
        return item;
276
    }
277
278
    /**
279
     * Sets the about item.
280
     * @param item about item
281
     */
282
    public void setItem(AboutItem item) {
283
        this.item = item;
284
        if (item != null) {
285
        	styledText.setText(item.getText());
286
        	setLinkRanges(item.getLinkRanges()); 
287
        }
288
    }
289
290
    /**
291
     * Find the range of the current selection.
292
     */
293
    private StyleRange getCurrentRange() {
294
        StyleRange[] ranges = styledText.getStyleRanges();
295
        int currentSelectionEnd = styledText.getSelection().y;
296
        int currentSelectionStart = styledText.getSelection().x;
297
298
        for (int i = 0; i < ranges.length; i++) {
299
            if ((currentSelectionStart >= ranges[i].start)
300
                    && (currentSelectionEnd <= (ranges[i].start + ranges[i].length))) {
301
                return ranges[i];
302
            }
303
        }
304
        return null;
305
    }
306
307
    /**
308
     * Find the next range after the current 
309
     * selection.
310
     */
311
    private StyleRange findNextRange() {
312
        StyleRange[] ranges = styledText.getStyleRanges();
313
        int currentSelectionEnd = styledText.getSelection().y;
314
315
        for (int i = 0; i < ranges.length; i++) {
316
            if (ranges[i].start >= currentSelectionEnd) {
317
				return ranges[i];
318
			}
319
        }
320
        return null;
321
    }
322
323
    /**
324
     * Find the previous range before the current selection.
325
     */
326
    private StyleRange findPreviousRange() {
327
        StyleRange[] ranges = styledText.getStyleRanges();
328
        int currentSelectionStart = styledText.getSelection().x;
329
330
        for (int i = ranges.length - 1; i > -1; i--) {
331
            if ((ranges[i].start + ranges[i].length - 1) < currentSelectionStart) {
332
				return ranges[i];
333
			}
334
        }
335
        return null;
336
    }
337
338
    /**
339
     * Sets the styled text's link (blue) ranges
340
     */
341
    private void setLinkRanges(int[][] linkRanges) {
342
        Color fg = JFaceColors.getHyperlinkText(styledText.getShell()
343
                .getDisplay());
344
        for (int i = 0; i < linkRanges.length; i++) {
345
            StyleRange r = new StyleRange(linkRanges[i][0], linkRanges[i][1],
346
                    fg, null);
347
            styledText.setStyleRange(r);
348
        }
349
    }
350
}
(-)Eclipse (+184 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 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.ui.internal.about;
12
13
import java.io.IOException;
14
import java.net.MalformedURLException;
15
import java.net.URL;
16
import java.util.ArrayList;
17
import java.util.StringTokenizer;
18
19
import org.eclipse.core.runtime.IStatus;
20
import org.eclipse.core.runtime.Platform;
21
import org.eclipse.osgi.util.NLS;
22
import org.eclipse.swt.widgets.Shell;
23
import org.eclipse.ui.PartInitException;
24
import org.eclipse.ui.PlatformUI;
25
import org.eclipse.ui.browser.IWebBrowser;
26
import org.eclipse.ui.browser.IWorkbenchBrowserSupport;
27
import org.eclipse.ui.internal.WorkbenchMessages;
28
import org.eclipse.ui.internal.WorkbenchPlugin;
29
import org.eclipse.ui.internal.misc.StatusUtil;
30
import org.eclipse.ui.statushandlers.StatusManager;
31
32
/**
33
 * Manages links in styled text.
34
 */
35
36
public class AboutUtils {
37
38
	/**
39
	 * Scan the contents of the about text
40
	 * 
41
	 * @param s
42
	 * @return
43
	 */
44
	public static AboutItem scan(String s) {
45
		ArrayList linkRanges = new ArrayList();
46
		ArrayList links = new ArrayList();
47
48
		// slightly modified version of jface url detection
49
		// see org.eclipse.jface.text.hyperlink.URLHyperlinkDetector
50
51
		int urlSeparatorOffset = s.indexOf("://"); //$NON-NLS-1$
52
		while (urlSeparatorOffset >= 0) {
53
54
			boolean startDoubleQuote = false;
55
56
			// URL protocol (left to "://")
57
			int urlOffset = urlSeparatorOffset;
58
			char ch;
59
			do {
60
				urlOffset--;
61
				ch = ' ';
62
				if (urlOffset > -1)
63
					ch = s.charAt(urlOffset);
64
				startDoubleQuote = ch == '"';
65
			} while (Character.isUnicodeIdentifierStart(ch));
66
			urlOffset++;
67
68
			// Right to "://"
69
			StringTokenizer tokenizer = new StringTokenizer(s
70
					.substring(urlSeparatorOffset + 3), " \t\n\r\f<>", false); //$NON-NLS-1$
71
			if (!tokenizer.hasMoreTokens())
72
				return null;
73
74
			int urlLength = tokenizer.nextToken().length() + 3
75
					+ urlSeparatorOffset - urlOffset;
76
77
			if (startDoubleQuote) {
78
				int endOffset = -1;
79
				int nextDoubleQuote = s.indexOf('"', urlOffset);
80
				int nextWhitespace = s.indexOf(' ', urlOffset);
81
				if (nextDoubleQuote != -1 && nextWhitespace != -1)
82
					endOffset = Math.min(nextDoubleQuote, nextWhitespace);
83
				else if (nextDoubleQuote != -1)
84
					endOffset = nextDoubleQuote;
85
				else if (nextWhitespace != -1)
86
					endOffset = nextWhitespace;
87
				if (endOffset != -1)
88
					urlLength = endOffset - urlOffset;
89
			}
90
91
			linkRanges.add(new int[] { urlOffset, urlLength });
92
			links.add(s.substring(urlOffset, urlOffset + urlLength));
93
94
			urlSeparatorOffset = s.indexOf("://", urlOffset + urlLength + 1); //$NON-NLS-1$
95
		}
96
		return new AboutItem(s, (int[][]) linkRanges.toArray(new int[linkRanges
97
				.size()][2]), (String[]) links
98
				.toArray(new String[links.size()]));
99
	}
100
101
	/**
102
	 * Open a browser with the argument title on the argument url. If the url
103
	 * refers to a resource within a bundle, then a temp copy of the file will
104
	 * be extracted and opened.
105
	 * 
106
	 * @see <code>Platform.asLocalUrl</code>
107
	 * @param url
108
	 *            The target url to be displayed, null will be safely ignored
109
	 * @return true if the url was successfully displayed and false otherwise
110
	 */
111
	public static boolean openBrowser(Shell shell, URL url) {
112
		if (url != null) {
113
			try {
114
				url = Platform.asLocalURL(url);
115
			} catch (IOException e) {
116
				return false;
117
			}
118
		}
119
		if (url == null) {
120
			return false;
121
		}
122
		openLink(shell, url.toString());
123
		return true;
124
	}
125
126
	/**
127
	 * Open a link
128
	 */
129
	public static void openLink(Shell shell, String href) {
130
		// format the href for an html file (file:///<filename.html>
131
		// required for Mac only.
132
		if (href.startsWith("file:")) { //$NON-NLS-1$
133
			href = href.substring(5);
134
			while (href.startsWith("/")) { //$NON-NLS-1$
135
				href = href.substring(1);
136
			}
137
			href = "file:///" + href; //$NON-NLS-1$
138
		}
139
		IWorkbenchBrowserSupport support = PlatformUI.getWorkbench()
140
				.getBrowserSupport();
141
		try {
142
			IWebBrowser browser = support.getExternalBrowser();
143
			browser.openURL(new URL(urlEncodeForSpaces(href.toCharArray())));
144
		} catch (MalformedURLException e) {
145
			openWebBrowserError(shell, href, e);
146
		} catch (PartInitException e) {
147
			openWebBrowserError(shell, href, e);
148
		}
149
	}
150
151
	/**
152
	 * This method encodes the url, removes the spaces from the url and replaces
153
	 * the same with <code>"%20"</code>. This method is required to fix Bug
154
	 * 77840.
155
	 * 
156
	 * @since 3.0.2
157
	 */
158
	private static String urlEncodeForSpaces(char[] input) {
159
		StringBuffer retu = new StringBuffer(input.length);
160
		for (int i = 0; i < input.length; i++) {
161
			if (input[i] == ' ') {
162
				retu.append("%20"); //$NON-NLS-1$
163
			} else {
164
				retu.append(input[i]);
165
			}
166
		}
167
		return retu.toString();
168
	}
169
170
	/**
171
	 * display an error message
172
	 */
173
	private static void openWebBrowserError(Shell shell, final String href,
174
			final Throwable t) {
175
		String title = WorkbenchMessages.ProductInfoDialog_errorTitle;
176
		String msg = NLS.bind(
177
				WorkbenchMessages.ProductInfoDialog_unableToOpenWebBrowser,
178
				href);
179
		IStatus status = WorkbenchPlugin.getStatus(t);
180
		StatusUtil.handleStatus(status, title + ": " + msg, StatusManager.SHOW, //$NON-NLS-1$
181
				shell);
182
	}
183
184
}
(-)Eclipse (+150 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2007 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.ui.internal.about;
12
13
import org.eclipse.core.runtime.IProduct;
14
import org.eclipse.core.runtime.Platform;
15
import org.eclipse.jface.dialogs.TrayDialog;
16
import org.eclipse.jface.window.IShellProvider;
17
import org.eclipse.swt.SWT;
18
import org.eclipse.swt.events.DisposeEvent;
19
import org.eclipse.swt.events.DisposeListener;
20
import org.eclipse.swt.layout.GridData;
21
import org.eclipse.swt.layout.GridLayout;
22
import org.eclipse.swt.widgets.Composite;
23
import org.eclipse.swt.widgets.Control;
24
import org.eclipse.ui.about.IInstallationPageContainer;
25
import org.eclipse.ui.about.InstallationPage;
26
import org.eclipse.ui.handlers.IHandlerService;
27
import org.eclipse.ui.internal.WorkbenchMessages;
28
import org.eclipse.ui.menus.AbstractContributionFactory;
29
import org.eclipse.ui.menus.IMenuService;
30
import org.eclipse.ui.services.IServiceLocator;
31
32
/**
33
 * Abstract superclass of about dialog installation pages
34
 */
35
36
public abstract class ProductInfoPage extends InstallationPage implements
37
		IShellProvider {
38
39
	private IMenuService menuService;
40
41
	private IInstallationPageContainer pageContainer;
42
43
	private IHandlerService handlerService;
44
45
	private AbstractContributionFactory factory;
46
47
	private IProduct product;
48
49
	private String productName;
50
51
	/*
52
	 * (non-Javadoc)
53
	 * 
54
	 * @seeorg.eclipse.ui.about.InstallationPage#init(org.eclipse.ui.services.
55
	 * IServiceLocator)
56
	 */
57
	public void init(IServiceLocator locator) {
58
		pageContainer = (IInstallationPageContainer) locator
59
				.getService(IInstallationPageContainer.class);
60
		menuService = (IMenuService) locator.getService(IMenuService.class);
61
		handlerService = (IHandlerService) locator
62
				.getService(IHandlerService.class);
63
		// this assumes that the control is created before init
64
		addButtons();
65
	}
66
67
	protected IMenuService getMenuService() {
68
		return menuService;
69
	}
70
71
	protected IHandlerService getHandlerService() {
72
		return handlerService;
73
	}
74
75
	protected IInstallationPageContainer getPageContainer() {
76
		return pageContainer;
77
	}
78
79
	protected IProduct getProduct() {
80
		if (product == null)
81
			product = Platform.getProduct();
82
		return product;
83
	}
84
85
	public String getProductName() {
86
		if (productName == null) {
87
			if (getProduct() != null) {
88
				productName = getProduct().getName();
89
			}
90
			if (productName == null) {
91
				productName = WorkbenchMessages.AboutDialog_defaultProductName;
92
			}
93
		}
94
		return productName;
95
	}
96
97
	public void setProductName(String name) {
98
		productName = name;
99
	}
100
101
	protected TrayDialog getTrayDialog() {
102
		if (pageContainer instanceof TrayDialog)
103
			return (TrayDialog) pageContainer;
104
		return null;
105
	}
106
107
	abstract String getId();
108
109
	public final void createControl(Composite parent) {
110
		Control control = createPageControl(parent);
111
		control.addDisposeListener(new DisposeListener() {
112
			public void widgetDisposed(DisposeEvent e) {
113
				releaseContributionFactory();
114
			}
115
		});
116
		setControl(control);
117
	}
118
	
119
	protected abstract Control createPageControl(Composite parent);
120
121
	protected Composite createOuterComposite(Composite parent) {
122
		Composite composite = new Composite(parent, SWT.NONE);
123
		GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
124
		composite.setLayoutData(gd);
125
		GridLayout layout = new GridLayout();
126
		layout.marginWidth = 0;
127
		layout.marginHeight = 0;
128
		composite.setLayout(layout);
129
		return composite;
130
	}
131
132
	private void addButtons() {
133
		if (menuService == null)
134
			return;
135
		factory = makeContributionFactory();
136
		if (factory != null)
137
			menuService.addContributionFactory(factory);
138
	}
139
140
	protected AbstractContributionFactory makeContributionFactory() {
141
		return null;
142
	}
143
144
	protected void releaseContributionFactory() {
145
		if (factory != null) {
146
			menuService.removeContributionFactory(factory);
147
			factory = null;
148
		}
149
	}
150
}
(-)Eclipse (+670 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 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
 *  	Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
11
 * 		font should be activated and used by other components.
12
 *******************************************************************************/
13
package org.eclipse.ui.internal.about;
14
15
import java.io.IOException;
16
import java.net.URL;
17
import java.util.ArrayList;
18
import java.util.HashMap;
19
import java.util.LinkedList;
20
import java.util.List;
21
import java.util.Map;
22
23
import org.eclipse.core.runtime.IPath;
24
import org.eclipse.core.runtime.IProgressMonitor;
25
import org.eclipse.core.runtime.IStatus;
26
import org.eclipse.core.runtime.Path;
27
import org.eclipse.core.runtime.Platform;
28
import org.eclipse.core.runtime.Status;
29
import org.eclipse.core.runtime.jobs.Job;
30
import org.eclipse.jface.action.Action;
31
import org.eclipse.jface.action.ActionContributionItem;
32
import org.eclipse.jface.internal.ConfigureColumnsDialog;
33
import org.eclipse.jface.viewers.ArrayContentProvider;
34
import org.eclipse.jface.viewers.IBaseLabelProvider;
35
import org.eclipse.jface.viewers.ISelectionChangedListener;
36
import org.eclipse.jface.viewers.IStructuredSelection;
37
import org.eclipse.jface.viewers.ITableLabelProvider;
38
import org.eclipse.jface.viewers.LabelProvider;
39
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
40
import org.eclipse.jface.viewers.SelectionChangedEvent;
41
import org.eclipse.jface.viewers.TableViewer;
42
import org.eclipse.jface.viewers.Viewer;
43
import org.eclipse.jface.viewers.ViewerComparator;
44
import org.eclipse.osgi.util.NLS;
45
import org.eclipse.swt.SWT;
46
import org.eclipse.swt.custom.SashForm;
47
import org.eclipse.swt.events.SelectionAdapter;
48
import org.eclipse.swt.events.SelectionEvent;
49
import org.eclipse.swt.graphics.Image;
50
import org.eclipse.swt.layout.FillLayout;
51
import org.eclipse.swt.layout.GridData;
52
import org.eclipse.swt.widgets.Composite;
53
import org.eclipse.swt.widgets.Control;
54
import org.eclipse.swt.widgets.Label;
55
import org.eclipse.swt.widgets.Shell;
56
import org.eclipse.swt.widgets.Table;
57
import org.eclipse.swt.widgets.TableColumn;
58
import org.eclipse.ui.PlatformUI;
59
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
60
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
61
import org.eclipse.ui.internal.WorkbenchImages;
62
import org.eclipse.ui.internal.WorkbenchMessages;
63
import org.eclipse.ui.internal.WorkbenchPlugin;
64
import org.eclipse.ui.internal.misc.StatusUtil;
65
import org.eclipse.ui.internal.util.BundleUtility;
66
import org.eclipse.ui.menus.AbstractContributionFactory;
67
import org.eclipse.ui.menus.IContributionRoot;
68
import org.eclipse.ui.progress.WorkbenchJob;
69
import org.eclipse.ui.services.IServiceLocator;
70
import org.eclipse.ui.statushandlers.StatusManager;
71
import org.osgi.framework.Bundle;
72
73
/**
74
 * Displays information about the product plugins.
75
 * 
76
 * PRIVATE this class is internal to the ide
77
 */
78
public class AboutPluginsPage extends ProductInfoPage {
79
80
	public class BundleTableLabelProvider extends LabelProvider implements
81
			ITableLabelProvider {
82
83
		/**
84
		 * Queue containing bundle signing info to be resolved.
85
		 */
86
		private LinkedList resolveQueue = new LinkedList();
87
88
		/**
89
		 * Queue containing bundle data that's been resolve and needs updating.
90
		 */
91
		private List updateQueue = new ArrayList();
92
93
		/*
94
		 * this job will attempt to discover the signing state of a given bundle
95
		 * and then send it along to the update job
96
		 */
97
		private Job resolveJob = new Job(AboutPluginsPage.class.getName()) {
98
			{
99
				setSystem(true);
100
				setPriority(Job.SHORT);
101
			}
102
103
			protected IStatus run(IProgressMonitor monitor) {
104
				while (true) {
105
					// If the UI has not been created, nothing to do.
106
					if (vendorInfo == null)
107
						return Status.OK_STATUS;
108
					// If the UI has been disposed since we were asked to
109
					// render, nothing to do.
110
					Table table = vendorInfo.getTable();
111
					// the table has been disposed since we were asked to render
112
					if (table == null || table.isDisposed())
113
						return Status.OK_STATUS;
114
					AboutBundleData data = null;
115
					synchronized (resolveQueue) {
116
						if (resolveQueue.isEmpty())
117
							return Status.OK_STATUS;
118
						data = (AboutBundleData) resolveQueue.removeFirst();
119
					}
120
					try {
121
						// following is an expensive call
122
						data.isSigned();
123
124
						synchronized (updateQueue) {
125
							updateQueue.add(data);
126
						}
127
						// start the update job
128
						updateJob.schedule();
129
					} catch (IllegalStateException e) {
130
						// the bundle we're testing has been unloaded. Do
131
						// nothing.
132
					}
133
				}
134
			}
135
		};
136
137
		/*
138
		 * this job is responsible for feeding label change events into the
139
		 * viewer as they become available from the resolve job
140
		 */
141
		private Job updateJob = new WorkbenchJob(PlatformUI.getWorkbench()
142
				.getDisplay(), AboutPluginsPage.class.getName()) {
143
			{
144
				setSystem(true);
145
				setPriority(Job.DECORATE);
146
			}
147
148
			/*
149
			 * (non-Javadoc)
150
			 * 
151
			 * @see
152
			 * org.eclipse.ui.progress.UIJob#runInUIThread(org.eclipse.core.
153
			 * runtime.IProgressMonitor)
154
			 */
155
			public IStatus runInUIThread(IProgressMonitor monitor) {
156
				while (true) {
157
					Shell dialogShell = getShell();
158
					// the shell has gone down since we were asked to render
159
					if (dialogShell == null || dialogShell.isDisposed())
160
						return Status.OK_STATUS;
161
					AboutBundleData[] data = null;
162
					synchronized (updateQueue) {
163
						if (updateQueue.isEmpty())
164
							return Status.OK_STATUS;
165
166
						data = (AboutBundleData[]) updateQueue
167
								.toArray(new AboutBundleData[updateQueue.size()]);
168
						updateQueue.clear();
169
170
					}
171
					fireLabelProviderChanged(new LabelProviderChangedEvent(
172
							BundleTableLabelProvider.this, data));
173
				}
174
			}
175
		};
176
177
		/*
178
		 * (non-Javadoc)
179
		 * 
180
		 * @see
181
		 * org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java
182
		 * .lang.Object, int)
183
		 */
184
		public Image getColumnImage(Object element, int columnIndex) {
185
			if (columnIndex == 0) {
186
				if (element instanceof AboutBundleData) {
187
					final AboutBundleData data = (AboutBundleData) element;
188
					if (data.isSignedDetermined()) {
189
						return WorkbenchImages
190
								.getImage(data.isSigned() ? IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_YES
191
										: IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_NO);
192
					}
193
194
					synchronized (resolveQueue) {
195
						resolveQueue.add(data);
196
					}
197
					resolveJob.schedule();
198
199
					return WorkbenchImages
200
							.getImage(IWorkbenchGraphicConstants.IMG_OBJ_SIGNED_UNKNOWN);
201
				}
202
			}
203
			return null;
204
		}
205
206
		/*
207
		 * (non-Javadoc)
208
		 * 
209
		 * @see
210
		 * org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.
211
		 * lang.Object, int)
212
		 */
213
		public String getColumnText(Object element, int columnIndex) {
214
			if (element instanceof AboutBundleData) {
215
				AboutBundleData data = (AboutBundleData) element;
216
				switch (columnIndex) {
217
				case 1:
218
					return data.getProviderName();
219
				case 2:
220
					return data.getName();
221
				case 3:
222
					return data.getVersion();
223
				case 4:
224
					return data.getId();
225
				}
226
			}
227
			return ""; //$NON-NLS-1$
228
		}
229
	}
230
231
	// This id should *not* be the same id used for contributing the page in
232
	// the installationPage extension. It is used by ProductInfoDialog
233
	// to ensure a different namespace for button contributions than the id
234
	// for the page appearing in the InstallationDialog
235
	private static final String ID = "productInfo.plugins"; //$NON-NLS-1$
236
237
	/**
238
	 * Table height in dialog units (value 200).
239
	 */
240
	private static final int TABLE_HEIGHT = 200;
241
242
	private static final IPath baseNLPath = new Path("$nl$"); //$NON-NLS-1$
243
244
	private static final String PLUGININFO = "about.html"; //$NON-NLS-1$
245
246
	private static final int PLUGIN_NAME_COLUMN_INDEX = 2;
247
	
248
	private static final int SIGNING_AREA_PERCENTAGE = 30;
249
250
	private TableViewer vendorInfo;
251
252
	private Action moreInfo, signingInfo;
253
254
	private String message;
255
256
	private String helpContextId = IWorkbenchHelpContextIds.ABOUT_PLUGINS_DIALOG;
257
258
	private String columnTitles[] = {
259
			WorkbenchMessages.AboutPluginsDialog_signed,
260
			WorkbenchMessages.AboutPluginsDialog_provider,
261
			WorkbenchMessages.AboutPluginsDialog_pluginName,
262
			WorkbenchMessages.AboutPluginsDialog_version,
263
			WorkbenchMessages.AboutPluginsDialog_pluginId,
264
265
	};
266
	private Bundle[] bundles = WorkbenchPlugin.getDefault().getBundles();
267
	private AboutBundleData[] bundleInfos;
268
	private SashForm sashForm;
269
	private BundleSigningInfo signingArea;
270
271
	public void setBundles(Bundle[] bundles) {
272
		this.bundles = bundles;
273
	}
274
275
	public void setHelpContextId(String id) {
276
		this.helpContextId = id;
277
	}
278
279
	public void setMessage(String message) {
280
		this.message = message;
281
	}
282
283
	/**
284
	 * 
285
	 */
286
	private void handleColumnsPressed() {
287
		ConfigureColumnsDialog d = new ConfigureColumnsDialog(this, vendorInfo
288
				.getTable());
289
		d.open();
290
	}
291
292
	/**
293
	 */
294
	private void handleSigningInfoPressed() {
295
		if (signingArea == null) {
296
			signingArea = new BundleSigningInfo();
297
			AboutBundleData bundleInfo = (AboutBundleData) ((IStructuredSelection) vendorInfo
298
					.getSelection()).getFirstElement();
299
			signingArea.setData(bundleInfo);
300
301
			signingArea.createContents(sashForm);
302
			sashForm.setWeights(new int[] { 100 - SIGNING_AREA_PERCENTAGE, SIGNING_AREA_PERCENTAGE });
303
			signingInfo
304
					.setText(WorkbenchMessages.AboutPluginsDialog_signingInfo_hide);
305
306
		} else {
307
			// hide
308
			signingInfo
309
					.setText(WorkbenchMessages.AboutPluginsDialog_signingInfo_show);
310
			signingArea.dispose();
311
			signingArea = null;
312
			sashForm.setWeights(new int[] { 100 });
313
		}
314
	}
315
316
	protected AbstractContributionFactory makeContributionFactory() {
317
		return new AbstractContributionFactory(getPageContainer()
318
				.getButtonBarURI(), null) {
319
320
			public void createContributionItems(IServiceLocator serviceLocator,
321
					IContributionRoot additions) {
322
				moreInfo = new Action(
323
						WorkbenchMessages.AboutPluginsDialog_moreInfo) {
324
					public void run() {
325
						handleMoreInfoPressed();
326
					}
327
				};
328
				moreInfo.setEnabled(false);
329
				additions.addContributionItem(new ActionContributionItem(
330
						moreInfo), null);
331
332
				signingInfo = new Action(
333
						WorkbenchMessages.AboutPluginsDialog_signingInfo_show) {
334
					public void run() {
335
						handleSigningInfoPressed();
336
					}
337
				};
338
				signingInfo.setEnabled(false);
339
				additions.addContributionItem(new ActionContributionItem(
340
						signingInfo), null);
341
342
				Action action = new Action(
343
						WorkbenchMessages.AboutPluginsDialog_columns) {
344
					public void run() {
345
						handleColumnsPressed();
346
					}
347
				};
348
				additions.addContributionItem(
349
						new ActionContributionItem(action), null);
350
			}
351
		};
352
	}
353
354
	protected Control createPageControl(Composite parent) {
355
		initializeDialogUnits(parent);
356
357
		// create a data object for each bundle, remove duplicates, and include
358
		// only resolved bundles (bug 65548)
359
		Map map = new HashMap();
360
		for (int i = 0; i < bundles.length; ++i) {
361
			AboutBundleData data = new AboutBundleData(bundles[i]);
362
			if (BundleUtility.isReady(data.getState())
363
					&& !map.containsKey(data.getVersionedId())) {
364
				map.put(data.getVersionedId(), data);
365
			}
366
		}
367
		bundleInfos = (AboutBundleData[]) map.values().toArray(
368
				new AboutBundleData[0]);
369
		WorkbenchPlugin.class.getSigners();
370
371
		sashForm = new SashForm(parent, SWT.HORIZONTAL | SWT.SMOOTH);
372
		FillLayout layout = new FillLayout();
373
		sashForm.setLayout(layout);
374
		layout.marginHeight = 0;
375
		layout.marginWidth = 0;
376
		GridData data = new GridData(GridData.FILL_BOTH);
377
		sashForm.setLayoutData(data);
378
379
		Composite outer = createOuterComposite(sashForm);
380
		PlatformUI.getWorkbench().getHelpSystem().setHelp(outer, helpContextId);
381
382
		if (message != null) {
383
			Label label = new Label(outer, SWT.NONE);
384
			label.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
385
			label.setFont(parent.getFont());
386
			label.setText(message);
387
		}
388
389
		createTable(outer);
390
		return outer;
391
	}
392
393
	/**
394
	 * Create the table part of the dialog.
395
	 * 
396
	 * @param parent
397
	 *            the parent composite to contain the dialog area
398
	 */
399
	protected void createTable(Composite parent) {
400
		vendorInfo = new TableViewer(parent, SWT.H_SCROLL | SWT.V_SCROLL
401
				| SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
402
		vendorInfo.setUseHashlookup(true);
403
		vendorInfo.getTable().setHeaderVisible(true);
404
		vendorInfo.getTable().setLinesVisible(true);
405
		vendorInfo.getTable().setFont(parent.getFont());
406
		vendorInfo.addSelectionChangedListener(new ISelectionChangedListener() {
407
408
			public void selectionChanged(SelectionChangedEvent event) {
409
				// enable if there is an item selected and that
410
				// item has additional info
411
				IStructuredSelection selection = (IStructuredSelection) event
412
						.getSelection();
413
				if (selection.getFirstElement() instanceof AboutBundleData) {
414
					AboutBundleData selected = (AboutBundleData) selection
415
							.getFirstElement();
416
					moreInfo.setEnabled(selectionHasInfo(selected));
417
					signingInfo.setEnabled(true);
418
					if (signingArea != null) {
419
						signingArea.setData(selected);
420
					}
421
				} else {
422
					moreInfo.setEnabled(false);
423
					signingInfo.setEnabled(false);
424
				}
425
			}
426
		});
427
428
		final TableComparator comparator = new TableComparator();
429
		vendorInfo.setComparator(comparator);
430
		int[] columnWidths = {
431
				convertHorizontalDLUsToPixels(30), // signature
432
				convertHorizontalDLUsToPixels(120),
433
				convertHorizontalDLUsToPixels(120),
434
				convertHorizontalDLUsToPixels(70),
435
				convertHorizontalDLUsToPixels(130), };
436
437
		// create table headers
438
		for (int i = 0; i < columnTitles.length; i++) {
439
			TableColumn column = new TableColumn(vendorInfo.getTable(),
440
					SWT.NULL);
441
			if (i == PLUGIN_NAME_COLUMN_INDEX) { // prime initial sorting
442
				updateTableSorting(i);
443
			}
444
			column.setWidth(columnWidths[i]);
445
			column.setText(columnTitles[i]);
446
			final int columnIndex = i;
447
			column.addSelectionListener(new SelectionAdapter() {
448
				public void widgetSelected(SelectionEvent e) {
449
					updateTableSorting(columnIndex);
450
				}
451
			});
452
		}
453
454
		vendorInfo.setContentProvider(new ArrayContentProvider());
455
		vendorInfo.setLabelProvider(new BundleTableLabelProvider());
456
457
		GridData gridData = new GridData(GridData.FILL, GridData.FILL, true,
458
				true);
459
		gridData.heightHint = convertVerticalDLUsToPixels(TABLE_HEIGHT);
460
		vendorInfo.getTable().setLayoutData(gridData);
461
462
		vendorInfo.setInput(bundleInfos);
463
	}
464
465
	/**
466
	 * Update the sort information on both the comparator and the table.
467
	 * 
468
	 * @param columnIndex
469
	 *            the index to sort by
470
	 * @since 3.4
471
	 */
472
	private void updateTableSorting(final int columnIndex) {
473
		TableComparator comparator = (TableComparator) vendorInfo
474
				.getComparator();
475
		// toggle direction if it's the same column
476
		if (columnIndex == comparator.getSortColumn()) {
477
			comparator.setAscending(!comparator.isAscending());
478
		}
479
		comparator.setSortColumn(columnIndex);
480
		vendorInfo.getTable().setSortColumn(
481
				vendorInfo.getTable().getColumn(columnIndex));
482
		vendorInfo.getTable().setSortDirection(
483
				comparator.isAscending() ? SWT.UP : SWT.DOWN);
484
		vendorInfo.refresh(false);
485
	}
486
487
	/**
488
	 * Check if the currently selected plugin has additional information to
489
	 * show.
490
	 * 
491
	 * @param bundleInfo
492
	 * 
493
	 * @return true if the selected plugin has additional info available to
494
	 *         display
495
	 */
496
	private boolean selectionHasInfo(AboutBundleData bundleInfo) {
497
498
		URL infoURL = getMoreInfoURL(bundleInfo, false);
499
500
		// only report ini problems if the -debug command line argument is used
501
		if (infoURL == null && WorkbenchPlugin.DEBUG) {
502
			WorkbenchPlugin.log("Problem reading plugin info for: " //$NON-NLS-1$
503
					+ bundleInfo.getName());
504
		}
505
506
		return infoURL != null;
507
	}
508
509
	/**
510
	 * The More Info button was pressed. Open a browser showing the license
511
	 * information for the selected bundle or an error dialog if the browser
512
	 * cannot be opened.
513
	 */
514
	protected void handleMoreInfoPressed() {
515
		if (vendorInfo == null) {
516
			return;
517
		}
518
519
		if (vendorInfo.getSelection().isEmpty())
520
			return;
521
522
		AboutBundleData bundleInfo = (AboutBundleData) ((IStructuredSelection) vendorInfo
523
				.getSelection()).getFirstElement();
524
525
		if (!AboutUtils.openBrowser(getShell(),
526
				getMoreInfoURL(bundleInfo, true))) {
527
			String message = NLS.bind(
528
					WorkbenchMessages.AboutPluginsDialog_unableToOpenFile,
529
					PLUGININFO, bundleInfo.getId());
530
			StatusUtil.handleStatus(
531
					WorkbenchMessages.AboutPluginsDialog_errorTitle
532
							+ ": " + message, StatusManager.SHOW, getShell()); //$NON-NLS-1$
533
		}
534
	}
535
536
	/**
537
	 * Return an url to the plugin's about.html file (what is shown when
538
	 * "More info" is pressed) or null if no such file exists. The method does
539
	 * nl lookup to allow for i18n.
540
	 * 
541
	 * @param bundleInfo
542
	 *            the bundle info
543
	 * @param makeLocal
544
	 *            whether to make the about content local
545
	 * @return the url or <code>null</code>
546
	 */
547
	private URL getMoreInfoURL(AboutBundleData bundleInfo, boolean makeLocal) {
548
		Bundle bundle = Platform.getBundle(bundleInfo.getId());
549
		if (bundle == null) {
550
			return null;
551
		}
552
553
		URL aboutUrl = Platform.find(bundle, baseNLPath.append(PLUGININFO),
554
				null);
555
		if (!makeLocal) {
556
			return aboutUrl;
557
		}
558
		if (aboutUrl != null) {
559
			try {
560
				URL result = Platform.asLocalURL(aboutUrl);
561
				try {
562
					// Make local all content in the "about" directory.
563
					// This is needed to handle jar'ed plug-ins.
564
					// See Bug 88240 [About] About dialog needs to extract
565
					// subdirs.
566
					URL about = new URL(aboutUrl, "about_files"); //$NON-NLS-1$
567
					if (about != null) {
568
						Platform.asLocalURL(about);
569
					}
570
				} catch (IOException e) {
571
					// skip the about dir if its not found or there are other
572
					// problems.
573
				}
574
				return result;
575
			} catch (IOException e) {
576
				// do nothing
577
			}
578
		}
579
		return null;
580
	}
581
582
	/*
583
	 * (non-Javadoc)
584
	 * 
585
	 * @see org.eclipse.ui.internal.about.ProductInfoPage#getId()
586
	 */
587
	String getId() {
588
		return ID;
589
	}
590
}
591
592
class TableComparator extends ViewerComparator {
593
594
	private int sortColumn = 0;
595
	private boolean ascending = true;
596
597
	/*
598
	 * (non-Javadoc)
599
	 * 
600
	 * @see
601
	 * org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.
602
	 * viewers.Viewer, java.lang.Object, java.lang.Object)
603
	 */
604
	public int compare(Viewer viewer, Object e1, Object e2) {
605
		if (sortColumn == 0 && e1 instanceof AboutBundleData
606
				&& e2 instanceof AboutBundleData) {
607
			AboutBundleData d1 = (AboutBundleData) e1;
608
			AboutBundleData d2 = (AboutBundleData) e2;
609
			int diff = getSignedSortValue(d1) - getSignedSortValue(d2);
610
			return ascending ? diff : -diff;
611
		}
612
		if (viewer instanceof TableViewer) {
613
			TableViewer tableViewer = (TableViewer) viewer;
614
			IBaseLabelProvider baseLabel = tableViewer.getLabelProvider();
615
			if (baseLabel instanceof ITableLabelProvider) {
616
				ITableLabelProvider tableProvider = (ITableLabelProvider) baseLabel;
617
				String e1p = tableProvider.getColumnText(e1, sortColumn);
618
				String e2p = tableProvider.getColumnText(e2, sortColumn);
619
				int result = getComparator().compare(e1p, e2p);
620
				return ascending ? result : (-1) * result;
621
			}
622
		}
623
624
		return super.compare(viewer, e1, e2);
625
	}
626
627
	/**
628
	 * @param data
629
	 * @return a sort value depending on the signed state
630
	 */
631
	private int getSignedSortValue(AboutBundleData data) {
632
		if (!data.isSignedDetermined()) {
633
			return 0;
634
		} else if (data.isSigned()) {
635
			return 1;
636
		} else {
637
			return -1;
638
		}
639
	}
640
641
	/**
642
	 * @return Returns the sortColumn.
643
	 */
644
	public int getSortColumn() {
645
		return sortColumn;
646
	}
647
648
	/**
649
	 * @param sortColumn
650
	 *            The sortColumn to set.
651
	 */
652
	public void setSortColumn(int sortColumn) {
653
		this.sortColumn = sortColumn;
654
	}
655
656
	/**
657
	 * @return Returns the ascending.
658
	 */
659
	public boolean isAscending() {
660
		return ascending;
661
	}
662
663
	/**
664
	 * @param ascending
665
	 *            The ascending to set.
666
	 */
667
	public void setAscending(boolean ascending) {
668
		this.ascending = ascending;
669
	}
670
}
(-)Eclipse (+303 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2007, 2009 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
12
package org.eclipse.ui.internal.about;
13
14
import java.io.IOException;
15
import java.security.GeneralSecurityException;
16
import java.security.cert.Certificate;
17
import java.security.cert.X509Certificate;
18
import java.text.DateFormat;
19
import java.util.ArrayList;
20
import java.util.Date;
21
import java.util.Iterator;
22
import java.util.List;
23
import java.util.Map;
24
import java.util.Properties;
25
import java.util.StringTokenizer;
26
import java.util.Map.Entry;
27
28
import org.eclipse.core.runtime.IProgressMonitor;
29
import org.eclipse.core.runtime.IStatus;
30
import org.eclipse.core.runtime.OperationCanceledException;
31
import org.eclipse.core.runtime.Status;
32
import org.eclipse.core.runtime.jobs.Job;
33
import org.eclipse.jface.dialogs.Dialog;
34
import org.eclipse.jface.resource.JFaceResources;
35
import org.eclipse.osgi.signedcontent.SignedContent;
36
import org.eclipse.osgi.signedcontent.SignedContentFactory;
37
import org.eclipse.osgi.signedcontent.SignerInfo;
38
import org.eclipse.osgi.util.NLS;
39
import org.eclipse.swt.SWT;
40
import org.eclipse.swt.custom.StyledText;
41
import org.eclipse.swt.graphics.GC;
42
import org.eclipse.swt.graphics.Point;
43
import org.eclipse.swt.layout.GridData;
44
import org.eclipse.swt.layout.GridLayout;
45
import org.eclipse.swt.widgets.Composite;
46
import org.eclipse.swt.widgets.Control;
47
import org.eclipse.swt.widgets.Label;
48
import org.eclipse.swt.widgets.Text;
49
import org.eclipse.ui.PlatformUI;
50
import org.eclipse.ui.internal.WorkbenchMessages;
51
import org.eclipse.ui.internal.WorkbenchPlugin;
52
import org.eclipse.ui.statushandlers.StatusManager;
53
import org.osgi.framework.BundleContext;
54
import org.osgi.framework.ServiceReference;
55
56
/**
57
 * @since 3.3
58
 * 
59
 */
60
public class BundleSigningInfo {
61
62
	private Composite composite;
63
	private Text date;
64
	private StyledText certificate;
65
	private AboutBundleData data;
66
67
	public BundleSigningInfo() {
68
	}
69
70
	public void setData(AboutBundleData data) {
71
		this.data = data;
72
		startJobs();
73
	}
74
75
	public Control createContents(Composite parent) {
76
77
		composite = new Composite(parent, SWT.BORDER);
78
		composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
79
		GridLayout layout = new GridLayout(2, false);
80
		layout.marginHeight = 0;
81
		layout.marginWidth = 0;
82
		composite.setLayout(layout);
83
84
		// date
85
		{
86
			Label label = new Label(composite, SWT.NONE);
87
			label.setText(WorkbenchMessages.BundleSigningTray_Signing_Date);
88
			GridData data = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
89
			date = new Text(composite, SWT.READ_ONLY);
90
			GC gc = new GC(date);
91
			gc.setFont(JFaceResources.getDialogFont());
92
			Point size = gc.stringExtent(DateFormat.getDateTimeInstance()
93
					.format(new Date()));
94
			data.widthHint = size.x;
95
			gc.dispose();
96
			date.setText(WorkbenchMessages.BundleSigningTray_Working);
97
			date.setLayoutData(data);
98
		}
99
		// signer
100
		{
101
			Label label = new Label(composite, SWT.NONE);
102
			label
103
					.setText(WorkbenchMessages.BundleSigningTray_Signing_Certificate);
104
			GridData data = new GridData(SWT.BEGINNING, SWT.BEGINNING, true,
105
					false);
106
			data.horizontalSpan = 2;
107
			data = new GridData(SWT.FILL, SWT.FILL, true, true);
108
			data.horizontalSpan = 2;
109
			certificate = new StyledText(composite, SWT.READ_ONLY | SWT.MULTI
110
					| SWT.WRAP);
111
			certificate.setText(WorkbenchMessages.BundleSigningTray_Working);
112
			certificate.setLayoutData(data);
113
		}
114
		Dialog.applyDialogFont(composite);
115
116
		startJobs(); // start the jobs that will prime the content
117
		return composite;
118
	}
119
120
	/**
121
	 * 
122
	 */
123
	private void startJobs() {
124
		if (!isOpen())
125
			return;
126
		certificate.setText(WorkbenchMessages.BundleSigningTray_Working);
127
		date.setText(WorkbenchMessages.BundleSigningTray_Working);
128
		final BundleContext bundleContext = WorkbenchPlugin.getDefault()
129
				.getBundleContext();
130
		final ServiceReference factoryRef = bundleContext
131
				.getServiceReference(SignedContentFactory.class.getName());
132
		if (factoryRef == null) {
133
			StatusManager
134
					.getManager()
135
					.handle(
136
							new Status(
137
									IStatus.WARNING,
138
									WorkbenchPlugin.PI_WORKBENCH,
139
									WorkbenchMessages.BundleSigningTray_Cant_Find_Service),
140
							StatusManager.LOG);
141
			return;
142
		}
143
144
		final SignedContentFactory contentFactory = (SignedContentFactory) bundleContext
145
				.getService(factoryRef);
146
		if (contentFactory == null) {
147
			StatusManager
148
					.getManager()
149
					.handle(
150
							new Status(
151
									IStatus.WARNING,
152
									WorkbenchPlugin.PI_WORKBENCH,
153
									WorkbenchMessages.BundleSigningTray_Cant_Find_Service),
154
							StatusManager.LOG);
155
			return;
156
		}
157
158
		final AboutBundleData myData = data;
159
		final Job signerJob = new Job(NLS.bind(
160
				WorkbenchMessages.BundleSigningTray_Determine_Signer_For,
161
				myData.getId())) {
162
163
			protected IStatus run(IProgressMonitor monitor) {
164
				try {
165
					if (myData != data)
166
						return Status.OK_STATUS;
167
					SignedContent signedContent = contentFactory
168
							.getSignedContent(myData.getBundle());
169
					if (myData != data)
170
						return Status.OK_STATUS;
171
					SignerInfo[] signers = signedContent.getSignerInfos();
172
					final String signerText, dateText;
173
					if (!isOpen() && BundleSigningInfo.this.data == myData)
174
						return Status.OK_STATUS;
175
176
					if (signers.length == 0) {
177
						signerText = WorkbenchMessages.BundleSigningTray_Unsigned;
178
						dateText = WorkbenchMessages.BundleSigningTray_Unsigned;
179
					} else {
180
						Properties[] certs = parseCerts(signers[0]
181
								.getCertificateChain());
182
						if (certs.length == 0)
183
							signerText = WorkbenchMessages.BundleSigningTray_Unknown;
184
						else {
185
							StringBuffer buffer = new StringBuffer();
186
							for (Iterator i = certs[0].entrySet().iterator(); i
187
									.hasNext();) {
188
								Map.Entry entry = (Entry) i.next();
189
								buffer.append(entry.getKey());
190
								buffer.append('=');
191
								buffer.append(entry.getValue());
192
								if (i.hasNext())
193
									buffer.append('\n');
194
							}
195
							signerText = buffer.toString();
196
						}
197
198
						Date signDate = signedContent
199
								.getSigningTime(signers[0]);
200
						if (signDate != null)
201
							dateText = DateFormat.getDateTimeInstance().format(
202
									signDate);
203
						else
204
							dateText = WorkbenchMessages.BundleSigningTray_Unknown;
205
					}
206
207
					PlatformUI.getWorkbench().getDisplay().asyncExec(
208
							new Runnable() {
209
								public void run() {
210
									// check to see if the tray is still visible
211
									// and if
212
									// we're still looking at the same item
213
									if (!isOpen()
214
											&& BundleSigningInfo.this.data != myData)
215
										return;
216
									certificate.setText(signerText);
217
									date.setText(dateText);
218
								}
219
							});
220
221
				} catch (IOException e) {
222
					return new Status(IStatus.ERROR,
223
							WorkbenchPlugin.PI_WORKBENCH, e.getMessage(), e);
224
				} catch (GeneralSecurityException e) {
225
					return new Status(IStatus.ERROR,
226
							WorkbenchPlugin.PI_WORKBENCH, e.getMessage(), e);
227
				}
228
				return Status.OK_STATUS;
229
			}
230
		};
231
		signerJob.setSystem(true);
232
		signerJob.belongsTo(signerJob);
233
		signerJob.schedule();
234
235
		Job cleanup = new Job(
236
				WorkbenchMessages.BundleSigningTray_Unget_Signing_Service) {
237
238
			protected IStatus run(IProgressMonitor monitor) {
239
				try {
240
					getJobManager().join(signerJob, monitor);
241
				} catch (OperationCanceledException e) {
242
				} catch (InterruptedException e) {
243
				}
244
				bundleContext.ungetService(factoryRef);
245
				return Status.OK_STATUS;
246
			}
247
		};
248
		cleanup.setSystem(true);
249
		cleanup.schedule();
250
251
	}
252
253
	/**
254
	 * 
255
	 */
256
	private boolean isOpen() {
257
		return certificate != null && !certificate.isDisposed();
258
	}
259
260
	private Properties[] parseCerts(Certificate[] chain) {
261
		List certs = new ArrayList(chain.length);
262
		for (int i = 0; i < chain.length; i++) {
263
			if (!(chain[i] instanceof X509Certificate))
264
				continue;
265
			Map cert = parseCert(((X509Certificate) chain[i]).getSubjectDN()
266
					.getName());
267
			if (cert != null)
268
				certs.add(cert);
269
		}
270
		return (Properties[]) certs.toArray(new Properties[certs.size()]);
271
272
	}
273
274
	/**
275
	 * @param certString
276
	 * @return
277
	 */
278
	private Properties parseCert(String certString) {
279
		StringTokenizer toker = new StringTokenizer(certString, ","); //$NON-NLS-1$
280
		Properties cert = new Properties();
281
		while (toker.hasMoreTokens()) {
282
			String pair = toker.nextToken();
283
			int idx = pair.indexOf('=');
284
			if (idx > 0 && idx < pair.length() - 2) {
285
				String key = pair.substring(0, idx).trim();
286
				String value = pair.substring(idx + 1).trim();
287
				if (value.length() > 2) {
288
					if (value.charAt(0) == '\"')
289
						value = value.substring(1);
290
291
					if (value.charAt(value.length() - 1) == '\"')
292
						value = value.substring(0, value.length() - 1);
293
				}
294
				cert.setProperty(key, value);
295
			}
296
		}
297
		return cert;
298
	}
299
300
	public void dispose() {
301
		composite.dispose();
302
	}
303
}
(-)Eclipse (+181 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2003, 2009 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.ui.internal.about;
12
13
import java.io.File;
14
import java.io.FileNotFoundException;
15
import java.io.FileReader;
16
import java.io.FileWriter;
17
import java.io.IOException;
18
19
import org.eclipse.core.runtime.IPath;
20
import org.eclipse.core.runtime.Platform;
21
import org.eclipse.jface.action.Action;
22
import org.eclipse.jface.action.ActionContributionItem;
23
import org.eclipse.jface.dialogs.MessageDialog;
24
import org.eclipse.jface.resource.JFaceResources;
25
import org.eclipse.osgi.util.NLS;
26
import org.eclipse.swt.SWT;
27
import org.eclipse.swt.layout.GridData;
28
import org.eclipse.swt.widgets.Composite;
29
import org.eclipse.swt.widgets.Control;
30
import org.eclipse.swt.widgets.Text;
31
import org.eclipse.ui.PlatformUI;
32
import org.eclipse.ui.internal.ConfigurationInfo;
33
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
34
import org.eclipse.ui.internal.WorkbenchMessages;
35
import org.eclipse.ui.internal.WorkbenchPlugin;
36
import org.eclipse.ui.menus.AbstractContributionFactory;
37
import org.eclipse.ui.menus.IContributionRoot;
38
import org.eclipse.ui.services.IServiceLocator;
39
40
/**
41
 * Displays system information about the eclipse application. The content of
42
 * what is displayed is selectable through the
43
 * <code>org.eclipse.ui.systemSummaryExtensions</code> extension point.
44
 */
45
public final class AboutSystemPage extends ProductInfoPage {
46
	
47
	private final static String ERROR_LOG_COPY_FILENAME = "log"; //$NON-NLS-1$
48
	// This id should *not* be the same id used for contributing the page in
49
	// the installationPage extension.  It is used by ProductInfoDialog 
50
	// to ensure a different namespace for button contributions than the id 
51
	// for the page appearing in the InstallationDialog
52
	private static final String ID = "productInfo.system"; //$NON-NLS-1$
53
	
54
	private Text text;
55
56
	protected Control createPageControl(Composite parent) {
57
		PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
58
				IWorkbenchHelpContextIds.SYSTEM_SUMMARY_DIALOG);
59
60
		Composite outer = createOuterComposite(parent);
61
62
		text = new Text(outer, SWT.MULTI | SWT.BORDER | SWT.READ_ONLY
63
				| SWT.V_SCROLL | SWT.NO_FOCUS | SWT.H_SCROLL);
64
		text.setBackground(parent.getDisplay().getSystemColor(
65
				SWT.COLOR_LIST_BACKGROUND));
66
		GridData gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL
67
				| GridData.VERTICAL_ALIGN_FILL);
68
		gridData.grabExcessVerticalSpace = true;
69
		gridData.grabExcessHorizontalSpace = true;
70
		gridData.heightHint = convertVerticalDLUsToPixels(300);
71
		gridData.widthHint = convertHorizontalDLUsToPixels(400);
72
		text.setLayoutData(gridData);
73
		text.setText(ConfigurationInfo.getSystemSummary());
74
		text.setFont(JFaceResources.getTextFont());
75
		return outer;
76
	}
77
78
	protected AbstractContributionFactory makeContributionFactory() {
79
		return new AbstractContributionFactory(
80
				getPageContainer().getButtonBarURI(), null) {
81
82
			public void createContributionItems(IServiceLocator serviceLocator,
83
					IContributionRoot additions) {
84
				Action action = new Action(
85
						WorkbenchMessages.AboutSystemDialog_browseErrorLogName) {
86
					public void run() {
87
						openErrorLogBrowser();
88
					}
89
				};
90
				String filename = Platform.getLogFileLocation().toOSString();
91
				action.setEnabled(new File(filename).exists());
92
				additions.addContributionItem(
93
						new ActionContributionItem(action), null);
94
			}
95
		};
96
	}
97
98
	private void openErrorLogBrowser() {
99
		String filename = Platform.getLogFileLocation().toOSString();
100
101
		File log = new File(filename);
102
		if (log.exists()) {
103
			// Make a copy of the file with a temporary name.
104
			// Working around an issue with windows file associations/browser
105
			// malfunction whereby the browser doesn't open on ".log" and we 
106
			// aren't returned an error.
107
			// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=97783
108
			File logCopy = makeDisplayCopy(log);
109
			if (logCopy != null) {
110
				AboutUtils.openLink(getShell(), "file:///" + logCopy.getAbsolutePath()); //$NON-NLS-1$
111
				return;
112
			}
113
			// Couldn't make copy, try to open the original log.
114
			// We try the original in this case rather than putting up an error,
115
			// because the copy could fail due to an I/O or out of space
116
			// problem.
117
			// In that case we may still be able to show the original log,
118
			// depending on the platform. The risk is that users with
119
			// configurations that have bug #97783 will still get nothing 
120
			// (vs. an error) but we'd rather
121
			// try again than put up an error dialog on platforms where the
122
			// ability to view the original log works just fine.
123
			AboutUtils.openLink(getShell(), "file:///" + filename); //$NON-NLS-1$
124
			return;
125
		}
126
		MessageDialog.openInformation(getShell(),
127
				WorkbenchMessages.AboutSystemDialog_noLogTitle, NLS.bind(
128
						WorkbenchMessages.AboutSystemDialog_noLogMessage,
129
						filename));
130
	}
131
132
	/**
133
	 * Returns a copy of the given file to be used for display in a browser.
134
	 * 
135
	 * @return the file, or <code>null</code>
136
	 */
137
	private File makeDisplayCopy(File file) {
138
		IPath path = WorkbenchPlugin.getDefault().getDataLocation();
139
		if (path == null) {
140
			return null;
141
		}
142
		path = path.append(ERROR_LOG_COPY_FILENAME);
143
		File copy = path.toFile();
144
		FileReader in = null;
145
		FileWriter out = null;
146
		try {
147
			in = new FileReader(file);
148
			// don't append data, overwrite what was there
149
			out = new FileWriter(copy);
150
			char buffer[] = new char[4096];
151
			int count;
152
			while ((count = in.read(buffer, 0, buffer.length)) > 0) {
153
				out.write(buffer, 0, count);
154
			}
155
		} catch (FileNotFoundException e) {
156
			return null;
157
		} catch (IOException e) {
158
			return null;
159
		} finally {
160
			try {
161
				if (in != null) {
162
					in.close();
163
				}
164
				if (out != null) {
165
					out.close();
166
				}
167
			} catch (IOException e) {
168
				return null;
169
			}
170
		}
171
		return copy;
172
173
	}
174
175
	/* (non-Javadoc)
176
	 * @see org.eclipse.ui.internal.about.ProductInfoPage#getId()
177
	 */
178
	String getId() {
179
		return ID;
180
	}
181
}
(-)Eclipse (+522 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2008 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
 *  	Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog
11
 *      font should be activated and used by other components.
12
 *******************************************************************************/
13
package org.eclipse.ui.internal.about;
14
15
import java.io.File;
16
import java.util.HashMap;
17
import java.util.Iterator;
18
import java.util.LinkedList;
19
import java.util.Map;
20
21
import org.eclipse.core.runtime.IBundleGroup;
22
import org.eclipse.core.runtime.IBundleGroupProvider;
23
import org.eclipse.core.runtime.Platform;
24
import org.eclipse.jface.action.Action;
25
import org.eclipse.jface.action.ActionContributionItem;
26
import org.eclipse.jface.dialogs.MessageDialog;
27
import org.eclipse.jface.internal.ConfigureColumnsDialog;
28
import org.eclipse.jface.resource.ImageDescriptor;
29
import org.eclipse.osgi.util.NLS;
30
import org.eclipse.swt.SWT;
31
import org.eclipse.swt.custom.StyledText;
32
import org.eclipse.swt.events.DisposeEvent;
33
import org.eclipse.swt.events.DisposeListener;
34
import org.eclipse.swt.events.SelectionAdapter;
35
import org.eclipse.swt.events.SelectionEvent;
36
import org.eclipse.swt.graphics.Font;
37
import org.eclipse.swt.graphics.Image;
38
import org.eclipse.swt.layout.GridData;
39
import org.eclipse.swt.layout.GridLayout;
40
import org.eclipse.swt.widgets.Composite;
41
import org.eclipse.swt.widgets.Control;
42
import org.eclipse.swt.widgets.Label;
43
import org.eclipse.swt.widgets.Table;
44
import org.eclipse.swt.widgets.TableColumn;
45
import org.eclipse.swt.widgets.TableItem;
46
import org.eclipse.ui.PlatformUI;
47
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
48
import org.eclipse.ui.internal.WorkbenchMessages;
49
import org.eclipse.ui.internal.dialogs.AboutPluginsDialog;
50
import org.eclipse.ui.menus.AbstractContributionFactory;
51
import org.eclipse.ui.menus.IContributionRoot;
52
import org.eclipse.ui.services.IServiceLocator;
53
import org.osgi.framework.Bundle;
54
55
/**
56
 * Displays information about the product plugins.
57
 * 
58
 * PRIVATE This class is internal to the workbench and must not be called
59
 * outside the workbench.
60
 */
61
public class AboutFeaturesPage extends ProductInfoPage {
62
63
	// This id should *not* be the same id used for contributing the page in
64
	// the installationPage extension.  It is used by ProductInfoDialog 
65
	// to ensure a different namespace for button contributions than the id 
66
	// for the page appearing in the InstallationDialog
67
	private static final String ID = "productInfo.features"; //$NON-NLS-1$
68
	/**
69
	 * Table height in dialog units (value 150).
70
	 */
71
	private static final int TABLE_HEIGHT = 150;
72
73
	private static final int INFO_HEIGHT = 100;
74
75
	private Table table;
76
77
	private Label imageLabel;
78
79
	private StyledText text;
80
	
81
	private AboutTextManager textManager;
82
83
	private Composite infoArea;
84
85
	private Map cachedImages = new HashMap();
86
87
	private AboutBundleGroupData[] bundleGroupInfos;
88
89
	private String columnTitles[] = {
90
			WorkbenchMessages.AboutFeaturesDialog_provider,
91
			WorkbenchMessages.AboutFeaturesDialog_featureName,
92
			WorkbenchMessages.AboutFeaturesDialog_version,
93
			WorkbenchMessages.AboutFeaturesDialog_featureId, };
94
95
	private int lastColumnChosen = 0; // initially sort by provider
96
97
	private boolean reverseSort = false; // initially sort ascending
98
99
	private AboutBundleGroupData lastSelection = null;
100
101
	private Action moreAction;
102
103
	private Action pluginsAction;
104
105
	private static Map featuresMap;
106
107
	public void setBundleGroupInfos(AboutBundleGroupData[] bundleGroupInfos) {
108
		this.bundleGroupInfos = bundleGroupInfos;
109
	}
110
	
111
	String getId() {
112
		return ID;
113
	}
114
115
	private void initializeBundleGroupInfos() {
116
		if (bundleGroupInfos == null) {
117
			IBundleGroupProvider[] providers = Platform
118
					.getBundleGroupProviders();
119
120
			// create a descriptive object for each BundleGroup
121
			LinkedList groups = new LinkedList();
122
			if (providers != null) {
123
				for (int i = 0; i < providers.length; ++i) {
124
					IBundleGroup[] bundleGroups = providers[i]
125
							.getBundleGroups();
126
					for (int j = 0; j < bundleGroups.length; ++j) {
127
						groups.add(new AboutBundleGroupData(bundleGroups[j]));
128
					}
129
				}
130
			}
131
			bundleGroupInfos = (AboutBundleGroupData[]) groups
132
					.toArray(new AboutBundleGroupData[0]);
133
		} else {
134
			// the order of the array may be changed due to sorting, so create a
135
			// copy, since the client set this value.
136
			AboutBundleGroupData[] clientArray = bundleGroupInfos;
137
			bundleGroupInfos = new AboutBundleGroupData[clientArray.length];
138
			System.arraycopy(clientArray, 0, bundleGroupInfos, 0,
139
					clientArray.length);
140
		}
141
		AboutData.sortByProvider(reverseSort, bundleGroupInfos);
142
	}
143
144
	/**
145
	 * The More Info button was pressed. Open a browser with the license for the
146
	 * selected item or an information dialog if there is no license, or the
147
	 * browser cannot be opened.
148
	 */
149
	private void handleMoreInfoPressed() {
150
		TableItem[] items = table.getSelection();
151
		if (items.length <= 0) {
152
			return;
153
		}
154
155
		AboutBundleGroupData info = (AboutBundleGroupData) items[0].getData();
156
		if (info == null || !AboutUtils.openBrowser(getShell(), info.getLicenseUrl())) {
157
			MessageDialog.openInformation(getShell(),
158
					WorkbenchMessages.AboutFeaturesDialog_noInfoTitle,
159
					WorkbenchMessages.AboutFeaturesDialog_noInformation);
160
		}
161
	}
162
163
	/**
164
	 * The Plugins button was pressed. Open an about dialog on the plugins for
165
	 * the selected feature.
166
	 */
167
	private void handlePluginInfoPressed() {
168
		TableItem[] items = table.getSelection();
169
		if (items.length <= 0) {
170
			return;
171
		}
172
173
		AboutBundleGroupData info = (AboutBundleGroupData) items[0].getData();
174
		IBundleGroup bundleGroup = info.getBundleGroup();
175
		Bundle[] bundles = bundleGroup == null ? new Bundle[0] : bundleGroup
176
				.getBundles();
177
178
		AboutPluginsDialog d = new AboutPluginsDialog(
179
				getShell(),
180
				getProductName(),
181
				bundles,
182
				WorkbenchMessages.AboutFeaturesDialog_pluginInfoTitle,
183
				NLS
184
						.bind(
185
								WorkbenchMessages.AboutFeaturesDialog_pluginInfoMessage,
186
								bundleGroup.getIdentifier()),
187
				IWorkbenchHelpContextIds.ABOUT_FEATURES_PLUGINS_DIALOG);
188
		d.open();
189
	}
190
191
	/**
192
	 * 
193
	 */
194
	private void handleColumnsPressed() {
195
		ConfigureColumnsDialog d = new ConfigureColumnsDialog(this, table);
196
		d.open();
197
	}
198
199
	protected AbstractContributionFactory makeContributionFactory() {
200
		return new AbstractContributionFactory(
201
				getPageContainer().getButtonBarURI(), null) {
202
203
			public void createContributionItems(IServiceLocator serviceLocator,
204
					IContributionRoot additions) {
205
				moreAction = new Action(
206
						WorkbenchMessages.AboutFeaturesDialog_moreInfo) {
207
					public void run() {
208
						handleMoreInfoPressed();
209
					}
210
				};
211
				additions.addContributionItem(new ActionContributionItem(
212
						moreAction), null);
213
214
				String filename = Platform.getLogFileLocation().toOSString();
215
				moreAction.setEnabled(new File(filename).exists());
216
217
				pluginsAction = new Action(
218
						WorkbenchMessages.AboutFeaturesDialog_pluginsInfo) {
219
					public void run() {
220
						handlePluginInfoPressed();
221
					}
222
				};
223
				additions.addContributionItem(new ActionContributionItem(
224
						pluginsAction), null);
225
226
				Action action = new Action(
227
						WorkbenchMessages.AboutFeaturesDialog_columns) {
228
					public void run() {
229
						handleColumnsPressed();
230
					}
231
				};
232
				additions.addContributionItem(
233
						new ActionContributionItem(action), null);
234
			}
235
		};
236
	}
237
238
	protected Control createPageControl(Composite parent) {
239
		initializeDialogUnits(parent);
240
		parent.getShell().addDisposeListener(new DisposeListener() {
241
			public void widgetDisposed(DisposeEvent arg0) {
242
				disposeImages();
243
			}
244
		});
245
		PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
246
				IWorkbenchHelpContextIds.ABOUT_FEATURES_DIALOG);
247
248
		Composite outer = createOuterComposite(parent);
249
250
		createTable(outer);
251
		createInfoArea(outer);
252
		return outer;
253
	}
254
255
	/**
256
	 * Create the info area containing the image and text
257
	 */
258
	protected void createInfoArea(Composite parent) {
259
		Font font = parent.getFont();
260
261
		infoArea = new Composite(parent, SWT.NULL);
262
		GridData data = new GridData(GridData.FILL, GridData.FILL, true, true);
263
		// need to provide space for arbitrary feature infos, not just the
264
		// one selected by default
265
		data.heightHint = convertVerticalDLUsToPixels(INFO_HEIGHT);
266
		infoArea.setLayoutData(data);
267
268
		GridLayout layout = new GridLayout();
269
		layout.numColumns = 2;
270
		infoArea.setLayout(layout);
271
272
		imageLabel = new Label(infoArea, SWT.NONE);
273
		data = new GridData(GridData.FILL, GridData.BEGINNING, false, false);
274
		data.widthHint = 32;
275
		data.heightHint = 32;
276
		imageLabel.setLayoutData(data);
277
		imageLabel.setFont(font);
278
279
		// text on the right
280
		text = new StyledText(infoArea, SWT.MULTI | SWT.WRAP | SWT.READ_ONLY);
281
		text.setCaret(null);
282
		text.setFont(parent.getFont());
283
		data = new GridData(GridData.FILL, GridData.FILL, true, true);
284
		text.setLayoutData(data);
285
		text.setFont(font);
286
		text.setCursor(null);
287
288
		textManager = new AboutTextManager(text);
289
290
		TableItem[] items = table.getSelection();
291
		if (items.length > 0) {
292
			updateInfoArea((AboutBundleGroupData) items[0].getData());
293
		}
294
	}
295
296
	/**
297
	 * Create the table part of the dialog.
298
	 * 
299
	 * @param parent
300
	 *            the parent composite to contain the dialog area
301
	 */
302
	protected void createTable(Composite parent) {
303
304
		initializeBundleGroupInfos();
305
306
		table = new Table(parent, SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE
307
				| SWT.FULL_SELECTION | SWT.BORDER);
308
309
		GridData gridData = new GridData(GridData.FILL, GridData.FILL, true,
310
				true);
311
		gridData.heightHint = convertVerticalDLUsToPixels(TABLE_HEIGHT);
312
		table.setLayoutData(gridData);
313
		table.setHeaderVisible(true);
314
315
		table.setLinesVisible(true);
316
		table.setFont(parent.getFont());
317
		table.addSelectionListener(new SelectionAdapter() {
318
			public void widgetSelected(SelectionEvent e) {
319
				AboutBundleGroupData info = (AboutBundleGroupData) e.item
320
						.getData();
321
				updateInfoArea(info);
322
				updateButtons(info);
323
			}
324
		});
325
326
		int[] columnWidths = { convertHorizontalDLUsToPixels(120),
327
				convertHorizontalDLUsToPixels(120),
328
				convertHorizontalDLUsToPixels(70),
329
				convertHorizontalDLUsToPixels(130) };
330
331
		for (int i = 0; i < columnTitles.length; i++) {
332
			TableColumn tableColumn = new TableColumn(table, SWT.NULL);
333
			tableColumn.setWidth(columnWidths[i]);
334
			tableColumn.setText(columnTitles[i]);
335
			final int columnIndex = i;
336
			tableColumn.addSelectionListener(new SelectionAdapter() {
337
				public void widgetSelected(SelectionEvent e) {
338
					sort(columnIndex);
339
				}
340
			});
341
		}
342
343
		// create a table row for each bundle group
344
		String selId = lastSelection == null ? null : lastSelection.getId();
345
		int sel = 0;
346
		for (int i = 0; i < bundleGroupInfos.length; i++) {
347
			if (bundleGroupInfos[i].getId().equals(selId)) {
348
				sel = i;
349
			}
350
351
			TableItem item = new TableItem(table, SWT.NULL);
352
			item.setText(createRow(bundleGroupInfos[i]));
353
			item.setData(bundleGroupInfos[i]);
354
		}
355
356
		// if an item was specified during construction, it should be
357
		// selected when the table is created
358
		if (bundleGroupInfos.length > 0) {
359
			table.setSelection(sel);
360
			table.showSelection();
361
		}
362
	}
363
364
	private void disposeImages() {
365
		Iterator iter = cachedImages.values().iterator();
366
		while (iter.hasNext()) {
367
			Image image = (Image) iter.next();
368
			image.dispose();
369
		}
370
	}
371
372
	/**
373
	 * Update the button enablement
374
	 */
375
	private void updateButtons(AboutBundleGroupData info) {
376
		// called too early
377
		if (moreAction == null || pluginsAction == null)
378
			return;
379
		
380
		if (info == null) {
381
			moreAction.setEnabled(false);
382
			pluginsAction.setEnabled(false);
383
			return;
384
		}
385
386
		// Creating the feature map is too much just to determine enablement, so
387
		// if doesn't already exist, just enable the buttons. If this was the
388
		// wrong choice, then when the button is actually pressed an dialog will be
389
		// opened.
390
		if (featuresMap == null) {
391
			moreAction.setEnabled(true);
392
			pluginsAction.setEnabled(true);
393
			return;
394
		}
395
396
		moreAction.setEnabled(info.getLicenseUrl() != null);
397
		pluginsAction.setEnabled(true);
398
	}
399
400
	/**
401
	 * Update the info area
402
	 */
403
	private void updateInfoArea(AboutBundleGroupData info) {
404
		if (info == null) {
405
			imageLabel.setImage(null);
406
			text.setText(""); //$NON-NLS-1$
407
			return;
408
		}
409
410
		ImageDescriptor desc = info.getFeatureImage();
411
		Image image = (Image) cachedImages.get(desc);
412
		if (image == null && desc != null) {
413
			image = desc.createImage();
414
			cachedImages.put(desc, image);
415
		}
416
		imageLabel.setImage(image);
417
418
		String aboutText = info.getAboutText();
419
		textManager.setItem(null);
420
		if (aboutText != null) {
421
			textManager.setItem(AboutUtils.scan(aboutText));
422
		}
423
424
		if (textManager.getItem() == null) {
425
			text.setText(WorkbenchMessages.AboutFeaturesDialog_noInformation);
426
		}
427
	}
428
429
	/**
430
	 * Select the initial selection
431
	 * 
432
	 * @param info
433
	 *            the info
434
	 */
435
	public void setInitialSelection(AboutBundleGroupData info) {
436
		lastSelection = info;
437
	}
438
439
	/**
440
	 * Sort the rows of the table based on the selected column.
441
	 * 
442
	 * @param column
443
	 *            index of table column selected as sort criteria
444
	 */
445
	private void sort(int column) {
446
		if (lastColumnChosen == column) {
447
			reverseSort = !reverseSort;
448
		} else {
449
			reverseSort = false;
450
			lastColumnChosen = column;
451
		}
452
453
		if (table.getItemCount() <= 1) {
454
			return;
455
		}
456
457
		// Remember the last selection
458
		int sel = table.getSelectionIndex();
459
		if (sel != -1) {
460
			lastSelection = bundleGroupInfos[sel];
461
		}
462
463
		switch (column) {
464
		case 0:
465
			AboutData.sortByProvider(reverseSort, bundleGroupInfos);
466
			break;
467
		case 1:
468
			AboutData.sortByName(reverseSort, bundleGroupInfos);
469
			break;
470
		case 2:
471
			AboutData.sortByVersion(reverseSort, bundleGroupInfos);
472
			break;
473
		case 3:
474
			AboutData.sortById(reverseSort, bundleGroupInfos);
475
			break;
476
		}
477
478
		refreshTable();
479
	}
480
481
	/**
482
	 * Refresh the rows of the table based on the selected column. Maintain
483
	 * selection from before sort action request.
484
	 */
485
	private void refreshTable() {
486
		TableItem[] items = table.getItems();
487
488
		// create new order of table items
489
		for (int i = 0; i < items.length; i++) {
490
			items[i].setText(createRow(bundleGroupInfos[i]));
491
			items[i].setData(bundleGroupInfos[i]);
492
		}
493
494
		// Maintain the original selection
495
		int sel = -1;
496
		if (lastSelection != null) {
497
			String oldId = lastSelection.getId();
498
			for (int k = 0; k < bundleGroupInfos.length; k++) {
499
				if (oldId.equalsIgnoreCase(bundleGroupInfos[k].getId())) {
500
					sel = k;
501
				}
502
			}
503
504
			table.setSelection(sel);
505
			table.showSelection();
506
		}
507
508
		updateInfoArea(lastSelection);
509
	}
510
511
	/**
512
	 * Return an array of strings containing the argument's information in the
513
	 * proper order for this table's columns.
514
	 * 
515
	 * @param info
516
	 *            the source information for the new row, must not be null
517
	 */
518
	private static String[] createRow(AboutBundleGroupData info) {
519
		return new String[] { info.getProviderName(), info.getName(),
520
				info.getVersion(), info.getId() };
521
	}
522
}
(-)plugin.xml (-10 / +1 lines)
Lines 107-121 Link Here
107
            </command>
107
            </command>
108
                        
108
                        
109
      </menuContribution>
109
      </menuContribution>
110
      <menuContribution
111
            locationURI="menu:help?after=org.eclipse.equinox.p2.ui.sdk.install">
112
            <command
113
                  commandId="org.eclipse.ui.help.installationDialog"
114
            	  mnemonic="%TempInstallView.mnemonic"
115
                  id="org.eclipse.equinox.p2.ui.sdk.tempInstallInfo">
116
            </command>
117
                        
118
      </menuContribution>
119
   </extension>
110
   </extension>
120
   <extension
111
   <extension
121
         point="org.eclipse.ui.activities">
112
         point="org.eclipse.ui.activities">
Lines 153-159 Link Here
153
          <page
144
          <page
154
            name="%installedSoftwarePage"
145
            name="%installedSoftwarePage"
155
            class="org.eclipse.equinox.internal.provisional.p2.ui.dialogs.InstalledSoftwarePage"
146
            class="org.eclipse.equinox.internal.provisional.p2.ui.dialogs.InstalledSoftwarePage"
156
            id="org.eclipse.equinox.internal.p2.ui.sdk.InstalledSoftwarePage">
147
            id="10.org.eclipse.equinox.internal.p2.ui.sdk.InstalledSoftwarePage">
157
          </page>
148
          </page>
158
          <page
149
          <page
159
            name="%installHistoryPage"
150
            name="%installHistoryPage"
(-)src/org/eclipse/equinox/internal/provisional/p2/ui/dialogs/InstalledSoftwarePage.java (+1 lines)
Lines 98-103 Link Here
98
98
99
		detailsArea = new Text(group, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY | SWT.WRAP);
99
		detailsArea = new Text(group, SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL | SWT.READ_ONLY | SWT.WRAP);
100
		detailsArea.setLayoutData(gd);
100
		detailsArea.setLayoutData(gd);
101
		detailsArea.setBackground(detailsArea.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
101
102
102
		setControl(composite);
103
		setControl(composite);
103
	}
104
	}

Return to bug 246875