All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jface.viewers.ContentViewer Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2000, 2015 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Steven Spungin  - Bug 401439
 *     Lars Vogel  - Bug 475844, 475689
 *******************************************************************************/
package org.eclipse.jface.viewers;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.internal.InternalPolicy;
import org.eclipse.jface.util.Policy;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.widgets.Control;

/**
 * A content viewer is a model-based adapter on a widget which accesses its
 * model by means of a content provider and a label provider.
 * 

* A viewer's model consists of elements, represented by objects. A viewer * defines and implements generic infrastructure for handling model input, * updates, and selections in terms of elements. Input is obtained by querying * an IContentProvider which returns elements. The elements * themselves are not displayed directly. They are mapped to labels, containing * text and/or an image, using the viewer's ILabelProvider. *

*

* Implementing a concrete content viewer typically involves the following * steps: *

*
    *
  • create SWT controls for viewer (in constructor) (optional)
  • *
  • initialize SWT controls from input (inputChanged)
  • *
  • define viewer-specific update methods
  • *
  • support selections (setSelection, getSelection) *
*/ public abstract class ContentViewer extends Viewer { /** * This viewer's content provider, or null if none. */ private IContentProvider contentProvider = null; /** * This viewer's input, or null if none. * The viewer's input provides the "model" for the viewer's content. */ private Object input = null; /** * This viewer's label provider. Initially null, but * lazily initialized (to a SimpleLabelProvider). */ private IBaseLabelProvider labelProvider = null; /** * This viewer's label provider listener. * Note: Having a viewer register a label provider listener with * a label provider avoids having to define public methods * for internal events. */ private final ILabelProviderListener labelProviderListener = new ILabelProviderListener() { private boolean logWhenDisposed = true; // initially true, set to false @Override public void labelProviderChanged(LabelProviderChangedEvent event) { Control control = getControl(); if (control == null || control.isDisposed()) { if (logWhenDisposed) { String message = "Ignored labelProviderChanged notification because control is diposed." + //$NON-NLS-1$ " This indicates a potential memory leak."; //$NON-NLS-1$ if (!InternalPolicy.DEBUG_LOG_LABEL_PROVIDER_NOTIFICATIONS_WHEN_DISPOSED) { // stop logging after the first logWhenDisposed = false; message += " This is only logged once per viewer instance," + //$NON-NLS-1$ " but similar calls will still be ignored."; //$NON-NLS-1$ } Policy.getLog().log( new Status(IStatus.WARNING, Policy.JFACE, message, new RuntimeException())); } return; } ContentViewer.this.handleLabelProviderChanged(event); } }; /** * Creates a content viewer with no input, no content provider, and a * default label provider. */ protected ContentViewer() { } /** * Returns the content provider used by this viewer, * or null if this view does not yet have a content * provider. *

* The ContentViewer implementation of this method returns the content * provider recorded is an internal state variable. * Overriding this method is generally not required; * however, if overriding in a subclass, * super.getContentProvider must be invoked. *

* * @return the content provider, or null if none */ public IContentProvider getContentProvider() { return contentProvider; } /** * The ContentViewer implementation of this IInputProvider * method returns the current input of this viewer, or null * if none. The viewer's input provides the "model" for the viewer's * content. */ @Override public Object getInput() { return input; } /** * Returns the label provider used by this viewer. *

* The ContentViewer implementation of this method returns the label * provider recorded in an internal state variable; if none has been * set (with setLabelProvider) a default label provider * will be created, remembered, and returned. * Overriding this method is generally not required; * however, if overriding in a subclass, * super.getLabelProvider must be invoked. *

* * @return a label provider */ public IBaseLabelProvider getLabelProvider() { if (labelProvider == null) { labelProvider = new LabelProvider(); } return labelProvider; } /** * Handles a dispose event on this viewer's control. *

* The ContentViewer implementation of this method disposes of this * viewer's label provider and content provider (if it has one). * Subclasses should override this method to perform any additional * cleanup of resources; however, overriding methods must invoke * super.handleDispose. *

* * @param event a dispose event */ protected void handleDispose(DisposeEvent event) { if (contentProvider != null) { try { contentProvider.inputChanged(this, getInput(), null); } catch (Exception e) { // ignore exception String message = "Exception while calling ContentProvider.inputChanged from ContentViewer.handleDispose"; //$NON-NLS-1$ message += " (" + contentProvider.getClass().getName() + ")"; //$NON-NLS-1$//$NON-NLS-2$ Policy.getLog().log(new Status(IStatus.WARNING, Policy.JFACE, message, e)); } contentProvider.dispose(); contentProvider = null; } if (labelProvider != null) { labelProvider.removeListener(labelProviderListener); labelProvider.dispose(); labelProvider = null; } input = null; } /** * Handles a label provider changed event. *

* The ContentViewer implementation of this method calls labelProviderChanged() * to cause a complete refresh of the viewer. * Subclasses may reimplement or extend. *

* @param event the change event */ protected void handleLabelProviderChanged(LabelProviderChangedEvent event) { labelProviderChanged(); } /** * Adds event listener hooks to the given control. *

* All subclasses must call this method when their control is * first established. *

*

* The ContentViewer implementation of this method hooks * dispose events for the given control. * Subclasses may override if they need to add other control hooks; * however, super.hookControl must be invoked. *

* * @param control the control */ protected void hookControl(Control control) { control.addDisposeListener(this::handleDispose); } /** * Notifies that the label provider has changed. *

* The ContentViewer implementation of this method calls refresh(). * Subclasses may reimplement or extend. *

*/ protected void labelProviderChanged() { refresh(); } /** * Sets the content provider used by this viewer. *

* The ContentViewer implementation of this method records the * content provider in an internal state variable. * Overriding this method is generally not required; * however, if overriding in a subclass, * super.setContentProvider must be invoked. *

* * @param contentProvider the content provider * @see #getContentProvider */ public void setContentProvider(IContentProvider contentProvider) { Assert.isNotNull(contentProvider); IContentProvider oldContentProvider = this.contentProvider; this.contentProvider = contentProvider; if (oldContentProvider != null) { Object currentInput = getInput(); oldContentProvider.inputChanged(this, currentInput, null); oldContentProvider.dispose(); contentProvider.inputChanged(this, null, currentInput); refresh(); } } /** * The ContentViewer implementation of this Viewer * method invokes inputChanged on the content provider and then the * inputChanged hook method. This method fails if this viewer does * not have a content provider. Subclassers are advised to override * inputChanged rather than this method, but may extend this method * if required. */ @Override public void setInput(Object input) { Control control = getControl(); if (control == null || control.isDisposed()) { throw new IllegalStateException( "Need an underlying widget to be able to set the input." + //$NON-NLS-1$ "(Has the widget been disposed?)"); //$NON-NLS-1$ } Assert.isTrue(getContentProvider() != null, "Instances of ContentViewer must have a content provider assigned before the setInput method is called."); //$NON-NLS-1$ Object oldInput = getInput(); contentProvider.inputChanged(this, oldInput, input); this.input = input; // call input hook inputChanged(this.input, oldInput); } /** * Sets the label provider for this viewer. *

* The ContentViewer implementation of this method ensures that the * given label provider is connected to this viewer and the * former label provider is disconnected from this viewer. * Overriding this method is generally not required; * however, if overriding in a subclass, * super.setLabelProvider must be invoked. *

* * @param labelProvider the label provider, or null if none */ public void setLabelProvider(IBaseLabelProvider labelProvider) { IBaseLabelProvider oldProvider = this.labelProvider; // If it hasn't changed, do nothing. // This also ensures that the provider is not disposed // if set a second time. if (labelProvider == oldProvider) { return; } if (oldProvider != null) { oldProvider.removeListener(this.labelProviderListener); } this.labelProvider = labelProvider; if (labelProvider != null) { labelProvider.addListener(this.labelProviderListener); } refresh(); // Dispose old provider after refresh, so that items never refer to stale images. if (oldProvider != null) { internalDisposeLabelProvider(oldProvider); } } /** * @param oldProvider * * @since 3.4 */ void internalDisposeLabelProvider(IBaseLabelProvider oldProvider) { oldProvider.dispose(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy