Java tutorial
package codeswarm; /* Copyright 2008-2009 code_swarm project team This file is part of code_swarm. code_swarm is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. code_swarm 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 General Public License for more details. You should have received a copy of the GNU General Public License along with code_swarm. If not, see <http://www.gnu.org/licenses/>. */ import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.ListIterator; import java.util.Properties; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import processing.core.PApplet; import processing.core.PFont; import processing.core.PImage; import codeswarm.physics.PhysicsEngine; import codeswarm.processing.ColorAssigner; import codeswarm.processing.ColorBins; import codeswarm.processing.ColorTest; import codeswarm.processing.Drawable; import codeswarm.processing.Edge; import codeswarm.processing.FileEvent; import codeswarm.processing.FileNode; import codeswarm.processing.Node; import codeswarm.processing.PersonNode; import codeswarm.ui.MainView; public class code_swarm extends PApplet implements TaskListener { /** @remark needed for any serializable class */ private static final long serialVersionUID = 0; private static Log logger = LogFactory.getLog(code_swarm.class); // User-defined variables private int FRAME_RATE = 24; private long UPDATE_DELTA = -1; private String SCREENSHOT_FILE; private int background; // Data storage private BlockingQueue<FileEvent> eventsQueue; private boolean isInputSorted = false; private static CopyOnWriteArrayList<FileNode> nodes; private static CopyOnWriteArrayList<Edge> edges; private static CopyOnWriteArrayList<PersonNode> people; private LinkedList<ColorBins> history; private boolean finishedLoading = false; // Temporary variables private FileEvent currentEvent; private Date nextDate; private Date prevDate; // private FileNode prevNode; // Graphics objects private static PFont font; private static PFont boldFont; private PImage sprite; // Graphics state variables private boolean looping = true; private boolean coolDown = false; private boolean showHistogram = true; private boolean showDate = true; private boolean showLegend = false; private boolean showPopular = false; private boolean showEdges = false; private boolean showEngine = false; private boolean showHelp = false; private boolean takeSnapshots = false; private boolean showDebug = false; private boolean drawNamesSharp = false; private boolean drawNamesHalos = false; private boolean drawFilesSharp = false; private boolean drawFilesFuzzy = false; private boolean drawFilesJelly = false; // Color mapper private ColorAssigner colorAssigner; // private int currentColor; // Physics engine configuration private String physicsEngineConfigDir; private String physicsEngineSelection; private java.util.Vector<PhysicsEngine> mPhysicsEngineChoices = new java.util.Vector<PhysicsEngine>(); private PhysicsEngine mPhysicsEngine = null; private boolean safeToToggle = false; private boolean wantToToggle = false; private boolean toggleDirection = false; // Default Physics Engine (class) name private static final String PHYSICS_ENGINE_LEGACY = "PhysicsEngineLegacy"; // Formats the date string nicely private DateFormat formatter = DateFormat.getDateInstance(); private static CodeSwarmConfig cfg; private long lastDrawDuration = 0; private String loadingMessage = "Reading input file"; private static int width = 0; private static int height = 0; private int maxFramesSaved; private int maxBackgroundThreads; private ExecutorService backgroundExecutor; /** * Initialisation */ public void setup() { width = cfg.getIntProperty(CodeSwarmConfig.WIDTH_KEY, 640); if (width <= 0) { width = 640; } height = cfg.getIntProperty(CodeSwarmConfig.HEIGHT_KEY, 480); if (height <= 0) { height = 480; } maxBackgroundThreads = cfg.getIntProperty(CodeSwarmConfig.MAX_THREADS_KEY, 4); if (maxBackgroundThreads <= 0) { maxBackgroundThreads = 4; } backgroundExecutor = new ThreadPoolExecutor(1, maxBackgroundThreads, Long.MAX_VALUE, TimeUnit.NANOSECONDS, new ArrayBlockingQueue<Runnable>(4 * maxBackgroundThreads), new ThreadPoolExecutor.CallerRunsPolicy()); if (cfg.getBooleanProperty(CodeSwarmConfig.USE_OPEN_GL, false)) { size(width, height, OPENGL); } else { size(width, height); } showLegend = cfg.getBooleanProperty(CodeSwarmConfig.SHOW_LEGEND, false); showHistogram = cfg.getBooleanProperty(CodeSwarmConfig.SHOW_HISTORY, false); showDate = cfg.getBooleanProperty(CodeSwarmConfig.SHOW_DATE, false); showEdges = cfg.getBooleanProperty(CodeSwarmConfig.SHOW_EDGES, false); showDebug = cfg.getBooleanProperty(CodeSwarmConfig.SHOW_DEBUG, false); takeSnapshots = cfg.getBooleanProperty(CodeSwarmConfig.TAKE_SNAPSHOTS_KEY, false); drawNamesSharp = cfg.getBooleanProperty(CodeSwarmConfig.DRAW_NAMES_SHARP, true); drawNamesHalos = cfg.getBooleanProperty(CodeSwarmConfig.DRAW_NAMES_HALOS, false); drawFilesSharp = cfg.getBooleanProperty(CodeSwarmConfig.DRAW_FILES_SHARP, false); drawFilesFuzzy = cfg.getBooleanProperty(CodeSwarmConfig.DRAW_FILES_FUZZY, true); drawFilesJelly = cfg.getBooleanProperty(CodeSwarmConfig.DRAW_FILES_JELLY, false); background = cfg.getBackground().getRGB(); UPDATE_DELTA = cfg.getIntProperty(CodeSwarmConfig.MSEC_PER_FRAME_KEY, -1); if (UPDATE_DELTA == -1) { int framesperday = cfg.getIntProperty(CodeSwarmConfig.FRAMES_PER_DAY_KEY, 4); if (framesperday > 0) { UPDATE_DELTA = (86400000 / framesperday); } } if (UPDATE_DELTA <= 0) { // Default to 4 frames per day. UPDATE_DELTA = 21600000; } isInputSorted = cfg.getBooleanProperty(CodeSwarmConfig.IS_INPUT_SORTED_KEY, false); /** * This section loads config files and calls the setup method for all physics engines. */ physicsEngineConfigDir = cfg.getStringProperty(CodeSwarmConfig.PHYSICS_ENGINE_CONF_DIR, "physics_engine"); File f = new File(physicsEngineConfigDir); String[] configFiles = null; if (f.exists() && f.isDirectory()) { configFiles = f.list(); } for (int i = 0; configFiles != null && i < configFiles.length; i++) { if (configFiles[i].endsWith(".config")) { Properties p = new Properties(); String ConfigPath = physicsEngineConfigDir + System.getProperty("file.separator") + configFiles[i]; try { p.load(new FileInputStream(ConfigPath)); } catch (FileNotFoundException e) { e.printStackTrace(); System.exit(1); } catch (IOException e) { e.printStackTrace(); System.exit(1); } String ClassName = p.getProperty("name", "__DEFAULT__"); if (!ClassName.equals("__DEFAULT__")) { PhysicsEngine pe = getPhysicsEngine(ClassName); pe.setup(p); mPhysicsEngineChoices.add(pe); } else { logger.error("Skipping config file '" + ConfigPath + "'. Must specify class name via the 'name' parameter."); System.exit(1); } } } if (mPhysicsEngineChoices.size() == 0) { logger.error("No physics engine config files found in '" + physicsEngineConfigDir + "'."); System.exit(1); } // Physics engine configuration and instantiation physicsEngineSelection = cfg.getStringProperty(CodeSwarmConfig.PHYSICS_ENGINE_SELECTION, PHYSICS_ENGINE_LEGACY); for (PhysicsEngine p : mPhysicsEngineChoices) { if (physicsEngineSelection.equals(p.getClass().getName())) { mPhysicsEngine = p; } } if (mPhysicsEngine == null) { logger.error("No physics engine matches your choice of '" + physicsEngineSelection + "'. Check '" + physicsEngineConfigDir + "' for options."); System.exit(1); } smooth(); frameRate(FRAME_RATE); // init data structures nodes = new CopyOnWriteArrayList<FileNode>(); edges = new CopyOnWriteArrayList<Edge>(); people = new CopyOnWriteArrayList<PersonNode>(); history = new LinkedList<ColorBins>(); if (isInputSorted) { //If the input is sorted, we only need to store the next few events eventsQueue = new ArrayBlockingQueue<FileEvent>(5000); } else { //Otherwise we need to store them all at once in a data structure that will sort them eventsQueue = new PriorityBlockingQueue<FileEvent>(); } // Init color map initColors(); loadRepEvents(cfg.getStringProperty(CodeSwarmConfig.INPUT_FILE_KEY)); // event formatted (this is the standard) synchronized (this) { while (!finishedLoading && eventsQueue.isEmpty()) { try { wait(); } catch (InterruptedException e) { logger.error("The ready-check thread was interrupted", e); } } } prevDate = eventsQueue.peek().getDate(); SCREENSHOT_FILE = cfg.getStringProperty(CodeSwarmConfig.SNAPSHOT_LOCATION_KEY); maxFramesSaved = (int) Math.pow(10, SCREENSHOT_FILE.replaceAll("[^#]", "").length()); // Create fonts String fontName = cfg.getStringProperty(CodeSwarmConfig.FONT_KEY, "SansSerif"); String fontNameBold = cfg.getStringProperty(CodeSwarmConfig.FONT_KEY_BOLD, "SansSerif"); Integer fontSize = cfg.getIntProperty(CodeSwarmConfig.FONT_SIZE, 10); Integer fontSizeBold = cfg.getIntProperty(CodeSwarmConfig.FONT_SIZE_BOLD, 14); font = createFont(fontName, fontSize); boldFont = createFont(fontNameBold, fontSizeBold); textFont(font); // Create the file particle image sprite = loadImage(cfg.getStringProperty(CodeSwarmConfig.SPRITE_FILE_KEY, "particle.png")); // Add translucency (using itself in this case) sprite.mask(sprite); } /** * Load a colormap */ public void initColors() { colorAssigner = new ColorAssigner(); int i = 1; String property; while ((property = cfg.getColorAssignProperty(i)) != null) { ColorTest ct = new ColorTest(); ct.loadProperty(property); colorAssigner.addRule(ct); i++; } // Load the default. ColorTest ct = new ColorTest(); ct.loadProperty(CodeSwarmConfig.DEFAULT_COLOR_ASSIGN); colorAssigner.addRule(ct); } /** * Main loop */ public void draw() { long start = System.currentTimeMillis(); background(background); // clear screen with background color this.update(); // update state to next frame // Draw edges (for debugging only) if (showEdges) { for (Edge edge : edges) { edge.draw(); } } // Surround names with aura // Then blur it if (drawNamesHalos) { drawPeopleNodesBlur(); } // Then draw names again, but sharp if (drawNamesSharp) { drawPeopleNodesSharp(); } // Draw file particles for (FileNode node : nodes) { node.draw(); } textFont(font); // Show the physics engine name if (showEngine) { drawEngine(); } // help, legend and debug information are exclusive if (showHelp) { // help override legend and debug information drawHelp(); } else if (showDebug) { // debug override legend information drawDebugData(); } else if (showLegend) { // legend only if nothing "more important" drawLegend(); } if (showPopular) { drawPopular(); } if (showHistogram) { drawHistory(); } if (showDate) { drawDate(); } if (takeSnapshots) { dumpFrame(); } // Stop animation when we run out of data AND all nodes are dead if (eventsQueue.isEmpty()) { coolDown = true; if (!isThereLife()) { // noLoop(); backgroundExecutor.shutdown(); try { backgroundExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); } catch (InterruptedException e) { /* Do nothing, just exit */} exit(); } } long end = System.currentTimeMillis(); lastDrawDuration = end - start; } /** * Surround names with aura */ public void drawPeopleNodesBlur() { colorMode(HSB); // First draw the name for (PersonNode p : people) { fill(hue(p.getFlavor()), 64, 255, p.getLife()); p.draw(); } // Then blur it filter(BLUR, 3); } /** * Draw person's name */ public void drawPeopleNodesSharp() { colorMode(RGB); for (int i = 0; i < people.size(); i++) { PersonNode p = people.get(i); fill(lerpColor(p.getFlavor(), color(255), 0.5f), max(p.getLife() - 50, 0)); p.draw(); } } /** * Draw date in lower-right corner */ public void drawDate() { fill(255); String dateText = formatter.format(prevDate); textAlign(RIGHT, BASELINE); textSize(font.size); if (coolDown) dateText = "End of history: " + dateText; text(dateText, width - 1, height - textDescent()); } /** * Draw histogram in lower-left */ public void drawHistory() { int counter = 0; strokeWeight(1); for (ColorBins cb : history) { for (int i = 0; i < cb.getNum(); i++) { int c = cb.getColorList()[i]; stroke(c, 200); point(counter, height - i - 3); } counter++; } } /** * Show the Loading screen. */ public void drawLoading() { noStroke(); textFont(font, 20); textAlign(LEFT, TOP); fill(255, 200); text(loadingMessage, 0, 0); } /** * Show color codings */ public void drawLegend() { noStroke(); textFont(font); textAlign(LEFT, TOP); fill(255, 200); text("Legend:", 0, 0); for (int i = 0; i < colorAssigner.getTests().size(); i++) { ColorTest t = colorAssigner.getTests().get(i); fill(t.getC1(), 200); text(t.getLabel(), font.size, (i + 1) * font.size); } } /** * Show physics engine name */ public void drawEngine() { fill(255); textAlign(RIGHT, BASELINE); textSize(10); text(physicsEngineSelection, width - 1, height - (textDescent() * 5)); } /** * Show short help on available commands */ public void drawHelp() { int line = 0; noStroke(); textFont(font); textAlign(LEFT, TOP); fill(255, 200); text("Help on keyboard commands:", 0, 10 * line++); text("space bar : pause", 0, 10 * line++); text(" a : show name halos", 0, 10 * line++); text(" b : show debug", 0, 10 * line++); text(" d : show date", 0, 10 * line++); text(" e : show edges", 0, 10 * line++); text(" E : show physics engine name", 0, 10 * line++); text(" f : draw files fuzzy", 0, 10 * line++); text(" h : show histogram", 0, 10 * line++); text(" j : draw files jelly", 0, 10 * line++); text(" l : show legend", 0, 10 * line++); text(" p : show popular", 0, 10 * line++); text(" q : quit code_swarm", 0, 10 * line++); text(" s : draw names sharp", 0, 10 * line++); text(" S : draw files sharp", 0, 10 * line++); text(" minus : previous physics engine", 0, 10 * line++); text(" plus : next physics engine", 0, 10 * line++); text(" ? : show help", 0, 10 * line++); } /** * Show debug information about all drawable objects */ public void drawDebugData() { noStroke(); textFont(font); textAlign(LEFT, TOP); fill(255, 200); text("Nodes: " + nodes.size(), 0, 0); text("People: " + people.size(), 0, 10); text("Queue: " + eventsQueue.size(), 0, 20); text("Last render time: " + lastDrawDuration, 0, 30); } /** * TODO This could be made to look a lot better. */ public void drawPopular() { CopyOnWriteArrayList<FileNode> al = new CopyOnWriteArrayList<FileNode>(); noStroke(); textFont(font); textAlign(RIGHT, TOP); fill(255, 200); text("Popular Nodes (touches):", width - 120, 0); for (int i = 0; i < nodes.size(); i++) { FileNode fn = nodes.get(i); if (fn.qualifies()) { // Insertion Sort if (al.size() > 0) { int j = 0; for (; j < al.size(); j++) { if (fn.compareTo(al.get(j)) <= 0) { continue; } else { break; } } al.add(j, fn); } else { al.add(fn); } } } int i = 1; ListIterator<FileNode> it = al.listIterator(); while (it.hasNext()) { FileNode n = it.next(); // Limit to the top 10. if (i <= 10) { text(n.getName() + " (" + n.getTouches() + ")", width - 100, 10 * i++); } else if (i > 10) { break; } } } /** * @param name * @return physics engine instance */ @SuppressWarnings("unchecked") public PhysicsEngine getPhysicsEngine(String name) { PhysicsEngine pe = null; try { Class<PhysicsEngine> c = (Class<PhysicsEngine>) Class.forName(name); Class partypes[] = { code_swarm.class }; Constructor<PhysicsEngine> peConstructor = c.getConstructor(partypes); Object arglist[] = { this }; pe = peConstructor.newInstance(arglist); } catch (Exception e) { e.printStackTrace(); System.exit(1); } return pe; } /** * @return list of people whose life is > 0 */ public static Iterable<PersonNode> getLivingPeople() { return filterLiving(people); } /** * @return list of edges whose life is > 0 */ public static Iterable<Edge> getLivingEdges() { return filterLiving(edges); } /** * @return list of file nodes whose life is > 0 */ public static Iterable<FileNode> getLivingNodes() { return filterLiving(nodes); } private static <T extends Drawable> Iterable<T> filterLiving(Iterable<T> iter) { ArrayList<T> livingThings = new ArrayList<T>(); for (T thing : iter) if (thing.isAlive()) livingThings.add(thing); return livingThings; } /** * Take screenshot */ public void dumpFrame() { if (frameCount < maxFramesSaved) { final String outputFileName = insertFrame(SCREENSHOT_FILE); final PImage image = get(); backgroundExecutor.execute(new Runnable() { public void run() { image.save(new File(outputFileName).getAbsolutePath()); } }); // saveFrame(SCREENSHOT_FILE); } } /** * Update the particle positions */ public void update() { // Create a new histogram line ColorBins cb = new ColorBins(); history.add(cb); nextDate = new Date(prevDate.getTime() + UPDATE_DELTA); currentEvent = eventsQueue.peek(); while (currentEvent != null && currentEvent.getDate().before(nextDate)) { if (finishedLoading) { currentEvent = eventsQueue.poll(); if (currentEvent == null) return; } else { try { currentEvent = eventsQueue.take(); } catch (InterruptedException e) { logger.warn("Interrupted while fetching current event from eventsQueue", e); continue; } } FileNode n = findNode(currentEvent.getPath() + currentEvent.getFilename()); if (n == null) { float FILE_MASS = cfg.getFloatProperty(CodeSwarmConfig.FILE_MASS_KEY, 1.0f); n = new FileNode(currentEvent, FILE_MASS, mPhysicsEngine.pStartLocation(), mPhysicsEngine.pStartVelocity(FILE_MASS), this); nodes.add(n); } else { n.freshen(currentEvent); } // add to color bin cb.add(n.getNodeHue()); PersonNode p = findPerson(currentEvent.getAuthor()); if (p == null) { float PERSON_MASS = cfg.getFloatProperty(CodeSwarmConfig.PERSON_MASS_KEY, 1.0f); p = new PersonNode(currentEvent.getAuthor(), color(0), PERSON_MASS, mPhysicsEngine.pStartLocation(), mPhysicsEngine.pStartVelocity(PERSON_MASS), this); people.add(p); } else { p.freshen(); } p.addColor(n.getNodeHue()); Edge ped = findEdge(n, p); if (ped == null) { ped = new Edge(n, p, this); edges.add(ped); } else ped.freshen(); /* * if ( currentEvent.date.equals( prevDate ) ) { * Edge e = findEdge( n, prevNode); * if ( e == null ) { * e = new Edge( n, prevNode ); * edges.add( e ); * } else { * e.freshen(); * } * } */ // prevDate = currentEvent.date; // prevNode = n; if (finishedLoading) currentEvent = eventsQueue.peek(); else { synchronized (this) { while (eventsQueue.isEmpty()) { try { wait(); } catch (InterruptedException e) { logger.error("The queue-check thread was interrupted", e); } } } currentEvent = eventsQueue.peek(); } } if (!coolDown) prevDate = nextDate; // sort colorbins cb.sort(); // restrict history to drawable area while (history.size() > 320) history.remove(); // Do not allow toggle Physics Engine yet. safeToToggle = false; // Init frame: mPhysicsEngine.initializeFrame(); Iterable<Edge> livingEdges = getLivingEdges(); Iterable<FileNode> livingNodes = getLivingNodes(); Iterable<PersonNode> livingPeople = getLivingPeople(); // update velocity for (Edge edge : livingEdges) { mPhysicsEngine.onRelaxEdge(edge); } // update velocity for (FileNode node : livingNodes) { mPhysicsEngine.onRelaxNode(node); } // update velocity for (PersonNode person : livingPeople) { mPhysicsEngine.onRelaxPerson(person); } // update position for (Edge edge : livingEdges) { mPhysicsEngine.onUpdateEdge(edge); } // update position for (FileNode node : livingNodes) { mPhysicsEngine.onUpdateNode(node); } // update position for (PersonNode person : livingPeople) { mPhysicsEngine.onUpdatePerson(person); } // Finalize frame: mPhysicsEngine.finalizeFrame(); safeToToggle = true; if (wantToToggle == true) { switchPhysicsEngine(toggleDirection); } } /** * Checks the node list for signs of life. * @return Does life exist? */ public boolean isThereLife() { for (FileNode node : nodes) { if (node.getLife() > 0) return true; } return false; } /** * Searches the nodes array for a given name * @param name * @return FileNode with matching name or null if not found. */ public FileNode findNode(String name) { for (FileNode node : nodes) { if (node.getName().equals(name)) return node; } return null; } /** * Searches the nodes array for a given name * @param n1 From * @param n2 To * @return Edge connecting n1 to n2 or null if not found */ public Edge findEdge(Node n1, Node n2) { for (Edge edge : edges) { if (edge.getNodeFrom() == n1 && edge.getNodeTo() == n2) return edge; } return null; } /** * Searches the people array for a given name. * @param name * @return PersonNode for given name or null if not found. */ public PersonNode findPerson(String name) { for (PersonNode p : people) { if (p.getName().equals(name)) return p; } return null; } /** * Load the standard event-formatted file. * @param filename */ public void loadRepEvents(String filename) { final String fullFilename = filename; XMLQueueLoader eventLoader = new XMLQueueLoader(fullFilename, eventsQueue, isInputSorted); eventLoader.addTaskListener(this); if (isInputSorted) backgroundExecutor.execute(eventLoader); else //we have to load all of the data before we can continue if it isn't sorted eventLoader.run(); } /* * Output file events for debugging void printQueue() { while( * eventsQueue.size() > 0 ) { FileEvent fe = (FileEvent)eventsQueue.poll(); * println( fe.date ); } } */ /** * @note Keystroke callback function */ public void keyPressed() { switch (key) { case ' ': { pauseButton(); break; } case 'a': { drawNamesHalos = !drawNamesHalos; break; } case 'b': { showDebug = !showDebug; break; } case 'd': { showDate = !showDate; break; } case 'e': { showEdges = !showEdges; break; } case 'E': { showEngine = !showEngine; break; } case 'f': { drawFilesFuzzy = !drawFilesFuzzy; break; } case 'h': { showHistogram = !showHistogram; break; } case 'j': { drawFilesJelly = !drawFilesJelly; break; } case 'l': { showLegend = !showLegend; break; } case 'p': { showPopular = !showPopular; break; } case 'q': { exit(); break; } case 's': { drawNamesSharp = !drawNamesSharp; break; } case 'S': { drawFilesSharp = !drawFilesSharp; break; } case '-': { wantToToggle = true; toggleDirection = false; break; } case '+': { wantToToggle = true; toggleDirection = true; break; } case '?': { showHelp = !showHelp; break; } } } /** * Method to switch between Physics Engines * @param direction Indicates whether or not to go left or right on the list */ public void switchPhysicsEngine(boolean direction) { if (mPhysicsEngineChoices.size() > 1 && safeToToggle) { boolean found = false; for (int i = 0; i < mPhysicsEngineChoices.size() && !found; i++) { if (mPhysicsEngineChoices.get(i) == mPhysicsEngine) { found = true; wantToToggle = false; if (direction == true) { if ((i + 1) < mPhysicsEngineChoices.size()) { mPhysicsEngine = mPhysicsEngineChoices.get(i + 1); physicsEngineSelection = mPhysicsEngineChoices.get(i + 1).getClass().getName(); } else { mPhysicsEngine = mPhysicsEngineChoices.get(0); physicsEngineSelection = mPhysicsEngineChoices.get(0).getClass().getName(); } } else { if ((i - 1) >= 0) { mPhysicsEngine = mPhysicsEngineChoices.get(i - 1); physicsEngineSelection = mPhysicsEngineChoices.get(i - 1).getClass().getName(); } else { mPhysicsEngine = mPhysicsEngineChoices.get(mPhysicsEngineChoices.size() - 1); physicsEngineSelection = mPhysicsEngineChoices.get(mPhysicsEngineChoices.size() - 1) .getClass().getName(); } } } } } } /** * Toggle pause */ public void pauseButton() { if (looping) noLoop(); else loop(); looping = !looping; } /** * Draws a point. * @param x * @param y * @param red * @param green * @param blue */ public void drawPoint(int x, int y, int red, int green, int blue) { noStroke(); colorMode(RGB); stroke(red, green, blue); point(x, y); } /** * Draws a line. * @param fromX * @param fromY * @param toX * @param toY * @param red * @param green * @param blue */ public void drawLine(int fromX, int fromY, int toX, int toY, int red, int green, int blue) { noStroke(); colorMode(RGB); stroke(red, green, blue); strokeWeight(1.5f); line(fromX, fromY, toX, toY); } /** * Returns the height of the code swarm component. * * @return int height of the code swarm component */ public static int getCodeSwarmHeight() { return height; } /** * Returns the width of the code swarm component. * * @return int width of the code swarm component */ public static int getCodeSwarmWidth() { return width; } public static CodeSwarmConfig getConfig() { return cfg; } /** * code_swarm Entry point. * @param args : should be the path to the config file */ public static void main(String args[]) { try { if (args.length > 0) { System.out.println("code_swarm is free software: you can redistribute it and/or modify"); System.out.println("it under the terms of the GNU General Public License as published by"); System.out.println("the Free Software Foundation, either version 3 of the License, or"); System.out.println("(at your option) any later version."); System.out.flush(); start(new CodeSwarmConfig(args[0])); } else { logger.error("Specify a config file."); } } catch (IOException e) { logger.error("Failed due to exception: " + e.getMessage(), e); } } /** * the alternative entry-point for code_swarm. It gets called from * {@link MainView} after fetching the repository log. * @param config the modified config * (it's InputFile-property has been changed to reflect the * fetched repository-log) */ public static void start(CodeSwarmConfig config) { cfg = config; PApplet.main(new String[] { "codeswarm.code_swarm" }); } /* * (non-Javadoc) * @see codeswarm.TaskListener#fireTaskDoneEvent() * * Notify waiting Threads to wake since the loading of the Document is complete. */ @Override public void fireTaskDoneEvent() { synchronized (this) { finishedLoading = true; notifyAll(); } } /* * (non-Javadoc) * @see codeswarm.TaskListener#fireEventAddedEvent() * * Notify waiting Threads to wake since an Event has been added to the queue. */ @Override public void fireEventAddedEvent() { synchronized (this) { notifyAll(); } } public static PFont getBoldPFont() { return boldFont; } public static PFont getPFont() { return font; } public PImage getSprite() { return sprite; } public boolean isDrawFilesSharp() { return drawFilesSharp; } public boolean isDrawFilesFuzzy() { return drawFilesFuzzy; } public boolean isDrawFilesJelly() { return drawFilesJelly; } public boolean isShowPopular() { return showPopular; } public ColorAssigner getColorAssigner() { return colorAssigner; } }