/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.filters; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; import org.gephi.filters.api.PropertyExecutor.Callback; import org.gephi.filters.api.Query; import org.gephi.filters.spi.FilterProperty; import org.gephi.graph.api.Graph; import org.gephi.graph.api.GraphController; import org.gephi.graph.api.GraphModel; import org.gephi.graph.api.GraphView; import org.gephi.utils.progress.Progress; import org.gephi.utils.progress.ProgressTicket; import org.gephi.utils.progress.ProgressTicketProvider; import org.gephi.visualization.api.VisualizationController; import org.openide.util.Exceptions; import org.openide.util.Lookup; /** * * @author Mathieu Bastian */ public class FilterThread extends Thread { private FilterModelImpl model; private AtomicReference<AbstractQueryImpl> rootQuery; ConcurrentHashMap<String, PropertyModifier> modifiersMap; private boolean running = true; private final Object lock = new Object(); private final boolean filtering; public FilterThread(FilterModelImpl model) { super("Filter Thread"); setDaemon(true); this.model = model; this.filtering = model.isFiltering(); rootQuery = new AtomicReference<AbstractQueryImpl>(); modifiersMap = new ConcurrentHashMap<String, PropertyModifier>(); } @Override public void run() { while (running) { AbstractQueryImpl q; while ((q = rootQuery.getAndSet(null)) == null && running) { try { synchronized (this.lock) { lock.wait(); } } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); } } if (!running) { return; } Query modifiedQuery = null; for (Iterator<PropertyModifier> itr = modifiersMap.values().iterator(); itr.hasNext();) { PropertyModifier pm = itr.next(); itr.remove(); pm.callback.setValue(pm.value); modifiedQuery = pm.query; } if (modifiedQuery != null) { model.updateParameters(modifiedQuery); } //Progress ProgressTicket progressTicket = null; ProgressTicketProvider progressTicketProvider = Lookup.getDefault().lookup(ProgressTicketProvider.class); if (progressTicketProvider != null) { progressTicket = progressTicketProvider.createTicket("Filtering", null); Progress.start(progressTicket); } if (filtering) { filter(q); } else { select(q); } Progress.finish(progressTicket); /*try { //System.out.println("filter query " + q.getName()); Thread.sleep(5000); } catch (InterruptedException ex) { Exceptions.printStackTrace(ex); }*/ } //clear map Query q = null; for (Iterator<PropertyModifier> itr = modifiersMap.values().iterator(); itr.hasNext();) { PropertyModifier pm = itr.next(); pm.callback.setValue(pm.value); q = pm.query; } modifiersMap.clear(); if (q != null) { model.updateParameters(q); } } private void filter(AbstractQueryImpl query) { FilterProcessor processor = new FilterProcessor(); GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel(); Graph result = processor.process((AbstractQueryImpl) query, graphModel); // System.out.println("#Nodes: " + result.getNodeCount()); // System.out.println("#Edges: " + result.getEdgeCount()); if (running) { GraphView view = result.getView(); graphModel.setVisibleView(view); if (model.getCurrentResult() != null) { graphModel.destroyView(model.getCurrentResult()); } model.setCurrentResult(view); } else { //destroy view graphModel.destroyView(result.getView()); } } private void select(AbstractQueryImpl query) { FilterProcessor processor = new FilterProcessor(); GraphModel graphModel = Lookup.getDefault().lookup(GraphController.class).getModel(); Graph result = processor.process((AbstractQueryImpl) query, graphModel); // System.out.println("#Nodes: " + result.getNodeCount()); // System.out.println("#Edges: " + result.getEdgeCount()); if (running) { VisualizationController visController = Lookup.getDefault().lookup(VisualizationController.class); if (visController != null) { visController.selectNodes(result.getNodes().toArray()); visController.selectEdges(result.getEdges().toArray()); } GraphView view = result.getView(); model.setCurrentResult(view); } else { //destroy view graphModel.destroyView(result.getView()); } } public void setRootQuery(AbstractQueryImpl rootQuery) { this.rootQuery.set(rootQuery); synchronized (this.lock) { lock.notify(); } } public AbstractQueryImpl getRootQuery() { return rootQuery.get(); } public void setRunning(boolean running) { this.running = running; synchronized (this.lock) { lock.notify(); } } public void addModifier(PropertyModifier modifier) { modifiersMap.put(modifier.property.getName(), modifier); } protected static class PropertyModifier { protected final Object value; protected final Callback callback; protected final FilterProperty property; protected final Query query; public PropertyModifier(Query query, FilterProperty property, Object value, Callback callback) { this.query = query; this.property = property; this.value = value; this.callback = callback; } } }