KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > intro > config > CustomizableIntroPart


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 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.intro.config;
13
14 import org.eclipse.core.runtime.IAdapterFactory;
15 import org.eclipse.core.runtime.IRegistryChangeEvent;
16 import org.eclipse.core.runtime.IRegistryChangeListener;
17 import org.eclipse.core.runtime.PerformanceStats;
18 import org.eclipse.core.runtime.Platform;
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.custom.StackLayout;
21 import org.eclipse.swt.widgets.Composite;
22 import org.eclipse.swt.widgets.Control;
23 import org.eclipse.swt.widgets.Display;
24 import org.eclipse.ui.IMemento;
25 import org.eclipse.ui.PartInitException;
26 import org.eclipse.ui.internal.intro.impl.IIntroConstants;
27 import org.eclipse.ui.internal.intro.impl.IntroPlugin;
28 import org.eclipse.ui.internal.intro.impl.Messages;
29 import org.eclipse.ui.internal.intro.impl.model.IntroModelRoot;
30 import org.eclipse.ui.internal.intro.impl.model.IntroPartPresentation;
31 import org.eclipse.ui.internal.intro.impl.model.loader.ContentProviderManager;
32 import org.eclipse.ui.internal.intro.impl.model.loader.ExtensionPointManager;
33 import org.eclipse.ui.internal.intro.impl.model.loader.ModelLoaderUtil;
34 import org.eclipse.ui.internal.intro.impl.parts.StandbyPart;
35 import org.eclipse.ui.internal.intro.impl.presentations.BrowserIntroPartImplementation;
36 import org.eclipse.ui.internal.intro.impl.util.DialogUtil;
37 import org.eclipse.ui.internal.intro.impl.util.Log;
38 import org.eclipse.ui.intro.IIntroSite;
39 import org.eclipse.ui.part.IntroPart;
40
41 /**
42  * A re-usable intro part that the Eclipse platform uses for its Out of the Box
43  * Experience. It is a customizable intro part where both its presentation, and
44  * its content can be customized based on a configuration. Both are contributed
45  * using the org.eclipse.ui.intro.config extension point. There are two
46  * presentations: an SWT browser based presentation, and a UI forms
47  * presentation. Based on the configuration, one is chosen on startup. If a
48  * Browser based presentation is selected, and the intro is being loaded on a
49  * platform that does not support the SWT Browser control, the default behavior
50  * is to degrade to UI forms presentation. Content displayed in this intro part
51  * can be static or dynamic. Static is html files, dynamic is markup in content
52  * files. Again, both of which can be specified using the above extension point.
53  * <p>
54  * Memento Support: This intro part tries to restore its previous state when
55  * possible. The state of the intro page is remembered, along with which standby
56  * content content part was opened. IStandbyContent parts are passed the Intro's
57  * memento shortly after construction, and are expected to restore there own
58  * state based on the memento. The customizable intro part handles there initial
59  * creation on load, and leaves restoring state to content part. Same with
60  * saving state. The memento is passed shortly before shutdown to enable storing
61  * of part specific data.
62  *
63  * Note: This class was made public for re-use, as-is, as a valid class for the
64  * <code>org.eclipse.ui.intro</code> extension point. It is not intended to be
65  * subclassed or used otherwise.
66  * </p>
67  *
68  * @since 3.0
69  */

70
71 /*
72  * Internal docs: This class wraps a presentation part and a standby part. The
73  * standby part is only shown when an IntroURL asks to show standby or when we
74  * are restarting an Intro with an old memento. An internal data object
75  * "showStandbyPart" is set on the control by the intro URL to signal standby
76  * part needed. This data is nulled when the close button on the standby part is
77  * clicked, signaling that the standby part is no longer needed.
78  */

79 public final class CustomizableIntroPart extends IntroPart implements
80         IIntroConstants, IRegistryChangeListener {
81
82     private IntroPartPresentation presentation;
83     private StandbyPart standbyPart;
84     private Composite container;
85     private IMemento memento;
86     IntroModelRoot model;
87     // this flag is used to recreate a cached standby part. It is used once and
88
// the set to false when the standby part is first created.
89
private boolean restoreStandby;
90
91
92     // Adapter factory to abstract out the StandbyPart implementation from APIs.
93
IAdapterFactory factory = new IAdapterFactory() {
94
95         public Class JavaDoc[] getAdapterList() {
96             return new Class JavaDoc[] { StandbyPart.class, IntroPartPresentation.class };
97         }
98
99         public Object JavaDoc getAdapter(Object JavaDoc adaptableObject, Class JavaDoc adapterType) {
100             if (!(adaptableObject instanceof CustomizableIntroPart))
101                 return null;
102
103             if (adapterType.equals(StandbyPart.class)) {
104                 return getStandbyPart();
105             } else if (adapterType.equals(IntroPartPresentation.class)) {
106                 return getPresentation();
107             } else
108                 return null;
109         }
110     };
111
112     public CustomizableIntroPart() {
113         // register adapter to hide standbypart.
114
Platform.getAdapterManager().registerAdapters(factory,
115             CustomizableIntroPart.class);
116         // model can not be loaded here because the configElement of this part
117
// is still not loaded here.
118

119         // if we are logging performance, start the UI creation start time.
120
// Clock stops at the end of the standbyStateChanged event.
121
if (Log.logPerformance) {
122             if (PerformanceStats.ENABLED)
123                 PerformanceStats.getStats(
124                     IIntroConstants.PERF_VIEW_CREATION_TIME,
125                     IIntroConstants.INTRO).startRun();
126             else
127                 // capture start time to be used when only Intro performance
128
// trace
129
// is turned on.
130
IntroPlugin.getDefault().setUICreationStartTime(
131                     System.currentTimeMillis());
132         }
133     }
134
135     /*
136      * (non-Javadoc)
137      *
138      * @see org.eclipse.ui.intro.IIntroPart#init(org.eclipse.ui.intro.IIntroSite,
139      * org.eclipse.ui.IMemento)
140      */

141     public void init(IIntroSite site, IMemento memento)
142             throws PartInitException {
143         super.init(site, memento);
144         IntroPlugin.getDefault().closeLaunchBar();
145         // load the correct model based in the current Intro Part id. Set the
146
// IntroPartId in the manager class.
147
String JavaDoc introId = getConfigurationElement().getAttribute("id"); //$NON-NLS-1$
148
ExtensionPointManager extensionPointManager = IntroPlugin.getDefault()
149             .getExtensionPointManager();
150         extensionPointManager.setIntroId(introId);
151         model = extensionPointManager.getCurrentModel();
152
153         if (model != null && model.hasValidConfig()) {
154             // we have a valid config contribution, get presentation. Make sure
155
// you pass corret memento.
156
presentation = model.getPresentation();
157             if (presentation != null)
158                 presentation.init(this, getMemento(memento,
159                     MEMENTO_PRESENTATION_TAG));
160
161             // standby part is not created here for performance.
162

163             // cache memento, and detemine if we have a cached standby part.
164
this.memento = memento;
165             restoreStandby = needToRestoreStandby(memento);
166
167             // add the registry listerner for dynamic awarness.
168
Platform.getExtensionRegistry().addRegistryChangeListener(this,
169                 IIntroConstants.PLUGIN_ID);
170         }
171
172         if (model == null || !model.hasValidConfig())
173             DialogUtil.displayErrorMessage(site.getShell(),
174                 Messages.CustomizableIntroPart_configNotFound,
175                 new Object JavaDoc[] { ModelLoaderUtil.getLogString(
176                     getConfigurationElement(), null) }, null);
177
178     }
179
180     /**
181      * Creates the UI based on how the InroPart has been configured.
182      *
183      * @see org.eclipse.ui.IWorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
184      */

185     public void createPartControl(Composite parent) {
186         container = new Composite(parent, SWT.NULL);
187         StackLayout layout = new StackLayout();
188         layout.marginHeight = 0;
189         layout.marginWidth = 0;
190         container.setLayout(layout);
191
192         if (model != null && model.hasValidConfig()) {
193             presentation.createPartControl(container);
194             // do not create the standby part here for performance.
195
}
196
197         if (Log.logPerformance) {
198             PerformanceStats stats = PerformanceStats.getStats(
199                 IIntroConstants.PERF_UI_ZOOM, IIntroConstants.INTRO);
200             stats.startRun();
201         }
202
203     }
204
205
206
207
208     /**
209      * Determine if we need to recreate a standby part. Return true if we have a
210      * standby part memento that is not for the empty part AND stangby memento
211      * has been tagged for restore, ie: it was open when workbench closed.
212      *
213      * @param memento
214      * @return
215      */

216     private boolean needToRestoreStandby(IMemento memento) {
217         // If we have a standby memento, it means we closed with standby open,
218
// and so recreate it.
219
IMemento standbyMemento = getMemento(memento, MEMENTO_STANDBY_PART_TAG);
220         if (standbyMemento == null)
221             return false;
222         String JavaDoc restore = standbyMemento.getString(MEMENTO_RESTORE_ATT);
223         if (restore == null)
224             return false;
225         String JavaDoc cachedStandbyPart = standbyMemento
226             .getString(MEMENTO_STANDBY_CONTENT_PART_ID_ATT);
227         if (cachedStandbyPart != null
228                 && cachedStandbyPart.equals(EMPTY_STANDBY_CONTENT_PART))
229             return false;
230
231         return cachedStandbyPart != null ? true : false;
232     }
233
234     /*
235      * Handled state changes. Recreates the standby part if workbench was shut
236      * down with one.
237      *
238      * @see org.eclipse.ui.IIntroPart#standbyStateChanged(boolean)
239      */

240     public void standbyStateChanged(boolean standby) {
241
242         // do this only if there is a valid config.
243
if (model == null || !model.hasValidConfig())
244             return;
245
246         if (!standby)
247             // we started of not in standby, no need to restore standby.
248
restoreStandby = false;
249
250         boolean isStandbyPartNeeded = isStandbyPartNeeded();
251         isStandbyPartNeeded = isStandbyPartNeeded | restoreStandby;
252
253         if (standbyPart == null && standby && isStandbyPartNeeded)
254             // if standby part is not created yet, create it only if in
255
// standby, and we need to.
256
createStandbyPart();
257
258         handleSetFocus(isStandbyPartNeeded);
259         setTopControl(isStandbyPartNeeded ? getStandbyControl()
260                 : getPresentationControl());
261         // triger state change in presentation to enable/disable toobar
262
// actions. For this, we need to disable actions as long as we are in
263
// standby, or we need to show standby part.
264
presentation.standbyStateChanged(standby, isStandbyPartNeeded);
265
266     }
267
268     /**
269      * Returns true if we need to show the standby part. False in all other
270      * cases. This basically overrides the workbench behavior of Standby/normal
271      * states. The design here is that if the showStandbyPart flag is set, then
272      * we always need to show the standby part.
273      *
274      * @param standby
275      * @return
276      */

277     private boolean isStandbyPartNeeded() {
278         return container.getData(SHOW_STANDBY_PART) == null ? false : true;
279     }
280
281     /*
282      * Create standby part. Called only when really needed. We reset the restore
283      * falg, but we need to tag the intro part as needing standby.
284      */

285     private void createStandbyPart() {
286         standbyPart = new StandbyPart(model);
287         standbyPart.init(this, getMemento(memento, MEMENTO_STANDBY_PART_TAG));
288         standbyPart.createPartControl((Composite) getControl());
289         restoreStandby = false;
290         container.setData(SHOW_STANDBY_PART, "true"); //$NON-NLS-1$
291
}
292
293     private void handleSetFocus(boolean standby) {
294         if (standby) {
295             // standby part is null when Intro has not gone into standby state
296
// yet.
297
if (standbyPart != null)
298                 standbyPart.setFocus();
299         } else
300             presentation.setFocus();
301     }
302
303     /*
304      * (non-Javadoc)
305      *
306      * @see org.eclipse.ui.IWorkbenchPart#setFocus()
307      */

308     public void setFocus() {
309         handleSetFocus(IntroPlugin.isIntroStandby());
310     }
311
312     private void setTopControl(Control c) {
313         // container has stack layout. safe to cast.
314
StackLayout layout = (StackLayout) container.getLayout();
315         layout.topControl = c;
316         container.layout();
317     }
318
319     private Control getPresentationControl() {
320         return container.getChildren()[0];
321     }
322
323     private Control getStandbyControl() {
324         // the Container top control may have only one child if the standby
325
// part is not created yet. This happens if the intro never goes into
326
// standby. Doing this for performance.
327
if (standbyPart != null)
328             return container.getChildren()[1];
329         return null;
330     }
331
332     IntroPartPresentation getPresentation() {
333         return presentation;
334     }
335
336     /*
337      * (non-Javadoc)
338      *
339      * @see org.eclipse.ui.IWorkbenchPart#dispose()
340      */

341     public void dispose() {
342         super.dispose();
343         // call dispose on both parts.
344
if (presentation != null)
345             presentation.dispose();
346         if (standbyPart != null)
347             standbyPart.dispose();
348         // clear all loaded models since we are disposing of the Intro Part.
349
IntroPlugin.getDefault().getExtensionPointManager().clear();
350         ContentProviderManager.getInst().clear();
351         // clean platform adapter.
352
Platform.getAdapterManager().unregisterAdapters(factory,
353             CustomizableIntroPart.class);
354         if (model != null && model.hasValidConfig())
355             Platform.getExtensionRegistry().removeRegistryChangeListener(this);
356
357     }
358
359     /**
360      * @return Returns the standbyPart.
361      */

362     StandbyPart getStandbyPart() {
363         return standbyPart;
364     }
365
366     /**
367      * Returns the primary control associated with this Intro part.
368      *
369      * @return the SWT control which displays this Intro part's content, or
370      * <code>null</code> if this standby part's controls have not yet
371      * been created.
372      */

373     public Control getControl() {
374         return container;
375     }
376
377     public void saveState(IMemento memento) {
378         // give presentation and standby part there own children to create a
379
// name space for each. But save either the presentation or the standby
380
// part as needing to be restored. This way if we close with a standby
381
// mode, we dont get the cached standby part.
382

383         // Find out if presentation or standby is at the top and restore
384
// them. Container has stack layout. safe to cast.
385
boolean restorePresentation = false;
386         StackLayout layout = (StackLayout) container.getLayout();
387         if (getPresentationControl().equals(layout.topControl))
388             restorePresentation = true;
389
390         IMemento presentationMemento = memento
391             .createChild(MEMENTO_PRESENTATION_TAG);
392         IMemento standbyPartMemento = memento
393             .createChild(MEMENTO_STANDBY_PART_TAG);
394         if (restorePresentation)
395             presentationMemento.putString(MEMENTO_RESTORE_ATT, "true"); //$NON-NLS-1$
396
else
397             standbyPartMemento.putString(MEMENTO_RESTORE_ATT, "true"); //$NON-NLS-1$
398
if (presentation != null)
399             presentation.saveState(presentationMemento);
400         if (standbyPart != null)
401             standbyPart.saveState(standbyPartMemento);
402     }
403
404     /*
405      * (non-Javadoc)
406      *
407      * @see org.eclipse.ui.intro.IIntroPart#saveState(org.eclipse.ui.IMemento)
408      */

409
410     private IMemento getMemento(IMemento memento, String JavaDoc key) {
411         if (memento == null)
412             return null;
413         return memento.getChild(key);
414     }
415
416     /**
417      * Support dynamic awarness.
418      *
419      * @see org.eclipse.core.runtime.IRegistryChangeListener#registryChanged(org.eclipse.core.runtime.IRegistryChangeEvent)
420      */

421     public void registryChanged(final IRegistryChangeEvent event) {
422         // Clear cached models first, then update UI by delegating to
423
// implementation. wrap in synchExec because notification is
424
// asynchronous. The design here is that the notification is centralized
425
// here, then this event propagates and each receiving class reacts
426
// accordingly.
427
Display.getDefault().syncExec(new Runnable JavaDoc() {
428
429             public void run() {
430                 String JavaDoc currentPageId = model.getCurrentPageId();
431                 // clear model, including content providers.
432
ExtensionPointManager.getInst().clear();
433                 ContentProviderManager.getInst().clear();
434                 // refresh to new model.
435
model = ExtensionPointManager.getInst().getCurrentModel();
436                 // reuse existing presentation, since we just nulled it.
437
model.setPresentation(getPresentation());
438                 // keep same page on refresh. No need for notification here.
439
model.setCurrentPageId(currentPageId, false);
440                 if (getPresentation() != null)
441                     getPresentation().registryChanged(event);
442
443             }
444         });
445
446     }
447
448     /*
449      * Internal test hook (Non-API).
450      */

451     public boolean internal_isFinishedLoading() {
452         BrowserIntroPartImplementation impl = (BrowserIntroPartImplementation)presentation.getIntroPartImplementation();
453         return impl.isFinishedLoading();
454     }
455 }
456
Popular Tags