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

edu.uci.ics.jung.visualization.BaseVisualizationModel Maven / Gradle / Ivy

/*
 * Copyright (c) 2003, The JUNG Authors
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either "license.txt"
 * or https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 *
 * Created on Jul 7, 2003
 *
 */
package edu.uci.ics.jung.visualization;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.graph.Network;
import edu.uci.ics.jung.layout.algorithms.LayoutAlgorithm;
import edu.uci.ics.jung.layout.model.LayoutModel;
import edu.uci.ics.jung.layout.model.LoadingCacheLayoutModel;
import edu.uci.ics.jung.layout.model.Point;
import edu.uci.ics.jung.layout.util.LayoutChangeListener;
import edu.uci.ics.jung.layout.util.LayoutEvent;
import edu.uci.ics.jung.layout.util.LayoutEventSupport;
import edu.uci.ics.jung.layout.util.LayoutNetworkEvent;
import edu.uci.ics.jung.layout.util.RandomLocationTransformer;
import edu.uci.ics.jung.visualization.util.ChangeEventSupport;
import edu.uci.ics.jung.visualization.util.DefaultChangeEventSupport;
import java.awt.Dimension;
import java.util.List;
import java.util.function.Function;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** @author Tom Nelson */
public class BaseVisualizationModel
    implements VisualizationModel,
        ChangeEventSupport,
        LayoutEventSupport,
        LayoutChangeListener,
        ChangeListener,
        LayoutModel.ChangeListener {

  private static final Logger log = LoggerFactory.getLogger(BaseVisualizationModel.class);

  protected Network network;

  protected LayoutModel layoutModel;

  protected LayoutAlgorithm layoutAlgorithm;

  protected ChangeEventSupport changeSupport = new DefaultChangeEventSupport(this);
  private List> layoutChangeListeners = Lists.newArrayList();

  public BaseVisualizationModel(VisualizationModel other) {
    this(other.getNetwork(), other.getLayoutAlgorithm(), null, other.getLayoutSize());
  }

  public BaseVisualizationModel(VisualizationModel other, Dimension layoutSize) {
    this(other.getNetwork(), other.getLayoutAlgorithm(), null, layoutSize);
  }

  /**
   * @param network the network to visualize
   * @param layoutAlgorithm the algorithm to apply
   * @param layoutSize the size of the layout area
   */
  public BaseVisualizationModel(
      Network network, LayoutAlgorithm layoutAlgorithm, Dimension layoutSize) {
    this(network, layoutAlgorithm, null, layoutSize);
  }

  /**
   * Creates an instance for {@code graph} which initializes the node locations using {@code
   * initializer} and sets the layoutSize of the layout to {@code layoutSize}.
   *
   * @param network the graph on which the layout algorithm is to operate
   * @param initializer specifies the starting positions of the nodes
   * @param layoutSize the dimensions of the region in which the layout algorithm will place nodes
   */
  public BaseVisualizationModel(
      Network network,
      LayoutAlgorithm layoutAlgorithm,
      Function initializer,
      Dimension layoutSize) {
    Preconditions.checkNotNull(network);
    Preconditions.checkNotNull(layoutSize);
    Preconditions.checkArgument(layoutSize.width > 0, "width must be > 0");
    Preconditions.checkArgument(layoutSize.height > 0, "height must be > 0");
    this.layoutAlgorithm = layoutAlgorithm;
    this.layoutModel =
        LoadingCacheLayoutModel.builder()
            .setGraph(network.asGraph())
            .setSize(layoutSize.width, layoutSize.height)
            .setInitializer(
                new RandomLocationTransformer(
                    layoutSize.width, layoutSize.height, System.currentTimeMillis()))
            .build();

    if (this.layoutModel instanceof LayoutModel.ChangeSupport) {
      ((LayoutModel.ChangeSupport) layoutModel).addChangeListener(this);
    }
    if (layoutModel instanceof LayoutEventSupport) {
      ((LayoutEventSupport) layoutModel).addLayoutChangeListener(this);
    }
    this.network = network;
    if (initializer != null) {
      this.layoutModel.setInitializer(initializer);
    }

    this.layoutModel.accept(layoutAlgorithm);
  }

  public BaseVisualizationModel(
      Network network, LayoutModel layoutModel, LayoutAlgorithm layoutAlgorithm) {
    Preconditions.checkNotNull(network);
    Preconditions.checkNotNull(layoutModel);
    this.layoutModel = layoutModel;
    if (this.layoutModel instanceof ChangeEventSupport) {
      ((ChangeEventSupport) layoutModel).addChangeListener(this);
    }
    this.network = network;
    this.layoutModel.accept(layoutAlgorithm);
    this.layoutAlgorithm = layoutAlgorithm;
  }

  public LayoutModel getLayoutModel() {
    log.trace("getting a layourModel " + layoutModel);
    return layoutModel;
  }

  public void setLayoutModel(LayoutModel layoutModel) {
    // stop any Relaxer threads before abandoning the previous LayoutModel
    if (this.layoutModel != null) {
      this.layoutModel.stopRelaxer();
    }
    this.layoutModel = layoutModel;
    if (layoutAlgorithm != null) {
      layoutModel.accept(layoutAlgorithm);
    }
  }

  public void setLayoutAlgorithm(LayoutAlgorithm layoutAlgorithm) {
    this.layoutAlgorithm = layoutAlgorithm;
    log.trace("setLayoutAlgorithm to " + layoutAlgorithm);
    layoutModel.accept(layoutAlgorithm);
  }

  /**
   * Returns the current layoutSize of the visualization space, accoring to the last call to
   * resize().
   *
   * @return the current layoutSize of the screen
   */
  public Dimension getLayoutSize() {
    return new Dimension(layoutModel.getWidth(), layoutModel.getHeight());
  }

  public void setNetwork(Network network) {
    this.setNetwork(network, true);
  }

  public void setNetwork(Network network, boolean forceUpdate) {
    log.trace("setNetwork to n:{} e:{}", network.nodes(), network.edges());
    this.network = network;
    this.layoutModel.setGraph(network.asGraph());
    if (forceUpdate && this.layoutAlgorithm != null) {
      log.trace("will accept {}", layoutAlgorithm);
      layoutModel.accept(this.layoutAlgorithm);
      log.trace("will fire stateChanged");
      changeSupport.fireStateChanged();
      log.trace("fired stateChanged");
    }
  }

  public LayoutAlgorithm getLayoutAlgorithm() {
    return layoutAlgorithm;
  }

  public Network getNetwork() {
    return this.network;
  }

  @Override
  public void addChangeListener(ChangeListener l) {
    this.changeSupport.addChangeListener(l);
  }

  @Override
  public void removeChangeListener(ChangeListener l) {
    this.changeSupport.removeChangeListener(l);
  }

  @Override
  public ChangeListener[] getChangeListeners() {
    return changeSupport.getChangeListeners();
  }

  @Override
  public void fireStateChanged() {
    this.changeSupport.fireStateChanged();
  }

  @Override
  public void addLayoutChangeListener(LayoutChangeListener listener) {
    this.layoutChangeListeners.add(listener);
  }

  @Override
  public void removeLayoutChangeListener(LayoutChangeListener listener) {
    this.layoutChangeListeners.remove(listener);
  }

  private void fireLayoutChanged(LayoutEvent layoutEvent, Network network) {
    if (!layoutChangeListeners.isEmpty()) {
      LayoutEvent evt = new LayoutNetworkEvent(layoutEvent, network);
      for (LayoutChangeListener listener : layoutChangeListeners) {
        listener.layoutChanged(evt);
      }
    }
  }

  /** this is the event from the LayoutModel */
  @Override
  public void changed() {
    this.fireStateChanged();
  }

  @Override
  public void stateChanged(ChangeEvent e) {
    this.fireStateChanged();
  }

  @Override
  public void layoutChanged(LayoutEvent evt) {
    fireLayoutChanged(evt, network);
  }

  @Override
  public void layoutChanged(LayoutNetworkEvent evt) {
    fireLayoutChanged(evt, network);
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy