View Javadoc

1   /********************************************************************************
2    * Copyright (c) 2000, 2004 IBM Corporation and others. All rights reserved.
3    * This program and the accompanying materials are made available under the
4    * terms of the Eclipse Public License v1.0 which accompanies this distribution,
5    * and is available at http://www.eclipse.org/legal/epl-v10.html Contributors:
6    * IBM Corporation - initial API and implementation
7    ******************************************************************************/
8   package sk.uniba.euromath.editor.wizards;
9   import java.util.ArrayList;
10  import java.util.List;
11  import org.eclipse.core.runtime.IStatus;
12  import org.eclipse.jface.dialogs.IDialogConstants;
13  import org.eclipse.jface.dialogs.IMessageProvider;
14  import org.eclipse.jface.dialogs.IPageChangeProvider;
15  import org.eclipse.jface.dialogs.IPageChangedListener;
16  import org.eclipse.jface.dialogs.MessageDialog;
17  import org.eclipse.jface.dialogs.PageChangedEvent;
18  import org.eclipse.jface.dialogs.TitleAreaDialog;
19  import org.eclipse.jface.util.Assert;
20  import org.eclipse.core.runtime.ListenerList;
21  import org.eclipse.jface.util.SafeRunnable;
22  import org.eclipse.swt.SWT;
23  import org.eclipse.swt.events.SelectionAdapter;
24  import org.eclipse.swt.events.SelectionEvent;
25  import org.eclipse.swt.graphics.Point;
26  import org.eclipse.swt.graphics.Rectangle;
27  import org.eclipse.swt.layout.GridData;
28  import org.eclipse.swt.layout.GridLayout;
29  import org.eclipse.swt.widgets.Button;
30  import org.eclipse.swt.widgets.Composite;
31  import org.eclipse.swt.widgets.Control;
32  import org.eclipse.swt.widgets.Label;
33  import org.eclipse.swt.widgets.Layout;
34  import org.eclipse.swt.widgets.Shell;
35  import sk.uniba.euromath.EuroMath;
36  import sk.uniba.euromath.editor.lang.Messages;
37  import sk.uniba.euromath.editor.widgets.ValidityMessages;
38  import sk.uniba.euromath.tools.JavaTools;
39  import sk.uniba.euromath.tools.StringTools;
40  /***
41   * A dialog to show a wizard to the end user.
42   * <p>
43   * In typical usage, the client instantiates this class with a particular
44   * wizard. The dialog serves as the wizard container and orchestrates the
45   * presentation of its pages.
46   * <p>
47   * The standard layout is roughly as follows: it has an area at the top
48   * containing both the wizard's title, description, and image; the actual wizard
49   * page appears in the middle; below that is a progress indicator (which is made
50   * visible if needed); and at the bottom of the page is message line and a
51   * button bar containing Help, Next, Back, Finish, and Cancel buttons (or some
52   * subset).
53   * </p>
54   * <p>
55   * Wizard is not disposed when the dialog exits.
56   * </p>
57   */
58  public final class WizardDialog extends TitleAreaDialog implements
59  		IPageChangeProvider {
60  	/***
61  	 * Image registry key for error message image (value
62  	 * <code>"dialog_title_error_image"</code>).
63  	 */
64  	public static final String WIZ_IMG_ERROR = "dialog_title_error_image"; //$NON-NLS-1$
65  	/***
66  	 * The wizard the dialog is currently showing.
67  	 */
68  	private final IWizard wizard;
69  	// Navigation buttons
70  	private Button backButton;
71  	private Button nextButton;
72  	private Button finishButton;
73  	private Button cancelButton;
74  	private SelectionAdapter cancelListener;
75  	private Composite pageContainer;
76  	private final PageContainerFillLayout pageContainerLayout = new PageContainerFillLayout(
77  			5, 5, 300, 225);
78  	private int pageWidth = SWT.DEFAULT;
79  	private int pageHeight = SWT.DEFAULT;
80  	private ListenerList pageChangedListeners = new ListenerList(ListenerList.IDENTITY);
81  	/***
82  	 * A layout for a container which includes several pages, like a notebook,
83  	 * wizard, or preference dialog. The size computed by this layout is the
84  	 * maximum width and height of all pages currently inserted into the
85  	 * container.
86  	 */
87  	protected class PageContainerFillLayout extends Layout {
88  		/***
89  		 * The margin width; <code>5</code> pixels by default.
90  		 */
91  		public int marginWidth = 5;
92  		/***
93  		 * The margin height; <code>5</code> pixels by default.
94  		 */
95  		public int marginHeight = 5;
96  		/***
97  		 * The minimum width; <code>0</code> pixels by default.
98  		 */
99  		public int minimumWidth = 0;
100 		/***
101 		 * The minimum height; <code>0</code> pixels by default.
102 		 */
103 		public int minimumHeight = 0;
104 		/***
105 		 * Creates new layout object.
106 		 * @param mw the margin width
107 		 * @param mh the margin height
108 		 * @param minW the minimum width
109 		 * @param minH the minimum height
110 		 */
111 		public PageContainerFillLayout(int mw, int mh, int minW, int minH) {
112 			marginWidth = mw;
113 			marginHeight = mh;
114 			minimumWidth = minW;
115 			minimumHeight = minH;
116 		}
117 		/*
118 		 * (non-Javadoc) Method declared on Layout.
119 		 */
120 		@Override
121 		public Point computeSize(Composite composite, int wHint, int hHint,
122 				boolean force) {
123 			if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT)
124 				return new Point(wHint, hHint);
125 			Point result = null;
126 			Control[] children = composite.getChildren();
127 			if (children.length > 0) {
128 				result = new Point(0, 0);
129 				for (int i = 0; i < children.length; i++) {
130 					Point cp = children[i].computeSize(wHint, hHint, force);
131 					result.x = Math.max(result.x, cp.x);
132 					result.y = Math.max(result.y, cp.y);
133 				}
134 				result.x = result.x + 2 * marginWidth;
135 				result.y = result.y + 2 * marginHeight;
136 			} else {
137 				Rectangle rect = composite.getClientArea();
138 				result = new Point(rect.width, rect.height);
139 			}
140 			result.x = Math.max(result.x, minimumWidth);
141 			result.y = Math.max(result.y, minimumHeight);
142 			if (wHint != SWT.DEFAULT)
143 				result.x = wHint;
144 			if (hHint != SWT.DEFAULT)
145 				result.y = hHint;
146 			return result;
147 		}
148 		/***
149 		 * Returns the client area for the given composite according to this
150 		 * layout.
151 		 * @param c the composite
152 		 * @return the client area rectangle
153 		 */
154 		public Rectangle getClientArea(Composite c) {
155 			Rectangle rect = c.getClientArea();
156 			rect.x = rect.x + marginWidth;
157 			rect.y = rect.y + marginHeight;
158 			rect.width = rect.width - 2 * marginWidth;
159 			rect.height = rect.height - 2 * marginHeight;
160 			return rect;
161 		}
162 		/*
163 		 * (non-Javadoc) Method declared on Layout.
164 		 */
165 		@Override
166 		public void layout(Composite composite, boolean force) {
167 			Rectangle rect = getClientArea(composite);
168 			Control[] children = composite.getChildren();
169 			for (int i = 0; i < children.length; i++) {
170 				children[i].setBounds(rect);
171 			}
172 		}
173 		/***
174 		 * Lays outs the page according to this layout.
175 		 * @param w the control
176 		 */
177 		public void layoutPage(Control w) {
178 			w.setBounds(getClientArea(w.getParent()));
179 		}
180 		/***
181 		 * Sets the location of the page so that its origin is in the upper left
182 		 * corner.
183 		 * @param w the control
184 		 */
185 		public void setPageLocation(Control w) {
186 			w.setLocation(marginWidth, marginHeight);
187 		}
188 	}
189 	/***
190 	 * The name of the functionality that the wizard provides. Shown in the
191 	 * window caption.
192 	 */
193 	private final String processName;
194 	/***
195 	 * Creates a new wizard dialog for the given wizard.
196 	 * @param parentShell the parent shell
197 	 * @param newWizard the wizard this dialog is working on
198 	 * @param processName the name of the functionality that the wizard
199 	 * provides. Shown in the window caption.
200 	 */
201 	public WizardDialog(Shell parentShell, IWizard newWizard, String processName) {
202 		super(parentShell);
203 		if (newWizard == null)
204 			throw new IllegalArgumentException("wizard must not be null"); //$NON-NLS-1$
205 		setShellStyle(SWT.CLOSE | SWT.TITLE | SWT.BORDER
206 				| SWT.APPLICATION_MODAL | SWT.RESIZE | getDefaultOrientation());
207 		wizard = newWizard;
208 		this.processName = processName;
209 		// since VAJava can't initialize an instance var with an anonymous
210 		// class outside a constructor we do it here:
211 		cancelListener = new SelectionAdapter() {
212 			/*
213 			 * (non-Javadoc)
214 			 * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent)
215 			 */
216 			@Override
217 			public void widgetSelected(SelectionEvent e) {
218 				cancelPressed();
219 			}
220 		};
221 	}
222 	/*
223 	 * (non-Javadoc)
224 	 * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
225 	 */
226 	@Override
227 	protected void configureShell(Shell newShell) {
228 		super.configureShell(newShell);
229 		newShell.setText(processName);
230 	}
231 	/***
232 	 * On these composites the page controls are placed. Last composite shows
233 	 * the current page.
234 	 */
235 	private final List<Composite> pageTiles = new ArrayList<Composite>();
236 	/***
237 	 * List of wizard pages. Last page is the page currently being shown.
238 	 */
239 	private final List<BaseWizardPage> wizardPages = new ArrayList<BaseWizardPage>();
240 	/***
241 	 * The Back button has been pressed.
242 	 */
243 	protected void backPressed() {
244 		if (!wizard.hasPrevious())
245 			throw new IllegalStateException("The button must be grayed out"); //$NON-NLS-1$
246 		BaseWizardPage current = wizard.current();
247 		// dispose the page and show previous
248 		current.dispose();
249 		final Composite lastTile = pageTiles.get(pageTiles.size() - 1);
250 		BaseWizardPage lastPage = wizardPages.get(wizardPages.size() - 1);
251 		if (lastPage != current)
252 			throw new IllegalStateException("The wizard offers illegal pages."); //$NON-NLS-1$
253 		lastTile.dispose();
254 		pageTiles.remove(pageTiles.size() - 1);
255 		wizardPages.remove(wizardPages.size() - 1);
256 		current = wizard.previous();
257 		lastPage = wizardPages.get(wizardPages.size() - 1);
258 		if (lastPage != current)
259 			throw new IllegalStateException("The wizard offers illegal pages."); //$NON-NLS-1$
260 		showLastPage();
261 		firePageChanged();
262 	}
263 	/*
264 	 * (non-Javadoc) Method declared on Dialog.
265 	 */
266 	@Override
267 	protected void buttonPressed(int buttonId) {
268 		switch (buttonId) {
269 			case IDialogConstants.BACK_ID: {
270 				backPressed();
271 				break;
272 			}
273 			case IDialogConstants.NEXT_ID: {
274 				nextPressed();
275 				break;
276 			}
277 			case IDialogConstants.FINISH_ID: {
278 				finishPressed();
279 				break;
280 			}
281 		// The Cancel button has a listener which calls cancelPressed directly
282 		}
283 	}
284 	/***
285 	 * Calculates the difference in size between the given page and the page
286 	 * container. A larger page results in a positive delta.
287 	 * @param tile composite where the page is placed.
288 	 * @return the size difference encoded as a
289 	 * <code>new Point(deltaWidth,deltaHeight)</code>
290 	 */
291 	private Point calculatePageSizeDelta(Composite tile) {
292 		Point contentSize = tile.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
293 		Rectangle rect = pageContainerLayout.getClientArea(pageContainer);
294 		Point containerSize = new Point(rect.width, rect.height);
295 		return new Point(Math.max(0, contentSize.x - containerSize.x), Math
296 				.max(0, contentSize.y - containerSize.y));
297 	}
298 	/*
299 	 * (non-Javadoc) Method declared on Dialog.
300 	 */
301 	@Override
302 	protected void cancelPressed() {
303 		// Close the dialog. The check whether the dialog can be
304 		// closed or not is done in <code>okToClose</code>.
305 		// This ensures that the check is also evaluated when the user
306 		// presses the window's close button.
307 		setReturnCode(CANCEL);
308 		close();
309 	}
310 	/*
311 	 * (non-Javadoc)
312 	 * @see org.eclipse.jface.window.Window#close()
313 	 */
314 	@Override
315 	public boolean close() {
316 		if (okToClose())
317 			return hardClose();
318 		return false;
319 	}
320 	/***
321 	 * Creates and returns the contents of this dialog's button bar.
322 	 * <p>
323 	 * The <code>WizardDialog</code> implementation of this framework method
324 	 * prevents the composite's columns from being made equal width in order to
325 	 * remove the margin between the Back and Next buttons.
326 	 * </p>
327 	 * @param parent the parent composite to contain the button bar
328 	 * @return the button bar control
329 	 */
330 	@Override
331 	protected Control createButtonBar(Composite parent) {
332 		Composite composite = (Composite) super.createButtonBar(parent);
333 		((GridLayout) composite.getLayout()).makeColumnsEqualWidth = false;
334 		return composite;
335 	}
336 	/*
337 	 * (non-Javadoc) Method declared on Dialog.
338 	 */
339 	@Override
340 	protected void createButtonsForButtonBar(Composite parent) {
341 		createPreviousAndNextButtons(parent);
342 		finishButton = createButton(parent, IDialogConstants.FINISH_ID,
343 				IDialogConstants.FINISH_LABEL, true);
344 		cancelButton = createCancelButton(parent);
345 	}
346 	/***
347 	 * Creates the Cancel button for this wizard dialog. Creates a standard (<code>SWT.PUSH</code>)
348 	 * button and registers for its selection events. Note that the number of
349 	 * columns in the button bar composite is incremented. The Cancel button is
350 	 * created specially to give it a removeable listener.
351 	 * @param parent the parent button bar
352 	 * @return the new Cancel button
353 	 */
354 	private Button createCancelButton(Composite parent) {
355 		// increment the number of columns in the button bar
356 		((GridLayout) parent.getLayout()).numColumns++;
357 		Button button = new Button(parent, SWT.PUSH);
358 		button.setText(IDialogConstants.CANCEL_LABEL);
359 		setButtonLayoutData(button);
360 		button.setFont(parent.getFont());
361 		button.setData(new Integer(IDialogConstants.CANCEL_ID));
362 		button.addSelectionListener(cancelListener);
363 		return button;
364 	}
365 	/***
366 	 * Return the cancel button if the id is a the cancel id.
367 	 * @param id the button id
368 	 * @return the button corresponding to the button id
369 	 */
370 	@Override
371 	protected Button getButton(int id) {
372 		if (id == IDialogConstants.CANCEL_ID)
373 			return cancelButton;
374 		return super.getButton(id);
375 	}
376 	/***
377 	 * The <code>WizardDialog</code> implementation of this
378 	 * <code>Window</code> method calls <code>super.createContents</code> to
379 	 * create the controls. Then it shows the first page.
380 	 */
381 	@Override
382 	protected Control createContents(Composite parent) {
383 		Control contents = super.createContents(parent);
384 		// Create and show the first page
385 		final BaseWizardPage first = wizard.current();
386 		if (first == null)
387 			return contents;
388 		// initialize the page
389 		final Composite tile = new Composite(pageContainer, SWT.NONE);
390 		tile.setLayout(new GridLayout(1, false));
391 		tile.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
392 		first.createControl(tile);
393 		first.setContext(pageContext);
394 		pageTiles.add(tile);
395 		wizardPages.add(first);
396 		// show the next page
397 		showLastPage();
398 		return contents;
399 	}
400 	/*
401 	 * (non-Javadoc) Method declared on Dialog.
402 	 */
403 	@Override
404 	protected Control createDialogArea(Composite parent) {
405 		Composite composite = (Composite) super.createDialogArea(parent);
406 		// Build the Page container
407 		pageContainer = createPageContainer(composite);
408 		GridData gd = new GridData(GridData.FILL_BOTH);
409 		gd.widthHint = pageWidth;
410 		gd.heightHint = pageHeight;
411 		pageContainer.setLayoutData(gd);
412 		pageContainer.setFont(parent.getFont());
413 		// Insert a progress monitor
414 		GridLayout pmlayout = new GridLayout();
415 		pmlayout.numColumns = 1;
416 		// Build the separator line
417 		Label separator = new Label(composite, SWT.HORIZONTAL | SWT.SEPARATOR);
418 		separator.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
419 		return composite;
420 	}
421 	/***
422 	 * Creates the container that holds all pages.
423 	 * @param parent
424 	 * @return Composite
425 	 */
426 	private Composite createPageContainer(Composite parent) {
427 		Composite result = new Composite(parent, SWT.NULL);
428 		result.setLayout(pageContainerLayout);
429 		return result;
430 	}
431 	/***
432 	 * Creates the Previous and Next buttons for this wizard dialog. Creates
433 	 * standard (<code>SWT.PUSH</code>) buttons and registers for their
434 	 * selection events. Note that the number of columns in the button bar
435 	 * composite is incremented. These buttons are created specially to prevent
436 	 * any space between them.
437 	 * @param parent the parent button bar
438 	 * @return a composite containing the new buttons
439 	 */
440 	private Composite createPreviousAndNextButtons(Composite parent) {
441 		// increment the number of columns in the button bar
442 		((GridLayout) parent.getLayout()).numColumns++;
443 		Composite composite = new Composite(parent, SWT.NONE);
444 		// create a layout with spacing and margins appropriate for the font
445 		// size.
446 		GridLayout layout = new GridLayout();
447 		layout.numColumns = 0; // will be incremented by createButton
448 		layout.marginWidth = 0;
449 		layout.marginHeight = 0;
450 		layout.horizontalSpacing = 0;
451 		layout.verticalSpacing = 0;
452 		composite.setLayout(layout);
453 		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_CENTER
454 				| GridData.VERTICAL_ALIGN_CENTER);
455 		composite.setLayoutData(data);
456 		composite.setFont(parent.getFont());
457 		backButton = createButton(composite, IDialogConstants.BACK_ID,
458 				IDialogConstants.BACK_LABEL, false);
459 		nextButton = createButton(composite, IDialogConstants.NEXT_ID,
460 				IDialogConstants.NEXT_LABEL, false);
461 		return composite;
462 	}
463 	/***
464 	 * The Finish button has been pressed.
465 	 */
466 	protected void finishPressed() {
467 		if (!wizard.canFinish())
468 			throw new IllegalStateException("Finish button should be disabled"); //$NON-NLS-1$
469 		// Wizards are added to the nested wizards list in setWizard.
470 		// This means that the current wizard is always the last wizard in the
471 		// list.
472 		// Note that we first call the current wizard directly (to give it a
473 		// chance to
474 		// abort, do work, and save state) then call the remaining n-1 wizards
475 		// in the
476 		// list (to save state).
477 		if (wizard.performFinish()) {
478 			// Hard close the dialog.
479 			setReturnCode(OK);
480 			hardClose();
481 		}
482 	}
483 	/***
484 	 * Returns page, currently shown on screen.
485 	 * @return currently shown page.
486 	 */
487 	public BaseWizardPage getCurrentPage() {
488 		return wizard.current();
489 	}
490 	/***
491 	 * Returns the wizard this dialog is currently displaying.
492 	 * @return the current wizard
493 	 */
494 	protected IWizard getWizard() {
495 		return wizard;
496 	}
497 	/***
498 	 * Closes this window.
499 	 * @return <code>true</code> if the window is (or was already) closed, and
500 	 * <code>false</code> if it is still open
501 	 */
502 	private boolean hardClose() {
503 		// dispose all pages.
504 		for (BaseWizardPage page : wizardPages) {
505 			page.dispose();
506 		}
507 		// dispose the wizard itself
508 		wizard.dispose();
509 		// close the form
510 		return super.close();
511 	}
512 	/***
513 	 * The Next button has been pressed.
514 	 */
515 	protected void nextPressed() {
516 		if (!wizard.hasNext())
517 			throw new IllegalStateException("Next button must not be enabled"); //$NON-NLS-1$
518 		final BaseWizardPage next;
519 		try {
520 			next = wizard.next();
521 		} catch (ProviderException ex) {
522 			// error happened during creating next wizard. show error msg
523 			// and stay at current page.
524 			EuroMath.log(IStatus.ERROR, 0,
525 					"Provider has thrown error while creating next wizard", ex); //$NON-NLS-1$
526 			MessageDialog.openError(getShell(), Messages.getString("ERROR"), ex //$NON-NLS-1$
527 					.getLocalizedMessage());
528 			return;
529 		}
530 		// initialize the page
531 		final Composite tile = new Composite(pageContainer, SWT.NONE);
532 		tile.setLayout(new GridLayout(1, false));
533 		tile.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
534 		next.createControl(tile);
535 		next.setContext(pageContext);
536 		pageTiles.add(tile);
537 		wizardPages.add(next);
538 		// show the next page
539 		showLastPage();
540 		firePageChanged();
541 	}
542 	/***
543 	 * Checks whether it is alright to close this wizard dialog and performed
544 	 * standard cancel processing. If there is a long running operation in
545 	 * progress, this method posts an alert message saying that the wizard
546 	 * cannot be closed.
547 	 * @return <code>true</code> if it is alright to close this dialog, and
548 	 * <code>false</code> if it is not
549 	 */
550 	private boolean okToClose() {
551 		return wizard.performCancel();
552 	}
553 	/***
554 	 * Sets the minimum page size used for the pages.
555 	 * @param minWidth the minimum page width
556 	 * @param minHeight the minimum page height
557 	 * @see #setMinimumPageSize(Point)
558 	 */
559 	public void setMinimumPageSize(int minWidth, int minHeight) {
560 		Assert.isTrue(minWidth >= 0 && minHeight >= 0);
561 		pageContainerLayout.minimumWidth = minWidth;
562 		pageContainerLayout.minimumHeight = minHeight;
563 	}
564 	/***
565 	 * Sets the minimum page size used for the pages.
566 	 * @param size the page size encoded as <code>new Point(width,height)</code>
567 	 * @see #setMinimumPageSize(int,int)
568 	 */
569 	public void setMinimumPageSize(Point size) {
570 		setMinimumPageSize(size.x, size.y);
571 	}
572 	/***
573 	 * Sets the size of all pages. The given size takes precedence over computed
574 	 * sizes.
575 	 * @param width the page width
576 	 * @param height the page height
577 	 * @see #setPageSize(Point)
578 	 */
579 	public void setPageSize(int width, int height) {
580 		pageWidth = width;
581 		pageHeight = height;
582 	}
583 	/***
584 	 * Sets the size of all pages. The given size takes precedence over computed
585 	 * sizes.
586 	 * @param size the page size encoded as <code>new Point(width,height)</code>
587 	 * @see #setPageSize(int,int)
588 	 */
589 	public void setPageSize(Point size) {
590 		setPageSize(size.x, size.y);
591 	}
592 	/***
593 	 * Ensures that the last page is the visible one.
594 	 */
595 	private void showLastPage() {
596 		final Composite currentTile = pageTiles.get(pageTiles.size() - 1);
597 		currentTile.setVisible(true);
598 		if (pageTiles.size() > 1) {
599 			final Composite prevTile = pageTiles.get(pageTiles.size() - 2);
600 			prevTile.setVisible(false);
601 		}
602 		// ensure the dialog is large enough for this page
603 		updateSize(currentTile);
604 		// update the dialog controls
605 		update();
606 	}
607 	/***
608 	 * Updates this dialog's controls to reflect the current page.
609 	 */
610 	protected void update() {
611 		// Update the title bar
612 		updateTitleBar();
613 		// Update the buttons
614 		updateButtons();
615 	}
616 	/***
617 	 * Updates buttons state.
618 	 */
619 	private void updateButtons() {
620 		final boolean canFinish = wizard.canFinish();
621 		final boolean canFlipToNextPage = wizard.hasNext();
622 		backButton.setEnabled(wizard.hasPrevious());
623 		nextButton.setEnabled(canFlipToNextPage);
624 		finishButton.setEnabled(canFinish);
625 		// finish is default unless it is diabled and next is enabled
626 		if (canFlipToNextPage && !canFinish)
627 			getShell().setDefaultButton(nextButton);
628 		else
629 			getShell().setDefaultButton(finishButton);
630 	}
631 	/*
632 	 * (non-Javadoc)
633 	 * @see org.eclipse.jface.dialogs.TitleAreaDialog#setMessage(java.lang.String,
634 	 * int)
635 	 */
636 	@Override
637 	public void setMessage(String newMessage, int newType) {
638 		super.setMessage(newMessage, newType);
639 		currentMessage = newMessage;
640 		currentMessageLevel = newType;
641 	}
642 	/*
643 	 * (non-Javadoc)
644 	 * @see org.eclipse.jface.dialogs.TitleAreaDialog#setErrorMessage(java.lang.String)
645 	 */
646 	@Override
647 	public void setErrorMessage(String newErrorMessage) {
648 		super.setErrorMessage(newErrorMessage);
649 		currentErrorMessage = newErrorMessage;
650 	}
651 	/***
652 	 * Returns current error message.
653 	 * @return current error message.
654 	 */
655 	public String getErrorMessage() {
656 		return currentErrorMessage;
657 	}
658 	/***
659 	 * Returns current message.
660 	 * @return current message.
661 	 */
662 	public String getMessage() {
663 		return currentMessage;
664 	}
665 	/***
666 	 * Returns current message's level.
667 	 * @return current message's level.
668 	 */
669 	public int getMessageType() {
670 		return currentMessageLevel;
671 	}
672 	/***
673 	 * Updates currently shown messages from current page.
674 	 */
675 	private void updateMessage() {
676 		if (wizard.current() == null)
677 			setMessages(null);
678 		else
679 			setMessages(wizard.current().getMessages());
680 	}
681 	/***
682 	 * Currently shown error message.
683 	 */
684 	private String currentErrorMessage = null;
685 	/***
686 	 * Currently shown message.
687 	 */
688 	private String currentMessage = null;
689 	/***
690 	 * Level of currently shown message.
691 	 */
692 	private int currentMessageLevel = IMessageProvider.NONE;
693 	/***
694 	 * Updates messages.
695 	 * @param messages validity messages. If <code>null</code> then all
696 	 * messages are cleared.
697 	 */
698 	private void setMessages(ValidityMessages messages) {
699 		if (messages == null) {
700 			if (getErrorMessage() != null)
701 				setErrorMessage(null);
702 			if (getMessage() != null) {
703 				setMessage(null, IMessageProvider.NONE);
704 			}
705 			return;
706 		}
707 		// check if we have new error message.
708 		if (!JavaTools.equals(getErrorMessage(), messages.error))
709 			setErrorMessage(messages.error);
710 		if (messages.error != null) {
711 			// cannot show both error and warning, bail out.
712 			return;
713 		}
714 		// check if we have new warning message.
715 		if ((getMessageType() != IMessageProvider.WARNING)
716 				|| (!JavaTools.equals(getMessage(), messages.warning))) {
717 			// warning message has been changed. Update, but only if needed. We
718 			// don't have to null warning message if there is non-null info
719 			// message.
720 			if ((messages.warning != null) || (messages.info == null))
721 				setMessage(messages.warning, IMessageProvider.WARNING);
722 		}
723 		if (messages.warning != null) {
724 			// cannot show both warning and information, bail out.
725 			return;
726 		}
727 		// check if we have new information message.
728 		if ((getMessageType() != IMessageProvider.INFORMATION)
729 				|| (!JavaTools.equals(getMessage(), messages.info))) {
730 			setMessage(messages.info, IMessageProvider.INFORMATION);
731 		}
732 	}
733 	/***
734 	 * Changes the shell size to the given size, ensuring that it is no larger
735 	 * than the display bounds.
736 	 * @param width the shell width
737 	 * @param height the shell height
738 	 */
739 	private void setShellSize(int width, int height) {
740 		Rectangle size = getShell().getBounds();
741 		size.height = height;
742 		size.width = width;
743 		getShell().setBounds(getConstrainedShellBounds(size));
744 	}
745 	/***
746 	 * Computes the correct dialog size for the current page and resizes its
747 	 * shell if nessessary. Also causes the container to refresh its layout.
748 	 * @param tile the composite where the wizard page is placed, to use to
749 	 * resize the dialog
750 	 * @since 2.0
751 	 */
752 	protected void updateSize(Composite tile) {
753 		updateSizeForPage(tile);
754 		pageContainerLayout.layoutPage(tile);
755 	}
756 	/***
757 	 * Updates size of the window.
758 	 */
759 	public void updateSize() {
760 		updateSize(pageTiles.get(pageTiles.size() - 1));
761 	}
762 	/***
763 	 * Computes the correct dialog size for the given page and resizes its shell
764 	 * if nessessary.
765 	 * @param tile the composite where the wizard page is placed
766 	 */
767 	private void updateSizeForPage(Composite tile) {
768 		// ensure the page container is large enough
769 		Point delta = calculatePageSizeDelta(tile);
770 		if (delta.x > 0 || delta.y > 0) {
771 			// increase the size of the shell
772 			Shell shell = getShell();
773 			Point shellSize = shell.getSize();
774 			setShellSize(shellSize.x + delta.x, shellSize.y + delta.y);
775 			constrainShellSize();
776 		}
777 	}
778 	/***
779 	 * Updates the titlebar.
780 	 */
781 	private void updateTitleBar() {
782 		final String s = StringTools.nonNullStr(wizard.getName());
783 		setTitle(s);
784 		final BaseWizardPage currentPage = wizard.current();
785 		if (currentPage != null)
786 			setTitleImage(currentPage.titleImage);
787 		updateMessage();
788 	}
789 	/*
790 	 * (non-Javadoc)
791 	 * @see org.eclipse.jface.dialogs.IPageChangeProvider#getSelectedPage()
792 	 */
793 	public Object getSelectedPage() {
794 		return getCurrentPage();
795 	}
796 	/*
797 	 * (non-Javadoc)
798 	 * @see org.eclipse.jface.dialog.IPageChangeProvider#addPageChangedListener()
799 	 */
800 	public void addPageChangedListener(IPageChangedListener listener) {
801 		pageChangedListeners.add(listener);
802 	}
803 	/*
804 	 * (non-Javadoc)
805 	 * @see org.eclipse.jface.dialog.IPageChangeProvider#removePageChangedListener()
806 	 */
807 	public void removePageChangedListener(IPageChangedListener listener) {
808 		pageChangedListeners.remove(listener);
809 	}
810 	/***
811 	 * Notifies any selection changed listeners that the selected page has
812 	 * changed. Only listeners registered at the time this method is called are
813 	 * notified.
814 	 * @see IPageChangedListener#pageChanged
815 	 */
816 	protected void firePageChanged() {
817 		final PageChangedEvent event = new PageChangedEvent(this, wizard
818 				.current());
819 		Object[] listeners = pageChangedListeners.getListeners();
820 		for (int i = 0; i < listeners.length; ++i) {
821 			final IPageChangedListener l = (IPageChangedListener) listeners[i];
822 			SafeRunnable.run(new SafeRunnable() {
823 				public void run() {
824 					l.pageChanged(event);
825 				}
826 			});
827 		}
828 	}
829 	/***
830 	 * The context given to each page.
831 	 * @author Martin Vysny
832 	 */
833 	private final class PageContext implements IWizardPageContext {
834 		/*
835 		 * (non-Javadoc)
836 		 * @see sk.uniba.euromath.editor.wizards.IWizardPageContext#getShell()
837 		 */
838 		public Shell getShell() {
839 			return WizardDialog.this.getShell();
840 		}
841 		/*
842 		 * (non-Javadoc)
843 		 * @see sk.uniba.euromath.editor.wizards.IWizardPageContext#updateMessages()
844 		 */
845 		public void updateMessages() {
846 			update();
847 		}
848 	}
849 	/***
850 	 * Context given to each page.
851 	 */
852 	private final IWizardPageContext pageContext = new PageContext();
853 }